Вызов второго сценария с аргументами из сценария

Я относительно новичок в 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

Я бы рекомендовал поймать исключение здесь