powershell cmdlet如何将信息或错误传递给写入事件日志

时间:2018-11-10 17:54:47

标签: powershell event-log io-redirection

我试图基于从我的cmdlet发出的流,将事件日志输出到正确的条目类型(信息,警告,错误),如下所示:

function myfunction {
   Param(
   [switch]$stream1,
   [switch]$stream2
)
   if ($stream1) {write-output 'stream 1 msg'}
   if ($stream2) {write-error 'stream 2 msg'}
}

$eventlogparams = @{'logname'='application';'source'='myapp';'eventid'='1'}

myfunction -stream1 -stream2 `
  1> write-eventlog @eventlogparams -entrytype information -message $_ `
  2> write-eventlog @eventlogparams -entrytype error -message $_

有人知道如何做到这一点吗?

2 个答案:

答案 0 :(得分:3)

您可以 合并错误流和其他错误流到成功,并通过在源流之间进行区分。每个管道对象的数据类型

myfunction -channel1 -channel2 *>&1 | ForEach-Object { 
  $entryType = switch ($_.GetType().FullName) {
        'System.Management.Automation.ErrorRecord' { 'error'; break }
        'System.Management.Automation.WarningRecord' { 'warning'; break }
        default { 'information'}
    }
  write-eventlog @eventlogparams -entrytype $entryType -message $_
}

重定向*>&1将所有所有*)流的输出发送到(&)成功流(1),以便所有输出,无论它来自什么流,都通过管道发送。

以上内容仅专门处理错误和警告,并将其他信息(包括成功输出)报告为信息,但扩展方法很容易-请参见底部。

请参见about_Redirections,以了解PowerShell(自v6起)中可用的全部6个输出流。


以一个更简单的示例来说明该技术:

& { Write-Output good; Write-Error bad; Write-Warning problematic } *>&1 | ForEach-Object {
  $entryType = switch ($_.GetType().FullName) {
        'System.Management.Automation.ErrorRecord' { 'error'; break }
        'System.Management.Automation.WarningRecord' { 'warning'; break }
        default { 'information'}
    }
  '[{0}] {1}' -f $entryType, $_
}

以上结果:

[information] good
[error] bad
[warning] problematic

各种流输出的数据类型的列表

Stream           Type
------           ----
#1 (Success)     (whatever input type is provided).
#2 (Error)       [System.Management.Automation.ErrorRecord]
#3 (Warning)     [System.Management.Automation.WarningRecord]
#4 (Verbose)     [System.Management.Automation.VerboseRecord]
#5 (Debug)       [System.Management.Automation.DebugRecord]
#6 (Information) [System.Management.Automation.InformationRecord]

以下代码用于生成以上列表(第一个数据行除外):

& {
    $VerbosePreference = $DebugPreference = $InformationPreference = 'Continue'
    $ndx = 2
    "Write-Error", "Write-Warning", "Write-Verbose", "Write-Debug", "Write-Information" | % {
        & $_ ($_ -split '-')[-1] *>&1
        ++$ndx
    } | Select-Object @{n='Stream'; e={"#$ndx ($_)"} }, @{n='Type'; e={"[$($_.GetType().FullName)]"} }
}

答案 1 :(得分:1)

正如@Lee_Dailey正确指出的那样,您需要事件源存在。即使在那之后,您的代码片段也可能会抛出错误(如PS v5中已选中)

  

该进程无法访问文件   'C:\ Users \ username \ Desktop \ write-eventlog',因为它正在被使用   另一个过程。

因为重定向操作符期望文件不重定向cmdlet或函数,所以这是导致上述错误的原因。

您可以尝试修改代码,以便重定向操作员将数据存储在文件中,然后将其推送到事件日志中:

myfunction -channel1 -channel2 > output.txt  2> error.txt 

write-eventlog @eventlogparams -entrytype error -message ((get-content error.txt) -join "")

write-eventlog @eventlogparams -entrytype information -message ((get-content output.txt) -join "")

另一种方法是使用outvariable和errorvariable,为此,该功能必须是高级功能(为此我添加了cmdletbinding):

function myfunction {
[CmdletBinding()]
   Param(
   [switch]$channel1,
   [switch]$channel2
)
   if ($channel1) {write-output 'channel 1 msg'}
   if ($channel2) {write-error 'channel 2 msg'}
}

$eventlogparams = @{'logname'='application';'source'='myapp';'eventid'='1'}

myfunction -channel1 -channel2 -OutVariable output -ErrorVariable errordata
write-eventlog @eventlogparams -entrytype error -message ($errordata -join "")

write-eventlog @eventlogparams -entrytype information -message ($output -join "")