• Windows PowerShell 入門(9)-エラー編


    対象読者

    • Windows PowerShellでコマンドレット操作ができる方
    • 何らかのプログラミング経験があればなお良い

    必要環境

    • Windows PowerShell

    エラーをリダイレクトする

     リダイレクトとは、処理を行った結果の出力先を別の場所へ変更することを意味します。

     通常PowerShell上で、あるコマンドを実行してエラーが発生した場合は、コンソールウィンドウにエラーメッセージが表示されます。ここでは、このエラーをファイルに出力することを「リダイレクトする」と呼んでいます。

     PowerShellでエラーをファイルにリダイレクトするには、リダイレクト演算子を使用した3つの方法があります。

    2> 演算子

     この演算子は、エラーの内容をファイルに出力します。出力先のファイルが既に存在する場合には上書きをします。

     下記は、dirコマンドで存在しないファイルを指定した場合の例です。(「C:Work」フォルダに「HOGE.txt」が存在しないものとします)

    PS C:Work> dir HOGE.txt
    Get-ChildItem : パス 'C:WorkHOGE.txt' が存在しないため検出できません。
    発生場所 行:1 文字:4
    + dir  <<<< HOGE.txt
    

     では、このエラーをファイルにリダイレクトしてみます。

    PS C:Work> dir HOGE.txt 2>err.txt
    

     上記のように、2>演算子の後ろに、エラーメッセージを書き込むファイル名を記述します。

     では、Get-Contentコマンドレットを使用して作成された「err.txt」ファイルの中身をみてみましょう。

    PS C:Work> Get-Content err.txt
    Get-ChildItem : パス 'C:WorkHOGE.txt' が存在しないため検出できませ
    ん。
    発生場所 行:1 文字:4
    + dir  <<<< HOGE.txt 2>err.txt
    

     エラーの内容がリダイレクトされていることが分かります。

    2>> 演算子

     この演算子は、エラーの出力先のファイルが既に存在する場合は、追記書き込みを行います。

     追記されることを確認するために、出力先のファイルは先ほどと同じ「err.txt」とします。また。異なるエラーメッセージが記述されるようmkdirコマンドに変更しました。

    PS C:Work> mkdir HO*GE 2>> err.txt
    

     実行したら、先ほど同様Get-Contentコマンドレットで確認してみましょう。

    PS C:Work> Get-Content err.txt
    Get-ChildItem : パス 'C:WorkHOGE.txt' が存在しないため検出できませ
    ん。
    発生場所 行:1 文字:4
    + dir  <<<< HOGE.txt 2>err.txt
    New-Item : パスに無効な文字が含まれています。
    発生場所 行:1 文字:34
    + param([string[]]$paths); New-Item <<<< -type directory -path $paths
    

     エラーメッセージが追記されていることが分かります。

    2>&1 演算子

     この演算子を使用すると、エラーの内容を変数に書き込むことができます。

    $err = mkdir HO*GE 2>&1
    

     では、エラーの内容が変数に代入されているかを確認してみましょう。

    caption
    PS C:Work> $err
    New-Item : パスに無効な文字が含まれています。
    発生場所 行:1 文字:34
    + param([string[]]$paths); New-Item <<<< -type directory -path $paths
    

     通常、変数の内容を確認してもメッセージに色がつかないのですが、2>&1演算子を使用して代入された値は、赤色で表示されていることが分かります。

     これは、変数に代入された値はエラーであることを示すErrorRecordオブジェクトとなるからです。(Errorオブジェクトは後述します))

    PS C:Work> $err.GetType()
    
    IsPublic IsSerial Name                                  BaseType
    -------- -------- ----                                  --------
    True     True     ErrorRecord                           System.Object
    
    -ErrorVariableパラメータ
     2>&1 演算子を使用する以外に-ErrorVariableパラメータを使用しても変数にエラーを代入することが可能です。
    PS C:Work> Get-ChildItem HOGE.txt -ErrorVariable err1
    Get-ChildItem : パス 'C:WorkHOGE.txt' が存在しないため検出できませ
    ん。
    発生場所 行:1 文字:14
    + Get-ChildItem  <<<< HOGE.txt -ErrorVariable err1
    
     -ErrorVariableパラメータの後ろには、エラー内容を代入するための変数を指定します。このとき、指定する変数に$を付加してはいけないことに注意してください。
     $Error変数は、PowerShellの操作時に発生したすべてのエラーが格納されますが、この-ErrorVariableパラメータを使用した場合は、そのとき発生したエラーの内容だけを特定の変数に代入できるという違いがあります。
     

    ErrorRecordオブジェクト

     さきほど、2>&1演算子で代入したエラーはErrorRecordオブジェクトとなることを説明しました。では、ErrorRecordオブジェクトにはどのようなメンバーが備わっているかを確認したいと思います。

     先ほどの変数$errに対してGet-Memberコマンドレットを使用し、どのようなメンバーがあるかを確認してみたいと思います。

    PS C:Work> $err | Get-Member
    
       TypeName: System.Management.Automation.ErrorRecord
    
    Name                   MemberType   Definition
    ----                   ----------   ----------
    Equals                 Method       System.Boolean Equals(Object obj)
    GetHashCode            Method       System.Int32 GetHashCode()
    GetObjectData          Method       System.Void 
          GetObjectData(SerializationInfo info, StreamingContext context)
    GetType                Method       System.Type GetType()
    get_CategoryInfo       Method 
       System.Management.Automation.ErrorCategoryInfo get_CategoryInfo()
    get_ErrorDetails       Method 
       System.Management.Automation.ErrorDetails get_ErrorDetails()
    get_Exception          Method 
       System.Exception get_Exception()
    get_FullyQualifiedErrorId Method 
       System.String get_FullyQualifiedErrorId()
    get_InvocationInfo     Method 
       System.Management.Automation.InvocationInfo get_InvocationInfo()
    get_TargetObject       Method       System.Object get_TargetObject()
    set_ErrorDetails       Method 
       System.Void set_ErrorDetails(ErrorDetails value)
    ToString               Method       System.String ToString()
    writeErrorStream       NoteProperty 
       System.Boolean writeErrorStream=True
    CategoryInfo           Property 
       System.Management.Automation.ErrorCategoryInfo CategoryInfo {get;}
    ErrorDetails           Property 
       System.Management.Automation.ErrorDetails ErrorDetails {get;set;}
    Exception              Property 
       System.Exception Exception {get;}
    FullyQualifiedErrorId  Property 
       System.String FullyQualifiedErrorId {get;}
    InvocationInfo         Property 
       System.Management.Automation.InvocationInfo InvocationInfo {get;}
    TargetObject           Property     System.Object TargetObject {get;}
    

     多くのメンバーを備えていることが確認できます。これらの中から、主要なものについて説明したいと思います。

    CategoryInfoプロパティ

     このプロパティは文字通り、エラーの種類についての情報が格納されています。

    PS C:Work> $err.CategoryInfo
    
    Category   : InvalidArgument
    Activity   : New-Item
    Reason     : ArgumentException
    TargetName : C:WorkHO*GE
    TargetType : String
    

     Categoryが「InvalidArgument」となっていることが分かります。これはdirコマンドに対して、無効な文字が含まれたパスを指定しているためです。さらにReason(発生理由)をみると、「ArgumentException」という例外が発生したことが分かります。

    Exceptionプロパティ

     Exceptionプロパティ自体もさまざまなメンバーを持っていますが、規定のプロパティはMessageとなっており、エラーの内容を確認することができます。

    PS C:Work> $err.Exception
    パスに無効な文字が含まれています。
    

    InvocationInfoプロパティ

     このプロパティはエラーの発生場所に関する情報が格納されます。PositionMessageの欄を見ると、「1行目の34文字目でエラーが発生した」ということを確認できます。

    PS C:Work> $err.InvocationInfo
    
    MyCommand        : New-Item
    ScriptLineNumber : 1
    OffsetInLine     : -2147483648
    ScriptName       :
    Line             : param([string[]]$paths); New-Item -type directory
                       -path $paths
    PositionMessage  :
                       発生場所 行:1 文字:34
                       + param([string[]]$paths); New-Item 
                       <<<< -type directory -path $paths
    InvocationName   : New-Item
    PipelineLength   : 1
    PipelinePosition : 1
    

    TargetObjectプロパティ

     このプロパティには、エラー発生時の操作対象オブジェクトが格納されます。ただし、すべてのエラーがこのプロパティを設定するわけではないため、Nullの場合もあります。

    PS C:Work> $err.TargetObject
    C:WorkHO*GE
    

     このようにErrorRecordオブジェクトには、エラーの原因を解明する上で役立つ情報が格納されています。

    $Error変数

     PowerShellではエラーが発生するごとに、そのエラー内容を保存している変数があります。この変数は$Errorという自動変数で、配列型となっています。

     また、この変数に格納できる最大要素数は自動変数$MaximumErrorCountで決められており、256のエラー(規定値)を保持します。

     では、実際にエラーを発生させて$Error変数がどのように変わっていくのかを見てみます。(PowerShellを立ち上げていた方は、念のため起動し直してから始めてください)

     まずは、PowerShell立ち上げ時点の$Error変数の内容を確認しておきましょう。

    PS C:Work> $Error
    PS C:Work>
    

     この時点でエラーは発生していないので、何も格納されていません。下記のように入力して、エラーを発生させます。

    PS C:Work> dir HOGE
    Get-ChildItem : パス 'C:WorkHOGE' が存在しないため検出できません。
    発生場所 行:1 文字:4
    + dir  <<<< HOGE
    

     エラーを発生させた後の$Error変数を確認してみます。

    PS C:Work> $Error
    Get-ChildItem : パス 'C:WorkHOGE' が存在しないため検出できません。
    発生場所 行:1 文字:4
    + dir  <<<< HOGE
    

     上記のように、先ほど発生した内容が格納されていることが分かります。

     $Errorは配列なので、要素数の変化について確認してみます。要素数はCountプロパティで確認することができます。

    PS C:Work> $Error.Count
    1
    

     エラーは1つしか発生していないので、要素数は"1"となります。

     次に、もう1つエラーを発生させてみましょう。

    PS C:Work> mkdir HO*GE2
    New-Item : パスに無効な文字が含まれています。
    発生場所 行:1 文字:34
    + param([string[]]$paths); New-Item <<<< -type directory -path $paths
    

     この状態で$Error変数の内容を確認してみると

    PS C:Work> $Error
    New-Item : パスに無効な文字が含まれています。
    発生場所 行:1 文字:34
    + param([string[]]$paths); New-Item <<<< -type directory -path $paths
    Get-ChildItem : パス 'C:WorkHOGE' が存在しないため検出できません。
    発生場所 行:1 文字:4
    + dir  <<<< HOGE
    

     少し見づらいですが、2つのエラーが格納されていることが分かります。

     $Error変数は配列なので、下記のように要素番号を指定して1つずつエラーを取り出すことができます。

    PS C:Work> $Error[0]
    New-Item : パスに無効な文字が含まれています。
    発生場所 行:1 文字:34
    + param([string[]]$paths); New-Item <<<< -type directory -path $paths
    

     また$Error変数は、新しいエラーが発生すると常に$error[0]へ書き込みます。以前に$error[0]に代入されていたエラーは$error[1]へ、$error[1]のエラーは$error[2]へと移動します。

     このことから、最新のエラーは$error[0]を参照すればよいことが分かります。

    $?変数

     この変数は、最後に実行したコマンドの実行状態を保持するブール変数です。直前の処理が成功した場合にはTrue、それ以外の場合はFalseとなります。

     まずは、この変数の動きを見てみましょう。何もエラーが発生していない状態で、$?変数の中身を確認すると

    PS C:Work> $?
    True
    

     上記のようにTrueを返します。

     下記のようにエラー発生させ

    PS C:Work> Get-ChildItem HOGE
    Get-ChildItem : パス 'C:WorkHOGE' が存在しないため検出できません。
    発生場所 行:1 文字:14
    + Get-ChildItem  <<<< HOGE
    

     $?の値を確認すると

    PS C:Work> $?
    False
    

     上記のようにFalseを返します。

     この$?変数は特にスクリプトの中で効果を発揮します。

     下記はカレントディレクトリに「HOGE」が存在するかを確認していますが、存在しない場合にはエラーが発生します。しかし、2>&1演算子を利用してエラー内容を$err変数に書き込むので、エラーメッセージは表示されません。また、エラーが発生しても処理は続行します。

     このような場合に$?を使用することで、直前のコマンドが成功したか否かを確認することが可能となります。

    $err = Get-ChildItem HOGE 2>&1
    
    if ($?) {"エラーは発生しませんでした" }
    else {"エラーが発生しました"}
    

    -ErrorActionパラメータと$ErrorActionPreference変数

     PowerShellでは、エラーの表示方法を制御することが可能で

    • コマンドレット使用時に発生したエラー
    • すべてのエラー

     それぞれに対して行うことができます。

     コマンドレット使用時のエラー表示を制御するには-ErrorActionパラメータを、すべてのエラー表示の制御を行うには$ErrorActionPreference変数を設定します。

     設定可能な値は共通です。それぞれについて見ていきます。

    continue

     デフォルトではcontinueになっています。エラーが発生した場合はメッセージが出力されます。

     エラーの内容は$Error変数に追加され、$?変数はFalseとなります。スクリプトは次の行から実行されます。

    silentlycontinue

     エラーが発生してもメッセージは出力されません。

     エラーの内容は$Error変数に追加され、$?変数はFalseとなります。スクリプトは次の行から実行されます。

    stop

     エラーが発生した時点で処理を中止します。

     エラーの内容は$Error変数に追加され、$?変数はFalseとなります。スクリプトは停止します。

    -ErrorActionパラメータの使用方法

     このパラメータは、コマンドレット使用時に発生したエラーの表示を制御します。

     -ErrorActionパラメータにcontinueを設定した場合は、エラーメッセージが出力されます。

    PS C:Work> Get-ChildItem Hoge -ErrorAction "continue"
    Get-ChildItem : パス 'C:WorkHoge' が存在しないため検出できません。
    発生場所 行:1 文字:14
    + Get-ChildItem  <<<< Hoge -ErrorAction "continue"
    

     -ErrorActionパラメータにsilentlycontinueを設定した場合は、エラーメッセージが出力されません。

    PS C:Work> Get-ChildItem Hoge -ErrorAction "silentlycontinue"
    PS C:Work>
    

     -ErrorActionパラメータにstopを設定した場合は、エラーアクション設定によって実行が中止されたことを示すメッセージが表示され、処理を中止します。

    PS C:Work> Get-ChildItem Hoge -ErrorAction "stop"
    Get-ChildItem : シェル変数 "ErrorActionPreference" が Stop に設定さ
    れているため、コマンドの実行が停止しました。
    パス 'C:WorkHoge' が存在しないため検出できません。
    発生場所 行:1 文字:14
    + Get-ChildItem  <<<< Hoge -ErrorAction "stop"
    

    $ErrorActionPreference変数の使用方法

     この変数に設定した値は、発生したエラーすべてのエラー表示を制御します。

     $ErrorActionPreference変数への値の設定は、=演算子の左辺に$ErrorActionPreference変数を、右側に設定する値を記述します。

     試しに$ErrorActionPreference変数へsilentlycontinueを設定してみます。

    PS C:Work> $ErrorActionPreference = "silentlycontinue"
    

     この状態で、エラーが発生するコマンドを実行してみます。

    PS C:Work> Get-ChildItem Hoge
    PS C:Work>
    

     エラーメッセージは表示されません。

     $ErrorActionPreference変数にsilentlycontinueを設定した効果が現れていることが分かります。(元に戻すには$ErrorActionPreference="Continue"と入力してください。)

    例外処理をする

     PowerShellではtrap文を用いることで、例外処理を行うことができます。trap文の構文は下記の通りです。

    trap [<例外の種類>]
    {
        trap文本体
    }
    

     「例外の種類」は省略することが可能です。

     例えば下記では、1/$Nullを実行されるゼロ除算例外が発生するため、trapへ制御が移り「例外発生」の文字列を表示します。

    PS C:Work> trap
    >> {"例外発生" }
    >> 1/$Null
    >>
    例外発生
    0 で除算しようとしました。
    発生場所 行:3 文字:3
    + 1/$ <<<< Null
    

    breakで処理を中断する

     次に、例外が発生したら処理を中断する方法について見てみましょう。中断するにはbreakを使用します。

    trap2.ps1
    trap
    {
        "例外が発生しました"
        break
    }
    
    1/$Null
    
    Write-Host "スクリプト終了"
    

     このスクリプトは、例外が発生するとtrapを実行するので「例外が発生しました」のメッセージを表示します。さらにbreakが実行されエラーメッセージを表示し、処理を中断します。

     この結果、「スクリプト終了」の文字列は表示されません。

    PS C:Work> ./trap2.ps1
    例外が発生しました
    0 で除算しようとしました。
    発生場所 C:Work	rap.ps1:7 文字:3
    + 1/$ <<<< Null
    

    continueを使用する

     次にtrapの中でcontinueを使用するとどうなるか、見てみましょう。

    trap3.ps1
    trap
    {
        "例外が発生しました"
        continue
    }
    
    1/$Null
    
    Write-Host "スクリプト終了"
    

     実行結果は下記のとおりで、例外が発生すると「例外が発生しました」のメッセージが表示され、最後の「スクリプト終了」が表示されます。

    PS C:Work> ./trap3.ps1
    例外が発生しました
    スクリプト終了
    

     このようにcontinueを使用した場合はエラーメッセージは表示されず、trapを実行後、例外が発生した次の行から処理が再開されます。

    まとめ

     今回は

    • エラーのリダイレクト
    • -ErrorRecordオブジェクト
    • $Error変数
    • $?変数
    • -ErrorActionパラメータと$ErrorActionPreference変数
    • --ErrorVariableパラメータ
    • 例外処理

     について取り上げました。

     PowerShellでは、エラーに対するさまざまな対処方法および内容の取得方法が準備されています。このことを理解し、スクリプト開発に役立てていただければと思います。

  • 相关阅读:
    [你必须知道的.NET]第二十一回:认识全面的null
    《你必须知道的.NET》,内容简介
    [IT史记]开篇:盖茨本纪之离歌
    《你必须知道的.NET》,封面
    《博客园精华集》,CLR/C#分册征求意见稿
    [开发故事]第二回:LINQ来了,先忘记foreach
    《你必须知道的.NET》,封底
    [不得不转载]一个时代的结束:微软盖茨的人生掠影
    [技术速递]MSDN在线改版,新风格新体验
    《你必须知道的.NET》,勘误支持
  • 原文地址:https://www.cnblogs.com/c-x-a/p/4488144.html
Copyright © 2020-2023  润新知