Invoke a second script with arguments from a script

Hoobajoob picture Hoobajoob · Oct 12, 2012 · Viewed 184.4k times · Source

I have a script that reads a configuration file that results in a set of name value pairs that I would like to pass as arguments to a function in a second PowerShell script.

I do not know what parameters will be placed in this configuration file at design time, so right at the point where I need to invoke this second PowerShell script, I basically just have one variable that has the path to this second script, and a second variable that is an array of arguments to pass to the script identified in the path variable.

So the variable containing the path to the second script ($scriptPath), might have a value like:

"c:\the\path\to\the\second\script.ps1"

The variable containing the arguments ($argumentList) might look something like:

-ConfigFilename "doohickey.txt" -RootDirectory "c:\some\kind\of\path" -Max 11

How do I get from this state of affairs to the execution of script.ps1 with all of the arguments from $argumentList?

I'd like any write-host commands from this second script to be visible to the console from which this first script is invoked.

I have tried dot-sourcing, Invoke-Command, Invoke-Expression, and Start-Job, but I haven't found an approach that doesn't produce errors.

For example, I thought the easiest first route was to try Start-Job called as follows:

Start-Job -FilePath $scriptPath -ArgumentList $argumentList

...but this fails with this error:

System.Management.Automation.ValidationMetadataException:
Attribute cannot be added because it would cause the variable
ConfigFilename with value -ConfigFilename to become invalid.

...in this case, "ConfigFilename" is the first parameter in the param list defined by the second script, and my invocation is apparently trying to set its value to "-ConfigFilename", which is obviously intended to identify the parameter by name, not set its value.

What am I missing?

EDIT:

Ok, here is a mock-up of the to-be-called script, in a file named invokee.ps1

Param(
[parameter(Mandatory=$true)]
[alias("rc")]
[string]
[ValidateScript( {Test-Path $_ -PathType Leaf} )]
$ConfigurationFilename,
[alias("e")]
[switch]
$Evaluate,
[array]
[Parameter(ValueFromRemainingArguments=$true)]
$remaining)

function sayHelloWorld()
{
    Write-Host "Hello, everybody, the config file is <$ConfigurationFilename>."
    if ($ExitOnErrors)
    {
        Write-Host "I should mention that I was told to evaluate things."
    }
    Write-Host "I currently live here: $gScriptDirectory"
    Write-Host "My remaining arguments are: $remaining"
    Set-Content .\hello.world.txt "It worked"
}

$gScriptPath = $MyInvocation.MyCommand.Path
$gScriptDirectory = (Split-Path $gScriptPath -Parent)
sayHelloWorld

...and here is a mock-up of the calling script, in a file named invoker.ps1:

function pokeTheInvokee()
{
    $scriptPath = (Join-Path -Path "." -ChildPath "invokee.ps1")
    $scriptPath = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($scriptPath)
    
    $configPath = (Join-Path -Path "." -ChildPath "invoker.ps1")
    $configPath = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($configPath)
    
    $argumentList = @()
    $argumentList += ("-ConfigurationFilename", "`"$configPath`"")
    $argumentList += , "-Evaluate"

    Write-Host "Attempting to invoke-expression with: `"$scriptPath`" $argumentList"
    Invoke-Expression "`"$scriptPath`" $argumentList"
    Invoke-Expression ".\invokee.ps1 -ConfigurationFilename `".\invoker.ps1`" -Evaluate
    Write-Host "Invokee invoked."
}

pokeTheInvokee

When I run invoker.ps1, this is the error I'm currently getting on the first call to Invoke-Expression:

Invoke-Expression : You must provide a value expression on
the right-hand side of the '-' operator.

The second call works just fine, but one significant difference is that the first version is using arguments whose paths have spaces in them, and the second does not. Am I mishandling the presence of spaces in these paths?

Answer

Hoobajoob picture Hoobajoob · Oct 12, 2012

Aha. This turned out to be a simple problem of there being spaces in the path to the script.

Changing the Invoke-Expression line to:

Invoke-Expression "& `"$scriptPath`" $argumentList"

...was enough to get it to kick off. Thanks to Neolisk for your help and feedback!