Как передать скриптовый блок как один из параметров в start-job

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

Он отлично работает, когда я передаю блок script в локальную функцию, но не через start-job

Работает следующий синтаксис:

function LocalFunction
{
    param (
        [parameter(Mandatory=$true)]
        [ScriptBlock]$ScriptBlock
    )

    &$ScriptBlock | % { echo "got $_" }
}

LocalFunction -ScriptBlock { echo "hello" }

Этот результат "получил привет", как ожидалось.

Но выполняется следующее:

$job = start-job -argumentlist { echo "hello" } -scriptblock {
    param (
        [parameter(Mandatory=$true)]
        [ScriptBlock]$ScriptBlock
    )
    &$ScriptBlock | % { echo "got $_" }
}
start-sleep -s 1
receive-job $job

Возвращаемая ошибка:

Receive-Job : Cannot process argument transformation on parameter 'ScriptBlock'. Cannot convert the " echo "hello" " value of type "System.String" to type "System.Management.Automation.ScriptBlock".

Итак, если я правильно читаю ошибку, похоже, что -argumentlist каким-то образом заставляет свои аргументы в строки.

Любые мастера PowerShell знают, как заставить этот синтаксис работать?

Спасибо заранее,

Бен

Ответ 1

Здесь один из способов решить эту проблему, передать код скриптового блока как строку, а затем создать скриптовый блок из строки внутри задания и выполнить его

Start-Job -ArgumentList "write-host hello"  -scriptblock {

    param (
        [parameter(Mandatory=$true)][string]$ScriptBlock
    )

    & ([scriptblock]::Create($ScriptBlock))

} | Wait-Job | Receive-Job

Ответ 2

Основываясь на моих экспериментах, PowerShell анализирует -ArgumentList, который является Object [], как строка, даже когда вы проходите блок script. Следующий код:

$job = start-job -scriptblock { $args[0].GetType().FullName } -argumentlist { echo "hello" }
start-sleep -s 1
receive-job $job

выводит следующий результат:

System.String

Насколько я знаю, единственным решением здесь является Shay, хотя вам не нужно передавать в -ArgumentList в виде строки, поскольку PowerShell будет анализировать ваш блок script как строку в этом случае.

Ответ 3

Похоже, что это работает сегодня.

function LocalFunction
{
    param
    (
        [scriptblock] $block
    )

    $block.Invoke() | % { "got $_" }
}

LocalFunction { "Hello"} 

Ответ 4

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

В powershell v1 вы можете сделать это:

$ScriptBlock = $executioncontext.invokecommand.NewScriptBlock($string)

И в powershell v2 вы можете это сделать:

$ScriptBlock = [scriptblock]::Create($string)

Итак, ваш код будет выглядеть так:

function LocalFunction
{
    param (
        [parameter(Mandatory=$true)]
        $ScriptBlock
    )

    $sb = [scriptblock]::Create($ScriptBlock)

    $sb | % { echo "got $_" }
}

LocalFunction -ScriptBlock "echo 'hello'"

"[scriptblock]:: Create ($ ScriptBlock)" поместит фигурные скобки вокруг строки для создания блока script.

Найдена информация здесь http://get-powershell.com/post/2008/12/15/ConvertTo-ScriptBlock.aspx

Ответ 5

Итак, если вы хотите вставить встроенный скриптовый блок, то решение Shay (как указано), вероятно, является лучшим. С другой стороны, если вы просто хотите передать скриптблока в качестве параметра, используйте переменную типа scriptblock, а затем передайте ее как значение параметра -ScriptBlock.

function LocalFunction
{
    param (
        [parameter(Mandatory=$true)]
        [ScriptBlock]$ScriptBlock
    )

    &$ScriptBlock | % { echo "got $_" }
}

[scriptblock]$sb = { echo "hello" }

LocalFunction -ScriptBlock $sb