如何解决实时在控制台上或在PowerShell中使用其他应用程序输出 尤其是这是我的主要问题:
'我已经构建了一个PowerShell脚本,可以实时处理MS Windows可执行程序集(* .exe)的输出。
诸如“ WaitForExit()”之类的方法不在范围内,因为此类方法将阻止事件/输出! 使用此类方法只会在退出后显示结果。 (可以使用“ ping.exe”轻松进行测试)
也许有人可以进行一些其他改进,以避免我的通用脚本出现意外行为。尤其是对于特定的可执行文件。
尤其是(这是我的主要问题):
使用7z.exe检查档案的完整性时,如何获取(按事件)主机更新:
例如
7z t "D:\<someBigArchive.7z"
->在CMD中,我得到了正在运行的进程的百分比,但没有该脚本的信息。
当应用程序向控制台写入新行时,所有其他实时输出正常工作。
这是我当前的PS脚本:
param(
[string] $appFilePath = 'ping.exe',[string] $appArguments = 'google.com',[string] $appWorkingDirPath = '',[int] $consoleOutputEncoding = 850 # 850 = default windows console output encoding (useful for e.g 7z.exe). use "<=0" for host's default encooding.
)
if (!$consoleOutputEncoding -le 0) {
[Console]::OutputEncoding = [System.Text.Encoding]::GetEncoding($consoleOutputEncoding)
}
$eventScriptBlock = {
# received app output
$receivedAppData = $Event.SourceEventArgs.Data
# Write output as stream to console in real-time (without -stream parameter output will produce blank lines!)
# (without "Out-String" output with multiple lines at once would be displayed as tab delimited line!)
Write-Host ($receivedAppData | Out-String -Stream)
<#
< Insert additional real-time processing steps here.
< Since it''s in an entirely different scope (not child),variables of parent scope won't be populated to that child scope and scope "$script:" won't work as well. (scope "$global:" would work but should be avoided!)
< Modify/Enhance variables "*MessageData" (see below) before registering the event to access such variables.
#>
# add received data to stringbuilder definded in $stdOutEventMessageData and $stdErrEventMessageData
$Event.MessageData.outStringBuilder.AppendLine($receivedAppData)
}
# MessageData parameters for default events (used for event input and output)
$stdOutEventMessageData = @{
# used for adding output within events to stringbuilder (OUT) for further usage
outStringBuilder = [System.Text.StringBuilder]::new()
#< add additional properties if necessary. Can be used as input and output in $eventScriptBlock ($Event.MessageData.*)
#< ....
}
# MessageData parameters for error events (used for event input and output)
$stdErrEventMessageData = @{
# used for adding output within events to stringbuilder (OUT) for further usage
outStringBuilder = [System.Text.StringBuilder]::new()
#< add additional properties if necessary. Can be used as input and output in $eventScriptBlock ($Event.MessageData.*)
#< ....
}
#######################################################
#region Process-Definition,-Start and Event-Subscriptions (Adaptions in that region should be avoided!)
#------------------------------------------------------
try {
$appProcess = [System.Diagnostics.Process]::new()
$appProcess.StartInfo = @{
Arguments = $appArguments
WorkingDirectory = $appWorkingDirPath
FileName = $appFilePath # mandatory
RedirectStandardOutput = $true # mandatory = $true
RedirectStandardError = $true # mandatory = $true
#< RedirectStandardInput = $true # leave commented; only useful in some circumstances. Didn''t find any use,but mentioned in: https://stackoverflow.com/questions/8808663/get-live-output-from-process
UseShellExecute = $false # mandatory = $false
CreateNoWindow = $true # mandatory = $true
}
$stdOutEvent = Register-ObjectEvent -InputObject $appProcess -Action $eventScriptBlock -EventName 'OutputDataReceived' -MessageData $stdOutEventMessageData
$stdErrEvent = Register-ObjectEvent -InputObject $appProcess -Action $eventScriptBlock -EventName 'ErrorDataReceived' -MessageData $stdErrEventMessageData
[void]$appProcess.Start()
$appProcess.BeginOutputReadLine()
$appProcess.BeginErrorReadLine()
while (!$appProcess.HasExited) {
# Don't use method "WaitForExit()"! This will not show the output in real-time as it blocks the output stream!
# using "Sleep" from System.Threading.Thread class for short sleep times below 1/1.5 seconds is better than "Start-Sleep" in terms of PS overhead/performance on init (Test it yourself)
# (sleep will block console output --> don't set too high; but also not too low for performance reasons in long running actions)
[System.Threading.Thread]::Sleep(250)
#< maybe timeout ...
}
} finally {
if (!$appProcess.HasExited) {
$appProcess.Kill() # WARNING: Entire process gets killed! Review and adapt!
}
if ($stdOutEvent -is [System.Management.Automation.PSEventJob]) {
Unregister-Event -SourceIdentifier $stdOutEvent.Name
}
if ($stdErrEvent -is [System.Management.Automation.PSEventJob]) {
Unregister-Event -SourceIdentifier $stdErrEvent.Name
}
}
#------------------------------------------------------
#endregion
#######################################################
$stdOutText = $stdOutEventMessageData.outStringBuilder.ToString() # final output for further usage
$stErrText = $stdErrEventMessageData.outStringBuilder.ToString() # final errors for further usage
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。