Invoke-Sqlcmdのエラーをtry-catchで拾いきれなかった話

はじめに

こんにちは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.GetScriptCommand

try:成功しました

Invoke-Sqlcmd自体でエラーになる場合とは反対に、catch内の処理は実行されずにそのままtry内で処理が継続していることが分かるかと思います。

今回のようにスクリプトにメッセージの出力処理(Write-Hostなど)を加えている場合には、メッセージの内容と実行結果に乖離が発生してしまう恐れがあります。

 

よって、try-catchで拾ってもらえないエラーに対しては自動変数$Error.Countを使用するなど少し工夫が必要となります。

「はじめに」にてご紹介した記事の中にも対応策について記載がありますので是非ご参考ください。

 

おわりに

以上、Invoke-Sqlcmdのエラーとtry-catchの関係についてご説明させていただきました。

エラーの種類によってはただtry-catchを実装するのみでは不十分な場合があり、Invoke-Sqlcmdはそれに該当するということがお分かりいただけたのではないでしょうか。

今後Invoke-Sqlcmdを使用したスクリプトを作成される方にとって本ブログが少しでも参考となれば幸いです。

最後までお付き合いいただきありがとうございました!

いいね (この記事が参考になった人の数:1)
(↑参考になった場合はハートマークを押して評価お願いします)
読み込み中...

注意事項・免責事項

※技術情報につきましては投稿日時点の情報となります。投稿日以降に仕様等が変更されていることがありますのでご了承ください。

※公式な技術情報の紹介の他、当社による検証結果および経験に基づく独自の見解が含まれている場合がございます。

※これらの技術情報によって被ったいかなる損害についても、当社は一切責任を負わないものといたします。十分な確認・検証の上、ご活用お願いたします。

※当サイトはマイクロソフト社によるサポートページではございません。パーソルクロステクノロジー株式会社が運営しているサイトのため、マイクロソフト社によるサポートを希望される方は適切な問い合わせ先にご確認ください。
 【重要】マイクロソフト社のサポートをお求めの方は、問い合わせ窓口をご確認ください