我看到了this question和this question,但无法找到解决问题的方法。
所以情况如下: 我在脚本(.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个后台作业(使用带有3个元素的$ array)并使用事件将消息从后台作业传递到主机。我希望powershell主机每次显示“处理开始”和“处理结束”1次,“开始工作”和“结束工作”3次。但相反,我没有在控制台中显示“正在开始工作”/“结束工作”。
事件也被视为powershell中的一项工作,因此当我执行Get-Job时,我可以看到与事件工作相关的以下错误:
{术语'DisplayMessage'未被识别为cmdlet的名称, 功能,脚本文件或可操作程序。检查拼写 名称,或者如果包含路径,请验证路径是否正确 再试一次。}
我的问题:我们如何重用(或引用)我在调用Start-Job的同一个脚本中定义的函数(在我的情况下是DisplayMessage)?可能吗? 我知道我们可以使用-InitializationScript将函数/模块传递给Start-Job,但我不想两次编写DisplayMessage函数,一个是脚本,另一个是初始化。
答案 0 :(得分:8)
在后台作业中包含本地功能的简便方法:
$init=[scriptblock]::create(@"
function DoWork {$function:DoWork}
"@)
Start-Job -Name "DoActualWork" $ScriptBlock -ArgumentList $array -InitializationScript $init | Out-Null
答案 1 :(得分:5)
后台作业在单独的过程中运行,因此您使用Start-Job
创建的作业无法与功能交互,除非您将其包含在$scriptblock
中。
即使您在$scripblock
中包含该功能,Write-Host
也不会将其内容输出到控制台,直到您使用Get-Job | Receive-Job
来接收作业结果。
编辑问题是您的DisplayMessage
函数位于本地脚本范围内,而您的事件处理程序在另一个父作用域中运行(如全局即会话范围),因此它找不到你的功能。如果在全局范围内创建函数并从全局范围调用它,它将起作用。
我已修改您的脚本以执行此操作。我还修改了脚本块并在脚本完成时取消注册事件,因此当您多次运行脚本时,您将不会收到10条消息: - )
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
答案 2 :(得分:0)
我按如下方式工作;
function CreateTable {
$table = "" | select ServerName, ExitCode, ProcessID, StartMode, State, Status, Comment
$table
}
$init=[scriptblock]::create(@"
function CreateTable {$function:createtable}
"@)