Learn about Windows PowerShell
Summary: Windows PowerShell MVP, Jeffery Hicks, provides expert commentary for 2012 Scripting Games Beginner Event 5.
Microsoft Scripting Guy, Ed Wilson, is here. Jeffery Hicks is the expert commentator for Beginner Event 5.
Jeffery is a Microsoft MVP in Windows PowerShell, Microsoft Certified Trainer, and an IT veteran with 20 years of experience—much of it spent as an IT consultant specializing in Microsoft server technologies. He works today as an independent author, trainer, and consultant. Jeff writes the popular Prof. PowerShell column for MPCMag.com, and he is a regular contributor to SMB IT Simplified and the Petri IT Knowledgebase. Jeff is a regular speaker at conferences, such as TechEd, and he often speaks about Windows PowerShell, Active Directory, Group Policy, and anything else than can make IT Pros more efficient and productive.
Your task is to write a Windows PowerShell command or tool that can query the application log on a computer and show how many events are associated with each event log source. Your first step would be to use the Get-EventLog cmdlet.
To use this cmdlet you can specify an event log (in this case, Application) and a computer name. Running this cmdlet could return a lot of entries, so to test your work as you develop it, I suggest using the –Newest parameter to only get a subset of entries. You might start like this:
PS C:\> Get-Eventlog –logname Application –computername $env:computername –newest 50
I like using the environmental variable for the computer name because it resolves to a “real” name rather than to LocalHost. When I have the command working, all that needs to be done is to insert a remote computer name. The output of the ComputerName cmdlet is a collection of event log entries.
What we are after is a way to group entries by the Source property. In other words, create a bucket for each Source value and put each matching entry in that bucket. Think about what is being asked? You need to group entries, so ask Windows PowerShell what you should use as follows:
PS C:\> help group
You should see the Group-Object cmdlet. After you read the Help and look at examples, hopefully you realize that you can pipe the event entries to Group-Object and specify the property to group on (in this case, Source). One quick tip though: Don’t assume that the table headings you see from cmdlet output are the actual property names. There are a number of cmdlets that use custom headings. The only way to learn the actual property name is to pipe the object to Get-Member. If you piped the Get-EventLog cmdlet to Get-Member, you would see that, in this case, the property is the same as the default output. Let’s group:
PS C:\> Get-Eventlog –logname Application –computername $env:computername –newest 50 | Group-Object –property Source
Group-Object writes a different object to the pipeline. Rerun the command and pipe it to Get-Member to see. To make it easier to read, we can sort on the Count property as follows:
PS C:\> get-eventlog -LogName Application -ComputerName $env:computername –newest 50 | Group-Object -property Source | Sort-property Count -descending
The manager wants a simple list, so we can limit the display by selecting the Group-Object properties that we need:
PS C:\> get-eventlog -LogName Application -ComputerName $env:computername –Newest 50| Group-Object -property Source | Sort-property Count -descending | Select Count,Name
The result isn’t necessarily formatted that nicely, but we can fix that. In fact, at this point, we can get all the application event log entries as shown here:
PS C:\> get-eventlog -LogName Application -ComputerName $env:computername | Group-Object -property Source | Sort-property Count -descending | Select Count,Name | format-Table-autosize
You could send this to Out-File—or you could drop the Format-Table if you wanted to export to a CSV or do anything else with it. Finally, since we are doing this interactively, we can also take advantage of aliases and positional parameters to simplify the typing.
PS C:\>get-eventlog application –computer $env:computername | Group Source | Sort Count –desc | Select Count,Name | ft –auto
When faced with a task like, this start small and test each portion of the pipelined expression. Don’t try to write it all in one go. But when you have this worked out, you can easily turn it into a simple script so you don’t have to type all of this. Here’s my simple script that uses parameters with some default values. Because I only have to write this once, I’m using full cmdlet and parameter names.
#requires –version 2.0
Param ([string]$Logfile="Application", [string]$Computername=$env:computername)
Write-Host "Getting logs from $logfile on $computername" –foregroundcolor Cyan
get-eventlog –Logname application –computername $env:computername | Group-object -property Source | Sort-object -property Count –descending | Select-Object -property Count,Name
I can run the script with default values or specify a computer name. The one addition I made was to add a Write-Host line to indicate what the script is doing because it might take a few minutes to query all the logs. I always use a color with Write-Host so I can tell what is console output and what is pipelined output.
If I wanted to format the results and save to a text file, because the script writes to the pipeline, all I need is an expression like this:
PS S:\> .\Beg5_2012.ps1 | format-table -autosize | out-file c:\work\applog.txt
Think about what you are trying to do, and seek Help in Windows PowerShell. Then when scripting, always think about writing objects to the pipeline and leave formatting out of the script so you have maximum flexibility.
2012 Scripting Games Guest Commentator Week Part 2 will continue Monday when we will present the scenario for Event 6. Join me tomorrow for a wrap-up blog about the 2012 Scripting Games.
I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at email@example.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson, Microsoft Scripting Guy
Thanks a lot, Jeff. One this you've missed is to use the parameters with the cmdlets in the sample script, like
get-eventlog –Logname $Logfile –computername $Computername