Вызов второго сценария с аргументами из сценария
Я относительно новичок в PowerShell и имею скрипт, который читает файл конфигурации, который приводит к набору пар значений имен, которые я хотел бы передать в качестве аргументов функции во втором скрипте PowerShell.
Я не знаю, какие параметры будут помещены в этот файл конфигурации во время разработки, поэтому прямо в тот момент, когда мне нужно вызвать этот второй скрипт PowerShell, у меня в основном есть только одна переменная, которая имеет путь к этому второму скрипту, и второй переменная, представляющая собой массив аргументов для передачи скрипту, указанному в переменной path.
таким образом, переменная, содержащая путь ко второму скрипту ($scriptPath), может иметь значение типа:
"c:thepathtothesecondscript.ps1"
переменная, содержащая аргументы ($argumentList), может выглядеть примерно так:
-ConfigFilename "doohickey.txt" -RootDirectory "c:somekindofpath" -Max 11
как мне перейти от такого состояния дел к выполнению скрипта.ps1 со всеми аргументами из $argumentList?
Я хотел бы любой команды 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", которое, очевидно, предназначено для идентификации параметра по имени, а не для установки его значения.
что я упустил?
EDIT:
Ok, вот макет сценария, который будет называться, в файле с именем 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.пс1:
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.
второй вызов работает просто отлично, но одно существенное различие заключается в том, что первая версия использует аргументы, пути которых имеют пробелы в них, а вторая-нет. Я неправильно понимаю наличие пространства на этих путях?
7 ответов
Аха. Это оказалось простой проблемой наличия пробелов в пути к скрипту.
изменение строки Invoke-Expression на:
Invoke-Expression "& `"$scriptPath`" $argumentList"
...этого было достаточно, чтобы начать. Спасибо Neolisk за вашу помощь и отзывы!
Invoke-Expression
должны отлично работать, просто убедитесь, что вы используете его правильно. Для вашего случая это должно выглядеть так:
Invoke-Expression "$scriptPath $argumentList"
я протестировал этот подход с Get-Service и, похоже, работает так, как ожидалось.
много проще на самом деле:
Способ 1:
Invoke-Expression $scriptPath $argumentList
Способ 2:
& $scriptPath $argumentList
Способ 3:
$scriptPath $argumentList
если у вас есть пробелы в вашей scriptPath
, не забудьте защитить их `"$scriptPath`"
вот ответ, охватывающий более общий вопрос о вызове другого сценария PS из сценария PS, Как вы можете сделать,если вы составляете свои сценарии многих маленьких, узких сценариев.
я обнаружил, что это просто случай использования точечного поиска. То есть вы просто делаете:
# This is Script-A.ps1
. ./Script-B.ps1 -SomeObject $variableFromScriptA -SomeOtherParam 1234;
Я нашел все Q / A очень запутанным и сложным и в конечном итоге приземлился на простой метод выше, который действительно похож на вызов другого скрипта, как если бы это была функция в оригинальный сценарий, который мне кажется более понятным.
Dot-sourcing может "импортировать" другой скрипт полностью, используя:
. ./Script-B.ps1
теперь как будто два файла объединены.
в конечном счете, мне действительно не хватало понятия, что я должен создавать модуль многоразовых функций.
можно использовать сплаттинг для этого:
& $command @args
здесь @args
(автоматическая переменная $args) разбивается на массив параметров.
под PS, 5.1
я попробовал принятое решение с помощью командлета Invoke-Expression, но оно не сработало, потому что в моих аргументах были пробелы. Я попытался разобрать аргументы и избежать пробелов, но я не мог должным образом заставить его работать, а также это была действительно грязная работа по моему мнению. Итак, после некоторых экспериментов, мой взгляд на проблему таков:
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".
вы можете выполнить его так же, как SQL-запрос. во-первых, создайте команду/выражение и сохраните в переменной и выполните/invoke.
$command = ".\yourExternalScriptFile.ps1" + " -param1 '$paramValue'"
это довольно вперед, я не думаю, что это требует объяснений. Итак, все готово для выполнения вашей команды сейчас,
Invoke-Expression $command
Я бы рекомендовал поймать исключение здесь