짧은 문제 설명 :
파워 쉘 실행 영역 및 컬러 출력
내가 내 스크립트를 생성합니다 추가 파워 쉘의 실행 영역에서 비 산재 출력이 필요합니다. 출력에서 개별 라인의 색상을 설정할 수 있어야합니다.
긴 문제 설명 :
나는 여러 원격 서버 공급 업체 응용 프로그램 업데이트를 배포하는 스크립트를 썼다. 원래 스크립트는 한 번에 하나의 업데이트 만 배포하기위한 것이었지만 이제는 여러 업데이트를 대화식으로 처리해야한다는 새로운 요구 사항이 있습니다. 그래서 스크립트를 다시 작성하여 모든 서버에서 세션을 열고 초기화 한 다음 사용자가 입력 한 runspace가 초기화 된 각 세션에 대해 작성되고 배포 작업이 완료 될 때까지 runspaces를 사용하도록 스크립트를 다시 작성했습니다. 이전에는 작업을 사용했지만 PSSession을 작업에 전달할 수 없기 때문에 실행 영역으로 이동해야했습니다.
이제 스크립트가 제대로 작동하지만 결과가 좋지 않습니다. Receive-Job을 호출하고 모든 출력을 스레드별로 그룹화 할 수 있기 때문에 작업 버전의 출력이 좋았습니다. 또한 쓰기 호스트를 사용하여 컬러 응답 (예 : 업데이트가 적용되지 않으면 빨간색 텍스트)을 허용하는 출력을 기록 할 수 있습니다. 스레드의 출력을 그룹화하기 위해 작업의 내 runspace 버전을 얻을 수 있었지만 쓰기 출력 만 사용했습니다. write-host 출력을 사용하면 즉시 발생하여 중간에 출력되는 것을 받아 들일 수 없습니다. 불행히도 write-output은 컬러 출력을 허용하지 않습니다. $ host.UI.RawUI.ForegroundColor를 설정해도 색상이 설정된 시점에 출력이 발생하지 않으면 효과가 나타나지 않으므로 작동하지 않습니다. 출력이 끝날 때까지 발생하지 않기 때문에 $ 호스트 설정은 더 이상 작동하지 않습니다. 다음은
내 불황을 설명하는 빠른 데모 스크립트입니다#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()
출력을 지정하지 않는 출력은 다음과 같습니다 은 회색에 있습니다
내 목표는 라인을 얻을 수있을 것입니다 "일부 쓰기 출력 : 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, 너는 맞다. 나는 직업을 직업에 넘겨 줄 수있다; 위의 예를 지나치게 단순화했습니다. 아래의 예제에서 내가 작업에 기능을 전송하는 위치를 고려해보십시오. 이 행 (if (1 -ne 1) {MyFunc -ses $ args [0]})이 아래 주석 처리되면 실행됩니다. 해당 줄이 주석 처리되지 않은 경우 MyFunc 호출에 적중 될 수 없더라도 세션 (System.Management.Automation.Runspaces.PSSession 형식)이 Deserialized.System.Management.Automation.Runspaces.PSSession 형식으로 변환됩니다. 나는 이것을 알아낼 수 없었기 때문에 나는 무한대로 움직이기 시작했다. 직업 지향적 인 해결책이 있다고 생각합니까?
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-command를 사용해 보셨습니까? Start-Job은 로컬 시스템에 백그라운드 작업을 생성합니다. 원격 시스템에서 스크립트를 실행하기 위해 로컬 백그라운드 작업을 만드는 이유를 이해할 수 없습니다. 작업으로 원격 시스템에서 스크립트를 호출하기 만하면됩니다. – mjolinor
로컬 작업을 시작한 다음 작업 내에서 invoke-command를 호출합니다. 배포 성공에 따라 필자는 invoke 명령을 사용하여 로그 파일의 내용을 로컬 작업에 다시 표시 할 수 있습니다. 그런 다음 로컬 작업은 로컬 로그 파일을 만들 수 있으므로 사용자가 여러 서버에 로그인하여 오류 로그를 검색 할 필요가 없습니다. invoke-command를 사용하여 동일한 결과를 얻으 려합니다. –