PowerShell – How to Retrieve Specific Events From All Servers

Occasionally you may have to implement something which will improve the security of your organisation but that does introduce a risk. Often the correct way to determine if it will cause issues is to enable logging and then to review those logs.

But what if you don’t have centralised logging?

This article does not replace a fully functional centralised event logging system which I would strongly suggest anybody have, however, it will allow you to retrieve specific logs from all servers in your estate. If your estate is too large then the script can be modified to instead of storing all of the data in the $allEvents variable you could simply append it to an Excel file inside of the for each loop.

The Code

# Get a list of server names for all enabled servers in the estate
$allServers = Get-ADComputer -Filter { OperatingSystem -Like '*Windows Server*' -and Enabled -eq $True} | select Name

$currentIndex = 1
$startTime = Get-Date

## Loop through each computer in list, assigning output straight to allEvents is much quicker than += as that recreates an array each loop
$allEvents = foreach($computer in $allServers.name) {
    # Estimate time to completion
    $estimation = $null
    $now = Get-Date
    if ($currentIndex -gt 0) {
        $elapsed = $now - $startTime # how much time has been spent
        $average = $elapsed.TotalSeconds / $currentIndex # how many seconds per site
        $totalSecondsToGo = ($allServers.Count - $currentIndex) * $average # seconds left
        $span = New-TimeSpan -Seconds $totalSecondsToGo # time left
        $estimatedCompletion = $now + $span # when it will be complete
        $estimation = $estimatedCompletion.ToString() # readable estimation

    # Show progress and estimated completion
    Write-Progress -Id 0 -Activity "Retrieving events from servers" -Status "$currentIndex of $($allServers.Count), Est Completion - $($estimation)" -PercentComplete (($currentIndex / $allServers.Count) * 100)

    # Define the xmlQuery to return the events we want
    $xmlQuery = @'
          <Query Id="0" Path="Microsoft-Windows-CodeIntegrity/Operational">
            <Select Path="Microsoft-Windows-CodeIntegrity/Operational">*[System[Provider[@Name='Microsoft-Windows-CodeIntegrity'] and (Level=4 or Level=0) and (EventID=3066) and TimeCreated[timediff(@SystemTime) &lt;= 2592000000]]]</Select>

    try {
        # Retrieve events from each machine using the xml query
        $eventData = Get-WinEvent -FilterXML $xmlQuery -ComputerName $computer -ErrorAction Stop

        # add the returned data as output to the loop, fed straight into $allEvents
        @($eventData | select TimeCreated, MachineName, Message )
    } catch {
        Write-Host -ForegroundColor Yellow "No events found for" $computer

Write-Progress -Id 0 -Activity " " -Status " " -Completed

$allEvents | select * | ft

You can figure out exactly what XML query you need by opening Event Viewer on a server and filtering the log so that it only displays the events you want to return. Then open ‘Filter Current Log’ > XML tab and copy the entire XML query.

Once you’ve got the XML, you can simply paste it over the xmlQuery variable found in the script above.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.