我有一个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"
扩展到脚本的绝对路径,%*
扩展为参数列表。是否有捷径可寻?或者,至少,一种有效的方式?
答案 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"