1
class getVar {
    static [string]pdConfigVarGetMethod($var = "") {

        $configFilePath = "$Env:PD_SCRIPTS\pdConfigurationFile.ps1"
        $configFileContent = Get-Content -Path $configFilePath
    
        foreach ($line in $configFileContent) {
            $lineVar = $line -split (':::')
            if ($lineVar[0] -eq $var) {
                return $lineVar[1]
            }
        }
    
        return ""
    }   
}

$path = [getVar]::pdConfigVarGetMethod("PD_SCRIPTS")
Set-Location -Path $path

The above code works. What I want to understand is why this won't work:

Set-Location -Path [getVar]::pdConfigVarGetMethod("PD_SCRIPTS")

I used a class method because I learned that PS function return values have no contract. A class method's return value is loosly typed and can be relied upon to return only what I asked it to return with the proper type.

So why then doesn't the method call resolve into a string value that Set-Content -Path can understand???

I get the error:

Set-Location : A positional parameter cannot be found that accepts argument 'PD_SCRIPTS'.
At C:\Users\Paul.Defina\Documents\PowershellScripts\ScriptDir.ps1:11 char:1
+ Set-Location -Path [getVar]::pdConfigVarGetMethod("PD_SCRIPTS")
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Set-Location], ParameterBindingException
    + FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.PowerShell.Commands.SetLocationCommand

I expected:

Set-Location -Path [getVar]::pdConfigVarGetMethod("PD_SCRIPTS")

to work the same as:

$path = [getVar]::pdConfigVarGetMethod("PD_SCRIPTS")
Set-Location -Path $path
mklement0
  • 382,024
  • 64
  • 607
  • 775

1 Answers1

1

In argument parsing mode, [ is not a metacharacter, and therefore what in expression (parsing) mode is a type literal, such as [getVar], is not recognized as such and is simply interpreted verbatim.

Therefore, you must enclose your expression in parentheses - (...) - in order for it to be recognized as such:

Set-Location -Path ([getVar]::pdConfigVarGetMethod("PD_SCRIPTS"))

As an aside: -Path interprets its argument as a wildcard expression. If you know your path to be a literal one, it is more robust to use -LiteralPath.


As for what you tried:

Set-Location -Path [getVar]::pdConfigVarGetMethod("PD_SCRIPTS")

While [ isn't a metacharacter in argument mode, ( is, and -despite there being no space before (, PowerShell considers the (...) expression to be a separate argument, so that in effect you passed two arguments:

  • Verbatim [getVar]::pdConfigVarGetMethod

  • Verbatim PD_SCRIPTS, which is what the expression ("PD_SCRIPTS") evaluated to.

This unexpected extra argument caused Set-Location to report an error.

By contrast:

$path = [getVar]::pdConfigVarGetMethod("PD_SCRIPTS")
Set-Location -Path $path

This did work, because in the context of an assignment statement, [getVar] is recognized as a type literal, because the RHS of the assignment starting with a [ causes it to be parsed in expression mode.

In short:

  • In a given parsing context, it is the first token that determines which mode is entered:

    • If the first token of a statement is an unquoted name (symbolic identifier) - such as Set-Location - it is assumed to refer to a command, and argument mode is entered.

    • Otherwise, it is assumed to be an expression, and expression mode is entered - this therefore includes tokens that start with [, so that they're recognized as part of type literals.

  • You can create a new parsing context with (...), and also $(...) (primarily for use inside "...") and @(...).

See also:

mklement0
  • 382,024
  • 64
  • 607
  • 775