紛らわしいのですが、名前で世代が分かれています。
| 呼び名 | バージョン | 実行ファイル | 本資料での表記 |
|---|---|---|---|
| Windows PowerShell | 1.0 〜 5.1 | powershell.exe | 5.1 |
| PowerShell | 6.0 〜 7.x | pwsh.exe | pwsh 7 |
「Windows」が付くほうが古い世代です。6.0 でクロスプラットフォーム化したときに「Windows」が取れました。実行ファイル名も powershell.exe から pwsh.exe に変わっています。
ここが重要です。7 を入れても 5.1 は消えません。上書きではなく、別の場所に別のプログラムとして入ります。
豆知識5.1 の実行ファイルが WindowsPowerShell\v1.0\ の下にあることに気づきましたか。バージョン 5.1 なのに v1.0 フォルダです。互換性のためにパスを変えられなくなった結果で、.ps1 の「1」と同じ事情です。
$PSVersionTable
実行すると次のように出ます(PowerShell 7 の例)。
Name Value
---- -----
PSVersion 7.6.3
PSEdition Core
OS Microsoft Windows 10.0.26200
Platform Win32NT
| 項目 | 5.1 の場合 | 7 の場合 |
|---|---|---|
PSVersion | 5.1.x | 7.x.x |
PSEdition | Desktop | Core |
PSEdition が Desktop なら 5.1、Core なら 7 です。スクリプトの中で分岐したいときはこれを見ます。
if ($PSVersionTable.PSEdition -eq 'Core') {
# PowerShell 7 での処理
} else {
# Windows PowerShell 5.1 での処理
}
$host.Version は使わない 間違えやすい$host.Version # ✗ PowerShell のバージョンではない
$host は「PowerShell を動かしているアプリ」を指します。$host.Version は環境によって異なる値を返します。PowerShell 本体のバージョンとは無関係です。$PSVersionTable を使ってください。
片方で作業中でも、もう一方に問い合わせられます。共存しているからこそできる確認方法です。
powershell.exe -NoProfile -Command '$PSVersionTable.PSVersion' # 5.1 側
pwsh.exe -NoProfile -Command '$PSVersionTable.PSVersion' # 7 側
実測結果です。
| 実行ファイル | PSVersion | PSEdition |
|---|---|---|
| powershell.exe | 5.1.26100.9168 | Desktop |
| pwsh.exe | 7.6.3 | Core |
-NoProfile を付けているのは、相手側のプロファイルに影響されないためです(03.3 で扱います)。
| 観点 | 5.1 | pwsh 7 |
|---|---|---|
| 土台 | .NET Framework 4.x | .NET 8 以降 |
| 対応 OS | Windows のみ | Windows / Linux / macOS |
| 入手方法 | Windows に標準搭載 | winget や MSI で別途導入 |
| 今後の更新 | セキュリティ修正のみ(機能追加は終了) | 機能追加が継続 |
| 既定の文字コード | ANSI / UTF-16LE が混在(02 章参照) | UTF-8 に統一 |
| WMI 操作 | Get-WmiObject が使える | 削除済み。Get-CimInstance を使う |
| 条件付き実行 | なし | && / || が使える |
| 三項演算子 | なし | $a ? $b : $c |
| 並列処理 | なし | ForEach-Object -Parallel |
Get-WmiObject が 7 で消えているのは要注意です。Get-WmiObject を使っています。7 で実行すると「コマンドレットが見つかりません」で止まります。置き換え先は Get-CimInstance で、引数もほぼ同じです。
# 5.1 の書き方(7 では動かない)
Get-WmiObject Win32_OperatingSystem
# 両方で動く書き方
Get-CimInstance Win32_OperatingSystem
5.1 はOS に同梱されています。pwsh 7 はどの Windows にも入っていません。Windows 11 でも Server 2025 でも、必ず自分で入れます。
| OS | 同梱される PowerShell | 7 の扱い |
|---|---|---|
| Windows 11 | 5.1 | 別途導入 |
| Windows 10(1607 以降) | 5.1 | 別途導入 |
| Windows Server 2016 / 2019 / 2022 / 2025 | 5.1 | 別途導入 |
| Windows 8.1 / Server 2012 R2 | 4.0 | まず WMF 5.1 で 5.1 に上げる |
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe、7 は C:\Program Files\PowerShell\7\pwsh.exe と置き場所が別です。アンインストールも別々にできます。
| 経路 | 向いている場面 | 注意 |
|---|---|---|
| winget | 自分の PC。1行で済む | winget が無い環境がある(下記) |
| MSI | winget が使えない環境。社内配布 | 更新も手動 |
| Microsoft Store | 個人利用で自動更新したい | ストアが無効化された組織では不可 |
winget install --id Microsoft.PowerShell --source winget
導入後、pwsh と打てば 7 が起動します。powershell は今までどおり 5.1 のままです。
次の環境では winget が使えません。業務 PC ではむしろこちらが普通です。
MSI は GitHub の公式リリースページから入手します。
リリースページの Assets を開き、PowerShell-7.x.y-win-x64.msi を選びます。32bit の PC なら -win-x86.msi、ARM なら -win-arm64.msi です。.zip もありますが、こちらはインストールせずに展開して使う形式で、PATH の登録も右クリックメニューも付きません。
.ps1 を持ち込むと RemoteSigned で止まるので、Unblock-File が要ります。
# 画面を出して入れる
msiexec.exe /i PowerShell-7.6.3-win-x64.msi
# 無人で入れる(社内配布・タスクから叩く場合)
msiexec.exe /i PowerShell-7.6.3-win-x64.msi /quiet /norestart
# 右クリックメニューと「ここで開く」を付けて無人で入れる
msiexec.exe /i PowerShell-7.6.3-win-x64.msi /quiet /norestart `
ADD_EXPLORER_CONTEXT_MENU_OPENPOWERSHELL=1 `
ADD_FILE_CONTEXT_MENU_RUNPOWERSHELL=1 `
ENABLE_PSREMOTING=0 `
REGISTER_MANIFEST=1
| MSI のオプション | 意味 |
|---|---|
| ADD_EXPLORER_CONTEXT_MENU_OPENPOWERSHELL | フォルダの右クリックに「PowerShell 7 で開く」を追加 |
| ADD_FILE_CONTEXT_MENU_RUNPOWERSHELL | .ps1 の右クリックに「PowerShell 7 で実行」を追加 |
| ENABLE_PSREMOTING | リモート実行を有効にする。不要なら 0 |
| REGISTER_MANIFEST | イベントログにログを書けるようにする |
| USE_MU / ENABLE_MU | Microsoft Update 経由で自動更新する |
winget list に出ません。winget list --id Microsoft.PowerShell は「一致するインストール済みのパッケージが見つかりませんでした」と返します。一方、アンインストール情報(レジストリ)には PowerShell 7-x64 / 7.6.3.0 として登録されています。pwsh -v で確かめてください。
powershell か pwsh か)。切り替え操作は要りません。.ps1 を作って実行しようとすると、多くの環境で次のエラーが出ます。
.\hello.ps1 : このシステムではスクリプトの実行が無効になっているため、
ファイル C:\work\hello.ps1 を読み込むことができません。
これが実行ポリシーです。02 章で cmd ランチャーに -ExecutionPolicy Bypass と書いたのは、これを回避するためでした。
Bypass の一言で通ります)、悪意のある相手を止める力はありません。目的は「うっかり実行」の防止です。メールで届いた .ps1 を何も考えずダブルクリックしてしまう、といった事故を減らすための仕組みだと理解してください。
| 値 | 意味 | 使いどころ |
|---|---|---|
Restricted | スクリプトを一切実行しない | Windows クライアントの既定値であることが多い |
AllSigned | 署名されたスクリプトのみ実行 | 厳格な運用。自作スクリプトにも署名が要る |
RemoteSigned | ローカル作成は実行可、ダウンロード品は署名が必要 | 推奨開発時の現実的な落としどころ |
Unrestricted | すべて実行(ダウンロード品は警告) | 非推奨 |
Bypass | 何もブロックせず警告も出さない | 自動実行するとき。Process スコープに限定して使う |
Undefined | 未設定。上位スコープの値が使われる | — |
実行ポリシーは1つの値ではなく、5つのスコープの重ね合わせです。上にあるものが優先されます。
Get-ExecutionPolicy -List
Scope ExecutionPolicy
----- ---------------
MachinePolicy Undefined
UserPolicy Undefined
Process Bypass
CurrentUser Undefined
LocalMachine RemoteSigned
上から順に見て、最初に Undefined 以外だったものが採用されます。この例では Process の Bypass が効いており、下段の LocalMachine の RemoteSigned は無視されます。ランチャーから -ExecutionPolicy Bypass で起動すると、この行が設定されます。
Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned
CurrentUser スコープのため)相手の PC の設定を変えさせるのは筋が悪いので、ランチャー側で Process スコープだけ緩めます。02 章で作った形がこれです。
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%~dp0foo.ps1"
-ExecutionPolicy Bypass が安全に使える理由。Set-ExecutionPolicy -Scope LocalMachine Bypass のような恒久的な緩和は避けてください。
RemoteSigned が「ダウンロード品」を見分けられるのは、ファイルに印が付いているからです。Windows はインターネットから来たファイルに Zone.Identifier という情報を付けます。
# 印が付いているか確認(5.1 / 7 共通)
Get-Item .\downloaded.ps1 -Stream Zone.Identifier
# 印を外す(内容を確認してから実行すること)
Unblock-File .\downloaded.ps1
Zone.Identifier はそこに書かれる「このファイルはネットから来た」という記録です。ファイルサイズには現れず、コピー先によっては消えます(例: ZIP 経由や USB 経由)。PowerShell は起動時にプロファイルという .ps1 を自動実行します。エイリアスや関数を常駐させたいときに使います。
# 自分のプロファイルの場所を表示(無くてもパスは返る)
$PROFILE
# 実際に存在するか
Test-Path $PROFILE
# 無ければ作って開く
if (-not (Test-Path $PROFILE)) { New-Item -ItemType File -Path $PROFILE -Force }
notepad $PROFILE
Documents\WindowsPowerShell\、pwsh 7 は Documents\PowerShell\ の下です。片方に書いた設定はもう片方では読まれません。「7 では動くのに 5.1 では関数が無い」の典型的な原因がこれです。
| バージョン | プロファイルのパス |
|---|---|
| 5.1 | C:\Users\<username>\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1 |
| pwsh 7 | C:\Users\<username>\Documents\PowerShell\Microsoft.PowerShell_profile.ps1 |
-NoProfile を付ける理由02 章のランチャーに -NoProfile を書きました。その意味がここで分かります。
-NoProfile を付けてください。Set-Alias や function が上書きされていると、同じスクリプトが人によって違う動きをします。原因の特定が非常に困難になるため、最初から読ませないのが安全です。
PowerShell の機能拡張はモジュールという単位で配布されます。JavaScript でいう npm パッケージにあたります。
# 探す
Find-Module -Name ImportExcel
# 入れる(-Scope CurrentUser なら管理者権限が不要)
Install-Module -Name ImportExcel -Scope CurrentUser
# 入っているものを見る
Get-Module -ListAvailable
# 読み込む(多くは自動で読まれるので通常は不要)
Import-Module ImportExcel
| PowerShell | Node.js での対応物 | 備考 |
|---|---|---|
Install-Module | npm install -g | 既定はユーザー単位ではなく全体。-Scope CurrentUser を付ける |
| PowerShell Gallery | npm レジストリ | 公式の配布元 |
$env:PSModulePath | NODE_PATH | モジュールを探す場所の一覧 |
Import-Module | require / import | PowerShell は自動読み込みが効くことが多い |
node_modules にあたる仕組みがありません。モジュールはユーザー単位か PC 全体に入り、どのスクリプトからも見えます。#Requires -Modules ImportExcel と書いて明示してください。
$env:PSModulePath -split ';'
実行するバージョンによって異なる一覧が返ります。7 で入れたモジュールは 5.1 からは見えません(Windows 用の一部を除く)。プロファイルと同じ事情です。
拡張機能マーケットプレースで 「PowerShell」(発行元 Microsoft) を入れます。これだけで補完・構文チェック・デバッグが揃います。
Windows のスタートメニューには 「Windows PowerShell ISE」 という項目があります。VS Code が普及する前の標準的なスクリプト編集ツールで、いまも標準搭載されています。
C:\Windows\System32\WindowsPowerShell\v1.0\powershell_ise.exe
上下2ペインで「上で編集、下のコンソールで実行」ができる便利な作りですが、これから学ぶなら選ばないでください。理由は3つあります。
| 理由 | 内容 |
|---|---|
| ① 5.1 専用 | pwsh 7 では使えない。ISE のコンソールは常に 5.1 で、7 に切り替えられない |
| ② 開発が終了 | Microsoft がメンテナンスモードと宣言済み。新機能は追加されない。公式の推奨は VS Code |
| ③ 挙動が違う | ISE は別のホストなので、コンソールと動作が一致しない箇所がある(下記) |
| 項目 | ISE | コンソール |
|---|---|---|
| $host.Name | Windows PowerShell ISE Host | ConsoleHost |
| $psISE | 使える | 存在しない |
| Write-Progress | 専用ペインに表示 | 画面上部に表示 |
| コンソールアプリとの対話 | 正しく動かないことがある | 正常 |
$psISE を使ったコードは ISE 専用になります。| 用途 | 使うもの |
|---|---|
| これから学ぶ・新しく書く | 推奨VS Code + PowerShell 拡張機能 |
| 既存の ISE 資産を保守する | ISE でも可。ただし動作確認はコンソールで |
| PowerShell 7 を使う | 不可ISE は選択肢にならない |
02 章で「ps1 は BOM 付き UTF-8 + CRLF」「bat は Shift-JIS + CRLF」と決めました。これは手作業で守るものではありません。拡張子ごとに設定しておけば、保存するだけで正しい形式になります。
{
"[powershell]": {
"files.encoding": "utf8bom",
"files.eol": "\r\n"
},
"[bat]": {
"files.encoding": "shiftjis",
"files.eol": "\r\n"
},
"files.autoGuessEncoding": true
}
| 設定 | 効果 | 02 章との対応 |
|---|---|---|
files.encoding: utf8bom | ps1 を BOM 付き UTF-8 で保存する | 5.1 が ANSI と誤認するのを防ぐ |
files.eol: \r\n | 改行を CRLF にする | 混在による diff の崩れを防ぐ |
files.encoding: shiftjis | bat を Shift-JIS で保存する | cmd.exe のコードページに合わせる |
files.autoGuessEncoding | 既存ファイルを開くとき文字コードを推測する | 過去のファイルを開いて壊すのを防ぐ |
.vscode/settings.json を作って上記を書けば、チーム全員に同じ規約が効きます。個人設定に頼ると、新しく参加した人のファイルだけ形式が違う、という事態が起こります。
VS Code のターミナルは + の横の ∨ から起動するシェルを選べます。PowerShell(5.1)と PowerShell 7 は別項目として並びます。動作確認は両方で行うのが安全です。
// 既定を PowerShell 7 にする場合
"terminal.integrated.defaultProfile.windows": "PowerShell"
紛らわしいVS Code の表示では、7 のほうが「PowerShell」、5.1 が「Windows PowerShell」です。03.1 の名前の整理と同じ規則になっています。
$data.Count など)$_ や変数の中身を触ったり、Get-Member でオブジェクトの構造を調べたりできます。| 困りごと | 確認・対処 |
|---|---|
| どっちで動いているか分からない | $PSVersionTable の PSEdition。Desktop なら 5.1、Core なら 7 |
| スクリプトが実行できない | Get-ExecutionPolicy -List で確認 → Set-ExecutionPolicy -Scope CurrentUser RemoteSigned |
| 配布先で実行できない | ランチャーに -ExecutionPolicy Bypass(Process スコープのみ) |
| ダウンロードした ps1 が動かない | Unblock-File、または zip の段階で[許可する] |
| 入れたモジュールが見つからない | 別のバージョンで探している可能性。$env:PSModulePath を確認 |
| プロファイルの設定が効かない | 5.1 と 7 で置き場所が違う。$PROFILE で実際のパスを確認 |
| 古いサンプルが 7 で動かない | Get-WmiObject → Get-CimInstance に置き換える |
CurrentUser に RemoteSigned、配布時は Process に Bypass が定石.vscode/settings.json に書けばチーム全員に効く$ 記法、単一引用符と二重引用符の違い、そして比較演算子が既定で大文字小文字を区別しないという、経験者ほど引っかかる落とし穴を扱います。