Learn about Windows PowerShell
Summary: Microsoft Scripting Guy, Ed Wilson, shows how to use Windows PowerShell to find the date for a specific holiday by using a web service.
Hey, Scripting Guy! I have a problem. I guess you hear that a lot. Anyway, my boss has given me what I think is an impossible task—to find the holidays we have coming up this year. Not just a list of the standard holidays, but the actual days they will be celebrated. I know there is a holiday thing I can turn on in Microsoft Outlook, and I thought about trying to write a script that would find holidays marked in my Outlook Calendar, but I suspect that my boss has other ideas. You see, he never tells me what is on his mind. It is always just a series of seemingly random requests. I really wish he would clue me in on what goes on in his fuzzy-headed brain, but that is a different story—so I have to try and anticipate him and that is not easy. Anyway, I suspect, eventually he wants a script that will be able to do something with holiday dates—got any clues, ideas, or suggestions, oh, scripting wizard?
Microsoft Scripting Guy, Ed Wilson, is here. This morning seems cold. A quick look outside reveals frost on the ground. In Charlotte, North Carolina, in the southern portion of the United States, having frost on the ground is not a normal event. In fact, I would not be surprised if they called off school. But as the old song goes, the weather outside is frightful, but the fire inside is delightful. Yes, I turned on the fire when I came down and saw the glittering grass in the early morning sunlight. I also decided today would be a good coffee day. The Scripting Wife had a nice bag of Kona coffee shipped from the island of Kauai, Hawaii, for me, and today seems like a nice day to open it. When I make coffee, I grind fresh beans, use fresh spring water, and I employ my French press. I usually use turbinado raw sugar, but today I am using crushed rock sugar I brought back from Munich—it is actually a nice addition. For me, I want to taste the coffee, not cheap flavoring. Nor do I want to drink a glass of warm milk with a shot of coffee in it.
GG, there may be a completely international web service that returns holiday information, but I was unable to find one doing a few Bing searches. I was able to find a web service that contains holiday information for a few countries. I found the HolidayService2 web service. The service defines six methods. Opening the URL in Internet Explorer shows the six methods.
To use a method from a web service, I use the New-WebServiceProxy cmdlet, and I store the returned object in a variable. When using the New-WebServiceProxy cmdlet, the most important parameter is the URI for the web service. For this example, the class and the holiday parameters do not matter. To make things more readable, I always store the URI for the web service in a separate variable. I end up with two lines of code, as shown here.
$URI = "http://www.holidaywebservice.com/HolidayService_v2/HolidayService2.asmx"
$proxy = New-WebServiceProxy -Uri $URI -Class holiday -Namespace webservice
All I need to do now is figure out how to use the web service. This particular web service is really nice because it is based on the .NET Framework, and it returns .NET objects—I will get to that in a minute. First, I need to know what countries or regions are supported by the web service. To do this, I call the GetCountriesAvailable method.
Note Keep in mind this web service is case-sensitive. Therefore, UnitedStates must be cased as shown (I cannot do everything in lowercase as I often do), as it is required for the other countries or regions and holidays.
To call GetCountriesAvailable, I begin typing and use the tab expansion to complete the method name. This command is shown here.
The command and associated output appear in the image that follows.
OK, so I know what countries or regions the service supports. Now I need to know what holidays the service supports. To do this, I call the GetHolidaysAvailable method, as shown here.
The neat thing about the service returning objects is that I can pipe the returned objects to other Windows PowerShell cmdlets. For example, looking through a random listing of holidays may not be too illuminating, but if I sort them alphabetically, it makes things easier to see. This command is shown here.
$proxy.GetHolidaysAvailable("UnitedStates") | sort code
The command and associated output appear here.
Hey, want to know the difference between holidays celebrated in Northern Ireland and the holidays celebrated in the Republic of Ireland? I call the GetHolidaysAvailable method twice (once for each region), store the results in variables, and pass the resultant objects to the Compare-Object cmdlet. Piece of cake. The three commands are shown here.
$in = $proxy.GetHolidaysAvailable("IrelandNorthern") | sort code
$ir = $proxy.GetHolidaysAvailable("IrelandRepublicOf") | sort code
Compare-Object -Property code -ReferenceObject $in -DifferenceObject $ir
The commands and the associated output are shown here.
Now, I can figure it out. It might take a bit of time. A few of my attempts are shown here.
Rather than cluttering up my Windows PowerShell console with red, how about if I go back to the HolidayService2 web page and look at the parameters for the GetHolidayDate method. In fact, there is even a little form I can use to see if what I am thinking about using will actually work. The web page with the form and the SOAP definition are shown here.
So, the correct way to call the GetHolidayDate method appears here.
PS C:\> $proxy.GetHolidayDate("UnitedStates","LABOR-DAY",2013)
Monday, September 2, 2013 12:00:00 AM
Notice that the returned date looks amazingly like the good old-fashioned System.DateTime object we PowerShellers know and love. Once again, because this web service returns .NET objects, I can do some really cool Windows PowerShell stuff. For example, if I want to know how long it is until Labor Day in the United States, I can use the New-TimeSpan cmdlet, as shown here.
PS C:\> New-TimeSpan -Start (get-date) -End ($proxy.GetHolidayDate("UnitedStates","LA
Days : 196
Hours : 11
Minutes : 19
Seconds : 45
Milliseconds : 909
Ticks : 171479859090373
TotalDays : 198.472059132376
TotalHours : 4763.32941917703
TotalMinutes : 285799.765150622
TotalSeconds : 17147985.9090373
TotalMilliseconds : 17147985909.0373
GG, that is all there is to using a web service to work with holidays. It should be much easier for you than attempting to parse your Outlook calendar. Join me tomorrow when I will talk about a cool function I wrote to determine if a command exists or not in Windows PowerShell.
I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at firstname.lastname@example.org, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson, Microsoft Scripting Guy
From where do we get the -Class and -Namespace values ? Or can we put anything there ?
Sameer, nobody seems to want to answer your question, but I have the same question. Where did the values 'holiday' and 'webservice' come from?
Technet's page for New-WebService seems circular and doesn't really answer the question, either. For class: "The value of this parameter is used with the Namespace parameter to provide a fully qualified name for the class. The default value is generated from
Okay, in Ed's example, there are three instances of the word 'holiday' in the URI. Not helpful. Back to Technet:
For Namespace: "The value of this parameter is used with the value of the Class parameter to generate a fully qualified name for the class. The default value is Microsoft.PowerShell.Commands.NewWebserviceProxy.AutogeneratedTypes plus a type that is generated
from the URI."
Well, again there is an occurrence of 'webservice' buried in the URI, but how I would deduce the Namespace for a different webservice? Don't know.
While tinkering around, I used different values for -class and -namespace, namely 'vacation' and 'holidayservice' respectively, neither of which are in the URI. The commands worked just fine.
Finally, I created a proxy without bothering with -class and -namespace:
$proxy = New-WebServiceProxy -Uri $URI
and had no problems duplicating the rest of the examples on this page. There may be instances where -class and -namespace are necessary, but not in the examples that Ed or Technet have provided.
Have you tried this?
PS C:\scripts> $proxy = New-WebServiceProxy -Uri $URI -Class kibiddle -Namespace GoFigure
PS C:\scripts> $krispie=New-Object GoFigure.kibiddle
PS C:\scripts> $krispie
The "class" and "namepace" arguments are used to prevent conflict or to merge objects.
This is what we would normally do:
PS C:\scripts> $URI = "http://www.holidaywebservice.com/HolidayService_v2/HolidayService2.asmx"
PS C:\scripts> $proxy = New-WebServiceProxy -Uri $URI
PS C:\scripts> $proxy|gm
Name MemberType Definition
---- ---------- ----------
Disposed Event System.EventHandler Disposed(System.Object, System.EventArgs)
GetCountriesAvailableCompleted Event Microsoft.PowerShell.Commands.NewWebserviceProxy.AutogeneratedTypes....
GetHolidayDateCompleted Event Microsoft.PowerShell.Commands.NewWebserviceProxy.AutogeneratedTypes....
GetHolidaysAvailableCompleted Event Microsoft.PowerShell.Commands.NewWebserviceProxy.AutogeneratedTypes....
GetHolidaysForDateRangeCompleted Event Microsoft.PowerShell.Commands.NewWebserviceProxy.AutogeneratedTypes....
GetHolidaysForMonthCompleted Event Microsoft.PowerShell.Commands.NewWebserviceProxy.AutogeneratedTypes....
GetHolidaysForYearCompleted Event Microsoft.PowerShell.Commands.NewWebserviceProxy.AutogeneratedTypes....
Abort Method void Abort()
BeginGetCountriesAvailable Method System.IAsyncResult BeginGetCountriesAvailable(System.AsyncCallback ...
BeginGetHolidayDate Method System.IAsyncResult BeginGetHolidayDate(Microsoft.PowerShell.Command...
BeginGetHolidaysAvailable Method System.IAsyncResult BeginGetHolidaysAvailable(Microsoft.PowerShell.C...
BeginGetHolidaysForDateRange Method System.IAsyncResult BeginGetHolidaysForDateRange(Microsoft.PowerShel...