注:質問のコマンドではを使用しているためStart-Process
、ターゲットプログラムの出力が直接キャプチャされません。通常は、コンソールアプリケーションを同期的に実行するために使用しないStart-Process
で ください。他のシェルと同様に、直接呼び出すだけです。そうすることで、アプリケーションが呼び出しコンソールの標準ストリームに接続されたままになり、$output = netdom ...
以下に詳述するように、単純な割り当てによって出力をキャプチャできます。
基本的に、外部ユーティリティからの出力のキャプチャは、PowerShellネイティブコマンドと同じように機能します(外部ツールの実行方法について復習したい場合があります)。
$cmdOutput = <command> # captures the command's success stream / stdout
$cmdOutput
は、複数の出力オブジェクトを生成する場合にオブジェクトの配列を受け取ります。これは、外部プログラムの場合、プログラムの出力行を含む文字列配列を意味します。常に単一の、
場合によっては複数行の文字列を受け取りたい場合は、<command>
$cmdOutput
$cmdOutput = <command> | Out-String
キャプチャ変数に出力し、画面に印刷:
<command> | Tee-Object -Variable cmdOutput # Note how the var name is NOT $-prefixed
または、コマンドレットまたは高度な関数の場合<command>
は、共通パラメーター/を使用できます。
-OutVariable
-ov
<command> -OutVariable cmdOutput # cmdlets and advanced functions only
なおとともに-OutVariable
、他のシナリオとは異なり、 $cmdOutput
ある常に収集だけしても、1オブジェクトが出力されます。具体的には、配列のような[System.Collections.ArrayList]
型のインスタンスが返されます。この矛盾については、GitHubの問題を
ご覧ください。
以下からの出力をキャプチャするには、複数のコマンド、使用のいずれかの部分式($(...)
)または(スクリプトブロックを呼び出す{ ... }
)を持ちます&
か.
:
$cmdOutput = $(<command>; ...) # subexpression
$cmdOutput = & {<command>; ...} # script block with & - creates child scope for vars.
$cmdOutput = . {<command>; ...} # script block with . - no child scope
なお、接頭辞に一般的な必要性&
(コールオペレータ)、名前/パスされた個々のコマンドを引用し -例えば、$cmdOutput = & 'netdom.exe' ...
-それ自体が外部プログラムに関連していない(それが均等にPowerShellスクリプトに適用されます)が、ある構文要件:PowerShellのは、デフォルトでは式モードで引用符付きの文字列で始まるステートメントを解析しますが、コマンド(コマンドレット、外部プログラム、関数、エイリアス)を呼び出すには引数モードが必要です。&
$(...)
と& { ... }
/ の主な違い. { ... }
は、前者は全体を返す前にすべての入力をメモリに収集するのに対し、後者は1つずつパイプライン処理に適した出力をストリーミングすることです。
リダイレクトも基本的には同じように機能します(ただし、以下の警告を参照してください)。
$cmdOutput = <command> 2>&1 # redirect error stream (2) to success stream (1)
ただし、外部コマンドの場合、以下は期待どおりに機能する可能性が高くなります。
$cmdOutput = cmd /c <command> '2>&1' # Let cmd.exe handle redirection - see below.
外部プログラムに固有の考慮事項:
外部プログラムは、PowerShellの型システムの外部で動作するため、成功ストリーム(stdout)を介してのみ文字列を返します。
出力に複数の行が含まれている場合、PowerShellはデフォルトでそれを文字列の配列に分割します。より正確には、出力行は[System.Object[]]
、要素が文字列([System.String]
)であるタイプの配列に格納されます。
あなたがいる場合、出力になりたい、単一の、潜在的に複数行の文字列を、パイプへOut-String
:
$cmdOutput = <command> | Out-String
stderrをでstdoutにリダイレクトし2>&1
、成功ストリームの一部としてもキャプチャできるようにするには、注意が必要です。
作るために2>&1
マージstdoutとstderrを元に、聞かせてcmd.exe
リダイレクトを処理し、次のイディオムを使用して、:
$cmdOutput = cmd /c <command> '2>&1' # *array* of strings (typically)
$cmdOutput = cmd /c <command> '2>&1' | Out-String # single string
cmd /c
cmd.exe
コマンド<command>
を使用して呼び出し、終了後<command>
に終了します。
- 周りの単一引用符に注意してください
2>&1
。これにより、リダイレクトがcmd.exe
PowerShellによって解釈されるのではなく、確実に渡されます。
関与cmd.exe
とは、 PowerShell独自の要件に加えて、文字のエスケープと環境変数の拡張に関するルールがデフォルトで機能することを意味します。PS v3 +では、特別なパラメーター--%
(いわゆる解析停止記号)を使用して、PowerShellによる残りのパラメーターの解釈をオフにすることができます。ただし、cmd.exe
などの-スタイルの環境変数参照は除きます%PATH%
。
このアプローチでは、ソースでstdoutとstderr をマージしているため、PowerShellでstdoutから発生した行とstderrから発生した行を区別できないことに注意してください。この区別が必要な場合は、PowerShell独自の2>&1
リダイレクトを使用してください-以下を参照してください。
PowerShellの 2>&1
リダイレクトを使用して、どのストリームがどのストリームからのものかを確認します。
stderr出力は文字列ではなくエラーレコード([System.Management.Automation.ErrorRecord]
)としてキャプチャされるため、出力配列には文字列(各文字列はstdout行を表す)とエラーレコード(各レコードはstderr行を表す)の混合が含まれる場合があります。からの要求に応じて2>&1
、文字列とエラーレコードの両方がPowerShellの成功出力ストリームを介して受信されることに注意してください。
コンソールでは、エラーレコードは赤で印刷され、最初のレコードはデフォルトで、コマンドレットの非終了エラーが表示するのと同じ形式で複数行の表示を生成します。後続のエラーレコードも赤で印刷されますが、エラーメッセージは1行でのみ印刷されます。
コンソールに出力する場合、通常、文字列は出力配列の最初に来て、その後にエラーレコードが続きます(少なくとも「同時に」出力されるstdout / stderr行のバッチの間)が、幸い、出力をキャプチャすると、適切にインターリーブされ、なしで得られるのと同じ出力順序を使用します2>&1
。つまり、コンソールに出力する場合、キャプチャされた出力は、stdoutおよびstderr行が外部コマンドによって生成された順序を反映していません。
あなたがいる場合における全体の出力キャプチャする単一の文字列をOut-String
、PowerShellは追加されます余分な行をエラーレコードの文字列表現は、このような場所(などの追加情報が含まれているので、At line:...
)およびカテゴリを(+ CategoryInfo ...
); 奇妙なことに、これは最初のエラーレコードにのみ適用されます。
- この問題を回避するには、適用
.ToString()
の代わりに、配管の各出力オブジェクトのメソッドをOut-String
:
$cmdOutput = <command> 2>&1 | % { $_.ToString() }
;
PS v3 +では、次のように簡略化できます
$cmdOutput = <command> 2>&1 | % ToString
(おまけとして、出力がキャプチャされない場合、コンソールに出力する場合でも、適切にインターリーブされた出力が生成されます)。
また、フィルタエラーが記録されてとしてPowerShellののエラーストリームに送信Write-Error
(出力がキャプチャされていない場合はボーナスとして、これは適切にコンソールに印刷しても、インターリーブ出力を生成します):
$cmdOutput = <command> 2>&1 | ForEach-Object {
if ($_ -is [System.Management.Automation.ErrorRecord]) {
Write-Error $_
} else {
$_
}
}
Start-Process
まず:(定義により)コンソールアプリケーションを同期的に実行するために使用しないでください-他のシェルのように、それらを直接呼び出すだけです。ウィットに:netdom /verify $pc /domain:hosp.uhhg.org
。そうすることで、アプリケーションが呼び出し側コンソールの標準ストリームに接続されたままになり、単純な割り当てでその出力をキャプチャでき$output = netdom ...
ます。以下に示す回答のほとんどStart-Process
は、直接実行を支持することを暗黙のうちに無視しています。