回避策

回避策

Invoke-Commandコマンドをリモートで実行した場合と、まったく同じコマンドをまったく同じシステム上でローカルに実行した場合とで結果が異なるのはなぜですか?

リモートで呼び出されたこれらのコマンドは、4 つの空行を表示します。

PS > Invoke-Command cluster02 { cmd /c dir c:\ | select-string 'bytes free' }

これらのローカル コマンドは期待どおりに出力します。

PS > Invoke-Command cluster02 { cmd /c dir c:\ | select-string 'bytes free' }

11 Dir(s) 828,179,570,688 bytes free

最初に を起動してEnter-PSSession cluster02から実行すると、両方のコマンドが期待どおりの出力を返します。

これは古い PowerShell (Windows 2012) のバグでしょうか、それとも PS の特殊性を見逃しているのでしょうか? バグまたは特殊性である場合、いつ現れるのでしょうか? つまり、この奇妙な動作から学ぶべきことはあるのでしょうか?

答え1

問題は、cmd /ccmddirコマンドを使用してリモートで実行し、それをリモートで PowerShell コマンドにパイプしようとしていることです。

これをリモートで実行する場合、ローカルで実行する場合とまったく同じように動作すると期待されますが、違いが生じて混乱が生じることが知られています。

に記載されているように、ユーザープロファイルを必要とするコマンドはリモートで実行すると失敗する可能性があります役職

問題は、リモート コンピューターに接続しても、完全なユーザー環境が構築されないことです。技術的には、通常の意味でマシンに「ログオン」しているわけではありません。認証は行いますが、共有フォルダーに認証するのとほぼ同じ方法です。リモート接続には完全なユーザー プロファイルがないため、完全なユーザー プロファイルを期待するものはすべてエラーが発生して失敗する可能性があります (エラーが表示されなくても)。

残念ながら、これを簡単に解決する方法はありません。

リモート マシンに対して実行する場合Invoke-Command -ScriptBlock {}、コマンドはできる限り PowerShell のままにしておきます。cmd と PowerShell を混在させる場合は、対話形式でシステムにログオンして実行した場合と同じように動作しない可能性があるため、徹底的にテストする必要があります。

リモート PowerShell、ドライブの空き容量をバイト単位で取得 (いいえcmd)

Invoke-Command -ComputerName Cluster02 -ScriptBlock {(Get-PSDrive C).Free}

出力

599257099776

回避策

の出力をInvoke-Command変数として設定し、そこから文字列と行プロパティを選択すると、希望する出力が得られるようです。

PowerShell (バリエーション 1)

$var = Invoke-Command cluster02 -ScriptBlock { cmd /c "dir c:\" }; 
($var| select-string 'bytes free').Line.Trim();

出力

11 Dir(s)  36,011,925,504 bytes free

問題はおそらくを呼び出し、次に PowerShell パイプがリモートで呼び出されたセッションでそこから一致する文字列を選択するためです。この問題を回避するには、 の外部の変数として正しく返されるcmd /cからの完全な出力を保存し、 の外部でもその変数を適切に解析します。invoke-commandinvoke-commandinvoke-command

PowerShell (バリエーション 2)

これは上記と同じ処理ですが、変数をミックスに投入するのではなく、クエリInvoke-CommandにパイプするだけですSelect-String

Invoke-Command cluster02 -ScriptBlock { cmd /c "dir c:\"; } | select-string 'bytes free';

あるいは、このようなものも...

(Invoke-Command cluster02 -ScriptBlock { cmd /c "dir c:\"; } | select-string 'bytes free').Line.Trim()

答え2

(この TLDR バージョンが気に入った場合は、承認された回答にも賛成票を投じてください)

TLDRガイドライン

スクリプト ブロックをリモートで実行する場合:

  • 可能であれば、ネイティブ PowerShell 以外のものを実行しないでください。例:cmd /c dir c:\|sls 'bytes free'を に置き換えます(Get-PSDrive C).Free
  • そうでない場合は、リモート シェルで最小限の処理を実行します。たとえば、次のようにして select-string をリモート シェルの外に移動しますInvoke-Command cluster02 { cmd /c "dir c:\" } | sls 'bytes free'

関連情報