hakeの日記

Windows環境でプログラミングの勉強をしています。

PowerShell - 例外処理(throw)

意図的に例外を発生させる場合にはthrowを使用する。

try { 
    "try節です"
    throw "例外発生"
}
catch [Exception] {
    "catch節です"
}
finally {
    "finary節です"
}
PS C:\> $error[0].CategoryInfo

Category   : OperationStopped
Activity   : 
Reason     : RuntimeException
TargetName : 例外発生
TargetType : String

例外として任意のオブジェクトも渡せる

try { 
    "try節です"
    throw New-Object regex ".."
}
catch [Exception] {
    "catch節です"
}
finally {
    "finary節です"
}
PS C:\> $error[0].CategoryInfo

Category   : OperationStopped
Activity   : 
Reason     : RuntimeException
TargetName : ..
TargetType : Regex


PS C:\> $error[0].TargetObject.GetType()

IsPublic IsSerial Name                    BaseType
-------- -------- ----                    --------
True     True     Regex                   System.Object

PowerShell - 関数(値渡しと参照渡し)

参照渡しの場合、呼び出し側の引数に[ref]をつける、また引数に括弧がないとエラーになった。
関数定義の仮引数の[ref]は無くても良い、関数内では仮引数のValueプロパティにアクセスする。

# 値渡し
function byVal($arg){
    $arg = "Good Bye"
    Write-Host "in Function : $arg"
}

# 参照渡し
function byRef([ref]$arg){
    $arg.Value= "Good Bye"  # Valueプロパティにアクセス
    Write-Host "in Function : $($arg.Value)"
}


$a = "Hello"
$a
byVal $a      # 値渡し
$a            # Hello


$a = "Hello"
byRef([ref]$a) # 参照渡し
$a             # Good Bye

PowerShell - 関数(パイプ)

パイプで渡されるてくるデータの処理用の関数。
開始処理はbeginブロック、終了処理はendブロック、渡されてくるデータの処理はprocessブロックに記述する。渡されてきたデータは変数$_に格納されている。
returnで値を返すと関数の出力になる。

even.ps1

function even {
    begin{ $cnt = 0 }
    process {
        $cnt++
        if($_ % 2 -eq 0){
            return "${cnt}番目のデータ:$_"
        } else {
            return
        }
    }
    end{ return "終了" }
}

実行結果

PS C:\> . C:\even.ps1

PS C:\> 1..10 | even
2番目のデータ:2
4番目のデータ:4
6番目のデータ:6
8番目のデータ:8
10番目のデータ:10
終了

PowerShell - 関数(可変長引数)

引数は変数$argsという配列にわたされる。

test.ps1

function foo {
    $args.GetType()

    foreach( $i in $args ) {
        Write-Host $i
    }
}

結果

PS C:\> . C:\test.ps1  # 関数読み込み
PS C:\> foo 1 2 3

IsPublic IsSerial Name                                     BaseType                    
-------- -------- ----                                     --------                    
True     True     Object[]                                 System.Array                
1
2
3

PS C:\> foo "a" "b" "c"

IsPublic IsSerial Name                                     BaseType                    
-------- -------- ----                                     --------                    
True     True     Object[]                                 System.Array                
a
b
c

PowerShell - 再帰関数

function fact($i) {
    if($i -eq 0) { 
        return 1
    } else {
        return $i * (fact ($i - 1))
    }
}

fact 5 # 120

2017/1/28追記 再帰回数に限界がある模様

Win10 PowerShell 5.1の環境で、以下の関数fooの引数が1000の場合は正常終了しましたが、5000の場合はエラーになりました。

function foo {
    param($i)

    #Write-Host $i
    if($i -eq 0){return 1}
    return (foo($i - 1)) + 1
}


Write-Host (Get-Date)
Write-Host "Result: $(foo(5000))" 
Write-Host (Get-Date)
PS C:\> C:\powershell\test.ps1
2017/01/28 21:47:03
Result: 1001
2017/01/28 21:47:04

PS C:\> C:\powershell\test.ps1
2017/01/28 21:47:18
呼び出しの深さのオーバーフローのため、スクリプトが失敗しました。
    + CategoryInfo          : InvalidOperation: (0:Int32) []、ParentContainsErrorRecordException
    + FullyQualifiedErrorId : CallDepthOverflow

PowerShell - 文字列

変数展開

PS C:\> $a = "Hello "
PS C:\> "${a} world" # " "で囲まれた中の変数は展開される
Hello  world

PS C:\> '${a} world' # ' 'で囲まれた中の変数は展開されない
${a} world

部分式

PS C:\> $a = 100

PS C:\> "$($a + 1) is 101"
101 is 101

ヒアドキュメント

改行付き文字列の代入と参照

$s = @"
abdefg
hijklmn
opqrstu
"@

write-host $s 

連結

PS C:\> "a" + "b"
ab

繰り返し

PS C:\> "a" * 5
aaaaa

ワイルドカード

PS C:\> "abcdefg" -like "a*"
True

否定演算子は -notlike

正規表現

PS C:\> "abcdefg" -match "^a"
True

否定演算子は -notmatch

分割

PS C:\> "abcdefg" -split "\B"
a
b
c
d
e
f
g

置換

PS C:\> "abcdefg" -replace "b","z"
azcdefg

フォーマット

PS C:\> "{0:#0.00}, {1:00.00}" -f(0.123, 0.123)
0.12, 00.12

その他

PS C:\> "abcdefg".Length
7
PS C:\> "abcdefg".Contains("c")
True
PS C:\> "abcdefg".IndexOf("c")
2
PS C:\> "abcdefg"[2]
c
PS C:\> "abcdefg".Insert(2, "z")
abzcdefg
PS C:\> "abzcdefg".Remove(2,1)
abcdefg