PowerShell $_


In my previous post — my first blog ever! — I gave a high level overview of PowerShell. I tried to provide enough material to make it immediately useful.

But in order to see how typing could possibly be more efficient then clicking around with a mouse, I need to introduce a few more basic constructs.

Here is a (contrived) hypothetical: I log onto a production machine that far too many people have access to. And I see something strange. iTunes is installed. Why would someone install iTunes on a production machine? I need to find out who installed it and decide whether I can safely remove it.

The graphical way:

  1. For starters, in Windows 8.1, it just took me almost five minutes just to find the Event Log Viewer Application…. but that’s a rant for another day.
  2. I click on the “Application” log, but see lots of useless metadata (such as a bunch of event entries with a “Task Category” of “None.”)
  3. So I randomly click on a log entry. The bottom half of my screen shows details. Do I have to read all the details for each entry? Should I have chosen another career path?
  4. I move down to the next event log entry. More of the same. The text just blurs together.
  5. Now I notice an option on the right side of my screen to “Filter Current Log…”
  6. But I click on this and am already lost. What could the correct “Event level” be? What about the “Event sources” or “keywords?” This did not help.
  7. This is where I am thinking it’s time to hire an intern.
Windows Event Viewer

Windows Event Viewer Chaos – Now What?

And now the PowerShell way:

  1. I launch PowerShell (I have it pinned to my Windows desktop).
  2. I type: Get-EventLog Application | ? {$_.Message -like "*itunes*"} and get this:
    PowerShell: list of iTunes install events

    PowerShell: list of iTunes install events

  3. Hmmm. Id 152 looks interesting. I type: (Get-EventLog Application | ? {$_.Index -like "152"}).UserName PowerShell thinks for a second and then replies back with this: Peter
  4. So I go talk with Peter and find out he installed it by accident. He promises to be more careful next time.
  5. Life is good.

Advanced Aside: in PowerShell, there are MANY ways to do the same thing. For example, starting with PowerShell V3, I could have typed Get-EventLog Application | ? Message -like "*itunes*" instead of Get-EventLog Application | ? {$_.Message -like "*itunes*"}. Or I could have listed all properties of Index 152, instead of just the UserName. Or I could have formatted the results of my first query as a list instead of a table.

Now to Explain What I am doing in step 2

  • Get-EventLog Application: The word “Application” is called a parameter. With an important exception (called a switch), parameters are name/value pairs, that look like this: Verb-Noun -ParamaterName -ParamaterValue. So in my case I would type Get-EventLog -LogName Application. But when I type help Get-EventLog -Full (note help is short (an alias) for Get-Help) I see a detailed explanation of the parameter -LogName including this information: Position? 1. This means -LogName is what is called a positional paramamter, meaning that if the value appears in a certain position after the cmdlet (in this case first), then the name -LogName is not required. This helps shorten the amount I have to type into the PowerShell host, since PowerShell is all about user efficiency. So instead of typing Get-EventLog -LogName Application, I just type Get-EventLog Application.

    Advanced Aside: -Full is an example of a switch, i.e. it is like a parameter with a name/value pair but it only has a name, no value. In other words, it is a Boolean indicator where it’s absence is like “false” and its presence is like “true.” So when I type help Get-EventLog -Full I am turning on a property (more information) for the cmdlet.

  • | (pronounced pipe): Indicates that the output to the left of the pipe becomes the input to the right of the pipe. So in my case, the result of Get-EventLog Application becomes the input for ? {$_.Message -like "*itunes*"}.
  • ? — The “?” is NOT a typo. It is short (an “alias” for) Where-Object, another cmdlet. In other words, I am taking the results on the left side of the pipe and searching only for results WHERE
  • {$_.Message -like “*itunes*”}: OK, this is the hardest part for me to explain. For starters, the stuff between { and } is called a script-block. It is basically an expression that we are asking PowerShell to evaluate. Buried in the middle of our script block is -like. This means our script block expression is a Boolean expression; within the script block, we are comparing something on the left side of -like to something on the right hand side of -like. In other words, if the something on the left side is ALIKE to what is on the right side then the expression is true. In our case, we are comparing $_.Message to "*itunes*".

    Hopefully the "*itunes*" part is pretty self-explanatory. It’s just looking for any strings (case-insensitive) that contain the text “iTunes.” $_.Message requires some discussion, however. Remember that everything in PowerShell is an object. The syntax “$_” is equivalent to the keyword this in C#. In other words, $_ means the instance of this object (where each object is one row/entry from Get-EventLog Application. The . (period) after $_ tells us we are looking at the property of an object. This is just like many other programming languages. In C#, for instance, we could type string x = "hi"; int length = x.Length where x is an instance of a string (an object) and x.Length is the property Length on the object x. So in summary, $_.Message means we are looking at the property Message on the current instance of whatever object came in from the left side of the pipe (an entry in the EventLog).

    Now things get more fun…. If we run the left hand side of our pipe statement (Get-EventLog Application) by itself, we would find a lot of results. This makes sense. Surely the computer has more than one entry in the event log. So we are actually piping to the right hand side ? {$_.Message -like "*itunes*"} each EventLog entry individually. And the right hand side of our pipe is outputting to us every EventLog entry in which the -like expression is true. So PowerShell is showing us EVERY Application EventLog entry in which the “Message” contains “iTunes” (case-insensitive).

  • Finally, notice in step 3 I wrapped the entire command in parenthesis ( and ) and then added the .UserName. That enabled me to hone in on just the specified property I was looking for, the user who installed iTunes. I could just have easily typed: Get-EventLog Application | ? {$_.Index -like "152"} and gotten back all of the properties, including UserName.
Advanced Aside: Although I ran this example against the event log on my local machine, I could just have easily used PowerShell on my local machine to check event logs on remote machines. It is not necessary to remote desktop into a remote machine to check event logs using PowerShell. If you are interested, check-out these two PowerShell commands: Invoke-Command and New-PSSession.

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 )

Google+ photo

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

Connecting to %s