Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does PowerShell handle empty string differently on the command line?

This question is similar to Passing empty arguments to executables using powershell but I want to expand upon both the question and the answer and understand the "why" better, because it seems like a PowerShell pitfall.

If you load up PSCX and run echoargs (an external command, i.e. an exe file) you can see that the empty string argument is skipped:

PS> echoargs word "two words" "" 123
Arg 0 is <word>
Arg 1 is <two words>
Arg 2 is <123>

But if you use the "CMD escape" (--%) you can make it appear "properly":

PS> echoargs --% word "two words" "" 123
Arg 0 is <word>
Arg 1 is <two words>
Arg 2 is <>
Arg 3 is <123>

Similarly if one writes a PowerShell function the empty string is properly handled:

PS> Show-Args word "two words" "" 123
Arg 0 is <word>
Arg 1 is <two words>
Arg 2 is <>
Arg 3 is <123>

This difference seems like a big deal to me for the following reason. The examples as shown above use a literal empty string on the command-line so at least you have a hint of the problem. But the results are exactly the same if one uses a variable containing an empty string. Which means one has to either:

  1. rigorously police all variables being fed to external commands, or
  2. use the CMD escape (--%) and forego using any PowerShell constructs on the rest of the line
  3. quote every argument to an external command with backquote/double quote like `"this`" or `"$this`" or `"`"

...or bad things will happen!

(@KeithHill pointed out the third workaround above so I added it there for completeness. It works for literals or variables so, though ugly, is perhaps the best choice of the three workarounds.)

So PowerShell handles arguments to a function differently than arguments to an external command--dramatically so. Is this an inconsistency in PowerShell's behavior? If not, why not?


Addendum

For reference, here's the PowerShell function body used above:

function Show-Args()
{
    for ($i = 0; $i -lt $args.length; $i++)
    {
        Write-Host ("Arg {0} is <{1}>" -f $i, $args[$i])
    }   
}

And here is an echoargs-equivalent in C#:

class Program
{
    static void Main(string[] args)
    {
        for (int i = 0; i < args.Length; i++)
        {
            System.Console.WriteLine("Arg {0} is <{1}>", i, args[i]);
        }
    }
}
like image 251
Michael Sorens Avatar asked May 13 '14 19:05

Michael Sorens


People also ask

Is null or empty string PowerShell?

String to check if a string variable is null or empty in PowerShell. The IsNullorEmpty() method indicates whether the specified string is empty or null. It returns True if the string is empty and False if it is not empty.

How do I use IsNullOrEmpty in PowerShell?

You can use the [string]::IsNullOrEmpty($version) method if it is a string. But, I was looking for a universal way to check nulls (regardless of data type) in Powershell. Checking for null (or not null) values in PowerShell is tricky. Using ($value -eq $null) or ($value -ne $null) does not always work.

What does 0 mean in PowerShell?

Note that the index always begins with a number starting from 0 and it corresponds to the items in the list of objects. Therefore, an item using parameter specifier 0 corresponds to the first object in the list of objects. In examples 1 and 2, the object list is simply the variable $name.

How do you define a string in PowerShell?

In PowerShell, there are two ways to define a string: by using single quotes or double quotes. Both create the same System. String object, but what happens inside those strings is different. When you're just defining a string with no variables inside, always use single quotes.


1 Answers

The behavior might be considered "by design" (it's hard to know for sure based on the implementation and tests), but I don't think the matter was given much thought and you bring up excellent points.

Personally I think you are right and PowerShell is being inconsistent. It's worth considering a change to be consistent, though that has some risk of breaking existing scripts.

like image 120
Jason Shirk Avatar answered Oct 12 '22 04:10

Jason Shirk