9

信じられないことです。test.ps1これは、ファイル内のPowerShellコードスニペットです。

Set-StrictMode -Version 2
mkdir c:\tmp\1  # same with 'md c:\tmp\1'

開始し、スクリプトcmd.exeを含むフォルダーに移動して実行します。test.ps1

c:\tmp>powershell ".\test.ps1"

これにより、次のエラーが発生します。

The variable '$_' cannot be retrieved because it has not been set.
At line:50 char:38
+         $steppablePipeline.Process($_ <<<< )
    + CategoryInfo          : InvalidOperation: (_:Token) [], ParentContainsEr
   rorRecordException
    + FullyQualifiedErrorId : VariableIsUndefined

なんで?

PowerShellコンソールから起動した場合は機能しますが、cmd.exeでは機能しません。私はこのバグをはるかに大きなスクリプトで発見しました。それはWTFの瞬間でした。

この単純なスクリプトの何が問題になっていますか?

4

2 に答える 2

14

回避策はすでに見つかっていますが、人々は説明に興味があるのではないかと思いました。

シェルと cmd.exe で動作が異なる理由については、「Powershell 2.0 - コマンド ライン呼び出しと ISE からのスクリプトの実行」を参照してください。

リファレンスに記載されているように、次の 2 つのコマンドには違いがあります。

powershell ".\test.ps1"
powershell -File ".\test.ps1"

最初の構文を使用すると、スコープが混乱するように見え、Set-StrictMode コマンドがグローバル スコープで定義された関数の厳密モードを変更します。

これにより、mkdir 関数の定義にバグ (または誤った仮定) が発生します。

この関数は、GetSteppablePipeline メソッドを使用して、New-Item コマンドレットのパイプラインをプロキシします。ただし、作成者は、パイプラインに何もない場合でも PROCESS セクションが実行されるという事実を説明することを怠っています。したがって、PROCESS セクションに到達すると、$_ 自動変数は定義されません。厳密モードが有効になっている場合、例外が発生します。

Microsoft がこれを説明する 1 つの方法は、次の行を置き換えることです。

    $steppablePipeline.Process($_)

次のように:

    if (test-path Variable:Local:_) {
        $steppablePipeline.Process($_)
    }

これが最善の修正方法ではないことは認めますが、オーバーヘッドはごくわずかです。もう 1 つのオプションは、パイプラインが BEGIN セクションで空かどうかを何らかの方法でテストし、$_ を $null に設定することです。

いずれにせよ、"powershell.exe -File filename" 構文を使用してスクリプトを実行する場合は、心配する必要はありません。

于 2011-07-01T20:21:17.277 に答える
2

バグのようです (PowerShell の場合)。

于 2011-02-16T23:26:49.397 に答える