Advanced Parameter Validation (revisiting get-filehash)
I am currently working on the rebuild of my template for all of my PowerShell scripts, trying to do things "better" this time around. I have learnt a few things over the last hour, one of which I don't understand (but everything works if I do it, so I will keep doing it), and another I just had to write about.
What is the great new thing? Well I wish i had known about it earlier, its the advanced parmater validation features.
Let's take a look at the first few lines of the get-filehash (original article, update) method I wrote about previously.
Now, I removed the comment based help syntax for brevity, but it is a little long, and there is the annoying enum defining the valid hash values to deal with as well, and then the section validating the file is a path etc. What if we could clean this all up?
Lets see:
Its a lot cleaner!
What we have is a ValidateScript, which is performing a test-path on the input. I am using the -pathtype 'leaf' to ensure we are hashing a file, not a folder. Then we have a ValidateSet, here we are saying, lets confirm the value for that parameter is in this array.
If either of these validations fail, we will get an error message along the lines of:
Get-FileHash : Cannot validate argument on parameter 'File'. The "Test-Path $_ -PathType 'leaf'" validation script for
the argument with value "D:\WIP\powershell\FileHash\filehash.jljdklf" did not return true. Determine why the
validation script failed and then try the command again.
At line:1 char:20
+ Get-FileHash -File D:\WIP\powershell\FileHash\filehash.jljdklf
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Get-FileHash], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Get-FileHash
Get-FileHash : Cannot validate argument on parameter 'File'. The "Test-Path $_ -PathType 'leaf'" validation script forthe argument with value "D:\WIP\powershell\FileHash\filehash.jljdklf" did not return true. Determine why thevalidation script failed and then try the command again.At line:1 char:20+ Get-FileHash -File D:\WIP\powershell\FileHash\filehash.jljdklf+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidData: (:) [Get-FileHash], ParameterBindingValidationException + FullyQualifiedErrorId : ParameterArgumentValidationError,Get-FileHash
Not bad is it?
Another option to check out is ValidateRange. As you can guess, it allows you to validate the parameter against a range. An example would be [ValidateRange(1,10)], which will validate the paramater to ensure it is between 1 and 10!
Here is the new get-filehash in full...
Accessing the Internet from PowerShell: Get-WebPage Part2
Welcome back.
So last time we looked at the get-webpage CMDLet, but first, you may notice that it is different from this version of this CMDLet to that I showed off at Infrastructure Saturday; your right, it has been updated. The update is to make supplying user-agent headers more easily.
Let’s go back to the get-externalip function we defined a few months ago. Previously it was:
Now if we make use of the cmdlet we just finished:
Pretty neat?
I will leave it here, explore the cmdlet on your own.
Accessing the Internet from PowerShell: Get-WebPage Part1
So last time we looked at accessing the web from PowerShell, we looked a simple function which returned our external IP address, we then used that function to make a script to automatically alert us when our external IP address changed. This was a pretty simple function and script, but I want to spend some time discussing some of this further and build a full CMDLet.
In later posts I want to discuss how I believe you should design your PowerShell code, including CMDLets, functions, scripts and modules, but I want to touch on some of this today.
In the get-externalip function, we have simply created the .Net framework webclient object, set up some headers, and the called the downloadstring method. This is fine for this simple script, but it isn't great design in the long term. What we need is a CMDLet that downloads a URL from the internet (or maybe a local source) and then make use of that CMDLet. The CMDLet should enable us to have a powerful framework where we can easily leverage all of the webclient class functionality, but in a refined and controlled PowerShell manner.
We should also ensure that we provide all the help and documentation with our CMDLets, so anyone can use them. For this we will use the PowerShell Comment Based Help Syntax, something that is an over looked part of PowerShell. Seriously, Microsoft should be encouraging more use of this, every language has something like similar to this, it’s not something special in PowerShell, but if every PowerShell developer used the comment based help syntax, the world would be a much better place.
Let’s take a look at a CMDLet that will get the HTML representation of a page, this CMDLet will also allow us to set things like the proxy server, headers, credentials for the remote page and the user agent!
The CMDLet below is based upon my Infrastructure Saturday 2012 presentation on PowerShell.
Whoa, quite a bit here, around 100 lines of code! Most of which though is documentation. As you can see, we have the start of the function definition, then the comment based help syntax. This syntax is providing documentation for the get-help CMDLet, including descriptions, parameters, inputs, outputs and examples.
Next we have the CMDLetBinding, we are not specifying anything extra here, just telling PowerShell that this is a CMDLet.
After this we have parameters, there all look pretty simple, only one is mandatory, URL. I have also specified types for all of the parameters. Whilst the specification of types is option, I am not doing this wherever possible, it reduces errors and provides very useful input validation.
Now we have the body of the CMDLet. As expected, we are making a new instance of the WebClient class. Then we have some if statements. If these optional parameters have been specified, then we need to set the various parts of the WebClient object.
I hard set the encoding, it makes things simple an easy.
We then create an object to hold the result, and within a try {} catch{} block will call download string. If we do catch any errors, simply throw them to the calling code. We don’t particularly care about handling errors here, the calling code should; however its crucial to handle errors in a controlled manner.
Finally return the resulting page.
Next time we will look at some examples and some further discussion of the code.
Update to Hashing Post
Just decided to make the CMDLet in the article: PowerShell File Hashing , a little more clear by renaming it to Get-FileHash, it makes more sense in the long run in my head, and explains what the CmdLet does.
Git to Azure
Just a quick guide on publishing web content to Windows Azure using Git!
First things first, make sure you have TortoiseGit and its dependencies installed, and create a new Windows Azure web site in the management console.
For this example, we will be publishing out own mirror of the http://isitup.org site. The sites code is available from GitHub here: https://github.com/sjparkinson/isitup
Let's begin!
Part 1 - Configuring Windows Azure for Git
- Visit https://manage.windowsazure.com
- Select the website you wish to use Git to publish to
- Select "Setup Git publishing"
- If you have never specified deployment credentials, select "reset deployment credentials" and specify a username and password
- Note down the Git Clone URL
Part 2 - Pulling and Pushing with Git
- In your local working copy folder, right click and select "Git Clone"
- The URL will be "https://github.com/sjparkinson/isitup"
- The directory will be the base URL for the Git working copy/repository for me "c:\users\defaultusername\workinprogress"
- Hit ok
- wait for a sucess message, and hit close
- Right click on the isitup folder, select TortoiseGit, and then Push
- select "Arbitary URL" enter the URL noted earlier
- Hit OK
- Enter your password
- Wait for completion
- DONE!!!
One I prepared earlier http://isitup.azurewebsites.net
PowerShell file hashing
So, I was reading the Microsoft Security Response Centres post on verifying your Windows Update files, available here, and saw their comments about using PowerShell to verify the upates. They used some code from Mike Wilbur's Blog, here, which is a nice simple little bit of code to get your SHA256 hashes for files.
I decided that the world needed something a bit more, and started to see if we could make a cmdlet that used the pipeline, and also checked the faile we were passing to the cmdlet actually existed. Whilst I was pokeing around in the .Net framework, I also noticed that SHA1, SHA384, SHA512, MD5 and RIPEMD160 was also available to us.
So I spent some time, and have developed the following piece of code:
To use the code, copy the code above into a .ps1 file, and then import-module yourfile.ps1, the function is called get-hash.
As you can see, I am using the comment based help, and there are some nice examples included.
Infrastructure Saturday 2012
I loved presenting at Infrastructure Saturday, as promised to you all, my presentations are available from the links below (and from the infrastructuresaturday.org website).
And as a bonus, my 2011 presentation!
What is coming up:
- I will be talking about Web access and PowerShell
- Web Functions Library
- PushOver.Net and PowerShell
- Malware, malware, malware!
- new base template script with huge amount of extensibility for other notification types!
Azure Powered External IP Address Returning Pages!
In my last post, we made 4 different pages that all did one thing, tell you your external IP address, now lets introduce the power of Microsoft Windows Azure!
Azure will let us run any or all of the 4 pages I showed you how to make earlier! Yes even PHP!
We will do this in 8 easy steps!
- Signup for a Windows Azure trial (or in my case active my AWESOME MSDN subscription's Azure Subscription)
- Go to the account management portal, and signup for the Website Beta Program http://account.windowsazure.com
- Once accepted for the Web Site program (you will get an email, or just keep checking the management portal), go to the management portal, http://manage.windowsazure.com/ and create a new website using the Quick Create option. I called mine whatismyip, which will result in the FQDN of http://whatismyip.azurewebsites.net
- Open the dashboard for your website, select "Reset Deployment Credentials". Enter appropriate username and password.
- Still in the dashboard, make a note of the "Deployment User" and "FTP Hostname"
- Open up your favorite FTP client, the server name will be the previously noted hostname, username will be the previously noted down username, password will be what you specified earlier.
- Copy up the file or files for the IP returning page that you wish to use, I uploaded all 4!
- Use the pages!
Here are mine:
http://whatismyip.azurewebsites.net/getip.php
http://whatismyip.azurewebsites.net/getip.aspx