Zum Inhalt springen
sw
en

Tippe um zu suchen

Scripting & Automatisierung

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.

20 Min Lesezeit Fortgeschritten Zuletzt aktualisiert:

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:

BausteinFunktion
TriggerWann oder warum die Aufgabe startet (Zeitplan, Ereignis, Login)
AktionWas ausgeführt wird (Programm, Skript, Befehl)
BedingungenZusätzliche Voraussetzungen (z.B. nur bei Netzstrom)
EinstellungenVerhalten bei Fehlern, Timeouts, Retry-Logik

Trigger-Typen im Überblick

TriggerTypischer Einsatz
EinmaligGeplante Migration, einmaliges Update
TäglichNachtbackup, Log-Rotation
WöchentlichWochenbericht, Speicherplatz-Check
MonatlichMonatsabschluss-Export
Beim SystemstartDienst oder Monitoring-Agent starten
Bei BenutzeranmeldungLogin-Skript, Drive-Mapping
Bei LeerlaufRessourcenintensive 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):

  1. Aufgabenplanung öffnen (taskschd.msc)
  2. Rechts auf Aufgabe erstellen… klicken (nicht „Einfache Aufgabe erstellen” – das ist zu eingeschränkt)
  3. Reiter Allgemein:
    • Name vergeben (z.B. Backup-NachtScript)
    • Benutzerkonto auf SYSTEM setzen
    • Mit höchsten Privilegien ausführen aktivieren
    • „Ausführen unabhängig von der Benutzeranmeldung” wählen
  4. Reiter Trigger: Neu > Täglich, Uhrzeit setzen
  5. Reiter Aktionen: Neu > Programm: powershell.exe, Argumente: -NonInteractive -ExecutionPolicy Bypass -File "C:\Scripts\backup.ps1"
  6. Reiter Bedingungen: „Aufgabe nur starten, wenn folgende Netzwerkverbindung verfügbar ist” ggf. aktivieren
  7. 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-OptionPowerShell-ParameterBedeutung
Nur im Netzbetrieb starten(Standard, kein Parameter nötig)Task startet nicht auf Akku
-AllowStartIfOnBatteriesSchalter setzenTask darf auch auf Akku starten
-DontStopIfGoingOnBatteriesSchalter setzenTask läuft weiter, wenn Nutzer den Stecker zieht
Nur im Leerlauf starten-RunOnlyIfIdle + -IdleDurationWartet auf inaktive Tastatur/Maus
Leerlauf-Wartezeit-IdleWaitTimeoutWie lange maximal auf Leerlauf gewartet wird
Bei Leerlaufende weiterlaufen lassen-DontStopOnIdleEndTask 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:

EigenschaftWirkung
Enabled = $falseTrigger bleibt in der Aufgabe erhalten, ist aber deaktiviert – praktisch zum temporären Stilllegen ohne Löschen
StartBoundary / EndBoundaryAufgabe ist nur innerhalb eines Zeitfensters aktiv (z.B. Migrationsphase)
RandomDelayStartzeit wird zufällig gestreut – verhindert, dass hunderte Clients exakt um 08:00 Uhr gleichzeitig einen Server bombardieren
RepetitionInterval + RepetitionDurationWiederholt 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

KontoWann nutzen
SYSTEMLokale Aufgaben, kein Netzwerkzugriff nötig
NT AUTHORITY\NETWORK SERVICEAufgaben mit eingeschränktem Netzwerkzugriff
DOMAIN\ServiceAccountNetzlaufwerke, AD-Abfragen, Mail-Versand
Lokaler Admin-UserVermeiden – 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
0x0Erfolgreich
0x1Allgemeiner Fehler
0x41301Aufgabe läuft gerade
0x41306Aufgabe wurde beendet (Timeout)
0x8007010BVerzeichnis ungültig
0xC000013AAnwendung 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

ProblemLösung
Skript läuft manuell, nicht automatischExecutionPolicy fehlt im Argument (-ExecutionPolicy Bypass)
Relative Pfade funktionieren nichtImmer absolute Pfade verwenden; Arbeitsverzeichnis (-WorkingDirectory) in der Aktion setzen
Aufgabe startet nicht ohne LoginKonto auf SYSTEM oder Domänen-Service-Account ändern
Netzlaufwerke nicht erreichbarSYSTEM hat keinen Netzwerkzugriff; Domänen-Account nutzen
Aufgabe übersprungen-StartWhenAvailable in Settings aktivieren
GUI-Fehler bei PassworteingabePasswort 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, MicrosoftEdgeUpdateTaskMachineCore mit 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 aus C:\Program Files oder C:\Scripts starten
  • Verschleierte PowerShell-Aufrufe: powershell.exe -enc <Base64> oder -WindowStyle Hidden -NoProfile in der Argumentzeile
  • Alternative Erstellungswege abseits von schtasks.exe: direkte COM-Automatisierung, Invoke-CimMethod gegen die WMI-Klasse PS_ScheduledTask, oder die netapi32-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-CheckpunktWorauf achten
Ersteller vs. AusführungskontoAufgabe von einem Nicht-Admin-Konto erstellt, läuft aber als SYSTEM
Aktionpowershell.exe mit -enc, -WindowStyle Hidden oder Download-Cradle (Invoke-WebRequest, IEX)
PfadAusführbare Datei/Skript liegt in %TEMP%, %APPDATA% oder einem Benutzerprofil
SichtbarkeitHidden-Flag gesetzt, kein Autor/keine Beschreibung
ZeitplanEinmal-Trigger weit in der Zukunft, ungewöhnlich häufige Wiederholung
Vergleich zur BaselineNeue 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:

  1. Gruppenrichtlinien-Verwaltungskonsole öffnen
  2. GPO bearbeiten > Computerkonfiguration > Einstellungen > Systemsteuerungseinstellungen > Geplante Aufgaben
  3. Rechtsklick > Neu > Geplante Aufgabe (mindestens Windows 7)
  4. 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.

MethodeReichweiteVoraussetzung
CimSession-Loop (oben)Wenige bis mehrere hundert RechnerWinRM aktiv, Firewall offen für WS-Man
GPO-Skript (Anmeldung/Abmeldung)Alle Domänen-PCs, ohne zentrale SteuerungZentrale Ablage, z.B. Freigabe
SCCM/Intune Skript-SammlungEnterprise-Skalierung, mit ReportingSCCM- oder Intune-Lizenz
SIEM-Abfrage (Security 4698/4702, Sysmon)Security-Fokus, nahezu in EchtzeitLog-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

Kommentare

Frage, Verbesserungsvorschlag oder eigene Erfahrung zu diesem Artikel? Schreib einen Kommentar. Neue Beiträge erscheinen nach kurzer Moderation.

  • Lade Kommentare …
Kommentar schreiben