Powershell: Feature Request: Make New-WinEvent pipeline friendly

Created on 26 Jul 2019  路  13Comments  路  Source: PowerShell/PowerShell

Summary of the new feature/enhancement

Write-EventLog does not currently accept pipeline input, although it might be useful in situations where you want to log multiple events log entries of the same type:

Get-SomeInformation |Write-EventLog -LogName Application -Source -EventID 100

Proposed technical implementation details (optional)

We might optionally want to consider an alternative InputObject parameter in a separate set that passes non-string "messages" through OutStringCommand before writing them to the event log

First-Time-Issue Issue-Enhancement Up-for-Grabs

Most helpful comment

Fair enough, let's make New-WinEvent pipeline friendly then! 馃槄
image

All 13 comments

I believe Write-EventLog and other event log commands are not part of PS 7; we have the source code here, but it's not compiled or shipped. The Write-EventLog command available in PS 7 on Windows is from Windows PowerShell.

The easiest solution would probably be to create a wrapper module that overrides Write-EventLog and then routes the objects to the actual implementation internally.

Also I think New-WinEvent is the recommended cmdlet to use now. We do build and ship that with PS 7.

Fair enough, let's make New-WinEvent pipeline friendly then! 馃槄
image

@IISResetMe Please update the issue description too.

@PowerShellTeam I'd like to take this on.

I did a bit of quick prototyping. There's a challenge with taking pipeline input on the Payload parameter.

When the event template expects multiple inputs, you could currently invoke the cmdlet like this:
New-WinEvent -ProviderName Microsoft-Windows-PowerShell -Id 49153 -Payload @('Param1', 'Param2')

However, passing the Payload array as an object through the pipeline will not work the same:
@('Param1', 'Param2') | New-WinEvent -ProviderName Microsoft-Windows-PowerShell -Id 49153
Results in each member of the input array being processed as individual records. Because of the way the pipeline input arrays get flattened, putting a payload array inside another array has the same result.

To overcome this, I'd like to propose that Payload take the value from the pipeline by Property name. This would then work as expected:
[pscustomobject]@{Payload=@('Param1', 'Param2')} | New-WinEvent -ProviderName Microsoft-Windows-PowerShell -Id 49153
With the payload array being treated as a single input record.

We can expand on this approach, taking each Parameter as a pipeline value by property name. For example, sending different events to the same provider:

$a = [pscustomobject]@{Id=49153;Payload=@('Param1','Param2')}
$b = [pscustomobject]@{Id=49152;Payload='Param1'}
$a,$b | New-WinEvent -ProviderName Microsoft-Windows-PowerShell

Or even sending multiple events to different providers. This would require some additional refactoring to move the LoadProvider and LoadEventDescription calls into the ProcessRecord override. If we require that pipeline input all goes to one provider, then we would only need to load the provider once in BeginProcessing. This would reduce perf overhead, but limit flexibility.

The biggest drawback is a custom object has to be created. So sending simple single objects on the pipeline won't work, and there would be perf impacts if creating many events.

We could mitigate the single object scenario by taking more strongly typed parameters in separate parameter sets. With a string-only Payload parameter set, we could make this work:
'One', 'Two', 'Three' | New-WinEvent -ProviderName Microsoft-Windows-PowerShell -Id 49153

This would multiply the complexity of the implementation, and each payload type we would want to support would need its own parameter set.

I see .Net Core has API https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.eventlog.writeentry?view=netcore-3.0 to write to Windows Event logs.
Perhaps we could simplify the cmdlet implementation.
@SteveL-MSFT Can we use the API?

Writes an entry in the event log.

@iSazonov as long as it's a documented API, it can be used. Whether it's the right API to use, I'll defer to code review.

@CharlesWillis3 If you are interesting you would consider the referenced API for New-WinEvent. Maybe this will lead to the cmdlet redesign.

Currently, New-WinEvent (and it's counterpart, Get-WinEvent) deal directly with ETW and ETW providers. EventLog.WriteEntry and related methods appear to interact with Windows Event Log at a higher level than ETW.

If I'm understanding everything correctly, it seems to me that using EventLog would fundamentally change the capabilities of the New-WinEvent cmdlet.

If that new API only works against the old EventLog APIs and not the new ETW ones, then it's a subset of capability and shouldn't be used.

It looks like EventLog goes all the way back to .NET FX 1.1. So not too new :-).

The changes to support the feature request should be pretty straightforward. I think most of the complexity is in deciding what exactly to support, and agreeing on the API.

So, I'd still like to take this on. I'm a big fan and major user of ETW, so making this work with pipeline input would be great.

I noticed this old API because old Write-EventLog looks more user friendly. I don鈥檛 even remember that I used New-WinEvent once.

According to the docs, Write-EventLog only works on "classic" event logs. Get-WinEvent and New-WinEvent are required for interacting with the logs from Vista forward. I think this is because the Window Event Log was rebuilt on top of ETW.

I agree Write-EventLog looks more friendly. As a separate feature request, could be worth considering adding a cmdlet for simple logging. Possibly as a marketplace extensions, maybe even xplat?

But New-WinEvent has its uses. It's one of the easiest ways I know of to interact with existing ETW providers.

As a separate feature request, could be worth considering adding a cmdlet for simple logging.

We could add new parameter set in the cmdlet (maybe to emulate old cmdlet). Notice, Get-WinEvent
has -LogName.

Was this page helpful?
0 / 5 - 0 ratings