У меня есть сценарий PowerShell, который использует пространство имен System.Data.OleDb
для чтения данных из книги Excel
. Поскольку 64-разрядная реализация поставщика Microsoft Jet отсутствует, сценарий необходимо запустить из 32-разрядного сеанса PowerShell. Вместо простого сбоя скрипта с сообщением об ошибке, если он запускается из 64-битного сеанса, я бы хотел, чтобы 64-битный сеанс вызывал скрипт и получал результаты из 32-битного сеанса. Я обнаружил, что это можно сделать с помощью командлета Start-Job
с переключателем -RunAs32
, однако у меня возникают проблемы с предоставлением значения для параметра -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;
}
... но когда я запускаю .\Test.ps1 'string' 12345
из 64-битного сеанса, он отображает ...
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"
расширяется до абсолютного пути скрипта, а %*
расширяется до списка параметров. Есть простой способ сделать это? Или, по крайней мере, способ, который работает?