Private/Start-ConsoleProcess.ps1
<#
.Synopsis Launch console process, pipe strings to its StandardInput and get resulting StandardOutput/StandardError streams and exit code. .Description This function will start console executable, pipe any user-specified strings to it and capture StandardOutput/StandardError streams and exit code. It returns object with following properties: StdOut - array of strings captured from StandardOutput StdErr - array of strings captured from StandardError ExitCode - exit code set by executable .Parameter FilePath Path to the executable or its name. .Parameter ArgumentList Array of arguments for the executable. Passing arguments as an array allows to run even such unfriendly applications as robocopy. .Parameter InputObject Array of strings to be piped to the executable's StandardInput. This allows you to execute commands in interactive sessions of netsh and diskpart. .Example Start-ConsoleProcess -FilePath find Start find.exe and capture its output. Because no arguments specified, find.exe prints error to StandardError stream, which is captured by the function: StdOut StdErr ExitCode ------ ------ -------- {} {FIND: Parameter format not correct} 2 .Example 'aaa', 'bbb', 'ccc' | Start-ConsoleProcess -FilePath find -ArgumentList '"aaa"' Start find.exe, pipe strings to its StandardInput and capture its output. Find.exe will attempt to find string "aaa" in StandardInput stream and print matches to StandardOutput stream, which is captured by the function: StdOut StdErr ExitCode ------ ------ -------- {aaa} {} 0 .Example 'list disk', 'list volume' | Start-ConsoleProcess -FilePath diskpart Start diskpart.exe, pipe string to its StandardInput and capture its output. Diskpart.exe will accept piped strings as if they were typed in the interactive session and list all disks and volumes on the PC. Note that running diskpart requires already elevated PowerShell console. Otherwise, you will recieve elevation request and diskpart will run, however, no strings would be piped to it. Example: PS > $Result = 'list disk', 'list volume' | Start-ConsoleProcess -FilePath diskpart PS > $Result.StdOut Microsoft DiskPart version 6.3.9600 Copyright (C) 1999-2013 Microsoft Corporation. On computer: HAL9000 DISKPART> Disk ### Status Size Free Dyn Gpt -------- ------------- ------- ------- --- --- Disk 0 Online 298 GB 0 B DISKPART> Volume ### Ltr Label Fs Type Size Status Info ---------- --- ----------- ----- ---------- ------- --------- -------- Volume 0 E DVD-ROM 0 B No Media Volume 1 C System NTFS Partition 100 GB Healthy System Volume 2 D Storage NTFS Partition 198 GB Healthy DISKPART> .Example Start-ConsoleProcess -FilePath robocopy -ArgumentList 'C:\Src', 'C:\Dst', '/mir' Start robocopy.exe with arguments and capture its output. Robocopy.exe will mirror contents of the 'C:\Src' folder to 'C:\Dst' and print log to StandardOutput stream, which is captured by the function. Example: PS > $Result = Start-ConsoleProcess -FilePath robocopy -ArgumentList 'C:\Src', 'C:\Dst', '/mir' PS > $Result.StdOut ------------------------------------------------------------------------------- ROBOCOPY :: Robust File Copy for Windows ------------------------------------------------------------------------------- Started : 01 January 2016 y. 00:00:01 Source : C:\Src\ Dest : C:\Dst\ Files : *.* Options : *.* /S /E /DCOPY:DA /COPY:DAT /PURGE /MIR /R:1000000 /W:30 ------------------------------------------------------------------------------ 1 C:\Src\ New File 6 Readme.txt 0% 100% ------------------------------------------------------------------------------ Total Copied Skipped Mismatch FAILED Extras Dirs : 1 0 0 0 0 0 Files : 1 1 0 0 0 0 Bytes : 6 6 0 0 0 0 Times : 0:00:00 0:00:00 0:00:00 0:00:00 Speed : 103 Bytes/sec. Speed : 0.005 MegaBytes/min. Ended : 01 January 2016 y. 00:00:01 #> function Start-ConsoleProcess { Param ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [string]$FilePath, [string[]]$ArgumentList, [Parameter(ValueFromPipeline = $true)] [string[]]$InputObject ) End { if($Input) { # Collect all pipeline input # http://www.powertheshell.com/input_psv3/ $StdIn = @($Input) } else { $StdIn = $InputObject } try { "Starting process: $FilePath", "Redirect StdIn: $([bool]$StdIn.Count)", "Arguments: $ArgumentList" | Write-Verbose if($StdIn.Count) { $Output = $StdIn | & $FilePath $ArgumentList 2>&1 } else { $Output = & $FilePath $ArgumentList 2>&1 } } catch { throw $_ } Write-Verbose 'Finished, processing output' $StdOut = New-Object -TypeName System.Collections.Generic.List``1[String] $StdErr = New-Object -TypeName System.Collections.Generic.List``1[String] foreach($item in $Output) { # Data from StdOut will be strings, while StdErr produces # System.Management.Automation.ErrorRecord objects. # http://stackoverflow.com/a/33002914/4424236 if($item.Exception.Message) { $StdErr.Add($item.Exception.Message) } else { $StdOut.Add($item) } } Write-Verbose 'Returning result' New-Object -TypeName PSCustomObject -Property @{ ExitCode = $LASTEXITCODE StdOut = $StdOut.ToArray() StdErr = $StdErr.ToArray() } | Select-Object -Property StdOut, StdErr, ExitCode } } |