Skip to content

MS_PowerShellPS1File

nishi_74322014 edited this page Aug 31, 2026 · 1 revision

PowerShellのPS1ファイルの作成と実行

概要

PS1 ファイルの作成と実行について。

実行ポリシー

補足(実行ポリシーはセキュリティ境界ではない): 押さえておくべき点として、
Microsoft 自身が実行ポリシーをセキュリティ機能ではないと位置づけている。
本ページが挙げている回避方法(標準入力から流す、貼り付ける)が
成立することからも分かるとおり、
意図せずスクリプトを実行してしまう事故を防ぐための安全装置であって、
悪意ある実行を止めるものではない。

実際のセキュリティ境界は、

  • コード署名AllSigned + 証明書)
  • AppLocker / Windows Defender Application Control
  • PowerShell の制約言語モード(Constrained Language Mode)

の側にある。
したがって、本ページの運用時の実行ポリシーの検討は、
「事故防止をどのレベルで行うか」の判断として読むとよい。

実行ポリシーを変更

Set-ExecutionPolicy

  • 実行ポリシーを変更するには、Set-ExecutionPolicy を実行します。
Set-ExecutionPolicy RemoteSigned
  • RemoteSigned を指定すると、

    • ローカルコンピュータの .ps1 ファイルか、
    • ファイル共有またはダウンロードした署名付きの .ps1 ファイルが

    実行できます。

  • Set-ExecutionPolicy の設定は、恒久的に設定される。

    • Bypass(= 無制限に .ps1 を実行可能)に変更してそのまま放置しないように。
    • 用が済んだら、既定値の Restricted に戻しておきます。
Set-ExecutionPolicy Restricted
  • scope を指定して、設定変更の対象を限定することもできます。
    CurrentUser はこのコマンドを実行したユーザーだけ、設定変更します。
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser

補足(-Scope Process が最も影響が小さい): 本ページが挙げている
CurrentUser よりさらに限定的な Process スコープがある。

Set-ExecutionPolicy -Scope Process -ExecutionPolicy RemoteSigned

そのプロセス(そのウィンドウ)を閉じれば元に戻るため、
「用が済んだら戻す」という本ページの注意を、
戻し忘れの心配なく実現できる。
一時的な作業では、これが第一候補になる。

なお、スクリプトを 1 回だけ実行するなら、
起動時のパラメーターで指定する方法もある。

powershell -ExecutionPolicy Bypass -File .\script.ps1

こちらは既存の設定を一切変更しないため、
タスク スケジューラや BAT から呼ぶ場合の定番になる。

補足(RemoteSigned が効く仕組み): 「ダウンロードしたファイル」の判定は、
Zone.Identifier(Mark of the Web) という代替データ ストリームで行われる。
インターネットから取得したファイルには、これが自動的に付く。
自作したスクリプトなのにブロックされる場合は、

Unblock-File .\script.ps1

で解除できる。
これは VBA移行 で触れた
「インターネット由来の Office ファイルのマクロが既定でブロックされる」
のと同じ仕組みである。

運用時の実行ポリシー

メンテナンスや運用作業で .ps1 を使用する場合は、
通常時にどの実行ポリシーにしておくか、検討ください。

  • .ps1 ファイルに署名を行い、AllSigned にしておくか。
  • あるいは、RemoteSigned にしておくか。
  • それとも Restricted にしておき、都度実行ポリシーを変更するか。等

補足(実務での落としどころ): 一般に、

  • サーバ(運用スクリプトを常用する)RemoteSigned
    ローカルで作ったものは動き、外部から持ち込んだものは署名が要る。
  • クライアント(一般ユーザー)Restricted のまま、
    必要なものはグループ・ポリシーで配布・制御する。
  • 署名運用ができる組織AllSigned
    ただし、社内 CA とコード署名証明書の運用が前提になる。

という切り分けになる。
なお、グループ・ポリシーで設定した実行ポリシーは
Set-ExecutionPolicy より優先されるため、
ドメイン環境では GPO 側の設定を先に確認すること。

PowerShell -Command - 構文でスクリプトを読み込ませる

  • PowerShell コマンドプロンプトに手入力して逐次実行するかわりに、
    -Command - を使用して、標準入力からコマンドを連続実行できる。

  • 手打ちと同じなので、Set-ExecutionPolicy Restricted のままでも、実行可能。
    実行ポリシーをどうしても変更したくない場合の次善策として、使用できるか検討する意味は有ります。
    下の例の様に、bat ファイルと echo を組み合わせて、引数を与えることも出来ます。

batファイル

ps_test.bat

@( echo $arg1 = "%~1"
   echo $arg2 = "%~2"
   type ps_test.ps1 ) | powershell -command -

ps1ファイル

ps_test.ps1

function main() {
 $a = ($arg1 + $arg2)
 $b = ([int]$arg1 + [int]$arg2)
 write-output "string : $arg1 + $arg2 = $a"
 write-output "integer : $arg1 + $arg2 = $b"
}

$err=0
$ErrorActionPreference = "stop"
try {
  $log = main
} catch [Exception] {
  $err=1
  $log = $_
}

write-output $log
exit $err
  • .ps1try / catch} の下に空行があることに注意。
  • powershell コマンドを -Command - で読み込ませる場合、
    手入力と同じようにコードブロックの後に空行が必要です。

実行例

これを実行すると、echo の 2 つが ps_test.ps1 の先頭に挿入されて、
PowerShell コマンドプロンプトに手入力して逐次実行することになります。

ps_test 1 2

string : 1 + 2 = 12
integer : 1 + 2 = 3

標準入力を手入力の代わりに使用してしまうため、
スクリプトのなかでキー打鍵待ちのようなことは難しくなります。

補足(現在は -EncodedCommand という手もある): 同じく実行ポリシーを
変更せずに済む方法として、Base64 に符号化したコマンドを渡す
-EncodedCommand がある。

powershell -EncodedCommand <Base64(UTF-16LE)>

引用符のエスケープに悩まずに済む利点があるが、
難読化に使われることが多く、監視製品にマルウェア的挙動として
検知されやすい
という副作用がある。
運用スクリプトでは、素直に -ExecutionPolicy Bypass -File を使う方が無難。

PowerShell コマンドプロンプトの中に貼り付ける

  • PowerShell コマンドプロンプトの画面に、クリップボードからスクリプトを貼り付けます。

    • スクリプトは、テキストファイルなどで用意しておき、
    • メモ帳などで開いたら、テキスト全体をクリップボードにコピー。
    • それを、PowerShell コマンドプロンプトに貼り付けます。
  • 実行ポリシーを変更しない、上のようなバッチファイルも不可であれば、

    • 手動で PowerShell コマンドプロンプトへ貼り付けをするか、
    • PowerShell の使用をあきらめるか

    しかありません。

変数のスコープ

スクリプト

ps_scope1.ps1

$global:g1 = "0"
$script:s1 = "0"
$v1 = "0"

write-host "before      : g1=$global:g1 s1=$script:s1 v1=$v1 v2=$v2"

function test1 {
  write-host "start test1 : g1=$global:g1 s1=$script:s1 v1=$v1 v2=$v2"
  $global:g1 = "1"
  $script:s1 = "1"
  $v1 = "1"
  $v2 = "1"
  write-host "end test1   : g1=$global:g1 s1=$script:s1 v1=$v1 v2=$v2"
}

test1

write-host "after       : g1=$global:g1 s1=$script:s1 v1=$v1 v2=$v2"

実行例

E:\temp>powershell
Windows PowerShell
Copyright (C) 2009 Microsoft Corporation. All rights reserved.

PS E:\temp> Set-ExecutionPolicy RemoteSigned -Scope CurrentUser

PS E:\temp> .\ps_scope1.ps1
before      : g1=0 s1=0 v1=0 v2=
start test1 : g1=0 s1=0 v1=0 v2=
end test1   : g1=1 s1=1 v1=1 v2=1
after       : g1=1 s1=1 v1=0 v2=

PS E:\temp> write-host "g1=$global:g1 s1=$script:s1 v1=$v1 v2=$v2"
g1=1 s1= v1= v2=

PS E:\temp>

解説

  • $v1

    • .ps1 の中で最初に設定している値が、関数 test1 の中でも参照できますが、
    • 関数 test1 の中で設定した値は、関数 test1 の外では有効ではありません。
  • $v2

    • .ps1 の中で未定義のため、関数 test1 の中でのみ有効。
  • $script:s1 $v1 $v2

    • .ps1 の中だけで有効なため、スクリプトを終了した後で write-host しても値は設定されていない。
  • $global:g1

    • スコープがグローバルなので、スクリプトを終了した後で write-host しても値は設定されたまま。
  • 通常は、

    • .ps1 の中でスコープが閉じると考えておき、
    • .ps1 の中から write-output 以外の方法でスクリプト呼び出し元へ返す情報がある場合に、
      $global: を使用するか検討するのがいいでしょう。
    • あとは、.ps1 の中に限らず、関数間で共有の変数の場合、$script: を使用すると考えておけばいいでしょう。

移行メモ(正誤): 元ページの「スクリプトを終了しや後で」は
「スクリプトを終了した後で」の誤記と判断し、修正した。

補足(読めるが書けない、という挙動): この実行例の要点は、
PowerShell のスコープは「読み取りは親を辿るが、代入は常にローカルに新規作成される」
という点にある。

test1 の中の $v1 = "1" は、
外側の $v1 を書き換えているのではなく、関数ローカルの $v1 を新たに作っている
だから関数を抜けると外側の $v10 のままになる。
C 系の言語に慣れていると引っかかりやすい。

明示的に外側を書き換えたい場合は、

$script:v1 = "1"     # スクリプト スコープを指定
Set-Variable -Name v1 -Value "1" -Scope 1   # 1 つ上のスコープ

のようにスコープ修飾子を付ける。
ただし、著者の言うとおり write-output で値を返す方が素直で、
オブジェクトベースのシェル
「オブジェクトを返すようにしておくと再利用し易い」という方針とも一致する。

引数

ps1 スクリプトへの引数。

  • ps1 ファイルの最初に param(..) を記述することで、引数を定義出来ます。
param (
  [string]$filename,
  [int]$count = 5
)
  • 引数名を定義すると
powershell .\test.ps1 -filename c:\temp\test.txt -count 2

の様に -引数名 として使用できます。

移行メモ(正誤): 元ページの powersehllpowershell
testt.txttest.txt の誤記と判断し、修正した。

  • [型] と引数名と、省略時の既定値も、指定できます。

  • また、Mandatory 属性を指定すると、必須の引数になり、省略した場合には、
    PowerShell によって、追加の引数を要求するプロンプトが表示されます。

param (
  [Parameter(Mandatory=$True)]
  [string]$filename,

  [int]$count = 5
)

補足(param はファイルの先頭でなければならない): param(...)
コメントを除いてスクリプトの最初の実行文である必要がある。
前に何か書くと構文エラーになるため、
#Requires 行やコメント ベース ヘルプは param より前に置く。

#Requires -Version 5.1
<#
.SYNOPSIS
  ファイルを処理する。
.EXAMPLE
  .\test.ps1 -filename c:\temp\test.txt -count 2
#>
[CmdletBinding()]
param (
  [Parameter(Mandatory = $true)]
  [string]$filename,
  [int]$count = 5
)

コメント ベース ヘルプを書いておくと、
Get-Help .\test.ps1 で参照できるようになる
(→ PowerShell Cmdletの作り方)。

参考

本 Wiki 内


Tags: シェル, インフラストラクチャ, Windows

NetDevInfraWiki

マイクロソフト系技術情報 Wiki
Open 棟梁 Wiki

(未着手)

開発基盤部会 Wiki

移行管理: DONETODO

Clone this wiki locally