PowerShell ScriptBlock и несколько функций

Я написал следующий код:

cls
function GetFoo() { 
    function GetBar() {
        $bar = "bar"
        $bar
    }

    $foo = "foo"
    $bar = GetBar
    $foo
    $bar
}


$cred = Get-Credential "firmwide\srabhi_adm"
$result = Invoke-Command -Credential $cred -ComputerName localhost 
-ScriptBlock ${function:GetFoo}
Write-Host $result[0]
Write-Host $result[1]

Это работает, но я не хочу определять GetBar внутри GetFoo.

Могу ли я сделать что-то подобное?

cls
function GetBar() {
    $bar = "bar"
    $bar
}

function GetFoo() {     
    $foo = "foo"
    $bar = GetBar
    $foo
    $bar
}


$cred = Get-Credential "firmwide\srabhi_adm"
$result = Invoke-Command -Credential $cred -ComputerName localhost 
-ScriptBlock ${function:GetFoo; function:GetBar; call GetFoo}
Write-Host $result[0]
Write-Host $result[1]

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


person Knows Not Much    schedule 27.10.2012    source источник


Ответы (4)


Проблема в том, что Invoke-Command может видеть только то, что находится внутри ScriptBlock, он не может видеть функции, определенные снаружи. Если очень хочется - можно запустить все в одну строку, вот так:

$result = Invoke-Command  -ComputerName localhost  -ScriptBlock { function GetBar() { $bar = "bar"; $bar }; function GetFoo() { $foo = "foo"; $bar = GetBar; $foo;  $bar }; GetFoo }

Но лично я бы посоветовал сохранять функции в скрипт и вызывать Invoke-Command с параметром -FilePath, вот так:

$result = Invoke-Command  -ComputerName localhost  -FilePath "\1.ps1"
person Andrey Marchuk    schedule 29.10.2012

Я знаю, что это старая тема, но я надеюсь, что это поможет кому-то.

[CmdletBinding()]
param()
$barScriptBlock = {
    function GetBar() {
        $bar = "bar"
        $bar
    }
}
$fooScriptBlock = {
    function GetFoo() {     
        $foo = "foo"
        $bar = GetBar
        $foo
        $bar
    }
}
# Concatenate all functions into a script block; add a parameter for extra credit.
$scriptBlockString = @"
param(`$hello)
$($barScriptBlock.ToString())
$($fooScriptBlock.ToString())
`$hello
GetFoo
"@
Write-Verbose $scriptBlockString
# Convert combined string to script block.
$finalScriptBlock = [ScriptBlock]::Create($scriptBlockString)
# Run synchronously, passing runtime parameter.
$result = & $finalScriptBlock "Hola"
# (Async results would not be reiably accessed here yet.)
Write-Host $result[0]
Write-Host $result[1]
Write-Host $result[2]
person Joe Zamora    schedule 23.05.2020

Опираясь на ответ Джо Заморы, вот команда, которая, как мне кажется, подходит вопрос лучше:

$result = Invoke-Command -Credential $cred -ScriptBlock ([ScriptBlock]::Create("${function:GetFoo}; ${function:GetBar}; GetFoo"))
person Philip Busse    schedule 17.03.2021

Я недавно получил это:

function GetBar() {
    $bar = "bar"
    $bar
}

function GetFoo() {     
    $foo = "foo"
    $bar = GetBar
    $foo
    $bar
}

$NewScriptBlock = [scriptblock]::Create("function GetBar() { ${function:GetBar} } function GetFoo() { ${function:GetFoo} } GetFoo")
Invoke-Command -ComputerName localhost -ScriptBlock $NewScriptBlock

В качестве альтернативы вы можете сэкономить строку, используя:

Invoke-Command -ComputerName localhost -ScriptBlock ([scriptblock]::Create("function GetBar() { ${function:GetBar} } function GetFoo() { ${function:GetFoo} } GetFoo"))

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

person Harmen Hulsman    schedule 07.06.2021