Wednesday, December 09, 2009

One More Reason To Hate DOS Command

Today one of my command script starts to fail mysteriously. I had run it many times before. The failing fragment seems to be like this:

if Exist "%ProgramFiles(x86)%\Microsoft Visual Studio 10.0" (
    Set VS10=%ProgramFiles(x86)%\Microsoft Visual Studio 10.0
)

At a glance this looks perfectly fine. I can even run the individual commands on the command line. The “if” statement runs fine, the “set” statement also runs ok. However, running them together like above results in this:

\Microsoft was unexpected at this time.

I scratched my head for quite a while. Looking for help in “if”, “cmd”, or searching online did not help either. Is this a Windows 7 incompatibility?

It was just by luck that I suddenly noticed the “(“ and “)”. Apparently the “set” statement contains “(“ and “)”, which likely confused the command host. More experiments reveal that even if only the variable value contains “(“ / “)”, this problem still happens. The command host expands the variables upon “if” statement being seen. As a result, the script below still won’t run:

Set ProgramFilesX86=%ProgramFiles(x86)%
if Exist "%ProgramFilesX86%\Microsoft Visual Studio 10.0" (
    Set VS10=%ProgramFilesX86%\Microsoft Visual Studio 10.0
)

To work around this issue, the final solution I come up with is to combine “delayed variable expansion”:

setlocal ENABLEDELAYEDEXPANSION

Set ProgramFilesX86=%ProgramFiles(x86)%
if Exist "%ProgramFilesX86%\Microsoft Visual Studio 10.0" (
    Set VS10=!ProgramFilesX86!\Microsoft Visual Studio 10.0
)

Technorati Tags: ,,

Sunday, December 06, 2009

PowerShell Splat Operator

There is a new “splat” operator in PowerShell v2 which is quite useful but not well documented. The best info I can find is from this blog. From a PowerShell console I can see help content of “about_Split” and “about_Join”, but not “about_Splat”, or anything mentioned in “about_Operators”.

It is described that this new splat operator “@” can be used to pass a collection as parameters to a function. It’s easy to find out the details by experiments. First, draft a test function:

PS> function Echo-Args
>>  {
>>      echo "=== Args: ($($args.Length)) ==="
>>      echo $args
>>  }
PS>
PS> Echo-Args a b c 1 2 3
=== Args: (6) ===
a
b
c
1
2
3

Try it out with an array:

PS> $a = @(1,2,3)
PS> Echo-Args $a
=== Args: (1) ===
1
2
3
PS> Echo-Args @a
=== Args: (3) ===
1
2
3

See the difference of passing “$a” and “@a”? “$a” passes the whole array as one parameter. “@a” passes the elements as parameters.

To admit it, I was testing this for several days, but every time I ran into an “invalid operator” kind of error, because I was using “@$a”.

Now try it out with a hash table:

PS> $a = @{a=1;b=2;c=3}
PS> Echo-Args @a
=== Args: (6) ===
c
3
b
2
a
1
PS> function f($A, $B, $C) { $PSBoundParameters }
PS> f @a

Key                                                                       Value
---                                                                       -----
C                                                                             3
B                                                                             2
A                                                                             1


PS> $a = @{"-a"=1;"-b"=2;"-c"=3}
PS> f @a

Key                                                                       Value
---                                                                       -----
A                                                                             1
C                                                                             3
B                                                                             2

Now this is interesting. So you can splat and pass a hash table of parameters to a function, and PowerShell will always try to “do it right”. When the function is expecting named parameters, PowerShell can match them with or without leading “-“.

In summary, this splat operator is quite useful when you just want to pass some collection of parameters to another function, e.g. the current “$args” or “$PSBoundParameters”, with or without modification.

Technorati Tags: ,