Командлет powershell, как передать информацию или ошибку в write-eventlog - PullRequest
0 голосов
/ 10 ноября 2018

Я пытаюсь вывести в журнал событий правильный тип записи (Информация, Предупреждение, Ошибка) на основе потока, который выходит из моего командлета, что-то вроде этого:

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 голосов
/ 10 ноября 2018

Вы можете объединить поток ошибок и другие данные в success stream и различать исходные потоки по типу данных каждого объекта трубопровода:

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 для обзора всех 6 потоков вывода, доступных в PowerShell (начиная с версии 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)]"} }
}
0 голосов
/ 10 ноября 2018

Как правильно заметил @Lee_Dailey, источник события должен существовать. Даже после этого ваш фрагмент может выдать ошибку, как (проверено в PS v5)

Процесс не может получить доступ к файлу 'C: \ Users \ username \ Desktop \ write-eventlog', потому что он используется другой процесс.

, поскольку оператор перенаправления ожидает, что файл перенаправляет не командлет или функцию, которая является причиной вышеуказанной ошибки.

Вы можете попробовать изменить код, чтобы оператор перенаправления сохранял данные в файлах, а затем вставил их в журнал событий:

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, для того, чтобы эта функция работала, функция должна быть расширенной (для этого я добавил привязку cmdlet):

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 "")
...