【问题标题】:Powershell stream eventsPowershell 流事件
【发布时间】:2022-12-18 00:57:19
【问题描述】:

我想知道是否可以订阅当前的 Powershell 会话事件流,以便每次将一些信息/警告/错误等添加到流中时,我都可以将其作为对象读取。我能够订阅上述 3 个流的 DataAdded 事件,但由于某种原因我只能拦截来自 error stream 的事件

$InformationPreference = 'Continue'

$ps = [PowerShell]::Create("CurrentRunspace")
$ps.Streams.Information.Add_DataAdded({
     # THE EVENT IS NEVER TRIGGERED
    $ps.Streams.Information.ReadAll().ForEach{ 
        Write-Host ($_ | Out-String)
    }
})
$ps.Streams.Warning.Add_DataAdded({
    # THE EVENT IS NEVER TRIGGERED
    $ps.Streams.Warning.ReadAll().ForEach{ 
        Write-Host ($_ | Out-String)
    }
})
$ps.Streams.Error.Add_DataAdded({
    #WORKS FINE
    $ps.Streams.Error.ReadAll().ForEach{ 
        Write-Host ($_ | Out-String)
    }
})

$ps.AddScript({
    Write-Information 'Some Information'
    Write-Warning 'Some Warning'
    Write-Error 'Some Error'
}).Invoke()

知道为什么警告和信息流不触发事件吗?

【问题讨论】:

  • 这背后的目的是什么? PowerShell 已经提供了用于重定向任何流(进度流除外)的本机机制,例如。 G。 & { Write-Information 'Some Information'; Write-Warning 'Some Warning'; Write-Error 'Some Error' } *>&1 | Out-String -Stream
  • @zett42 这个想法是将输出实时流式传输到 WebApplication,消息到达后我需要显示它。您提到的机制几乎符合我的需要,但问题是所有消息都只是字符串,并且不可能从信息中分辨出调试消息。
  • 您可以在它们仍然是对象时区分它们:... *>&1 | ForEach-Object { if( $_ -is [Management.Automation.ErrorRecord] ) { "ERROR: $_" } }。如果您愿意,我可以写一个更完整的示例作为答案。
  • @zett42 是的,你是对的!这是实现我需要的更简单/更好的方法。谢谢!

标签: powershell runspace


【解决方案1】:

这是一个将脚本块的所有流重定向到成功流的示例,保持原始格式不变并且仍然能够区分流的种类.

& {
    [PSCustomObject]@{ Foo = 42; Bar = 23 } | Format-Table  # Output
    $DebugPreference = 'Continue'
    Write-Debug 'Some Debug'
    Write-Information 'Some Information'
    Write-Warning 'Some Warning'
    Write-Error 'Some Error'

} *>&1 | ForEach-Object -PV record { $_ } | Out-String -Stream | ForEach-Object {
    # Process a single line of formatted output

    $prefix = switch( $record ) {
        { $_ -is [Management.Automation.DebugRecord] }       { 'DBG'; break }
        { $_ -is [Management.Automation.InformationRecord] } { 'INF'; break }
        { $_ -is [Management.Automation.WarningRecord] }     { 'WRN'; break }
        { $_ -is [Management.Automation.ErrorRecord] }       { 'ERR'; break }
        default                                              { 'OUT' }
    }

    # Prepend prefix and output current line 
    "[$prefix] $_"  
}

输出:

[OUT]        
[OUT] Foo Bar
[OUT] --- ---
[OUT]  42  23
[OUT]        
[OUT]
[DBG] Some Debug
[INF] Some Information
[WRN] Some Warning    
[ERR] 
[ERR]   [PSCustomObject]@{ Foo = 42; Bar = 23 } | Format-Table  # Output
[ERR]   Write-Debug 'Some Debug'
[ERR]     Write-Information 'Some Information'
[ERR]     Write-Warning 'Some Warning'
[ERR]     Write-Error 'Some Error'
[ERR]
[ERR]  : Some Error
[ERR] In ***RedirectAllStreams.ps1:1 Char:1
[ERR] + & {
[ERR] + ~~~
[ERR]     + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
[ERR]     + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException
[ERR]

评论:

  • *>&1 redirects(合并)所有流(进度除外)到成功(又名标准输出) 溪流
  • ForEach-Object -PV record { $_ } - 存储当前流目的通过使用公共参数-PipelineVariable-PV)进入变量record并将其转发到下一个命令
  • Out-String -Stream - 转换当前流目的成字符串流(每行输出一个字符串),以确保 PowerShell 的格式化系统得到尊重(例如,如果没有这个,Format-Table 示例将无法工作)。
  • 最后的ForEach-Object只处理字符串,但是流对象的类型仍然可以通过变量$record获得,所以我们可以使用-is运算符来区分。

【讨论】:

    【解决方案2】:

    下面是我得到的。看起来它正在工作。我刚刚复制了你的代码并发布到 powershell 中。

    【讨论】:

    • 不完全是……您看到的输出来自脚本执行,而不是来自事件处理程序。如果把Write-Host ($_ | Out-String)改成($_ | Out-String) | Out-File -Path ...,那么文件中只会出现Write-Error的内容
    • 你是管理员吗?您是否通过右键单击快捷方式并选择以管理员身份运行来启动 powershell?对“未指定 powershell 类别信息”进行网络搜索
    猜你喜欢
    • 1970-01-01
    • 2011-01-01
    • 2020-05-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多