PowerShell gotchas

Here’s my list of top gotchas in PowerShell and an explanation for why PowerShell made the design decisions they did. PowerShell is both a shell and a scripting language.

5. PowerShell will not run scripts by default.

This was done for security reasons. The default execution policy in PowerShell prohibits all scripts from running. Before you can run scripts, you have to call Set-ExecutionPolicy with one of the following arguments, in order of increasing paranoia: Unrestricted, RemoteSigned, AllSigned, Restricted (default). If you set your policy to RemoteSigned, you don’t have to digitally sign scripts you write, but scripts that you download will need to be signed.

You only have to call Set-ExecutionPolicy once. Your setting will be saved for future PowerShell sessions.

4. PowerShell requires .\ to run a script in the current directory.

This was also done for security. Your current working directory is not in your path by default. So to run a script foo.ps1 in your current directory, you have to type .\foo.ps1. This comes as no surprise for Unix users who often have such a restriction in their shells but seems odd to Windows users accustomed to cmd.exe.

The motivation behind requiring an explicit path to scripts, even scripts in your current directory, is to prevent someone tricking you into running a script with the same name as the one you think you’re running but in a different location.

3. PowerShell uses -eq, -gt, etc. for comparison operators.

PowerShell is both a shell and a scripting language, but first of all it is a shell. Those of us who tend to see it more as a scripting language forget that and are surprised when PowerShell follows shell conventions rather than programming language conventions.

Firmly established shell convention dictates that > and < are redirection operators, not a comparison operators. There was great uproar when the PowerShell development team floated the idea of using different redirection operators. So PowerShell uses -gt and -lt instead of > and <. And because PowerShell emphasizes consistency, it uses analogous syntax for other comparison operators. So, for example, it uses -eq and -ne rather than == and != to test for whether two objects are equal or not equal.

2. PowerShell uses backquote as the escape character.

This means, for example, that a newline character is denoted `n rather than \n and a tab is denoted `t rather than \t. As a mnemonic, think of the backquote as a small backslash.

PowerShell is a Windows shell, and Windows allows backslashes as path separators. Windows also allows forward slashes as path separators, and the PowerShell designers could have dictated that users restrict themselves to forward slashes so backslash could be reserved for the escape character, but that would have caused great frustration for many Windows users.

1. PowerShell separates function arguments with spaces, not commas.

If you call a PowerShell function foo with a comma-separated list, such as foo(a, b, c), you are sending the function one argument: the three-element list a, b, c. If you want to call foo with three arguments, the correct syntax is foo a b c.

This is probably the biggest gotcha in PowerShell. I’ve fallen into this trap, told other people about it, then fallen into the trap again. The worst thing about it is that an erroneous function call may not throw an exception but just work strangely.

When the interpreter sees foo (a, b, c), it says “I’m expecting three arguments to foo, but I only see one: a list contained in superfluous parentheses. That must be the first argument, so I will set the other two arguments to the default value null.”

What were the PowerShell designers thinking? PowerShell is a shell. The primary usage scenario is a system administrator typing at the command line. Tradition and convenience dictate that shell command arguments are separated by spaces and are not delimited by parentheses and commas.

There is an exception to the function call rule: When you call methods on .NET objects from PowerShell, use parentheses and commas just as you would in C#.


Other PowerShell resources on this site: