Windows Powershell
基礎 勉強会
講師:山本 哲也
対象読者
• バッチを書くのが辛いからPowershell出来るように
なりたい人
• VBS書いてるけど時代に乗り遅れてる感あるから、
Powershellに乗り換えたい人
• Linux系(Bash,Perl)で仕事してきたけど、Windowsの
スクリプトを任されてしまって「わからん」状態の
人
• 「スクリプトを書くこと」の雰囲気が知りたい人
Tetsuya Yamamoto(山本 哲也
)
• 座右の銘:実践躬行(やってみる)
• 目標:WEBサイトをめちゃくちゃ作れる人になる
• 趣味:散歩、読書、銭湯(サウナ付き)にいくこと
• 入社5年目(2013年7月〜在籍)
目次
・自己紹介
・Powershellとは (他のスクリプト言語との比較)
・Powershellを実行するための準備
・実行ポリシー
・基本的なコマンドレットの使い方、書式
・変数
・配列
・入出力
・パイプライン
・構文
・課題
・エラー処理
・関数
・スクリプトで引数を受け取る
1. Powershellとは (他のスクリプト言語との比較)
インフラエンジニアから見たPowershell
1. WSH(VBS)の代替として登場したOS管理用スクリ
プト言語
2. 高機能 (WSFC、Active Directory、Hyper-Vのモジ
ュールもある)
3. WinRMを使ったリモートサーバ管理も可能
(※psexec.exeの方が便利なので、どっかで説明する)
他の言語との比較
1. バッチ (.cmd / .bat)
1. MS-DOS時代からある、利用者の多いスクリプト
2. コマンドがたくさんあって結構なんでもできる
3. 実行ファイルや他のスクリプトを呼び出すのが得意
4. プログラミング言語で行うような構造的な文法記述には
不向き( for 文が独特だったり、エスケープが難しい)
5. 今後もOSバージョンに合わせて拡張され続ける★
2. VBS (.vbs)
1. Visual Basic のスクリプト版
2. 一定数の人から根強い人気
3. バッチで出来ないことをするために使うことが多
い
4. 今後拡張される予定はない★
3. Jscript (.js)
1. JavascriptのMS版として、VBSと同時期に誕生
2. 現場では2〜3年に1回ぐらい見かける気がする (
かなり私見かも)
3. 今後拡張される予定はない★
4. Powershell (.ps1)
1. 2006年に誕生した割と新しいスクリプト
2. 各社がPowershell用にコマンドレットを出している(例:AWS Tools For
Powershell、VMware PowerCLI)
3. 利用者数が急増中 (Windowsの管理用スクリプト言語としては2010年から
ユーザー数1位)
4. 今後もOSバージョンに合わせて拡張され続ける★
5. GithubよりLinux,MacOS向けにも展開中 (オープンソース化しました)
6. 標準で付属しているIDE (ISEエディタ) が便利
参考:ISEエディタ
Powershellのアイコンを右
クリックすると出てくる
補完機能
実行ボタン
検索機能
スクリプト記述エ
リア
リモートホストのPowershellに
接続 (WinRM設定時)
VBS vs Powershell
PowershellよりVBSを使うべき時
1. 今動いてるVBSが問題ない時(わざわざリファクタリングする必要ない)
2. Powershellが入っていない環境(WindowsXP,Windows Server 2003)のシステム管理
3. Powershellが入っていない環境に、Powershellをインストールするためのスクリプトを
作る時
4. メモリやCPUがかなり枯渇している中で、どうしても動かしたい処理がある時 (WSHの
方が動作エンジンが軽い。)
(参考記事:https://mcpmag.com/articles/2015/03/19/vbscript-instead-of-powershell.aspx)
凡例: ◎ : インストール済み
△ : インストール可能
- : 未対応
バージョン 1.0 2.0 3.0 4.0 5.0
Windows Server 2003
△
SP1
△
SP2
- - -
Windows Server 2003 R2
△
SP1
△
SP2
- - -
Windows Server 2008 -
△
SP1
△
SP2
- -
Windows Server 2008 R2 - ◎
△
SP1
△
SP1
△
SP1
Windows Server 2012 - - ◎ △ △
Windows Server 2012 R2 - - - ◎ △
バージョン 1.0 2.0 3.0 4.0 5.0
Windows XP x64 △ - - - -
Windows XP
△
SP2
△
SP3
- - -
Windows Vista △
△
SP1
- - -
Windows 7 - ◎
△
SP1
△
SP1
△
SP1
Windows 8 - - ◎ - -
Windows 8.1 - - - ◎ △
Windows 10 - - - - ◎
Powershell を実行するための準備
必要なもの
1. PC
• Windowsの場合は、Windows 7 以上のスペックであれば可
• macやubuntuの場合、Powershell入ってればok
※入ってない場合は下記からダウンロードしインストール(How to Install を見よ)
https://github.com/PowerShell/PowerShell
準備
エクスプローラ開く ⇨ 「表示」⇨「拡張子を表示する」に設定
(Windows PC以外は不要)
・拡張子が表示されていればOK
・試しに1つ、デスクトップに拡張子が.ps1のPowershellファイルを作る
ダブルクリックすると、メモ帳で開く
• GUIでは、右クリックし「Powershellで実行」を
クリックし実行できる
• コンソールでは、Powershell.exe の引数にPowershell
スクリプトのパスを指定して実行することができる
実行ポリシー
1. Powershell スクリプトを右クリックし、「
Powershell で実行」をクリックした際の動作
2. Powershell.exe の引数にPowershell スクリプトを
指定して実行した際の動作
• 実行ポリシーの種類
項目
(主なもの)
説明
Restricted
実行できるスクリプトはありません。
PowerShell は対話モードでのみ使用可能です。
AllSigned
信頼できる発行元が署名したスクリプトのみを
実行できます。
RemoteSigned
ダウンロードしたスクリプトは信頼できる発行
元が署名した場合にのみ実行できます。デフォ
ルト。
Unrestricted
制限なし。すべての Windows PowerShell スク
リプトを実行できます。
実行ポリシーは・・・
• Get-Executionpolicy コマンドレットにて確認可能
• Set-Executionpolicy コマンドレットにて変更可能
例:Unrestricted に設定
Set-Executionpolicy Unrestricted
⇨ ローカルコンピュータの設定を恒久変更するため注意
一時的な実行ポリシー変更
※ローカルコンピュータの設定を恒久変更せずに、
指定したPowershellスクリプトだけを、指定したポリシーで実行する
1. バッチ(.bat /.cmd) 実行により起動する場合
• 下記のように記載したバッチを作成 (Call-Hello.ps1)
Powershell -Executionpolicy Unrestricted “C:¥Hello.ps1”
2. ショートカットファイル実行により起動する場合
• ターゲットに下記のように記載したショートカットを作成
Powershell -Executionpolicy Unrestricted “C:¥Hello.ps1”
3. Powershellスクリプトを対話モードから実行する場合
• Set-ExecutionPolicyの「-Scope」オプションに「
process」を指定する
Set-Executionpolicy <値> -Scope process
基本的なコマンドレットの使い方、書式
コマンドレット
(動詞)-(名詞) の形式を取る。
動詞は主に「Get」か「Set」
• Get-Command
• (コマンド)を(参照)
• Set-Executionpolicy
• (実行ポリシー)を(設定)
• オプションの調べ方
• 先頭にman を付ける
例:man get-service
• 末尾に-? を付ける
例:get-date -?
• 牟田口さんのリファレンス本を見る、ググる
Get-Serviceコマンドレットを用いて、BITS のサービス
状態を取得する例
今月の1日の日付を取
得
2017/1/1を取得
コマンドレットの持つ、
プロパティとメソッド
プロパティ
特徴や性質に関する情報
• iPhoneで例えると下記のような情報
• バージョン (6、6S、SE、7)
• 色 (赤、黒、白)
• 容量 (32、64、128 GB)
• キャリア (au、docomo、Softbank)
メソッド
提供している操作
• iPhoneで例えると下記のような操作
• 導入済みアプリの起動
• 連絡先への通話
• 写真を撮る
• 音声での機能検索
• 各コマンドレットが持つプロパティ、
メソッドの調べ方
• パイプでGet-Memberに渡す
例:get-service | Get-Member
• プロパティの使い方
• コマンドレットを括弧() でくくって
、「.プロパティ名」
例:(Get-Childitem).fullname
• Get-Childitem (=dir) コマンドレットから、
fullnameプロパティを取得する例
日付プロパティを取得
• メソッドの使い方
• コマンドレットを括弧() でくくって
、「.メソッド名(引数)」
例:(Get-Service -name “BITS”).start()
• Get-Serviceコマンドレットの start()
メソッドを使い、BITSのサービスを開
始する例
今日の日付を
yyyyMMddで取得
今日の日付に10日加
算してyyyyMMddで取
得
今月の1日から1日引き算して
、先月の最終日をyyyyMMdd
で取得
エイリアス
各コマンドレットに用意された省略系。
Unixのコマンドを意識して作られている。下記は抜粋。
ls ・・・・・Get-Childitem
cat ・・・・・Get-Content (gc)
sleep ・・・・Start-Sleep
mkdir ・・・・New-Item -type directory
cd ・・・・・Set-Location
pushd・・・・Push-Location
popd ・・・・Pop-Location
cp ・・・・・Copy-Item
mv ・・・・・Move-Item
rm ・・・・・Remove-Item
clear (cls) ・・Clear-Host
ps ・・・・・Get-Process
kill ・・・・・Stop-Process
pwd ・・・・Get-Location
tee ・・・・Tee-Object
wget (curl) ・・Invoke-WebRequest
エイリアスは下記のコマンドで見れるよ
Get-Alias
Sleepしてくれて可愛い
コマンドレットの出力行数を指定
• (コマンドレット)[n]
• n は 0 から始まる数字で、0を指定すると1行目の出
力が取れる
• Get-Childitem (ls) の出力結果より、1行目を取得
する例
(Get-Childitem)[0]
• (コマンドレット)[n..o]
• n行目〜o行目の出力が取れる
• Get-Childitem (ls) の出力結果より、1行目
〜4行目を取得する例
(Get-Childitem)[0..3]
• (コマンドレット)[-1]
• 最終行の出力が取れる
• Get-Childitem (ls) の出力結果より、最終
行を取得する例
(Get-Childitem)[-1]
おまけ①:Get-Childitem のfullnameプロパティにつ
いて、1行目、最終行を出力する例
おまけ②:プロパティやメソッドにも、プロパティや
メソッドは付いており(Get-Memberで確認できる)、使う
ときにはピリオドでつなげる。
おまけ③: Lengthプロパティは出力行数を返すプロパティ。
しかし、出力が1行のときは1行中の文字数を返す。一方Count
プロパティは基本的に出力行数を返す。
7行
7行
7行
5文字
1行
変数
${VAL} の形式を取る。
$VAL とも記述可能。
スコープ(参照範囲)
• global・・・スクリプト外からも参照可能
• script・・・スクリプト内
• local・・・同一ブロックとその子ブロック内
• private・・同一ブロック内のみ
• 使い方・・・・$スコープ:変数名
• 例
$script:val
親ブロック内
子ブロッ
ク内
親ブロック内でprivateとして定義した
$pは子ブロックでは参照不可
親ブロックの外では、親ブロック内で
scripとして定義した
$sのみ参照可
スコープについて補足(というかバグ)
• 変数(A)を子ブロック(関数)で操作するとき
• 「+= 」だとローカル変数として変数(A)の値を
継承せずに、右辺が加算される。
• 「++」だと、ローカル変数として変数(A)の値
を継承し、右辺が加算される。
インクリメントされる
スコープを指定して参照すると、親スコープで定義した$aの値は変更
されていないとわかる
++
300にはならずに、値を200として、
新たなローカル変数が作成される
+=200
そもそも、スコープを意識しなきゃいけないほど
階層的なスクリプトを書かないこと。
親ブロックで定義した変数を子ブロックで参照し
たり、書き換えするときは、スコープを書くよう
にする (例:$script:a += 1)。
また、親ブロックで定義したものと同じ名前の変
数を子ブロックで使わないようにする。
⇨抑えるべき点
型
⇨代入すると自動で型変換される
• $a = 1 # ⇦System.Int32 (数値)
• $b = "1" # ⇦System.String (文字列)
• $a + $b # ⇦2 ※先の$aの型に $bが変換される
• $b + $a # ⇦11 ※先の$bの型に $aが変換される
変数でなくても、先の型が優先される
型指定して代入することも可能
※型指定すると、異なる型による上書きが禁止にな
る
• [int32]$a = 1 # ⇦System.Int32 (数値)になる
• [int32]$b = "1" # ⇦System.Int32 (数値)になる
• [string]$b = "1" # ⇦System.String (文字列)になる
• [string]$b = 1 # ⇦System.String (文字列)になる
• 型の調べ方
• 「変数名.gettype()」
例:$a.gettype()
型の変換
int32型(数値)に変換
• $a = $a -as [int32]
string型(文字列)に変換
• $a = $a -as [string]
変数にもプロパティやメソッドは存在。
⇨パイプラインで Get-Member コマンドレ
ットに渡して調べる
文字列型
数値型
コマンドの出力結果も変数に代入可能
• 例
• $a = ls
• $a = (ls)[0]
a.txt の末尾に、
yyyyMMdd形式の日付を付与する例
※ログローテーションなどに使用
フルパス
拡張子
フォルダパス
拡張子無しのファイル名
日付(yyyyMMdd)
名称変更する処理
net config workstation の実行結果から、所属し
ているドメイン名を変数格納する
※下の場合は「WORKGROUP」
バッチでドメイン名を変数格納してみる
※補足:インタラクティブに動かす場合は ”%1” だ
が、バッチファイルとして動かす場合は “%%1” と
書く。
for /f "tokens=3" %1 in ('net config
workstation ^|findstr /R
/c:"^Workstation.*domain.*$"') do set
domainname=%1
黒魔術かよ・・・・(DOS窓黒いけど)
配列
配列
• $list = @() # ⇦ 空配列作成
• $list = 1,2,3,4 # ⇦ 要素入り配列作成
• $list += 5,6,7,8 # ⇦要素追加①
• $list += 9,”string” # ⇦要素追加②
文字列演算子・・・文字列として比較し、一致したものを出力
。
• -match # 正規表現比較
• -notmatch # 正規表現比較(不一致)
• -like # ワイルドカード比較
• -notlike # ワイルドカード比較(不一致)
• -replace # 置換
比較演算子・・・数値として比較し、一致したものを出力。
• -eq # 左辺が右辺と等しい
• -ne # 左辺が右辺と等しくない
• -ge # 左辺が右辺と等しい、または右辺より大きい
• -gt # 左辺が右辺より大きい
• -le # 左辺が右辺と等しい、または右辺より小さい
• -lt # 左辺が右辺より小さい
おまけ:配列ではオブジェクトへのリファレンスを保持している
連想配列
• $hash = @{} # ⇦ 空配列作成
• $hash = @{key1=value1} # ⇦ 要素入り配列作成
• $hash += @{key1=value1; key2=value2} # ⇦要素追加①
• $hash[key3] = value3 # ⇦要素追加②
• $hash[key3] = new-value3 # ⇦値変更
• $hash.key1 # ⇦値取り出し
おまけ:連想配列の連結
変数、配列の削除
• $a を削除する場合
• Remove-Variable a
使用している変数・配列の確認
• Get-Variable
入出力
• 標準出力
• Write-Output “Hello”
• echo “Hello”
• “Hello”
• 標準入力
• Read-Host
• ファイル出力
• “Hello” |out-file Hello.txt
• “漢字” |out-file 漢字.txt -encoding unicode
※漢字は文字化けするのでunicodeに変換する
• ファイル入力
• gc Hello.txt # gc はGet-Contentのエイリアス
• gc 漢字.txt
標準出力(>)をNORMAL.logに、
標準エラー出力(2>)をERROR.logに出力
リダイレクトも使えます!
標準出力の切り替えによく使うリダイレクト記号「>」は、
「1>」の省略形。
1> ・・・・標準出力
2> ・・・・標準エラー出力
※1番目のファイル記述子、という意味です。
同じ意味
標準出力(>)をC:¥All.logに入れて、
そのあとに標準エラー出力(2>)を、
標準出力に混ぜる(&1)・・・・と、いつかの私は覚えました
。
>logfile 2>&1
ちなみに、順番を入れ替える(2>&1 >logfile)と、うまく動きま
せん。
コマンドの出力は標準出力が先に出るからです。
なので正しくは・・・・「先に出てきた標準出力(>)をlogfile
に入れて、
次に出る標準エラー出力(2>)を、標準出力に混ぜる(&1)。」
です。
と思ったら動いてる・・・・
Powershellすごい・・・
でもシェルスクリプトだと動かないから、
極力 ”>logfile 2>&1” と書きましょう。
参考:シェルスクリプトだと動きが変わる例
• 特殊文字(よく使うもの)
• エスケープ文字「`」
• 改行「`n」
• キャリッジリターン「`r」
• タブ「`t」
Windowsの改行(CRLF)を特殊文字で表現
CR=`r
LF=`n
Windowsの改行(CRLF)をタブに置換
タブ=`t
number.txtの1111を7777に置換
Windowsの改行(CRLF)を####に置換した
はずが、
変わらない・・・・
解説:cat (Get-Content) は改行(CRLF)を区切りにして、
1行ずつ読み込み表示している。
そのため、読み込んだテキストの改行(CRLF)は
既に取り除かれているため置換できない。
cat (Get-Content)の出力結果を、Out-Stringコマンドレッ
トに渡す。
Out-Stringコマンドレットは受け取った出力を、
「ひとまとまりの文字列」
として出力する。
出力結果は一見同
じ
cat (Get-Content) の出力から、行末のCRLFは、取
り除かれている
CR
LF
CR
LF
Out-String は受け取った出力を
「ひとまとまりの文字列」にする
• CSV出力
• dir |convertto-csv
• dir |export-csv dir.csv -encoding unicode
※コマンドの出力をCSV形式に変換
• CSV入力
• Import-Csv dir.csv
• (Import-Csv dir.csv).fullname # ヘッダ指定
各プロパティ毎に列出力する
Export-CSV でファイル出力する前に
どういう形式で出力されるか
コンソール上で確認するときに使う
でも、わかりにくいよね・・・・
スクロールできる
Out-Gridview コマンドレ
ットで
ビュー表示できる。
パイプライン
• Where-Object (エイリアス:?)
• パイプラインから渡されるオブジェクト
を1行ずつ特殊変数「 $_ 」に格納し、
スクリプトブロック内で比較を行い、結
果を出力する。比較には比較演算子、文
字列演算子を用いることができる。
• dirコマンドの出力結果から、名前(ファイル
名、フォルダ名)に「a」を含む行を抽出す
る例
dir | ? {$_.name -match “^.*a.*$” }
正規表現(.*`.txt)に
一致したnameプロパティ
を取り出す。
※Where-Objectを使わない例
dirコマンドレットの出力結果の中で、
nameプロパティが、
正規表現(.*`.txt)に
一致したレコード(オブジェクト)を取
り出す。
※Where-Objectを使う
例
? (Where-Object) を使うと、
コマンドレットの出力をフィルターで
きる。
フィルターして、そこからさらに必要
なプロパティを取り出すことが可能。
abcd.txt から”aaaa”を含む行を抜粋
• Foreach-Object (エイリアス:%)
• パイプラインから渡されるオブジェクト
を1行ずつ特殊変数「 $_ 」に格納し、
スクリプトブロック内で処理を行い、結
果を出力する。処理には標準のコマンド
レットを用いる。
パイプラインを経由して渡された各要
素を、
一つ一つ、
%{} 内のコマンド(echo “times:$_” )に
渡す。
$_ には各要素が入る。
dirコマンドレットの出力結果の
中から
各要素のfullnameプロパティを
出力
? (Where-Object) と組み合わせ
ること多し。?で抽出、パイプで
渡して%で処理が基本になる。
• Measure-Object (エイリアス:measure)
• 数字リストの最大値、最小値、平均値、
合計値、要素数を算出する
• 行数を合計するオプションもある(-Line)
1,2,3,4 の最大・最小値、合計、平
均を取得
参考:ファイルサイズ取得
• Select-String
• 入力元のテキストやファイルから、指定
したテキストを検索する。unixのgrepコ
マンド。検索には正規表現を用いる。ま
たプロパティとして、一致した行の行番
号(linenumber)などを返す。
abcd.txt から”aaaa”を含む行を出力
abcd.txt から”abcd”を含む行の
行番号を出力
※0ではなく1から始まる
• Select-Object (エイリアス:select)
• プロパティ値を指定して取り出す。必要
な出力だけ参照したいときに使用。
export-csvのCSV出力サイズを小さくし
たいときに便利だったり。
必要な列を抜粋できる
• Group-Object
• 入力オブジェクトを指定したプロパティ
値でグループ化する。
配列を同じ要素でグループ
化
Aが一番多い(4回)
• Sort-Object
• 入力されたオブジェクトを昇順で並び替
え。降順にするときは -desc をつける。
昇順で並び替え
降順で並び替え
構文
• For文
• 例:
for ($i=1;$i -le 10;$i++) {“$i 回目”}
1から10まで1ずつ加算
(10までインクリメント)
個人的に使ったことのある実例。
(次のスライドに続く)
先月の1日から最終日(上の例では31日)までの
ログ(xxxx_yyyyMMdd.log)をローカルにコピーしてくる
。
$i -as [string]で文字列型に型変換し、
padleftメソッドで、10未満の数の前に”0”をつけている
。
先月(2017/08)の1日から最終日(31日)
のログが取れる
※画面はechoしてるだけで実際にコピーは
してない
• while文
• 例:
while ($i -lt 10) {$i++;“$i 回目”}
do{$i++;“$i 回目”} while ($i -lt 10)
特殊変数「$True」を用いた無限ループ。
netstat の結果から127.0.0.1を含むコネクシ
ョンを 1秒間隔で出力
• if文
• 文字列演算子や比較演算子を用いて比較する
• 例:
if ($i -lt 10) {“$i”} else {“over 10”}
if (“$i” -match “^a$”) {“$i”} else {“x”}
• switch文
• 文字列演算子や比較演算子を用いて比較する
• if文でいう「else」は、「default」 を使う
• 正規表現を使う際は -regex オプションを使う
• 例:
switch (“$a”) {
“a” {“a”}
default {“NOT a”}
}
文字列比較
オプション無し 完全一致
-regex 正規表現
-wildcard ワイルドカード
-casesensitive 大文字小文字区
別
数値比較
※一致したらbreakで抜
けることも可能(数値に
限らず)
ブール値比較
課題
• 前提:Listener サービスの起動後、
Listener.logに、「Listener completed
notification to CRS on start」が出力されていな
い場合、Listenerが内部で起動ハングしていま
す。
• その場合、出力されていないことを検知し
て、処置としてListenerを再起動する必要が
あります。
• 課題:Listenerサービスの起動処理後に、「
Listener completed notification to CRS on start」
と出力されていれば、”OK”と出力し、出力され
ていなければ”NG”と出力する処理(問題の検知部
分)を作成してください。
• 条件:pid=xxxxで起動しました。」から3行(
リスニングしています・・・・)までは毎回
必ず出力されているものとします。
いちばん最後の起動。正常終了
。これをチェックしたい
Listener.log
最後から1回前の起動。正常終了
課題解答
https://qiita.com/lucky_happy_jicchoku_engineer/items/b3fcd85
dfd719cbf5c2d
エラー処理
•エラー時に処理を止める?続ける?
• $ErrorActionPreference
• エラー発生時の動きを定義している特殊変数
項目
(主なもの)
説明
continue
赤文字でエラー内容を表示し、
処理を継続する ★デフォルト
silentlycontinue
赤文字でエラー内容を表示せずに、
処理を継続する
stop
赤文字でエラー内容を表示し、
処理を中断する
• 変更するには下記のようにする
$ErrorActionPreference = “stop”
⇨ スクリプト先頭に記述すると、
スクリプトで使用しているコマンド全てに適用される。
(つまり、記述した箇所以降から適用される)
⇨各コマンドごとに制御することも可能。
後述しますが、$ErrorActionPreferenceをstopにした際の動作は、try-catch構
文とtrap構文で異なるため、変更をお勧めしません。$ErrorActionPreferenceはそっ
としておく。
スクリプトを書くときは、各コマンドの後処理を考えることになるので、各コマ
ンドごとに動作定義するのが良いと考えます。
各コマンドごとに制御する
オプションに -erroraction (エイリアス: -ea)を使う
• dir notexistfolder -erroraction “stop”
• dir notexistfolder -ea “stop”
• -erroraction はすべてのコマンドレットに存在する共通パラ
メータ。
•エラー時に処理を止めた後に、何かする
1. エラーが発生した場合に検知し、何かコマンドを
実行する
(try~catch~finally)
try {
エラー発生の可能性があるコマンド1 -ea “stop”
エラー発生の可能性があるコマンド2 -ea “stop”
}
catch [エラーの型] {
エラー発生時に実行するコマンド
return または exit (処理終了の場合)
}
finally {
# エラー発生有無に関わらず最後に実行するコマンド
}
$command after try-catch-finally
※[エラーの型]は省略可能。
省略した場合、すべてのエラーがcatchされる(Exceptionクラス)
※ReturnまたはExitをしない場合、
tryで失敗してcatchに入り、finallyを実行した後は、
finallyブロックの次の行にいく。
※スクリプトの先頭で$ErrorActionPreferenceの値をstopにしていて
も、です。
(後述のTrap構文では、stopのときスクリプトが終了します。)
(tryブロック中にある、catchされたコマンド以後の行のみ、スキップ
する)
• catch内でエラー発生時の処理を行い、関数やスクリプトを終了す
るには下記を記述。
Return・・・・引数を返して関数を終了する ※関数は後述
Exit・・・・・引数を返してスクリプトを終了する
→コーディング次第では、try-catchのリトライ処理も可能です。
ググると出てきます。(残念ながらretry文は無い)
• コマンドで発生したエラーの型を調べる方法
$error.exception.gettype().fullname
• 例:Copy-Item でコピー元ファイルがない時のエラー型
System.Management.Automation.ItemNotFoundException
• 例:Copy-Item でコピー先フォルダがない時のエラー型
System.IO.IOException
* クラスライブラリ(2017/11/26現在)
https://msdn.microsoft.com/en-
us/library/ms714469(v=vs.85).aspx
* Windows PowerShell コマンドレットのタスク別ガイド
https://technet.microsoft.com/ja-
jp/scriptcenter/dd772285.aspx
• エラー型ごとに複数のcatchを作る例(catchは複数可能)
⇨ 複数catchを作るとき、
どこか1つの[エラー型]に”exception”を指定すると、全てのエラーが
”exception”のcatchに入ってしまう。
⇨ エラー型を指定する場合、指定しないエラー型をcatchできなく
なる。(他にやり方あるかも)
Powershellスクリプトでは、(.Netの)エラー型での処理分岐はあまり
現実的ではない。(コマンドレットの例外エラー型を網羅するのは至
難に思う。)
[エラー型]に”exception”を記載 (または記載自体を省略しても同じ)し
、全てのエラーをcatchするのが良いと考える。
フォルダの存在確認などは、Test-Pathコマンドなど、確認用のコマ
ンドが用意されている。事前に実行して、switch文などでブール値判
定しておくとよい、かも。
tryに一連の処理を記述し、エラーがあればcatchしてログ出力する例
• $Error って何?
• コマンドで発生したエラーの出力を保存している特殊変数(読み
取り専用)
• $Error をログファイルに出力
$Error >> c:¥err.log
注意点:$errorは追記されていくため、$error を出力する処理が複数回ある場合
、前回のエラーがもう一度出力されてしまう。
→各コマンドでの出力をリダイレクトすると同じになる
例:
dir hogefolder -ea stop 1>>c:¥err.log 2>&1
2. スクリプトの途中でエラーが発生した場合に検知し、
何かコマンドを実行する (trap)
trap {
1. エラー発生時に実行するコマンドレット(複数可)
コマンドレット1・・・・
コマンドレット2・・・・
2. continue (処理継続) または break (処理終了)
}
■補足
trapは、スクリプト文中のどこに記載しても同じように動作する。
(先頭でも最後尾でも同じ動き)
Trapは、$ErrorActionPreference = “stop”
が指定されている場合、
または 実行したコマンドレットに -ea = “stop”
が指定されている場合のエラー発生時に作動する。
• 後続処理の継続または終了
continue・・・エラーの発生した次の行から処理を継続する
break・・・・エラーの発生した行でスクリプトを終了する
trap文で break または continue を記載しない場合、
次ページのようになる。
挙動がわかりづらいので、記載するのがオススメ。
• $ErrorActionPreference = “stop” を設定した状態で、コマ
ンドレットの実行エラーが発生したとき
⇨ trap文が実行され、そのままスクリプト終了
• $ErrorActionPreference = “continue”(デフォルトのまま)を
設定した状態で、コマンドレットのオプションに”-ea
stop”を指定し、実行エラーが発生した時
⇨ trap文が実行され、エラーの発生した次の行から
処理継続
• trap ステートメント内で、日付時刻と $Error の内容をログファイルに
出力し、スクリプトを終了する例
trap {
get-date >> c:¥err.log
$Error >> c:¥err.log
break
}
•最後の補足
• trap文とtry~catch文では、try~catch文が優先される。(try~catch文でcatchしたエラ
ーはtrapには掛からない)
• try~catch文のfinallyブロックは省略できる
• エラー処理についてはインターネットにあまり情報がないため、本資料が役に立つ
ことを祈る。
• 基本的にtry-catchで補足して処理し、意図しない例外のために一応trapを書いてお
く。$ErrorActionPreferenceは触らないで、continueのままにしておく。エラーは
各コマンド毎に取得するようにする。コマンドにはエラー時停止命令を書いておく
。
# コマンド -ea stop >>$log 2>&1
上記↑にてtry-catchやtrapに引っかかり、処理ごとにログが出せる
関数
• 関数定義
• 引数なし
function 関数名 {
コマンド
}
• 引数あり
function 関数名 (引数) {
コマンド
}
# 例1:関数
function hello-yamazoon ($first,$last) {
“Hello ${last} ${first} !! Welcome to Yamazoon !!”
}
# 関数実行
hello-yamazoon “Yamamoto” “Tetsuya”
⇨ Hello Tetsuya Yamamoto !! Welcome to Yamazoon !!
# 例2:begin process end 関数
function count-value {
begin {
$count = 0
}
process {
$count++
echo “$count 回目の値 : ${_}”
}
end {
echo “数え終わりました。”
}
}
# 実行
1,1,2,3,5,8,13 |count-value
# 結果
1 回目の値 : 1
2 回目の値 : 1
3 回目の値 : 2
4 回目の値 : 3
5 回目の値 : 5
6 回目の値 : 8
7 回目の値 : 13
数え終わりました。
• 関数の結果返却
Return・・・・引数を返して関数を終了する
Exit・・・・・引数を返してスクリプトを終了する
例:第一引数をそのまま返却する、test-return 関数
関数を実行した
結果を変数格納
関数の実行結果には、returnの引数だけではなく、
標準出力が含まれる。
なので、コマンドの実行結果の出力などは消すようにする。
command >$null 2>&1 # $null はnullを表す特殊変数
スクリプトで引数を受け取る
• パターン1/2
• スクリプト側にデフォルトの定義なし
• 第一引数・・・・args[0]
• 第二引数・・・・args[1]
• 第三引数・・・・args[2]
• 第四引数・・・・args[3]
•quotion.ps1
• パターン2/2
• スクリプト側にデフォルトの定義あり
•quotion2.ps1
• 多い引数を連想配列にまとめて与える
• おまけ:終了系コマンドまとめ
Exit・・・・・引数を返してスクリプトを終了する
Return・・・・引数を返して関数を終了する
Break・・・・switch文の中:switch文を抜ける
while文の中 :while文を抜ける
trap文の中 :スクリプトを終了する
Continue・・・trap文の中 :スクリプトを継続する

Powershell基礎_20180521用