-
Notifications
You must be signed in to change notification settings - Fork 0
MS_PowerShellPS1File
-
TOP > シェル > PowerShell
- PowerShell オブジェクトベースのシェル
- PowerShellのPS1ファイルの作成と実行
- PowerShell ISE
PS1 ファイルの作成と実行について。
-
PowerShell のスクリプトファイルは、拡張子
.ps1のテキストファイル。 -
*.ps1スクリプトファイルは、コマンドプロンプトの中で-
powershell .\script.ps1、 - または、PowerShell コマンドプロンプトの中で
.\script.ps1
の様にして実行できる。
-
-
が既定では、PowerShell スクリプトそのものについて、
実行が抑止されているので*.ps1を実行するには、
以下の設定変更または回避方法を検討する。
補足(実行ポリシーはセキュリティ境界ではない): 押さえておくべき点として、
Microsoft 自身が実行ポリシーをセキュリティ機能ではないと位置づけている。
本ページが挙げている回避方法(標準入力から流す、貼り付ける)が
成立することからも分かるとおり、
意図せずスクリプトを実行してしまう事故を防ぐための安全装置であって、
悪意ある実行を止めるものではない。実際のセキュリティ境界は、
- コード署名(
AllSigned+ 証明書)- AppLocker / Windows Defender Application Control
- PowerShell の制約言語モード(Constrained Language Mode)
の側にある。
したがって、本ページの運用時の実行ポリシーの検討は、
「事故防止をどのレベルで行うか」の判断として読むとよい。
- 実行ポリシーを変更するには、
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 -を使用して、標準入力からコマンドを連続実行できる。 -
手打ちと同じなので、
Set-ExecutionPolicy Restrictedのままでも、実行可能。
実行ポリシーをどうしても変更したくない場合の次善策として、使用できるか検討する意味は有ります。
下の例の様に、bat ファイルとechoを組み合わせて、引数を与えることも出来ます。
ps_test.bat
@( echo $arg1 = "%~1"
echo $arg2 = "%~2"
type ps_test.ps1 ) | powershell -command -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-
.ps1のtry/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 の使用をあきらめるか
しかありません。
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を新たに作っている。
だから関数を抜けると外側の$v1は0のままになる。
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
の様に
-引数名として使用できます。
移行メモ(正誤): 元ページの
powersehllはpowershell、
testt.txtはtest.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の作り方)。
- 詳細は、
-
下のページを参照。
- Windows PowerShell: スクリプト作成の短期集中講座
http://technet.microsoft.com/ja-jp/magazine/hh551144.aspx - Windows PowerShell: パラメーターを定義する
http://technet.microsoft.com/ja-jp/magazine/jj554301.aspx
- Windows PowerShell: スクリプト作成の短期集中講座
-
または、PowerShell コマンドプロンプト内で、
get-help about_Functions_Advanced_Parametersを実行。
-
- Windows PowerShell: スクリプト作成の短期集中講座
http://technet.microsoft.com/ja-jp/magazine/hh551144.aspx
Tags: シェル, インフラストラクチャ, Windows
このWikiは「Open棟梁Project」,「OSSコンソーシアム 開発基盤部会」によって運営されています。