Windows 10 Anniversary UpdateからサポートしたWindows Subsystem for Linux(WSL)。その結果としてWindows 10上でもBashを始めとするLinuxコマンドが利用可能になった。本連載ではWSLに関する情報や、Bashから実行するシェルスクリプトを紹介する。
PowerShellコマンドレットをシェルスクリプトから利用する
最新のWSLではWindowsの環境変数PATHをBash on Ubuntu on Windows (BUW)で引き継ぎ、bash上でコマンドプロンプトやWin32アプリケーションの実行が可能になった。つまり、BUW上でMS-DOSのバッチファイルやPowerShellのシェルスクリプトが実行できるという意味である。
だが、PowerShell上の環境がそのまま使える訳ではない。例えばPowerShell環境は強力なコマンドレットやパラメーターの補完機能を備えているが、それらはBUW上で使用不可能。また、現在はパイプ処理がサポートされていないため、出力結果を加工するFormat-ListやCSVファイルとして出力するExport-CSVといったコマンドレットは使えない。
Bashのシェルスクリプト上でPowerShellのコマンドレットが使えると、Windows 10環境の情報取得や設定変更など、管理面が大幅に強化されるため、今後の機能強化を期待したいところだ。
さて、既存のシェルスクリプト上からPowerShellを単独で呼び出すことは可能である。そこでPowerShellのスクリプトを作成し、そのスクリプトをBashのシェルスクリプトから呼び出すことで、イベントログの出力手順を自動化することにした。なお、PowerShellはセキュリティを強化するため、既定ではスクリプトを実行できない。PowerShell上で「Set-ExecutionPolicy RemoteSigned」を実行して、スクリプトの実行ポリシーを変更するか、「設定」の<更新とセキュリティ/開発者向け>に並ぶ、<署名せずに実行するローカルPowerShellスクリプトを許可するように、実行ポリシーを変更します。リモートスクリプトには署名が必要です>にチェックを入れてほしい。
では、今回のPowerShellスクリプトおよびBashシェルスクリプトを紹介する。PowerShellスクリプトはWindows 10上のテキストエディターでもBUW上のvimなどでもかまないので、以下の内容をコピー&ペーストし、「Begin1.ps1」として保存してほしい。
Get-EventLog System | Select-Object $Args[0]
Bashのシェルスクリプトだが、いつもと同じく実行権限を与えてからお試し頂きたい。後はPowerShellスクリプトと同じ場所にあるBashシェルスクリプトを実行する。
#!/bin/bash
CMDNAME=`basename $0`
function usage() {
echo "Usage: $CMDNAME [-ls]" 1>&2
exit 0
}
while getopts :ls Option
do
case $Option in
l )
Flag_L="TRUE" ;;
s )
Flag_S="TRUE" ;;
\?* )
usage ;;
esac
done
shift $((OPTIND - 1))
if [ "$Flag_L" = "TRUE" ]; then
Count_Critical=0
Count_Alert=0
Count_Details=0
Count_Error=0
Count_Info=0
orig_ifs=$IFS
IFS=$'\n'
for Line in `powershell.exe ./Begin.ps1 EntryType`; do
x=`echo ${Line} | grep -v -e '^\s*$' -e '^EntryType' -e '^------'`
case $x in
*Critical* )
Count_Critical=$((Count_Critical+1)) ;;
*Warning* )
Count_Alert=$((Count_Alert+1)) ;;
*Verbose* )
Count_Details=$((Count_Details+1)) ;;
*Error* )
Count_Error=$((Count_Error+1)) ;;
*Information* )
Count_Info=$((Count_Info+1)) ;;
esac
done
IFS=$orig_ifs
echo 重大レベルは $Count_Critical 件
echo 警告レベルは $Count_Alert 件
echo 詳細レベルは $Count_Details 件
echo エラーレベル $Count_Error 件
echo 情報レベルは $Count_Info 件
fi
if [ "$Flag_S" = "TRUE" ]; then
TMPFILE=/mnt/c/Users/kaz/Desktop/$$tmp.txt
Count=0
for Line in `powershell.exe ./Begin.ps1 Source`; do
x=`echo ${Line} | grep -v -e '^\s*$' -e '^Source' -e '^------'`
if [ -n "$x" ]; then
Array=(`echo $x` "${Array[@]}")
Count=$((Count+1))
fi
done
orig_ifs=$IFS
IFS=$'\n'
Array2=($(echo "${Array[*]}" | sort))
IFS=$orig_ifs
for v in "${Array2[@]}"; do
echo $v >> $TMPFILE
done
uniq -c $TMPFILE
rm $TMPFILE
fi
コードをご覧になるとお分かりのとおり、今回の変更点は必要最小限にとどめているが、31行~32行目および48行目で、変数IFSの内容を変更していることに気付かれることだろう。Bashは既定で空白やタブ、改行を区切り文字としているが、ここでは既存の設定を待避させ、区切り文字を改行に変更。そして、元に戻している。この処理はPowerShellスクリプトの内容をBUW上で正しく処理するために必要だ。
続いて33行目のfor文では、そのPowerShellスクリプトに引数を付けて呼び出している。今回はSelect-Objectコマンドレットを併用し、引数として列挙するオブジェクトを指定する方法をも用いた。次の34行目で行う変数xへの代入も、あらかじめgrepで空行や不要な文字列を除外している。なお、35~45行目のcase文もロジックは一緒だが、出力された文字列に合わせるためパターンの内容を変更した。57~78行目で始まるオプション-sの動作も若干の変更を加えているが、ロジックは前回、変更箇所もオプション-lと同じため割愛する。
このようにBUW環境にとどまらず、Windows 10のコマンドなどを組み合わせることで、これまでは冗長になりがちなコードも比較的簡単に記述可能になった。これこそWSLで実現できる新たな開発環境 と言えるだろう。
阿久津良和(Cactus)