跨会话的 Powershell 作业?
Powershell jobs across sessions?
我一直在探索 Powershell 作业(使用 Start-Job、Get-Job、Receive-Job 等)。
只要我保持在同一个 powershell session/window,一切都很好,但是如果我打开一个新的 Powershell window 并执行“Get-Job”,它 returns 没有工作.
没有任何方法可以在 Powershell 中启动后台作业,关闭 window/session,然后稍后从另一个 session/window 访问它吗?我有几个长 运行 cmdlet,我希望它们能够在后台启动,然后稍后检查,而不必保证使用相同的提示。
更新
正如我所承诺的那样,我为你找到了另一个潜力 DaveUK。今天我了解到 PowerShell 中的“RunSpaces”。我认为这可能是我们 are/were 都在寻找的东西。它需要更多的工作,但使用 Boe Prox 的 Thread-Safe Collections. The below example is taken from Sharing Variables and Live Objects Between PowerShell Runspaces。他的文章详细描述了它的作用、工作原理,甚至还做了多个 'jobs'.
使用 Debug-Runspace 您可以从其他会话监控它。我将致力于在此答案中提供更多详细信息,以防该网站消失。但就目前而言,希望这会有所帮助。
$hash = [hashtable]::Synchronized(@{})
$hash.value = 1
$hash.Flag = $True
$hash.Host = $host
Write-host ('Value of $Hash.value before background runspace is {0}' -f $hash.value) -ForegroundColor Green -BackgroundColor Black
$runspace = [runspacefactory]::CreateRunspace()
$runspace.Open()
$runspace.SessionStateProxy.SetVariable('Hash',$hash)
$powershell = [powershell]::Create()
$powershell.Runspace = $runspace
$powershell.AddScript({
While ($hash.Flag) {
$hash.value++
$hash.Services = Get-Service
$hash.host.ui.WriteVerboseLine($hash.value)
Start-Sleep -Seconds 5
}
}) | Out-Null
$handle = $powershell.BeginInvoke()
上一个回复
几年来,我一直在尝试监控后台作业,而不依赖主要 window 保持开放状态,但尚未找到一个非 hacky 解决方案。这让我相信使用内置的“-Job”功能是不可能的。因此,这并不是主要问题的真正答案,而是我使用的解决方法。基本上它是在创建我自己的“工作”设置,因为内置的功能不像我想要的那样。在此请注意,我很少 运行 在新流程中“完成一项工作”。这通常是一个创造许多就业机会的过程。如果您长期需要 运行 的 cmdlet,我会在它自己的 PowerShell 进程中启动它,并详细记录到文件中。
对于“后台进程”中的 运行 多个作业,我将使用各种模板构建您的 cmdlet 或作业。
- 将输出记录到一个文件中,而不是试图依赖从 Receive-Job 中读取它。
- 实现一种在使用完后停止 cmdlet 的方法,我通常做的是在使用 JobID 启动作业时创建一个文件,如果 JobID 文件不再存在,则结束作业。这样,如果您想停止它,您可以删除该 JobID。我也经常给他们起名字,所以我记得是什么工作。
- 如果您想要状态报告,请执行与 'JobID' 文件类似的项目,但类似于 JobID-Status,它会在状态所在的日志文件中添加一行,然后删除该文件.
- 最后,您必须从当前所在的 PowerShell window 中单独启动作业进程。使用 Start-Process 调用脚本启动作业会将其与主程序分离 window进入“后台”进程。请记住,您调用的脚本应该在作业完成时退出 PowerShell。类似于:
示例启动进程脚本:
$Jobs = @("Name1", "Name2")
ForEach ($JobName in $Jobs) {
$Job = Start-Job -Name $JobName -ScriptBlock {
# Code Here either static file or from variable
# With logic to stop a job if the file is removed, and create the file
}
}
$JobsRunning = $true
while ($JobsRunning) {
$JobsRunning = $false
ForEach ($JobName in $Jobs) {
if ((Get-Job -Name $JobName).State -ne "Completed") {
$JobsRunning = $true
}
}
Start-Sleep -seconds 120
}
}
exit
我没有您想要的完整解决方案,但在多年想要此功能并通读 Google、M$、SO 等上的所有内容后,我来到了结论不可能在 PowerShell window 会话之间传输作业。
我希望我是错的并且有人发布了如何做。如果不是上面概述的方式对我很有用。烦人和一些额外的工作,但有效。
我遇到了 PSScheduledJob 模块,它似乎比常规作业更适合解决我的问题:
https://docs.microsoft.com/en-us/powershell/module/psscheduledjob/?view=powershell-5.1
计划的作业似乎确实存在并且可以从任何 PS 会话中检索,因此您可以将其用作触发“作业”的方式,该作业即使在您关闭后也会继续 运行 PS window.
到目前为止,我发现的唯一问题是 ScheduledJob 在运行时会生成一个常规作业,但该常规作业在完成之前没有子作业并且 progress/status 不可用。似乎无法监控工作的 status/output,因为它是 运行,所以这仍然不完美:(
我建议研究工作流,因为它们被设计为健壮的,可以处理长时间的 运行ning 任务,并且可以从 outages/reboots 中恢复。但是,您也可以在后台使用 Invoke-Command
和 -InDisconnectedSession
到 运行 命令或脚本,然后从相同或不同的机器再次连接到它。试一试这个例子。
创建会话
注意 - 在我的测试中 运行在本地需要管理员,而 运行在远程不需要。
$opt = New-PSSessionOption -IdleTimeout 86400000
$log = 'c:\temp\workflowtest.txt'
Invoke-Command -InDisconnectedSession -ScriptBlock {
1..10 | ForEach-Object {
"Current number is $_" | Add-Content $using:log
Start-Sleep -Seconds 1
write-host current iteration $_ -ForegroundColor Green
}
Get-Content $using:log
} -SessionOption $opt -SessionName testsession -ComputerName $env:COMPUTERNAME
关闭 window 你 运行 这是一个很好的测试步骤。
接收输出
打开一个新的 powershell window(以管理员身份)并检索输出。如果没有完成,它会一直接收直到完成。
Get-PSSession -ComputerName $env:computername | Receive-PSSession
删除会话
Get-PSSession -ComputerName $env:computername | Remove-PSSession
我一直在探索 Powershell 作业(使用 Start-Job、Get-Job、Receive-Job 等)。
只要我保持在同一个 powershell session/window,一切都很好,但是如果我打开一个新的 Powershell window 并执行“Get-Job”,它 returns 没有工作.
没有任何方法可以在 Powershell 中启动后台作业,关闭 window/session,然后稍后从另一个 session/window 访问它吗?我有几个长 运行 cmdlet,我希望它们能够在后台启动,然后稍后检查,而不必保证使用相同的提示。
更新
正如我所承诺的那样,我为你找到了另一个潜力 DaveUK。今天我了解到 PowerShell 中的“RunSpaces”。我认为这可能是我们 are/were 都在寻找的东西。它需要更多的工作,但使用 Boe Prox 的 Thread-Safe Collections. The below example is taken from Sharing Variables and Live Objects Between PowerShell Runspaces。他的文章详细描述了它的作用、工作原理,甚至还做了多个 'jobs'.
使用 Debug-Runspace 您可以从其他会话监控它。我将致力于在此答案中提供更多详细信息,以防该网站消失。但就目前而言,希望这会有所帮助。
$hash = [hashtable]::Synchronized(@{})
$hash.value = 1
$hash.Flag = $True
$hash.Host = $host
Write-host ('Value of $Hash.value before background runspace is {0}' -f $hash.value) -ForegroundColor Green -BackgroundColor Black
$runspace = [runspacefactory]::CreateRunspace()
$runspace.Open()
$runspace.SessionStateProxy.SetVariable('Hash',$hash)
$powershell = [powershell]::Create()
$powershell.Runspace = $runspace
$powershell.AddScript({
While ($hash.Flag) {
$hash.value++
$hash.Services = Get-Service
$hash.host.ui.WriteVerboseLine($hash.value)
Start-Sleep -Seconds 5
}
}) | Out-Null
$handle = $powershell.BeginInvoke()
上一个回复
几年来,我一直在尝试监控后台作业,而不依赖主要 window 保持开放状态,但尚未找到一个非 hacky 解决方案。这让我相信使用内置的“-Job”功能是不可能的。因此,这并不是主要问题的真正答案,而是我使用的解决方法。基本上它是在创建我自己的“工作”设置,因为内置的功能不像我想要的那样。在此请注意,我很少 运行 在新流程中“完成一项工作”。这通常是一个创造许多就业机会的过程。如果您长期需要 运行 的 cmdlet,我会在它自己的 PowerShell 进程中启动它,并详细记录到文件中。
对于“后台进程”中的 运行 多个作业,我将使用各种模板构建您的 cmdlet 或作业。
- 将输出记录到一个文件中,而不是试图依赖从 Receive-Job 中读取它。
- 实现一种在使用完后停止 cmdlet 的方法,我通常做的是在使用 JobID 启动作业时创建一个文件,如果 JobID 文件不再存在,则结束作业。这样,如果您想停止它,您可以删除该 JobID。我也经常给他们起名字,所以我记得是什么工作。
- 如果您想要状态报告,请执行与 'JobID' 文件类似的项目,但类似于 JobID-Status,它会在状态所在的日志文件中添加一行,然后删除该文件.
- 最后,您必须从当前所在的 PowerShell window 中单独启动作业进程。使用 Start-Process 调用脚本启动作业会将其与主程序分离 window进入“后台”进程。请记住,您调用的脚本应该在作业完成时退出 PowerShell。类似于:
示例启动进程脚本:
$Jobs = @("Name1", "Name2")
ForEach ($JobName in $Jobs) {
$Job = Start-Job -Name $JobName -ScriptBlock {
# Code Here either static file or from variable
# With logic to stop a job if the file is removed, and create the file
}
}
$JobsRunning = $true
while ($JobsRunning) {
$JobsRunning = $false
ForEach ($JobName in $Jobs) {
if ((Get-Job -Name $JobName).State -ne "Completed") {
$JobsRunning = $true
}
}
Start-Sleep -seconds 120
}
}
exit
我没有您想要的完整解决方案,但在多年想要此功能并通读 Google、M$、SO 等上的所有内容后,我来到了结论不可能在 PowerShell window 会话之间传输作业。
我希望我是错的并且有人发布了如何做。如果不是上面概述的方式对我很有用。烦人和一些额外的工作,但有效。
我遇到了 PSScheduledJob 模块,它似乎比常规作业更适合解决我的问题:
https://docs.microsoft.com/en-us/powershell/module/psscheduledjob/?view=powershell-5.1
计划的作业似乎确实存在并且可以从任何 PS 会话中检索,因此您可以将其用作触发“作业”的方式,该作业即使在您关闭后也会继续 运行 PS window.
到目前为止,我发现的唯一问题是 ScheduledJob 在运行时会生成一个常规作业,但该常规作业在完成之前没有子作业并且 progress/status 不可用。似乎无法监控工作的 status/output,因为它是 运行,所以这仍然不完美:(
我建议研究工作流,因为它们被设计为健壮的,可以处理长时间的 运行ning 任务,并且可以从 outages/reboots 中恢复。但是,您也可以在后台使用 Invoke-Command
和 -InDisconnectedSession
到 运行 命令或脚本,然后从相同或不同的机器再次连接到它。试一试这个例子。
创建会话
注意 - 在我的测试中 运行在本地需要管理员,而 运行在远程不需要。
$opt = New-PSSessionOption -IdleTimeout 86400000
$log = 'c:\temp\workflowtest.txt'
Invoke-Command -InDisconnectedSession -ScriptBlock {
1..10 | ForEach-Object {
"Current number is $_" | Add-Content $using:log
Start-Sleep -Seconds 1
write-host current iteration $_ -ForegroundColor Green
}
Get-Content $using:log
} -SessionOption $opt -SessionName testsession -ComputerName $env:COMPUTERNAME
关闭 window 你 运行 这是一个很好的测试步骤。
接收输出
打开一个新的 powershell window(以管理员身份)并检索输出。如果没有完成,它会一直接收直到完成。
Get-PSSession -ComputerName $env:computername | Receive-PSSession
删除会话
Get-PSSession -ComputerName $env:computername | Remove-PSSession