Summary: Write a Windows PowerShell function to determine the status of time changes to daylight savings time.
Microsoft Scripting Guy, Ed Wilson, is here. At the Windows PowerShell User Group meeting in Charlotte, North Carolina, Brian Wilhite talked about a few of his scripts during the script club. I said, “Dude, that is cool, and I immediately challenged Brian to share his scripts with us. The result is two excellent guest postings. Here is the first one.
Brian Wilhite works as a Windows System Administrator for a large health-care provider in North Carolina. He has over 15 years of experience in IT. In his current capacity as a Windows SysAdmin, he leads a team of individuals that have responsibilities for Microsoft Exchange Server, Windows Server builds, and management and system performance. Brian also supports and participates in the Charlotte PowerShell Users Group.
Twitter: Brian Wilhite
Here’s Brian…
Just prior to the latest time change in the fall, I was asked to run a time verification script on all of our computers running Windows Server. Typically, this was done after the time change, between 1:00 AM and 2:00 AM. Being an IT Guy, I’m used to long days and/or long, late nights, but I thought to myself, “I wonder if I can be proactive in knowing which servers may have problems making the change this year.” So I researched, and found the Win32_TimeZone WMI Class and all the goodness therein. Here is some of what I found:
Get-WMIObject –Class Win32_TimeZone
DaylightDay : 2
DaylightDayOfWeek : 0
DaylightMonth : 3
DaylightName : Eastern Daylight Time
Description : (UTC-05:00) Eastern Time (US & Canada)
StandardDay : 1
StandardDayOfWeek : 0
StandardMonth : 11
StandardName : Eastern Standard Time
So…
Like I always do when I evaluate WMI classes, I performed a BING search on MSDN Win32_TimeZone.
After I reviewed all of the information there, specifically DaylightDay, DaylightDayOfWeek, etc., I determined that I could, in fact, proactively identify servers that could have time change issues on the day of the time change.
This excerpt from the MSDN website sums it all up:
If the transition day (DaylightDayOfWeek) occurs on a Sunday, then the value “1” indicates the first Sunday of the DaylightMonth, “2” indicates the second Sunday, and so on. The value “5” indicates the last DaylightDayOfWeek in the month.
I took this information and started thinking, “I can write a function that will gather this information and report what it finds.” So here’s what I did…
First, I created the framework for an advanced function. It contains the usual items, such as: CmdletBinding, defining parameters, setting up the Begin, Process, Try, Catch, and End Script blocks. This is shown in the following image.
Next, I started thinking of all the data that I wanted to capture. I know I will need the Win32_TimeZone WMI class. Because in the past, we always checked for current time, I will also query the Win32_LocalTime. Therefore, here is the start of the processing part of the Get-DSTInfo function:
As you see in the previous image, I casted the $LocalTime variable as a DateTime object by passing it a string that is comprised of variables made up from the Win32_LocalTime WMI class. I will use this later to create a custom PSObject, which will allow you to treat this property as a DateTime object, if needed.
I also captured the WMI class that’s going to gather all the data to make the magic happen, the Win32_TimeZone class. You may have noticed the switch statement for the $TimeZone.DaylightDay property. Because the value is numeric and not “display friendly,” I set up several switch statements. They are shortened for brevity, but you get the idea:
Switch ($TimeZone.DaylightDay)
{
1 {$DSTDay = “First”}
2 {$DSTDay = “Second”}
#From 1 to 5 signifying the First through Last week in the month.
}
Switch ($TimeZone.DaylightDayOfWeek)
{
0 {$DSTWeek = “Sunday”}
1 {$DSTWeek = “Monday”}
#From 0 to 6 to signify the days of the week.
}
Switch ($TimeZone.DaylightMonth)
{
1 {$DSTMonth = “January”}
2 {$DSTMonth = “February”}
3 {$DSTMonth = “March”}
#From 1 to 12 to signify months of the year.
}
OK. So consider the following properties of the $TimeZone object, which is an instance of Win32_TimeZone.
$TimeZone.DaylightDay = 2
$TimeZone.DaylightDayOfWeek = 0
$TimeZone.DaylightMonth = 3
These property values will mean the “spring ahead.” The time change will occur on the “Second (2) Sunday (0) of March (3)”. The same thing holds true with the $TimeZone.StandardDay, $TimeZone.StandardDayOfWeek, and $TimeZone.StandardMonth—but obviously, they will have different values.
When all of my switch statements were setup (six in total), I created several objects depending on what parameters were passed when running the function. The two parameters that I defined were -Standard and -Daylight. Neither parameter is mandatory because running the function without parameters will return both Standard and Daylight time change information in the form of a PSObject for the local host that is stated. Here is the If statement that I used to accomplish neither parameter being passed:
If ((-not $Standard) -and (-not $Daylight))
{
$STND_DL = New-Object PSObject -Property @{
Computer=$Computer
StandardName=$STDTime
StandardDay=$STDDay
StandardDayOfWeek=$STDWeek
StandardMonth=$STDMonth
DaylightName=$DayTime
DaylightDay=$DSTDay
DaylightDayOfWeek=$DSTWeek
DaylightMonth=$DSTMonth
CurrentTime=$LocalTime
}#End $DL New-Object
$STND_DL = $STND_DL | Select-Object -Property Computer, StandardName, StandardDay, StandardDayOfWeek, StandardMonth, DaylightName, DaylightDay, DaylightDayOfWeek, DaylightMonth, CurrentTime
$STND_DL
As you may have noticed, I did something pretty cool. If you have played with custom objects in Windows PowerShell, you know that they don’t always display the properties the way you would like them to. So, I piped my custom PSObject ($STND_DL) to the Select-Object cmdlet to display the object properties in logical order as you read it—something that makes logical sense to a variable.
This is what you get when you run the function; the output is an object that you can have your way with:
Yes, you read that right, 3:49AM. Like I said, I’m not a stranger to long late nights—after all, I am an IT Guy.
Getting back to the topic…
You could also pipe computer names to Get-DSTInfo, something like the following:
Get-ADComputer –Filter * | Select –Expandproperty Name | Get-DSTInfo | Export-Csv –Path C:\TimeZoneInfo.csv
This would gather all the computers in your domain and run the Get-DSTInfo function against them, then export the findings to a .csv file. The way you would read the object output is that the time change would occur the First Sunday of November and Second Sunday of March.
This function allowed me to proactively review the time change information of all 1500+ servers in our domain. The great thing is that I did find a few that did not have the correct time change patch installed, and I was able to remediate that before it became an issue when the clocks turned back last fall.
Thanks for listening to me ramble on about my simple but useful function. Happy PowerShelling!
~Brian
Thank you, Brian. The full script can be found on the Script Center Repository.
I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson, Microsoft Scripting Guy
0 comments