Task Scheduler – Aufgaben automatisieren
Der Windows Task Scheduler automatisiert Skripte und Programme per Zeitplan oder Ereignis – von der GUI bis zur vollständigen PowerShell-Verwaltung.
Was ist der Task Scheduler und wozu brauchst du ihn?
Der Windows Task Scheduler (Aufgabenplanung) ist ein in Windows integrierter Dienst, der Programme, Skripte und Befehle automatisch ausführt – entweder nach Zeitplan oder als Reaktion auf bestimmte Systemereignisse. Für dich als IT-Allrounder in einem KMU ist er eines der wichtigsten Werkzeuge überhaupt: Backup-Skripte, Log-Rotationen, Monitoring-Checks, Benutzerberichte – all das läuft zuverlässig im Hintergrund, ohne dass jemand manuell etwas anstossen muss.
Im Alltag triffst du auf drei typische Szenarien:
- Regelmässige Wartungsaufgaben: Backups, Disk-Cleanup, Antivirus-Updates
- Ereignisgesteuerte Automatisierung: Ein Skript läuft, wenn sich ein User anmeldet oder ein bestimmtes Windows-Ereignis (Event Log) auftritt
- Einmalige geplante Aktionen: Eine Migration, ein Update-Rollout zu einem definierten Zeitpunkt
Den Task Scheduler öffnen
Es gibt drei Wege, die Aufgabenplanung aufzurufen:
Per Ausführen-Dialog:
Drücke Win+R, tippe taskschd.msc und bestätige mit Enter.
Per PowerShell oder CMD:
taskschd.msc
Per Suchfeld:
Startmenü öffnen, „Aufgabenplanung” eingeben, als Administrator starten.
Die Oberfläche zeigt dir links die Aufgabenbibliothek (Ordnerstruktur), mittig die Aufgabenliste und rechts den Aktionsbereich. Eigene Aufgaben legst du am besten in einem eigenen Unterordner ab, z.B. \Firma\Automatisierung – das hält die Übersicht sauber.
Anatomie einer geplanten Aufgabe
Jede Aufgabe besteht aus vier Bausteinen:
| Baustein | Funktion |
|---|---|
| Trigger | Wann oder warum die Aufgabe startet (Zeitplan, Ereignis, Login) |
| Aktion | Was ausgeführt wird (Programm, Skript, Befehl) |
| Bedingungen | Zusätzliche Voraussetzungen (z.B. nur bei Netzstrom) |
| Einstellungen | Verhalten bei Fehlern, Timeouts, Retry-Logik |
Trigger-Typen im Überblick
| Trigger | Typischer Einsatz |
|---|---|
| Einmalig | Geplante Migration, einmaliges Update |
| Täglich | Nachtbackup, Log-Rotation |
| Wöchentlich | Wochenbericht, Speicherplatz-Check |
| Monatlich | Monatsabschluss-Export |
| Beim Systemstart | Dienst oder Monitoring-Agent starten |
| Bei Benutzeranmeldung | Login-Skript, Drive-Mapping |
| Bei Leerlauf | Ressourcenintensive Aufgaben |
| Bei Ereignis (Event Log) | Reaktion auf Fehler oder Sicherheitsereignisse |
Neue Aufgabe per GUI erstellen
Wenn du eine Aufgabe per GUI anlegen willst (gut zum Verstehen der Parameter):
- Aufgabenplanung öffnen (
taskschd.msc) - Rechts auf Aufgabe erstellen… klicken (nicht „Einfache Aufgabe erstellen” – das ist zu eingeschränkt)
- Reiter Allgemein:
- Name vergeben (z.B.
Backup-NachtScript) - Benutzerkonto auf
SYSTEMsetzen - Mit höchsten Privilegien ausführen aktivieren
- „Ausführen unabhängig von der Benutzeranmeldung” wählen
- Name vergeben (z.B.
- Reiter Trigger: Neu > Täglich, Uhrzeit setzen
- Reiter Aktionen: Neu > Programm:
powershell.exe, Argumente:-NonInteractive -ExecutionPolicy Bypass -File "C:\Scripts\backup.ps1" - Reiter Bedingungen: „Aufgabe nur starten, wenn folgende Netzwerkverbindung verfügbar ist” ggf. aktivieren
- Reiter Einstellungen: Ausführungszeit-Limit setzen, Wiederholung bei Fehler konfigurieren
Bedingungen: Idle-, Akku- und Netzwerk-Voraussetzungen für Laptop-Flotten
Der dritte Baustein einer Aufgabe – die Bedingungen – wird gerne übersehen, ist aber bei einer Flotte aus Notebooks entscheidend. Ein Backup- oder Inventarisierungs-Skript, das mitten in einer Kundenpräsentation den Lüfter hochdreht und den Akku leersaugt, sorgt zuverlässig für Ärger im Team. Im Reiter Bedingungen der GUI stellst du deshalb typischerweise ein:
- Aufgabe nur starten, wenn Computer im Netzbetrieb läuft (aktiv)
- Aufgabe beenden, falls Computer in den Akkubetrieb wechselt (aktiv)
- Aufgabe nur starten, wenn Computer im Leerlauf ist, inklusive Leerlaufdauer und Wartezeit
- Aufgabe nur starten, wenn folgende Netzwerkverbindung verfügbar ist – praktisch, wenn ein Skript nur im Firmennetz oder per VPN Sinn ergibt
Per PowerShell bildest du das über New-ScheduledTaskSettingsSet ab. Wichtig zu wissen: Die konservativen Standardwerte (kein Start im Akkubetrieb, Abbruch bei Wechsel auf Akku) gelten automatisch, sobald du die zugehörigen „Erlauben”-Schalter weglässt – du musst sie also nicht explizit setzen, sondern nur bewusst nicht aktivieren.
$settings = New-ScheduledTaskSettingsSet `
-RunOnlyIfIdle `
-IdleDuration (New-TimeSpan -Minutes 10) `
-IdleWaitTimeout (New-TimeSpan -Hours 2) `
-DontStopOnIdleEnd `
-RunOnlyIfNetworkAvailable `
-StartWhenAvailable
# Kein -AllowStartIfOnBatteries -> Task startet nur im Netzbetrieb (Standard)
# Kein -DontStopIfGoingOnBatteries -> Task wird bei Akkuwechsel gestoppt (Standard)
| GUI-Option | PowerShell-Parameter | Bedeutung |
|---|---|---|
| Nur im Netzbetrieb starten | (Standard, kein Parameter nötig) | Task startet nicht auf Akku |
-AllowStartIfOnBatteries | Schalter setzen | Task darf auch auf Akku starten |
-DontStopIfGoingOnBatteries | Schalter setzen | Task läuft weiter, wenn Nutzer den Stecker zieht |
| Nur im Leerlauf starten | -RunOnlyIfIdle + -IdleDuration | Wartet auf inaktive Tastatur/Maus |
| Leerlauf-Wartezeit | -IdleWaitTimeout | Wie lange maximal auf Leerlauf gewartet wird |
| Bei Leerlaufende weiterlaufen lassen | -DontStopOnIdleEnd | Task wird nicht abgebrochen, sobald der User wieder aktiv wird |
| Nur bei Netzwerk starten | -RunOnlyIfNetworkAvailable (+ -NetworkName) | Sinnvoll für VPN-abhängige Skripte |
Aufgaben per PowerShell erstellen und verwalten
Die GUI ist gut zum Verstehen – für produktive Umgebungen nimmst du PowerShell. Du kannst Aufgaben skriptieren, versionieren und auf mehrere Maschinen ausrollen.
Grundstruktur: Vier Cmdlets, eine Registrierung
# 1. Aktion definieren: was soll ausgeführt werden?
$action = New-ScheduledTaskAction `
-Execute "powershell.exe" `
-Argument "-NonInteractive -ExecutionPolicy Bypass -File `"C:\Scripts\backup.ps1`""
# 2. Trigger definieren: wann?
$trigger = New-ScheduledTaskTrigger -Daily -At "23:00"
# 3. Einstellungen: Timeout, Retry
$settings = New-ScheduledTaskSettingsSet `
-ExecutionTimeLimit (New-TimeSpan -Hours 2) `
-RestartCount 3 `
-RestartInterval (New-TimeSpan -Minutes 5) `
-StartWhenAvailable
# 4. Principal: unter welchem Konto laufen?
$principal = New-ScheduledTaskPrincipal `
-UserId "SYSTEM" `
-RunLevel Highest
# 5. Aufgabe registrieren
Register-ScheduledTask `
-TaskName "NaechtlichesBackup" `
-TaskPath "\Firma\Automatisierung" `
-Action $action `
-Trigger $trigger `
-Settings $settings `
-Principal $principal `
-Description "Taegliches Backup um 23 Uhr, laeuft als SYSTEM"
Wöchentliche Aufgabe (jeden Montag)
$trigger = New-ScheduledTaskTrigger `
-Weekly `
-DaysOfWeek Monday `
-At "06:00"
Bei Systemstart (z.B. Monitoring-Agent)
$trigger = New-ScheduledTaskTrigger -AtStartup
Bei Benutzeranmeldung
# Für einen spezifischen User
$trigger = New-ScheduledTaskTrigger -AtLogOn -User "DOMAIN\mmuster"
# Für alle User (User-Parameter weglassen)
$trigger = New-ScheduledTaskTrigger -AtLogOn
Ereignisgesteuert (Event Log)
# Aufgabe startet wenn Ereignis-ID 4625 (fehlgeschlagener Login) auftritt
$xmlQuery = @"
<QueryList>
<Query Id="0" Path="Security">
<Select Path="Security">*[System[Provider[@Name='Microsoft-Windows-Security-Auditing'] and EventID=4625]]</Select>
</Query>
</QueryList>
"@
$trigger = New-ScheduledTaskTrigger -OnEvent -Subscription $xmlQuery -Delay (New-TimeSpan -Seconds 30)
Mehrere Trigger und Aktionen in einer Aufgabe kombinieren
Eine Aufgabe ist nicht auf einen Trigger oder eine Aktion beschränkt. Das lohnt sich, sobald ein Skript aus mehreren Gründen anspringen soll oder mehrere Schritte nacheinander ablaufen müssen.
Mehrere Trigger: ODER-Verknüpfung
Trigger werden mit ODER verknüpft – reicht irgendeiner der Trigger, läuft die Aufgabe. Ein klassisches Muster: nächtlicher Zeitplan plus ein Nachhol-Trigger beim Systemstart, falls der Rechner zur geplanten Zeit ausgeschaltet war.
$triggerNachts = New-ScheduledTaskTrigger -Daily -At "23:00"
$triggerNachholen = New-ScheduledTaskTrigger -AtStartup
$triggerNachholen.Delay = "PT5M" # 5 Minuten nach dem Hochfahren, damit Dienste bereit sind
Register-ScheduledTask -TaskName "Backup-MitNachhol-Trigger" -TaskPath "\Firma\Automatisierung" `
-Action $action -Trigger $triggerNachts, $triggerNachholen -Settings $settings -Principal $principal
Nützliche Trigger-Eigenschaften, die über die reine Uhrzeit hinausgehen:
| Eigenschaft | Wirkung |
|---|---|
Enabled = $false | Trigger bleibt in der Aufgabe erhalten, ist aber deaktiviert – praktisch zum temporären Stilllegen ohne Löschen |
StartBoundary / EndBoundary | Aufgabe ist nur innerhalb eines Zeitfensters aktiv (z.B. Migrationsphase) |
RandomDelay | Startzeit wird zufällig gestreut – verhindert, dass hunderte Clients exakt um 08:00 Uhr gleichzeitig einen Server bombardieren |
RepetitionInterval + RepetitionDuration | Wiederholt die Aufgabe innerhalb eines Zeitfensters, z.B. alle 15 Minuten für 8 Stunden |
# Alle 15 Minuten wiederholen, 8 Stunden lang - typisch fuer Monitoring-Checks
$trigger = New-ScheduledTaskTrigger -Once -At (Get-Date) `
-RepetitionInterval (New-TimeSpan -Minutes 15) `
-RepetitionDuration (New-TimeSpan -Hours 8)
# Startzeit um bis zu 10 Minuten streuen, um Lastspitzen zu vermeiden
$triggerVerteilt = New-ScheduledTaskTrigger -Daily -At "08:00"
$triggerVerteilt.RandomDelay = "PT10M"
Mehrere Aktionen: sequenzielle Ausführung
Aktionen laufen der Reihe nach ab. Ein Beispiel: erst das eigentliche Wartungsskript, danach ein Heartbeat an ein Monitoring-System, damit dokumentiert ist, dass die Aufgabe durchgelaufen ist.
$action1 = New-ScheduledTaskAction -Execute "powershell.exe" `
-Argument "-NonInteractive -ExecutionPolicy Bypass -File `"C:\Scripts\cleanup-logs.ps1`""
$action2 = New-ScheduledTaskAction -Execute "powershell.exe" `
-Argument "-NonInteractive -Command `"Invoke-RestMethod -Uri 'https://monitoring.firma.ch/heartbeat/logcleanup'`""
Register-ScheduledTask -TaskName "LogCleanup-MitHeartbeat" -TaskPath "\Firma\Wartung" `
-Action $action1, $action2 -Trigger $trigger -Settings $settings -User "SYSTEM" -RunLevel Highest
Bestehende Aufgabe um einen Trigger erweitern
Ohne die Aufgabe neu zu registrieren, kannst du Trigger nachträglich ergänzen:
$task = Get-ScheduledTask -TaskName "Backup-MitNachhol-Trigger" -TaskPath "\Firma\Automatisierung"
$task.Triggers += New-ScheduledTaskTrigger -Weekly -DaysOfWeek Sunday -At "04:00"
Set-ScheduledTask -InputObject $task
Aufgaben verwalten und überwachen
# Alle Aufgaben im eigenen Ordner anzeigen
Get-ScheduledTask -TaskPath "\Firma\Automatisierung\"
# Aufgabenstatus und letzten Laufzeitpunkt anzeigen
Get-ScheduledTask -TaskName "NaechtlichesBackup" | Get-ScheduledTaskInfo
# Aufgabe manuell starten (zum Testen)
Start-ScheduledTask -TaskName "NaechtlichesBackup" -TaskPath "\Firma\Automatisierung"
# Aufgabe deaktivieren (ohne löschen)
Disable-ScheduledTask -TaskName "NaechtlichesBackup" -TaskPath "\Firma\Automatisierung"
# Aufgabe wieder aktivieren
Enable-ScheduledTask -TaskName "NaechtlichesBackup" -TaskPath "\Firma\Automatisierung"
# Aufgabe löschen
Unregister-ScheduledTask -TaskName "NaechtlichesBackup" -Confirm:$false
Letzten Laufstatus prüfen
$info = Get-ScheduledTask -TaskName "NaechtlichesBackup" | Get-ScheduledTaskInfo
Write-Host "Letzter Start: $($info.LastRunTime)"
Write-Host "Letzter Exitcode: $($info.LastTaskResult)"
Write-Host "Naechster Start: $($info.NextRunTime)"
Exit-Code 0 = Erfolg. Code 0x41301 bedeutet „Aufgabe läuft gerade”. Andere Codes findest du in der Microsoft-Dokumentation oder mit net helpmsg [Dezimalwert].
Automatisches Alerting bei fehlgeschlagenen Aufgaben
Der Task Scheduler meldet Fehler nicht von sich aus – er protokolliert sie nur passiv im Ereignisprotokoll und in Get-ScheduledTaskInfo. Wenn niemand aktiv nachschaut, merkst du ein fehlgeschlagenes Nachtbackup im schlimmsten Fall erst, wenn der Wiederherstellungsfall eintritt. Die robusteste Lösung: ein Wrapper-Skript, das dein eigentliches Skript ausführt, den Erfolg prüft und bei Fehlern aktiv Alarm schlägt.
Wrapper-Skript mit Teams-Webhook und Mail
# C:\Scripts\alert-wrapper.ps1
param(
[Parameter(Mandatory)][string]$ScriptPath,
[string]$TeamsWebhookUrl = "https://firma.webhook.office.com/webhookb2/...",
[string]$MailTo = "it-alerts@firma.ch"
)
$taskName = Split-Path $ScriptPath -Leaf
$logFile = "C:\Logs\$taskName-$(Get-Date -Format 'yyyyMMdd-HHmmss').log"
try {
& $ScriptPath *>&1 | Tee-Object -FilePath $logFile
if ($LASTEXITCODE -and $LASTEXITCODE -ne 0) {
throw "Skript beendet mit Exitcode $LASTEXITCODE"
}
}
catch {
$fehlertext = $_.Exception.Message
# Teams-Webhook (MessageCard-Format)
$body = @{
"@type" = "MessageCard"
"@context" = "http://schema.org/extensions"
themeColor = "FF0000"
summary = "Task fehlgeschlagen: $taskName"
title = "Geplante Aufgabe fehlgeschlagen: $taskName"
text = "**Host:** $env:COMPUTERNAME `n**Zeit:** $(Get-Date -Format 'yyyy-MM-dd HH:mm') `n**Fehler:** $fehlertext"
} | ConvertTo-Json -Depth 4
Invoke-RestMethod -Uri $TeamsWebhookUrl -Method Post -Body $body -ContentType 'application/json'
Send-MailMessage -To $MailTo -From "taskscheduler@firma.ch" -SmtpServer "smtp.firma.ch" `
-Subject "Task fehlgeschlagen: $taskName auf $env:COMPUTERNAME" `
-Body "Fehler: $fehlertext`nLog: $logFile"
exit 1
}
Die geplante Aufgabe ruft nicht mehr backup.ps1 direkt auf, sondern den Wrapper:
$action = New-ScheduledTaskAction -Execute "powershell.exe" `
-Argument "-NonInteractive -ExecutionPolicy Bypass -File `"C:\Scripts\alert-wrapper.ps1`" -ScriptPath `"C:\Scripts\backup.ps1`""
Alternative: Watchdog-Task über das Ereignisprotokoll
Statt jedes Skript in einen Wrapper zu packen, kannst du auch eine separate „Watchdog”-Aufgabe registrieren, die per Ereignistrigger auf Fehler im Task-Scheduler-eigenen Protokoll reagiert (siehe nächster Abschnitt zum Aufgabenverlauf) – etwa auf Ereignis-ID 102 („Aufgabe abgeschlossen”) mit einem Rückgabewert ungleich 0. Das ist zentraler, aber weniger präzise als der Wrapper, weil du im Alarmtext keinen Zugriff auf die eigentliche Fehlermeldung des Skripts hast, sondern nur auf den Exitcode.
schtasks.exe – das Legacy-Werkzeug
Für Batch-Skripte oder wenn du keine PowerShell nutzen kannst, steht schtasks.exe zur Verfügung. Es ist weniger mächtig, aber überall verfügbar.
REM Neue Aufgabe erstellen (täglich um 23:00)
schtasks /create /tn "NaechtlichesBackup" /tr "powershell.exe -File C:\Scripts\backup.ps1" /sc DAILY /st 23:00 /ru SYSTEM /rl HIGHEST /f
REM Alle Aufgaben anzeigen
schtasks /query /fo LIST /v
REM Aufgabe manuell ausführen
schtasks /run /tn "NaechtlichesBackup"
REM Aufgabe löschen
schtasks /delete /tn "NaechtlichesBackup" /f
REM Aufgabe auf Remotecomputer erstellen
schtasks /create /s WS-MUSTER-01 /tn "DailyCheck" /tr "C:\Scripts\check.ps1" /sc DAILY /st 08:00 /ru SYSTEM /f
Praxisbeispiel: Automatisches Logfile-Cleanup
Ein typischer KMU-Use-Case: Der Logs-Ordner einer Applikation füllt sich mit alten .log-Dateien. Du willst Dateien, die älter als 30 Tage sind, automatisch löschen.
Das Skript (C:\Scripts\cleanup-logs.ps1):
$logPfad = "C:\AppLogs"
$maxAlterTage = 30
$cutoff = (Get-Date).AddDays(-$maxAlterTage)
$geloescht = Get-ChildItem -Path $logPfad -Filter "*.log" -File |
Where-Object { $_.LastWriteTime -lt $cutoff }
foreach ($datei in $geloescht) {
Remove-Item $datei.FullName -Force
Write-Output "$(Get-Date -Format 'yyyy-MM-dd HH:mm') - Geloescht: $($datei.Name)"
}
Write-Output "$(Get-Date -Format 'yyyy-MM-dd HH:mm') - Cleanup abgeschlossen. $($geloescht.Count) Dateien entfernt."
Die geplante Aufgabe dazu:
$action = New-ScheduledTaskAction `
-Execute "powershell.exe" `
-Argument "-NonInteractive -ExecutionPolicy Bypass -File `"C:\Scripts\cleanup-logs.ps1`" >> `"C:\Logs\cleanup.log`" 2>&1"
$trigger = New-ScheduledTaskTrigger -Weekly -DaysOfWeek Sunday -At "03:00"
$settings = New-ScheduledTaskSettingsSet `
-ExecutionTimeLimit (New-TimeSpan -Minutes 30) `
-StartWhenAvailable
Register-ScheduledTask `
-TaskName "LogCleanup-AppLogs" `
-TaskPath "\Firma\Wartung" `
-Action $action `
-Trigger $trigger `
-Settings $settings `
-RunLevel Highest `
-User "SYSTEM" `
-Description "Loescht Log-Dateien aelter als 30 Tage jeden Sonntag um 03:00"
Aufgaben als SYSTEM vs. Domänenbenutzer
| Konto | Wann nutzen |
|---|---|
SYSTEM | Lokale Aufgaben, kein Netzwerkzugriff nötig |
NT AUTHORITY\NETWORK SERVICE | Aufgaben mit eingeschränktem Netzwerkzugriff |
DOMAIN\ServiceAccount | Netzlaufwerke, AD-Abfragen, Mail-Versand |
| Lokaler Admin-User | Vermeiden – Passwort in Aufgabe gespeichert, rotiert nicht |
Für Aufgaben, die auf Netzlaufwerke oder Active Directory zugreifen müssen, legst du am besten ein dediziertes Service-Konto in der Domäne an. Dieses Konto bekommt nur die nötigen Rechte und hat „Passwort läuft nie ab” gesetzt. Mehr dazu in Active Directory – Benutzer und Gruppen.
Troubleshooting: Wenn die Aufgabe nicht läuft
Das ist das häufigste Frustrations-Szenario: Manuell klappt es, automatisch nicht. Hier ist die systematische Vorgehensweise:
1. Exit-Code prüfen
Get-ScheduledTask -TaskName "MeineAufgabe" | Get-ScheduledTaskInfo | Select-Object LastRunTime, LastTaskResult
Häufige Exit-Codes:
| Code (Hex) | Bedeutung |
|---|---|
0x0 | Erfolgreich |
0x1 | Allgemeiner Fehler |
0x41301 | Aufgabe läuft gerade |
0x41306 | Aufgabe wurde beendet (Timeout) |
0x8007010B | Verzeichnis ungültig |
0xC000013A | Anwendung wurde beendet (Ctrl+C / Kill) |
2. Event Log prüfen
# Task Scheduler Events der letzten 24 Stunden
Get-WinEvent -LogName "Microsoft-Windows-TaskScheduler/Operational" |
Where-Object { $_.TimeCreated -gt (Get-Date).AddHours(-24) } |
Select-Object TimeCreated, Id, Message |
Format-List
Das Operational-Log des Task Schedulers findest du auch in der Ereignisanzeige unter:
Anwendungs- und Dienstprotokolle > Microsoft > Windows > TaskScheduler > Operational
Mehr zur Ereignisanzeige in Windows Ereignisanzeige.
3. Häufige Fehlerquellen
| Problem | Lösung |
|---|---|
| Skript läuft manuell, nicht automatisch | ExecutionPolicy fehlt im Argument (-ExecutionPolicy Bypass) |
| Relative Pfade funktionieren nicht | Immer absolute Pfade verwenden; Arbeitsverzeichnis (-WorkingDirectory) in der Aktion setzen |
| Aufgabe startet nicht ohne Login | Konto auf SYSTEM oder Domänen-Service-Account ändern |
| Netzlaufwerke nicht erreichbar | SYSTEM hat keinen Netzwerkzugriff; Domänen-Account nutzen |
| Aufgabe übersprungen | -StartWhenAvailable in Settings aktivieren |
| GUI-Fehler bei Passworteingabe | Passwort des Service-Accounts abgelaufen – erneuern |
4. Skript mit vollem Logging testen
# Testlauf: Ausgabe in Datei umleiten, damit du siehst was passiert
Start-ScheduledTask -TaskName "MeineAufgabe"
# Danach Log-Datei prüfen (falls du Redirect im Argument hast)
Get-Content "C:\Logs\meine-aufgabe.log" -Tail 20
Aufgabenverlauf (Task History) aktivieren und vergrössern
Verwirrenderweise ist der Aufgabenverlauf – die Detailhistorie, die du im Reiter „Verlauf” einer markierten Aufgabe siehst – standardmässig deaktiviert. Ohne ihn zeigt dir die GUI bei Problemen nur ein karges „Der Verlauf für diese Aufgabe ist deaktiviert”. Das solltest du auf jeder Maschine ändern, auf der wichtige Automatisierung läuft.
Aktivieren per GUI
In der Aufgabenplanung im rechten Aktionsbereich auf Alle Aufgabenverlaufsdetails anzeigen klicken. Der Menüpunkt wirkt wie ein Filter, aktiviert im Hintergrund aber tatsächlich das zugehörige Ereignisprotokoll.
Aktivieren und dimensionieren per Kommandozeile
REM Verlauf (Operational-Log) aktivieren
wevtutil set-log Microsoft-Windows-TaskScheduler/Operational /enabled:true
REM Aktuelle Konfiguration und Groesse pruefen
wevtutil get-log Microsoft-Windows-TaskScheduler/Operational
REM Maximale Logdatei-Groesse auf 100 MB setzen (Wert in Bytes, Vielfaches von 64 KB)
wevtutil set-log Microsoft-Windows-TaskScheduler/Operational /ms:104857600
REM Aeltere Eintraege ueberschreiben statt das Log bei Erreichen der Groesse einzufrieren
wevtutil set-log Microsoft-Windows-TaskScheduler/Operational /rt:false
Der Standardwert liegt bei nur 1 MB, was bei vielen Aufgaben mit kurzen Intervallen (z.B. alle 15 Minuten) innert Tagen volllaufen kann. 100 MB sind für die meisten KMU-Umgebungen ein guter Kompromiss zwischen Nachvollziehbarkeit und Plattenplatz.
Einmal aktiviert, kannst du den Verlauf sowohl in der GUI (Reiter „Verlauf” bei markierter Aufgabe) als auch per PowerShell auswerten – siehe den Get-WinEvent-Befehl weiter oben im Troubleshooting-Abschnitt.
Task Scheduler als Persistenz- und Angriffsvektor (Security-Audit-Perspektive)
Aus Sicht eines Angreifers ist der Task Scheduler ausgesprochen attraktiv: Eine geplante Aufgabe übersteht Neustarts, sieht auf den ersten Blick aus wie tausende andere legitime Aufgaben im System, und ihre Erstellung erfordert oft nur normale Benutzerrechte – für einen Task, der als SYSTEM läuft, reichen lokale Admin-Rechte. MITRE ATT&CK führt diese Technik als T1053.005 – Scheduled Task und ordnet sie gleich drei Taktiken zu: Execution, Persistence und Privilege Escalation. In der Praxis zählt die Technik zu den am häufigsten dokumentierten Persistenzmechanismen auf Windows-Systemen und wird von zahlreichen bekannten Angreifergruppen eingesetzt.
Typische Angriffsmuster
- Tarnung durch Namensgebung: Aufgaben, die legitime Systemkomponenten imitieren (
GoogleUpdateTaskMachine,MicrosoftEdgeUpdateTaskMachineCoremit leicht abweichender Schreibweise) - Versteckte Aufgaben: Registrierung mit der
Hidden-Eigenschaft (siehe Einstellungen weiter oben) – in der Standardansicht der GUI unsichtbar, erst über „Ansicht > Ausgeblendete Aufgaben anzeigen” sichtbar - Untypische Ausführungspfade: Aktionen, die Skripte aus
%TEMP%,%APPDATA%oder Benutzerprofilen statt ausC:\Program FilesoderC:\Scriptsstarten - Verschleierte PowerShell-Aufrufe:
powershell.exe -enc <Base64>oder-WindowStyle Hidden -NoProfilein der Argumentzeile - Alternative Erstellungswege abseits von
schtasks.exe: direkte COM-Automatisierung,Invoke-CimMethodgegen die WMI-KlassePS_ScheduledTask, oder dienetapi32-Bibliothek – teils gezielt, um simple Kommandozeilen-Überwachung zu umgehen - Weit in der Zukunft liegende Einmal-Trigger („Sleeper Tasks”), die erst nach einer Tarnphase auslösen
Erkennung und Audit
Windows protokolliert Erstellung und Änderung von Aufgaben im Security-Log unter den Ereignis-IDs 4698 (Aufgabe erstellt) und 4702 (Aufgabe aktualisiert) – vorausgesetzt, die erweiterte Überwachungsrichtlinie „Andere Objektzugriffsereignisse” ist aktiviert, was standardmässig nicht der Fall ist:
auditpol /set /subcategory:"Weitere Objektzugriffsereignisse" /success:enable /failure:enable
Danach lassen sich neu angelegte oder geänderte Aufgaben systematisch auswerten:
Get-WinEvent -FilterHashtable @{ LogName = 'Security'; Id = 4698, 4702 } |
Select-Object TimeCreated, Id, `
@{n='Benutzer'; e={ $_.Properties[1].Value }}, `
@{n='Aufgabenname'; e={ $_.Properties[4].Value }} |
Format-Table -AutoSize
Ergänzend hilft das oben aktivierte Microsoft-Windows-TaskScheduler/Operational-Log sowie – auf Endpoints mit entsprechender Ausstattung – Sysmon (Event-ID 1 für Prozessstarts von schtasks.exe oder powershell.exe mit auffälligen Argumenten) und ein EDR-Produkt. Mehr zur zentralen Auswertung solcher Ereignisse in SIEM/SOC – Grundlagen und Incident-Response-Plan für KMU.
| Audit-Checkpunkt | Worauf achten |
|---|---|
| Ersteller vs. Ausführungskonto | Aufgabe von einem Nicht-Admin-Konto erstellt, läuft aber als SYSTEM |
| Aktion | powershell.exe mit -enc, -WindowStyle Hidden oder Download-Cradle (Invoke-WebRequest, IEX) |
| Pfad | Ausführbare Datei/Skript liegt in %TEMP%, %APPDATA% oder einem Benutzerprofil |
| Sichtbarkeit | Hidden-Flag gesetzt, kein Autor/keine Beschreibung |
| Zeitplan | Einmal-Trigger weit in der Zukunft, ungewöhnlich häufige Wiederholung |
| Vergleich zur Baseline | Neue Aufgabe taucht in keiner früheren Inventar-Exportliste auf (siehe Massenverwaltung weiter unten) |
Aufgaben zwischen Maschinen kopieren oder per GPO verteilen
Einzelne Aufgabe exportieren und importieren
# Exportieren (als XML)
Export-ScheduledTask -TaskName "NaechtlichesBackup" -TaskPath "\Firma\Automatisierung" |
Out-File "C:\Temp\NaechtlichesBackup.xml" -Encoding UTF8
# Auf Zielmaschine importieren
Register-ScheduledTask -Xml (Get-Content "C:\Temp\NaechtlichesBackup.xml" -Raw) `
-TaskName "NaechtlichesBackup" `
-TaskPath "\Firma\Automatisierung" `
-Force
Per GPO auf alle Maschinen verteilen
Geplante Aufgaben können per Gruppenrichtlinie auf alle Domänen-Computer ausgerollt werden:
- Gruppenrichtlinien-Verwaltungskonsole öffnen
- GPO bearbeiten >
Computerkonfiguration > Einstellungen > Systemsteuerungseinstellungen > Geplante Aufgaben - Rechtsklick > Neu > Geplante Aufgabe (mindestens Windows 7)
- Alle Parameter wie in der GUI konfigurieren
Mehr zu GPOs in Gruppenrichtlinien – Grundlagen.
Aufgaben per PowerShell auf Remotecomputern verwalten
# Aufgabe auf Remote-PC registrieren
$session = New-PSSession -ComputerName "WS-MUSTER-01" -Credential (Get-Credential)
Invoke-Command -Session $session -ScriptBlock {
$action = New-ScheduledTaskAction -Execute "powershell.exe" `
-Argument "-NonInteractive -ExecutionPolicy Bypass -File C:\Scripts\check.ps1"
$trigger = New-ScheduledTaskTrigger -Daily -At "07:00"
Register-ScheduledTask -TaskName "MorgenCheck" -Action $action -Trigger $trigger `
-RunLevel Highest -User "SYSTEM"
}
Remove-PSSession $session
Für PowerShell-Remoting-Grundlagen schau in PowerShell Scripting – Vertiefung.
Massenverwaltung: Aufgaben auf allen Domänen-Computern inventarisieren
Für Security-Audits ebenso wie für den operativen Überblick lohnt sich ein zentrales Inventar aller geplanten Aufgaben über die ganze Domäne. Der pragmatische Ansatz mit Bordmitteln: alle Computerobjekte aus dem Active Directory holen und pro Rechner per CIM-Session abfragen.
$computers = Get-ADComputer -Filter { Enabled -eq $true } -Properties OperatingSystem |
Where-Object { $_.OperatingSystem -like "Windows 1*" } |
Select-Object -ExpandProperty Name
$ergebnis = foreach ($pc in $computers) {
if (Test-Connection -ComputerName $pc -Count 1 -Quiet) {
try {
$session = New-CimSession -ComputerName $pc -ErrorAction Stop
Get-ScheduledTask -CimSession $session |
Where-Object { $_.TaskPath -notlike "\Microsoft\*" } |
Select-Object @{n='Computer'; e={ $pc }}, TaskName, TaskPath, State, `
@{n='Autor'; e={ $_.Author }}, `
@{n='Aktion'; e={ ($_.Actions.Execute) -join '; ' }}
Remove-CimSession $session
}
catch {
Write-Warning "Keine Verbindung zu $pc : $($_.Exception.Message)"
}
}
}
$ergebnis | Export-Csv -Path "C:\Reports\TaskInventar-$(Get-Date -Format 'yyyyMMdd').csv" `
-NoTypeInformation -Encoding UTF8
Der Filter TaskPath -notlike "\Microsoft\*" blendet die Hunderte von eingebauten Windows-Aufgaben aus und konzentriert den Report auf selbst angelegte oder potenziell fremde Aufgaben. CimSession setzt WinRM auf den Zielrechnern voraus – Details dazu in PowerShell Remoting, PSSession & JEA.
Bei grösseren Flotten lohnt sich ForEach-Object -Parallel (ab PowerShell 7) anstelle der sequenziellen foreach-Schleife, um die Abfrage zu parallelisieren, sowie ein sinnvoller -ThrottleLimit, damit nicht hunderte gleichzeitige CIM-Sessions das Netzwerk fluten.
Den exportierten CSV-Report vergleichst du anschliessend Woche für Woche (z.B. mit Compare-Object) gegen den vorherigen Stand – neue, unbekannte Aufgaben fallen damit sofort auf und liefern die Baseline für den Security-Audit-Abschnitt weiter oben.
| Methode | Reichweite | Voraussetzung |
|---|---|---|
| CimSession-Loop (oben) | Wenige bis mehrere hundert Rechner | WinRM aktiv, Firewall offen für WS-Man |
| GPO-Skript (Anmeldung/Abmeldung) | Alle Domänen-PCs, ohne zentrale Steuerung | Zentrale Ablage, z.B. Freigabe |
| SCCM/Intune Skript-Sammlung | Enterprise-Skalierung, mit Reporting | SCCM- oder Intune-Lizenz |
| SIEM-Abfrage (Security 4698/4702, Sysmon) | Security-Fokus, nahezu in Echtzeit | Log-Forwarding eingerichtet |
Für die Verteilung solcher Inventarisierungs-Skripte über die ganze Flotte siehe SCCM/Intune Softwareverteilung; für die dauerhafte Überwachung von Ergebnissen Monitoring – Grundlagen.
Weiterlernen
- Microsoft Learn: ScheduledTasks PowerShell-Modul (Referenz aller Cmdlets)
- Microsoft Learn: schtasks-Befehlsreferenz
- Microsoft Learn: Aufgabenplanung für Entwickler (Trigger, Aktionen, Bedingungen)
- Microsoft Learn: New-ScheduledTaskSettingsSet (Idle-, Akku- und Netzwerkbedingungen)
- MITRE ATT&CK: T1053.005 – Scheduled Task
- Windows OS Hub: Create Scheduled Tasks with PowerShell (Praxisbeispiele)
- German PowerShell Blog: Geplante Aufgaben erstellen in PowerShell
Kommentare
Frage, Verbesserungsvorschlag oder eigene Erfahrung zu diesem Artikel? Schreib einen Kommentar. Neue Beiträge erscheinen nach kurzer Moderation.
- Lade Kommentare …