PowerShell调用CMD执行exe时如何将实时输出流式传递给函数
问题根因
你遇到的输出无法实时传递的核心原因是:支持管道输入的PowerShell自定义函数,必须显式声明process块才能逐行处理管道输入,否则函数默认会等待所有管道输入全部接收完成后,才会一次性执行函数逻辑。
而Out-Host是PowerShell原生命令,内部已经实现了逐行处理的逻辑,所以可以实时显示输出。
修复方案
步骤1:修改自定义函数,新增process块
将你原本写在函数体里的所有处理逻辑,包裹到process {}块内,这样每收到一行管道输入就会立即执行一次处理逻辑:
function get-ValidateProgress { param ([Parameter(Mandatory,HelpMessage='Value Passed from ValidateLDS.exe',Position=0,ValueFromPipeline)]$ValidateLine) # 新增process块,包裹所有处理逻辑 process { IF($ValidateLine -like 'Proccessing Active Users record*' ) { $Current=$ValidateLine -replace 'Proccessing Active Users record ','' -replace 'of.*','' -replace ' ','' $TotalValue=$ValidateLine -replace "Proccessing Active Users record $Current of " ,'' [INT]$Progress=(($Current/$TotalValue)*100) Write-Progress -Id 1 -Activity ValidateDBLDS -Status 'Proccessing LDS User records' -PercentComplete $Progress -CurrentOperation 'Active Users' IF($Current -eq $TotalValue){write-host 'Finished procccsing Active Users' -ForegroundColor Green} } ELSEIF($ValidateLine -like 'Proccessing Deleted Users record*' ) { $Current=$ValidateLine -replace 'Proccessing Deleted Users record ','' -replace 'of.*','' -replace ' ','' $TotalValue=$ValidateLine -replace "Proccessing Deleted Users record $Current of " ,'' [INT]$Progress=(($Current/$TotalValue)*100) Write-Progress -Id 1 -Activity ValidateDBLDS -Status 'Proccessing LDS User records' -PercentComplete $Progress -CurrentOperation 'Deleted Users' IF($Current -eq $TotalValue){write-host 'Finished procccsing Deleted Users' -ForegroundColor Green} } # 如果需要保留输出到变量,可以加一行返回$ValidateLine $ValidateLine } }
步骤2:调整调用逻辑
你原代码中将管道结果赋值给$cmdOutput的操作,会触发PowerShell等待整个管道执行完成才返回结果,如果不需要保存执行输出可以直接去掉赋值,如果需要保存输出,保留赋值即可,配合上面修改后的函数依然可以实时处理进度:
Try{ # 如果不需要保存输出,直接执行即可 cmd.exe /c "cd /d D:\$Campus\Code\Utilities && ValidateDBLDS.exe /viewonly:false" 2>&1 | get-ValidateProgress # 如果需要保存输出,保留赋值即可,进度依然会实时更新 # $cmdOutput = cmd.exe /c "cd /d D:\$Campus\Code\Utilities && ValidateDBLDS.exe /viewonly:false" 2>&1 | get-ValidateProgress Write-Host "Successfully finished LDS Validation." -ForegroundColor Green sleep -Seconds 2 } Catch{ Write-host "An Error occured during validating LDS. See full expection below.`nExecption:"$Error[0].Exception"`nTargetObject:"$Error[0].TargetObject"`nInvocationInfo:"$Error[0].InvocationInfo -ForegroundColor Red }
可选优化
你可以不需要调用cmd.exe切换路径执行程序,直接在PowerShell中指定工作目录调用exe即可:
$workDir = "D:\$Campus\Code\Utilities" & "$workDir\ValidateDBLDS.exe" /viewonly:false 2>&1 | get-ValidateProgress
内容的提问来源于stack exchange,提问作者Elior Machlev
相关产品推荐
相关产品推荐

