programing

PowerShell의 외부 프로세스에서 출력 데이터를 변수로 캡처하려면 어떻게 해야 합니까?

magicmemo 2023. 4. 21. 20:26
반응형

PowerShell의 외부 프로세스에서 출력 데이터를 변수로 캡처하려면 어떻게 해야 합니까?

외부 프로세스를 실행하여 PowerShell의 변수에 대한 명령 출력을 캡처하고 싶습니다.현재 사용 중입니다.

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

명령이 실행 중인지 확인했지만 출력을 변수로 캡처해야 합니다.즉, -RedirectOutput은 파일로만 리다이렉트되므로 사용할 수 없습니다.

는 ": "를 사용합니다.Start-Process대상 프로그램의 출력을 직접 캡처할 수 없습니다.일반적으로 콘솔 응용 프로그램을 동기적으로 실행하기 위해사용하지 마십시오. 다른 셸과 마찬가지로 직접 실행하기만 하면 됩니다.이렇게 하면 애플리케이션의 출력 스트림이 PowerShell의 스트림에 계속 연결되어 간단한 할당으로 출력을 캡처할 수 있습니다.$output = netdom ... (와)2>stderr 출력의 경우)을 참조하십시오.

기본적으로 외부 프로그램에서 출력캡처하는 것은 PowerShell 네이티브 명령과 동일하게 동작합니다(외부 프로그램 실행 방법에 대한 새로 고침이 필요할 수 있습니다).<command>는, 다음의 유효한 커맨드의 플레이스 홀더입니다).

# IMPORTANT: 
# <command> is a *placeholder* for any valid command; e.g.:
#    $cmdOutput = Get-Date
#    $cmdOutput = attrib.exe +R readonly.txt
$cmdOutput = <command>   # captures the command's success stream / stdout output

:$cmdOutput 는, 복수의 출력 오브젝트를 생성하는 경우, 오브젝트의 배열을 수신합니다.외부 프로그램의 경우는, 프로그램출력 라인을 포함한 문자열[1] 배열을 의미합니다.

결과가 항상 배열인지 확인하려면 하나의 개체만 출력되는 경우에도 변수를 배열로 입력합니다( ).[object[]]를 에 @(...), array-subexpression 연산자:[2]

[array] $cmdOutput = <command>
$cmdOutput = @(<command>)       # alternative

당신이 , 이 원하는 것은, 신면면면면면면면면면 by by by by by?$cmdOutput항상 단일(잠재적으로 여러 행) 문자열을 수신하려면 를 사용합니다.단, 후행의 새 행은 항상 추가됩니다(GitHub 문제 #14444는 이 문제가 있는 동작을 설명합니다).

# Note: Adds a trailing newline.
$cmdOutput = <command> | Out-String

PowerShell에서[1] 문자열만 반환하는 외부 프로그램에 대한 호출에서는 연산자를 대신 사용하면 이러한 문제를 방지할 수 있습니다.

# NO trailing newline.
$cmdOutput = (<command>) -join "`n"

주의: 심플화를 위해 상기의 용도는 다음과 같습니다."`n"이 모든 Unix 의 LF 전용 회선을 작성하려면 새)이 Unix LF를 하십시오.Windows CRLF, Unix LF, LF, LF,[Environment]::NewLine★★★★★★ 。


변수에 출력을 캡처하여 화면에 인쇄하려면:

<command> | Tee-Object -Variable cmdOutput # Note how the var name is NOT $-prefixed

「 」의 경우는,<command>cmdlet 또는 고급 함수입니다.공통
파라미터 / : 를 사용할 수 있습니다.

<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은 기본적으로 표현 모드에서 따옴표로 시작하는 문자열을 구문 분석하지만, 인수 모드는 명령어(cmdlets, 외부 프로그램, 함수, 별칭)를 호출하기 위해 필요합니다.&증합니니다다

「 」의 $(...) ★★★★★★★★★★★★★★★★★」& { ... }. { ... }전자는 전체를 반환하기 전에 모든 입력을 메모리에 수집하는 반면 후자는 출력을 스트리밍하여 하나씩 파이프라인 처리에 적합합니다.


리다이렉트도 기본적으로 동일하게 기능합니다(다만, 다음의 경고를 참조해 주세요).

$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은 파이프라인을 [1]통해 외부 프로그램에만 문자열을 보냅니다.

    • 따라서 문자 인코딩 문제가 발생할 수 있습니다.
      • 파이프라인을 통해 외부 프로그램으로 데이터를 전송할 때 PowerShell은 에 저장된 인코딩을 사용합니다.$OutVariable 변수에서는 ASCII로, PowerShell 되어 있습니다.Windows PowerShell에서는 ASCII(!)로 설정되며 PowerShell [Core]에서는 UTF-8로 설정됩니다.

      • PowerShell은 외부 프로그램으로부터 데이터를 수신할 때 에 저장된 인코딩을 사용합니다.[Console]::OutputEncoding두 PowerShell 에디션 모두 기본적으로 시스템의 활성 OEM 코드 페이지가 됩니다.

      • 상세한 것에 대하여는, 회답을 참조해 주세요. 회답에서는, 시스템 전체의 ANSI 및 OEM 코드 페이지로서 UTF-8 를 설정할 수 있는 Windows 10 의 미사용 기능에 대해 설명합니다.

  • 출력에 여러 행이 포함되어 있는 경우 PowerShell은 기본적으로 해당 행을 문자열 배열로 나눕니다.보다 정확하게는 출력 라인이 하나씩 스트리밍되고 캡처되면 유형 배열에 저장됩니다.[System.Object[]]그)[System.String]를 참조해 주세요.

  • 출력1 행 또는 복수의 행으로 하는 경우는,-join로 접속할 수도 ).Out-String, 의 줄바꿈이
    $cmdOutput = (<command>) -join [Environment]::NewLine

  • 성공 스트림의 일부로 stderr을 캡처하기 위해 stdout에 stderr을 Marge하면 다음과 같은 주의필요합니다.

    • 이것소스에서 실시하려면 , 다음의 어구를 사용해 리다이렉션을 처리해 주세요(와 유사하게 동작합니다.shUnix ( ) :
      $cmdOutput = cmd /c <command> '2>&1' # *array* of strings (typically)
      $cmdOutput = (cmd /c <command> '2>&1') -join "`r`n" # single string

      • cmd /ccmd.exe 「」를 지정해 주세요.<command> 그 뒤에 거예요.<command>을 사용하다

      • 「 」의 주위에 작은 있는 에 주의해 .2>&1 '접근하다'로 cmd.exePowerShell power power power power 。

      • 「」가 포함되는 것에 .cmd.exePowerShell 자체 요건과 더불어 문자 이스케이프 및 환경변수 확장 규칙이 기본적으로 적용됩니다.PS v3+에서는 특수한 파라미터를 사용할 수 있습니다.--%(이른바 정지 기호) PowerShell에 의한 나머지 파라미터의 해석을 비활성화합니다(단,cmd.exe%PATH%.

      • 이 접근 방식에서는 소스의 stdout과 stderr을 병합하기 때문에 PowerShell에서 stdout과 stderr에서 시작하는 행을 구분할 수 없습니다. 이 구별이 필요한 경우 PowerShell의 고유 라인을 사용하십시오.2>&1리다이렉트 - 아래를 참조하십시오.

    • PowerShell의 리디렉션을 사용하여 어떤 행이 어떤 스트림에서 왔는지 알 수 있습니다.

      • Stderr 출력은 오류 레코드로 캡처됩니다([System.Management.Automation.ErrorRecord]문자열이 아니기 때문에 출력 배열에는 문자열(stdout 회선을 나타내는문자열)과 에러 레코드(stderr 회선을 나타내는 각 레코드)가 혼재하는 경우가 있습니다.이 점에 주의해 주십시오.2>&1문자열과 오류 레코드는 모두 PowerShell의 성공 출력 스트림을 통해 수신됩니다).

      • 주의: 다음은 Windows PowerShell에만 적용됩니다.이러한 문제는 PowerShell [Core]v6+에서 수정되었습니다.다만, 오브젝트 타입에 의한 필터링 기술은 다음과 같습니다( )$_ -is [System.Management.Automation.ErrorRecord]도.)도 도움이 됩니다.

      • 콘솔에서 오류 레코드는 빨간색으로 인쇄되며 기본적으로는 첫 번째 레코드는 cmdlet의 종료되지 않은 오류가 표시되는 것과 동일한 형식으로 여러 줄 표시됩니다.이후 오류 레코드는 빨간색으로 인쇄되지만 오류 메시지는 한 줄에만 인쇄됩니다.

      • 콘솔에 출력할 때 일반적으로 문자열은 출력 배열의 선두에 있고 오류 레코드(적어도 "동시에" 출력되는 stdout/stderr 행의 배치 중 하나)가 이어집니다.다만, 다행히 출력을 캡처는, 같은 출력 순서를 사용해 인터리브 됩니다.2>&1즉, 콘솔출력할 때 캡처된 출력에는 외부 명령에 의해 stdoutstderr 행이 생성된 순서가 반영되지 않습니다.

      • 에러 레코드의 문자열 표시에 위치 등의 정보가 포함되어 있기 때문에 출력 전체를 1개의 문자열로 캡처하면 PowerShell에 행이 추가됩니다.At line:... 「 」)+ CategoryInfo ...이상하게도 이것은 첫 번째 에러 레코드에만 적용됩니다.

        • 하려면 , 「」를 적용합니다..ToString() 각 출력 Out-String:
          $cmdOutput = <command> 2>&1 | % { $_.ToString() };
          PS v3+ 、 음음음 ps 、 ps ps ps ps ps ps ps ps ps 。
          $cmdOutput = <command> 2>&1 | % ToString
          (보너스로 출력이 캡처되지 않으면 콘솔에 인쇄할 때에도 올바르게 인터리브 출력이 생성됩니다.)

        • 또는 에러 레코드필터링하여 PowerShell의 에러 스트림으로 전송합니다(보너스로 출력이 캡처되지 않으면 콘솔로 인쇄할 때에도 올바르게 인터리브된 출력이 생성됩니다).

$cmdOutput = <command> 2>&1 | ForEach-Object {
  if ($_ -is [System.Management.Automation.ErrorRecord]) {
    Write-Error $_
  } else {
    $_
  }
}

PowerShell 7.2.x에서는 별도re-인수 전달:

  • 포함된 문자열 인수 및 인수와 관련하여 외부 프로그램에 인수를 전달하는 작업이 중단되었습니다. "★★★★★★ 。

  • 실행 의 (비표준)는 (입니다.msiexec.exe배치 파일이 수용되지 않습니다.

앞의 문제에 대해서만 이 답변에서 설명한 바와 같이 수정이 이루어질 수 있습니다(Unix와 유사한 플랫폼에서는 수정이 완료되지만). 이 답변에서는 현재의 모든 문제와 해결 방법이 상세하게 설명되어 있습니다.

서드파티제 모듈 설치가 옵션인 경우ie모듈로부터 기능합니다(Install-Module Native)는 포괄적인 솔루션을 제공합니다.


[1] PowerShell 7.1 이후 PowerShell은 외부 프로그램과 통신할 때 문자열인식합니다.PowerShell 파이프라인에는 일반적으로 원시 바이트 데이터의 개념이 없습니다.외부 프로그램에서 원시 바이트 데이터를 반환하려면 다음 명령을 수행해야 합니다.cmd.exe /c (Windows) ★★sh -c(Unix) 해당 파일에 저장한 후 PowerShell에서 해당 파일을 읽습니다.상세한 것에 대하여는, 회답을 참조해 주세요.

[2] 두 가지 접근 방식(결합할 수 있음)에는 미묘한 차이가 있지만, 일반적으로는 문제가 되지 않습니다.명령어에 출력이 없는 경우[array]type-constraint 접근법은 대상 변수에 저장되는 반면, 다음과 같은 경우 [object[]빈() 배열입니다.@(...) 「 」는,[array]type contraint는 동일한 변수에 대한 향후(빈칸이 아닌) 할당도 배열로 강제됨을 의미합니다.

시도해 보셨습니까?

$OutputVariable = (Shell command) | Out-String

에러 출력도 리다이렉트 하려면 , 다음의 조작을 실시할 필요가 있습니다.

$cmdOutput = command 2>&1

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

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

아니면 이거 먹어봐.출력을 변수 $scriptOutput으로 캡처합니다.

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

$scriptOutput

또 다른 실제 예는 다음과 같습니다.

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

이 예에는 환경변수로 시작하는 경로가 포함되어 있습니다.따옴표는 경로와 EXE 파일을 둘러싸야 하지만 매개 변수를 둘러싸서는 안 됩니다.

주의: 잊지 마십시오.&명령어 앞에 있는 문자가 따옴표 밖에 있습니다.

에러 출력도 수집됩니다.

이 조합이 작동하는데 시간이 좀 걸려서 공유하려고 했어요.

나는 답을 시도했지만, 나의 경우는 미가공의 결과를 얻지 못했다.대신 PowerShell 예외로 변환되었습니다.

실제 결과는 다음과 같습니다.

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

나는 다음과 같은 일을 한다.

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

$result는 필요한 기능을 제공합니다.

다음을 사용합니다.

Function GetProgramOutput([string]$exe, [string]$arguments)
{
    $process = New-Object -TypeName System.Diagnostics.Process
    $process.StartInfo.FileName = $exe
    $process.StartInfo.Arguments = $arguments
    
    $process.StartInfo.UseShellExecute = $false
    $process.StartInfo.RedirectStandardOutput = $true
    $process.StartInfo.RedirectStandardError = $true
    $process.Start()
    
    $output = $process.StandardOutput.ReadToEnd()   
    $err = $process.StandardError.ReadToEnd()
    
    $process.WaitForExit()
    
    $output
    $err
}
    
$exe = "C:\Program Files\7-Zip\7z.exe"
$arguments = "i"
    
$runResult = (GetProgramOutput $exe $arguments)
$stdout = $runResult[-2]
$stderr = $runResult[-1]
    
[System.Console]::WriteLine("Standard out: " + $stdout)
[System.Console]::WriteLine("Standard error: " + $stderr)

이건 나한테 효과가 있었어

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

명령어 출력만 캡처하면 됩니다.

합니다.[timezoneinfo]::local는 시스템을 변경한 에도 항상 동일한 정보를 생성합니다.시간대 변경을 확인하고 기록할 수 있는 유일한 방법은 다음과 같습니다.

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

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

외부 명령어를 사용할 때, 그리고 명령어를 실행한 결과(또는 명령어가 혼재된 경우)에 표준 오류 스트림과 표준 출력 스트림이 모두 사용될 수 있는 경우에는 다음과 같은 이점이 있습니다.

$output = (command 2>&1)

언급URL : https://stackoverflow.com/questions/8097354/how-do-i-capture-the-output-into-a-variable-from-an-external-process-in-powershe

반응형