Freigeben über


Kapitel 6 – Ablaufsteuerung

Skripterstellung

Wenn Sie vom Schreiben von PowerShell-Einzeilen zum Schreiben von Skripts wechseln, klingt es komplizierter als das ist. Ein Skript ist nichts anderes als die gleichen oder ähnlichen Befehle, die Sie interaktiv in der PowerShell-Konsole ausführen, allerdings speichern Sie sie als eine .ps1 Datei. Es gibt einige Skriptkonstrukte, die Sie verwenden können, z. B. eine foreach Schleife anstelle des ForEach-Object Cmdlets. Die Unterschiede können für Anfänger verwirrend sein, wenn sie berücksichtigen, dass es foreach sich sowohl um ein Sprachwort als auch um einen Alias für das ForEach-Object Cmdlet handelt.

Schleifen

Einer der besten Aspekte von PowerShell ist seine Skalierbarkeit. Sobald Sie erfahren, wie Sie eine Aufgabe für ein einzelnes Element ausführen, ist das Anwenden derselben Aktion auf Hunderte von Elementen fast so einfach. Durchlaufen Sie die Elemente mithilfe einer der verschiedenen Typen von Schleifen in PowerShell.

ForEach-Object

ForEach-Object ist ein Cmdlet zum Durchlaufen von Elementen in einer Pipeline, wie mit PowerShell-Einzeilern. ForEach-Object leitet die Objekte durch die Pipeline.

Obwohl der Module-Parameter von Get-Command mehrere String-Werte akzeptiert, akzeptiert er sie nur über die Pipelineeingabe nach Eigenschaftsnamen. Wenn Sie im folgenden Szenario zwei Zeichenfolgenwerte an Get-Command für die Verwendung mit dem Module-Parameter weiterleiten möchten, müssen Sie das ForEach-Object-Cmdlet verwenden.

'ActiveDirectory', 'SQLServer' |
    ForEach-Object {Get-Command -Module $_} |
    Group-Object -Property ModuleName -NoElement |
    Sort-Object -Property Count -Descending
Count Name
----- ----
  147 ActiveDirectory
   82 SqlServer

Im vorherigen Beispiel ist $_ das aktuelle Objekt. Seit PowerShell Version 3.0 kann $PSItem anstelle von $_ verwendet werden. Die meisten erfahrenen PowerShell-Benutzer bevorzugen die Verwendung von $_, da er abwärtskompatibel ist und weniger getippt werden muss.

Wenn Sie das foreach-Schlüsselwort verwenden, müssen Sie die Elemente im Arbeitsspeicher speichern, bevor Sie sie durchlaufen, was schwierig sein kann, wenn Sie nicht wissen, womit Sie arbeiten.

$ComputerName = 'DC01', 'WEB01'
foreach ($Computer in $ComputerName) {
    Get-ADComputer -Identity $Computer
}
DistinguishedName : CN=DC01,OU=Domain Controllers,DC=mikefrobbins,DC=com
DNSHostName       : dc01.mikefrobbins.com
Enabled           : True
Name              : DC01
ObjectClass       : computer
ObjectGUID        : c38da20c-a484-469d-ba4c-bab3fb71ae8e
SamAccountName    : DC01$
SID               : S-1-5-21-2989741381-570885089-3319121794-1001
UserPrincipalName :

DistinguishedName : CN=WEB01,CN=Computers,DC=mikefrobbins,DC=com
DNSHostName       : web01.mikefrobbins.com
Enabled           : True
Name              : WEB01
ObjectClass       : computer
ObjectGUID        : 33aa530e-1e31-40d8-8c78-76a18b673c33
SamAccountName    : WEB01$
SID               : S-1-5-21-2989741381-570885089-3319121794-1107
UserPrincipalName :

Häufig ist eine Schleife wie foreach oder ForEach-Object erforderlich. Andernfalls wird eine Fehlermeldung angezeigt.

Get-ADComputer -Identity 'DC01', 'WEB01'
Get-ADComputer : Cannot convert 'System.Object[]' to the type
'Microsoft.ActiveDirectory.Management.ADComputer' required by parameter
'Identity'. Specified method is not supported.
At line:1 char:26
+ Get-ADComputer -Identity 'DC01', 'WEB01'
+                          ~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Get-ADComputer], Parame
   terBindingException
    + FullyQualifiedErrorId : CannotConvertArgument,Microsoft.ActiveDirecto
   ry.Management.Commands.GetADComputer

In anderen Fällen können sie dieselben Ergebnisse erzielen und gleichzeitig die Schleife beseitigen. Wenden Sie sich an das Cmdlet, um Ihre Optionen zu verstehen.

'DC01', 'WEB01' | Get-ADComputer
DistinguishedName : CN=DC01,OU=Domain Controllers,DC=mikefrobbins,DC=com
DNSHostName       : dc01.mikefrobbins.com
Enabled           : True
Name              : DC01
ObjectClass       : computer
ObjectGUID        : c38da20c-a484-469d-ba4c-bab3fb71ae8e
SamAccountName    : DC01$
SID               : S-1-5-21-2989741381-570885089-3319121794-1001
UserPrincipalName :

DistinguishedName : CN=WEB01,CN=Computers,DC=mikefrobbins,DC=com
DNSHostName       : web01.mikefrobbins.com
Enabled           : True
Name              : WEB01
ObjectClass       : computer
ObjectGUID        : 33aa530e-1e31-40d8-8c78-76a18b673c33
SamAccountName    : WEB01$
SID               : S-1-5-21-2989741381-570885089-3319121794-1107
UserPrincipalName :

Wie Sie in den vorherigen Beispielen sehen können, akzeptiert der Identity-Parameter für Get-ADComputer nur einen einzelnen Wert, wenn er über die Parametereingabe bereitgestellt wird. Mithilfe der Pipeline können Sie jedoch mehrere Werte an den Befehl senden, da die Werte jeweils einzeln verarbeitet werden.

Für

Eine for Schleife iteriert, solange eine angegebene Bedingung wahr ist. Ich verwende die for Schleife nicht oft, aber sie hat Verwendungen.

for ($i = 1; $i -lt 5; $i++) {
    Write-Output "Sleeping for $i seconds"
    Start-Sleep -Seconds $i
}
Sleeping for 1 seconds
Sleeping for 2 seconds
Sleeping for 3 seconds
Sleeping for 4 seconds

Im vorherigen Beispiel wird die Schleife viermal durchlaufen, beginnend mit der Zahl 1, und wird fortgesetzt, solange die Zählervariable $i kleiner als 5 ist. Er schläft insgesamt 10 Sekunden lang.

Empfehlung

Es gibt zwei verschiedene do Schleifen in PowerShell: do until und do while. do until wird ausgeführt, während die angegebene Bedingung nicht erfüllt (false) ist.

Im folgenden Beispiel handelt es sich um ein Zahlenspiel, das fortgesetzt wird, bis der Wert, den Sie erraten, der gleichen Zahl entspricht, die das Get-Random-Cmdlet generiert hat.

$number = Get-Random -Minimum 1 -Maximum 10
do {
    $guess = Read-Host -Prompt "What's your guess?"
    if ($guess -lt $number) {
        Write-Output 'Too low!'
    } elseif ($guess -gt $number) {
        Write-Output 'Too high!'
    }
}
until ($guess -eq $number)
What's your guess?: 1
Too low!
What's your guess?: 2
Too low!
What's your guess?: 3

Do While ist das Gegenteil. Sie wird ausgeführt, solange die angegebene Bedingung als „true“ ausgewertet wird.

$number = Get-Random -Minimum 1 -Maximum 10
do {
    $guess = Read-Host -Prompt "What's your guess?"
    if ($guess -lt $number) {
        Write-Output 'Too low!'
    } elseif ($guess -gt $number) {
        Write-Output 'Too high!'
    }
}
while ($guess -ne $number)
What's your guess?: 1
Too low!
What's your guess?: 2
Too low!
What's your guess?: 3
Too low!
What's your guess?: 4

Dieselben Ergebnisse werden mit einer Do While-Schleife erzielt, indem die Testbedingung in „ungleich“ umgekehrt wird.

do-Schleifen werden immer mindestens einmal ausgeführt, weil die Bedingung am Ende der Schleife ausgewertet wird.

Während

Wie die do while-Schleife wird eine while-Schleife ausgeführt, solange die angegebene Bedingung wahr ist. Der Unterschied besteht jedoch darin, dass eine while-Schleife die Bedingung am Anfang der Schleife auswertet, bevor der Code ausgeführt wird. Somit wird sie gar nicht ausgeführt, wenn die Bedingung als „false“ ausgewertet wird.

Im folgenden Beispiel wird berechnet, an welchem Tag sich der Thanksgiving-Tag in den VEREINIGTEN Staaten befindet. Es ist immer am vierten Donnerstag des Novembers. Die Schleife beginnt mit dem 22. November und fügt einen Tag hinzu, während der Wochentag nicht dem Donnerstag entspricht. Wenn der 22. ein Donnerstag ist, wird die Schleife überhaupt nicht ausgeführt.

$date = Get-Date -Date 'November 22'
while ($date.DayOfWeek -ne 'Thursday') {
    $date = $date.AddDays(1)
}
Write-Output $date
Thursday, November 23, 2017 12:00:00 AM

unterbrechen, fortsetzen und zurückkehren

Das break-Schlüsselwort dient zum Beenden einer Schleife und wird häufig mit der switch-Anweisung verwendet. Im folgenden Beispiel führt break dazu, dass die Schleife nach der ersten Iteration endet.

for ($i = 1; $i -lt 5; $i++) {
    Write-Output "Sleeping for $i seconds"
    Start-Sleep -Seconds $i
    break
}
Sleeping for 1 seconds

Das continue Schlüsselwort ist dafür vorgesehen, zur nächsten Iteration einer Schleife zu springen.

Im folgenden Beispiel werden die Zahlen 1, 2, 4 und 5 ausgegeben. Es überspringt die Zahl 3 und fährt mit der nächsten Iteration der Schleife fort. Ähnlich wie bei break, unterbricht continue die Schleife, wenn auch nur für die aktuelle Iteration. Die Ausführung wird mit der nächsten Iteration fortgesetzt, anstatt die Schleife vollständig zu unterbrechen und zu beenden.

while ($i -lt 5) {
    $i += 1
    if ($i -eq 3) {
        continue
    }
    Write-Output $i
}
1
2
4
5

Das return Schlüsselwort ist so konzipiert, dass es den vorhandenen Bereich verlässt.

Beachten Sie im folgenden Beispiel, dass return das erste Ergebnis ausgibt und dann die Schleife verlässt.

$number = 1..10
foreach ($n in $number) {
    if ($n -ge 4) {
        return $n
    }
}
4

Eine ausführlichere Erläuterung der Ergebnisanweisung finden Sie in einem meiner Blogartikel: Das PowerShell-Rückgabeschlüsselwort.

Zusammenfassung

In diesem Kapitel haben Sie die verschiedenen Typen von Schleifen kennengelernt, die in PowerShell vorhanden sind.

Rezension

  1. Was ist der Unterschied zwischen dem ForEach-Object-Cmdlet und der foreach-Anweisung?
  2. Was ist der Hauptvorteil der Verwendung einer while Schleife anstelle einer do while Schleife oder do until Schleife?
  3. Wie unterscheiden sich die break- und continue-Anweisungen?

Referenzen