PowerShell의 외부 프로세스에서 변수로 출력을 어떻게 캡처합니까?


158

외부 프로세스를 실행하고 PowerShell의 변수에 대한 명령 출력을 캡처하고 싶습니다. 나는 현재 이것을 사용하고있다 :

$params = "/verify $pc /domain:hosp.uhhg.org"
start-process "netdom.exe" $params -WindowStyle Hidden -Wait

명령이 실행되고 있음을 확인했지만 출력을 변수로 캡처해야합니다. 이것은 파일로만 리디렉션되기 때문에 -RedirectOutput을 사용할 수 없음을 의미합니다.


3
무엇보다도 : (외부 적으로) 콘솔 애플리케이션을 동기식으로 실행 하는 Start-Process데 사용하지 마십시오 . 쉘에서와 같이 직접 실행 하십시오. 재치 : netdom /verify $pc /domain:hosp.uhhg.org. 이렇게하면 응용 프로그램이 호출 콘솔의 표준 스트림에 연결되어 유지되므로 간단한 할당으로 출력을 캡처 할 수 있습니다 $output = netdom .... 아래에 주어진 대부분의 답변은 암시 적 Start-Process으로 직접 실행을 선호합니다.
mklement0

-Credential매개 변수 를 사용하려는 경우를 제외하고 @ mklement0
CJBS

@CJBS 예, 실행하기 위해 다른 사용자 ID 의 사용을 Start-Process필수입니다 -하지만 다음 (당신은 별도의 창에서 명령을 실행하려는 경우). 그리고 하나는이 경우에 피할 수없는 한계를 알고 있어야 제외하고 캡처 출력 없음 능력, - 비 인터리브 - 텍스트 에서 파일 을 통해 -RedirectStandardOutput하고 -RedirectStandardError.
mklement0

답변:


161

시도해 보셨습니까?

$OutputVariable = (Shell command) | Out-String


"="를 사용하여 변수에 할당하려고했지만 먼저 출력을 Out-String으로 파이프하려고하지 않았습니다. 시도해 볼게요.
Adam Bertram

10
나는 여기서 무슨 일이 일어나고 있는지 이해하지 못하고 제대로 작동하지 않습니다. "쉘"이 파워 쉘 키워드입니까? 실제로 Start-Process cmdlet을 사용하지 않습니까? 구체적인 예를 들어 주시겠습니까 (예 : "쉘"및 / 또는 "명령"을 실제 예로 바꾸십시오).
deadlydog

@deadlydog Shell Command실행하려는 모든 것으로 바꿉니다 . 그렇게 간단합니다.
JNK

1
@ stej, 당신이 맞아요. 귀하의 의견의 코드가 답변의 코드와 다른 기능을 가지고 있음을 주로 밝혔습니다. 나와 같은 초보자는 이와 같은 행동의 미묘한 차이로 버릴 수 있습니다!
Sam

1
@ Atique 나는 같은 문제에 부딪쳤다. 예를 들어 -i출력 파일을 지정하지 않고 옵션 을 사용하는 경우 ffmpeg가 stdout 대신 stderr에 쓰는 경우가 있습니다. 2>&1다른 답변 중 일부에 설명 된대로 출력을 리디렉션하는 것이 해결책입니다.
jmbpiano

159

참고 : 질문의 명령은을 사용 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>A는 cmdlet을 또는 고급 기능, 당신이 사용할 수있는 공통 매개 변수를
-OutVariable/-ov
:

<command> -OutVariable cmdOutput   # cmdlets and advanced functions only

와 그주의 -OutVariable다른 시나리오에서, 달리 $cmdOutput입니다 항상 수집 에만하더라도, 하나의 객체가 출력됩니다. 특히, 배열과 같은 [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을 기본적으로 표현식 모드 에서 따옴표로 묶인 문자열로 시작하는 명령문을 구문 분석 하지만 인수 모드 는 명령 (cmdlet, 외부 프로그램, 함수, 별명)을 호출하는 데 필요합니다.& 합니다.

$(...)& { ... }/ 사이의 주요 차이점 . { ... }은 전자 가 전체 입력을 반환하기 전에 메모리의 모든 입력을 수집하는 반면, 후자 는 1 대 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

  • 2>&1성공 스트림의 일부로 캡처하기 위해 stderr를 stdout으로 리디렉션 하면 다음과 같은 경고있습니다 .

    • 하려면 2>&1병합 표준 출력과 표준 에러를 소스에서 , 하자 cmd.exe리디렉션을 처리하는 다음과 같은 관용구를 사용하여 :
      $cmdOutput = cmd /c <command> '2>&1' # *array* of strings (typically)
      $cmdOutput = cmd /c <command> '2>&1' | Out-String # single string

      • cmd /ccmd.exe명령으로 호출 하고 <command>이후에 종료<command> 완료되었습니다.
      • 주위에 작은 따옴표 2>&1를 사용하면 리디렉션이 전달됩니다.cmd.exe PowerShell에서 해석하지 않고 .
      • 포함 cmd.exe한다는 것은 기본적으로 PowerShell 자체 요구 사항 외에도 캐릭터를 이스케이프하고 환경 변수를 확장 하는 규칙이 적용됨 을 의미합니다 . PS v3 +에서는 특수 매개 변수 --%(소위 중지 구문 분석 기호 )를 사용하여 cmd.exe와 같은 스타일 환경 변수 참조를 제외하고 PowerShell에 의해 나머지 매개 변수의 해석을 해제 할 수 %PATH%있습니다.

      • 이 접근 방식으로 소스에서 stdout과 stderr 병합하므로 PowerShell에서 stdout-originated 라인과 stderr-originated 라인을 구별 할 수 없습니다 . 이 구분이 필요한 경우 PowerShell 자체 2>&1리디렉션을 사용 하십시오 (아래 참조).

    • PowerShell의 2>&1 리디렉션을 사용 하여 어떤 스트림에서 어떤 라인이 나왔는지 알 수 있습니다 .

      • STDERR 출력으로 캡처 오류 기록 ( [System.Management.Automation.ErrorRecord]소위)가 아닌 문자열 출력 어레이가 포함될 수 믹스문자열 과 (a 표준 출력 라인 각각 나타내는 문자열) 오류 기록 (a 열려진 행을 나타내는 각 레코드) . 에서 요청한대로 2>&1문자열과 오류 레코드는 PowerShell의 성공 출력 스트림을 통해 수신됩니다 ).

      • 콘솔에서 오류 기록에 인쇄 빨간색 , 그리고 1 기본적으로 하나의 생산 멀티 라인 cmdlet에의 종료되지 않는 오류가 표시 것 같은 형식으로 표시; 후속 오류 레코드도 빨간색으로 인쇄되지만 오류 메시지한 줄 에 인쇄 됩니다 .

      • 콘솔에 출력 때 문자열은 일반적으로 출력 배열에서 가장 먼저 나오고 그 뒤에 오류 레코드 (적어도 "동시에"stdout / stderr 출력 일괄 처리 중)가옵니다. 그러나 다행히도 출력 캡처 할 때 , 그것 없이 얻을 수있는 것과 같은 출력 순서를 사용하여 올바르게 인터리브된다2>&1 ; 다시 말해 , 콘솔로 출력 할 때 캡처 된 출력은 외부 명령에 의해 stdout 및 stderr 행이 생성 된 순서를 반영하지 않습니다.

      • 이 경우 A의 전체 출력 캡처 하나 와 문자열을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 {
    $_
  }
}

실행 경로와 인수를 가져 와서 문자열로 던져서 <command>로 처리 한 후에 결국에는 효과가있었습니다.
Dan

2
@Dan : PowerShell을 자체 해석 할 때 <command>, 당신은 하나의 문자열의 실행 및 인수를 결합; 호출을 통해 그렇게 cmd /c 있으며 상황에 따라 상황에 따라 다릅니다. 어떤 시나리오를 언급하고 있으며 최소한의 예를들 수 있습니까?
mklement0

작품 : $ 명령 = "C : \ mycommand.exe"+ $ 인수 ..... $ 출력 = cmd를 / C $ 명령 '2> & 1'

1
@ Dan : 예, 작동하지만 +연산자 를 사용하여 문자열의 중간 변수와 명시 적 구성이 필요하지 않습니다 . 다음도 작동합니다. cmd /c c:\mycommand.exe $Args '2>&1'-PowerShell은이 경우 요소를 $Args공백으로 구분 된 문자열 ( splatting 이라는 기능)로 전달합니다 .
mklement0

마지막으로 PS6.1 +에서 작동하는 정답입니다. 소스의 비밀은 실제로 '2>&1'부분이며 ()많은 스크립트가하는 경향이 있습니다.
not2qubit

24

오류 출력을 리디렉션하려면 다음을 수행해야합니다.

$cmdOutput = command 2>&1

또는 프로그램 이름에 공백이있는 경우 :

$cmdOutput = & "command with spaces" 2>&1

4
2> & 1은 무슨 뜻인가요? '2라는 명령을 실행하고 출력을 1이라는 명령에 넣습니다'?
Richard

7
"표준 오류 출력 (파일 설명자 2)을 표준 출력 (파일 설명자 1)이있는 곳으로 리디렉션합니다"를 의미합니다. 기본적으로 정상 및 오류 메시지를 동일한 위치로 리디렉션합니다 (이 경우 stdout이 파일과 같이 다른 곳으로 리디렉션되지 않으면 콘솔).
Giovanni Tirloni

11

아니면 이것을 시도하십시오. 출력을 변수 $ scriptOutput으로 캡처합니다.

& "netdom.exe" $params | Tee-Object -Variable scriptOutput | Out-Null

$scriptOutput

7
-1, 불필요하게 복잡합니다. $scriptOutput = & "netdom.exe" $params
CharlesB

8
널을 제거하면 쉘과 변수를 동시에 배관 할 때 좋습니다.
ferventcoder

10

또 다른 실제 예 :

$result = & "$env:cust_tls_store\Tools\WDK\x64\devcon.exe" enable $strHwid 2>&1 | Out-String

이 예에는 경로 (환경 변수로 시작)가 포함되어 있습니다. 따옴표는 경로와 EXE 파일을 둘러싸 야하지만 매개 변수는 포함하지 않아야합니다!

참고 :& 명령 앞의 문자를 잊지 말고 따옴표 외부의 문자를 잊지 마십시오 .

오류 출력도 수집됩니다.

이 조합을 작동시키는 데 시간이 걸렸으므로 공유하기로 생각했습니다.


8

나는 대답을 시도했지만 내 경우에는 원시 출력을 얻지 못했습니다. 대신 PowerShell 예외로 변환되었습니다.

내가 얻은 원시 결과 :

$rawOutput = (cmd /c <command> 2`>`&1)

2

나는 다음을 작동시켰다.

$Command1="C:\\ProgramData\Amazon\Tools\ebsnvme-id.exe"
$result = & invoke-Expression $Command1 | Out-String

$ result 는 당신에게 필요한 것을 제공합니다


1

이 일은 나를 위해 일했다 :

$scriptOutput = (cmd /s /c $FilePath $ArgumentList)

0

명령에서 출력을 캡처하는 것만으로도 제대로 작동합니다.

시스템을 변경 한 후에도[timezoneinfo]::local 항상 동일한 정보를 생성하므로 시스템 시간을 변경하는 데 사용합니다 . 이것이 시간대 변경 사항을 확인하고 기록 할 수있는 유일한 방법입니다.

$NewTime = (powershell.exe -command [timezoneinfo]::local)
$NewTime | Tee-Object -FilePath $strLFpath\$strLFName -Append

시스템 변수를 다시로드하려면 새 PowerShell 세션을 열어야 함을 의미 합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.