見出し画像

PowerShell の個人的メモ

たまにPowerShellでスクリプト書くので、個人的によく使うものをメモしておきたくブログに書きました。プログラム素人なので参考になるかは微妙です。

1. コマンド実行時の引数を必須にする

Param(
    [Parameter(Mandatory = $true)]
    [ValidateNotNullOrEmpty()]
    [string] $argHoge,
    [Parameter(Mandatory = $true)]
    [ValidateNotNullOrEmpty()]
    [string] $argFuga
)

1-1. サンプル

test01.ps1
===============
Param(
    [Parameter(Mandatory = $true)]
    [ValidateNotNullOrEmpty()]
    [string] $argHoge,
    [Parameter(Mandatory = $true)]
    [ValidateNotNullOrEmpty()]
    [string] $argFuga
)
echo "-----------------"
echo "argHoge = $argHoge"
echo "argFuga = $argFuga"

1-2. サンプルの実行結果①

引数なしでスクリプトを実行すると、対話式で値の入力が必要になります。

PS C:\> .\test01.ps1

コマンド パイプライン位置 1 のコマンドレット test01.ps1
次のパラメーターに値を指定してください:
argHoge: ほげ
argFuga: ふが
-----------------
argHoge = ほげ
argFuga = ふが

# 実行結果2
PS C:\> .\test01.ps1 あいう えお
-----------------
argHoge = あいう
argFuga = えお

1-3. サンプルの実行結果②

スクリプト実行時に引数を指定することもできます。

PS C:\> .\test01.ps1 あいう えお
-----------------
argHoge = あいう
argFuga = えお

2. 配列を使う

$targetList = @("HOGE","FUGA","PIYO")

@("xxx","xxx") という感じで配列を作ります。配列番号を指定して値を引き出すことができます。1番目の値を引き出すときは、0 番を指定します。

$targetList = @("HOGE","FUGA","PIYO")

echo $targetList
echo "------------"
echo $targetList[0]
echo $targetList[1]
echo $targetList[2]

2-1. 実行結果

PS C:\> .\test01.ps1
HOGE
FUGA
PIYO
------------
HOGE
FUGA
PIYO
PS C:\>

3. 変数を初期化する

$hoge = ""

4. 関数を定義する

functin <関数名>() {  }

function 関数名(){ } で関数を定義できます。{ と } の間に処理を書きます。
関数を呼び出すときは、関数名を書きます。

4-1. サンプル

function Hoge(){
    echo "function is HOGE."
 }

# 関数の呼び出し
Hoge

4-2. サンプルの実行結果

PS C:\> .\test01.ps1
function is HOGE.
PS C:\>

5. エラーが発生したときに実行する処理を書く

try{
   # 通常の処理
}catch{
   # 通常の処理でエラーが発生したときの処理
}finally{
   # 通常の処理でエラーが発生してもしなくても実行する処理
}

5-1. サンプル

echo "--- TEST 1 ERROR ---"

try{
    echo "test 1 calc start"
    1/0
    echo "test 1 calc end"
}catch{
    echo "ERROR!"
}finally{
    echo "END"
}

echo ""
echo "--- TEST 2 OK ---"

try{
    echo "test 2 calc start"
    0/1
    echo "test 2 calc end"
}catch{
    echo "ERROR!"
}finally{
    echo "END"
}

5-2. 実行結果

PS C:\> .\test01.ps1
--- TEST 1 ERROR ---
test 1 calc start
ERROR!
END

--- TEST 2 OK ---
test 2 calc start
0
test 2 calc end
END
PS C:\>

6. 文字列を出力する

Write-Host "xxxx"
Write-Output "xxxx"

※Write-Host,Write-Output の使い分けはよくわかってないです。
私は echo も含め適当に使っています。

6-1. サンプル

Write-Host "Write-Host で出力"
Write-Output "Write-Output で出力"

6-2. サンプルの実行結果

PS C:\> .\test01.ps1
Write-Host で出力
Write-Output で出力
PS C:\>

7. 配列の初期化

$hogeList = @()

7-1. サンプル

$hogeList = @("HOGE","FUGA","PIYO")
echo $hogeList
$hogeList = @()
echo "----"
echo $hogeList
echo "^^^"

7-2. 実行結果

PS C:\> .\test01.ps1
HOGE
FUGA
PIYO
----
^^^
PS C:\>

8. 2次元配列に値を動的に追加する

$hogeList += ,@( `
"hoge1";
"fuga1";
"piyo1";
)

@(アットマーク)の前に , (カンマ) を書くことを忘れずに!

8-1. サンプルの実行結果

$hogeList = @()

$hogeList += ,@( `
"hoge1";
"fuga1";
"piyo1";
)

$hogeList += ,@( `
"hoge2";
"fuga2";
"piyo2";
)
echo $hogeList[0][1]
echo $hogeList[1][2]

8-2. サンプルの実行結果

PS C:\> .\test01.ps1
fuga1
piyo2
PS C:\>

9. 2次元配列の値を操作する

for( $uniNum=0; $uniNum -lt $uniInfoList.Count; $uniNum++){
    # 1次元目のループ
    $inner_ary = $uniInfoList[ $uniNum ];
    for($x=0; $x -lt $inner_ary.Count; $x++){
        # 2次元目のループ
    }
}

9-1. サンプル

$uniInfoList = @( @("ほげ","ふが","ぴよ"),@("HOGE","FUGA","PIYO"),@("ホゲ","フガ","ピヨ") )

for( $uniNum=0; $uniNum -lt $uniInfoList.Count; $uniNum++){
    $inner_ary = $uniInfoList[ $uniNum ];
    $outHoge = ""
    $outFuga = ""
    $outPiyo = ""
    for($x=0; $x -lt $inner_ary.Count; $x++){
        switch($x){
            0 { $outHoge = $inner_ary[$x] }
            1 { $outFuga = $inner_ary[$x] }
            2 { $outPiyo = $inner_ary[$x] }
        }
    }
    echo "LoopNumber $uniNum : subNo 1 Valu = $outHoge ; subNo 2 Value = $outFuga ; subNo 3 Value = $outPiyo"
}

9-2. サンプルの実行結果

PS C:\> .\test01.ps1
LoopNumber 0 : subNo 1 Valu = ほげ ; subNo 2 Value = ふが ; subNo 3 Value = ぴよ
LoopNumber 1 : subNo 1 Valu = HOGE ; subNo 2 Value = FUGA ; subNo 3 Value = PIYO
LoopNumber 2 : subNo 1 Valu = ホゲ ; subNo 2 Value = フガ ; subNo 3 Value = ピヨ
PS C:\>

10. スリープ

# 3秒
sleep 3

11. csvファイル読み込みと出力

$csv = import-csv c1.csv
$csv | % {
    $tmpId = $_.id
    $tmpName = $_.Name
    echo "$tmpId : $tmpName"
}

11-1. サンプル①

$csv = import-csv c1.csv
$csvArr = @()
$csv | % {
    $tmpId = $_.id
    $tmpName = $_.Name
    echo "$tmpId : $tmpName"
}

# c1.csv ファイル
"id","Name"
"1001","Yamada"
"1002","Suzuki"
"1003","Mikimoto"
"1004","Tanaka"
"1005","Simada"
"1006","Furuta"

11-2. サンプル①の実行結果

PS C:\> .\test01.ps1
1001 : Yamada
1002 : Suzuki
1003 : Mikimoto
1004 : Tanaka
1005 : Simada
1006 : Furuta
PS C:\>

11-3. サンプル②

$csv = import-csv c2.csv
$csvArr = @()
$csv | % {
    if($_.flag1 -eq 1){
        $tmpId = $_.id
        $tmpName = $_.Name
        echo "$tmpId : $tmpName"
    }
}
# c2.csv ファイル
"id","Name","flag1"
"1001","Yamada","1"
"1002","Suzuki","0"
"1003","Mikimoto","0"
"1004","Tanaka","1"
"1005","Simada","0"
"1006","Furuta","1"

11-4. サンプル②の実行結果

PS C:\> .\test01.ps1
1001 : Yamada
1004 : Tanaka
1006 : Furuta
PS C:\>

11-5. サンプル③

csvファイルから取得した値を2次元配列に格納します。

$csv = import-csv c1.csv
$csvArr = @()
$csv | % {
    if($_.flag1 -eq 1){
        $csvArr += ,@( $_.id, $_.Name )
    }
}

12. csv形式でファイル出力する

$csv | % {
    New-Object PSObject -Property @{
        id = $_[0]
        Name = $_[1]
    }
} | Export-Csv -Path "c2.csv" -Encoding UTF8

12.1 サンプル

$csv = import-csv c2.csv
$csv | % {
    New-Object PSObject -Property @{
        id = $_.id
        Name = $_.Name
    }
} | Export-Csv -Path "c3.csv" -Encoding UTF8

#c2.csv
"id","Name","flag1"
"1001","Yamada","1"
"1002","Suzuki","0"
"1003","Mikimoto","0"
"1004","Tanaka","1"
"1005","Simada","0"
"1006","Furuta","1"

12.2 サンプルの実行結果

出力されたc3.csvファイルの中身です。

#TYPE System.Management.Automation.PSCustomObject
"id","Name"
"1001","Yamada"
"1002","Suzuki"
"1003","Mikimoto"
"1004","Tanaka"
"1005","Simada"
"1006","Furuta"

13. 別の関数と変数の値をやり取りする

関数の前に . (ドット) をつけるとグローバル変数を操作できるっぽい(?)
※動きがよくわかってないです。

. funchoge

13-1. サンプル

$hoge=1
function Hoge(){
    $hoge = 99
 }

function Fuga(){
    echo "---"
    echo $hoge
 }

Hoge
Fuga
. Hoge
Fuga

13-2. サンプルの実行結果

PS C:\> .\test01.ps1
---
1
---
99
PS >

14. 実行結果をファイルに出力する

Start-Transcript .\log_$hoge-$fuga.log -append
Write-Output "log hoge fuga"
Stop-Transcript

14-1. サンプル

Start-Transcript .\log.log -append
Write-Output "log hoge fuga"
Stop-Transcript

14-2. サンプルの実行結果

PS C:\> .\test01.ps1
トランスクリプトが開始されました。出力ファイル: .\log.log
log hoge fuga
トランスクリプトが停止されました。出力ファイル: C:\tmp\log.log
PS C:\>

# log.log の中身
**********************
Windows PowerShell トランスクリプト開始
開始時刻: 20190203214527
ユーザー名: HOST001\user001
RunAs ユーザー: HOST001\user001
構成名: 
コンピューター: HOST001 (Microsoft Windows NT 10.0.17134.0)
ホスト アプリケーション: C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe
プロセス ID: 16396
PSVersion: 5.1.17134.407
PSEdition: Desktop
PSCompatibleVersions: 1.0, 2.0, 3.0, 4.0, 5.0, 5.1.17134.407
BuildVersion: 10.0.17134.407
CLRVersion: 4.0.30319.42000
WSManStackVersion: 3.0
PSRemotingProtocolVersion: 2.3
SerializationVersion: 1.1.0.1
**********************
トランスクリプトが開始されました。出力ファイル: .\log.log
log hoge fuga
**********************
Windows PowerShell トランスクリプト終了
終了時刻: 20190203214527
**********************

15. ファイルの値をiniファイル的に変数に格納する

$filename = "conf.ini"
$lines = get-content $filename -Encoding utf8
foreach($line in $lines){
    if($line -match "^$"){ continue }
    if($line -match "^\s*#"){ continue }
    $param = $line.split("=",2)
    switch ($param[0]){
        "hogeVal" { $hoge = $param[1] }
        "fugaVal" { $fuga = $param[1] }
        default { Write-Output "Not Found : $param[0]" }
    }
}

15.1 サンプル

$filename = "conf.ini"
$lines = get-content $filename -Encoding utf8
foreach($line in $lines){
    if($line -match "^$"){ continue }
    if($line -match "^\s*#"){ continue }
    $param = $line.split("=",2)
    switch ($param[0]){
        "hogeVal" { $hoge = $param[1] }
        "fugaVal" { $fuga = $param[1] }
        default { Write-Output "Not Found : $param" }
    }
}
echo "hoge = $hoge"
echo "fuga = $fuga"

# conf.ini
hogeVal=HOGEです
fugaVal=FUGAですよ
piyoVal=PIYOですかね

15.2 サンプルの実行結果

PS C:\> .\test01.ps1
Not Found : piyoVal PIYOですかね
hoge = HOGEです
fuga = FUGAですよ
PS C:\>

16. 配列から特定の要素を削除する

PS C:\> $hoge = @("A","B","C")
PS C:\> $hoge
A
B
C
PS C:\> $hoge.length
3
PS C:\> $hoge2 = $hoge -ne "B"
PS C:\> $hoge2
A
C
PS C:\> $hoge2.length
2
PS C:\>

トラブルシュート

[問題] PowerShell実行結果が文字化けする
[対策] 文字コードをShitf-JIS にする

スクリプトファイル(.ps1)に日本語などの2バイト文字があり、ファイルの拡張しが Shift-JIS 以外の場合、文字化けが発生する場合があります。

PS > .\test01.ps1
・醍分逶ョ縺ョ蛟、縺ッ縲・targetList[0] 縺ァ縺吶�・
PS >

メモ帳で文字コードを変換する場合は、[ファイル]->[名前を付けて保存]で、ANSI を選択します(ShiftJIS ≒ANSI)

こんな弱小ブログでもサポートしてくれる人がいることに感謝です。