Files
windows-updater/docs/task-scheduler.md
2026-07-14 19:28:08 +02:00

9.7 KiB

Aufgabenplanung (Task Scheduler)

Das Script kann über die Windows Aufgabenplanung automatisch ausgeführt werden, z.B. täglich zu einer bestimmten Uhrzeit.

Voraussetzungen

  • Das Script muss als Administrator (bzw. SYSTEM) ausgeführt werden
  • Eine config.ini muss im Script-Verzeichnis vorhanden sein
  • PowerShell 5.1 muss verfügbar sein (auf allen unterstützten OS standardmäßig vorhanden)

Aufgabe per PowerShell erstellen (empfohlen)

Folgende Befehle in einer administrativen PowerShell ausführen:

Täglich um 04:00 Uhr

$action = New-ScheduledTaskAction `
    -Execute "powershell.exe" `
    -Argument "-ExecutionPolicy Bypass -NoProfile -File `"C:\scripts\windows-updater\windows-updater.ps1`""

$trigger = New-ScheduledTaskTrigger -Daily -At "04:00"

$principal = New-ScheduledTaskPrincipal `
    -UserId "SYSTEM" `
    -RunLevel Highest `
    -LogonType ServiceAccount

$settings = New-ScheduledTaskSettingsSet `
    -AllowStartIfOnBatteries `
    -DontStopIfGoingOnBatteries `
    -StartWhenAvailable `
    -ExecutionTimeLimit (New-TimeSpan -Hours 2)

Register-ScheduledTask `
    -TaskName "Windows Updater" `
    -Action $action `
    -Trigger $trigger `
    -Principal $principal `
    -Settings $settings `
    -Description "Automatische Windows Updates mit Benachrichtigung"

Wöchentlich (z.B. Sonntags um 03:00 Uhr)

$trigger = New-ScheduledTaskTrigger -Weekly -DaysOfWeek Sunday -At "03:00"

Den Rest wie oben, nur den Trigger austauschen.

Monatlich (z.B. erster Montag im Monat um 04:00 Uhr)

New-ScheduledTaskTrigger bietet keine -Monthly-Option mit Wochentag, und die CIM-Klasse MSFT_TaskMonthlyDOWTrigger wird von Register-ScheduledTask nicht akzeptiert ("Falscher Parameter"). Daher wird die Aufgabe per XML über schtasks.exe erstellt:

$startDate = (Get-Date "04:00").ToString("yyyy-MM-dd'T'HH:mm:ss")
$xml = @"
<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
  <Triggers>
    <CalendarTrigger>
      <StartBoundary>$startDate</StartBoundary>
      <Enabled>true</Enabled>
      <ScheduleByMonthDayOfWeek>
        <Weeks><Week>1</Week></Weeks>
        <DaysOfWeek><Monday /></DaysOfWeek>
        <Months>
          <January /><February /><March /><April /><May /><June />
          <July /><August /><September /><October /><November /><December />
        </Months>
      </ScheduleByMonthDayOfWeek>
    </CalendarTrigger>
  </Triggers>
  <Principals>
    <Principal id="Author">
      <UserId>S-1-5-18</UserId>
      <RunLevel>HighestAvailable</RunLevel>
    </Principal>
  </Principals>
  <Actions Context="Author">
    <Exec>
      <Command>powershell.exe</Command>
      <Arguments>-ExecutionPolicy Bypass -NoProfile -File "C:\scripts\windows-updater\windows-updater.ps1"</Arguments>
    </Exec>
  </Actions>
  <Settings>
    <AllowStartOnDemand>true</AllowStartOnDemand>
    <StartWhenAvailable>true</StartWhenAvailable>
    <AllowHardTerminate>true</AllowHardTerminate>
    <ExecutionTimeLimit>PT2H</ExecutionTimeLimit>
    <DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
    <StopIfGoingOnBatteries>false</StopIfGoingOnBatteries>
  </Settings>
</Task>
"@
$xmlPath = "$env:TEMP\windows-updater-monthly.xml"
$xml | Out-File -FilePath $xmlPath -Encoding Unicode
schtasks.exe /Create /TN "Windows Updater - Monthly" /XML $xmlPath /F
Remove-Item $xmlPath

Wochentag/Woche anpassen: <Monday /> durch den gewünschten Tag ersetzen (<Sunday />, <Tuesday />, etc.), <Week>1</Week> durch die gewünschte Woche (1-4) oder <Last /> für die letzte Woche.

Defender-Updates alle 4 Stunden

$action = New-ScheduledTaskAction `
    -Execute "powershell.exe" `
    -Argument "-ExecutionPolicy Bypass -NoProfile -File `"C:\scripts\windows-updater\windows-updater.ps1`" -DefenderOnly"

$trigger = New-ScheduledTaskTrigger -Once -At "00:00" -RepetitionInterval (New-TimeSpan -Hours 4)

$principal = New-ScheduledTaskPrincipal `
    -UserId "SYSTEM" `
    -RunLevel Highest `
    -LogonType ServiceAccount

$settings = New-ScheduledTaskSettingsSet `
    -AllowStartIfOnBatteries `
    -DontStopIfGoingOnBatteries `
    -StartWhenAvailable `
    -ExecutionTimeLimit (New-TimeSpan -Minutes 30)

Register-ScheduledTask `
    -TaskName "Windows Updater - Defender" `
    -Action $action `
    -Trigger $trigger `
    -Principal $principal `
    -Settings $settings `
    -Description "Defender-Definitionsupdates alle 4 Stunden"

Dual-Setup: Defender häufig + volle Updates monatlich

Zwei Aufgaben anlegen — eine für Defender (häufig), eine für alle Updates (selten):

# Aufgabe 1: Defender alle 4 Stunden (wie oben)

# Aufgabe 2: Volle Updates monatlich am ersten Sonntag um 03:00
$startDate = (Get-Date "03:00").ToString("yyyy-MM-dd'T'HH:mm:ss")
$xml = @"
<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
  <Triggers>
    <CalendarTrigger>
      <StartBoundary>$startDate</StartBoundary>
      <Enabled>true</Enabled>
      <ScheduleByMonthDayOfWeek>
        <Weeks><Week>1</Week></Weeks>
        <DaysOfWeek><Sunday /></DaysOfWeek>
        <Months>
          <January /><February /><March /><April /><May /><June />
          <July /><August /><September /><October /><November /><December />
        </Months>
      </ScheduleByMonthDayOfWeek>
    </CalendarTrigger>
  </Triggers>
  <Principals>
    <Principal id="Author">
      <UserId>S-1-5-18</UserId>
      <RunLevel>HighestAvailable</RunLevel>
    </Principal>
  </Principals>
  <Actions Context="Author">
    <Exec>
      <Command>powershell.exe</Command>
      <Arguments>-ExecutionPolicy Bypass -NoProfile -File "C:\scripts\windows-updater\windows-updater.ps1"</Arguments>
    </Exec>
  </Actions>
  <Settings>
    <AllowStartOnDemand>true</AllowStartOnDemand>
    <StartWhenAvailable>true</StartWhenAvailable>
    <AllowHardTerminate>true</AllowHardTerminate>
    <ExecutionTimeLimit>PT2H</ExecutionTimeLimit>
    <DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
    <StopIfGoingOnBatteries>false</StopIfGoingOnBatteries>
  </Settings>
</Task>
"@
$xmlPath = "$env:TEMP\windows-updater-monthly.xml"
$xml | Out-File -FilePath $xmlPath -Encoding Unicode
schtasks.exe /Create /TN "Windows Updater - Monthly" /XML $xmlPath /F
Remove-Item $xmlPath

Bestehende Aufgabe ändern

# Uhrzeit ändern
$trigger = New-ScheduledTaskTrigger -Daily -At "02:00"
Set-ScheduledTask -TaskName "Windows Updater" -Trigger $trigger

# Aufgabe deaktivieren
Disable-ScheduledTask -TaskName "Windows Updater"

# Aufgabe aktivieren
Enable-ScheduledTask -TaskName "Windows Updater"

# Aufgabe löschen
Unregister-ScheduledTask -TaskName "Windows Updater" -Confirm:$false

Aufgabe manuell starten (zum Testen)

Start-ScheduledTask -TaskName "Windows Updater"

Aufgabe per GUI erstellen

  1. taskschd.msc öffnen (oder "Aufgabenplanung" im Startmenü suchen)
  2. Rechtsklick auf "Aufgabenplanungsbibliothek" → "Aufgabe erstellen..."
  3. Reiter Allgemein:
    • Name: Windows Updater
    • "Mit höchsten Privilegien ausführen" aktivieren
    • "Unabhängig von der Benutzeranmeldung ausführen" wählen
    • Benutzer auf SYSTEM ändern
  4. Reiter Trigger:
    • Neuer Trigger → Täglich → Startzeit z.B. 04:00
  5. Reiter Aktionen:
    • Neue Aktion → "Programm starten"
    • Programm: powershell.exe
    • Argumente: -ExecutionPolicy Bypass -NoProfile -File "C:\scripts\windows-updater\windows-updater.ps1"
  6. Reiter Einstellungen:
    • "Aufgabe so schnell wie möglich nach einem verpassten Start ausführen" aktivieren
    • "Aufgabe beenden, falls sie länger ausgeführt wird als:" 2 Stunden

Wichtige Hinweise

SYSTEM-Kontext

Das Script läuft als SYSTEM-Benutzer. Beachte dabei:

  • Netzlaufwerke sind nicht verfügbar (SYSTEM hat keine zugeordneten Laufwerke)
  • Umgebungsvariablen wie %USERPROFILE% zeigen auf C:\Windows\system32\config\systemprofile
  • winget muss ggf. über den vollen Pfad aufgerufen werden (das Script behandelt dies automatisch)
  • Log-Dateien müssen in einem Verzeichnis liegen, auf das SYSTEM Schreibrechte hat (z.B. C:\logs\)

Execution Policy

Das Script wird mit -ExecutionPolicy Bypass aufgerufen, damit es ohne vorherige Änderung der systemweiten Execution Policy läuft. Dies ist sicher, da nur dieses spezifische Script betroffen ist.

Timeout

Die Standard-Ausführungszeitbegrenzung ist auf 2 Stunden gesetzt. Bei Servern mit vielen Updates kann dies ggf. erhöht werden:

$settings = New-ScheduledTaskSettingsSet `
    -ExecutionTimeLimit (New-TimeSpan -Hours 4)
Set-ScheduledTask -TaskName "Windows Updater" -Settings $settings

Log prüfen

Nach der ersten automatischen Ausführung die Logs prüfen:

# Heutiges Log anzeigen
$today = Get-Date -Format "yyyy-MM-dd"
Get-Content "C:\logs\windows-updater\windows-updater_$today.log"

# Letzten Lauf in der Aufgabenplanung prüfen
Get-ScheduledTaskInfo -TaskName "Windows Updater" | Select-Object LastRunTime, LastTaskResult

Exit-Codes in der Aufgabenplanung

Task Result Bedeutung
0 Erfolg
1 Fehler (Details im Log)
2 Neustart erforderlich (Auto-Reboot deaktiviert)
0x1 Allgemeiner Fehler
0x41301 Aufgabe läuft gerade

Empfohlene Zeitplanung

Szenario Empfehlung
Arbeitsstation Täglich, 12:00 (Mittagspause) mit DryRun, Manuelles Update später
Server (nicht-kritisch) Täglich, 03:00-05:00 mit Auto-Reboot
Server (kritisch/Produktion) Wöchentlich Sonntag, 03:00 mit DryRun. Manuell nach Prüfung
Testumgebung Täglich, 02:00 mit Auto-Reboot
Defender-Signaturen Alle 4 Stunden mit -DefenderOnly, zusätzlich zu einem der obigen Szenarien