Taking PowerShell on a date

I needed to filter the event logs from a remote computer for power off events. The user was powering it off himself every now and then, but wouldn’t believe me when I said so. No problem, thanks to the event logs all his shutdown requests are logged so it’s only a matter of culling it out.

I could have user Event Viewer but PowerShell is way easier. I only need to check the System event logs for any events with ID 1074. Further, for every shutdown, events with this ID are logged twice – one starting with the line “The process C:Windowssystem32winlogon.exe …” the other starting with the line “The process Explorer.EXE has initiated the power off …” – so I’d like to filter the output to just include one of these lines. Finally, I’d also like the day of the week to be shown.

So here’s what I did:

So far so good. I use Get-WinEvent to return the event logs I want, use the Message property of these returned objects to filter logs containing just the text we want. And finally I use the TimeCreated property of these objects to display the time and day. This TimeCreated property is the subject of this post so let’s focus on that further.

First, how do we get the members and properties of the objects returned by Get-WinEvent? Here’s how:

Notice the TimeCreated property.

The TimeCreated property is an object of class DateTime. To get the day of the date instance, use the TimeCreated.DayofWeek property. Which is what I extract via the Format-Table expression in my initial code:

This post from the “Hey, Scripting Guy! Blog” is a good read on Get-WinEvent and the DateTime class.

Focussing on the DateTime class, this is the type of the object returned by the get-date cmdlet too. Although not obvious from the syntax of the get-date cmdlet, you can use it to return a DateTime object instance of the date you specify as string. Like thus:

What’s more, you can even format the string:

The -Format switch takes a format specifier. As seen above “dd” stands for the date, “ddd” stands for the day in short-hand, “dddd” stands for the date in longhand, and so on.

You can also typecast a string to the DateTime class:

The typecast technique has a limitation though in that it expects the input to be in the format of US, i.e. “MM/dd/YYYY”. The DateTime class has a static member called Parse(), however, that is smart enough the use the country/ culture of the computer.

How do we parse the date if it’s in a different format though? Both the get-date cmdlet and the [datetime]::Parse() method fail if the input string does not match the date format of the computer:

It is possible to specify the date format of the input string. This only works with the Parse() method though. Like thus (thanks to this blog post):

The Globalization.cultureinfo class has a GetCultureInfo() method, so what we are doing above is we create a variable that is an instance of the “en-US” culture and then pass this variable to the Parse() method so it knows which format to parse the input in. Of course we could have also specified the whole thing on one line:

Let’s examine the Globalization.cultureinfo class. First, let’s examine its static members and properties:

The GetCulture() method can be used to list all available cultures:

To get details about a specific culture use the GetCultureInfo() method:

The LCID corresponds to the Locale ID assigned by Microsoft. To see all the properties use the get-member cmdlet or format-list to see the values:

On the topic of dates, the DateTimeFormat property seems interesting:

Notice the ShortDatePattern above. This is exactly what the -Format switch of Get-Date cmdlet expects, so one can use this to format the output of Get-Date in a different locale. Like thus:

So now we have seen to use the [datetime]::Parse() method to parse an input string into a DateTime object while specifying the country format of the input string. We have also seen how to output the result of get-date in the format of a different country. Both methods use the [Globalization.cultureinfo] class.

Lastly, there is an easy way to parse any string – irrespective of whether it matches the format of a country or not – into a DateTime object via the ParseExact() method. This is worth mentioning as without such a method one would have to resort to regular expressions and such!

In the example below we match an input string with time “02:50PM” by specifying the format as “hh:mmtt” to the ParseExact() method.

I am not sure what the third parameter of this method is supposed to be. Most examples put it as $null. It seems to take a “culture” as input, but I am not sure how it affects the output. Instead of $null the following too seem to work: $(get-culture), [Globalization.Cultureinfo]::GetCultureInfo("en-US") (“en-GB” too works), and [Globalization.Cultureinfo]::InvariantCulture.

The format can contain other text too. Escape the characters of such text with a slash or put the text within quotes ':

And just to show what happens if the format does not match:

Thanks to these two posts for showing me ParseExact().