Saturday, August 25, 2012

Taming Wild Console Applications in PowerShell v3

One of the great features of PowerShell, especially for beginners, is that you can easily run old console applications that were originally written to be run under CMD.EXE. These are can be managed or unmanaged applications as well as older VBScripts. PowerShell, and PowerShell v3, just runs them. However, there is a fundamental problem which can often trip up those new to PowerShell (and from time to time us oldies too!).

In PowerShell there is a single parser therefore a single syntax that each and every cmdlet, function, script object, etc., have to obey. There’s only one parser, therefore there’s only one way to call a script/function/workflow/etc. This consistency is is wonderful. Compare that to older console line applications where each application implements it’s own parser, implementing an application unique syntax for usage. Compare NetShell, with it’s hierarchical contexts with calling IPconfig that uses the ‘/’ character to prefix parameters.

For the most part, the syntax you use when running a console application in CMD.EXE is the very same as you would run in PowerShell. So that’s all good then. Well – there are exceptions. There are some console applications whose command syntax confuses PowerShell’s parser. That is, the way PowerShell’s parser parses the call to that application does not quite do what you want. My favorite example is BcdEdit.exe. According to TechNet, you can use BcdEdit to add a native-boot VHD to an existing WIn7 boot menu (and appears to work just fine for Win8 too!) using the following commands:

bcdedit /copy {default} /d "vhd boot (locate)"
bcdedit /set {guid} device vhd=[locate]\windows7.vhd
bcdedit /set {guid} osdevice vhd=[locate]\windows7.vhd
The problem here is that BcdEdit wants arguments that are enclosed in brace characters – PowerShell sees text inside a pair of braces as a script block, not just a string that happens to have a pair of brace characters at the start/end. The result is that the command will not do what you want. There are often discussions on various PowerShell Forums. The solution rationally was to add quote characters, e.g.:
bcdedit /set “{guid}” osdevice vhd=[locate]\windows7.vhd
Which works, but is not always obvious. There are other examples which are even harder to fix quickly. The problem this causes is that it ‘proves’ to those who want it to, that PowerShell is not quite ready. The reality is that moving from one older inconsistent regime to another hopefully consistent regime was bound to turn up a a few minor incompatibilities. These areas are ones that came in for a lot of attention in PowerShell v3.
For those facing this issue, one of the cooler features in PowerShell v3 is the –% operator (that is: two hyphens and a percent symbol). You specify this character sequence after the command name but before the command’s parameters, like this.
bcdedit –% /set {guid} osdevice vhd=[locate]\windows7.vhd
What this character sequence does it to tell PowerShell to just pass the rest of the command line to the console application ‘as is’. This means you can old .bat scripts into .ps1 scripts, incorporating new PowerShell features for example, but being able to convert the calls to some curiously written console applications. 

1 comment:

Peter Kriegel said...

See also :
http://social.technet.microsoft.com/wiki/contents/articles/7703.powershell-running-executables.aspx