Windows PowerShell, Invalid Certificates, and Automated Downloading

ScriptingGuy1

Summary: If a trusted website has an expired or self-signed certificate, you must ignore the error to use Windows PowerShell with the website.

 

Microsoft Scripting Guy Ed Wilson here. Years ago I used to teach MCSE training classes and one of my favorites was a course on troubleshooting. Because I was a consultant by day and instructor at night, I would often bring in anecdotes from problems I had solved that very day. I remember one Microsoft PowerPoint slide from that class particularly well. It displayed the way IT pros solve problems. At that time, something like 45 percent of the solutions were found on TechNet, 15 percent of the problems were solved based on experience with similar problems, and 25 percent of the problems were solved by luck. The remainder of the solutions were discovered by asking for help and other methods. It is unclear if the luck was a result of “when in doubt reboot” approach to troubleshooting, or if the preemptive reboot was classified in the experience part of the pie. What is clear is that luck does indeed play a part of the IT pro’s toolkit.

Today I am the beneficiary of such luck. I have had a problem with Direct Access for over three weeks. Actually; there has been no problem with Direct Access because it has not worked. It was going great until our IT department made a change to cut over to another configuration. And then it died. Of course, I opened a ticket with the help desk that was eventually escalated to Tier 2 support. Still no go.

Today, I solved the problem. I wanted to watch a video about the new Windows 7 phone and it required an update to Silverlight. The Silverlight update failed, so I could not watch the video—now things are becoming serious. Direct Access is one thing (I can, of course, use VPN for Corpnet access so the situation was not critical). When the Silverlight update failed, there was a link to a TechNet KB article. I followed it step for step, and step 3 was check to see if the Windows Installer Service was disabled. On my computer it was, and that was the problem. A quick reboot and my Direct Access problem (the setup was failing) and my Silverlight problem both went away. There are all kinds of lessons from this story. Three lessons stand out:

1. Document configuration changes made to workstations.

2. Return meaningful errors from scripts.

3. Read the errors that are returned from application setup. If a link is offered, check it out—they are getting better all the time

I received a tweet the other day from SQLVarient on Twitter, and he was having a problem downloading a file from within Windows PowerShell. The problem is that the website he was connecting to has an invalid certificate, and the site required HTTPS. When using the DownloadFile method from the System.Net.WebClient .NET Framework class, the download will fail if the website has an invalid certificate. There are many reasons for a certificate to be invalid, a few of which are listed here:

1. The certificate is expired.

2. The certificate is from an untrusted certificate authority (CA).

3. The name on the website does not match the name on the certificate.

There are very good reasons that Internet Explorer warns you about a website that has an invalid certificate. An example of such a warning is shown in the following image.

Image of invalid certificate error in Internet Explorer

If a certificate is from an untrusted CA, that is like trusting a room recommendation on a travel site that you do not know anything about. How do you know the travel recommendation is legitimate or bogus? If you see a travel recommendation on a legitimate website but it is from five years ago, how do you know if the hotel is still any good? On the other hand, if you see a great recommendation for a hotel, but the name of the hotel is different from the one you are looking at, how do you know the recommendation applies to the hotel you are thinking of booking? If you have additional information, you might be able to make a determination. But with just the information presented, the safe decision is to ease on down the road.

When SQLVariant asked about downloading a file from a particular site that had a bad certificate, he was familiar with the site and wanted to automate file downloading from a site that changes on a regular basis.

Though the DownloadFile method is not overloaded to allow you to specify an override for invalid certificate check, there is a delegate that can be used to set up a callback for the ServerCertificateValidationCallback static method from the System.Net.ServicePointManager .NET Framework class. Windows PowerShell 2.0 can use a script block to create a delegate. Delegates are like .NET Framework versions of function pointers. Function pointers are used in C, C++, and other languages, and they are indirect references to functions and enable you to do things such as pass a function as a parameter to another function. The difference between .NET Framework delegates and function pointers is that the .NET Framework delegates are type safe, and function pointers point to raw bytes of memory.

The Get-WebFileFromServerWithInvalidCertificate.ps1 script begins by creating some command-line parameters. The parameters are the URL of the website, the file to hold the downloaded page or file, and the force switch that will cause the script to override a certificate problem and continue to the file. The param section of the script is shown here:

Param( [string]$url, [string]$file, [switch]$force )

The Get-WebPage function begins with exactly the same parameters that mark the beginning of the script. The advantage of this is that it allows you to run the script without needing to dot-source a function into your Windows PowerShell console, or copy a function into your profile. After the parameters are created, the function looks to see if the $force variable is present. If it is, the script was run with the –force switched parameter, and therefore it will override an invalid certificate. This portion of function is shown here:

Function Get-WebPage { Param( $url, $file, [switch]$force ) if($force) {

The static ServerCertificateValidationCallback method from the System.Net.ServicePointManager .NET Framework class receives $true from a script block. This is the delegate return code, as shown here:

[Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}

After this is done, the System.Net.WebClient .NET Framework class is created. The returned object is stored in the $webclient variable. The DownloadFile method accepts two parameters. The first is the URL to connect to, and the second is the file and path to save the file to. This is shown here:

$webclient = New-Object system.net.webclient $webclient.DownloadFile($url,$file) } #end function Get-WebPage

The entry point to the script calls the Get-WebPage function and passes the url, file, and force parameters to the function:

 

# *** Entry Point to Script *** Get-WebPage -url $url -file $file –force

 

The complete Get-WebFileFromServerWithInvalidCertificate.ps1 script is shown here.

Get-WebFileFromServerWithInvalidCertificate.ps1

Param( [string]$url, [string]$file, [switch]$force ) Function Get-WebPage { Param( $url, $file, [switch]$force ) if($force) { [Net.ServicePointManager]::ServerCertificateValidationCallback = {$true} } $webclient = New-Object system.net.webclient $webclient.DownloadFile($url,$file) } #end function Get-WebPage # *** Entry Point to Script *** Get-WebPage -url $url -file $file -force

Tomorrow, we will begin a series of articles about string manipulation. We would love for you to follow us on Facebook. If you have any questions, send email to us at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

 

Ed Wilson and Craig Liebendorfer, Scripting Guys

0 comments

Discussion is closed.

Feedback usabilla icon