Подтвердить что ты не робот

Вызов второй script с аргументами из script

У меня есть скрипт, который читает файл конфигурации, который приводит к набору пар имя-значение, которые я хотел бы передать в качестве аргументов функции во втором скрипте PowerShell.

Я не знаю, какие параметры будут помещены в этот файл конфигурации во время разработки, поэтому в тот момент, когда мне нужно вызвать этот второй сценарий PowerShell, у меня в основном только одна переменная, которая имеет путь к этому второму сценарию, и вторая переменная, которая представляет собой массив аргументов для передачи в сценарий, указанный в переменной пути.

Таким образом, переменная, содержащая путь ко второму сценарию ($ scriptPath), может иметь значение вроде:

"c:\the\path\to\the\second\script.ps1"

Переменная, содержащая аргументы ($ argumentsList), может выглядеть примерно так:

-ConfigFilename "doohickey.txt" -RootDirectory "c:\some\kind\of\path" -Max 11

Как мне перейти от такого положения дел к выполнению script.ps1 со всеми аргументами из $ argumentsList?

Мне бы хотелось, чтобы любые команды write-host из этого второго скрипта были видны консоли, из которой вызывается этот первый скрипт.

Я пробовал точечный источник, 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" является первым параметром в списке параметров, определенном вторым сценарием, и мой вызов, очевидно, пытается установить его значение в "-ConfigFilename", которое, очевидно, предназначено для идентификации параметра посредством имя, а не установить его значение.

Что мне не хватает?

РЕДАКТИРОВАТЬ:

Хорошо, вот макет сценария, который должен быть вызван, в файле с именем 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.ps1:

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.

Второй вызов работает просто отлично, но одно существенное отличие состоит в том, что первая версия использует аргументы, пути которых содержат пробелы, а вторая - нет. Я неправильно обращаюсь с наличием пробелов в этих путях?

4b9b3361

Ответ 1

Ага. Это оказалось простой проблемой существования пробелов на пути к script.

Изменение строки Invoke-Expression:

Invoke-Expression "& `"$scriptPath`" $argumentList"

... было достаточно, чтобы заставить его начать. Благодаря Neolisk за вашу помощь и отзывы!

Ответ 2

Invoke-Expression должен работать отлично, просто убедитесь, что вы используете его правильно. Для вашего случая это должно выглядеть так:

Invoke-Expression "$scriptPath $argumentList"

Я тестировал этот подход с помощью Get-Service и, похоже, работал как ожидалось.

Ответ 3

На самом деле проще:

Метод 1:

Invoke-Expression $scriptPath $argumentList

Метод 2:

& $scriptPath $argumentList

Способ 3:

$scriptPath $argumentList

Если у вас есть пробелы в scriptPath, не забудьте избежать их `"$scriptPath`"

Ответ 4

Вот ответ, охватывающий более общий вопрос о вызове другого PS script из PS script, как вы можете это сделать, если бы вы составляли ваши скрипты из многих небольших узкоспециальных скриптов.

Я нашел, что это просто случай использования точек доступа. То есть, вы просто делаете:

# This is Script-A.ps1

. ./Script-B.ps1 -SomeObject $variableFromScriptA -SomeOtherParam 1234;

Я нашел все Q/A очень запутанным и сложным и в конечном итоге приземлился на простой метод выше, который действительно так же, как вызов другого script, как если бы он был функцией в исходном script, который, как мне кажется, найти более интуитивно понятный.

Dot-sourcing может "импортировать" другой script целиком, используя:

. ./Script-B.ps1

Теперь, как если бы эти два файла были объединены.

В конечном счете, я действительно не понял, что я должен создавать модуль многоразовых функций.

Ответ 6

Я попробовал принятое решение использования командлета 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

Единственным недостатком этого решения является то, что вам нужно убедиться, что ваш script не имеет параметра "Script" или "ArgumentList".

Ответ 7

Вы можете выполнить его так же, как SQL-запрос. сначала создайте свою команду/Выражение и сохраните в переменной и выполните/вызовите.

$command =  ".\yourExternalScriptFile.ps1" + " -param1 '$paramValue'"

Это довольно вперед, я не думаю, что ему нужны объяснения. Итак, все настроено на выполнение вашей команды сейчас,

Invoke-Expression $command

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