PowerShell Diversion #2: Discussion

[Follow-up discussion for PowerShell Diversion #2 ]

There are a number of things we need to look at to make a table with a  built-in chart (as mentioned in the hint file from the original post).  The first is working out how to read events from the event log:

This code will do that for us:

Get-EventLog -LogName System -EntryType Error,Warning |        Group-Object Source |              Sort-Object Count –Descending |                 Format-Table Count, Name -Autosize

This is a single line of PowerShell.  I have broken the line at each pipe and indented the next row – I find this makes for neater and easier to read code when you have a long or complex 1-liner.

What is it doing? Well, firstly the Get-EventLog cmdlet gathers the specific event types (“error” and “warning”) from the target log (“system”), which it then sends to be grouped by Group-ObjectGroup-Object produces a group of event entries for each unique source in the  stream sent by Get-EventLog.  It also kindly counts the number of items in each group, which Sort-Object makes use of to sort the groups in order starting with the most populous to the least.  Finally, Format-Table shows the information in a neat table like this:

Count Name                   ----- ----                     129 Kerberos                  57 NETLOGON                  36 cdrom                     29 Schannel                  26 Microsoft Antimalware     25 DCOM                      17 Service Control Manager     7 Disk                       2 Virtual Disk Service       2 WudfUsbccidDriver          2 volsnap                    2 SCardSvr                   1 Ntfs                       1 EventLog

We’re half-way to our end goal.  This information is useful as is (I think I might have an issue with Kerberos), but just to add that finishing touch of the ‘chart’, we need to tweak the code:

$Evt = Get-EventLog -LogName System `
    -EntryType Error,Warning |
        Group-Object Source |
            Sort-Object Count -Descending

$Scale = 20 / $Evt[0].Count

$Chart = @{Label="Chart";`
           Expression={"X"*(($_.Count) * $Scale)}}

$Evt | Format-Table Count, Name, $Chart -Autosize

Now, what is this doing?  The first line is just the same as before, except we capture the events into a variable instead of displaying them.  Next we calculate a scaling factor using the size of the largest group – here we divide 20 by the group size, so that in the final chart this group will be represented by 20 Xs. 

The interesting stuff takes place on the next line, where we use a hashtable (signified by ‘@{ … }’) to produce the ‘calculated property’ that will be our chart values.  The hashtable comprises of two parts, the ‘label’, which will become the title of the chart column in our final table, and the ‘expression’, which executes some PowerShell code to calculate the values in the rows of that column.  In this instance, we make use of the fact that the multiplication operator has an overload that effectively concatenates an input string with itself the given number of times.  For example, “X” * 5, produces: “XXXXX”.

Finally, we display the events in a table, which gives a result like this:

Count Name                    Chart               ----- ----                    -----                 129 Kerberos                XXXXXXXXXXXXXXXXXXXX    57 NETLOGON                XXXXXXXXX              36 cdrom                   XXXXXX                 29 Schannel                XXXX                   26 Microsoft Antimalware   XXXX                   25 DCOM                    XXXX                   17 Service Control Manager XXX                     7 Disk                    X 

For the optional enhancements (running against multiple computers and grouping by source and Event ID), we need to perform these two simple changes:

To run the script against multiple machines, simply alter the GetEventLog cmdlet to include the –ComputerName parameter, like this: –ComputerName Server1, Server2, Server3, …

To group by source and Event ID, change the Group-Object cmdlet to include both, like this: Group-Object Source, EventID