Created
December 6, 2017 23:39
-
-
Save Jaykul/a6c935a536eae88aacc4b88049094b9c to your computer and use it in GitHub Desktop.
Like Start-Process, but without files
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function Invoke-Process { | |
<# | |
.SYNOPSIS | |
Invokes a process, collecting the output | |
.DESCRIPTION | |
Invokes the process of the executable that is passed in using the command line arguments that are passed in | |
.EXAMPLE | |
Invoke-Process "C:\Program Files\7-Zip\7z.exe" 'x C:\temp -oC:\temp\path' | |
Invokes 7zip with the x (extract) option, a path, and the -o (output) path | |
.LINK | |
Start-Process | |
#> | |
[CmdletBinding()] | |
[OutputType([System.Diagnostics.Process], [String])] | |
param( | |
# Full path to the process exe | |
[Parameter(Mandatory, Position = 0)] | |
[ValidateNotNullOrEmpty()] | |
[ValidateScript( {Get-Command $_ -ErrorAction Stop; $True})] | |
[Alias("PSPath", "FilePath")] | |
[string]$ExePath, | |
# Run processes in the current window | |
[switch]$NoNewWindow, | |
# Output the process object INSTEAD OF its output | |
# If set, you are responsible to read the StandardInput and StandardError streams | |
[switch]$Passthru, | |
# Waits for the process to exit before continuing | |
[int32]$TimeOut = [int32]::MaxValue, | |
# The working directory to run the process in (defaults to PowerShell's current FileSystem location) | |
[string]$WorkingDirectory = $((Get-Location -PSProvider FileSystem).Path), | |
# Command Line Arguments | |
[Parameter(ValueFromRemainingArguments)] | |
[ValidateNotNullOrEmpty()] | |
[string[]]$Arguments | |
) | |
# Future Work: Add a way to pass strings for the StandardInput stream | |
# Add a way to specify exit codes that are acceptable | |
# Make the event handlers stream output to the console | |
$StartInfo = [System.Diagnostics.ProcessStartInfo]$ExePath | |
$StartInfo.CreateNoWindow = $NoNewWindow | |
$StartInfo.RedirectStandardError = $true | |
$StartInfo.RedirectStandardOutput = $true | |
$StartInfo.WorkingDirectory = $WorkingDirectory | |
$StartInfo.Arguments = $Arguments -join " " | |
$StartInfo.UseShellExecute = $false | |
$Process = [System.Diagnostics.Process]::new() | |
$Process.StartInfo = $StartInfo | |
$null = Register-ObjectEvent -InputObject $Process -EventName OutputDataReceived -Action {if ($EventArgs.Data) {[String[]]$Event.MessageData += $EventArgs.Data}} -MessageData $ProcessOutput | |
$null = Register-ObjectEvent -InputObject $Process -EventName ErrorDataReceived -Action {if ($EventArgs.Data) {[String[]]$Event.MessageData += $EventArgs.Data}} -MessageData $ProcessErrors | |
$Process.Start() | Out-Null | |
$Process.BeginOutputReadLine() | |
$Process.BeginErrorReadLine() | |
if (-not $Process.WaitForExit($TimeOut)) { | |
Write-Error "Process [$($ExePath)] has timed out after [$([TimeSpan]::FromMilliseconds($TimeOut))]" | |
} | |
if ($Passthru) { | |
$Process | |
if ($Process.ExitCode -ne 0) { | |
Write-Error "'$($ExePath) $($Arguments -join " ")' returned $($Process.ExitCode)." | |
} | |
return | |
} | |
# Normalize empty lines to only have one empty line together | |
$ProcessOutput -replace "[\r\n]{3,}", "`n`n" -split "\r?\n" | |
if ($ProcessErrors) { | |
# In errors write one error for each block of lines in a message | |
foreach ($message in $ProcessErrors -replace "[\r\n]{3,}", "`n`n" -split "\r?\n[\r\n]+") { | |
Write-Error "$($ExePath): $($message)" | |
} | |
} | |
if ($Process.ExitCode -ne 0) { | |
Write-Error "'$($ExePath) $($Arguments -join " ")' returned $($Process.ExitCode)." | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment