Inhalt
- Benutzerdefinierte Windows-Dienste erstellen und verwalten
- Hintergrundwissen
- 1. Grundlagen: Was sind Windows-Dienste?
- 2. Vorteile benutzerdefinierter Dienste
- 3. Verfügbare Tools und Methoden zum Erstellen von Diensten
- 4. Erstes Beispiel: PowerShell-Dienst erstellen (Grundgerüst)
- 5. Wichtige Befehle zur Dienstverwaltung (PowerShell)
- 6. Neustartverhalten bei Fehlern konfigurieren
- 7. Integration mit Aufgabenplanung
- 8. Sicherheit: Dienstkonten und Berechtigungen
- 9. Abhängigkeiten definieren
- 10. Fehlerprotokollierung und Debugging
- 11. Praxisnahe Einsatzbereiche
- 10 sinnvolle, praxinahe Beispiele zum Schreiben eigener PowerShell-Dienste
- Beispiel 1: Einfache CPU-Überwachung
- Beispiel 2: Automatische SQL-Datenbank-Backups
- Beispiel 3: Log-Archivierung mit Kompression
- Beispiel 4: Netzwerkfreigabe-Überwachung (Ping-Monitor)
- Beispiel 5: Automatische Firewallregel-Aktualisierung
- Beispiel 6: Automatischer Shutdown bei Inaktivität
- Beispiel 7: E-Mail-Warnung bei wenig Festplattenspeicher
- Beispiel 8: Zentrales Eventlog-Forwarding (Syslog)
- Beispiel 9: Registry-Bereinigung
- Beispiel 10: Datenkollektion für ein Custom-Dashboard
- Erweiterte Hinweise & Best Practices
- Weitere Quellen
Benutzerdefinierte Windows-Dienste erstellen und verwalten
Hintergrundwissen
Viele Windows-Nutzerinnen und -Nutzer – ob privat oder im Unternehmensumfeld – stoßen früher oder später auf die Notwendigkeit, Aufgaben automatisiert im Hintergrund ausführen zu lassen, ohne dass jemand konstant davor sitzt oder unmittelbar eingreift. Genau hier kommen die Windows-Dienste (Services) zum Einsatz: Sie ermöglichen es, Skripte oder Anwendungen „unsichtbar“ auszuführen, vom Systemstart an und unabhängig davon, ob ein Benutzer angemeldet ist.
Diese Funktionalität erweist sich als überaus nützlich für permanent laufende Überwachungsaufgaben, das Erfassen von Daten, wiederkehrende Backups, Protokollanalysen und viele weitere Szenarien, bei denen ein dauerhafter Hintergrundprozess wünschenswert ist. In diesem Artikel wird zunächst erläutert, was Windows-Dienste ausmacht, warum sie so wertvoll sind und welche Tools Microsoft (und die Community) zum Erstellen und Verwalten bereitstellen. Anschließend wird anhand einer Reihe konkreter, praxisnaher Beispiele aufgezeigt, wie man eigene Dienste mit PowerShell schreibt und produktiv betreibt.
Der Artikel richtet sich sowohl an ambitionierte Privatanwenderinnen und -anwender, die regelmäßig mit PowerShell arbeiten, als auch an erfahrene Administratorinnen und Administratoren, die Automatisierungsprozesse im Unternehmen einführen oder verbessern möchten. Viele der Hinweise basieren auf offiziellen Microsoft-Dokumenten, Community-Erfahrungen und jahrelanger Praxis in IT-Umgebungen verschiedenster Größenordnungen.
1. Grundlagen: Was sind Windows-Dienste?
Windows-Dienste sind spezielle Programme, die in einem eigenständigen Kontext ausgeführt werden und keinen direkten Benutzer benötigen. Sie starten oft bereits beim Hochfahren des Systems oder zu einem frei definierten Zeitpunkt, können ebenfalls angehalten und neu gestartet werden, ohne dass sich jemand anmeldet. Insbesondere in Server-Umgebungen, aber auch auf Workstations, ist das essenziell: So kann z. B. ein Dienst dazu dienen, regelmäßig bestimmte Dateien zu sichern, Netzwerkverbindungen zu testen, Systemupdates zu koordinieren oder mehrere Prozesse gleichzeitig zu steuern.
Das Betriebssystem bringt von Haus aus bereits zahlreiche Dienste mit (z. B. den Windows Update-Dienst, den Druckerwarteschlangendienst oder den Ereignisprotokolldienst). Der Clou: Man darf auch selbst Dienste erstellen, um die Automatisierung flexibler und leistungsfähiger zu gestalten. PowerShell bietet hierfür verschiedene Cmdlets – allen voran
New-Service
,
Start-Service
,
Stop-Service
,
Set-Service
und andere.
2. Vorteile benutzerdefinierter Dienste
1. Kontinuierliche Ausführung: Ein Dienst kann dauerhaft aktiv sein, selbst wenn niemand an der Maschine sitzt oder eingeloggt ist.
2. Früher Systemstart: Dienste können bereits unmittelbar nach Systemstart loslegen, auch noch vor einer Benutzeranmeldung.
3. Zuverlässigkeit: Sie lassen sich so konfigurieren, dass sie bei Fehlern automatisch neu starten oder andere Aktionen ausführen (z. B. Protokollierung).
4. Sicherheit: Wenn man mit einem dedizierten Dienstkonto (Service Account) arbeitet, sind die Rechte klar definiert. Das ist sicherer, als ein Skript jedes Mal mit hohen Privilegien von Hand auszuführen.
5. Zentralisierte Verwaltung: Über Dienste kann man in Netzwerken sehr viel automatisieren und orchestrieren.
3. Verfügbare Tools und Methoden zum Erstellen von Diensten
Windows selbst liefert verschiedene Werkzeuge mit, um Dienste anzulegen und zu konfigurieren:
PowerShell:
New-Service
: Legt einen neuen Dienst an.Remove-Service
: Löscht einen existierenden Dienst.Set-Service
: Ändert Parameter eines Dienstes wie Starttyp oder Anmeldekonto.
sc.exe (Service Controller):
- Ein Kommandozeilentool, das schon sehr lange unter Windows existiert und manuell oder in Batch-Skripten genutzt werden kann.
- Beispiel:
sc create MeinDienst binPath= "C:\path\to\programm.exe" start= auto
NSSM (Non-Sucking Service Manager):
- Ein beliebter Community-Weg, um selbst geschriebene Skripte (PowerShell, Python, Java etc.) als Dienst einzurichten.
- Vereinfacht das Handling und bietet u. a. eine übersichtliche GUI für die Konfiguration.
.NET und Visual Studio:
- Wer eine eigene Anwendung (z. B. in C#) schreibt, kann direkt auf die
ServiceBase
-Klasse zurückgreifen und so professionelle Windows-Dienste entwickeln.
Im Fokus dieses Artikels steht PowerShell, weil es schnell und unkompliziert ist, vorhandene Skripte in Form eines Windows-Dienstes laufen zu lassen.
4. Erstes Beispiel: PowerShell-Dienst erstellen (Grundgerüst)
Ein klassisches PowerShell-Beispiel für die Erstellung eines neuen Dienstes lautet:
New-Service -Name "MeinDienst" -BinaryPathName "C:\Scripts\MeinScript.ps1" -DisplayName "Mein PowerShell Dienst" -StartupType Automatic
Dieses Fragment erstellt formal einen Dienst namens „MeinDienst“. Allerdings werden PowerShell-Skripte nicht immer problemlos als Dienstprozesse anerkannt, da üblicherweise ein eigenständiges ausführbares Programm (EXE) erwartet wird. Man muss daher ggf. den Aufruf über powershell.exe -File "C:\Scripts\MeinScript.ps1"
als Parameter angeben. Alternativ setzt man auf Tools wie NSSM, die diesen Zwischenschritt automatisch für einen übernehmen.
5. Wichtige Befehle zur Dienstverwaltung (PowerShell)
Start-Service -Name "MeinDienst"
: Dienst starten.Stop-Service -Name "MeinDienst"
: Dienst anhalten.Restart-Service -Name "MeinDienst"
: Dienst neu starten (praktisch, wenn Konfigurationen geändert wurden).Get-Service -Name "MeinDienst"
: Liefert Informationen zum Dienststatus.
Darüber hinaus kann man mit Set-Service
den Starttyp ändern, z. B. Set-Service -Name "MeinDienst" -StartupType Manual
. Über Windows lässt sich dasselbe in der Dienste-Verwaltungskonsole services.msc
erledigen.
6. Neustartverhalten bei Fehlern konfigurieren
Gerade in produktiven Umgebungen ist es wichtig, das Wiederherstellungsverhalten einzustellen. Windows-Dienste können beispielsweise beim ersten Fehler, zweiten Fehler oder dritten und weiteren Fehlern automatisch neugestartet werden. Auch das Ausführen eines eigenen Programms oder das Erstellen eines Ereignisprotokolleintrags ist möglich.
Diese Optionen findet man entweder in services.msc
unter den Eigenschaften des jeweiligen Dienstes (Registerkarte „Wiederherstellung“) oder konfiguriert sie über Gruppenrichtlinien. So stellt man sicher, dass ein Dienst, der für den Geschäftsbetrieb essenziell ist, bei einer Störung automatisiert wieder angelaufen wird.
7. Integration mit Aufgabenplanung
Die Windows-Aufgabenplanung (Task Scheduler) ermöglicht ebenfalls, bestimmte Aktionen zeit- oder ereignisgesteuert auszuführen. Sie kann zudem genutzt werden, um Dienste zu starten oder zu stoppen, beispielsweise nach definierten Arbeitszeiten oder bei bestimmten Events (z. B. Login/Logout).
Mancherorts reicht es bereits aus, ein Skript über den Task Scheduler zu starten. Doch wenn ein dauerhafter, residenter Prozess benötigt wird, ist ein Dienst oft die stabilere Lösung.
8. Sicherheit: Dienstkonten und Berechtigungen
Ein wichtiger Aspekt bei Windows-Diensten ist das Anmeldekonto, unter dem sie laufen. Das Standardkonto „Lokales System“ hat weitreichende Privilegien. Für eigene Dienste empfiehlt es sich meist, ein spezielles Dienstkonto (bspw. einen eigenen lokalen Benutzer) mit minimal nötigen Rechten einzurichten. So minimiert man Risiken bei Kompromittierungen und hält das Berechtigungskonzept schlank.
9. Abhängigkeiten definieren
Muss ein eigener Dienst erst dann starten, wenn ein anderer Dienst (z. B. Netzwerk, Datenbank) bereits läuft, legt man eine Dienstabhängigkeit fest. Somit verhindert man Startfehler, die entstehen, wenn eine benötigte Ressource noch nicht bereitsteht.
In der Registry ist das unter HKLM\SYSTEM\CurrentControlSet\Services\<Dienstname>\DependOnService
hinterlegt. Oder man nutzt Tools wie sc.exe config MeinDienst depend= "NetMan"
usw.
10. Fehlerprotokollierung und Debugging
Eigene Skripte sollte man so schreiben, dass sie Fehlermeldungen protokollieren. Unter PowerShell kann man beispielsweise Write-EventLog
verwenden, um Einträge ins Eventlog zu senden. Alternativ können Logs auch in eine Datei geschrieben werden, was bei umfangreichen Debug-Informationen hilfreich ist.
Besonders in Umgebungen mit vielen Diensten ist eine gute Logstrategie wertvoll. So sieht man sofort, wann und warum ein Dienst ausfällt oder seine Aufgabe nicht erfüllt.
11. Praxisnahe Einsatzbereiche
- Monitoring (CPU, RAM, Netzwerk, Freigaben)
- Dateiverarbeitung (Archivierung, Kompression, Migration)
- Automatische Database-Jobs (Backup, Wartung)
- Alarmierungen per E-Mail (Low-Disk-Space, Zugriffsfehler)
- Konfigurationsanpassungen (Registry, Firewallregeln)
- Sammeln von Eventlog-Einträgen (zentrales Logging)
Im Folgenden werden nun zehn konkrete Beispiele für PowerShell-Skripte vorgestellt, die sich als Dienste eignen. Jedes Beispiel skizziert ein potenzielles Szenario, von simpel bis anspruchsvoll, und zeigt das grundlegende Skriptgerüst samt Vorgehen zum Registrieren als Dienst.
10 sinnvolle, praxinahe Beispiele zum Schreiben eigener PowerShell-Dienste
(Ergänzend zum allgemeinen Teil; die Skripte selbst werden nicht in die Textlänge eingerechnet.)
Jedes dieser Beispiele kann direkt in eine .ps1
-Datei kopiert und auf die eigene Umgebung angepasst werden. Anschließend wird der Dienst mit New-Service
(oder einer alternativen Methode) angelegt und ist bereit für den Betrieb. Wichtig bleibt, ein geeignetes Anmeldekonto und ausreichende Rechte für das Skript sicherzustellen.
Beispiel 1: Einfache CPU-Überwachung
Szenario
Ein Dienst, der in regelmäßigen Abständen die CPU-Auslastung misst und einen Warnhinweis ins Ereignisprotokoll schreibt, wenn sie über 80 % liegt. Nützlich in Situationen, in denen man eine gewisse Last nicht dauerhaft überschreiten möchte oder Engpässe frühzeitig bemerken will.
Skript (C:\Scripts\CPUWatchdog.ps1
):
# CPUWatchdog.ps1
# Überwacht die CPU-Auslastung und schreibt einen Log-Eintrag,
# wenn der Wert über 80% liegt.
$LogName = "Application"
$EventID = 3001
$EventSrc = "CPUWatchdog"
# Dienst-Schleife
while ($true) {
# CPU ermitteln
$cpu = Get-Counter -Counter "\Processor(_Total)\% Processor Time" -SampleInterval 1 -MaxSamples 1
$cpuValue = [int]$cpu.CounterSamples.CookedValue
if ($cpuValue -gt 80) {
# Ereignis ins Event Log schreiben
Write-EventLog -LogName $LogName -Source $EventSrc -EventId $EventID -EntryType Warning -Message "CPU-Auslastung über 80%: $cpuValue%"
}
Start-Sleep -Seconds 5
}
Dienst erstellen:
New-Service -Name "CPUWatchdog" `
-BinaryPathName "powershell.exe -ExecutionPolicy Bypass -File C:\Scripts\CPUWatchdog.ps1" `
-DisplayName "CPU Watchdog Dienst" `
-Description "Überwacht kontinuierlich die CPU-Auslastung und warnt bei Überschreitung." `
-StartupType Automatic
Beispiel 2: Automatische SQL-Datenbank-Backups
Szenario
Tägliche Sicherung einer oder mehrerer Datenbanken auf einem Netzlaufwerk. Unternehmen profitieren, da sie Backups nicht mehr manuell anstoßen müssen. Das Skript läuft im Hintergrund als Dienst und kümmert sich um die Datensicherung.
Skript (C:\Scripts\DatabaseBackup.ps1
):
# DatabaseBackup.ps1
# Führt ein tägliches Backup einer SQL-Datenbank durch und legt das Ergebnis
# in einem gewünschten Verzeichnis ab.
$SqlServer = "SQL01\INSTANCE"
$Database = "WichtigeDB"
$BackupDir = "\\Fileserver\Backups\Databases"
$LogName = "Application"
$Source = "DBBackupService"
function Do-DatabaseBackup {
param (
[string]$ServerInstance,
[string]$DbName,
[string]$BackupPath
)
$backupFile = Join-Path $BackupPath ("$($DbName)_$(Get-Date -Format yyyyMMdd_HHmmss).bak")
$sql = "BACKUP DATABASE [$DbName] TO DISK = N'$backupFile' WITH NOFORMAT, NOINIT, NAME = N'$($DbName) Full Backup', SKIP, NOREWIND, NOUNLOAD, STATS = 10;"
try {
Invoke-Sqlcmd -ServerInstance $ServerInstance -Query $sql
Write-EventLog -LogName $LogName -Source $Source -EventId 4001 -EntryType Information -Message "Backup für $DbName erfolgreich abgeschlossen. Datei: $backupFile"
}
catch {
Write-EventLog -LogName $LogName -Source $Source -EventId 4002 -EntryType Error -Message "Fehler beim Backup von $DbName: $_"
}
}
while ($true) {
$currentTime = Get-Date -Format "HH:mm"
if ($currentTime -eq "01:00") {
Do-DatabaseBackup -ServerInstance $SqlServer -DbName $Database -BackupPath $BackupDir
Start-Sleep -Seconds 86400
} else {
Start-Sleep -Seconds 300
}
}
Dienst erstellen:
New-Service -Name "DBBackupService" `
-BinaryPathName "powershell.exe -ExecutionPolicy Bypass -File C:\Scripts\DatabaseBackup.ps1" `
-DisplayName "Datenbank-Backup-Dienst" `
-Description "Sichert jede Nacht die SQL-Datenbank und legt die Sicherung auf dem Netzlaufwerk ab." `
-StartupType Automatic
Beispiel 3: Log-Archivierung mit Kompression
Szenario
Stetig wachsende Logdateien in einem bestimmten Verzeichnis belasten die Übersicht oder den Speicherplatz. Dieses Skript sucht nach älteren Logs (z. B. älter als eine Woche), komprimiert sie und verschiebt sie ins Archiv.
Skript (C:\Scripts\LogArchiver.ps1
):
# LogArchiver.ps1
# Durchsucht ein Verzeichnis nach alten Logdateien (älter als 7 Tage), komprimiert sie
# und verschiebt die Archiv-ZIP-Dateien in ein spezielles Archivverzeichnis.
$SourcePath = "C:\Logs"
$ArchivePath = "C:\Logs\Archiv"
$LogName = "Application"
$EventSource = "LogArchiver"
$ZipModule = "C:\Scripts\ModulesZipZip.psm1" # Beispiel für externes Modul
Import-Module $ZipModule -ErrorAction SilentlyContinue
function Compress-LogFile {
param (
[string]$FilePath
)
$fileName = Split-Path $FilePath -Leaf
$zipName = $fileName.Replace(".log", ".zip")
$zipTarget = Join-Path $ArchivePath $zipName
# Beispielhafter Aufruf einer externen ZIP-Funktion:
# Compress-7Zip -Source $FilePath -Destination $zipTarget
# Demonstration: nur Kopieren und alte Datei löschen
[System.IO.File]::Copy($FilePath, $zipTarget)
Remove-Item $FilePath -Force
}
while ($true) {
try {
$oldFiles = Get-ChildItem $SourcePath -Filter *.log -File | Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-7) }
foreach ($file in $oldFiles) {
Compress-LogFile -FilePath $file.FullName
}
Write-EventLog -LogName $LogName -Source $EventSource -EventId 5001 -EntryType Information -Message "Logarchivierung erfolgreich abgeschlossen."
}
catch {
Write-EventLog -LogName $LogName -Source $EventSource -EventId 5002 -EntryType Error -Message "Fehler bei der Logarchivierung: $_"
}
Start-Sleep -Seconds 86400
}
Dienst erstellen:
New-Service -Name "LogArchiverService" `
-BinaryPathName "powershell.exe -ExecutionPolicy Bypass -File C:\Scripts\LogArchiver.ps1" `
-DisplayName "Log-Archivierungsdienst" `
-Description "Komprimiert alte Logdateien und verschiebt sie ins Archiv." `
-StartupType Automatic
Beispiel 4: Netzwerkfreigabe-Überwachung (Ping-Monitor)
Szenario
Ein wichtiges Netzwerkshare wird sporadisch unerreichbar. Dieser PowerShell-Dienst pingt den Fileserver, um Ausfälle zu registrieren. Bei wiederholten Fehlschlägen wird ein Eintrag im Eventlog erzeugt und ggf. ein Dienstneustart (z. B. LanmanServer) ausgelöst.
Skript (C:\Scripts\ShareMonitor.ps1
):
# ShareMonitor.ps1
# Überwacht in festen Abständen eine Netzwerkfreigabe per Ping und meldet Ausfälle.
$Server = "FILESERVER01"
$LogName = "System"
$EventSource = "ShareMonitor"
$PingInterval = 60 # in Sekunden
$FailureCount = 0
$FailureLimit = 3 # Ab wie vielen aufeinanderfolgenden Fehlern eine Aktion ausgelöst wird
while ($true) {
$pingResult = Test-Connection -ComputerName $Server -Count 1 -Quiet
if ($pingResult -eq $false) {
$FailureCount++
if ($FailureCount -ge $FailureLimit) {
Write-EventLog -LogName $LogName -Source $EventSource -EventId 6001 -EntryType Error -Message "$Server nicht erreichbar. $FailureCount Pings fehlgeschlagen."
# Beispielhafter Neustart eines Dienstes
# Restart-Service -Name "LanmanServer" -ErrorAction SilentlyContinue
}
} else {
$FailureCount = 0
}
Start-Sleep -Seconds $PingInterval
}
Dienst erstellen:
New-Service -Name "ShareMonitorService" `
-BinaryPathName "powershell.exe -ExecutionPolicy Bypass -File C:\Scripts\ShareMonitor.ps1" `
-DisplayName "Netzwerkfreigabe-Überwachung" `
-Description "Ping-Überwachung einer wichtigen Netzwerkfreigabe." `
-StartupType Automatic
Beispiel 5: Automatische Firewallregel-Aktualisierung
Szenario
Bestimmte IP-Ranges ändern sich regelmäßig, sollen aber immer Zugriff auf Port 80/443 haben. Das Skript liest eine Konfigurationsdatei ein und passt eine Firewallregel an. Ideal, wenn sich externe Partner-Netzwerke öfter ändern.
Skript (C:\Scripts\FirewallUpdateService.ps1
):
# FirewallUpdateService.ps1
# Liest eine Datei mit neuen IP-Bereichen und passt die Windows-Firewallregeln an.
$configFile = "C:\Scripts\allowedIPs.txt"
$ruleName = "AllowCustomIPs"
$LogName = "Application"
$EventSource = "FirewallUpdateService"
function Update-FirewallRule {
param(
[string]$RuleName,
[string[]]$IPList
)
# Bestehende Regel löschen, falls vorhanden
netsh advfirewall firewall delete rule name="$RuleName" dir=in
# Neue Regel anlegen
netsh advfirewall firewall add rule name="$RuleName" dir=in action=allow protocol=TCP localport=80,443 remoteip=($IPList -join ",")
}
while ($true) {
try {
if (Test-Path $configFile) {
$ipList = Get-Content $configFile | Where-Object { $_ -match '^\d{1,3}\.' }
if ($ipList) {
Update-FirewallRule -RuleName $ruleName -IPList $ipList
Write-EventLog -LogName $LogName -Source $EventSource -EventId 7001 -EntryType Information -Message "Firewallregel erfolgreich aktualisiert."
}
}
}
catch {
Write-EventLog -LogName $LogName -Source $EventSource -EventId 7002 -EntryType Error -Message "Fehler bei Firewall-Aktualisierung: $_"
}
Start-Sleep -Seconds 14400
}
Dienst erstellen:
New-Service -Name "FirewallUpdateService" `
-BinaryPathName "powershell.exe -ExecutionPolicy Bypass -File C:\Scripts\FirewallUpdateService.ps1" `
-DisplayName "Firewall Update Dienst" `
-Description "Aktualisiert regelmäßig eine Windows-Firewallregel basierend auf externer Konfiguration." `
-StartupType Automatic
Beispiel 6: Automatischer Shutdown bei Inaktivität
Szenario
Ein Dienst, der prüft, ob der Computer in einem bestimmten Zeitfenster (z. B. 22–06 Uhr) nicht genutzt wird. Ist keine Session aktiv, erfolgt ein Herunterfahren, um Energie zu sparen. Typisch für Bürorechner oder Terminalserver, die nachts nicht laufen müssen.
Skript (C:\Scripts\AutoShutdown.ps1
):
# AutoShutdown.ps1
# Wenn das System in einem festgelegten Zeitfenster ohne aktive User ist,
# soll es heruntergefahren werden.
$startTime = [TimeSpan]"22:00"
$endTime = [TimeSpan]"06:00"
$LogSource = "AutoShutdownService"
while ($true) {
$nowTimeSpan = (Get-Date).TimeOfDay
if (($nowTimeSpan -ge $startTime) -or ($nowTimeSpan -le $endTime)) {
# Prüfen, ob ein Benutzer angemeldet ist
$sessions = quser 2>$null | Select-Object -Skip 1
if (-not $sessions) {
Write-EventLog -LogName "System" -Source $LogSource -EventId 8001 -EntryType Information -Message "Leerlauf erkannt, initiiere Shutdown."
Stop-Computer -Force
}
}
Start-Sleep -Seconds 300
}
Dienst erstellen:
New-Service -Name "AutoShutdownService" `
-BinaryPathName "powershell.exe -ExecutionPolicy Bypass -File C:\Scripts\AutoShutdown.ps1" `
-DisplayName "Automatischer Shutdown" `
-Description "Fährt das System in definierten Zeitfenstern automatisch herunter, wenn keine Benutzer angemeldet sind." `
-StartupType Automatic
Beispiel 7: E-Mail-Warnung bei wenig Festplattenspeicher
Szenario
Wird auf Laufwerk C: der freie Speicher zu knapp, soll eine Warn-E-Mail ans Administratorenteam gesendet werden. So vermeidet man Systemstillstände wegen volllaufender Partitionen.
Skript (C:\Scripts\DiskSpaceMonitor.ps1
):
# DiskSpaceMonitorSSL_Plaintext.ps1
# ---------------------------------
# Überwacht den freien Speicherplatz auf Laufwerk C und verschickt eine Warn-E-Mail
# über SSL/TLS, sobald ein definierter Schwellwert (z. B. 5 GB) unterschritten wird.
# Die SMTP-Zugangsdaten liegen hier bewusst im Klartext vor. In echten Produktivumgebungen
# ist dies aus Sicherheitsgründen NICHT empfohlen.
# ---------------------------
# KONFIGURATION
# ---------------------------
$Drive = "C:"
$ThresholdGB = 5
# SMTP-Einstellungen
$SmtpServer = "mail.example.com"
$SmtpPort = 587 # 587 (TLS) oder 465 (SSL)
$UseSsl = $true # True für SSL/TLS-Verschlüsselung
# Klartext-Zugangsdaten
$SmtpUsername = "monitor@example.com"
$SmtpPassword = "P@ssw0rd123" # Beispielpasswort (im Klartext!)
# Absender und Empfänger
$EmailFrom = "monitor@example.com"
$EmailTo = "admin@example.com"
$MailSubject = "WARNUNG: Freier Speicherplatz knapp"
# Windows-Eventlog-Einstellungen
$LogName = "Application"
$EventSource = "DiskSpaceMonitorSSLPlaintext"
# ---------------------------
# PSCredential für Send-MailMessage erstellen
# (Trotz Klartext-Passwort erzeugen wir ein SecureString-Objekt,
# damit Send-MailMessage ein Credential-Objekt nutzen kann.)
# ---------------------------
$SecurePassword = ConvertTo-SecureString $SmtpPassword -AsPlainText -Force
$SmtpCredential = New-Object System.Management.Automation.PSCredential($SmtpUsername, $SecurePassword)
# ---------------------------
# FUNKTION: SendWarningMail
# ---------------------------
function SendWarningMail {
param (
[string]$Subject,
[string]$Body
)
Send-MailMessage `
-SmtpServer $SmtpServer `
-Port $SmtpPort `
-UseSsl $UseSsl `
-Credential $SmtpCredential `
-From $EmailFrom `
-To $EmailTo `
-Subject $Subject `
-Body $Body
}
# ---------------------------
# HAUPTSCHLEIFE
# ---------------------------
while ($true) {
try {
# Freien Speicherplatz ermitteln
$FreeGB = [math]::Round((Get-PSDrive $Drive).Free / 1GB, 2)
# Prüfen, ob der Schwellwert unterschritten ist
if ($FreeGB -lt $ThresholdGB) {
$Subject = "$MailSubject ($FreeGB GB)"
$Body = "ACHTUNG: Das Laufwerk $Drive hat nur noch $FreeGB GB freien Speicherplatz."
# Warn-E-Mail versenden
SendWarningMail -Subject $Subject -Body $Body
# Ereignis ins Windows-Eventlog schreiben
Write-EventLog -LogName $LogName `
-Source $EventSource `
-EventId 9001 `
-EntryType Warning `
-Message $Subject
}
}
catch {
# Bei Fehlern Eintrag ins Eventlog
Write-EventLog -LogName $LogName `
-Source $EventSource `
-EventId 9002 `
-EntryType Error `
-Message "Fehler beim DiskSpace-Monitoring (SSL): $_"
}
# 30 Minuten warten, dann erneut prüfen
Start-Sleep -Seconds 1800
}
Dienst erstellen:
NeNew-Service -Name "DiskSpaceMonitorSSLPlaintextService" `
-BinaryPathName "powershell.exe -ExecutionPolicy Bypass -File C:\Scripts\DiskSpaceMonitorSSL_Plaintext.ps1" `
-DisplayName "Festplattenspeicher-Überwachung SSL (Plaintext Credentials)" `
-Description "Versendet Warnmails bei knappem Speicher. SMTP-Credentials im Klartext." `
-StartupType Automatic
Beispiel 8: Zentrales Eventlog-Forwarding (Syslog)
Szenario
Manche Organisationen leiten Windows-Ereignisse in Echtzeit an einen zentralen Syslog-Server weiter. Das folgende Skript beobachtet das „Application“-Log und leitet neu auftretende Events an einen Syslog-Endpunkt (beispielhaft) weiter.
Skript (C:\Scripts\EventLogCollector.ps1
):
# EventLogCollector.ps1
# Liest neu auftretende Ereignisse aus der Windows-Ereignisanzeige (Application) und sendet sie an einen Syslog-Server.
$syslogServer = "192.168.0.50"
$logname = "Application"
$EventSource = "EventLogCollector"
$lastCheck = Get-Date
function Send-Syslog {
param(
[string]$Message
)
# Beispiel: Syslog-Send via UDP oder externes Modul
Write-Host "Sende an Syslog: $Message"
}
while ($true) {
try {
$newEvents = Get-EventLog -LogName $logname -After $lastCheck
if ($newEvents) {
foreach ($evt in $newEvents) {
$msg = "EventID: $($evt.EventID), Source: $($evt.Source), Message: $($evt.Message)"
Send-Syslog -Message $msg
}
$lastCheck = Get-Date
}
}
catch {
Write-EventLog -LogName $logname -Source $EventSource -EventId 10001 -EntryType Error -Message "Fehler beim Abfragen von EventLogs: $_"
}
Start-Sleep -Seconds 15
}
Dienst erstellen:
New-Service -Name "EventLogCollectorService" `
-BinaryPathName "powershell.exe -ExecutionPolicy Bypass -File C:\Scripts\EventLogCollector.ps1" `
-DisplayName "Eventlog nach Syslog-Weiterleitung" `
-Description "Sammelt Ereignisse aus der Windows-Ereignisanzeige und sendet sie an einen Syslog-Server." `
-StartupType Automatic
Beispiel 9: Registry-Bereinigung
Szenario
In manchen Umgebungen entstehen nach dem Systemstart oder nach Software-Updates irrelevante Registry-Einträge, die regelmäßig entfernt werden sollen. Das Skript löscht diese Einträge periodisch.
Skript (C:\Scripts\RegistryCleaner.ps1
):
# RegistryCleaner.ps1
# Beispielhaftes Skript, das bestimmte Registrypfade bereinigt.
$pathsToClean = @(
"HKCU:\Software\SomeOldApp",
"HKLM:\SOFTWARE\AnotherKey"
)
$LogName = "System"
$EventSource = "RegistryCleaner"
while ($true) {
try {
foreach ($path in $pathsToClean) {
if (Test-Path $path) {
Remove-Item $path -Recurse -Force
Write-EventLog -LogName $LogName -Source $EventSource -EventId 11001 -EntryType Information -Message "Registry-Schlüssel entfernt: $path"
}
}
}
catch {
Write-EventLog -LogName $LogName -Source $EventSource -EventId 11002 -EntryType Error -Message "Fehler bei der Registry-Bereinigung: $_"
}
Start-Sleep -Seconds 43200
}
Dienst erstellen:
New-Service -Name "RegistryCleanerService" `
-BinaryPathName "powershell.exe -ExecutionPolicy Bypass -File C:\Scripts\RegistryCleaner.ps1" `
-DisplayName "Registry-Bereinigungsdienst" `
-Description "Entfernt ungenutzte Registry-Einträge in festen Intervallen." `
-StartupType Automatic
Beispiel 10: Datenkollektion für ein Custom-Dashboard
Szenario
In vielen IT-Teams entsteht das Bedürfnis, ein eigenes Dashboard zu bauen, das System-Kennzahlen in Echtzeit anzeigt. Dieses Skript sammelt CPU-Last, Speicherauslastung und Prozessanzahl und schreibt sie alle paar Minuten in eine CSV-Datei, die man mit Power BI, Excel oder anderen Tools visualisieren kann.
Skript (C:\Scripts\DashboardCollector.ps1
):
# DashboardCollector.ps1
# Sammelt diverse Kennzahlen und schreibt sie in eine CSV-Datei.
$outputFile = "C:\Scripts\DashboardData.csv"
if (-not (Test-Path $outputFile)) {
"Timestamp,CPU_Usage,Memory_MB,Processes_Count" | Out-File $outputFile
}
while ($true) {
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$cpuCounter = Get-Counter "\Processor(_Total)\% Processor Time" -SampleInterval 1 -MaxSamples 1
$cpuUsage = [int]$cpuCounter.CounterSamples.CookedValue
$memUsedMB = (Get-WmiObject Win32_OperatingSystem).TotalVisibleMemorySize - (Get-WmiObject Win32_OperatingSystem).FreePhysicalMemory
$procCount = (Get-Process | Measure-Object).Count
$line = "$timestamp,$cpuUsage,$memUsedMB,$procCount"
Add-Content -Path $outputFile -Value $line
Start-Sleep -Seconds 60
}
Dienst erstellen:
New-Service -Name "DashboardCollectorService" `
-BinaryPathName "powershell.exe -ExecutionPolicy Bypass -File C:\Scripts\DashboardCollector.ps1" `
-DisplayName "Dashboard-Datenkollektor" `
-Description "Erfasst Systemkennzahlen und schreibt sie in eine CSV-Datei." `
-StartupType Automatic
Erweiterte Hinweise & Best Practices
All die oben vorgestellten Beispiele legen nahe, wie man PowerShell-Skripte als kontinuierliche Prozesse im Hintergrund betreibt. Damit sie reibungslos in verschiedensten Systemen laufen, sollten folgende Punkte beachtet werden:
- Rechtemanagement und Dienstkonten
Dienste werden gerne im Kontext von „Lokales System“ gestartet, was jedoch sehr weitgehende Privilegien mit sich bringt. Sicherer ist es, ein eigenes Dienstkonto mit genau den Rechten anzulegen, die das Skript benötigt. Bei Datenbankzugriffen sollte man beispielsweise ein Konto wählen, das Zugriffsrechte auf die betreffende Datenbank besitzt, ansonsten aber keine unnötigen Admin-Privilegien. - Logging und Eventlog
Eine solide Protokollierung der Skriptaktivitäten ist essentiell. In vielen Beispielen werden Einträge ins Eventlog geschrieben, die im Fehlerfall wertvolle Hinweise liefern. Alternativ oder zusätzlich kann man Logfiles erstellen, insbesondere wenn sehr viele Detailinformationen anfallen. - Fehler- und Ausfallstrategie
Windows bietet die Option, einen Dienst bei Fehlern automatisch neu zu starten. Das ist besonders wichtig, wenn der Dienst geschäftskritische Aufgaben erfüllt (etwa Backups oder Monitoring). Ein Blick inservices.msc
unter „Wiederherstellung“ zeigt, wie sich das konfigurieren lässt: Neustart beim ersten Fehler, zweiten Fehler etc. - Starttyp und Timing
Nicht alle Skripte müssen rund um die Uhr laufen. Wer nur nächtliche Datensicherungen benötigt, kann sich überlegen, ob eine Windows-Aufgabe reicht. Ein Dienst, der ständig im Hintergrund aktiv ist, kann unnötige Ressourcen verbrauchen, wenn die Aufgabe lediglich einmal pro Tag relevant ist. - Modularisierung
Größere PowerShell-Skripte nutzt man oft in mehreren Kontexten. Es bietet sich an, Kernfunktionen in Module auszulagern und diese Module zu importieren. So bleibt das Hauptskript übersichtlich, und die Wartung fällt leichter. - Versionskontrolle
Wer regelmäßig Skripte anpasst, sollte ein Versionskontrollsystem (z. B. Git) verwenden. Ein Dienst wird in aller Regel nicht täglich umgeschrieben, aber es ist dennoch praktisch, bei Bedarf auf ältere Versionen zurückgreifen zu können oder Änderungen transparent nachzuvollziehen. - Zentrale Verwaltung und Deployment
In großen Umgebungen verteilen Administratorinnen und Administratoren Dienste in automatisierten Prozessen. Das kann via SCCM, über Gruppenrichtlinien oder PowerShell Remoting (Invoke-Command
) geschehen. Wichtig ist, die Dienste konsistent zu konfigurieren, etwa was Starttyp, Dienstkonto und Protokollierung angeht. - Troubleshooting
- Überprüfung, ob das Skript interaktiv läuft: Lässt sich das Skript als normale PowerShell-Session erfolgreich ausführen? Falls nein, findet man so erste Fehlerursachen.
- UAC und ExecutionPolicy: Standardmäßig verhindert die Windows-PowerShell möglicherweise Skript-Ausführungen (Policy). Daher bei Bedarf
-ExecutionPolicy Bypass
angeben. - Zeitüberschreitung beim Start: Dienste haben ein Startzeitlimit. Dauert die Initialisierung zu lange, interpretiert Windows das als Fehlschlag. Entweder das Skript optimieren oder den Timeout-Wert hochsetzen.
- Performance vs. Ressourcenverbrauch
Dienste wie das CPU-Monitoring könnten sehr häufig in kurzen Intervallen aktiv sein. Wenn das System stabil ist und die CPU nicht zu stark belastet wird, ist das unkritisch. Andernfalls sollte man Intervalle vergrößern (z. B. alle 15 Sekunden statt alle 5 Sekunden), um Ressourcen zu schonen. - Größere Anwendungen in .NET realisieren
Wer mehr Kontrolle oder komplexere Anforderungen hat, entwickelt eigene Windows-Dienstanwendungen in C# oder VB.NET. PowerShell-Skripte sind großartig für rasche Automatisierungen und moderate Komplexität. Bei Großprojekten bietet das .NET-Framework (oder .NET Core) jedoch umfassendere Tools, Debugmöglichkeiten und Integrationen.
Weitere Quellen
Windows-Dienste sind ein bewährter Mechanismus, um automatisierte Aufgaben ohne Benutzerinteraktion dauerhaft, sicher und stabil abzuwickeln. PowerShell ermöglicht es, diese Dienste unkompliziert zu erstellen, speziell wenn man bereits Skripte im Einsatz hat, die man nicht immer manuell starten möchte. Mit ein wenig Sorgfalt bei der Einrichtung und ausreichend Tests läuft ein Dienst nach seiner Installation oft jahrelang ohne nennenswerte Eingriffe.
Wer tiefer in das Thema einsteigen möchte, findet bei Microsoft reichlich Dokumentation:
- Microsoft Docs – Windows Services Overview
- Microsoft Docs – sc.exe (Service Controller)
- Microsoft Docs – PowerShell Cmdlets für Dienstverwaltung
- Microsoft Docs – Windows Service in .NET erstellen
- NSSM – Non-Sucking Service Manager (offizielle Seite)
Auch in der PowerShell-Community (z. B. in Foren, auf GitHub oder in einschlägigen Blogs) existieren zahlreiche erprobte Lösungen, Tutorials und Diskussionsbeiträge, die praktische Tipps liefern – gerade dann, wenn ein Dienst nicht so rund läuft wie erwartet oder besondere Anforderungen (etwa in Multi-Domänen-Netzwerken) bestehen.
Zudem lohnt es sich, die Weiterentwicklung von PowerShell im Auge zu behalten. In den aktuellen Versionen (PowerShell 7+) gibt es regelmäßig neue Cmdlets, Performance-Optimierungen und Sicherheitspatches. Für den professionellen Einsatz ist daher eine gewisse Pflege der Umgebung ratsam.
Zusammenfassend lässt sich festhalten, dass Windows-Dienste in Kombination mit PowerShell eine mächtige, stabile und dennoch relativ einfach zu beherrschende Grundlage für Automatisierungen aller Art darstellen. Ob man kleine Einzeiler zur CPU-Überwachung realisiert oder große Projekte mit Datenbank-Backups, Monitoring und Alarmierungen aufbaut – die vorgestellten Beispiele demonstrieren, wie flexibel und doch überschaubar die Umsetzung sein kann.
Viele Aufgaben, die sonst manuelle Eingriffe erfordern, lassen sich so dauerhaft ohne Aufsicht erledigen. Das entlastet das IT-Personal, reduziert menschliche Fehlerquellen und sorgt für eine lückenlose Erfüllung essenzieller Prozesse. Und ist der Dienst einmal eingerichtet, kann man sich darauf verlassen, dass er still und zuverlässig im Hintergrund seine Arbeit verrichtet.
(Alle Skripte sind Beispielcode und müssen ggf. an die individuelle Umgebung, Rechte- und Sicherheitsvorgaben sowie Pfade angepasst werden. Vor dem Einsatz in Produktionsumgebungen empfiehlt sich stets ein Testlauf in einer isolierten Umgebung.)