Multithreading Powershell运行空间和颜色输出
短期发行说明:Multithreading Powershell运行空间和颜色输出,multithreading,powershell,Multithreading,Powershell,短期发行说明: 我需要脚本生成的其他powershell运行空间的非分散输出。我需要能够设置输出中各行的颜色 长问题描述: 我编写了一个脚本,将更新部署到多个远程服务器上的供应商应用程序。最初,该脚本旨在一次只部署一个更新,但我有一个新的要求,即我现在以交互方式处理多个更新。因此,我重新编写了使用运行空间的脚本,这样我就可以在所有服务器上打开会话,初始化它们,然后为每次更新用户输入为每个初始化的会话创建一个运行空间,并完成部署工作。我以前使用过作业,但由于无法将PSSession传递给作业,所以
我需要脚本生成的其他powershell运行空间的非分散输出。我需要能够设置输出中各行的颜色 长问题描述:
我编写了一个脚本,将更新部署到多个远程服务器上的供应商应用程序。最初,该脚本旨在一次只部署一个更新,但我有一个新的要求,即我现在以交互方式处理多个更新。因此,我重新编写了使用运行空间的脚本,这样我就可以在所有服务器上打开会话,初始化它们,然后为每次更新用户输入为每个初始化的会话创建一个运行空间,并完成部署工作。我以前使用过作业,但由于无法将PSSession传递给作业,所以必须转到运行空间 现在我的脚本可以正常工作了,但是输出不太理想。作业版本有很好的输出,因为我可以调用Receive job并按线程对所有输出进行分组。此外,我还可以使用写主机来记录输出,这允许彩色响应(即更新失败时的红色文本)。我已经能够让我的作业运行空间版本按线程对输出进行分组,但只能使用写输出。如果我使用写主机输出立即发生,导致不可接受的分散输出。不幸的是,写入输出不允许彩色输出。设置$host.UI.RawUI.ForegroundColor也不起作用,因为如果在设置颜色时没有输出,则不会产生效果。由于我的输出直到最后才会发生,$host设置不再起作用 下面是一个快速演示脚本来说明我的困境:
#Runspacing output example. Fix interleaving
cls
#region Setup throttle, pool, iterations
$iterations = 5
$throttleLimit = 2
write-host ('Throttled to ' + $throttleLimit + ' concurrent threads')
$iss = [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault()
$Pool = [runspacefactory]::CreateRunspacePool(1,$throttleLimit,$iss,$Host)
$Pool.Open()
#endregion
#This works because the console color is set at the time output occurs
$OrigfC = $host.UI.RawUI.ForegroundColor
$host.UI.RawUI.ForegroundColor = 'red'
write-host 'THIS IS RED TEXT!'
start-sleep 2
$host.UI.RawUI.ForegroundColor = $OrigfC
#define code to run off the main thread
$scriptBlock = {
$nl = ([Environment]::NewLine.Chars(0)+[Environment]::NewLine.Chars(1))
#This does not work because output won't occur until after color has been reset
$OrigfC = $host.UI.RawUI.ForegroundColor
$host.UI.RawUI.ForegroundColor = 'yellow'
write-output ($nl + ' TEST: ' + $args[0])
Write-Output (' Some write-output: ' + $args[0])
Start-Sleep 1
write-host (' Some write-host: ' + $args[0]) -ForegroundColor Cyan # notice write-host occurs immediately
Start-Sleep 1
$host.UI.RawUI.ForegroundColor = $OrigfC
}
#Start new runspaces
$threads = @()
$handles = @(for($x = 1; $x -le $iterations; $x++)
{
$powerShell = [PowerShell]::Create().AddScript($scriptBlock).AddParameters(@($x))
$powershell.RunspacePool = $Pool
$powerShell.BeginInvoke()
$threads += $powerShell
})
#Wait for threads to complete
$completedCount = 0
$completed = ($handles | where-object {$_.IsCompleted -eq $true}).count
while($handles.IsCompleted.Contains($false))
{
if($completedCount -ne ($handles | where-object {$_.IsCompleted -eq $true}).count)
{
$completedCount = ($handles | where-object {$_.IsCompleted -eq $true}).count
write-host ('Threads Completed: ' + $completedCount + ' of ' + $iterations)
}
write-host '.' -nonewline
Start-Sleep 1
}
write-host ('Threads Completed: ' + ($handles | where-object {$_.IsCompleted -eq $true}).count + ' of ' + $iterations)
#output from threads
for($z = 0; $z -lt $handles.Count; $z++)
{
$threads[$z].EndInvoke($handles[$z]) #causes output
$threads[$z].Dispose()
$handles[$z] = $null
}
$Pool.Dispose()
输出如下,除非指定,否则输出为灰色:我的目标是能够将表示“somewrite-output:X”的行设置为一种颜色,“TEST:X”设置为另一种颜色。思想?请注意,我是从powershell提示符运行的。如果在ISE中运行,将获得不同的结果
Throttled to 2 concurrent threads
THIS IS RED TEXT! #Outputs in Red
. Some write-host: 1 #Outputs in Cyan
Some write-host: 2 #Outputs in Cyan
.Threads Completed: 2 of 5 #Outputs in Yellow
. Some write-host: 3 #Outputs in Cyan
Some write-host: 4 #Outputs in Cyan
.Threads Completed: 4 of 5 #Outputs in Yellow
. Some write-host: 5 #Outputs in Cyan
.Threads Completed: 5 of 5
TEST: 1
Some write-output: 1
TEST: 2
Some write-output: 2
TEST: 3
Some write-output: 3
TEST: 4
Some write-output: 4
TEST: 5
Some write-output: 5
编辑:添加另一个示例来说明Mjolinor的答案。M、 你是对的,我可以通过会议的工作;我把上面的例子过于简化了。请考虑下面的例子,我向作业发送一个函数。如果这一行(如果(1-NE1){MyFunc-ses$args[0]})在下面被注释掉,它将运行。如果未注释掉该行,则会话(类型System.Management.Automation.Runspaces.PSSession)将转换为反序列化的.System.Management.Automation.Runspaces.PSSession类型,即使无法调用MyFunc。我还没有弄明白这一点,所以我开始转向运行空间。你认为有一个以工作为导向的解决方案吗
cls
$ses = New-PSSession -ComputerName XXXX
Write-Host ('Outside job: '+$ses.GetType())
$func = {
function MyFunc {
param([parameter(Mandatory=$true)][PSSession]$ses)
Write-Host ('Inside fcn: '+$ses.GetType())
}
}
$scriptBlock = {
Write-Host ('Inside job: '+$args[0].GetType())
if(1 -ne 1){MyFunc -ses $args[0]}
}
Start-Job -InitializationScript $func -ScriptBlock $scriptBlock -Args @($ses) | Out-Null
While (Get-Job -State "Running") { }
Get-Job | Receive-Job
Remove-Job *
Remove-PSSession -Session $ses
我不太明白那种说法,即你不能把一个职位转让给一份工作。您可以使用-Session和-AsJob参数运行Invoke命令,创建针对会话的at作业
至于着色难题,您是否考虑过将详细或调试流用于您希望成为不同颜色的输出?Powershell应根据它来自的流自动将其设置为不同的颜色 我添加了一个额外的例子来说明我在工作中遇到的问题。请看一看。您是否尝试过使用带有-session和-asjob参数的invoke命令?开始作业在本地系统上创建后台作业。我不明白为什么要创建本地后台作业,只是为了在远程系统上运行脚本。只需将远程系统上的脚本作为作业调用即可。我启动本地作业,然后在作业内调用invoke命令。基于部署的成功,我可以使用invoke命令将日志文件的内容回显到本地作业。然后,本地作业可以创建本地日志文件,从而避免用户必须登录多个服务器才能检索故障日志。我将研究如何使用invoke-command实现相同的结果。感谢所有的帮助。使用invoke命令作为作业方法,我能够使脚本完全按照所需工作。