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