[PowerShell]ワンライナーでコマンドの存在チェックし条件分岐させる方法
概要
コマンドプロンプトやPowerShellにおいてコマンドの存在チェックしTrue・Falseの真偽で条件分岐する方法をこちらの記事で見つけました。
PowerShellの欄をみると「&&
や||
に対応するものは、おそらくないだろう」という趣旨の記述があり、
深掘りして調べてみた結果、やり方が見つかったので紹介します。
この記事のターゲット
- PowerShellユーザーの方
- PowerShellコマンドレットの存在有無により真偽(True・False)で条件分岐させたい方
環境
PS C:\Users\XXXX> $PSVersionTable
Name Value
---- -----
PSVersion 7.3.8
PSEdition Core
GitCommitId 7.3.8
OS Microsoft Windows 10.0.19045
Platform Win32NT
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
WSManStackVersion 3.0
PS C:\Users\XXXX>
見つかった記事の内容
前述した通り、こちらでShellScript(シェルスクリプト)やコマンドプロンプトを始めとする環境で、
コマンドの存在チェックを行い存在有無の結果、True・Falseの真偽で処理を分岐させる方法が紹介されていました。
その内、PowerShellの箇所で以下のように紹介されていました。
# PowerShell
### ワンライナー
&&
や||
に対応するものはたぶんない ?### 複数行
Get-Command
(gcm
) コマンドレットを使う.gcm perldoc -ea SilentlyContinue | Out-Null if ($? -eq $true) { # コマンドが存在すれば Write-Output 'Success!' perldoc perldoc } else { # コマンドが存在しなければ Write-Error 'Error!' exit 1 }
簡潔に書くと:
if (gcm perldoc -ea SilentlyContinue) { # コマンドが存在すれば Write-Output 'Success!' perldoc perldoc } else { # コマンドが存在しなければ Write-Error 'Error!' exit 1 }
複数行でも実現できる為、あえてワンライナーでコーディングする必要はありませんが、
本当にワンライナーで実現する方法がないのか気になったので深掘りして調べてみました。
(個人的には、可読性を考えるとワンライナーよりも複数行が良いと思っています。)
対応方法
こちらの記事にある見出し「論理演算」の欄で「 &&
は -and
」「 ||
は -or
」と紹介されていたので、
「 -and
」を使ってワンライナーのコマンドを作ってみました。
PowerShellのワンライナーコマンド
コピー用(PowerShellのワンライナーコマンド)
(Get-Command -Name "対象コマンド名" -ErrorAction SilentlyContinue) -and (Write-Output "存在した場合のメッセージ") | Out-Null
-Not(Get-Command -Name "対象コマンド名" -ErrorAction SilentlyContinue) -and (Write-Error "存在しない場合のメッセージ") | Out-Null
上記で実現できましたが、他の言語やスクリプトなどと比較すると違和感のあるワンライナーになってしまいました。
以下がこれらのコマンドを実際に実行した結果です。
実際の実行結果
# Test-Path が存在するコマンドである為、「 Success! 」と表示
PS C:\Users\XXXX> (Get-Command -Name Test-Path -ErrorAction SilentlyContinue) -and (Write-Output 'Success!') | Out-Null
Success!
PS C:\Users\XXXX>
# perldoc が存在しないコマンドである為、「 Error! 」と表示
PS C:\Users\XXXX> -Not(Get-Command -Name perldoc -ErrorAction SilentlyContinue) -and (Write-Error 'Error!') | Out-Null
Error!
PS C:\Users\XXXX>
ちまみにGet-Command -Name "対象コマンド名" -ErrorAction SilentlyContinue
にパイプライン(|
)をつけた後、Where-Object(省略だと?{}
)というコマンド構成でどうにかできないか、
いろいろ試してみましたが、うまくいく方法を見つける事ができませんでした。
他にもっと良いやり方があるかもしれません。
;
)を使った方法
セミコロン(あと、ワンライナーの定義で複数コマンド(複文?)の構成がNG条件だとワンライナーに当たりませんが、
下記のやり方でも動作します。
(セミコロン ;
でコマンド同士を区切る事で複数行のコマンドを1行で実現可能 )
# コマンドレットやオプションを省略
# 「Get-Command → gcm」
# 「-ErrorAction → -ea」
gcm Test-Path -ea SilentlyContinue | Out-Null ; if ($?) {Write-Output 'Success!'}
gcm perldoc -ea SilentlyContinue | Out-Null ; if (-Not($?)) {Write-Error 'Error!'}
コピー用[セミコロン(;
)を使った方法]
gcm "対象コマンド名" -ea SilentlyContinue | Out-Null ; if ($?) {Write-Output "存在した場合のメッセージ"}
gcm "対象コマンド名" -ea SilentlyContinue | Out-Null ; if (-Not($?)) {Write-Error "存在しない場合のメッセージ"}
正直、前述した論理演算の -and
を使う方法より、こちらのセミコロン;
で区切る方法の方がわかりやすいと感じます。
補足事項:Get-Command と Find-Command の違いをBing AIに聞いてみた
脱線しますが、PowerShellのコマンドを調べる方法がGet-Command
以外にもFind-Command
というコマンドレットもありました。
公式のリファレンスを確認しましたが、いまいち違いがわからなかったので、Bing AI(Microsoft Copilot・Bing チャット)に聞いてみました。
Bing AIの回答内容 < クリックで折りたたみが開く >
❓ Bing AIへの依頼内容("より創造的に")
PowerShellにおけるコマンドレット「Get-Command」と「Find-Command」の違いを教えて
✅ Bing AIからの回答
こんにちは、これはBingです。PowerShellに関する質問をありがとうございます。😊
コマンドレット「Get-Command」と「Find-Command」の違いは次のとおりです。
- 「Get-Command」は、コンピューターにインストールされているすべてのコマンドを取得します。コマンドの種類や名前、動詞、名詞などで絞り込むことができます¹。
- 「Find-Command」は、登録済みのリポジトリ内のモジュールを検索し、その中に含まれるコマンドを取得します。モジュールの名前やバージョン、タグなどで絞り込むことができます²。
たとえば、「Get-Command -Verb Get」は、動詞が「Get」であるすべてのコマンドを表示します。一方、「Find-Command -Verb Get」は、リポジトリ内のモジュールに含まれる動詞が「Get」であるコマンドを表示します。
「Get-Command」は、モジュールを自動的にインポートすることができますが、「Find-Command」はインポートしません。インポートするには、「Find-Command」の結果を「Install-Module」にパイプする必要があります²。
以上が、「Get-Command」と「Find-Command」の違いについての説明です。参考になれば幸いです。👍
¹: Get-Command (Microsoft.PowerShell.Core) - PowerShell
²: Find-Command (PowerShellGet) - PowerShell | Microsoft Learnソース: Bing との会話 2023/10/26
(1) Find-Command (PowerShellGet) - PowerShell | Microsoft Learn. https://learn.microsoft.com/ja-jp/powershell/module/powershellget/find-command?view=powershellget-2.x.
(2) Get-Command (Microsoft.PowerShell.Core) - PowerShell. https://learn.microsoft.com/ja-jp/powershell/module/microsoft.powershell.core/get-command?view=powershell-7.3.
(3) Get-Command (Microsoft.PowerShell.Core) - PowerShell. https://learn.microsoft.com/ja-jp/powershell/module/microsoft.powershell.core/get-command?view=powershell-7.3.
(4) Find-Command (PowerShellGet) - PowerShell | Microsoft Learn. https://learn.microsoft.com/ja-jp/powershell/module/powershellget/find-command?view=powershellget-2.x.
(5) Powershellで分からないコマンドはPowershellで調べる - Qiita. https://qiita.com/Anubis_369/items/9e265f479187c40cc626.
(6) コマンドレットの概要 - PowerShell | Microsoft Learn. https://learn.microsoft.com/ja-jp/powershell/scripting/developer/cmdlet/cmdlet-overview?view=powershell-7.2.
(7) 【PowerShell】コマンド入門編(Get-Command) - なんだか .... https://nandakagoodvibes.hatenablog.com/entry/2021/07/18/164927.
Bing AIの回答によると、
-
Get-Command
は
すべてのコマンドリストから取得できるコマンド -
Find-Command
は
登録済みのリポジトリ内のモジュール検索で取得できるコマンド
という内容でした。
Find-Commandの公式リファレンスをみるとPowerShellのバージョンが 2.x までの文書しかないようです。
とくに、こだわりが無ければGet-Command
の方を使用した方が無難そうという事は何となくわかりました。
さらに補足情報:PowerShellにおける登録済みリポジトリ内のモジュールとは < クリックで折りたたみが開く >
❓ Bing AIへの依頼内容("より創造的に")
PowerShellにおける登録済みリポジトリ内のモジュールとは
✅ Bing AIからの回答
PowerShellにおける登録済みリポジトリ内のモジュールとは、PowerShellGetというモジュール管理システムで利用できるモジュールの集合です¹。登録済みリポジトリとは、モジュールを検索したりインストールしたりするためのソースの場所を指定したものです²。登録済みリポジトリは、PowerShellギャラリー³やNuGet⁴などのオンラインサービスや、ローカルフォルダやネットワーク共有などのオフラインソースに設定できます²。登録済みリポジトリを管理するには、Set-PSRepository⁵やFind-PSRepository⁶などのコマンドレットを使用します²。
以上が、PowerShellにおける登録済みリポジトリ内のモジュールについての説明です。参考になれば幸いです。👍
¹: PowerShellGet とは - PowerShell | Microsoft Learn
²: Set-PSRepository (PowerShellGet) - PowerShell | Microsoft Learn
³: [PowerShell Gallery | Home]
⁴: [NuGet Gallery | Home]
⁵: [Set-PSRepository (PowerShellGet) - PowerShell | Microsoft Learn]
⁶: [Find-PSRepository (PowerShellGet) - PowerShell | Microsoft Learn]ソース: Bing との会話 2023/10/26
(1) Set-PSRepository (PowerShellGet) - PowerShell | Microsoft Learn. https://learn.microsoft.com/ja-jp/powershell/module/powershellget/set-psrepository?view=powershellget-2.x.
(2) PowerShellにおけるモジュールの取扱い方 #PowerShell - Qiita. https://qiita.com/tomomoss/items/5f8c027f3bdc3b189791v
(3) モジュールのインポート方法 - Forsenergy. https://forsenergy.com/ja-jp/windowspowershellhelp/html/a21640bb-853f-4dc2-b43a-fb44d3a774b2.htm.
(4) undefined. https://someNuGetUrl.com/api/v2.
(5) undefined. https://someNuGetUrl.com/api/v2/packages.
(6) undefined. https://someNuGetUrl.com/api/v2/Packages.
(7) Set-PSRepository (PowerShellGet) - PowerShell | Microsoft Learn. https://learn.microsoft.com/ja-jp/powershell/module/powershellget/set-psrepository?view=powershellget-2.x.
(8) PowerShellにおけるモジュールの取扱い方 #PowerShell - Qiita. https://qiita.com/tomomoss/items/5f8c027f3bdc3b189791.
実際、私の環境における登録済みリポジトリ内のモジュールをGet-PSRepository
コマンドで調べてみました。
PS C:\Users\XXXX> Get-PSRepository
Name InstallationPolicy SourceLocation
---- ------------------ --------------
PSGallery Untrusted https://www.powershellgallery.com/api/v2
PS C:\Users\XXXX>
私の環境下で登録済みリポジトリ内のモジュールは「 PSGallery
」のみのようです。
これらの環境は触っていないので、おそらくこのコマンド結果は、初期設定の状態だと思われます。
- 参考情報:PSGalleryを「
Untrusted
からTrusted
」に変更する方法
"信頼されていない(Untrusted
)" から "信頼できる(Trusted
)"に変更。
https://tomoh1r.github.io/blog/2016/11201_how_to_make_psgallery_trusted_repository.html
参考情報
- コマンドが存在するかしないかを判定して条件分岐する構文のまとめ
https://qiita.com/skkzsh/items/d63861293fd6bde1b0d8
まとめ
- PowerShellでワンライナーでコマンドの存在チェックし条件分岐させる方法
-
純粋(?)なワンライナーの方法
コマンドが存在する場合(Get-Command -Name "対象コマンド名" -ErrorAction SilentlyContinue) -and (Write-Output "存在した場合のメッセージ") | Out-Null`
コマンドが存在しない場合-Not(Get-Command -Name "対象コマンド名" -ErrorAction SilentlyContinue) -and (Write-Error "存在しない場合のメッセージ") | Out-Null
-
複数コマンドで実行する方法
コマンドレットやオプションの記述を以下の通り省略。
「Get-Command → gcm」
「-ErrorAction → -ea」コマンドが存在する場合gcm "対象コマンド名" -ea SilentlyContinue | Out-Null ; if ($?) {Write-Output "存在した場合のメッセージ"}
コマンドが存在しない場合gcm "対象コマンド名" -ea SilentlyContinue | Out-Null ; if (-Not($?)) {Write-Error "存在しない場合のメッセージ"}
-
関連記事
Discussion