はじめに
こんにちはDXソリューション統括部の鈴木です。
今回は、PowerShellのコマンド「Invoke-Sqlcmd」を実行した際のエラーについてtry-catchでは拾えないものがあるということをお伝えできればと思います。
PowerShellでスクリプトを作成する際エラーへの対処(エラーをどう拾い、どう対応するか)は必ずどこかで考慮するものかと思いますが、try-catchがあれば何でもエラーを拾ってくれる!と過信していた結果そうでないことが判明したという気付きが本ブログの元ネタとなっています。
まずは、私が上記の事実に気づいた際とてもとても参考になった記事がありますので先にご紹介させてください↓
PowerShell のエラーハンドリングを(今度こそ)理解する – Qiita
Invoke-Sqlcmdについてはこちら→Invoke-Sqlcmd (SQLServer) | Microsoft Learn
Invoke-Sqlcmd実行時に想定される二つのエラー
先ほどご紹介した記事ではPowerShelのエラーは3つに分類できるとありますが、Invoke-Sqlcmdの実行において想定されるエラーについてはそれ自体、エラーの発生元から二つに分けることができるではないかと思います。
その二つとは、
①「Invoke-Sqlcmd」自体のエラー
②引数「Query」の実行結果としてのエラー
です。
そしてさらにこの二つのエラーをそれぞれ先程の記事↑での分類に当てはめてみると、
①「Invoke-Sqlcmd」自体のエラー:ステートメント終了エラー
②引数「Query」の実行結果としてのエラー:終了しないエラー
となることが分かりました。
先ほどの記事によると②のエラーはtry-catchで拾ってもらえないそうで、そこでtry-catchを入れているのにエラー発生後もtry内の後続の処理が実行されてしまう原因が判明したのでした。
実際に①②に対しtry-catchを実装した場合にどうなるのかを改めて確認してみましょう↓
検証してみる
Invoke-Sqlcmd自体でエラーになるとき
Invoke-Sqlcmd自体のエラーとして、コマンドの引数の値が誤っている場合を挙げることができます。
以下では「-Database」の値を「$DBNameg」(本当は$DBName)としています。
#実行したスクリプト
try {
Invoke-Sqlcmd -ServerInstance $instance -Database $DBNameg -Username $username -Password $password -Query $query
Write-Host “try:成功しました”
}
catch {
Write-Host “catch:エラーが発生しました”
}
#実行結果
catch:エラーが発生しました
tryの中のWrite-Hostは実行されずcatch内の処理が実行されているため、Invoke-Sqlcmd自体のエラーはtry-catchで拾ってもらえることが分かるかと思います。
クエリの実行でエラーになるとき
クエリの実行エラーとして、今回は「-Query」の値に「sp_addpublication」を使用したクエリ($query)を指定します。
sp_addpublicationは対象のDBに既に同名のパブリケーションが作成されているとエラーになるため、そのエラーを利用します。
#実行したスクリプト
try {
Invoke-Sqlcmd -ServerInstance $instance -Database $DBName -Username $username -Password $password -Query $query
Write-Host “try:成功しました”
}
catch {
Write-Host “catch:エラーが発生しました”
}
#実行結果
Invoke-Sqlcmd : The publication ‘[パブリケーション名]’ already exists.
メッセージ 14016、レベル 16、状態 1、プロシージャ sys.sp_MSrepl_addpublication、行 261。
発生場所 行:1 文字:13
+ Invoke-Sqlcmd -ServerInstance $global:instance -Database …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Invoke-Sqlcmd]、SqlPowerShellSqlExecutionException
+ FullyQualifiedErrorId : SqlError,Microsoft.SqlServer.Management.PowerShell.GetScriptCommandtry:成功しました
Invoke-Sqlcmd自体でエラーになる場合とは反対に、catch内の処理は実行されずにそのままtry内で処理が継続していることが分かるかと思います。
今回のようにスクリプトにメッセージの出力処理(Write-Hostなど)を加えている場合には、メッセージの内容と実行結果に乖離が発生してしまう恐れがあります。
よって、try-catchで拾ってもらえないエラーに対しては自動変数$Error.Countを使用するなど少し工夫が必要となります。
「はじめに」にてご紹介した記事の中にも対応策について記載がありますので是非ご参考ください。
おわりに
以上、Invoke-Sqlcmdのエラーとtry-catchの関係についてご説明させていただきました。
エラーの種類によってはただtry-catchを実装するのみでは不十分な場合があり、Invoke-Sqlcmdはそれに該当するということがお分かりいただけたのではないでしょうか。
今後Invoke-Sqlcmdを使用したスクリプトを作成される方にとって本ブログが少しでも参考となれば幸いです。
最後までお付き合いいただきありがとうございました!