Windows PowerShell脚本如何将其参数传递给另一个脚本调用?

时间:2012-03-29 17:16:49

标签: powershell parameters 32bit-64bit powershell-v2.0 powershell-jobs

我有一个PowerShell脚本,它使用System.Data.OleDb命名空间从Excel工作簿中读取数据。由于Microsoft Jet提供程序没有64位实现,因此需要从32位PowerShell会话运行该脚本。如果脚本从64位会话运行,而不是简单地使脚本失败并显示错误消息,我希望让64位会话调用脚本并从32位会话中检索结果。我发现可以使用带有-RunAs32开关的Start-Job cmdlet来完成此操作,但是我无法为-ArgumentList参数提供值。

我想出了以下内容来搜索具有值的任何脚本参数并从中构建命令行:

function GetValueText([Object] $value)
{
    [String] $text = if ($value -eq $null) {
        '$null';
    } elseif ($value -is [String]) {
        "'$value'";
    } elseif ($value -is [Array]) {
        '@({0})' -f (($value | ForEach-Object { GetValueText $_ }) -join ', ');
    } else {
        "$value";
    }

    return $text;
}

if ([IntPtr]::Size -gt 4)
{
    [String] $scriptPath = $MyInvocation.MyCommand.Path;
    [String[]] $parameters = @(
        $MyInvocation.MyCommand.Parameters.Keys `
        | ForEach-Object {
            [Object] $parameterValue = Get-Variable -Name $_ -ValueOnly;

            if ($parameterValue -ne $null)
            {
                [String] $parameterValueText = GetValueText $parameterValue;

                '-{0}' -f $_;
                $parameterValueText;
            }
        }
    );
    [Object] $job = Start-Job -FilePath $scriptPath -RunAs32 -ArgumentList $parameters;
    [Object[]] $data = $job | Wait-Job | Receive-Job;

    $data;
}
else
{
    # Retrieve data...
}

当它到达Start-Job行时,会生成错误消息"Cannot convert value "-Argument1" to type "System.Int32[]""-Argument1是脚本的第一个参数,类型为[Int32[]],这是否意味着-ArgumentList仅适用于位置参数而非命名参数?

我也尝试将其简化为......

param(
    [String] $stringArg,
    [Int32] $int32Arg
)

$PSBoundParameters;

if ([IntPtr]::Size -gt 4)
{
    [String] $scriptPath = $MyInvocation.MyCommand.Path;
    [Object] $job = Start-Job -FilePath $scriptPath -RunAs32 -ArgumentList @PSBoundParameters;

    $job | Wait-Job | Receive-Job;
}
else
{
    Get-Date;
}

...但是当我从64位会话运行.\Test.ps1 'string' 12345时,它会显示...

Key                                                         Value
---                                                         -----
stringArg                                                   string
int32Arg                                                    12345
Start-Job : Missing an argument for parameter 'ArgumentList'. Specify a parameter of type 'System.Object[]' and try again.
At X:\Test.ps1:11 char:72
+     [Object] $job = Start-Job -FilePath $scriptPath -RunAs32 -ArgumentList <<<<  @PSBoundParameters;
    + CategoryInfo          : InvalidArgument: (:) [Start-Job], ParameterBindingException
    + FullyQualifiedErrorId : MissingArgument,Microsoft.PowerShell.Commands.StartJobCommand

...所以@PSBoundParameters似乎评估为$null

我不确定为什么这不起作用或者还有什么可尝试的。基本上,我只是在寻找PowerShell等效的批处理文件如何重新启动自己的相同参数......

"%~dpnx0" %*

...其中"%~dpnx0"扩展到脚本的绝对路径,%*扩展为参数列表。是否有捷径可寻?或者,至少,一种有效的方式?

2 个答案:

答案 0 :(得分:2)

这可能看起来有点奇怪,但是:

param(
[String] $stringArg,
[Int32] $int32Arg
)

if ([IntPtr]::Size -gt 4)
{
[String] $scriptPath = $MyInvocation.MyCommand.Path;

$params = @()
$psboundparameters.keys |
  foreach {
      $params += "-$($_)"
      $params +=  $psboundparameters.$_
      }


$sb = [scriptblock]::Create(@"
&'$scriptpath' $params
"@)

[Object] $job = Start-Job -scriptblock $sb -RunAs32 
$job | Wait-Job | Receive-Job;
}
else
{
Get-Date
}

答案 1 :(得分:1)

您可以通过编程方式重新启动脚本,如下所示:32位进程:

[cmdletbinding()]
param(
    [parameter(Mandatory=$true)]
    [String] $stringArg,
    [parameter(Mandatory=$true)]
    [Int32] $int32Arg
)

if ([IntPtr]::Size -ne 4) {
    $p = $PSBoundParameters
    $32bitPs = 'C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe'
    $myArgs = @($MyInvocation.MyCommand.Path)
    $myArgs += ( $p.Keys | % { ('-' + $_), $p.Item($_) } )
    Start-Process -NoNewWindow -FilePath $32bitPs -ArgumentList $myArgs
    exit
}

Write-Host "Hi I'm a 32 bit process, my args are:"
$PSBoundParameters
# Do 32 bit stuff here...
Read-Host "Press enter to quit"