Many, many years ago, I spent a bank holiday in Amsterdam with a life friend. We had a pretty outrageous time. The highlight was seeing Dave Edmunds in the Paradiso. We had outstanding seats and the evening was magic. It was the early 1980’s and Dave was in his prime. The sound was outstanding. The environment was even better!
I was reminded of this when I came across a bootleg concert featuring Dave and The Refreshments (a Swedish band). The show features Billy Bremner. It’s so wonderful to hear tunes like “I Knew The Bride”, “Here comes the Weekend” and “Standing at the Crossroads”. It’s a real shame Debra is not on their set list. If you can find this show (it’s on a few popular torrent sites) it’s worth the download.
This was disappointing a couple of years ago, and is disappointing now. Microsoft has taken a hugely popular and well understand brand and replaced it with, well what? Replacing a credential with “Engineer” in the title with “Administrator”??? How is that an improvement?. Does MSL really expect anyone to get excited about “upgrading” an Engineer credential with an Administrator credential?
I was one of the first MCSEs in the world, and am still quite proud of that credential. I’m not sure if I could ever get 1% as excited about being an Enterprise Administrator. It just sounds a step down and backwards. As a result, I’m just not chasing the new credentials any where near as fast as I used to. I know I am not alone.
I think Bill and the rest of MSL has made a huge mistake with killing off the MCSE. The fact that he’s heard the question (“Where is the MCSE 2008”) on a daily basis indicates the market is not anywhere near enough clued up on MSLs rebranding (and like “New Coke” don’t accept it). Despite several years of trying, the MCSE is sill a better known credential than Enterprise Administrator.
I spent some time in the autumn of 2007 trying to convince MSL that they needed to invest in evangelising the new credentials, otherwise, in a year or two’s time, the new credentials would be still unknown. Two years on, MSL still hears ‘the question’ on a daily basis (or at least Bill does).
MSL made a mistake – it’s time to correct that mistake and bring back the MCSE. Learning from one’s mistakes is hard to do, but Coke did it! MSL should take a hint and do the right thing.
One of the things we chatted about was when I first saw PowerShell.I was in the back of a big hall in LA, attending PDC 2003, and watched Jim Truer and Jeffrey Snover give Monad, as it was then called, its initial airing. I got quite excited – and waved a US$20 bill in the air and proclaimed “I’ll buy it now”! Jeffrey wisely declined, but many years later (and a bit worse for wear), I finally presented the $20 to him at an event in Redmond. You can see the $20 here and here!
It was one of those events I’ll not forget – it began a passion that continues to this day. As I say on the interview, nothing that has happened since – the community, the wealth of cmdlets, etc – has been a surprise at all. About the only surprise is that it’s taken a bit longer than I’d have hoped.
If you are around and on line on Thursday evening (12:00 EST, or 17:00 UK time), check out the Windows PowerShell Virtual User Group Meeting #8. This meeting will feature June Blender from Microsoft – no doubt she’ll be talking about the PowerShell Documentation.
Go to the site to get the credentials to the Live Meeting. No idea if the session is being recorded!
I’ve long enjoyed examples of social engineering, hoping I’d never fall for them. The IRC chat, at QDB: Quote #244321, is a great example of this. Take a read (I had to read it twice!).
I’ve been working with PowerShell’s error handling – trying to get a better handle on it. Yesterday, I looked at general error handling and discussed how to trap or catch an exception. By handling errors in your scripts, you make the script more production ready. And for many, this is a great thing!
One of the problems in trapping or catching an error is knowing what to look for. You can do a blanket catch, such as:
try {
... some dodgy bit of code...
}
catch {
"code broke..."
}
At one level this works. You can catch an error and avoid your script dying – and maybe returning some interesting info. But there’s often a need to do a better job in detecting different exceptions and handling them differently. As I noted yesterday, a simple script could result in a number of discreet different errors each of which might mean different actions in your script. Along these lines (with PowerShell V2 of course):
…
try {
... some dodgy bit of code...
}
catch [... exception 1]{
"code broke due to exception 1..."
}
catch [... exception 2]{
"code broke due to exception 2..."
}
catch {
“no idea why your code broke…”
}
In this second example, you are explicitly testing for two specific exceptions as well as a more general one. The idea here is that for the first two exceptions, you might be able to find some specific information to help the caller (or you) work out what went wrong and deal with it.
The big problem is knowing what exceptions you can trap. I saw a cool script today online - PowerShell Code Repository - Get-Exception. This script looks at all the loaded assemblies and works out what possible exceptions exist and then outputs them. Makes interesting reading and is a great reference.
At last week’s UK PowerShell User Group meeting, we heard a great talk on Error handling. It got me thinking about the whole business of errors and error handling in PowerShell.
One of the great differences between casual and production scripts is the need to manage, control and handle errors. If I write a script to open a file, eg c:\foo\gd.txt, I know it exists. I created it, I regularly edit it, and I can see it in my folder. So why bother with error handling?
Tor casual scripting the answer is probably that you don’t need to worry. But when you start moving scripts into production, you can’t always be so sure. Stuff happens in production and your scripts need to deal with that.
There are three sets of error handling statements included in the PowerShell language:
Trap – allows you to trap any errors that occur in your code. You define the trap block before any risky code is executed. Trap is part of V1 and included in V2.
Try/Catch/Finally – these three statements allow you to try some dodgy code, catch any errors that occur in that dodgy code then do any clean up (whether or not an error occurred). Try/catch/finally is an addition to V2 and is not supported in V1.
Throw – this allows you to detect an error (for example in a subordinate script or function) and throw an error for a higher level script or function to catch or trap. This statement is in both V1 and V2.
So which do you use? It depends I suppose. For most scripts, you probably won’t need to use Throw. If you have some utility function, you might enable it to catch specific errors then throw an exception to callers of that code. Typically a throw is inside of your subordinate’s trap or catch block. You handle the error, perhaps do some clue generation (ie is the file you are trying to open, or is the drive just not accessible, etc) then throwing a more specific error. Try/catch (and finally if needed) should surround any production script logic that could fail.
There are (at least!) two things that could go wrong with this fragment. First, the New-WebsServiceProxy cmdlet could fail – in fact, of late, this call has been producing errors (the site appears down). Second, the GetQuote web service could fail. There is a third source of error ($ticker is empty), but that would be dealt with via parameter declarations, which I omitted form this snippet!
As a casual script, just showing the basics of using this web service, I don’t need to worry about such things. But if this was a web service I depended on (and is outside my direct control!), I should either have one (or possibly) to trap blocks, or two try/catch blocks. I could expand this code as follows:
process { try { $s = new-webserviceproxy -uri http://www.webservicex.net/stockquote.asmx return } catch { "StockQuote web service not available"; $error[0] return } foreach ($symbolin$ticker) { try { $result = [xml]$s.GetQuote($symbol) } catch { return ("Can not get stock quote for {0}" -f $symbol) } # return results $result.StockQuotes.Stock }
This code is a bit longer, but it enables the script to run and not abort. When errors do occur, this script fragement won’t produce the results you might have hoped for. In both catch blocks, I’ve not added much in the way of error handling. In the first catch block, some additional detection might include:
Checking the host IP configuration to see if the host is on-line and host networking is enabled. There might be a local issue with a cable being unplugged.
Checking the local IP gateway. Networking might be OK, but the gateway might be down.
Determining if the site name (www.webservicex.net) was resolving via DNS to an IP address. Networking and gateways might be OK, but the DNS resolution of the site might be down.
Checking policy to see if the site’s IP address is being blocked. You might be able to ask the firewall(s) if they’re blocking traffic to the service.
Checking For SSL/TLS protected web services – can you create the secure tunnel? Is the certificate protecting the site duff?
Pinging the site to see if it’s actually up. DNS may resolve, but the site might be down.
Opening the home page for the site to see if there’s a working web site at the root. The site might be up but the web service gone.
Etc. I suspect there are more things you could check for.
Moving on in the code, with the second catch block, you could have checked the error details to produce a more relevant exception. Simply returning an instance of $Error puts the onus on the caller to handle the error. Also on both catch blocks, you could have thrown an exception for the caller to handle rather than just continuing.
As I think you can see, a pretty simple script that just creates a web proxy then calls it (effectively 2 lines of code) could end up with 10 times that many lines of error checking/handling code. This is amongst one aspect of writing production oriented PowerShell scripts.
Something related to this, of course, is the $Error variable. This is a subject worthy of an entire book chapter!
Every year, like many of you, I submit proposals for TechEd. In recent years, they’ve been less than successful – the competition is very fierce and there is so much great content to choose from. I almost have to feel sorry for the Microsoft folks having to wade through hundreds of proposals.
This year, I submitted three talks, two around PowerShell and one around OCS. To my great surprise and delight, one has thus far been accepted! YEAH
The accepted break out sessions, part of the Unified Communications track, is entitled “SIP - Naked In All Its Glory”. The abstract for the talk is:
This session will look at the key protocols behind Microsoft's OCS product, in particular Session Initiaion Protocol as well as Real Time Transfer Protocol (RTP) and Session Description Protocol. A short discussion on TCP, TLS, and PSOM will also be given. The talk will focus on looking at the SIP and related protocols "on the wire". We'll dive in to using NetMon as well as OCS's Snooper tool. Troubleshooting SIP will be the final part of this talk.
I’m still waiting on the other two talk proposals. The other proposed talks are PowerShell related and are titled: “PowerShell and WMI”, and “Writing Production Quality Power Shell Scripts with PowerShell V2 and Windows Serer 2008 R2”. I await the verdict on those two talks, but would like to think that at least one will get accepted
Irrespective of the PowerShell talks, I’m really excited that I’ll be a speaker again. LA, here I come!
I’ve just got a new laptop (Dell Lattitude E6500) and am running Win7 Beta. The combination is awesome – my old laptop (running XP) looks so old and dated.
One thing I’ve relied on for many years is Daemon Tools. I use this to mount ISO images of software and then use them. However, Daemon Tools does not install on Win7 (you get a known incomptibilty error message when you try to install it). From reading their forums, it looks like Win7 support will come, but not any time soon. In the mean while, I need a solution,
This is a neat package. Not only can it mount ISO images, but it also mounts VHDs and Zip files. This is a seriously nice package. Another cool thing about this tool is that’s free! I’ve downloaded and installed it, and have used it to install Office on my new laptop.
I recall the moment of amusement when Jeffrey Snover revealed the #Requires PowerShell statement when the first release of PowerShell V2 occurred. It had been in PowerShell V1, but was a very tight secret. As it turns out, with V2’s beta, the #Requires statement had additional functionality, as I pointed out in a recent blog post. With the release of V2 coming sooner rather than later, the question is whether this statement is rich enough (and whether it can get improved in V2). But let me explain what I mean by that.
The concept that a script or even a function/cmdlet requires some set of pre-requisites is obvious. If, for example, I have a script that relies on the Quest AD cmdlets, then I’d like to impose a rule that says the script needs those cmdlets. There’s no point me running any script that requires something not present on my system. I belive I should not only be able to describe this requirement, and that autohelp should provide that information.
The #Requires statement come some way towards meeting this general requirement. But I think it needs more than that. For me, the question becomes: what does a script need to ‘require’ and more importantly, how does it signal that need? As I see it, that means two separate questions: what do you NEED, distinct from how to express that requirement.
The second question taken first – I am not sure that just using the '#Requires statement is enough. As I think about it the need should be expressed in Powershell autohelp. Autohelp is that set of instructions that you can put at the start of a function, module or script that can leter provide help for users of your code.
I realise that the intention of autohelp was to, oddly enough, help. It seems to me that this can also be used to express the need that chunk of functionality might have a module/script/function for some pre-req. So I think that the should be a .REQUIRES statment in auto help, for example:
<#
...
.Requires
VERSION 2
MODULE Quest-ADTools
DLL tfl.reallycoolDLL.dl
ELEVATION
ASSEMBLY globalknowledge.powershell.ocs2007r2
...
#>
You should not only document the requirements but demand them in this Autohelp block (ie the autohelp block is more than just documentation). This would be a very elegant solution.
But separate to HOW you express the pre-reqs, I think V2 needs to expand what #Requires provides. Specially, I’d like to see the #REQUIRES statement expanded to allow you to specify:
A specific module
Elevation (should it need to run elevated)
A specific named DLL
A specify Assembly (i.e. in the GAC)
etc
I’d like to see the advanced function’s autohelp block be really useful!
It looks like some of my daily blog posts did not quite make it up to their sites on time. The posts (for both this blog and my PowerSHell Scripts blog) were written off line and I thought had been successfully posted. My Blogger-fu must be weak this week, but the latest scripts and PowerShell scripts are now up and running.
I’d love to have the time to spend to write some PowerShell scripts against Live Writer and Blogger to check that posts actually hit the blog properly! Maybe in another life when days are 40+ hours long!
I recently wrote about a cool weekly Podcast, The PowerScripting Podcast, delivered by Jonathan Walz and Hal Rottenberg. This is a great resource, and you can watch it in progress every Friday Morning at 0200 UK time. For most normal folks, this may be a bit much to ask, but you can of course download it later. One interesting aspect – the podcast is broadcast with a live chat going on. Sadly, this week, that failed, as noted over on the Podcast’s blog site.
More recently, I discovered a UK podcast, the Get-Scripting Podcast presented by Jonathan Medd and recently co-hosted by Alan Renouf. This is a monthly podcast and is prepared partly in advance (the interviews are pre-recorded). You can download this podcast from the blog site, http://get-scripting.blogspot.com/, or via iTunes.
At last week’s PowerShell use group meeting, I was interviewed for the Get-Scripting podcast. If I understand it correctly, the interview will be included in the next podcast, due for release this week. It was a lot of fun to record this interview. I spent some time talking about my first experience with PowerShell (over 5 years ago when it was still called Monad) – I hope the $20 dollar story will be interesting to some. I also spent some time talking about the Microsoft PowerShell class which I helped develop.
As I noted yesterday, Last night, I attended a great PowerShell user group on Friday night. One highlight that I forgot to mention was that I was interviewed for the Get-Scripting podcast. This will be broadcast sometime next week.
I’ve been writing this week about using GPOs with PowerShell. I noticed today, over on the Group Policy Team blog a neat article: Introduction to Windows PowerShell Cmdlets in Windows 7. With Windows 7 and Server 2008 R2, we’ll have decent cmdlet support for Group Policy – no more hard core COM objects.
The group policy support is meant to be implemented by a module (grouppolicy), although that module does not exist in the beta versions of either Windows 7 or Server 2008 R2.
I’m looking forward to seeing this module when it gets completed!
It turns out this story is a good excuse to update all my PowerShell scripts that I use to manage my Grateful Dead/Jerry Garcia archive. I’ve got getting on for a 1.5 terabytes of live shows by The Grateful Dead and Jerry Garcia (in his many incarnations as a solo act apart from the Dead). I developed a few scripts in the .MSH days and I need to dust them off and update them.
In a post yesterday, I looked at telling the difference between a scalar and arrays. The difference matters when working with PowerShell – a scalar has properties and methods, while an array has members that have properties and methods. You can directly reach into a scalar, whereas you need to process array members (e.g. using ForEach). If you assign a variable to the output of a cmdlet or a pipeline of cmdlets, you may end up with zero, one or more objects inside that variable. When you go to process that variable in your script/function, you need to know the differences.
In yesterday’s post, I noted that with GPO objects, what you got back was a collection, even if the collection had only one object. A comment left on the blog made a great point: this is a feature of the particular object model (i.e. GPMC objects). It’s not a feature of COM as such.
And this just underlines my conclusion – there’s no easy way to tell what you have, without knowing the object and underlying object model.
I have a lot of digital music, as many of my friends, and readers of this blog, know. I’ve been slowly getting around to writing some PowerShell scripts to manage this archive. This afternoon, someone asked me how many Jerry Garcia shows I had on my system. I could not recall off the top of my head, so I wrote a short script to do the counting, and published this over on my PowerShell Scripts blog. The Get-CountOfJerryShows.ps1 scritp may not, perhaps, be the most elegant of PowerShell scripts. And I know I could do it in fewer lines. But it works and it’s something I am likely to be able to read and understand in the future, if/when I want to update it.
The answer, thanks to PowerShell: I currently have 734 live Jerry Shows! This is in addition to my 1144 Grateful Dead shows.
The latter is a lot simpler, as I just store all the Grateful Dead Shows in a single folder. To get a count of Dead shows, I just type:
1: cd m:\gd;(ls | where {$_.Name -match "^gd"}).count
Pretty cool and to some degree more .NET than an another approach I’ve used. In some scripts, I’ve just checked for the existance of the count property. An array has one, but a scalar doesn’t. I do something like this:
PS C:\foo> if ($a.count) {"array"} else {"scalar"} array PS C:\foo> if ($b.count) {"array"} else {"scalar"} scalar
These three approaches (basetype, IsArray and checking for count) all work – they can help to determine whether an object (i.e. a PowerShell variable) is an array or just a scalar. However, this doesn’t always work. In particular, the approach does not give proper results if you are using COM objects. To show this problem, let’s take a look the Group Policy Management Console COM interface. In this example, I search for all the GPOs in my domain. There are currently just 4 GPOs – and these are returned. However, although checking the count works, the BaseType is not so helpful. Here’s a small script I wrote to demonstrate this
# Setup GPMC $gpm = new-object -com GPmgmt.Gpm $k = $gpm.getconstants() $dom = $gpm.getdomain("cookham.net", "","") # Search for all GPOs $sc=$gpm.CreateSearchCriteria() $gpos = $dom.SearchGPOs($sc) # Now - result time "Type :{0}" -f $gpos.gettype() "Base Type :{0}" -f $gpos.gettype().basetype If ($gpos.Count) {"Seems to be an array"} else {"Seems to be a scalar"} "Count :{0}" -f $gpos.Count "An array? :{0}" -f $gpos.gettype().IsArray
The results of this were a little surprising:
PS C:\foo> . 'C:\Users\tfl\AppData\Local\Temp\Untitled4.ps1' Type :System.__ComObject Base Type :System.MarshalByRefObject Seems to be an array Count :4 An array? :False
As you can see, the $GPOS object appears to be an array and has a count – but GetType says it’s not an array. ALso, the Type and BaseType don’t actually help all that much.
If I change the code above marginally (to search for just one GPO) as follows:
# Setup GPMC $gpm = new-object -com GPmgmt.Gpm $k = $gpm.getconstants() $dom = $gpm.getdomain("cookham.net", "","") # Search for one GPO $sc=$gpm.CreateSearchCriteria() #Add a searcher to search for just ONE GPO Object $sc.add($k.SearchPropertyGPODisplayName,$k.SearchOpEquals, "GPO1") # Now search $gpos = $dom.SearchGPOs($sc) # Now - result time "Type :{0}" -f $gpos.gettype() "Base Type :{0}" -f $gpos.gettype().basetype If ($gpos.Count) {"Seems to be an array"} else {"Seems to be a scalar"} "Count :{0}" -f $gpos.Count "An array? :{0}" -f $gpos.gettype().IsArray
The results of this were even more surprising to me:
PS C:\foo> . 'C:\Users\tfl\AppData\Local\Temp\Untitled4.ps1' Type :System.__ComObject Base Type :System.MarshalByRefObject Seems to be an array Count :1 An array? :False
This time, although only one object was returned, the count property exists and it appears to be an array! I wonder if I was the only person to be marginally confused!
While the three techniques above work great for .NET objects, they don’t work well for COM Objects. You just have to know what the underlying API (COM, .NET, etc) returns. In the case of the GPMC, the APIs seem to always return a collection, even when there’s only one object occurrence returned. For most harder-core developers, this really is not an issue, but for Admins using PowerShell it can be very confusing (It took me several hours to work this out. It’s one of those things that if you are to use PowerShell richly, you just have to know.
I love downloading podcasts to my Zune and listening to them as I travel. I’ve got a bit of a backlog, but one I’ve just downloaded and will be listening to shortly (possibly tomorrow as I head from Milan back to London) is the PowerScripting Podcast, Episode 53 which features Jeffrey Snover and Bruce Payette.
You can listen to the podcast on your PC, or download it to your MP3 player. The file, PSPodcast-053.mp3, is just over 38mb.