4
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

PowerShell スクリプトのエラー処理について

Last updated at Posted at 2019-12-24

Windows PowerShell 5.1 で確認。

構文エラー

パース段階でエラーが起きた場合、スクリプト全体が実行されない。例えば次のスクリプトを実行しようとしたとき、「###Start###」も「###End###」も表示されない。後述の trap ブロックや catch ブロックがあっても実行されない。

error_test.ps1
Write-Output "###Start###"
$syntaxError = (1/)
Write-Output "###End###"
PS C:\> .\error_test.ps1
発生場所 C:\error_test.ps1:2 文字:19
+ $syntaxError = (1/)
+                   ~
'/' 演算子に続けて値の式を指定する必要があります。
    + CategoryInfo          : ParserError: (:) [], ParseException
    + FullyQualifiedErrorId : ExpectedValueExpression

実行時エラー

ErrorAction

デフォルトでは、実行時エラーが起きてもスクリプトの実行が継続する。これは、ErrorAction パラメーターのデフォルト値が Continue であるため。

error_test.ps1
Write-Output "###Start###"
$divideByZero = (1/0)
Write-Output "###End###"
PS C:\> .\error_test.ps1
### Start###
0 で除算しようとしました。
発生場所 C:\error_test.ps1:2 文字:1
+ $divideByZero = (1/0)
+ ~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], RuntimeException
    + FullyQualifiedErrorId : RuntimeException

### End###

ErrorAction パラメーターの値を Stop にすると、エラーが起きた時点でスクリプトが停止する。

error_test.ps1
$ErrorActionPreference = "Stop"
Write-Output "###Start###"
$divideByZero = (1/0)
Write-Output "###End###"
PS C:\> .\error_test.ps1
### Start###
0 で除算しようとしました。
発生場所 C:\error_test.ps1:3 文字:1
+ $divideByZero = (1/0)
+ ~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : RuntimeException

「###End###」が表示されなくなった。例外のクラスが RuntimeException から ParentContainsErrorRecordException に変わっているが、なぜかは私にはわからない。

個々のコマンドレットで発生する実行時エラーに対しては、コマンドレットごとに ErrorAction の値を設定することもできる。

error_test.ps1
Write-Output "###Start###"
Get-ChildItem "NotExist" -ErrorAction "Stop"
Write-Output "###End###"
PS C:\> .\error_test.ps1
### Start###
Get-ChildItem : パス 'C:\NotExist' が存在しないため検出できません。
発生場所 C:\error_test.ps1:2 文字:1
+ Get-ChildItem "NotExist" -ErrorAction "Stop"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (C:\NotExist:String) [Get-ChildItem], ItemNotFoundException
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand

Trap

スクリプトの任意の位置に trap ブロックを置くと、エラーが起きたときに、trap ブロックの中身が実行されたのちエラーメッセージが出力される。trap ブロックの中では、エラーの内容を $_ で参照できる。

error_test.ps1
Write-Output "###Start###"
$divideByZero = (1/0)
Write-Output "###End###"
trap {
  Write-Output "###Trap start###"
  Write-Output $_
  Write-Output "###Trap end###"
}
PS C:\> .\error_test.ps1
### Start###
### Trap start###
0 で除算しようとしました。
発生場所 C:\error_test.ps1:2 文字:1
+ $divideByZero = (1/0)
+ ~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], DivideByZeroException
    + FullyQualifiedErrorId : RuntimeException

### Trap end###
0 で除算しようとしました。
発生場所 C:\error_test.ps1:2 文字:1
+ $divideByZero = (1/0)
+ ~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], RuntimeException
    + FullyQualifiedErrorId : RuntimeException

### End###

ErrorAction の値が Continue なので「###End###」が表示されている。trap で捕捉された例外とエラーメッセージに表示される例外が異なるが、なぜかは私にはわからない。

デフォルトでは、つまり ErrorAction の値が Continue の場合、個々のコマンドレットで発生する実行時エラーは捕捉されない。

error_test.ps1
Write-Output "###Start###"
Get-ChildItem "NotExist"
Write-Output "###End###"
trap {
  Write-Output "###Trap start###"
  Write-Output $_
  Write-Output "###Trap end###"
}
PS C:\> .\error_test.ps1
### Start###
Get-ChildItem : パス 'C:\NotExist' が存在しないため検出できません。
発生場所 C:\error_test.ps1:2 文字:1
+ Get-ChildItem "NotExist"
+ ~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (C:\NotExist:String) [Get-ChildItem], ItemNotFoundException
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand

### End###

個々のコマンドレットでの実行時エラーを捕捉するには、そのコマンドレットで ErrorAction の値を Stop にする。この場合も、スクリプトの実行はエラーが起きた後も継続する。

error_test.ps1
Write-Output "###Start###"
Get-ChildItem "NotExist" -ErrorAction "Stop"
Write-Output "###End###"
trap {
  Write-Output "###Trap start###"
  Write-Output $_
  Write-Output "###Trap end###"
}
PS C:\> .\error_test.ps1
### Start###
### Trap start###
Get-ChildItem : パス 'C:\NotExist' が存在しないため検出できません。
発生場所 C:\error_test.ps1:2 文字:1
+ Get-ChildItem "NotExist" -ErrorAction "Stop"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (C:\NotExist:String) [Get-ChildItem], ItemNotFoundException
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand

### Trap end###
Get-ChildItem : パス 'C:\NotExist' が存在しないため検出できません。
発生場所 C:\error_test.ps1:2 文字:1
+ Get-ChildItem "NotExist" -ErrorAction "Stop"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (C:\NotExist:String) [Get-ChildItem], ItemNotFoundException
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand

### End###

スクリプト全体で ErrorAction の値を Stop にすると、エラーを捕捉できるだけでなく、エラーが起きたときにスクリプトの実行が止まる。

error_test.ps1
$ErrorActionPreference = "Stop"
Write-Output "###Start###"
Get-ChildItem "NotExist"
Write-Output "###End###"
trap {
  Write-Output "###Trap start###"
  Write-Output $_
  Write-Output "###Trap end###"
}
PS C:\> .\error_test.ps1
### Start###
### Trap start###
Get-ChildItem : パス 'C:\NotExist' が存在しないため検出できません。
発生場所 C:\error_test.ps1:3 文字:1
+ Get-ChildItem "NotExist"
+ ~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (C:\NotExist:String) [Get-ChildItem], ItemNotFoundException
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand

### Trap end###
Get-ChildItem : パス 'C:\NotExist' が存在しないため検出できません。
発生場所 C:\error_test.ps1:3 文字:1
+ Get-ChildItem "NotExist"
+ ~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (C:\NotExist:String) [Get-ChildItem], ItemNotFoundException
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand

Try Catch Finally

try ブロックの中で実行時エラーが起きると、処理が catch ブロックに移る。trap と同様、catch ブロックの中でもエラーの内容を $_ で参照できる。ただし、trap と異なり、エラーメッセージは出力されない。

error_test.ps1
Write-Output "###Start###"
try {
  Write-Output "###Try start###"
  $divideByZero = (1/0)
  Write-Output "###Try end###"
} catch {
  Write-Output "###Catch start###"
  Write-Output $_
  Write-Output "###Catch end###"
}
Write-Output "###End###"
PS C:\> .\error_test.ps1
### Start###
### Try start###
### Catch start###
0 で除算しようとしました。
発生場所 C:\error_test.ps1:4 文字:3
+   $divideByZero = (1/0)
+   ~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], RuntimeException
    + FullyQualifiedErrorId : RuntimeException

### Catch end###
### End###

trap と同様、個々のコマンドレットで起きる実行エラーは捕捉されず、エラーメッセージが出力される。

error_test.ps1
Write-Output "###Start###"
try {
  Write-Output "###Try start###"
  Get-ChildItem "NotExist"
  Write-Output "###Try end###"
} catch {
  Write-Output "###Catch start###"
  Write-Output $_
  Write-Output "###Catch end###"
}
Write-Output "###End###"
PS C:\> .\error_test.ps1
### Start###
### Try start###
Get-ChildItem : パス 'C:\NotExist' が存在しないため検出できません。
発生場所 C:\error_test.ps1:4 文字:3
+   Get-ChildItem "NotExist"
+   ~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (C:\NotExist:String) [Get-ChildItem], ItemNotFoundException
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand

### Try end###
### End###

ErrorAction の値を Stop にすると、エラーを捕捉できるようになる。

error_test.ps1
Write-Output "###Start###"
try {
  Write-Output "###Try start###"
  Get-ChildItem "NotExist" -ErrorAction "Stop"
  Write-Output "###Try end###"
} catch {
  Write-Output "###Catch start###"
  Write-Output $_
  Write-Output "###Catch end###"
}
Write-Output "###End###"
PS C:\> .\error_test.ps1
### Start###
### Try start###
### Catch start###
Get-ChildItem : パス 'C:\NotExist' が存在しないため検出できません。
発生場所 C:\error_test.ps1:4 文字:3
+   Get-ChildItem "NotExist" -ErrorAction "Stop"
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (C:\NotExist:String) [Get-ChildItem], ItemNotFoundException
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand

### Catch end###
### End###

スクリプト全体で ErrorAction の値を Stop にしていても、try ブロックの中でエラーが起きた場合、catch ブロックの後にあるスクリプトが実行される。

error_test.ps1
$ErrorActionPreference = "Stop"
Write-Output "###Start###"
try {
  Write-Output "###Try start###"
  Get-ChildItem "NotExist"
  Write-Output "###Try end###"
} catch {
  Write-Output "###Catch start###"
  Write-Output $_
  Write-Output "###Catch end###"
}
Write-Output "###End###"
PS C:\> .\error_test.ps1
### Start###
### Try start###
### Catch start###
Get-ChildItem : パス 'C:\NotExist' が存在しないため検出できません。
発生場所 C:\error_test.ps1:5 文字:3
+   Get-ChildItem "NotExist" -ErrorAction "Stop"
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (C:\NotExist:String) [Get-ChildItem], ItemNotFoundException
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand

### Catch end###
### End###

エラーが起きた後にスクリプトの実行を止めたい場合、catch ブロックの末尾に break を置く。

error_test.ps1
$ErrorActionPreference = "Stop"
Write-Output "###Start###"
try {
  Write-Output "###Try start###"
  Get-ChildItem "NotExist"
  Write-Output "###Try end###"
} catch {
  Write-Output "###Catch start###"
  Write-Output $_
  Write-Output "###Catch end###"
  break
}
Write-Output "###End###"
PS C:\> .\error_test.ps1
### Start###
### Try start###
### Catch start###
Get-ChildItem : パス 'C:\NotExist' が存在しないため検出できません。
発生場所 C:\error_test.ps1:5 文字:3
+   Get-ChildItem "NotExist"
+   ~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (C:\NotExist:String) [Get-ChildItem], ItemNotFoundException
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand

### Catch end###

エラーが起きても起きなくても実行するスクリプトがある場合は、finally ブロックに記述する。

error_test.ps1
$ErrorActionPreference = "Stop"
Write-Output "###Start###"
try {
  Write-Output "###Try start###"
  Get-ChildItem "NotExist"
  Write-Output "###Try end###"
} catch {
  Write-Output "###Catch start###"
  Write-Output $_
  Write-Output "###Catch end###"
  break
} finally {
  Write-Output "###Finally###"
}
Write-Output "###End###"
PS C:\> .\error_test.ps1
### Start###
### Try start###
### Catch start###
Get-ChildItem : パス 'C:\NotExist' が存在しないため検出できません。
発生場所 C:\error_test.ps1:5 文字:3
+   Get-ChildItem "NotExist"
+   ~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (C:\NotExist:String) [Get-ChildItem], ItemNotFoundException
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand

### Catch end###
### Finally###

外部ツールのエラー

PowerShell スクリプトから呼び出した外部ツールでエラーが起きた場合、PowerShell スクリプトではエラーを捕捉できない。try ブロック内で結果を判定して、期待した結果でなければ throw すると、その例外を捕捉できる。外部プロセスの結果は $LastExitCode に書き込まれるので、この値を見て結果を判定できる。具体的な方法は外部ツールによって異なる。

4
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?