diff --git a/scripts/run-clean-scratch-iterations.ps1 b/scripts/run-clean-scratch-iterations.ps1 index 52de10b41..93bf4aa2b 100644 --- a/scripts/run-clean-scratch-iterations.ps1 +++ b/scripts/run-clean-scratch-iterations.ps1 @@ -67,16 +67,6 @@ function Format-ProcessArgument { return '"' + ($Value -replace '(\\*)"', '$1$1\"' -replace '(\\+)$', '$1$1') + '"' } -function ConvertTo-PowerShellLiteral { - param( - [Parameter(Mandatory = $true)] - [AllowEmptyString()] - [string]$Value - ) - - return "'" + ($Value -replace "'", "''") + "'" -} - function Invoke-External { param( [Parameter(Mandatory = $true)] @@ -88,9 +78,6 @@ function Invoke-External { ) Push-Location $WorkingDirectory - $stdoutPath = New-LogCapturePath -Suffix '.stdout.log' - $stderrPath = New-LogCapturePath -Suffix '.stderr.log' - $wrapperPath = New-LogCapturePath -Suffix '.invoke.ps1' try { $resolvedFilePath = $FilePath if (Test-Path $FilePath) { @@ -99,60 +86,85 @@ function Invoke-External { $startFilePath = $resolvedFilePath $startArgumentList = @($ArgumentList) - $powershellPath = (Get-Command powershell.exe -ErrorAction Stop).Source if ([System.IO.Path]::GetExtension($resolvedFilePath).Equals('.ps1', [System.StringComparison]::OrdinalIgnoreCase)) { + $powershellPath = (Get-Command powershell.exe -ErrorAction Stop).Source $startFilePath = $powershellPath $startArgumentList = @('-NoLogo', '-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', $resolvedFilePath) + @($ArgumentList) } - $invocationExpression = '& ' + (ConvertTo-PowerShellLiteral -Value $startFilePath) - if ($startArgumentList.Count -gt 0) { - $invocationExpression += ' ' + (($startArgumentList | ForEach-Object { ConvertTo-PowerShellLiteral -Value $_ }) -join ' ') + $startInfo = [System.Diagnostics.ProcessStartInfo]::new() + $startInfo.FileName = $startFilePath + $startInfo.WorkingDirectory = $WorkingDirectory + $startInfo.UseShellExecute = $false + $startInfo.RedirectStandardOutput = $true + $startInfo.RedirectStandardError = $true + foreach ($argument in $startArgumentList) { + [void]$startInfo.ArgumentList.Add([string]$argument) } - $wrapperContent = @( - '$ErrorActionPreference = ''Stop''' - "$invocationExpression 1> $(ConvertTo-PowerShellLiteral -Value $stdoutPath) 2> $(ConvertTo-PowerShellLiteral -Value $stderrPath)" - 'exit $LASTEXITCODE' - '' - ) - Set-Content -Path $wrapperPath -Value $wrapperContent -Encoding UTF8 + $process = [System.Diagnostics.Process]::new() + $process.StartInfo = $startInfo - $formattedArgumentList = @(@('-NoLogo', '-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', $wrapperPath) | ForEach-Object { Format-ProcessArgument -Value $_ }) + $stdoutQueue = [System.Collections.Concurrent.ConcurrentQueue[string]]::new() + $stderrQueue = [System.Collections.Concurrent.ConcurrentQueue[string]]::new() - $process = Start-Process ` - -FilePath $powershellPath ` - -ArgumentList $formattedArgumentList ` - -WorkingDirectory $WorkingDirectory ` - -PassThru + $stdoutHandler = [System.Diagnostics.DataReceivedEventHandler]{ + param($sender, $eventArgs) + if ($null -ne $eventArgs.Data) { + $stdoutQueue.Enqueue($eventArgs.Data) + } + } - $stdoutIndex = 0 - $stderrIndex = 0 + $stderrHandler = [System.Diagnostics.DataReceivedEventHandler]{ + param($sender, $eventArgs) + if ($null -ne $eventArgs.Data) { + $stderrQueue.Enqueue($eventArgs.Data) + } + } + $process.add_OutputDataReceived($stdoutHandler) + $process.add_ErrorDataReceived($stderrHandler) + + if (-not $process.Start()) { + throw "Failed to start process: $resolvedFilePath" + } + + $process.BeginOutputReadLine() + $process.BeginErrorReadLine() + + $dequeuedLine = $null while (-not $process.HasExited) { - Write-LogCaptureDelta -Path $stdoutPath -LineIndex ([ref]$stdoutIndex) - Write-LogCaptureDelta -Path $stderrPath -LineIndex ([ref]$stderrIndex) + while ($stdoutQueue.TryDequeue([ref]$dequeuedLine)) { + $dequeuedLine | Out-Host + $dequeuedLine = $null + } + + while ($stderrQueue.TryDequeue([ref]$dequeuedLine)) { + $dequeuedLine | Out-Host + $dequeuedLine = $null + } + Start-Sleep -Milliseconds 500 - $process.Refresh() } $process.WaitForExit() - $process.Refresh() - Write-LogCaptureDelta -Path $stdoutPath -LineIndex ([ref]$stdoutIndex) - Write-LogCaptureDelta -Path $stderrPath -LineIndex ([ref]$stderrIndex) + + while ($stdoutQueue.TryDequeue([ref]$dequeuedLine)) { + $dequeuedLine | Out-Host + $dequeuedLine = $null + } + + while ($stderrQueue.TryDequeue([ref]$dequeuedLine)) { + $dequeuedLine | Out-Host + $dequeuedLine = $null + } if ($process.ExitCode -ne 0) { throw "Command failed: $resolvedFilePath $($ArgumentList -join ' ')" } } finally { - foreach ($capturePath in @($stdoutPath, $stderrPath, $wrapperPath)) { - if (Test-Path $capturePath) { - Remove-Item $capturePath -Force -ErrorAction SilentlyContinue - } - } - Pop-Location } }