functions/powershell/Invoke-PowerShell.ps1
function Invoke-PowerShell { <# .SYNOPSIS Executes a script block in a specified version of PowerShell (5.1 or 7). .DESCRIPTION This function runs the provided script block in a new PowerShell instance of the specified version. It captures both the output and the exit code of the called PowerShell process. Useful for testing or cross-version script execution scenarios. .PARAMETER Command The script block to be executed in the target PowerShell version. .PARAMETER TargetVersion The version of PowerShell to use for execution. Supported values are 5 (Windows PowerShell 5.1) or 7 (PowerShell 7). .OUTPUTS [pscustomobject] with the following properties: - Output : The standard output of the command. - ExitCode : The exit code of the PowerShell process. .EXAMPLE Invoke-PowerShell -Command { Get-Process } -TargetVersion 7 .EXAMPLE Invoke-PowerShell -Command { Write-Error "Something failed" } -TargetVersion 5 .NOTES PowerShell 7 must be installed in "C:\Program Files\PowerShell\7\" to use version 7. Windows PowerShell 5.1 is assumed to be located in the system path. #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [scriptblock]$Command, [Parameter(Mandatory = $true)] [ValidateSet(5, 7)] [int]$TargetVersion ) $commandString = $Command.ToString() $tempFile = [System.IO.Path]::GetTempFileName() + ".ps1" [System.IO.File]::WriteAllText($tempFile, $commandString) try { $exePath = switch ($TargetVersion) { 7 { "C:\Program Files\PowerShell\7\pwsh.exe" } 5 { "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" } } if (-not (Test-Path $exePath)) { throw "PowerShell $TargetVersion not found at '$exePath'." } Write-Verbose "[$((Get-Date).ToString('HH:mm:ss'))] Running script in PowerShell $TargetVersion..." $startInfo = New-Object System.Diagnostics.ProcessStartInfo $startInfo.FileName = $exePath $startInfo.Arguments = "-NoLogo -NoProfile -ExecutionPolicy Bypass -File `"$tempFile`"" $startInfo.RedirectStandardOutput = $true $startInfo.RedirectStandardError = $true $startInfo.UseShellExecute = $false $startInfo.CreateNoWindow = $true $process = New-Object System.Diagnostics.Process $process.StartInfo = $startInfo $null = $process.Start() $stdOut = $process.StandardOutput.ReadToEnd() $stdErr = $process.StandardError.ReadToEnd() $process.WaitForExit() $exitCode = $process.ExitCode if ($stdErr) { Write-Verbose "[$((Get-Date).ToString('HH:mm:ss'))] Error output: $stdErr" } return [pscustomobject]@{ Output = if ($stdErr) { $stdErr.Trim() } else { $stdOut.Trim() } ExitCode = $exitCode } } catch { throw "Execution failed: $_" } finally { if (Test-Path $tempFile) { Remove-Item $tempFile -Force -ErrorAction SilentlyContinue } } } |