使用脚本中的参数调用第二个脚本

时间:2012-10-12 00:12:35

标签: powershell parameter-passing command-line-arguments invoke-command start-job

我有一个脚本,它读取一个配置文件,该文件生成一组名称值对,我希望将它作为参数传递给第二个PowerShell脚本中的函数。

我不知道在设计时将在此配置文件中放置哪些参数,所以就在我需要调用第二个PowerShell脚本时,我基本上只有一个变量具有第二个脚本的路径,和第二个变量,它是一个传递给路径变量中标识的脚本的参数数组。

因此,包含第二个脚本($ scriptPath)路径的变量可能具有如下值:

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

包含参数($ argumentList)的变量可能类似于:

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

如何从这种状态到使用$ argumentList中的所有参数执行script.ps1?

我希望来自第二个脚本的任何write-host命令对于调用此第一个脚本的控制台是可见的。

我尝试过dot-sourcing,Invoke-Command,Invoke-Expression和Start-Job,但我还没有找到一种不会产生错误的方法。

例如,我认为最简单的第一条路线是尝试按下列方式调用Start-Job:

Start-Job -FilePath $scriptPath -ArgumentList $argumentList

...但是这个失败并出现此错误:

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

...在这种情况下,“ConfigFilename”是第二个脚本定义的param列表中的第一个参数,我的调用显然试图将其值设置为“-ConfigFilename”,这显然是为了识别参数名称,不设置其值。

我错过了什么?

修改

好的,这是一个名为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

...这里是调用脚本的模型,位于名为invokee.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

当我运行invoker.ps1时,这是我第一次调用Invoke-Expression时遇到的错误:

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

第二个调用工作得很好,但一个显着的区别是第一个版本使用的参数的路径中有空格,第二个版本没有。我错误地处理了这些路径中空间的存在吗?

8 个答案:

答案 0 :(得分:48)

啊哈。事实证明这是一个简单的问题,即脚本路径中有空格。

将Invoke-Expression行更改为:

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

......足以让它开始。感谢Neolisk的帮助和反馈!

答案 1 :(得分:42)

Invoke-Expression应该可以正常工作,只需确保您正确使用它。对于你的情况,它应该是这样的:

Invoke-Expression "$scriptPath $argumentList"

我使用Get-Service测试了这种方法,似乎按预期工作。

答案 2 :(得分:27)

实际上很多simpler

方法1:

Invoke-Expression $scriptPath $argumentList

方法2:

& $scriptPath $argumentList

方法3:

$scriptPath $argumentList

如果scriptPath中有空格,请不要忘记逃避`"$scriptPath`"

答案 3 :(得分:9)

这里有一个答案,涵盖了从PS脚本调用另一个PS脚本这一更普遍的问题,就像你编写许多小的,狭窄目的脚本的脚本一样。

我发现这只是一个使用点源的案例。也就是说,你只需:

# This is Script-A.ps1

. ./Script-B.ps1 -SomeObject $variableFromScriptA -SomeOtherParam 1234;

我发现所有的Q / A非常令人困惑和复杂,并最终落在上面的简单方法上,这就像调用另一个脚本就好像它是原始脚本中的一个函数一样,我似乎更直观。

点源可以&#34;导入&#34;完整的另一个脚本,使用:

. ./Script-B.ps1

现在好像合并了两个文件。

最终,我真正缺少的是我应该构建一个可重用函数模块的概念。

答案 4 :(得分:5)

我们可以使用splatting

.sql

其中& $command @args automatic variable $args)被映射到参数数组中。

根据PS,5.1

答案 5 :(得分:2)

我尝试了使用Invoke-Expression cmdlet的已接受解决方案,但它对我不起作用,因为我的参数上有空格。我试图解析参数并逃避空间,但我无法正常工作,而且在我看来这真的是一个肮脏的工作。 经过一些实验,我对这个问题的看法是:

function Invoke-Script
{
    param
    (
        [Parameter(Mandatory = $true)]
        [string]
        $Script,

        [Parameter(Mandatory = $false)]
        [object[]]
        $ArgumentList
    )

    $ScriptBlock = [Scriptblock]::Create((Get-Content $Script -Raw))
    Invoke-Command -NoNewScope -ArgumentList $ArgumentList -ScriptBlock $ScriptBlock -Verbose
}

# example usage
Invoke-Script $scriptPath $argumentList

此解决方案的唯一缺点是您需要确保您的脚本没有“脚本”或“ArgumentList”参数。

答案 6 :(得分:0)

您可以像SQL查询一样执行它。 首先,构建您的命令/表达式并存储在变量中并执行/调用。

$command =  ".\yourExternalScriptFile.ps1" + " -param1 '$paramValue'"

这是非常前进的,我不认为它需要解释。 所以现在都设置为执行命令,

Invoke-Expression $command

我建议在这里捕获例外

答案 7 :(得分:0)

我假设您要从另一个.ps1文件运行.ps1文件[此处$ scriptPath以及存储在$ argumentList中的多个参数]

Invoke-Expression "& $scriptPath $argumentList"

这段代码可以正常工作