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?
To pass multiple parameters you must use the command line syntax that includes the names of the parameters. For example, here is a sample PowerShell script that runs the Get-Service function with two parameters. The parameters are the name of the service(s) and the name of the Computer.
PowerShell scripts can run other scripts. Just put the command that runs the second script as a command in the first script (the same way as you would type it on the PowerShell command line). You can experiment with this very easily by doing a quick test.
To make sure PowerShell executes what you want, navigate in the command line to the same directory where you will save your scripts. Name the script Unnamed_Arguments_Example_1. ps1 and run it with the argument FOO. It will echo back FOO.
Running a script with PowerShell To open the PowerShell console, click on the Start button (or search button), type powershell, and click Run as Administrator. To run a script in the PowerShell console, you can either: Use the full path to script, like: C:\TEMP\MyNotepadScript. ps1.
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!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With