03. 実行環境と実行ポリシー

5.1 と 7 はなぜ共存するのか、なぜ既定でスクリプトが動かないのか

📅 作成: 2026-08-22 / 更新: 2026-08-24 / 対象: Windows PowerShell 5.1 + PowerShell 7

この章で何ができるようになるか

この章を終えると、書いたスクリプトが実際に動くようになります。
02 章まではファイルの作り方の話でした。ここではそれを実行する側の環境を整えます。「スクリプトが動かない」の原因は、ほぼこの章のどれかに当てはまります。

03.1 5.1 と 7 — 2つの PowerShell

まず名前の整理から

紛らわしいのですが、名前で世代が分かれています

呼び名バージョン実行ファイル本資料での表記
Windows PowerShell1.0 〜 5.1powershell.exe5.1
PowerShell6.0 〜 7.xpwsh.exepwsh 7

「Windows」が付くほうが古い世代です。6.0 でクロスプラットフォーム化したときに「Windows」が取れました。実行ファイル名も powershell.exe から pwsh.exe に変わっています。

両者は別のプログラムとして共存する

ここが重要です。7 を入れても 5.1 は消えません。上書きではなく、別の場所に別のプログラムとして入ります。

Windows PowerShell 5.1 Windows に最初から入っている PowerShell 7 自分で入れる 実行ファイル C:\Windows\System32\ WindowsPowerShell\v1.0\powershell.exe 実行ファイル C:\Program Files\PowerShell\7\ pwsh.exe プロファイル Documents\WindowsPowerShell\ プロファイル Documents\PowerShell\ 実行ファイルも設定も別々。片方を変えてももう片方には影響しない
図 03.1 — 5.1 と 7 は独立して共存する。設定を片方だけ直しても、もう片方には反映されない

豆知識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 の場合
PSVersion5.1.x7.x.x
PSEditionDesktopCore

PSEditionDesktop なら 5.1、Core なら 7 です。スクリプトの中で分岐したいときはこれを見ます。

if ($PSVersionTable.PSEdition -eq 'Core') {
    # PowerShell 7 での処理
} else {
    # Windows PowerShell 5.1 での処理
}

$host.Version は使わない 間違えやすい

$host.Version      # ✗ PowerShell のバージョンではない
$host は「PowerShell を動かしているアプリ」を指します。
コンソール・VS Code の統合ターミナル・ISE などはそれぞれ別のホストなので、$host.Version は環境によって異なる値を返します。PowerShell 本体のバージョンとは無関係です。
バージョンの確認には必ず $PSVersionTable を使ってください。

もう一方のバージョンを外から調べる

片方で作業中でも、もう一方に問い合わせられます。共存しているからこそできる確認方法です。

powershell.exe -NoProfile -Command '$PSVersionTable.PSVersion'   # 5.1 側
pwsh.exe       -NoProfile -Command '$PSVersionTable.PSVersion'   # 7 側

実測結果です。

実行ファイルPSVersionPSEdition
powershell.exe5.1.26100.9168Desktop
pwsh.exe7.6.3Core

-NoProfile を付けているのは、相手側のプロファイルに影響されないためです(03.3 で扱います)。

実務で効いてくる違い

観点5.1pwsh 7
土台.NET Framework 4.x.NET 8 以降
対応 OSWindows のみ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

どちらを使うか

どちらがどの Windows に入っているか

5.1OS に同梱されています。pwsh 7どの Windows にも入っていません。Windows 11 でも Server 2025 でも、必ず自分で入れます。

OS同梱される PowerShell7 の扱い
Windows 115.1別途導入
Windows 10(1607 以降)5.1別途導入
Windows Server 2016 / 2019 / 2022 / 20255.1別途導入
Windows 8.1 / Server 2012 R24.0まず WMF 5.1 で 5.1 に上げる
「7 を入れると 5.1 が消える」ことはありません。
5.1 は C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe、7 は C:\Program Files\PowerShell\7\pwsh.exe置き場所が別です。アンインストールも別々にできます。

PowerShell 7 の導入 — 3つの経路

経路向いている場面注意
winget自分の PC。1行で済むwinget が無い環境がある(下記)
MSIwinget が使えない環境。社内配布更新も手動
Microsoft Store個人利用で自動更新したいストアが無効化された組織では不可
winget install --id Microsoft.PowerShell --source winget

導入後、pwsh と打てば 7 が起動します。powershell は今までどおり 5.1 のままです。

winget が使えないときは MSI で入れる

次の環境では winget が使えません。業務 PC ではむしろこちらが普通です。

MSI は GitHub の公式リリースページから入手します。

リリースページの Assets を開き、PowerShell-7.x.y-win-x64.msi を選びます。32bit の PC なら -win-x86.msi、ARM なら -win-arm64.msi です。.zip もありますが、こちらはインストールせずに展開して使う形式で、PATH の登録も右クリックメニューも付きません。

ネットに繋がらない PC に入れるときは、繋がる PC で MSI を落として持ち込みます。
その際、ダウンロードした MSI には「インターネットから来た」印(Zone.Identifier)が付きます(03.2 で扱います)。MSI 自体は実行できますが、同じ経路で .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_MUMicrosoft Update 経由で自動更新する
MSI で入れたものは winget list に出ません。
この資料を書いた PC は MSI で 7.6.3 を入れていますが、winget list --id Microsoft.PowerShell「一致するインストール済みのパッケージが見つかりませんでした」と返します。一方、アンインストール情報(レジストリ)には PowerShell 7-x64 / 7.6.3.0 として登録されています。
「winget で確認できない=入っていない」ではありません。入っているかは pwsh -v で確かめてください。
PowerShell が初めての人へ
Node.js のバージョン共存に慣れている方へ — nvm のように「切り替える」のではなく、2つが同時に居座る方式です。どちらで動かすかは起動する実行ファイルで決まりますpowershellpwsh か)。切り替え操作は要りません。
そのぶん、片方で入れたモジュールや設定はもう片方に効きません。「入れたはずのモジュールが見つからない」ときは、たいてい別のバージョンで探しています。

03.2 実行ポリシー — なぜ動かないのか

最初に必ず出会うエラー

.ps1 を作って実行しようとすると、多くの環境で次のエラーが出ます。

.\hello.ps1 : このシステムではスクリプトの実行が無効になっているため、
ファイル C:\work\hello.ps1 を読み込むことができません。

これが実行ポリシーです。02 章で cmd ランチャーに -ExecutionPolicy Bypass と書いたのは、これを回避するためでした。

実行ポリシーはセキュリティ機能ではありません。
Microsoft 自身がそう明言しています。回避方法はいくらでもあり(実際 Bypass の一言で通ります)、悪意のある相手を止める力はありません。目的は「うっかり実行」の防止です。メールで届いた .ps1 を何も考えずダブルクリックしてしまう、といった事故を減らすための仕組みだと理解してください。

ポリシーの種類

意味使いどころ
Restrictedスクリプトを一切実行しないWindows クライアントの既定値であることが多い
AllSigned署名されたスクリプトのみ実行厳格な運用。自作スクリプトにも署名が要る
RemoteSignedローカル作成は実行可、ダウンロード品は署名が必要推奨開発時の現実的な落としどころ
Unrestrictedすべて実行(ダウンロード品は警告)非推奨
Bypass何もブロックせず警告も出さない自動実行するとき。Process スコープに限定して使う
Undefined未設定。上位スコープの値が使われる

スコープには優先順位がある

実行ポリシーは1つの値ではなく、5つのスコープの重ね合わせです。上にあるものが優先されます。

優先度 スコープ 高い MachinePolicy — グループポリシー(会社が配る設定) UserPolicy — グループポリシー(ユーザー単位) Process — この起動中だけ有効(-ExecutionPolicy はここ) CurrentUser — 自分のユーザーの設定(管理者権限が不要) LocalMachine — PC 全体の設定(管理者権限が必要) 低い 上から順に見ていき、最初に Undefined 以外だったものが採用される 会社のポリシーが設定されていると、自分では変えられないのはこのため
図 03.2 — 実行ポリシーのスコープ。上位が設定されていると下位の値は無視される

いまの状態を確認する

Get-ExecutionPolicy -List
        Scope ExecutionPolicy
        ----- ---------------
MachinePolicy       Undefined
   UserPolicy       Undefined
      Process          Bypass
  CurrentUser       Undefined
 LocalMachine    RemoteSigned

上から順に見て、最初に Undefined 以外だったものが採用されます。この例では ProcessBypass が効いており、下段の LocalMachineRemoteSigned は無視されます。ランチャーから -ExecutionPolicy Bypass で起動すると、この行が設定されます。

正しい対処

開発中の自分の PC なら

Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned

配布するスクリプトなら

相手の PC の設定を変えさせるのは筋が悪いので、ランチャー側で Process スコープだけ緩めます。02 章で作った形がこれです。

powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%~dp0foo.ps1"
-ExecutionPolicy Bypass が安全に使える理由。
このスイッチが効くのは Process スコープ、つまりその1回の起動中だけです。PC の設定を書き換えるわけではないので、他のスクリプトや次回以降の起動には影響しません。「一時的に、この実行に限って」緩めるのが正しい使い方です。逆に Set-ExecutionPolicy -Scope LocalMachine Bypass のような恒久的な緩和は避けてください。

ダウンロードしたファイルの印

RemoteSigned が「ダウンロード品」を見分けられるのは、ファイルに印が付いているからです。Windows はインターネットから来たファイルに Zone.Identifier という情報を付けます。

# 印が付いているか確認(5.1 / 7 共通)
Get-Item .\downloaded.ps1 -Stream Zone.Identifier

# 印を外す(内容を確認してから実行すること)
Unblock-File .\downloaded.ps1
PowerShell が初めての人へ
NTFS のファイルには、本体とは別に「代替データストリーム」という付箋のような領域があります。Zone.Identifier はそこに書かれる「このファイルはネットから来た」という記録です。ファイルサイズには現れず、コピー先によっては消えます(例: ZIP 経由や USB 経由)。
Zip で受け取ったスクリプトが動かないときは、展開前の zip を右クリック →[プロパティ]→[許可する]にチェックを入れてから展開すると、中のファイルに印が付きません。

03.3 プロファイルとモジュール

プロファイル — 起動時に自動で読まれるスクリプト

PowerShell は起動時にプロファイルという .ps1 を自動実行します。エイリアスや関数を常駐させたいときに使います。

# 自分のプロファイルの場所を表示(無くてもパスは返る)
$PROFILE

# 実際に存在するか
Test-Path $PROFILE

# 無ければ作って開く
if (-not (Test-Path $PROFILE)) { New-Item -ItemType File -Path $PROFILE -Force }
notepad $PROFILE
プロファイルの置き場所は 5.1 と 7 で違います。
5.1Documents\WindowsPowerShell\pwsh 7Documents\PowerShell\ の下です。片方に書いた設定はもう片方では読まれません。「7 では動くのに 5.1 では関数が無い」の典型的な原因がこれです。
バージョンプロファイルのパス
5.1C:\Users\<username>\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1
pwsh 7C:\Users\<username>\Documents\PowerShell\Microsoft.PowerShell_profile.ps1

-NoProfile を付ける理由

02 章のランチャーに -NoProfile を書きました。その意味がここで分かります。

配布するスクリプトには必ず -NoProfile を付けてください。
プロファイルは各人が自由に書ける場所です。そこで Set-Aliasfunction が上書きされていると、同じスクリプトが人によって違う動きをします。原因の特定が非常に困難になるため、最初から読ませないのが安全です。

モジュール — 機能の追加

PowerShell の機能拡張はモジュールという単位で配布されます。JavaScript でいう npm パッケージにあたります。

# 探す
Find-Module -Name ImportExcel

# 入れる(-Scope CurrentUser なら管理者権限が不要)
Install-Module -Name ImportExcel -Scope CurrentUser

# 入っているものを見る
Get-Module -ListAvailable

# 読み込む(多くは自動で読まれるので通常は不要)
Import-Module ImportExcel
PowerShellNode.js での対応物備考
Install-Modulenpm install -g既定はユーザー単位ではなく全体。-Scope CurrentUser を付ける
PowerShell Gallerynpm レジストリ公式の配布元
$env:PSModulePathNODE_PATHモジュールを探す場所の一覧
Import-Modulerequire / importPowerShell は自動読み込みが効くことが多い
PowerShell が初めての人へ
Node.js と違い、プロジェクトごとの node_modules にあたる仕組みがありません。モジュールはユーザー単位か PC 全体に入り、どのスクリプトからも見えます。
そのため「動かすのにどのモジュールが要るか」がスクリプトから読み取れません。配布するときは、必要なモジュールをファイル冒頭のコメントに書くか、#Requires -Modules ImportExcel と書いて明示してください。

5.1 と 7 でモジュールの置き場所も違う

$env:PSModulePath -split ';'

実行するバージョンによって異なる一覧が返ります。7 で入れたモジュールは 5.1 からは見えません(Windows 用の一部を除く)。プロファイルと同じ事情です。

03.4 VS Code で編集環境を固める

拡張機能を入れる

拡張機能マーケットプレースで 「PowerShell」(発行元 Microsoft) を入れます。これだけで補完・構文チェック・デバッグが揃います。

PowerShell ISE は使わない 選んでしまいやすい

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 で動いたのに本番で動かない

項目ISEコンソール
$host.NameWindows PowerShell ISE HostConsoleHost
$psISE使える存在しない
Write-Progress専用ペインに表示画面上部に表示
コンソールアプリとの対話正しく動かないことがある正常
$psISE を使ったコードは ISE 専用になります。
ISE の中では快適に動きますが、タスクスケジューラから実行した途端に落ちます。09.4 で扱う無人実行では、ISE も画面も存在しません。
既存の ISE 資産を触る場合でも、動作確認は必ずコンソールで行ってください。
用途使うもの
これから学ぶ・新しく書く推奨VS Code + PowerShell 拡張機能
既存の ISE 資産を保守するISE でも可。ただし動作確認はコンソールで
PowerShell 7 を使う不可ISE は選択肢にならない

02 章の規約を設定で自動化する

02 章で「ps1 は BOM 付き UTF-8 + CRLF」「bat は Shift-JIS + CRLF」と決めました。これは手作業で守るものではありません。拡張子ごとに設定しておけば、保存するだけで正しい形式になります。

settings.json 拡張子ごとに1回だけ設定 .ps1 を保存 BOM 付き UTF-8 CRLF .bat / .cmd を保存 Shift-JIS CRLF 毎回意識せずに 規約どおりになる
図 03.4 — 文字コードは人が守るものではなく、エディタに守らせるもの

settings.json の設定

{
    "[powershell]": {
        "files.encoding": "utf8bom",
        "files.eol": "\r\n"
    },
    "[bat]": {
        "files.encoding": "shiftjis",
        "files.eol": "\r\n"
    },
    "files.autoGuessEncoding": true
}
設定効果02 章との対応
files.encoding: utf8bomps1 を BOM 付き UTF-8 で保存する5.1 が ANSI と誤認するのを防ぐ
files.eol: \r\n改行を CRLF にする混在による diff の崩れを防ぐ
files.encoding: shiftjisbat を 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 の名前の整理と同じ規則になっています。

デバッグ

PowerShell が初めての人へ
PowerShell のデバッグは、停止した時点のシェルにそのまま入れるのが特徴です。ブレークポイントで止めたあと、デバッグコンソールで $_ や変数の中身を触ったり、Get-Member でオブジェクトの構造を調べたりできます。
「print デバッグ」に頼る前に、一度止めて中身を見る癖をつけると、次章以降のパイプライン処理の理解がずっと速くなります。

この章のまとめ

困りごと確認・対処
どっちで動いているか分からない$PSVersionTablePSEdition。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-WmiObjectGet-CimInstance に置き換える

覚えておく3点

  1. 5.1 と 7 は共存する別プログラム。実行ファイル・プロファイル・モジュールの置き場所がすべて別。「片方では動く」の原因はたいていこれ
  2. 実行ポリシーはセキュリティ機能ではない。うっかり実行の防止が目的なので、CurrentUserRemoteSigned、配布時は ProcessBypass が定石
  3. 文字コードの規約はエディタに守らせる.vscode/settings.json に書けばチーム全員に効く
次章の予告 — 04. 変数・型・演算子
環境が整ったので、ここからは言語そのものに入ります。JavaScript の書き方を左に、PowerShell を右に並べて対比しながら進めます。$ 記法、単一引用符と二重引用符の違い、そして比較演算子が既定で大文字小文字を区別しないという、経験者ほど引っかかる落とし穴を扱います。