次の方法で共有


第 6 章 - フロー制御

スクリプトの作成

PowerShell ワンライナーの記述からスクリプトの記述に移行すると、より複雑に聞こえます。 スクリプトは、.ps1 ファイルとして保存する以外は、PowerShell コンソールで対話形式で実行するのと同じコマンドまたは同様のコマンドに過ぎない。 foreach コマンドレットの代わりに ForEach-Object ループなど、使用できるスクリプトコンストラクトがいくつかあります。 この違いは、foreach が言語キーワードと ForEach-Object コマンドレットのエイリアスの両方であることを考慮すると、初心者にとって混乱を招く可能性があります。

ループ

PowerShell の最適な側面の 1 つは、そのスケーラビリティです。 1 つのアイテムに対してタスクを実行する方法を学習したら、同じアクションを数百の項目に適用するのとほぼ同じ簡単な方法です。 PowerShell でさまざまな種類のループのいずれかを使用して、項目をループ処理します。

ForEach-Object

ForEach-Object は、PowerShell ワンライナーなど、パイプライン内の項目を反復処理するためのコマンドレットです。 ForEach-Object は、パイプラインを介してオブジェクトをストリーミングします。

モジュールGet-Command のパラメーターは複数の文字列値を受け入れますが、プロパティ名によるパイプライン入力でのみ受け入れます。 次のシナリオでは、Get-Command パラメーターで使用するために する 2 つの文字列値をパイプする場合は、ForEach-Object コマンドレットを使用する必要があります。

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

前の例では、$_ は現在のオブジェクトです。 PowerShell バージョン 3.0 以降では、$PSItemの代わりに $_ を使用できます。 ほとんどの経験豊富な PowerShell ユーザーは、下位互換性があり、入力が少ないため、$_ を使用することを好みます。

foreach キーワードを使用する場合は、アイテムを反復処理する前にメモリに格納する必要があります。操作している項目の数がわからない場合は困難な場合があります。

$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 :

多くの場合、foreachForEach-Object などのループが必要です。 それ以外の場合は、エラー メッセージが表示されます。

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

それ以外の場合は、ループを排除しながら同じ結果を得ることができます。 オプションを理解するには、コマンドレットのヘルプを参照してください。

'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 :

前の例でわかるように、Get-ADComputer パラメーターは、パラメーター入力を使用して指定した場合にのみ 1 つの値を受け入れます。 ただし、パイプラインを使用すると、値が一度に 1 つずつ処理されるため、複数の値をコマンドに送信できます。

対して

指定した条件が true である間、for ループが反復処理されます。 私は頻繁に for ループを使用しませんが、用途があります。

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

前の例では、ループは数値 1 から始まり、カウンター変数 $i が 5 未満である限り続行することで、4 回繰り返されます。 合計 10 秒間スリープ状態になります。

推奨

PowerShell には、dodo untilの 2 つの異なる do while ループがあります。 do until は、指定した条件が false になるまで実行されます。

次の例は、推測した値が、Get-Random コマンドレットによって生成されたのと同じ数値になるまで続く数値ゲームです。

$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 は反対です。 指定した条件が true と評価されている限り実行されます。

$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

Do Whileループでテスト条件を「等しくない」に逆にすることで、同じ結果が得られます。

do ループは常に少なくとも 1 回実行されます。これは、ループの終了時に条件が評価されるためです。

つつ

do while ループと同様に、指定した条件が true である限り、while ループが実行されます。 ただし、違いは、コードを実行する前に、while ループがループの先頭にある条件を評価することです。 そのため、条件が false と評価された場合は実行されません。

次の例では、米国で感謝祭が行われる日を計算します。 常に 11 月の第 4 木曜日です。 ループは 11 月 22 日から始まり、1 日を追加しますが、曜日は木曜日と等しくありません。 22 日が木曜日の場合、ループはまったく実行されません。

$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

break、continue、return

break キーワードはループを終了するように設計されており、多くの場合、switch ステートメントで使用されます。 次の例では、break によって、最初のイテレーションの後にループが終了します。

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

continue キーワードは、ループの次の反復にスキップするように設計されています。

次の例では、数値 1、2、4、5 を出力します。 数値 3 をスキップし、ループの次の反復を続行します。 breakと同様に、continue 現在のイテレーションのみを除き、ループから抜け出します。 ループから抜け出して停止する代わりに、次のイテレーションで実行が続行されます。

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

return キーワードは、既存のスコープから抜け出すために設計されています。

次の例では、return が最初の結果を出力し、ループから抜け出していることに注意してください。

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

結果文のより詳細な説明は、私のブログ記事「PowerShellのreturnキーワード」で見つけることができます。

概要

この章では、PowerShell に存在するさまざまな種類のループについて学習しました。

レビュー

  1. ForEach-Object コマンドレットと foreach ステートメントの違いは何ですか?
  2. while ループや do while ループの代わりに do until ループを使用する主な利点は何ですか?
  3. break ステートメントと continue ステートメントの違い

関連情報