Created
January 28, 2026 20:31
-
-
Save trackd/25a1f74167fe4a4a76f0db04d60d1914 to your computer and use it in GitHub Desktop.
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 { | |
| <# | |
| .DESCRIPTION | |
| Starts a new process and captures its output, error, and exit code. | |
| redirects output and error streams for capturing. | |
| doesnt require redirecting to files like Start-Process. | |
| caveat is you cannot get a window and redirected output at the same time. | |
| for that you need to use Start-Process | |
| .PARAMETER Process | |
| The name or path of the process to start. | |
| .PARAMETER Arguments | |
| The arguments to pass to the process as strings. | |
| .PARAMETER ScriptBlock | |
| A script block to execute. | |
| .EXAMPLE | |
| Invoke-Process pwsh { $env:WT_SESSION } | |
| Invoke-Process pwsh '[bool]$env:WT_SESSION' | |
| Invoke-Process cmd '/c ping localhost -n 1' | |
| .NOTES | |
| some weird quote handling may be required depending on the process being started. | |
| Invoke-Process cmd '/c echo Hello, World!' | |
| => Hello, World!" <- with the extra quote at the end. | |
| #> | |
| [cmdletbinding(DefaultParameterSetName = 'ByString')] | |
| param( | |
| [Parameter(Mandatory, Position = 0)] | |
| [string] $Process, | |
| [Parameter(ParameterSetName = 'ByString', Position = 1)] | |
| [string[]] $Arguments, | |
| [Parameter(ParameterSetName = 'ByScriptBlock', Position = 1)] | |
| [Scriptblock] $ScriptBlock, | |
| [Switch] $ShowWindow | |
| ) | |
| try { | |
| if ($Process -match 'powershell|pwsh' -or $ScriptBlock) { | |
| $Arguments = @( | |
| '-NoProfile' | |
| '-EncodedCommand' | |
| if ($ScriptBlock) { | |
| [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($ScriptBlock.ToString())) | |
| } | |
| else { | |
| [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($Arguments)) | |
| } | |
| ) | |
| } | |
| # wire up process | |
| $psi = [Diagnostics.ProcessStartInfo]::new($Process, $Arguments) | |
| if ($ShowWindow) { | |
| # we cannot redirect output when showing window.. | |
| $psi.UseShellExecute = $true | |
| $psi.CreateNoWindow = $false | |
| $psi.RedirectStandardOutput = $false | |
| $psi.RedirectStandardError = $false | |
| $proc = [Diagnostics.Process]::Start($psi) | |
| # $proc.WaitForExit() | |
| return | |
| } | |
| $psi.UseShellExecute = $false | |
| $psi.RedirectStandardOutput = $true | |
| $psi.RedirectStandardError = $true | |
| $psi.CreateNoWindow = $true | |
| $psi.StandardErrorEncoding = $psi.StandardOutputEncoding = $OutputEncoding | |
| $proc = [Diagnostics.Process]::Start($psi) | |
| # read output and error | |
| $cmdline = $proc.CommandLine | |
| $RedirectedOutput = $proc.StandardOutput.ReadToEnd() | |
| $RedirectedError = $proc.StandardError.ReadToEnd() | |
| $proc.WaitForExit() | |
| [PSCustomObject]@{ | |
| ExitCode = $proc.ExitCode | |
| Output = $RedirectedOutput.Trim() | |
| Errors = $RedirectedError.Trim() | |
| CommandLine = $cmdline | |
| } | |
| } | |
| catch { | |
| Write-Error $_ | |
| } | |
| finally { | |
| if ($proc) { | |
| $proc.Dispose() | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment