albertminrich
Goto Top

Powershell Pipelinevariable?

Hallo,

eine kleine Powershellfrage.
Ich möchte für einige Server alle runtimebroker Prozesse auslesen und sie nach Usernamen gruppieren und sortieren.

Funktioniert auch:
$host = "server1,server2"  
$host.split(",") | foreach {Invoke-Command $_ -ScriptBlock{Get-Process -Name runtimebroker -IncludeUserName} | Group-Object -Property username} | Sort-Object name  
Die Ausgabe sieht so aus:
Count Name                      Group
----- ----                      -----
    1 KHA\user1               {System.Diagnostics.Process (RuntimeBroker)}
    1 KHA\user2               {System.Diagnostics.Process (RuntimeBroker)}
    1 KHA\user3               {System.Diagnostics.Process (RuntimeBroker)}
    1 KHA\user4               {System.Diagnostics.Process (RuntimeBroker)}
    1 KHA\user5               {System.Diagnostics.Process (RuntimeBroker)}
    1 KHA\user6               {System.Diagnostics.Process (RuntimeBroker)}

Jetzt weiß ich aber nicht, welche Zeile zu welchem Server gehört.
Entweder hätte ich gerne eine Zeile, wenn ein neuer Server kommt, also so:
Count Name                      Group
----- ----                      -----
server1
    1 KHA\user1               {System.Diagnostics.Process (RuntimeBroker)}
    1 KHA\user2               {System.Diagnostics.Process (RuntimeBroker)}
    1 KHA\user3               {System.Diagnostics.Process (RuntimeBroker)}
    1 KHA\user4               {System.Diagnostics.Process (RuntimeBroker)}
server2
    1 KHA\user5               {System.Diagnostics.Process (RuntimeBroker)}
    1 KHA\user6               {System.Diagnostics.Process (RuntimeBroker)}

oder, und das wär mir noch lieber, den Server in jeder Zeile mit dabei, also so:
Count Name                      Group Server
----- ----                      ----- ---
    1 KHA\user1               {System.Diagnostics.Process (RuntimeBroker)}   server1
    1 KHA\user2               {System.Diagnostics.Process (RuntimeBroker)}   server1
    1 KHA\user3               {System.Diagnostics.Process (RuntimeBroker)}   server1
    1 KHA\user4               {System.Diagnostics.Process (RuntimeBroker)}   server1
    1 KHA\user5               {System.Diagnostics.Process (RuntimeBroker)}   server2
    1 KHA\user6               {System.Diagnostics.Process (RuntimeBroker)}   server2

Leider lassen das meine bescheidenen Powershellkenntnisse nicht zu. Irgendwie denke ich, dass mir PipelineVariable weiterhilft, aber wie genau?

Danke
Gruß
Martin

Content-ID: 565274

Url: https://administrator.de/contentid/565274

Ausgedruckt am: 24.11.2024 um 04:11 Uhr

143728
143728 16.04.2020 um 21:36:17 Uhr
Goto Top
$hosts = "server1","server2"  
Invoke-Command -Computername $hosts -ScriptBlock {
    Get-Process -Name runtimebroker -IncludeUserName | Group username | Select *,@{n='Server';e={$env:Computername}}  
} | Sort name
AlbertMinrich
AlbertMinrich 16.04.2020 um 21:47:10 Uhr
Goto Top
Irgendwie hab ich übersehen, dass beim Befehl get-process der Servername ja bereits mit ausgegeben wird (pscomputername), erst durch Weiterleitung an Group-Object geht er wieder verloren, außer man gruppiert auch nach pscomputername

$server = "server1,server2"  
$server.split(",") | foreach {Invoke-Command $_ -ScriptBlock{Get-Process -Name runtimebroker -IncludeUserName}} | Group-Object -Property pscomputername,username -PipelineVariable zaehler | where {$zaehler.count -gt 1} | Select-Object count,name  

Ausserdem interessieren mich nur die User, bei denen der Prozess mehrmals läuft und hier brauch ich jetzt die Pipelinevariable.
Ausgabe sieht dann so aus:
Count Name                              
----- ----                              
    2 server1, KHA\user1
    4 server1, KHA\user2
    2 server2, KHA\user4


Das passt soweit, jetzt geht's nur noch um Feinheiten:
  • Die Ausgabe erfolgt erst, wenn alle Server abgeklappert wurden. Das kann schon mal ein wenig dauern. Besser wäre, wenn nach jedem Server eine Ausgabe erfolgen würde für den jeweiligen Server
  • Gibt es auf einem Server gar keinen Prozess runtimebroker, wird ein Fehler ausgegeben. Das Script ackert zwar ohne Unterbrechung die restlichen Server klaglos durch, ist aber nicht schön:
Es kann kein Prozess mit dem Namen "runtimebroker" gefunden werden. Überprüfen Sie den Prozessnamen, und rufen Sie das Cmdlet erneut auf.  
    + CategoryInfo          : ObjectNotFound: (chrome:String) [Get-Process], ProcessCommandException
    + FullyQualifiedErrorId : NoProcessFoundForGivenName,Microsoft.PowerShell.Commands.GetProcessCommand
    + PSComputerName        : server3

Hat jemand eine Idee?
Danke
Martin
AlbertMinrich
AlbertMinrich 16.04.2020 um 21:55:03 Uhr
Goto Top
Zitat von @143728:

> $hosts = "server1","server2"  
> Invoke-Command -Computername $hosts -ScriptBlock {
>     Get-Process -Name runtimebroker -IncludeUserName | Group username | Select *,@{n='Server';e={$env:Computername}}  
> } | Sort name
> 

Danke, funktioniert, wobei bei deiner Lösung dieser Teil alleine auch schon reicht:
Invoke-Command -Computername $hosts -ScriptBlock {
    Get-Process -Name runtimebroker -IncludeUserName | group username
}

Weißt du vielleicht noch eine Lösung für meine anderen beiden Probleme(Feinheiten)?

Gruß
Martin
143728
143728 17.04.2020 aktualisiert um 11:09:30 Uhr
Goto Top
Punkt 1: Die Pipeline komplett nur im Foreach Abschnitt ausgeben und keine CMDLets mehr hinter Foreach anhängen dann erfolgt die Ausgabe schrittweise für jeden Server.
Alternativ würde ich bei mehreren Servern paralellisieren, entweder mit Powershell Workflows, oder Powershell Jobs (Start-Job/Receive-Job /-asjob), dann ist das ganze auch schneller fertig. Beispiele finden sich hier im Forum.

Punkt 2: Stichwort: Parameter -ErrorAction SilentlyContinue bzw. Try Catch

"Server1","Server2" | %{  
    Invoke-Command -ComputerName $_  -EA SilentlyContinue -ScriptBlock {gps -Name explorer -EA SilentlyContinue -IncludeUserName | group Username | ?{$_.count -gt 1}}
}