Nice programing

스크립트의 인수를 사용하여 두 번째 스크립트를 호출합니다.

nicepro 2021. 1. 5. 21:10
반응형

스크립트의 인수를 사용하여 두 번째 스크립트를 호출합니다.


두 번째 PowerShell 스크립트의 함수에 인수로 전달하려는 이름 값 쌍 집합을 생성하는 구성 파일을 읽는 스크립트가 있습니다.

디자인 타임에이 구성 파일에 어떤 매개 변수가 배치 될지 모르겠습니다. 따라서이 두 번째 PowerShell 스크립트를 호출해야하는 시점에서 기본적으로이 두 번째 스크립트에 대한 경로가있는 변수 하나와 두 번째 path 변수에서 식별 된 스크립트에 전달할 인수 배열 인 변수입니다.

따라서 두 번째 스크립트 ($ scriptPath)에 대한 경로를 포함하는 변수는 다음과 같은 값을 가질 수 있습니다.

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

인수 ($ argumentList)를 포함하는 변수는 다음과 같습니다.

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

$ argumentList의 모든 인수를 사용하여이 상태에서 script.ps1을 실행하려면 어떻게해야합니까?

이 두 번째 스크립트의 쓰기 호스트 명령이이 첫 번째 스크립트가 호출 된 콘솔에 표시되기를 원합니다.

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"은 두 번째 스크립트에 의해 정의 된 매개 변수 목록의 첫 번째 매개 변수이며 내 호출은 분명히 이름으로 매개 변수를 식별하기위한 "-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.

두 번째 호출은 잘 작동하지만 첫 번째 버전은 경로에 공백이있는 인수를 사용하고 두 번째 버전은 그렇지 않다는 점에서 중요한 차이점이 있습니다. 이 경로에 공백이 있는지 잘못 처리하고 있습니까?


아하. 이것은 스크립트 경로에 공백이 있다는 간단한 문제로 밝혀졌습니다.

Invoke-Expression 줄을 다음과 같이 변경합니다.

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

... 시작하기에 충분했습니다. 도움과 피드백을 주신 Neolisk에게 감사드립니다!


Invoke-Expression완벽하게 작동해야하며 올바르게 사용하고 있는지 확인하십시오. 귀하의 경우에는 다음과 같이 보일 것입니다.

Invoke-Expression "$scriptPath $argumentList"

I tested this approach with Get-Service and seems to be working as expected.


Much simpler actually:

Method 1:

Invoke-Expression $scriptPath $argumentList

Method 2:

& $scriptPath $argumentList

Method 3:

$scriptPath $argumentList

If you have spaces in your scriptPath, don't forget to escape them `"$scriptPath`"


Here's an answer covering the more general question of calling another PS script from a PS script, as you may do if you were composing your scripts of many little, narrow-purpose scripts.

I found it was simply a case of using dot-sourcing. That is, you just do:

# This is Script-A.ps1

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

I found all the Q/A very confusing and complicated and eventually landed upon the simple method above, which is really just like calling another script as if it was a function in the original script, which I seem to find more intuitive.

Dot-sourcing can "import" the other script in its entirety, using:

. ./Script-B.ps1

It's now as if the two files are merged.

Ultimately, what I was really missing is the notion that I should be building a module of reusable functions.


We can use splatting for this:

& $command @args

where @args (automatic variable $args) is splatted into array of parameters.

Under PS, 5.1


I tried the accepted solution of using the Invoke-Expression cmdlet but it didn't work for me because my arguments had spaces on them. I tried to parse the arguments and escape the spaces but I couldn't properly make it work and also it was really a dirty work around in my opinion. So after some experimenting, my take on the problem is this:

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

The only drawback of this solution is that you need to make sure that your script doesn't have a "Script" or "ArgumentList" parameter.


You can execute it same as SQL query. first, build your command/Expression and store in a variable and execute/invoke.

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

It is pretty forward, I don't think it needs explanations. So all set to execute your command now,

Invoke-Expression $command

I would recommend catching the exception here

ReferenceURL : https://stackoverflow.com/questions/12850487/invoke-a-second-script-with-arguments-from-a-script

반응형