h41msh1c0r
Goto Top

Powershell Funktion Pipeline oder nicht

Hi@All,

ich steh grad vor der Entscheidung ob pipeline oder nicht.

Momentan führe ich Scripte immer Blockweise aus den Servern aus und das nacheinander bis die Farm durch ist.

Jetzt bin ich dabei das schick zu machen inkl. zu parallelisieren, also die ersten 5 Server, dann die nächsten usw..

Ablauf:
- Server 1-5 führen Script aus
- lesen Dienste
- lesen platten ein
- parsen spezielle Logfiles
- liefern zusammengebautes PSCustomObject zurück
- schreibe die erhaltenen Daten in XML, SQL whatever
- fange von vorn an, wenn noch Server übrig

Macht es Generell Sinn Funktionen zu pipelinen?

VG

Content-Key: 338997

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

Ausgedruckt am: 19.03.2024 um 11:03 Uhr

Mitglied: colinardo
Lösung colinardo 26.05.2017 aktualisiert um 16:18:11 Uhr
Goto Top
Servus.
Macht es Generell Sinn Funktionen zu pipelinen?
Wenn es Aufgaben sind die lange laufen und sich eine Beschleunigung durch Parallelisierung lohnt, sicher. Wieso 5 mal länger warten wenn 5 Server gleichzeitig die Aufgabe in einem 5tel der Zeit erledigen können face-smile.
Schau dir mal Workflows an. Ein schönes Beispiel zum parallelen Abfragen der Eventlogs aller Server der Domain findest du hier mit einem Workflow:
An- und Abmelde Ereignisse mit Powershell auslesen

Grüße Uwe
Mitglied: H41mSh1C0R
H41mSh1C0R 26.05.2017 um 16:44:18 Uhr
Goto Top
Hi Uwe,

fettes ds ;), ich weiß jetzt wie mein WE ausschaut. =)

Schonmal vorweg:

Das ThrottleLimit ist nur begrenzt durch die Ressourcen der Maschine auf der das Script gestartet wird?

VG
Mitglied: colinardo
Lösung colinardo 26.05.2017 aktualisiert um 16:51:11 Uhr
Goto Top
Zitat von @H41mSh1C0R:
fettes ds ;), ich weiß jetzt wie mein WE ausschaut. =)
Dann viel Spaß face-smile, aber nicht verzweifeln hier gibt es einige Fallstricke die einen echt Nerven kosten können.
Das ThrottleLimit ist nur begrenzt durch die Ressourcen der Maschine auf der das Script gestartet wird?
Das ist abhängig davon was das Script so alles macht, mehr Threads wie Prozessorkerne macht oftmals keinen Sinn, mit 5 Threads habe ich hier mit einem etwas älteren 8-Kerner die besten Erfahrungen gemacht, ist für den Anfang ein guter Start mit dem du nicht viel falsch machen kannst, das kann bei dir aber ganz anders aussehen. Mehr Threads sind nicht immer die beste Wahl das musst du bei dir evaluieren und ausprobieren was für eure Aufgaben am effektivsten ist.
Mitglied: H41mSh1C0R
H41mSh1C0R 26.05.2017, aktualisiert am 03.07.2017 um 15:54:10 Uhr
Goto Top
Erster Versuch:

Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
$window = New-Object System.Windows.Forms.Form
$window.Width = 300
$window.Height = 100
 
$windowButton = New-Object System.Windows.Forms.Button
$windowButton.Location = New-Object System.Drawing.Size(10,10)
$windowButton.Size = New-Object System.Drawing.Size(150,50)
$windowButton.Text = "Start Jobs"  
 
workflow Get-ServicesStatus{
param(
)

    $servers = @('Name1','Name2')  

    foreach -parallel ($s in $servers){
        $result = InlineScript {Invoke-Command -ComputerName $Using:s -ScriptBlock { 
		                Get-Service | Where-Object{$_.DisplayName -like "*OSD PXE*"}  
        }}
        $result
    }
}
  
$windowButton.Add_Click({
    Get-ServicesStatus
})
 
$window.Controls.Add($windowButton)

[void]$window.ShowDialog()

Jetzt muss ich nur noch herausbekommen wie ich die Ergebnisse wieder in zurückbekomme.
VG
Mitglied: H41mSh1C0R
H41mSh1C0R 04.07.2017 aktualisiert um 13:43:32 Uhr
Goto Top
Ich steh gerade etwas auf dem Schlauch:

workflow Get-ServicesStatus{
param(
)

    $servers = @('Name1','Name2')  

    foreach -parallel ($s in $servers){
        InlineScript {Invoke-Command -ComputerName $Using:s -ScriptBlock { 
		                Get-Service | Where-Object{$_.DisplayName -like "*OSD PXE*"}  
        }}
    }
}
  
$windowButton.Add_Click({
         $result =  Get-ServicesStatus
        Write-host $result
})

Müsste er nicht an der Stelle was ausgeben? Oder wird ein PSCustomObject innerhalb des InlineScriptes benötigt? *grübel*
VG
Mitglied: colinardo
Lösung colinardo 04.07.2017 aktualisiert um 15:46:08 Uhr
Goto Top
Müsste er nicht an der Stelle was ausgeben?
Ja.
Oder wird ein PSCustomObject innerhalb des bInlineScriptes enötigt?
Nein das ist keine Bedingung.

Das was du im Workflow in den Outputstream ausgibst ohne das du es in einer Variablen zwischenspeicherst landet im Output des Workflows.

Btw. würde hier ein Get-Service -Name '*OSD PXE*' auch reichen.

Wenn es bei solch kurzen Aktionen bleibt brauchst du keinen Workflow, da würde eigentlich auch ein Invoke-Command mit den Servernamen als Array und dem Parameter -AsJob als Einzeiler reichen.
Invoke-Command -ComputerName "Server1","Server2" -ScriptBlock {Get-Service -Name '*OSD PXE*'} -AsJob | Receive-Job -Wait -AutoRemoveJob

Grüße Uwe
Mitglied: H41mSh1C0R
H41mSh1C0R 04.07.2017 um 16:27:00 Uhr
Goto Top
Hallo Uwe,

Danke für deine Antwort.

Aktuell möchte ich primär erstmal Dienste und Werte abholen.

Wenn ich das Invoke-Command nun in eine Schleife packe weil ich 300+ Server abgrasen möchte, würde ich dennoch diese parallel anstoßen oder jeweils warten bis der Job beendet ist?

VVG vom H41mSh1C0r
Mitglied: colinardo
Lösung colinardo 04.07.2017 aktualisiert um 16:35:29 Uhr
Goto Top
Jobs laufen im Hintergrund parallel da kannst du so viele starten wie du lustig bist nur sind sie nicht ganz so performant wie Workflows oder Runspaces. Für Simple Aufgaben wie die obige aber meist ausreichend.
Mitglied: H41mSh1C0R
H41mSh1C0R 05.07.2017 aktualisiert um 09:23:42 Uhr
Goto Top
Es geht vorwärts.

Function Get-ServiceInfo  ([string[]]$ComputerName) {
   
    $Result = @()

    ForEach ($Computer in $ComputerName) {    
        
        $Services = Invoke-Command -ComputerName $Computer -ScriptBlock { Get-Service -DisplayName "*OSD*"}  

        $tmpOBJ = New-Object psobject
        $tmpOBJ | Add-Member -MemberType NoteProperty -Name "Service" -Value $Services.Name  
        $tmpOBJ | Add-Member -MemberType NoteProperty -Name "Status" -Value $Services.Status   
        
        foreach ($s in $Services) {
            $ServiceName = $s.Service
            $ServiceStatus = $s.Status
            
            $tmpOBJ | Add-Member -MemberType NoteProperty -Name "$($ServiceName)_DienstName" -Value $ServiceStatus  
        }
        
        $Result += $tmpOBJ
    }
    return $Result
}

Jetzt liefert er mehr Dienste pro Server. Das ist ja auch korrekt.

Wenn ich das nun in dem inneren foreach aufdrieseln möchte bekomme ich immer die Meldung das er _DienstName nicht hinzufügen kann weil es bereits vorhanden sei.


Für das Holen der HDDInfo verwende ich das gleich Konstrukt und da funktioniert es.
            $tmpOBJ | Add-Member -MemberType NoteProperty -Name "$($VolumeLetter)_VolumeName" -Value $VolumeName  
            $tmpOBJ | Add-Member -MemberType NoteProperty -Name "$($VolumeLetter)_TotalSize" -Value $VolumeTotalSize  
            $tmpOBJ | Add-Member -MemberType NoteProperty -Name "$($VolumeLetter)_FreeSize" -Value $VolumeFreeSize  

In der 2ten ForEach werden die Variablen befüllt und dann an das tmpOBJ gehangen.

Bei der Dienstgeschichte geht das noch nicht.

VG
Mitglied: colinardo
Lösung colinardo 05.07.2017 aktualisiert um 09:42:24 Uhr
Goto Top
Wenn ich das nun in dem inneren foreach aufdrieseln möchte bekomme ich immer die Meldung das er _DienstName nicht hinzufügen kann weil es bereits vorhanden sei.
Klar, weil es schon einen Member mit dem Eigenschaften-Namen im Custom-Object gibt, ein angehängtes -Force beseitigt die Meldung. Normalerweise erstellt man einmal zu Beginn die Member des Objects ausserhalb der Schleife und fügt dann nur noch die custom Objects hinzu, oder man erstellt eben ein leeres Array und fügt die Customobjects mit [pscustomobject] und einer Hashtable dem Array hinzu.
Mitglied: H41mSh1C0R
H41mSh1C0R 05.07.2017 um 09:53:18 Uhr
Goto Top
Dickes Danke.

Die Meldung das "_Dienstname" existiert war korrekt, da das was in $ServiceName stand einfach leer war. =)
Jetzt löst er es korrekt auf.
Mitglied: H41mSh1C0R
H41mSh1C0R 05.07.2017 aktualisiert um 13:26:48 Uhr
Goto Top
Mein Fahrplan schaut derzeit wiefolgt aus:

- Import einer XML, Herausgezogen werden sämtliche Servernamen --> funktioniert
- Erstellen einer XML --> funktioniert
- jede Zeile bekommt Name, Plattenplatz, Dienste und ein Beschreibungsfeld --> A
- Der Inhalt der XML wird in eine DataTable gepackt um in einem DGV dargestellt zu werden --> funktioniert
- Refreshbutton kommt später

A:

Die Gedanken waren gewesen die Einzelnen Abholaktionen(HDD und Dienste getrennt) in jeweils eine Funktion zu packen und das zurückgelieferte Objekt in eine Funktion zu pipen die die Daten in die DataTable an die richtigen Stellen schreibt. Das alles idealerweise parallelisiert, so das langsame Büchsen nicht die Bremse spielen.

Oder Ist das schon die falsche Herangehensweise?