我看到了这个问题和这个问题,但找不到解决方法。
那么情况是这样的:我在脚本(.ps1)文件中有两个函数DoWork和DisplayMessage。下面是代码:
### START OF SCRIPT ###
function DoWork
{
$event = Register-EngineEvent -SourceIdentifier NewMessage -Action {
DisplayMessage($event.MessageData)
}
$scriptBlock = {
Register-EngineEvent -SourceIdentifier NewMessage -Forward
$message = "Starting work"
$null = New-Event -SourceIdentifier NewMessage -MessageData $message
### DO SOME WORK HERE ###
$message = "Ending work"
$null = New-Event -SourceIdentifier NewMessage -MessageData $message
Unregister-Event -SourceIdentifier NewMessage
}
DisplayMessage("Processing Starts")
$array = @(1,2,3)
foreach ($a in $array)
{
Start-Job -Name "DoActualWork" $ScriptBlock -ArgumentList $array | Out-Null
}
#$jobs = Get-Job -Name "DoActualWork"
While (Get-Job -Name "DoActualWork" | where { $_.State -eq "Running" } )
{
Start-Sleep 1
}
DisplayMessage("Processing Ends")
Get-Job -Name "DoActualWork" | Receive-Job
}
function DisplayMessage([string]$message)
{
Write-Host $message -ForegroundColor Red
}
DoWork
### END OF SCRIPT ###
我正在创建3个后台作业(使用$array与3个元素),并使用事件从后台作业传递消息到主机。我希望powershell主机显示"Processing Starts"one_answers"Processing Ends"各1次,"Starting work"one_answers"Ending work"各3次。但是,我没有得到"开始工作"/"结束工作"显示在控制台。
事件在powershell中也被视为一个作业,所以当我执行Get-Job时,我可以看到以下与事件作业相关的错误:
{术语"DisplayMessage"未被识别为cmlet的名称,函数、脚本文件或可操作程序。检查单词的拼写名称,或者如果包含路径,则验证路径是否正确再试一次。}
我的问题:我们如何重用(或引用)一个函数(DisplayMessage在我的情况下)定义在同一脚本从我调用Start-Job?这可能吗?我知道我们可以使用-InitializationScript来传递函数/模块到Start-Job,但我不想写DisplayMessage函数两次,一个在script中,另一个在InitializationScript中。
在后台任务中包含本地函数的简单方法:
$init=[scriptblock]::create(@"
function DoWork {$function:DoWork}
"@)
Start-Job -Name "DoActualWork" $ScriptBlock -ArgumentList $array -InitializationScript $init | Out-Null
后台作业在一个单独的进程中运行,所以你用Start-Job
创建的作业不能与函数交互,除非你把它们包含在$scriptblock
中。
即使您在$scripblock
中包含了该功能,Write-Host
也不会将其内容输出到控制台,直到您使用Get-Job | Receive-Job
接收作业结果。
EDIT问题是您的DisplayMessage
函数在本地脚本范围内,而您的事件处理程序在不同的父范围内运行(如全局这是会话范围),所以它找不到您的函数。如果您在全局作用域中创建函数并从全局作用域中调用它,它将正常工作。
我已经修改了你的脚本,现在这样做。我还修改了scriptblock,并在脚本完成时取消了事件的注册,这样当您多次运行脚本时,您就不会得到10x消息:-)
Untitled1.ps1
function DoWork
{
$event = Register-EngineEvent -SourceIdentifier NewMessage -Action {
global:DisplayMessage $event.MessageData
}
$scriptBlock = {
Register-EngineEvent -SourceIdentifier NewMessage -Forward
$message = "Starting work $args"
$null = New-Event -SourceIdentifier NewMessage -MessageData $message
### DO SOME WORK HERE ###
$message = "Ending work $args"
$null = New-Event -SourceIdentifier NewMessage -MessageData $message
Unregister-Event -SourceIdentifier NewMessage
}
DisplayMessage("Processing Starts")
$array = @(1,2,3)
foreach ($a in $array)
{
Start-Job -Name "DoActualWork" $ScriptBlock -ArgumentList $a | Out-Null
}
#$jobs = Get-Job -Name "DoActualWork"
While (Get-Job -Name "DoActualWork" | where { $_.State -eq "Running" } )
{
Start-Sleep 1
}
DisplayMessage("Processing Ends")
#Get-Job -Name "DoActualWork" | Receive-Job
}
function global:DisplayMessage([string]$message)
{
Write-Host $message -ForegroundColor Red
}
DoWork
Get-EventSubscriber | Unregister-Event
测试PS > .Untitled1.ps1
Processing Starts
Starting work 1
Starting work 2
Ending work 1
Ending work 2
Starting work 3
Ending work 3
Processing Ends
我让它工作如下;
function CreateTable {
$table = "" | select ServerName, ExitCode, ProcessID, StartMode, State, Status, Comment
$table
}
$init=[scriptblock]::create(@"
function CreateTable {$function:createtable}
"@)