Передать аргументы в блок сценария в powershell

Я думаю, вы не можете просто сделать это:

  $servicePath = $args[0]

  if(Test-Path -path $servicePath) <-- does not throw in here

  $block = {

        write-host $servicePath -foreground "magenta"

        if((Test-Path -path $servicePath)) { <-- throws here.

              dowork 
        }
  }

Итак, как я могу передать свои переменные в блок сценария $block?


person dexter    schedule 02.05.2013    source источник
comment
Что вы будете делать со своим скриптовым блоком? Использовать Invoke-Command или &?   -  person Lars Truijens    schedule 03.05.2013
comment
Если вы планируете использовать &, вы можете сделать это: & { param($hello) $hello } -hello world   -  person JohnL    schedule 03.05.2013
comment
@LarsTruijens - я планирую провести Invoke-Command -Session   -  person dexter    schedule 03.05.2013


Ответы (8)


Keith answer также работает для Invoke-Command с тем ограничением, что вы не можете использовать именованные параметры. Аргументы должны быть установлены с использованием параметра -ArgumentList и должны быть разделены запятыми.

$sb = {
    param($p1,$p2)
    $OFS=','
    "p1 is $p1, p2 is $p2, rest of args: $args"
}
Invoke-Command $sb -ArgumentList 1,2,3,4

Также см. здесь и здесь.

person Lars Truijens    schedule 03.05.2013

Скриптблок — это просто анонимная функция. Вы можете использовать $args внутри блока сценария, а также объявить блок параметров, например

$sb = {
  param($p1, $p2)
  $OFS = ','
  "p1 is $p1, p2 is $p2, rest of args: $args"
}
& $sb 1 2 3 4
& $sb -p2 2 -p1 1 3 4
person Keith Hill    schedule 03.05.2013
comment
Верно, но разве замыкания не захватывают и переменные? Я бы предположил, что указанный выше $servicePath будет захвачен. - person Kakira; 16.09.2014
comment
Не в PowerShell. Если вы запустите скриптовый блок в текущем пространстве выполнения, тогда да, эти переменные подхватываются. Но это всего лишь функция динамической области видимости. Попробуйте это с блоком сценария для Start-Job, где блок сценария сериализуется в другой процесс PowerShell для выполнения, и вы не увидите автоматически захваченных переменных. - person Keith Hill; 16.09.2014
comment
Если бы я хотел запустить эту же функцию в качестве нового экземпляра Powershell на экране, есть ли способ передать аргументы? Я бы подумал, что это будет что-то вроде start powershell $sb(1,2). - person Steve Taylor; 20.07.2021

Кстати, при использовании блока сценария для запуска в отдельном потоке (многопоточном):

$ScriptBlock = {
    param($AAA,$BBB) 
    return "AAA is $($AAA) and BBB is $($BBB)"
}

$AAA = "AAA"
$BBB = "BBB1234"    
$null = Start-Job $ScriptBlock -ArgumentList $AAA,$BBB

затем дает:

$null = Start-Job $ScriptBlock -ArgumentList $AAA,$BBB    
Get-Job | Receive-Job
AAA is AAA and BBB is BBB1234
person Jean-Claude DeMars    schedule 25.05.2017

Для тех, кто читает в 2020 году и хочет использовать локальные переменные в блоке сценария удаленного сеанса, начиная с Powershell 3.0, вы можете использовать локальные переменные непосредственно в блоке сценария с модификатором области действия «$ Using». Пример:

$MyLocalVariable = "C:\some_random_path\"
acl = Invoke-Command -ComputerName REMOTEPC -ScriptBlock {Get-Acl $Using:MyLocalVariable}

Найдено в примере 9 из https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/invoke-command?view=powershell-7

person user724067    schedule 19.05.2020

По умолчанию PowerShell не захватывает переменные для ScriptBlock. Однако вы можете явно захватить его, вызвав GetNewClosure():

$servicePath = $args[0]

if(Test-Path -path $servicePath) <-- does not throw in here

$block = {

    write-host $servicePath -foreground "magenta"

    if((Test-Path -path $servicePath)) { <-- no longer throws here.

          dowork 
    }
}.GetNewClosure() <-- this makes it work
person Chris R. Donnelly    schedule 16.10.2017
comment
Обратите внимание, что GetNewClosure() не работает с Start-Job. - person Ian Kemp; 13.04.2018
comment
@IanKemp Интересно, знаете ли вы еще, почему это не так? Это не удается, как описано в исходном вопросе, или с другой ошибкой? - person Chris R. Donnelly; 13.04.2018
comment
@ChrisRDonnelly Кажется, что значения переменных просто не копируются в переменные в ScriptBlock, поэтому те, что внутри блока, в конечном итоге имеют значение по умолчанию (null). - person Ian Kemp; 13.04.2018
comment
Это работает только с глобальными переменными. Если у вас есть блок скрипта и другой блок скрипта внутри него, переменная, определенная внутри первого родительского блока скрипта, станет локальной, а GetNewClosure() не будет захватывать и делать ее доступной внутри второго дочернего блока скрипта. Нужно сделать его глобальным, например: function parentScriptBlock(myParam) { myVar = 3; $Global:myVar = $myVar; $Global:myParam = $myParam; childScriptBlock = { echo $myParam }.GetNewClosure(); # use the script block here } - person papo; 08.09.2020

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

$foo = {
    param($arg)

    Write-Host "Hello $arg from Foo ScriptBlock" -ForegroundColor Yellow
}

$foo2 = {
    param($arg)

    Write-Host "Hello $arg from Foo2 ScriptBlock" -ForegroundColor Red
}


function Run-Foo([ScriptBlock] $cb, $fooArg){

    #fake getting the args to pass into callback... or it could be passed in...
    if(-not $fooArg) {
        $fooArg = "World" 
    }
    #invoke the callback function
    $cb.Invoke($fooArg);

    #rest of function code....
}

Clear-Host

Run-Foo -cb $foo 
Run-Foo -cb $foo 

Run-Foo -cb $foo2
Run-Foo -cb $foo2 -fooArg "Tim"
person SpaceGhost440    schedule 07.02.2017

Три примера синтаксиса:

$a ={ 
  param($p1, $p2)
  "p1 is $p1"
  "p2 is $p2"
  "rest of args: $args"
}
//Syntax 1:
Invoke-Command $a -ArgumentList 1,2,3,4 //PS> "p1 is 1, p2 is 2, rest of args: 3 4"
//Syntax 2:
&$a -p2 2 -p1 1 3      //PS> "p1 is 1, p2 is 2, rest of args: 3"
//Syntax 3:
&$a 2 1 3              //PS> "p1 is 2, p2 is 1, rest of args: 3"
person chnnn    schedule 05.11.2020

Другая возможность: $a = { param($p1, $p2) p1 — $p1 p2 — $p2 остальные аргументы: $args } $a.invoke(1,2,3,4,5)

person koekjesdoos    schedule 26.02.2021