【入門】PowerShell if not を使った条件分岐の基本

はい、承知いたしました。PowerShellで「~でない場合」という条件を表現するための、-not演算子を中心とした詳細な解説記事を作成します。PowerShellには直接の if not 構文は存在しませんので、その点を明確にし、同等の表現方法を徹底的に解説します。

以下が記事の内容です。


【入門】PowerShellで「~でない場合」を表現する:-not演算子を使った条件分岐の基本

はじめに

PowerShellスクリプトを書く上で、特定の条件が満たされたときに処理を実行したり、逆に特定の条件が満たされないときに処理を実行したりすることは不可欠です。このような「もし〇〇なら」「もし〇〇でないなら」といった判断を行うのが条件分岐です。

他のプログラミング言語に触れたことがある方の中には、「もし〇〇でないなら」という条件分岐を if not 条件式 のように書くことに慣れている方もいらっしゃるかもしれません。しかし、PowerShellには残念ながら直接的に if not という構文は存在しません。

では、PowerShellで「~でない場合」という条件はどのように書けば良いのでしょうか?

その答えは、-not 演算子を使うことです。-not 演算子は、PowerShellで条件式や変数の「真偽を反転させる」役割を果たします。この記事では、この -not 演算子を使った条件分岐の書き方を、基本的な使い方から応用、さらには-notが様々なデータ型に対してどのように振る舞うのか、そしてよくある落とし穴とその対策まで、詳細かつ網羅的に解説します。

この記事を読めば、PowerShellスクリプトで意図した通りの「~でない場合」の条件分岐を自在に記述できるようになるでしょう。

PowerShellに「if not」構文は存在しない

まず最初に明確にしておきます。PowerShellには、他の言語(例:Pythonの if not condition:)のような、if キーワードと not キーワードを組み合わせた直接的な構文は存在しません。

PowerShellの基本的な条件分岐の構文は以下の通りです。

powershell
if (<条件式>) {
# 条件式が $true と評価された場合に実行する処理
}

この <条件式> の部分に、条件が真 ($true) になるような式を記述します。では、「~でない場合」を表現するにはどうすれば良いのでしょうか?

ここで登場するのが、論理演算子である -not です。

核となる方法: -not 演算子を使った条件分岐

PowerShellで「条件が真 ($true) でない場合」、つまり「条件が偽 ($false) の場合」を表現する最も標準的かつ推奨される方法は、-not 演算子を条件式の前に付けることです。

-not 演算子は、後続の条件式や値のブール値を反転させます。

  • $true-not を付けると $false になります。
  • $false-not を付けると $true になります。

したがって、「条件式Aが真でない場合」は、-not 条件式A$true になる場合、と表現できます。

基本的な構文は以下のようになります。

powershell
if (-not <条件式>) {
# <条件式> が $false と評価された場合に実行する処理
}

例1:単純なブール値の反転

あるフラグ変数 $isProcessed$false の場合に処理を実行したいとします。

“`powershell
$isProcessed = $false

$isProcessed が $true ではない場合(つまり $false の場合)

if (-not $isProcessed) {
Write-Host “データはまだ処理されていません。”
# 処理を実行するコード…
$isProcessed = $true # 処理後フラグを立てる
}

$isProcessed が $true の場合

if ($isProcessed) {
Write-Host “データは処理済みです。”
}
“`

この例では、if (-not $isProcessed)$isProcessed$false であれば $true と評価されるため、ブロック内のコードが実行されます。

-not 演算子の詳細な挙動:非ブール値に対する評価

-not 演算子は、後続の値がブール値 ($true または $false) でない場合でも使用できます。PowerShellは、条件式内でブール値以外の値が使われた場合、自動的にその値をブール値に評価(変換)しようとします。この評価規則を理解することが、-not を正しく使う上で非常に重要です。

PowerShellにおける、さまざまなデータ型のブール値への評価規則(およびそれに対する -not の挙動)は以下のようになります。

元の値 PowerShellでのブール値評価 -not 適用後のブール値評価 -not を使った if 条件 意味(-not適用後)
$true $true $false if (-not $true) $true でない場合(偽)
$false $false $true if (-not $false) $false でない場合(真)
$null $false $true if (-not $null) $null である場合
0 (数値ゼロ) $false $true if (-not 0) 数値がゼロである場合
非ゼロの数値 (例: 5, -1) $true $false if (-not 5) 数値がゼロでない場合(偽)
"" (空文字列) $false $true if (-not "" 文字列が空である場合
非空文字列 (例: "hello") $true $false if (-not "hello") 文字列が空でない場合(偽)
@() (空の配列) $false $true if (-not @()) 配列が空である場合 ($nullも含む評価なので注意)
要素を持つ配列 (例: @(1,2)) $true $false if (-not @(1,2)) 配列が空でない場合(偽)
@{} (空のハッシュテーブル) $false $true if (-not @{}) ハッシュテーブルが空である場合 ($nullも含む評価なので注意)
要素を持つハッシュテーブル $true $false if (-not @{a=1}) ハッシュテーブルが空でない場合(偽)
$undefined $false $true if (-not $undefined) 未定義の変数である場合
$null のオブジェクト $true $false if (-not (New-Object PSObject)) オブジェクトが存在する場合(偽)

この表からわかる重要な点は以下の通りです。

  • $null、数値の 0、空文字列 ""、空のコレクション(配列やハッシュテーブル) は、ブール値としては $false と評価されます。したがって、これらの値に -not を付けると $true と評価されます。
  • 非ゼロの数値、非空文字列、要素を持つコレクション、およびほとんどの非 $null オブジェクト は、ブール値としては $true と評価されます。したがって、これらの値に -not を付けると $false と評価されます。

この挙動を利用すると、特定の状態を簡潔にチェックできます。

例2:変数が $null または空文字列かどうかのチェック

変数 $userName が設定されていない($null)または空文字列の場合にエラーメッセージを表示したい場合。

“`powershell
$userName = $null # または $userName = “”

$userName が $null または空文字列であれば $false と評価される -> -not で $true

if (-not $userName) {
Write-Error “ユーザー名が指定されていません。”
# スクリプトを終了するなど
# exit 1
} else {
Write-Host “ユーザー名は ‘$userName’ です。”
}

$userName = “Alice” # 値が設定されている場合
if (-not $userName) {
# ここは実行されない
} else {
Write-Host “ユーザー名は ‘$userName’ です。”
}
“`

ただし、文字列の場合に $null と空文字列を厳密に区別したい場合や、空白のみの文字列 (" ") も空とみなしたい場合は、.NET のメソッド [string]::IsNullOrEmpty()[string]::IsNullOrWhiteSpace() を使う方がより意図が明確になります。

“`powershell
$userName = ” ” # 空白のみの文字列

[string]::IsNullOrEmpty($userName) は $null または "" の場合に $true

[string]::IsNullOrWhiteSpace($userName) は $null, "", 空白のみの場合に $true

$userName が $null または空文字列でない場合

if (-not [string]::IsNullOrEmpty($userName)) {
Write-Host “ユーザー名が入力されています (空白のみの可能性あり): ‘$userName'”
}

$userName が $null, 空文字列, または空白のみでない場合

if (-not [string]::IsNullOrWhiteSpace($userName)) {
Write-Host “ユーザー名が有効な値です: ‘$userName'”
} else {
Write-Host “ユーザー名が無効です ($null, 空文字列, または空白のみ): ‘$userName'”
}
“`

この例のように、より特定の条件をチェックしたい場合は、-not を別の条件式と組み合わせて使うことが一般的です。

実用的なシナリオとコード例

-not 演算子を使った条件分岐は、実際のPowerShellスクリプトで非常によく使われます。ここではいくつかの一般的なシナリオにおける使用例を紹介します。

シナリオ1:ファイルやフォルダが存在しない場合の処理

ファイルやフォルダが存在するかどうかをチェックするには Test-Path コマンドレットを使います。Test-Path は存在すれば $true、存在しなければ $false を返します。したがって、「存在しない場合」をチェックするには -not を使います。

“`powershell
$filePath = “C:\Temp\my_log.txt”

ファイルが存在しない場合

if (-not (Test-Path -Path $filePath -PathType Leaf)) {
Write-Host “ファイル ‘$filePath’ が見つかりません。作成します…”
# ここにファイル作成処理などを記述
New-Item -Path $filePath -ItemType File -Force | Out-Null
Write-Host “ファイル ‘$filePath’ を作成しました。”
} else {
Write-Host “ファイル ‘$filePath’ は既に存在します。”
}

$folderPath = “C:\Backup”

フォルダが存在しない場合

if (-not (Test-Path -Path $folderPath -PathType Container)) {
Write-Host “フォルダ ‘$folderPath’ が見つかりません。作成します…”
# ここにフォルダ作成処理などを記述
New-Item -Path $folderPath -ItemType Directory -Force | Out-Null
Write-Host “フォルダ ‘$folderPath’ を作成しました。”
} else {
Write-Host “フォルダ ‘$folderPath’ は既に存在します。”
}
“`

Test-Path の戻り値(ブール値)に対して -not を適用することで、「存在しない」という条件を明確に表現できます。括弧 () を使って Test-Path のコマンド実行結果を先に評価させてから -not を適用するのが一般的な書き方です。

シナリオ2:コマンドレットの実行が失敗した場合の処理

PowerShellでは、多くのコマンドレットを実行した後、自動変数 $? にそのコマンドレットが成功したかどうかを示すブール値が格納されます。成功なら $true、失敗なら $false です。

したがって、直前のコマンドレットが失敗した場合の処理は if (-not $?) と記述できます。

“`powershell

存在しないファイルを取得しようとして、意図的にエラーを発生させる

Get-Content -Path “C:\NonExistentFile.txt” -ErrorAction SilentlyContinue

直前のコマンドレット (Get-Content) が失敗した場合

if (-not $?) {
Write-Warning “ファイルの取得に失敗しました。ファイルが存在しないか、アクセス権がありません。”
# 失敗時のログ記録や代替処理などを記述
} else {
Write-Host “ファイルの内容を取得しました。”
# 成功時の処理
}

存在するファイルを取得する (成功するはず)

Get-Content -Path $filePath -ErrorAction SilentlyContinue # 先ほど作成したファイル

直前のコマンドレット (Get-Content) が失敗した場合

if (-not $?) {
# ここは実行されない
} else {
Write-Host “ファイルの内容を取得しました。”
# 成功時の処理
}
“`

$? は非常に便利ですが、直前のコマンドレットの成否しか示さないため、連続するコマンドレットの中で使う場合は注意が必要です。また、パイプラインの中で使われると $? の値が変わる可能性もあります。より確実なエラーハンドリングには Try-Catch ブロックを使用することが推奨されますが、簡単な成否判定には if (-not $?) が役立ちます。

シナリオ3:配列やコレクションが空の場合の処理

先述の通り、空の配列 @() や空のハッシュテーブル @{} はブール値としては $false と評価されます。要素を持つコレクションは $true と評価されます。これを利用して、「コレクションが空である場合」をチェックできます。

“`powershell
$users = @() # 空の配列

$users が空の配列 ($false) または $null ($false) の場合 -> -not で $true

if (-not $users) {
Write-Host “ユーザーが見つかりませんでした。”
# ここに代替処理などを記述
} else {
Write-Host “ユーザーが $($users.Count) 人見つかりました。”
# ユーザー一覧を表示するなど
}

$users = “Alice”, “Bob” # 要素を持つ配列

$users が要素を持つ配列 ($true) の場合 -> -not で $false

if (-not $users) {
# ここは実行されない
} else {
Write-Host “ユーザーが $($users.Count) 人見つかりました。”
# ユーザー一覧を表示するなど
}
“`

注意点: $null の変数も $false と評価されるため、if (-not $users)$users$null の場合$users が空の配列 (@()) の場合の両方で $true となります。多くの場合、これで問題ありませんが、 $null と空の配列を厳密に区別したい場合は、-eq $null.Length プロパティ(配列の場合)を使う必要があります。

“`powershell
$users = @() # 空の配列

より厳密な空の配列判定: $users が $null ではなく、かつ要素数がゼロの場合

if ($users -ne $null -and $users.Length -eq 0) {
Write-Host “ユーザーが見つかりませんでした (空の配列)。”
}

または $null か空配列の場合

if ($users -eq $null -or $users.Length -eq 0) {
Write-Host “ユーザーが見つかりませんでした ($null または空の配列)。”
}

-not を使って「$nullでも空配列でもない場合」を判定

if (-not ($users -eq $null -or $users.Length -eq 0)) {
Write-Host “ユーザーが $($users.Count) 人見つかりました ($nullでも空配列でもない)。”
}
“`

-not を使う場合は、PowerShellが値をどのようにブール値に評価するかを理解しておくことが、意図しない挙動を防ぐ上で重要です。

-not と他の論理演算子の組み合わせ

-not 演算子は、-and-or といった他の論理演算子と組み合わせて、より複雑な条件式を構築できます。この場合、括弧 () を適切に使うことで、演算子の評価順序を明確にし、可読性を高めることが非常に重要です。

例1:条件Aが真でなく、かつ条件Bも真でない場合

これは if ((-not $conditionA) -and (-not $conditionB)) と書けます。

“`powershell
$isConfigured = $false
$isStarted = $false

設定されておらず、かつ、起動もされていない場合

if ((-not $isConfigured) -and (-not $isStarted)) {
Write-Host “システムは設定されておらず、起動もしていません。”
}
“`

例2:条件Aが真でなく、または条件Bが真でない場合

これは if ((-not $conditionA) -or (-not $conditionB)) と書けます。

“`powershell
$isLoggedIn = $true
$isAdmin = $false

ログイン状態でない、または管理者でない場合

if ((-not $isLoggedIn) -or (-not $isAdmin)) {
Write-Host “操作を実行する権限がありません。(ログイン状態でないか、管理者ではありません)”
}
“`

例3:複雑な条件式の否定

「条件Aが真で、かつ条件Bが真である」という条件全体の否定を考えます。これはデ・モルガンの法則 not (A and B) <=> (not A) or (not B) に従います。

“`powershell
$isValidInput = $false
$isAuthorized = $true

($isValidInput が true かつ $isAuthorized が true) でない場合

if (-not ($isValidInput -and $isAuthorized)) {
Write-Host “入力が無効であるか、または権限がありません。”
}

これは以下の条件式と同じ意味になります

if ((-not $isValidInput) -or (-not $isAuthorized)) {
Write-Host “入力が無効であるか、または権限がありません。”
}
“`

複雑な条件式を否定する場合は、条件式全体を括弧で囲み、その前に -not を置くことで、意図を明確にできます。

代替手段:ブール値との比較

「~でない場合」を表現するもう一つの方法として、条件式の結果を $false と直接比較する方法があります。

  • if (<条件式> -eq $false)
  • if (<条件式> -ne $true)

これらの構文も、-not <条件式> とほぼ同じ意味になります。

“`powershell
$isComplete = $false

-not を使う方法

if (-not $isComplete) {
Write-Host “処理は未完了です (-not を使用)。”
}

-eq $false を使う方法

if ($isComplete -eq $false) {
Write-Host “処理は未完了です (-eq $false を使用)。”
}

-ne $true を使う方法

if ($isComplete -ne $true) {
Write-Host “処理は未完了です (-ne $true を使用)。”
}
“`

どの方法を使うかは、個人の好みやコーディング規約にもよりますが、一般的には -not <条件式> が最も簡潔で、PowerShellコミュニティで広く使われている表現です。

ただし、以下のような場合は -eq $false-ne $true の方が適していることもあります。

  1. 可読性: 条件式が複雑な場合や、特定のコマンドレットの戻り値( $true$false 以外の値も返す可能性があるもの)に対して比較を行う場合など、明示的に $false$true と比較した方がコードの意図が分かりやすい場合があります。
  2. 厳密なブール値チェック: まれなケースですが、-not が PowerShellの自動的なブール値評価に依存するのに対し、-eq $false-ne $true は比較演算子としての振る舞いをします。通常は違いを意識する必要はありませんが、PowerShellの型変換の挙動に深く関わる場面では、比較演算子のほうが予測しやすい挙動を示すことがあります。

ほとんどの場合、-not <条件式> を使うのがシンプルで良いでしょう。特に、変数やシンプルなコマンドレット (Test-Path, $? など) の結果に対する「~でない」を表現する際には、-not が最も自然な表現です。

代替手段:否定演算子 ! (非推奨)

一部のプログラミング言語では、否定演算子として !(エクスクラメーションマーク)を使います。PowerShellでも ! は論理否定演算子として機能します。

“`powershell

$isAvailable が $false の場合

if (!$isAvailable) {
Write-Host “リソースは利用できません (! を使用)。”
}
“`

この if (!<条件式>) という構文も技術的には可能で、-not <条件式> とほぼ同じ意味になります。

しかし、PowerShellでは論理演算子として -not を使うのが一般的で、! はあまり推奨されません。 その理由は以下の通りです。

  1. PowerShellの標準: PowerShellの他の論理演算子(-and, -or)がハイフン付きの単語であるため、-not も含めて一貫性があります。! は他の演算子と形式が異なります。
  2. 可読性: -not は単語として「ではない」という意味が分かりやすいですが、! は記号であるため、特にPowerShellに慣れていない人にとっては直感的に理解しにくい場合があります。
  3. エイリアスとの衝突: !Invoke-History コマンドレットのエイリアスとしてデフォルトで定義されています。単独で ! と書くとコマンド履歴の実行と解釈されるため、条件式内で使う場合も、他のコマンドレットとの組み合わせなどで予期せぬ挙動を引き起こす可能性がゼロではありません(特にインタラクティブなセッションで)。
  4. 他の記号との見間違い: ! はプログラミング初心者にとって、他の記号(例えば ===)と見間違えやすいという側面もあります。

これらの理由から、PowerShellでは論理否定には -not を使うのがベストプラクティスとされています。特別な理由がない限り、! ではなく -not を使いましょう。

else および elseif との組み合わせ

「~でない場合」の条件分岐は、もちろん elseelseif ブロックと組み合わせて使うことができます。

if (-not condition) { ... } else { ... } のパターン

条件が満たされない場合と、満たされる場合で異なる処理を行いたい場合に使います。

“`powershell
$serviceName = “MyService”
$service = Get-Service -Name $serviceName -ErrorAction SilentlyContinue

サービスが見つからなかった場合 (Get-Service がエラーになり、$service が $null または未定義になり、-not で $true)

if (-not $service) {
Write-Error “サービス ‘$serviceName’ が見つかりませんでした。”
# サービスのインストール処理など
} else {
# サービスが見つかった場合
Write-Host “サービス ‘$serviceName’ は見つかりました。現在の状態: $($service.Status)”
# サービスの状態チェックや操作など
}
“`

この例では、Get-Service が指定したサービスを見つけられなかった場合、-not $service$true となり、if ブロックが実行されます。サービスが見つかった場合は $service はオブジェクトとなり $true と評価されるため、-not $service$false となり else ブロックが実行されます。

elseif との組み合わせ

複数の条件を段階的にチェックする中で、特定の条件の否定を判定したい場合に使います。

“`powershell
$progress = 75 # 0から100の数値

if ($progress -ge 100) {
Write-Host “完了しました。”
} elseif ($progress -ge 50) {
Write-Host “半分以上完了しています。”
} elseif (-not ($progress -ge 0 -and $progress -lt 50)) {
# 進捗が 0以上50未満 でない場合
# つまり、50以上の場合(ただし、最初のelseifで捕捉されている)
# あるいは、$progress が数値でないなどの異常値の場合
# この例では、論理的には前のelseifで捕捉されるため、このブロックは実行されにくいが、構文の例として
Write-Host “進捗が50未満ではありません。”
} else {
# 0未満の場合、または最初の2つの条件(>=100, >=50)を満たさない場合
# ただし数値の例なので、$progress < 0 の場合か、$progress >= 0 かつ $progress < 50 の場合
Write-Host “進捗は50未満です。”
}
“`

elseif の条件式の中でも -not を自由に使うことができます。複雑な条件判断を行う際には、条件の範囲や組み合わせをよく検討し、括弧を使って明確に記述することが重要です。

ベストプラクティスと可読性

-not 演算子を使った条件分岐を記述する上で、コードの可読性を高め、エラーを防ぐためのいくつかのベストプラクティスがあります。

  1. 括弧を適切に使う: -not は後続の単一の要素(変数、コマンドレット、式の結果など)に適用されます。複雑な条件式全体を否定したい場合は、その条件式全体を括弧で囲み、-not を括弧の前に置きます。if (-not (Test-Path ...)) のように、コマンドレットの実行結果に適用する場合も括弧を使うのが一般的です。これにより、何を否定しているのかが明確になります。

    “`powershell

    良い例: 括弧で明確にする

    if (-not (Test-Path -Path $filePath)) { … }

    悪い例: Test-Path -Path $filePath の結果ではなく、-not Test-Path という構文エラーになる可能性

    または意図しない評価になる可能性

    if (-not Test-Path -Path $filePath) { … } # これは構文として成立しないか、意図しない評価になる

    良い例: 複雑な条件式全体を否定

    if (-not ($conditionA -and $conditionB)) { … }
    “`

  2. -not の適用範囲を限定する: 一つの条件式の中で -not を多用すると、条件が読みにくくなります。「AでもなくBでもない」を if ((-not $A) -and (-not $B)) と書くのは良いですが、「Aでもなく、またはBでもなく、かつCである」のように複雑になる場合は、肯定形の条件に変換できないか検討するか、条件を複数の if / elseif に分けることを検討しましょう。

  3. PowerShellのブール値評価規則を理解する: $null, 0, "", 空のコレクションなどが $false と評価されることを常に意識しておきましょう。if (-not $variable) のような書き方が、変数が $null や空であることのチェックに使えることを知っておくと便利ですが、厳密な判定が必要な場合は他の方法 (-eq $null, .Length -eq 0, [string]::IsNullOrEmpty) を検討しましょう。
  4. 肯定形での表現も検討する: 「~でない場合」という否定形よりも、「~である場合」という肯定形で表現した方が自然で分かりやすい場合があります。例えば、「ファイルが存在しない場合」を if (-not (Test-Path ...)) と書くのは自然ですが、「サービスが実行中 でない 場合に開始する」という処理は、直接的に「サービスが停止中の場合に開始する」という肯定形で if ($service.Status -ne "Running") { Start-Service ... } または if ($service.Status -eq "Stopped") { Start-Service ... } と書く方が直感的かもしれません。常に否定形が良いわけではなく、最も分かりやすい表現を選択することが重要です。
  5. コメントを活用する: 特に複雑な条件式の場合や、-not が非自明な値に適用されている場合は、その条件が何をチェックしているのかをコメントで記述すると、後からコードを読んだ人が理解しやすくなります。

まとめ

この記事では、PowerShellで「~でない場合」という条件分岐を記述する方法について、詳細に解説しました。重要なポイントは以下の通りです。

  • PowerShellには直接的な if not 構文は存在しません。
  • 最も標準的で推奨される方法は、-not 演算子を条件式の前に付けることです。if (-not <条件式>) { ... }
  • -not 演算子は、真偽値を反転させるだけでなく、$null、数値の 0、空文字列 ""、空のコレクションなどを $true に評価します。このブール値評価規則を理解することが重要です。
  • Test-Path の結果、$? 自動変数、変数が $null かどうか、コレクションが空かどうかなど、様々なシナリオで -not を活用できます。
  • -and-or と組み合わせて複雑な条件式を作ることも可能です。この場合、括弧 () を使って評価順序を明確にしましょう。
  • 代替手段として、if (<条件式> -eq $false)if (<条件式> -ne $true) もありますが、一般的には -not が最もPowerShellらしい表現です。
  • 否定演算子 ! も使えますが、PowerShellの標準的な書き方ではないため、-not を使うことが推奨されます。
  • elseelseif ブロックと組み合わせて、より複雑な条件分岐フローを構築できます。
  • コードの可読性を高めるために、括弧の適切な使用、 -not の適用範囲の検討、そして場合によっては肯定形での表現を検討することが重要です。

-not 演算子は、PowerShellスクリプトにおける条件分岐の非常に強力なツールです。その挙動をしっかり理解し、この記事で紹介した様々な使用例やベストプラクティスを参考に、あなたのスクリプトで積極的に活用してみてください。これにより、より柔軟で堅牢なスクリプトを作成できるようになるはずです。


コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

上部へスクロール