ADMIN

2025

01

2024-12-30T12:00:00

Automatisierung

SCHWERPUNKT

090

Automatisierung

PowerShell

10 praktische PowerShell-Einzeiler

Auf die Schnelle

von Heiko Brenn

Veröffentlicht in Ausgabe 01/2025 - SCHWERPUNKT

Die PowerShell hat sich als eine der leistungsfähigsten Technologien für die Automatisierung und Verwaltung von IT-Umgebungen etabliert. Insbesondere bei der Arbeit mit Active Directory, Exchange, Microsoft 365 und VMware ist die Skriptsprache eine große Hilfe. Mit praktischen Einzeilern erledigen Sie viele Routineaufgaben im Handumdrehen, ohne aufwendige Skripte schreiben zu müssen.

Ein PowerShell-Einzeiler ist ein einzelner Befehl oder eine einzelne Zeile PowerShell-Code, die eine bestimmte Aufgabe ausführt. Diese kompakten Befehle kombinieren oft mehrere Operationen oder Cmdlets in einer Zeile, um wiederkehrende Aktionen effizient durchzuführen. Einzeiler sparen Zeit und reduzieren die Notwendigkeit, längere Skripte zu schreiben. Im Laufe der Zeit können sie sich aber natürlich auch schrittweise zu umfangreicheren PowerShell-Skripten entwickeln.
Ein typisches Merkmal von PowerShell-Einzeilern ist die Verwendung der Pipeline "|", die es ermöglicht, die Ausgabe eines Befehls direkt als Eingabe für den nächsten zu verwenden. Darüber hinaus lassen sich Cmdlets auch unabhängig voneinander mit ";" verketten. Auch wenn Einzeiler "nur" kurze PowerShell-Snippets darstellen, führen sie gegebenenfalls zu umfangreichen Änderungen in der jeweiligen Infrastruktur. Daher sind sorgfältiges Arbeiten, präzise Ausführung und gründliches Testen des Codes unerlässlich.
Typischer Aufbau eines Einzeilers
Der Aufbau eines PowerShell-Einzeilers folgt meist einer einfachen, aber logischen Struktur. Die grundlegenden Elemente sind:
Ein PowerShell-Einzeiler ist ein einzelner Befehl oder eine einzelne Zeile PowerShell-Code, die eine bestimmte Aufgabe ausführt. Diese kompakten Befehle kombinieren oft mehrere Operationen oder Cmdlets in einer Zeile, um wiederkehrende Aktionen effizient durchzuführen. Einzeiler sparen Zeit und reduzieren die Notwendigkeit, längere Skripte zu schreiben. Im Laufe der Zeit können sie sich aber natürlich auch schrittweise zu umfangreicheren PowerShell-Skripten entwickeln.
Ein typisches Merkmal von PowerShell-Einzeilern ist die Verwendung der Pipeline "|", die es ermöglicht, die Ausgabe eines Befehls direkt als Eingabe für den nächsten zu verwenden. Darüber hinaus lassen sich Cmdlets auch unabhängig voneinander mit ";" verketten. Auch wenn Einzeiler "nur" kurze PowerShell-Snippets darstellen, führen sie gegebenenfalls zu umfangreichen Änderungen in der jeweiligen Infrastruktur. Daher sind sorgfältiges Arbeiten, präzise Ausführung und gründliches Testen des Codes unerlässlich.
Typischer Aufbau eines Einzeilers
Der Aufbau eines PowerShell-Einzeilers folgt meist einer einfachen, aber logischen Struktur. Die grundlegenden Elemente sind:
1. Cmdlets: Dies sind die Grundbausteine, die eine bestimmte Aktion ausführen, wie etwa "Get-Process", um laufende Prozesse anzuzeigen, oder "Set-ADUser", um ein Benutzerobjekt im Active Directory zu ändern.
2. Parameter: Spezifische Parameter konfigurieren Cmdlets und steuern deren Verhalten. Beispielsweise bietet sich der Parameter "-Identity" in einem Cmdlet wie "Get-Mailbox" an, um das Postfach eines bestimmten Benutzers abzufragen: Get-Mailbox -Identity <Username>.
3. Piping: Das Piping ist eine der mächtigsten Funktionen in der PowerShell. Es erlaubt, die Ausgabe eines Cmdlets an ein weiteres Cmdlet als Eingabe weiterzugeben. Zum Einsatz kommt hierfür das charakteristische Pipe-Symbol "|". Ein typisches Beispiel wäre Get-Process | Where-Object { $_.CPU -gt 30 }. Hier wird die Liste aller Prozesse abgerufen und durch die Pipe an "Where-Object" weitergegeben, das dann Prozesse filtert, deren CPU-Auslastung größer als 30 ist.
4. Filtern und Sortieren: Viele Einzeiler verwenden Cmdlets wie "Where-Object" zum Filtern und "Sort-Object" zum Sortieren der Ergebnisse. Diese ermöglichen es, die Ausgabe zu fokussieren und nur die relevantesten Daten zu erhalten.
5. Select-Object: Oftmals ist die Ausgabe eines Cmdlets sehr umfangreich. Um die Ergebnisse zu beschränken oder nur bestimmte Eigenschaften anzuzeigen, kommt "Select-Object" zum Einsatz: Get-ADUser -Filter * | Select-Object Name, UserPrincipalName. Dieser Befehl zeigt nur den Namen und den User Principal Name aller Benutzer an.
6. Formatierung: Am Ende steht oft ein Kommando zur Ausgabeformatierung, wie "Format-Table", "Format-List" oder "Out-Gridview": Get-ADUser -Filter * | Select-Object Name, UserPrincipalName | Format-Table. Die Ausgabe der Ergebnisse erfolgt im Tabellenformat.
7. Schleifen: Kompakte Schleifenkonstrukte wie "ForEach-Object" ermöglichen Iterationen: Get-Team | ForEach-Object { Add-TeamUser -GroupId $_.GroupId-User` ‘BenutzerA@MeineDomain.onmicrosoft.com’ -Role Owner }. Das erste Cmdlet dient zur Ermittlung aller Microsoft-Teams. Mithilfe von ForEach-Object und "Add-TeamUser" erhält BenutzerA die Besitzerrolle in allen Teams.
8. Aliases: Kurznamen für Cmdlets, Funktionen und externe Programme ermöglicht Benutzern die schnelle Eingabe von Befehlen. Gleichzeitig schränken Aliases mitunter die Lesbarkeit des Codes ein, denn nicht jeder ist mit ihnen vertraut. Hier ein Einzeiler mit Alias, der fünf neue Room-Mailboxen erstellt: ( 0 .. 5 ) | % { New-Mailbox -Name "NY_MeetingRoom00$_" -Room }. Im Gegensatz dazu ein Beispiel ohne Alias: ( 0 .. 5 ) | ForEach-Object { New-Mailbox -Name "NY_MeetingRoom00$_" -Room }. Mit "Get-Alias" lassen sich die verfügbaren Aliases und die ausgeschriebenen Cmd-lets anzeigen.
Nachfolgend zeigen wir Ihnen zehn nützliche PowerShell-Einzeiler.
1. AD-Benutzer finden, deren Kennwörter nicht ablaufen
Benutzerkonten sollten in der Regel so konfiguriert sein, dass Passwörter nach einem bestimmten Zeitraum ablaufen. Die Multifaktor-Authentifizierung mag diese Notwendigkeit verringern, dennoch ist eine regelmäßige Überprüfung sinnvoll. Der nachfolgende Einzeiler ruft alle Benutzer aus dem AD ab und filtert diejenigen heraus, deren Passwort nicht abläuft (PasswordNeverExpires = True). Die Ergebnisse sind dann als Tabelle sichtbar:
Get-ADUser -Filter * -PropertiesName, PasswordNeverExpires | `Where-Object {$_.PasswordNeverExpires -like "True" } | Format-Table
Bild 1: Mit einem PowerShell-Einzeiler zum Cmdlet "Get-ADUser" finden Sie AD-Nutzer, deren Kennwörter nicht ablaufen.
2. AD-User finden, die seit 180 Tagen nicht angemeldet waren
Nicht verwendete AD-Konten stellen ein großes Sicherheitsrisiko dar, da sie möglicherweise noch über Berechtigungen verfügen, die Angreifer ausnutzen könnten. Das regelmäßige Entfernen von inaktiven Benutzern hilft dabei, das AD ressourcenoptimiert zu betreiben. Der aufgeführte Einzeiler sucht alle Benutzer im Active Directory, die sich in den letzten 180 Tagen nicht angemeldet haben und gibt eine sortierte Liste dieser Benutzer aus, zusammen mit deren Name, SamAccountName (Anmeldename) und LastLogonDate. Die Ergebnisse sind nach dem Datum der letzten Anmeldung sortiert:
Get-ADUser -Filter * -Properties LastLogonDate | Where-Object {$_.LastLogonDate -ne $null
-and $_.LastLogonDate -lt (Get-Date).AddDays(-180)} | Select-Object ` SamAccountname, LastLogonDate, Distinguishedname | Sort-Object LastLogonDate
Um die betroffenen Benutzer tatsächlich zu deaktivieren, ist nur eine kleine Erweiterung erforderlich:
Get-ADUser -Filter * -Properties ` LastLogonDate | Where-Object {$_.LastLogonDate -ne $null
-and $_.LastLogonDate -lt (Get-Date).AddDays(-180)} | Select-Object ` SamAccountname, ` LastLogonDate, ` Distinguishedname | Sort-Object ` LastLogonDate | Disable-ADAccount ` -WhatIf
Das PowerShell Cmdlet "Disable-ADAccount" deaktiviert die die identifizierten Benutzerkonten. Der verwendete Parameter "-WhatIf" ist eine Schutzfunktion. Diese stellt sicher, dass die Ausführung von "Disable-ADAccount" zunächst nur als Simulation abläuft. Entspricht der Output dem gewünschten Ergebnis, können Sie "-WhatIf" entfernen oder durch "# -WhatIf" auskommentieren.
3. Aufbewahrungszeit fürgelöschte Exchange-Elemente
Exchange bietet die Möglichkeit, gelöschte Elemente innerhalb eines Zeitraums wiederherzustellen. Compliance-Anforderungen, Datenschutzrichtlinien und interne Regularien erfordern hier unter Umständen strikte Löschmechanismen. Mithilfe dieses Einzeilers erhalten alle Mitglieder der Microsoft-365-Gruppe "Finance" ein zehntägige (-RetainDeletedItemsFor 10) Aufbewahrungsfrist für gelöschte Elemente ausgerollt. Durch Anpassungen bei "-Identity" und "-RetailDeletedItemsFor" lassen sich sehr einfach unterschiedliche Regelungen für verschiedene Unternehmensbereiche ausrollen. Der Parameter "-RetentionPolicy" erlaubt das Setzen einer Löschrichtlinien statt eines direkten Zeitraums:
Get-UnifiedGroupLinks -Identity `’Finance’ -LinkType Members | ` ForEach-Object
{ Set-Mailbox -Identity $_.PrimarySmtpAddress -RetainDeletedItemsFor 10 }
4. Große Online-Postfächeridentifizieren
Auch in Zeiten von Cloudinfrastrukturen und "unbegrenztem" Speicherplatz ist es wichtig, Postfachgrößen im Blick zu behalten. Sei es als Vorbereitung auf etwaige Migrationen, für Backupstrategien oder im Rahmen von Performance-Optimierungen und Compliance-Anforderungen. Die Auflistung der größten Postfächer dürfte hier sehr hilfreich sein. Der aufgeführte Befehl durchsucht alle Exchange-Onlinepostfächer in der Organisation, sammelt deren statistische Informationen, sortiert sie nach der "TotalItemSize" (Gesamtgröße der Postfächer) in absteigender Reihenfolge und gibt die fünf größten Postfächer basierend auf ihrer Speichergröße zurück:
Get-EXOMailbox -ResultSize Unlimited ` | Get-EXOMailboxStatistics | Sort-Object TotalItemSize
-Descending | Select-Object DisplayName, TotalItemSize -First 5
5. E-Mails in Exchange Online nachverfolgen
E-Mail-Kommunikation verläuft leider nicht immer reibungslos. So sind E-Mails beispielsweise nicht zustellbar oder die Zustellung verzögert sich. Im Exchange-Online-Umfeld hilft "Get-MessageTrace" bei der Überwachung und Fehlersuche. Dieses Cmdlet kann sich auf den gesamten Mailverkehr der letzten Tage beziehen oder auf bestimmte Absender oder Empfänger:
Get-MessageTrace -StartDate ((Get-Date).AddDays(-10)) -EndDate (Get-Date) | Where-Object ` {$_.Status ` -eq "Pending"} | Select-Object `Received, SenderAddress, ` RecipientAddress
, Subject, Status | Format-Table
Dieser Einzeiler verwendet das Cmdlet "Get-MessageTrace", um Informationen über E-Mails abzurufen, die sich noch im Status "Pending" befinden. Details wie das Empfangsdatum, die Absenderadresse, die Empfängeradresse, der Betreff und der Nachrichtenstatus werden angezeigt. Der Parameter namens "-StartDate ((Get-Date).AddDays(-10))" beschränkt die Abfrage auf Nachrichten, die innerhalb der letzten 10 Tage gesendet wurden. Es sollen nur E-Mails einer bestimmten Absenderadresse als Ergebnis erscheinen? Kein Problem. Die nachfolgende Erweiterung des Einzeilers zeigt alle E-Mails, die von "BenutzerA@MeineDomain.com" erfolgreich (Delivered) zugestellt wurde:
Get-MessageTrace -StartDate ((Get-Date).AddDays(-10)) -EndDate (Get-Date) | Where-Object ` {$_.Status -eq "Delivered" -and $_.SenderAddress -eq
‘BenutzerA@Meine Domain.com’} |Select-Object
Received, SenderAddress, RecipientAddress, Subject, Status | Format-Table
Neben "Delivered" und "Pending" stehen beispielsweise als Statusabfrage auch "Failed", "Quarantined" und "FilteredAsSpam" zur Verfügung.
6. Teams mit nur einem Besitzer
In vielen Organisationen sind beim Einsatz von Microsoft Teams eine ganze Reihe von IT-Governance-Richtlinien zu berücksichtigen. Für die ordnungsgemäße Verwaltung ist beispielsweise häufig sicherzustellen, dass jedes Team über mindestens zwei Besitzer verfügt. Dies erleichtert nicht nur das Delegieren von Verantwortungen und vermeidet "Single Points of Failures", es verringert auch die Fälle, in denen IT- oder Support-Abteilungen eingreifen müssen:
Get-Team | Where-Object { (Get-TeamUser -GroupId $_.GroupId | Where-Object { $_.Role -eq ` 'Owner' }).Count -eq 1 }
Dieser kurze Einzeiler durchsucht alle Microsoft-Teams in der Organisation und identifiziert jene, bei denen es nur einen Besitzer (Owner) gibt. Mit zwei kleinen Änderungen ist dieser Befehl auch hilfreich, um Teams zu finden, die keine Mitglieder besitzen und somit möglicherweise archiviert beziehungsweise gelöscht werden können:
Get-Team | Where-Object { (Get-TeamUser -GroupId $_.GroupId | Where-Object { $_.Role -eq ` 'Member' }).Count -eq 0 }
Bild 2: Dieser Befehl durchsucht alle Microsoft-Teams in der Organisation und identifiziert jene mit nur einem Owner.
7. Benutzer als Owner allen Teams hinzufügen
Wie oben festgestellt, ist es für den reibungslosen Einsatz von Teams wichtig, dass diese mindestens zwei Owner beinhalten. Der unten stehende Code löst dieses Problem, indem er einen Benutzer allen Teams als Owner hinzufügt:
Get-Team | ForEach-Object { Add-TeamUser -GroupId $_.GroupId -User
‘BenutzerA@Meine Domain.com’ -Role ` Owner }
Dieser Einzeiler fügt den Benutzer "BenutzerA" allen Teams als Besitzer hinzu. Eine Überprüfung, ob dieser User bereits Owner in den entsprechenden Teams ist, findet jedoch nicht statt, was gegebenenfalls zu Fehlermeldungen führt. Um das zu vermeiden, lässt sich der Code erweitern:
Get-Team | ForEach-Object { $groupId ` = $_.GroupId; $teamName = $_.DisplayName;
$user = ‘BenutzerA@MeineDomain.com’; if (Get-TeamUser -GroupId $groupId |
Where-Object { $_.User -eq $user }) { Write-Output "$user ist bereits Mitglied des Teams ` '$teamName'." } else { Add-TeamUser -GroupId ` $groupId -User $user -Role Owner;
Write-Output "$user wurde alsBesitzer dem Team '$teamName'hinzugefügt." } }
Dieser PowerShell-Code durchläuft alle Microsoft-Teams und überprüft, ob "BenutzerA@MeineDomain.com" bereits Mitglied der jeweiligen Gruppe ist. Ist er noch kein Mitglied, wird er als Besitzer (Owner) hinzugefügt. Andernfalls erscheint eine Nachricht, dass der Benutzer bereits Mitglied des Teams ist. Anhand dieses Beispiels erkennen Sie gut, dass, auch wenn dieser Einzeiler funktioniert, die Lesbarkeit ab einer bestimmten Länge abnimmt. Die Umsetzung in Form eines Skripts wäre hier sinnvoller.
8. Übersicht aller VMware-VMs
Reports über den Zustand der IT-Infrastruktur sind hilfreich und selbstverständlich auch im VMware-Umfeld wichtig. Sie geben Auskunft über Hardwaredetails und den Status der jeweiligen virtuellen Maschine. Das unten stehende Kommando zeigt eine Liste aller VMs mit Informationen wie Name, Anzahl der CPUs, Arbeitsspeicher, Power-Status und Host-Server in einer interaktiven GridView-Tabelle an. Diese Ansicht ist nützlich für Admins, die eine schnelle und flexible Überwachung und Analyse der VMs in einer Umgebung benötigen. GridView ermöglicht es, die Daten leicht zu durchsuchen beziehungsweise zu filtern und zu sortieren:
Get-VM | Select Name, NumCPU, MemoryMB, PowerState, Host |Out-GridView
9. Hardwareeinstellungen an VMware-VMs ändern
Die PowerShell ist hervorragend für die Massenverarbeitung von Objekten wie beispielsweise virtuellen Maschinen geeignet. So nehmen Sie mit einem Befehl schnell und einfach Anpassungen an einer ganzen Reihe von Maschinen vor.
Der unten aufgeführte Code setzt den Arbeitsspeicher aller VMs, deren Namen mit "TrainingVM" beginnen, auf 4 GByte fest. Die Bestätigungsabfrage entfällt dank des Parameters "-Confirm:$false". Durch den Parameter "-WhatIf" lässt sich die Änderung zunächst simulieren, um sicherzustellen, dass sie auf die gewünschten VMs angewendet wird:
Get-VM -Name TrainingVM* | Set-VM `-MemoryGB 4 -Confirm:$false ` -WhatIf
10. VMware-Snapshots erstellen
Snapshots sind ein wichtiger Bestandteil jedes VMware-Betriebskonzepts und ihre Erstellung erfolgt sehr häufig automatisch. In manchen Fällen ist es allerdings erforderlich, Snapshots ad hoc für eine Reihe von Maschinen zu erstellen. Mit dem folgenden Einzeiler ist das sehr einfach umsetzbar:
Get-VM -Name TrainingVM* | New-Snapshot -server $server `-name "Snapshot $(Get-Date)"
-Description "Snapshot vor Update- $(Get-Date)" -RunAsync
Dieser Befehl erstellt Snapshots für alle virtuellen Maschinen, deren Name mit "TrainingVM" beginnt. Der Snapshot-Vorgang findet asynchron statt, er läuft also im Hintergrund, ohne die PowerShell-Sitzung zu blockieren. Der Snapshot erhält dabei einen dynamischen Namen und eine Beschreibung mit dem aktuellen Datum und der Uhrzeit. Eine Übersicht der vorhandenen Snapshots für bestimmt VMs lässt sich übrigens schnell und einfach erstellen mit
Get-VM -Name TrainingVM* | Get-Snapshot | Format-Table `-Property VM, Description , ` Name, Created
Fazit
Es muss nicht immer ein PowerShell-Skript sein. Oft genügen für alltägliche Aufgaben in der IT geschickt erstellte Einzeiler. In diesem Artikel haben wir Ihnen einige Anwendungsfälle vorgestellt. Dank der Vielseitigkeit von PowerShell sind natürlich sehr viele weitere Szenarien für den Einsatz von Einzeilern denkbar und möglich. Und vielleicht inspiriert dieser Artikel auch den ein oder anderen Admin, sich mehr mit den vielfältigen Möglichkeiten der PowerShell zu beschäftigen.
(dr)
Heiko Brenn ist Head of Marketing bei ScriptRunner.