PowerShell-Skripte mit dem Windows Task Scheduler planen
Alles hat seine Zeit
von Philip Lorenz
Veröffentlicht in Ausgabe 04/2024 - PRAXIS
Mit der PowerShell sind Administratoren in der Lage, repetitive und zeitintensive Aufgaben zu automatisieren und die Genauigkeit und Konsistenz von Administrationsaufgaben zu verbessern. Das Herzstück einer solchen Automatisierung ist das Planen und Verwalten der Skripte. Über den Windows Task Scheduler ist die Ausführung von Skripten zu definierten Zeiten oder bei spezifischen Ereignissen möglich. Das Duo PowerShell und Task Scheduler bildet eine leistungsstarke Kombination, um die Administration zu automatisieren und zu optimieren.
Der Windows Task Scheduler (WTS) ist ein leistungsfähiges, in Windows integriertes Tool, das die Ausführung von Tasks (Aufgaben) automatisiert. Es ermöglicht Administratoren, Skripte oder Programme zu bestimmten Zeiten oder bei bestimmten Ereignissen automatisch auszuführen. Im Zusammenspiel mit PowerShell-Skripten lassen sich verschiedene Tasks gänzlich im Hintergrund durch ein effizientes Task Scheduling abbilden. Beispiele hierfür sind regelmäßige Reports über die Lizenzauslastung in M365-Umgebungen, das Logging von Anmeldungen von Admin-Accounts auf Windows-Servern oder eine automatische E-Mail-Benachrichtigung bei der Sperrung eines Active-Directory-Kontos nach zu vielen fehlerhaften Anmeldeversuchen.
Funktionen des Task Schedulers
Der Task Scheduler ermöglicht es, Aufgaben zu planen, sei es basierend auf Zeitplänen (täglich, wöchentlich, monatlich) oder auf Ereignisauslösern (beispielsweise beim Start des Systems oder bei der Anmeldung eines Benutzers). Diese Aufgaben können durch eine Vielzahl von Ereignissen ausgelöst werden und unterschiedliche Aktionen ausführen, einschließlich der Ausführung von PowerShell-Skripten. Dabei kann der Task Scheduler Aufgaben im Vordergrund (mit Benutzerinteraktion) oder im Hintergrund (ohne Benutzerinteraktion) ausführen.
Die Vorteile der Verwendung des Task Schedulers sind:
Der Windows Task Scheduler (WTS) ist ein leistungsfähiges, in Windows integriertes Tool, das die Ausführung von Tasks (Aufgaben) automatisiert. Es ermöglicht Administratoren, Skripte oder Programme zu bestimmten Zeiten oder bei bestimmten Ereignissen automatisch auszuführen. Im Zusammenspiel mit PowerShell-Skripten lassen sich verschiedene Tasks gänzlich im Hintergrund durch ein effizientes Task Scheduling abbilden. Beispiele hierfür sind regelmäßige Reports über die Lizenzauslastung in M365-Umgebungen, das Logging von Anmeldungen von Admin-Accounts auf Windows-Servern oder eine automatische E-Mail-Benachrichtigung bei der Sperrung eines Active-Directory-Kontos nach zu vielen fehlerhaften Anmeldeversuchen.
Funktionen des Task Schedulers
Der Task Scheduler ermöglicht es, Aufgaben zu planen, sei es basierend auf Zeitplänen (täglich, wöchentlich, monatlich) oder auf Ereignisauslösern (beispielsweise beim Start des Systems oder bei der Anmeldung eines Benutzers). Diese Aufgaben können durch eine Vielzahl von Ereignissen ausgelöst werden und unterschiedliche Aktionen ausführen, einschließlich der Ausführung von PowerShell-Skripten. Dabei kann der Task Scheduler Aufgaben im Vordergrund (mit Benutzerinteraktion) oder im Hintergrund (ohne Benutzerinteraktion) ausführen.
Die Vorteile der Verwendung des Task Schedulers sind:
- Zeitersparnis: Automatisieren Sie wiederkehrende Aufgaben und sparen Sie wertvolle Zeit.
- Zuverlässigkeit: Gewährleisten Sie die regelmäßige und genaue Ausführung von Aufgaben.
- Flexibilität: Planen Sie Aufgaben für Zeiten geringer Systemauslastung, um die Performance nicht zu beeinträchtigen.
Auf Windows-Systemen dient WTS als zentrales Tool zur Steuerung von Tasks und Jobs und stellt damit eine Alternative zu Linux-Tools wie crontab oder systemd Service Units dar.
Planung mit dem Task Scheduler
Um PowerShell-Skripte mit dem Task Scheduler zu planen, gibt es verschiedene Möglichkeiten. Sie können diese klassisch über die grafische Oberfläche, aber beispielsweise auch mittels der PowerShell selbst anlegen. Wir stellen beide Möglichkeiten vor.
Doch bevor wir damit beginnen den Task anzulegen, benötigen wir ein PowerShell-Skript, das durch den Task angestoßen werden soll. Für den initialen Test-Lauf eignet sich folgendes Skript, das wir unter "C:\ps\scheduledtask\logger.ps1" speichern:
powershell
$dump = @()
$dump += (Get-Date).ToString("HH:mm:ss")
$dump += (Get-Location).Path
$dump += ""
$dump | Out-File "C:\dump\test.log" -Append
Das Skript schreibt die Uhrzeit sowie den aktuellen Pfad in die angegebene Datei. Durch den Append-Parameter erfolgt dies fortlaufend, sodass das Skript den Inhasondern die Informationen unten hinzufügt. Dieses Vorgehen bietet sich deshalb an, weil der WTS die Ausführung des Tasks als erfolgreich deklarieren könnte, obwohl das eigentliche Skript nicht gelaufen ist. Anhand des Schreibzugriffs auf "test.log" ist ein Ausführungscheck recht simpel.
Zudem sollten Sie das Ausführungsverzeichnis beachten, denn es ist ein Irrglaube, dass Skripte automatisch aus ihrem Speicherort starten.
Werfen wir aber einen Blick in "C:\dump\ test.log", in das neben der Zeit auch das aktuelle Verzeichnis geschrieben wird, stellen wir fest, dass das Skript aus "C:\ Windows\system32" startet. Um Probleme mit relativen Pfaden zu vermeiden, empfiehlt sich der Kontextwechsel in das Skript-Verzeichnis. Dies erreichen Sie einfach mit der Umgebungsvariable "$PS- ScriptRoot". Diese beinhaltet immer den Verzeichnispfad des aktuell ausgeführten Codes und es empfiehlt sich, zu Beginn mit dorthin zu wechseln.
Bild 1: Im Windows Task Scheduler lassen sich neue Aufgaben über einen Assistenten anlegen.
Scheduled Tasks über die GUI
Den WTS finden Sie über die Windows-Suche und starten ihn direkt von dort. Über die Navigationsleiste auf der linken Seite öffnen Sie die Task Scheduler Library, um einen Überblick auf bereits bestehende Tasks zu erhalten. Es ist möglich weitere Verzeichnisse für Tasks anzulegen, um diese logisch zu segmentieren. Über den Button "Create Task" legen Sie einen neuen Scheduled Task an. Der zugehörige Wizard ermöglicht eine detaillierte Konfiguration des neuen Tasks. Für PowerShell-Tasks ist es wichtig den entsprechenden Benutzer auszuwählen, denn das PowerShell-Skript wird im Kontext dieses Benutzers ausgeführt. Fragt das Skript also beispielsweise Ressourcen auf einem Domaincontroller ab, müssen Sie einen Benutzer selektieren, der die notwendigen Berechtigungen besitzt.
Zudem sollte das Feld "Run whether user is logged on or not" aktiviert sein, um sicherzustellen, dass die Tasks im Hintergrund starten. Im Tab "Triggers" definieren Sie verschiedene Bedingungen für Ihr Skript, die wichtigsten Trigger sind dabei:
- On a schedule: Die Ausführung des Skripts folgt einem festen Zeitplan. Dieser Trigger ist unter anderem für das regelmäßige Erstellen von Berichten oder die Durchführung von Backup-routinen sinnvoll.
- On an event: Dieser Trigger ist an das Windows-Eventlog geknüpft. Sobald ein vordefiniertes Event auftritt, startet der Task. So ist es beispielsweise möglich, eine E-Mail zu versenden, wenn ein Benutzerkonto gesperrt wurde.
Um zu konfigurieren, dass der Scheduled Task ein Skript ausführt, müssen Sie im Reiter "Action" eine ebensolche erstellen. Dazu wählen Sie "Start a Program" und als Programm tragen Sie lediglich "powershell" ein. Das auszuführende Skript konfigurieren Sie über das Feld "Add Arguments". Die Angabe erfolgt dabei in der Form"-File C:\ps\scheduledtask\logger.ps1".
Nach dem Speichern der Konfiguration führen Sie den Task testweise über einen Rechtklick und "Run" aus. Anschließend sollte der Task Scheduler die aktuelle Zeit als "Last Run Time" und den Statuscode "0x0" bei "Last Run Result" anzeigen. Ob auch das PowerShell-Skript sauber durchgelaufen ist, können Sie über die Logdatei "test.log" validieren.
Scheduled Tasks im Cluster-Modus
Scheduled Tasks lassen sich auch Cluster-gesteuert via Register-ClusteredScheduledTask einsetzen. Die Vorteile sind:
- Hochverfügbarkeit: Geplante Aufgaben können bei Ausfall eines Knotens auf einem anderen fortgesetzt werden.
- Failover-Fähigkeit: Bei einem Knotenausfall verlagert sich die Aufgabe automatisch.
- Zentralisiertes Management: Ermöglicht die Verwaltung von Aufgaben im gesamten Cluster.
- Einheitliche Konfiguration: Stellt konsistente Konfigurationen über alle Knoten sicher.
- Verbesserte Skalierbarkeit: Lastverteilung auf mehrere Knoten.
Für die Nutzung benötigen Sie ein bestehendes Cluster:
# Initialisierung der benutzerdefinierten Variablen
$taskName = "pwsh-test"
$taskType = "ClusterWide"
$clusterName = "Cluster01"
<#
...
Anlage von Trigger, Pricipal und Action
...
#>
# Registrieren des Tasks
$registerParams = @{
TaskName = $taskName
TaskType = $taskType
Cluster = $clusterName
Trigger = $trigger
Principal = $principal
Action = $action
}
Register-ClusteredScheduledTask
@registerParams
Geplante Aufgaben via PowerShell anlegen
Ein deutlich charmanterer Weg, um Scheduled Tasks anzulegen, ist die Konfiguration in der PowerShell selbst. Dafür sprechen mehrere Aspekte. Zum einen dient der Code selbst als Dokumentation. Setzen Sie darüber hinaus auch eine Versionsverwaltung wie Git ein, können Sie jederzeit auf die Historie und Änderungen an der Konfiguration zurückgreifen. Zusätzlich ist der Task gleichzeitig auf mehreren Systemen ausrollbar, sofern notwendig. Für dieses Vorgehen stehen Ihnen spezielle Cmdlets zur Verfügung, die die Tabelle "Cmdlets für WTS" zeigt. Das Erstellen eines Scheduled Tasks benötigt dabei eine Kombination mehrerer Befehle, wie im Listing 1 zu sehen.
Listing 1: Eine geplante Aufgabe in der PowerShell definieren
t# Initialisierung der benutzerdefinierten Variablen
$taskName = "<pwsh-test"
$scriptPath = "<C:\ps\scheduledtask\logger.ps1"
$startTime = "<3am"
$userId = "<Benutzername>"
$randomDelayMinutes = 30
$daysInterval = 2
# Erstellen des Triggers
$triggerParams = @{
At = $startTime
Daily = $true
DaysInterval = $daysInterval
} $
trigger = New-ScheduledTaskTrigger @triggerParams
# Festlegen der Benutzerkontexteinstellungen
$principalParams = @{
UserId = $userId
RunLevel = 'Highest'
} $
principal = New-ScheduledTaskPrincipal @principalParams
# Erstellen der Aktion
$actionParams = @{
Execute = "Powershell.exe"
Argument = "-File $scriptPath"
} $
action = New-ScheduledTaskAction @actionParams
# Registrieren des Tasks
$registerParams = @{
TaskName = $taskName
Trigger = $trigger
Principal = $principal
Action = $action
} Register-ScheduledTask @registerParams
Der Code startet mit dem Deklarieren und Initialisieren benutzerdefinierter Variablen. Dann nutzen wir das sogenannte Splatting, das für jeden Schritt des Prozesses (Trigger, Aktion, ausführender Benutzer, Registrierung) Hashtabellen erstellt, die alle notwendigen Parameter enthalten. Diese Hashtabellen werden dann mit dem @-Symbol an die jeweiligen Cmdlets übergeben. Anschließend wird der Task mit dem angegebenen Namen, Trigger, Aktion und Einstellungen registriert, wobei Splatting für eine saubere und übersichtliche Übergabe der Parameter sorgt. Weiterführende Informationen zu den Scheduled-Task-Cmdlets können Sie online via abrufen.
Bild 2: Für PowerShell-Skripte sind im Windows Task Scheduler nur wenige Parameter zu hinterlegen.
Abgrenzung von Scheduled-Jobs
Scheduled-Jobs in PowerShell sind eine alternative Möglichkeit, Aufgaben zu planen, die sich von den hier vorgestellten Scheduled Tasks unterscheiden. Sie sindspeziell für PowerShell-Umgebungen konzipiert und bieten einige Vorteile, insbesondere in Bezug auf die Handhabung von PowerShell-spezifischen Funktionen. Ein Scheduled-Job ist eine PowerShell-Hintergrundaufgabe, die zu einem vordefinierten Zeitpunkt oder in regelmäßigen Intervallen läuft. Diese Jobs sind mit der PowerShell integriert und können PowerShell-Cmdlets, Funktionen und Skripte direkt nutzen, ohne dass externe Prozesse wie powershell.exe starten müssen. Ein Beispiel für einen solchen Scheduled-Job:
Scheduled Jobs unterscheiden sich dabei wie erwähnt von Scheduled Tasks, dass sie PowerShell-Cmdlets und -Skripte nativ ausführen können. Scheduled Tasks hingegen starten meist einen externen Prozess, um den PowerShell-Code auszuführen. Zudem bieten sie eine höhere Benutzer- freundlichkeit, sofern Sie mit der PowerShell bereits gut vertraut sind. Auch bieten sie mehr Flexibilität und Konfigurationsoptionen, wie beispielsweise das Ausführen unter verschiedenen Benutzerkonten und erweiterte Einstellungen zur Energieverwaltung. Sie sind zudem nicht auf die PowerShell beschränkt und können beliebige Programme oder Skripte starten. Schließlich sind Scheduled Tasks tief im Windows-Betriebssystem verankert und können unabhängig von derPowerShell zum Einsatz kommen. Scheduled Jobs hingegen sind spezifisch für die PowerShell und setzen deren Vorhandensein auf dem System voraus.
Insgesamt sind Scheduled Jobs ideal für Szenarien, in denen Sie sich auf PowerShell-Skripte und -Cmdlets konzentrieren, während Scheduled Tasks besser geeignet sind, wenn eine umfassendere Systemintegration oder die Ausführung nicht PowerShell-bezogener Aufgaben erforderlich ist.
Auf die Sicherheit achten
Vor dem Anlegen eines Scheduled Tasks sollten Sie verschiedene Aspekte bezüglich der Sicherheit evaluieren. Das PowerShell-Skript läuft immer im Kontext des angegebenen Users. Ein Gefahrenpotenzial liegt dabei darin, einen Superuser zu züchten, der iterativ immer mehr Berechtigungen erhält. Stattdessen sollten Sie bereits zu Beginn verschiedene Benutzer anlegen, auf die Sie die Berechtigungen verteilen.
Zudem sollten Sie das ausführende System beziehungsweise den Ablageort der Skripte ausreichend sichern. Andernfalls besteht die Möglichkeit, dass Dritte den hinterlegten Code austauschen oder manipulieren und dieser anschließend durch den Scheduled Task mit dem hinterlegten Benutzer ausgeführt wird.
Selbstverständlich sollten Monitoring und Logging hier ebenfalls eine Rolle spielen. Dabei ist das Standard-Logging des Task Schedulers oft unzureichend. Erweitern Sie es durch ein Log via PowerShell, etwa mit dem Transcript-Feature und den Start-Transcript- und Stop-Transcript-Cmdlets oder fortgeschrittenen Tools wie dem PSFramework-Modul. So können Sie den Erfolg und eventuelle Fehler der Task-Ausführung besser nachvollziehen.
Cmdlets für WTS
New-ScheduledTaskTrigger
Neuen Auslöser für eine geplante Aufgabe erstellen.
New-ScheduledTaskAction
Neue Aktion für eine geplante Aufgabe anlegen.
Register-ScheduledTask
Neue geplante Aufgabe auf dem lokalen Computer registrieren.
Get-ScheduledTask
Informationen über eine Aufgabe abrufen.
Set-ScheduledTask
Bestehenden Task modifizieren.
Start-ScheduledTask
Aufgabe manuell starten.
Stop-ScheduledTask
Task manuell stoppen.
Unregister-ScheduledTask
Eine geplante Aufgabe vom lokalen Computer entfernen.
Disable-ScheduledTask
Deaktiviert einen Scheduled Task.
Enable-ScheduledTask
Aktiviert eine geplante Aufgabe.
Umgang mit Parametern
Übergabeparameter sind eine Best Prac-tice und vermeiden fest im Code verankerte Werte. Stattdessen nimmt das Skript die variablen Werte wie Servernamen oder Konfigurationsparameter von außen entgegen. Für Skripte, die Sie über WTS anstoßen, gibt es grundsätzlich zwei Optionen, diese Werte außerhalb des Codes zu verwalten: die Parameter-Felder im Task Scheduler und die Konfigurationsdateien. Ersteres erfordert eine deutlich unkompliziertere Implementierung, wie Listing 2 zeigt.
# Task-Informationen mit Splatting für New-ScheduledTaskAction
$actionParams = @{
Execute = "Powershell.exe"
Argument = "`"$scriptPath`" $parameters"
}
$action = New-ScheduledTaskAction @actionParams
<#
...
Anlage von Trigger und Action
...
#>
# Splatting für Register-ScheduledTask
$taskParams = @{
TaskName = "MeinScheduledTask"
Action = $action
Trigger = $trigger
Principal = $principal
}
Register-ScheduledTask @taskParams
Trotz der simplen Implementierung sollten Sie dieses Vorgehen weitestgehend vermeiden, da es zwei entscheidende Nachteile mit sich bringt: Zwar stellt das Skript selbst quasi eine Konfiguration dar, dennoch müssen Sie die Parameter darin pflegen, was nicht Best Practices entspricht. Zudem gestaltet sich die Verwaltung der Parameter durch den Aufbau deutlich unübersichtlicher.
Eine bessere Option ist die Übergabe von Parametern über ein Konfigurationsfile. Dieses können Sie flexibel gestalten und es bietet sich an, Standards wie INI, JSON oder XML zu verwenden. Ein solche Datei lässt sich auf dem ausführenden Server hinterlegen und durch das Skript auslesen, das Sie über den Scheduled Task ansprechen.
Lastverteilung
Die Cmdlets zum Registrieren eines Scheduled Task bieten eine Vielzahl von Parametern, die einen positiven Einfluss auf die Systemauslastung des ausführenden Hosts nehmen. So sorgen Sie über den RandomDelay-Parameter des New-ScheduledTaskTrigger-Befehls für eine randomisierte Verzögerung. Dies ist hinsichtlich des Loadbalancings sinnvoll, sodass nicht beispielsweise 3 Uhr morgens mehrere Tasks gleichzeitig starten, sondern sich die Ausführung dieser Tasks auf den Zeitraum von 3 bis 3:30 Uhr verteilt.
Der Parameter "MultipleInstances" -ScheduledTaskSettingsSet-Cmdlets sorgt dafür, dass mehrere Instanzen desselben Tasks nicht gleichzeitig laufen, sondern in Reihe ausgeführt werden. Dieses Queueing bezieht sich dabei lediglich auf den Task "pwsh-test". Ein solchen Vorgehen ist gerade dann sinnvoll, wenn ein mehrstufiges Skript mit langer Laufzeit in der Lage wäre, sich selbst zu sabotieren, beispielsweise wenn zu Beginn eine Logdatei bereinigt und während der Laufzeit befüllt wird. Sollte eine zweite Instanz des Skripts starten, sorgt dies für Probleme bei der Bereinigung der Logdatei durch die Schreibzugriffe der ersten Instanz.
Fazit
Der Windows Task Scheduler in Kombination mit PowerShell-Skripten bietet einen effizienten Weg, um alltägliche IT-Aufgaben zu automatisieren und zu optimieren. Der Task Scheduler bietet dabei eine flexible und zuverlässige Plattform, um diese Skripte nach einem definierten Zeitplan oder in Reaktion auf bestimmte Ereignisse auszuführen.
Die Integration von PowerShell-Skripten mit dem Task Scheduler ermöglicht es, komplexe Aufgaben wie das Erstellen regelmäßiger Berichte, das Monitoring von Systemereignissen oder das Durchführen von Wartungsaufgaben zu automatisieren. Durch das Berücksichtigen von Best Practices und das Vermeiden gängiger Fehler, wie der Vernachlässigung von Berechtigungen, der Auswahl des richtigen Ausführungsverzeichnisses oder der effizienten Parameterübergabe, können Administratoren sicherstellen, dass ihre geplanten Aufgaben reibungslos und ohne unerwünschte Überraschungen ablaufen.