Windows Event Log in PowerShell – Part II

PowerShell Team

In part 1 of “Event logs in Powershell” we talked about differences between Get-EventLog and Get-WinEvent. In this second part we will dig deeper into Get-WinEvent.


Starting in Windows Vista, the Windows Event Log was updated to provide a more powerful event model which allows for events to be easily categorized into logs and for event providers to be easily discovered.  PowerShell V2 lets you search the Event Log for the data that’s interesting to you, making it easier than ever to mine events from the Event Log. The new Get-WinEvent cmdlet provides access to all event logs on the system, including the legacy Event Logs.  Get-WinEvent cmdLet will be available on PowerShell V2 Running on Windows Vista and above (i.e. Windows Vista, Windows Vista SP1, Windows Server 2008, Windows 7 and Windows Server 2008 R2).  Get-WinEvent replaces the existing Get-EventLog cmdlet on these systems.


Getting Events from the Event Log

Getting events is easy with PowerShell. If I want to list all of the events in the system, I can run Get-WinEvent without any parameters:

> Get-WinEvent

The number of events can be excessively large, so be prepared to use ‘Ctrl-C’ to break out of it early. Since some logs are protected, you might see an error when running this command if you are not running PowerShell elevated as an Administrator.

Suppose you want to see the most recent 10 events which were logged. In PowerShell, I’d make a small modification:

> Get-WinEvent -MaxEvents 10

 The command above uses the default behavior to get events from every event log and uses the MaxEvents parameter to return only the most recent 10 events.

 If you wanted to see the events from a specific channel, such as the general “Application” and “System” channels, simply specify which logs you want to get events from:

> Get-WinEvent Application, System -MaxEvents 10


Discovering Logs, Providers and Events

Generally it is more interesting to find the specific events that you care about.  For that, we can use wildcards to find event providers and logs which we’re interested in.


For example, if we’re interested in what Windows Update has been doing on a particular machine, we can search for the Windows Update event provider:

PS C:\> Get-WinEvent -ListProvider *update*

Name                                                                        LogLinks

—-                                                                               ——–

MCUpdate                                                                {Media Center}

Microsoft-Windows-WindowsUpdateClient      {System, Microsoft-Windows-WindowsUpdateClient/Operational}


Now that we know the name of the provider (Microsoft-Windows-WindowsUpdateClient), we can see the events that the provider has already logged to the Event Log:

> Get-WinEvent -ProviderName  Microsoft-Windows-WindowsUpdateClient


In some cases, it is more interesting to know what events the provider can potentially log instead of what it already has logged.  If we want to see the events that Windows Update can log in the future, we can take a deeper look at the provider: E.g to see the messages that will be logged with word “success” in the event message, we can use the following:


PS C:\> $provider = Get-WinEvent -ListProvider  Microsoft-Windows-WindowsUpdateClient

PS C:\> $ | ? {$_.description -match “success”} | select id,description | ft -AutoSize


Id   Description


19   Installation Successful: Windows successfully installed the following update: %1

23   Uninstallation Successful: Windows successfully uninstalled the following update: %1

36   The Windows Update Client Core component was successfully updated from version %1 to version %2.

37   The Windows Update Client Auxillary was successfully updated from version %1 to version %2.


PS C:\> $ | ? {$_.description -match “success”} | select -First 1


Id               : 19

Version      : 0

LogLink     : System.Diagnostics.Eventing.Reader.EventLogLink

Level          : System.Diagnostics.Eventing.Reader.EventLevel

Opcode       : System.Diagnostics.Eventing.Reader.EventOpcode

Task            : System.Diagnostics.Eventing.Reader.EventTask

Keywords    : {, success, install}

Template     : <template xmlns=””>

                         <data name=”updateTitle” inType=”win:UnicodeString” outType=”xs:string”/>

                         <data name=”updateGuid” inType=”win:GUID” outType=”xs:GUID”/>

                         <data name=”updateRevisionNumber” inType=”win:UInt32″ outType=”xs:unsignedInt”/>



Description : Installation Successful: Windows successfully installed the following update: %1


From this event description I can tell that the event logs the title of the update in the “updateTitle” field of the event Template, which will let me write a script that reports back the installed updates.


Filtering Events

If I want to look at all of the updates that have been installed, I can simply filter them in PowerShell:

> Get-WinEvent -Provider Microsoft-Windows-WindowsUpdateClient | ? {$ -eq 19} | ft timestamp, message -auto

While using PowerShell to filter the events in our last example works well, Get-WinEvent provides even more powerful filtering which is done by the Event Log. Generally, you’ll want to use the Get-WinEvent FilterXPath or FilterHashTable parameters to reduce the number of events that you have to process in PowerShell. This is because the Event Log is very efficient at filtering events based on these queries.


For example, to perform the same filtering as the previous example without using PowerShell to filter I can use a FilterHashTable:

> Get-WinEvent -FilterHashTable @{ProviderName=”Microsoft-Windows-WindowsUpdateClient”; ID=19} | ft timestamp, message -auto


Take a look at Get-WinEvent help for more information about how to use the FilterHashTable parameter.  It is very, very useful!


Working with Events

An individual event carries much more information than just the timestamp, event ID, and a message string. Event Log events contain a wealth of information such as the level which indicates if the event was an error, warning, or simply informational.  Events also carry payloads of data which are unique to each event which are described by their <template>.


Going back to our Windows Update example, if I wanted to just return the title of the update of each update installed, I could do so by pulling that data out of the event.  I know from the event description (above) that the first property of the event is the title of the update (which is given by the event template).  Knowing that, I can just pull out the single property and display it:


PS C:\> Get-WinEvent -FilterHashTable @{ProviderName=”Microsoft-Windows-WindowsUpdateClient”; ID=19} | foreach {$[0]}




Definition Update for Windows Defender – KB915597 (Definition 1.59.789.0)

Intel Corporation driver update for Mobile Intel(R) 45 Express Chipset Family (Microsoft Corporation …

Test Update for Windows 7 Release Candidate for x64-based Systems (KB970424)

Update for Office Communicator 2007 R2 (KB 971083)

Definition Update for Windows Defender – KB915597 (Definition 1.59.659.0)

Definition Update for Windows Defender – KB915597 (Definition 1.59.458.0)

Test Update for Windows 7 Release Candidate for x64-based Systems (KB970421)

Test Update for Windows 7 Release Candidate for x64-based Systems (KB970423)

Update for Internet Explorer 8 Compatibility View List for Windows 7 Release Candidate for x64-based Systems …



Events from Remote Machines

The Get-WinEvent cmdlet can be used to get events from remote machines using the Event Log remote connection protocol.  For example, if I want to get the most recent 100 events from the Application and System log from a remote machine:

> Get-WinEvent -ComputerName -LogName Application, System -MaxEvents 100


It’s important to know that Get-WinEvent uses the Windows Event Log to establish the remote connection and does not use the Windows PowerShell remoting for a couple of reasons.  First, since the Event Log is installed on every version of Windows Vista and above, you can use it to collect logs without requiring PowerShell Remoting. Secondly, since the cmdlet uses the Event Log’s remote protocol, any filtering that you pass to the cmdlet will be done on the remote machine. This means that, if you use one of the Filter* parameters of the cmdlet, you’ll minimize the data sent across the wire since the remote machine does the filtering instead of the local machine.

 If you want to gather data from multiple machines at once, you can do that with a simple script. Note that the events will need to be sorted after this script is run, since the events are gathered from one machine at a time.

PS C:\temp> import-csv .\computers.csv




PS C:\temp> import-csv .\computers.csv | %{Get-WinEvent -ComputerName $_.ComputerName -LogName Application, System -MaxEvents 100}

TimeCreated                          ProviderName                                    Id         Message

———–                                   ————                                                       ——-

6/8/2009 2:45:59 PM           Service Control Manager                 7036    The Multimedia Class Sched…

6/8/2009 2:45:59 PM           Service Control Manager                 7036    The Multimedia Class Sched…


We hope you find the new cmdlet very useful!


Kevin Woley, Windows Event Log PM 


Osama Sajid, Windows PowerShell PM




Discussion is closed.

Feedback usabilla icon