289 lines
9.7 KiB
Markdown
289 lines
9.7 KiB
Markdown
# 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
|
|
|
|
```powershell
|
|
$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)
|
|
|
|
```powershell
|
|
$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:
|
|
|
|
```powershell
|
|
$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
|
|
|
|
```powershell
|
|
$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):
|
|
|
|
```powershell
|
|
# 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
|
|
|
|
```powershell
|
|
# 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)
|
|
|
|
```powershell
|
|
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:
|
|
|
|
```powershell
|
|
$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:
|
|
|
|
```powershell
|
|
# 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 |
|