Endstand verifiziert: AutoAdminLogon=1, DefaultUserName=ah, DefaultDomainName=HOMEBASE, Aufgabe OilAutoLogonLock Bereit und auf autologon_lock.ps1 zeigend. Die Boot-Luecke ist damit konfiguratorisch geschlossen. ⚠ Der SICHERE Weg hat nicht funktioniert: Sysinternals Autologon beendete sich mit ExitCode 0, schrieb aber nichts — weder ueber den Dialog noch ueber die Argument-Form. Ausgeschlossen: DevicePasswordLessBuildVersion (nicht gesetzt), fehlende Elevation, haengender Prozess. Ursache ungeklaert. Aktiv ist deshalb der Registry-Weg, und damit steht das Passwort im KLARTEXT unter HKLM\...\Winlogon\DefaultPassword — lesbar fuer jeden lokalen Admin und jedes Backup-Image. Entfernen-Kommando in CLAUDE.md. ⚠ Dritter Fall derselben Fehlerklasse in diesem Skript, jetzt behoben: die Speicherart wurde aus einer stale Variable gelesen, die VOR dem Registry-Schreiben gefuellt war. Die Ausgabe widersprach sich direkt — erst korrekt 'steht jetzt im KLARTEXT', zwei Zeilen spaeter 'nicht im Klartext ✅'. Der Zustand wird jetzt nach jedem Schreibvorgang frisch gelesen. Lehre aus allen drei Faellen: eine Erfolgsmeldung muss den Zustand NACH der Aktion pruefen, nicht den davor. Offen: die Wirkung ist erst beim naechsten Reboot belegt. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
258 lines
13 KiB
PowerShell
258 lines
13 KiB
PowerShell
# Auto-Logon einrichten — schliesst die letzte Luecke der Boot-Pipeline.
|
|
#
|
|
# WOZU: `OilTradingServer` und `HyperliquidDashboard` haengen an einem LOGON-
|
|
# Trigger. Nach einem Windows-Update-Reboot laeuft nichts, bis sich jemand
|
|
# anmeldet — real in der Nacht zum 2026-07-20 passiert (Reboot 01:30, Server bis
|
|
# 07:42 tot, nur der broker-seitige SL schuetzte, -95,48 EUR). Ein Task ohne
|
|
# angemeldete Sitzung hilft NICHT: der Bot braucht das laufende MT5-TERMINAL,
|
|
# und das ist eine GUI-Anwendung — es braucht eine echte Desktop-Sitzung.
|
|
#
|
|
# ⚠⚠ WARUM SYSINTERNALS UND NICHT DIE REGISTRY. Der verbreitete Weg schreibt
|
|
# das Passwort als `DefaultPassword` im KLARTEXT nach HKLM\...\Winlogon — dort
|
|
# kann es jeder lokale Administrator und jedes Backup-Image lesen. Sysinternals
|
|
# `Autologon` legt es als verschluesseltes LSA-Secret ab.
|
|
#
|
|
# ⚠ RESTRISIKO, das bleibt: nach dem Reboot steht eine ANGEMELDETE Sitzung mit
|
|
# offenem MT5 und Live-Broker-Verbindung da. Schritt 2 sperrt deshalb den
|
|
# Bildschirm — aber nur nach einem Auto-Logon, nicht nach jeder Anmeldung
|
|
# (s. `autologon_lock.ps1`).
|
|
#
|
|
# AUFRUF (Fenster muss ALS ADMINISTRATOR laufen):
|
|
# powershell -ExecutionPolicy Bypass -File tools\autologon_einrichten.ps1
|
|
#
|
|
# ⚠ Das Passwort steht NICHT in dieser Datei und wird nirgends gespeichert —
|
|
# es wird im GUI-Dialog von Autologon eingegeben.
|
|
#
|
|
# ⚠⚠ ZWEI FEHLER AUS DEM ERSTEN VERSUCH (2026-08-07), hier behoben:
|
|
# 1. `$ErrorActionPreference = 'Stop'` PLUS `schtasks /Delete` auf eine noch
|
|
# nicht existierende Aufgabe = das Skript brach ab, BEVOR /Create lief.
|
|
# Native Programme schreiben nach stderr, und PowerShell macht daraus unter
|
|
# 'Stop' einen Abbruch. Jetzt wird vorher geprueft, ob es sie ueberhaupt gibt.
|
|
# 2. Die Erfolgsmeldung log: fehlendes `DefaultPassword` wurde als
|
|
# "LSA-Secret ✅" gemeldet — dabei war schlicht GAR NICHTS gesetzt. Jetzt
|
|
# ist `AutoAdminLogon = 1` die Bedingung, und erst danach wird ueberhaupt
|
|
# ueber die Speicherart geurteilt.
|
|
|
|
# AUFRUF-VARIANTEN:
|
|
# ... -File tools\autologon_einrichten.ps1 GUI-Dialog (Standard)
|
|
# ... -File tools\autologon_einrichten.ps1 -Direkt ohne Dialog, Passwort
|
|
# wird hier abgefragt
|
|
# ⚠ `-Direkt` ist der zuverlaessige Weg. Der Dialog OEFFNET sich zwar
|
|
# (Fenstertitel "Autologon - Sysinternals", verifiziert), muss aber mit ENABLE
|
|
# bestaetigt werden — wird er nur geschlossen, passiert nichts.
|
|
# ⚠ Abwaegung bei `-Direkt`: Autologon 3.10 nimmt Benutzer/Domaene/Passwort als
|
|
# Argumente. Das Passwort steht damit fuer den Moment des Aufrufs in der
|
|
# Kommandozeile des Kindprozesses (fuer Administratoren kurz sichtbar). Es wird
|
|
# NICHT in eine Datei geschrieben, nicht in die PowerShell-History (Read-Host)
|
|
# und landet anschliessend als verschluesseltes LSA-Secret — nicht im Klartext
|
|
# in der Registry.
|
|
param([switch]$Direkt)
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
$hier = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
$k = 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon'
|
|
$t = 'OilAutoLogonLock'
|
|
|
|
$id = [Security.Principal.WindowsIdentity]::GetCurrent()
|
|
if (-not (New-Object Security.Principal.WindowsPrincipal($id)).IsInRole(
|
|
[Security.Principal.WindowsBuiltInRole]::Administrator)) {
|
|
Write-Host " ABBRUCH: Dieses Fenster hat keine Administratorrechte." -ForegroundColor Red
|
|
exit 1
|
|
}
|
|
|
|
$exe = Join-Path $hier 'autologon\Autologon64.exe'
|
|
if (-not (Test-Path $exe)) { $exe = Join-Path $hier 'autologon\Autologon.exe' }
|
|
if (-not (Test-Path $exe)) {
|
|
Write-Host " ABBRUCH: Autologon.exe fehlt unter tools\autologon\." -ForegroundColor Red
|
|
exit 1
|
|
}
|
|
|
|
Write-Host "=================================================================="
|
|
Write-Host " SCHRITT 1 - Auto-Logon aktivieren (verschluesseltes LSA-Secret)"
|
|
Write-Host "=================================================================="
|
|
Write-Host " Benutzer: $env:USERNAME Domaene: $env:COMPUTERNAME (lokal)"
|
|
# Aktivierung ohne Dialog — als Funktion, damit sie auch als Rueckfall nach
|
|
# einem abgebrochenen Dialog aufgerufen werden kann (sonst muesste der Nutzer
|
|
# das Skript ein drittes Mal starten).
|
|
function Invoke-DirektAktivierung {
|
|
# ⚠ Read-Host -AsSecureString: die Eingabe erscheint nicht auf dem Schirm
|
|
# und landet nicht in der PowerShell-History.
|
|
$sec = Read-Host " Passwort fuer $env:USERNAME (Eingabe bleibt unsichtbar)" -AsSecureString
|
|
$bstr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($sec)
|
|
try {
|
|
$pw = [Runtime.InteropServices.Marshal]::PtrToStringAuto($bstr)
|
|
if (-not $pw) {
|
|
Write-Host " Kein Passwort eingegeben." -ForegroundColor Red
|
|
return $false
|
|
}
|
|
Write-Host " Aktiviere Auto-Logon ..."
|
|
# ⚠⚠ ZWEI FEHLER AUS DEM VORIGEN VERSUCH, hier behoben:
|
|
# (a) `& $exe ...` WARTET BEI GUI-ANWENDUNGEN NICHT — das Skript las die
|
|
# Registry, bevor Autologon ueberhaupt fertig war.
|
|
# (b) `$null = ... 2>&1` hat die Rueckmeldung VERSCHLUCKT. Genau die
|
|
# Information, die zur Diagnose noetig war, wurde weggeworfen.
|
|
# Jetzt: warten, Exit-Code auswerten, Ausgabe zeigen.
|
|
$log = Join-Path $env:TEMP 'autologon_out.txt'
|
|
$p = Start-Process -FilePath $exe `
|
|
-ArgumentList $env:USERNAME, $env:COMPUTERNAME, $pw `
|
|
-Wait -PassThru -RedirectStandardOutput $log `
|
|
-RedirectStandardError "$log.err" -WindowStyle Hidden
|
|
Write-Host " Autologon ExitCode: $($p.ExitCode)"
|
|
foreach ($f in @($log, "$log.err")) {
|
|
if ((Test-Path $f) -and (Get-Item $f).Length -gt 0) {
|
|
Write-Host " Ausgabe: $((Get-Content $f -Raw).Trim())"
|
|
}
|
|
Remove-Item $f -EA SilentlyContinue
|
|
}
|
|
return $true
|
|
} finally {
|
|
# Klartext so kurz wie moeglich im Speicher halten
|
|
[Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr)
|
|
Remove-Variable pw -ErrorAction SilentlyContinue
|
|
}
|
|
}
|
|
|
|
Write-Host ""
|
|
if ($Direkt) {
|
|
if (-not (Invoke-DirektAktivierung)) { exit 1 }
|
|
} else {
|
|
Write-Host " Es oeffnet sich gleich der Autologon-Dialog." -ForegroundColor Cyan
|
|
Write-Host " --> Passwort eintragen und auf ENABLE klicken." -ForegroundColor Cyan
|
|
Write-Host " (Nur schliessen reicht NICHT - dann passiert nichts."
|
|
Write-Host " Zuverlaessiger: Skript mit -Direkt aufrufen.)"
|
|
Write-Host ""
|
|
Start-Process -FilePath $exe -ArgumentList '/accepteula' -Wait
|
|
}
|
|
|
|
# ── Ergebnis ehrlich pruefen ────────────────────────────────────────────
|
|
$an = (Get-ItemProperty -Path $k -Name AutoAdminLogon -EA SilentlyContinue).AutoAdminLogon
|
|
$user = (Get-ItemProperty -Path $k -Name DefaultUserName -EA SilentlyContinue).DefaultUserName
|
|
$klartext = (Get-ItemProperty -Path $k -Name DefaultPassword -EA SilentlyContinue).DefaultPassword
|
|
$aktiv = ($an -eq '1')
|
|
|
|
Write-Host ""
|
|
Write-Host " AutoAdminLogon : $(if ($an) { $an } else { '(nicht gesetzt)' })"
|
|
Write-Host " DefaultUserName : $(if ($user) { $user } else { '(nicht gesetzt)' })"
|
|
|
|
# ⚠ RUECKFALL statt Sackgasse: schlaegt der Dialog-Weg fehl, wird hier direkt
|
|
# angeboten, es ohne Dialog zu erledigen — sonst muesste das Skript ein drittes
|
|
# Mal von Hand gestartet werden (real zweimal passiert).
|
|
if (-not $aktiv -and -not $Direkt) {
|
|
Write-Host ""
|
|
Write-Host " ==> Der Dialog wurde ohne 'Enable' geschlossen." -ForegroundColor Yellow
|
|
$a = Read-Host " Jetzt ohne Dialog erledigen? (j/n)"
|
|
if ($a -match '^[jJyY]') {
|
|
if (Invoke-DirektAktivierung) {
|
|
$an = (Get-ItemProperty -Path $k -Name AutoAdminLogon -EA SilentlyContinue).AutoAdminLogon
|
|
$user = (Get-ItemProperty -Path $k -Name DefaultUserName -EA SilentlyContinue).DefaultUserName
|
|
$klartext = (Get-ItemProperty -Path $k -Name DefaultPassword -EA SilentlyContinue).DefaultPassword
|
|
$aktiv = ($an -eq '1')
|
|
Write-Host ""
|
|
Write-Host " AutoAdminLogon : $(if ($an) { $an } else { '(nicht gesetzt)' })"
|
|
Write-Host " DefaultUserName : $(if ($user) { $user } else { '(nicht gesetzt)' })"
|
|
}
|
|
}
|
|
}
|
|
|
|
# ── Letzter Ausweg: Registry-Weg ────────────────────────────────────────
|
|
# ⚠⚠ BEWUSST ALS LETZTE OPTION und nur nach ausdruecklicher Zustimmung. Hier
|
|
# landet das Passwort im KLARTEXT unter HKLM\...\Winlogon\DefaultPassword —
|
|
# lesbar fuer jeden lokalen Administrator und in jedem Backup-Image. Der einzige
|
|
# Vorteil: er funktioniert immer, ohne Fremdprogramm. Wenn Autologon (der
|
|
# sichere Weg) partout nicht greift, ist das die Alternative — die Entscheidung
|
|
# gehoert dem Nutzer, nicht dem Skript.
|
|
if (-not $aktiv) {
|
|
Write-Host ""
|
|
Write-Host " ==> AUTO-LOGON IST NICHT AKTIV." -ForegroundColor Yellow
|
|
Write-Host " Sysinternals Autologon hat nichts geschrieben."
|
|
Write-Host ""
|
|
Write-Host " ALTERNATIVE: der Registry-Weg." -ForegroundColor Cyan
|
|
Write-Host " ⚠ Dabei steht das Passwort im KLARTEXT in der Registry" -ForegroundColor Yellow
|
|
Write-Host " (HKLM\...\Winlogon\DefaultPassword). Jeder lokale Admin und"
|
|
Write-Host " jedes Backup-Image kann es lesen. Er funktioniert dafuer immer."
|
|
$a = Read-Host " Registry-Weg jetzt verwenden? (j/n)"
|
|
if ($a -notmatch '^[jJyY]') {
|
|
Write-Host " Abgebrochen. Schritt 2 uebersprungen."
|
|
exit 1
|
|
}
|
|
$sec = Read-Host " Passwort fuer $env:USERNAME (Eingabe bleibt unsichtbar)" -AsSecureString
|
|
$bstr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($sec)
|
|
try {
|
|
$pw2 = [Runtime.InteropServices.Marshal]::PtrToStringAuto($bstr)
|
|
if (-not $pw2) { Write-Host " Kein Passwort." -ForegroundColor Red; exit 1 }
|
|
Set-ItemProperty -Path $k -Name AutoAdminLogon -Value '1' -Type String
|
|
Set-ItemProperty -Path $k -Name DefaultUserName -Value $env:USERNAME -Type String
|
|
Set-ItemProperty -Path $k -Name DefaultDomainName -Value $env:COMPUTERNAME -Type String
|
|
Set-ItemProperty -Path $k -Name DefaultPassword -Value $pw2 -Type String
|
|
} finally {
|
|
[Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr)
|
|
Remove-Variable pw2 -EA SilentlyContinue
|
|
}
|
|
$an = (Get-ItemProperty -Path $k -Name AutoAdminLogon -EA SilentlyContinue).AutoAdminLogon
|
|
$aktiv = ($an -eq '1')
|
|
Write-Host ""
|
|
Write-Host " AutoAdminLogon : $an"
|
|
}
|
|
|
|
if (-not $aktiv) {
|
|
Write-Host " ==> Auch das hat nicht gegriffen. Schritt 2 uebersprungen." -ForegroundColor Red
|
|
exit 1
|
|
}
|
|
|
|
# ⚠⚠ NEU EINLESEN, NICHT den alten Wert wiederverwenden. Beim ersten Bau stand
|
|
# hier eine stale Variable aus der Zeit VOR dem Registry-Schreiben — die Ausgabe
|
|
# widersprach sich dann direkt: erst korrekt "steht jetzt im KLARTEXT", zwei
|
|
# Zeilen spaeter "nicht im Klartext (LSA-Secret) ✅". DRITTER Fall derselben
|
|
# Fehlerklasse in diesem Skript (Erfolg melden, wo keiner ist bzw. wo das
|
|
# Gegenteil zutrifft). Der Zustand wird deshalb immer frisch gelesen.
|
|
$klartext = (Get-ItemProperty -Path $k -Name DefaultPassword -EA SilentlyContinue).DefaultPassword
|
|
Write-Host ""
|
|
if ($klartext) {
|
|
Write-Host " SPEICHERART: ⚠ Passwort im KLARTEXT in der Registry." -ForegroundColor Yellow
|
|
Write-Host " Entfernen (deaktiviert damit auch den Auto-Logon):"
|
|
Write-Host " Remove-ItemProperty -Path '$k' -Name DefaultPassword"
|
|
} else {
|
|
Write-Host " SPEICHERART: verschluesseltes LSA-Secret ✅" -ForegroundColor Green
|
|
}
|
|
|
|
if ($klartext) {
|
|
Write-Host " DefaultPassword : ⚠ KLARTEXT in der Registry!" -ForegroundColor Yellow
|
|
} else {
|
|
Write-Host " DefaultPassword : nicht im Klartext (LSA-Secret) ✅" -ForegroundColor Green
|
|
}
|
|
|
|
# ── Schritt 2: Bildschirmsperre nach dem Auto-Logon ─────────────────────
|
|
Write-Host ""
|
|
Write-Host "=================================================================="
|
|
Write-Host " SCHRITT 2 - Bildschirm nach dem Auto-Logon sperren"
|
|
Write-Host "=================================================================="
|
|
|
|
# ⚠ Erst pruefen, dann loeschen. `schtasks /Delete` auf eine fehlende Aufgabe
|
|
# schreibt nach stderr und wuerde unter $ErrorActionPreference='Stop' abbrechen.
|
|
$vorhanden = $false
|
|
try {
|
|
$null = & schtasks /Query /TN $t 2>&1
|
|
$vorhanden = ($LASTEXITCODE -eq 0)
|
|
} catch { $vorhanden = $false }
|
|
if ($vorhanden) {
|
|
$null = & schtasks /Delete /TN $t /F 2>&1
|
|
Write-Host " alte Aufgabe entfernt"
|
|
}
|
|
|
|
$lock = Join-Path $hier 'autologon_lock.ps1'
|
|
$cmd = "powershell -NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File `"$lock`""
|
|
$null = & schtasks /Create /TN $t /SC ONLOGON /RU "$env:USERNAME" /DELAY 0000:30 /TR $cmd /F 2>&1
|
|
if ($LASTEXITCODE -eq 0) {
|
|
Write-Host " Aufgabe '$t' angelegt." -ForegroundColor Green
|
|
Write-Host " Sperrt 30 s nach der Anmeldung - aber NUR, wenn der Rechner"
|
|
Write-Host " gerade gebootet hat. Nach manueller Anmeldung passiert nichts."
|
|
Write-Host " Die Sitzung laeuft weiter: MT5 und beide Server arbeiten."
|
|
} else {
|
|
Write-Host " ⚠ Aufgabe konnte nicht angelegt werden (Code $LASTEXITCODE)." -ForegroundColor Yellow
|
|
}
|
|
|
|
Write-Host ""
|
|
Write-Host " Rueckgaengig:"
|
|
Write-Host " $exe /accepteula (dann Disable)"
|
|
Write-Host " schtasks /Delete /TN $t /F"
|