Private/Wissen/B04_Pipelining.ps1
# ? TITEL Pipelining # ? DESCRIPTION Wie werden Pipeline-Objekte an Cmdlets gebunden # ? TAGS Parameter Binding Splatting # ? VERSION 2019.09.20.0800 [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '')] param() #region Pipeline-Verarbeitung # ! Nach einer Pipeline können Zeilenumbrüche eingefügt werden um die Lesbarkeit zu erhöhen # ! Ab jetzt muss der auszuführende Block selektiert und dann mit F8 ausgeführt werden. Get-Process | Where-Object -Property Company -like -Value "Microsoft*" | Sort-Object Name | Select-Object Name, Company | Out-File c:\temp\Process.txt -Force # ! Windows PowerShell überträgt über die Pipeline KEINE TEXTE von Cmdlet A zu Cmdlet B. # ! Es werden immer OBJEKT über die Pipeline übertragen. Get-Process | Where-Object -Property Company -Match -Value "Microsoft" Get-Process | ForEach-Object -Process {"Ist $_ ein Objekt? $($_ -is [System.Object])"} # ! Cmdlet liefert Objekt immer i.d.R. just-in-time an das nächste Cmdlet Get-ChildItem -Path c:\ -Recurse -ErrorAction SilentlyContinue | ForEach-Object -Process { Write-Output "Empfange Objekt $_ und gebe $($_.FullName) weiter ..."; $_.FullName } | Out-GridView #endregion #region Objekt-Bindung in der Pipeline # ! Einführungsbeispiel Get-Process -Name notepad | Stop-Process # ? Würde dieser Befehl die notepad-Prozesse beenden? (JA | NEIN) Get-ChildItem -Path c:\temp\DL | Stop-Process # ? Würde dieser Befehl die notepad-Prozesse beenden? (JA | NEIN) # ! Eine Erklärung folgt weiter unten. # ! 1. Das Pipeline-Objekt kann nur über die Parameter des Ziel-Cmdlet gebunden werden. # ! 2. Für diese Bindung zwischen Pipeline-Objekt und den Parametern des Ziel-Cmdlets # ! stehen ZWEI Verfahren zur Verfügung: # ! A) ByValue Siehe Ziel-Cmdlet/Parameter-Beschreibung, bzw. was der Ziel-Cmdlet-Programmierer # ! über ein Attribut 'ValueFromPipeline' konfiguriert hat. # ! Ein Bindung des GANZEN PIPELINE-OBJEKTES findet statt, # ! wenn der Pipeline-Objekt-TYP KOMPATIBEL (s.u.) mit diesem Parameter ist. # ! B) ByPropertyName Siehe Ziel-Cmdlet/Parameter-Beschreibung, bzw. was der Ziel-Cmdlet-Programmierer # ! über ein Attribut 'ValueFromPipelineByPropertyName' konfiguriert hat. # ! Ein Bindung EINER EIGENSCHAFT des Pipeline-Objektes findet statt, # ! wenn dieser Pipeline-Objekt-EigenschaftsNAME identisch ist mit dem Ziel-Cmdlet-ParameterNAME, # ! oder dessen ALIASNAMEN UND der Pipeline-Objekt-EigenschaftsTYP KOMPATIBEL (s.u.) # ! mit Ziel-Cmdlet-ParameterTYP. # ! 3. Ein Mehrfach-Binden bzw. Mehrfach-Verfahren an das Ziel-Cmdlet ist möglich. # ! Bzgl. Kompatibilität von Objekt-Typen: Objekte sind kompatibel wenn: # ! A) Die Typennamen 100% identisch sind, was den Namespace mit einschließt [System.String] -ceq [System.String] [System.Timers.Timer] -ceq [System.Windows.Forms.Timer] # ! B) Jedes Objekt ist kompatibel mit [System.Object] "Hallo Köln!" -is [System.Object] (Get-Process)[0] -is [System.Object] 12 -is [System.Object] # ! C) Jedes komplexe Objekt ist kompatibel mit [PSCustomObject] (Alias: PSObject) (Get-Process)[0] -is [PSCustomObject] (Get-Service)[0] -is [PSCustomObject] (Get-ChildItem)[0] -is [PSCustomObject] # ! D) Jedes Objekt ist kompatibel mit Typen die in der Vererbungshierarchie vorkommen: (Get-Process)[0] -is [System.Diagnostics.Process] (Get-Process)[0] -is [System.ComponentModel.Component] (Get-Process)[0] -is [System.MarshalByRefObject] (Get-Process)[0] -is [System.Object] # ! 1. Eine Klasse kann von EINER anderen Basisklasse abgeleitet sein und erbt so dessen Member/Funktionen. # ! 2. Jede Klasse ist früher oder später von der Klasse 'Object' abgeleitet worden. # ! 3. Eine abgeleitete Klasse A ist daher mit der Basisklasse B kompatibel, # ! daher kann auch ein Objekt von Typ A an einen Parameter vom Typ B übergeben werden. # ? Welche Typ A von welchem Typ B abgeleitet wurde erfahren Sie so: "Köln!".PSTypeNames (Get-Process)[0].PSTypeNames (Get-Process).PSTypeNames #region Folgendes Beispiel demonstriert das Bindungsverfahren function Test-PipelineBinding { [CmdletBinding()] param( [Parameter(ValueFromPipeline = $true)] [System.Object]$InputObject, [Parameter(ValueFromPipeline = $true)] [PSCustomObject]$InputPSCustomObject, [Parameter(ValueFromPipeline = $true)] [System.ComponentModel.Component]$InputComponent, [Parameter(ValueFromPipeline = $true)] [System.Diagnostics.Process]$InputProcess, [Parameter(ValueFromPipeline = $true)] [System.ServiceProcess.ServiceController]$InputService, [Parameter(ValueFromPipeline = $true)] [System.String]$InputString, [Parameter(ValueFromPipelineByPropertyName = $true)] [System.DateTime]$StartTime, [Parameter(ValueFromPipelineByPropertyName = $true)] [System.ServiceProcess.ServiceStartMode]$StartType, [Parameter(ValueFromPipelineByPropertyName = $true)] [System.String]$Name, [Parameter(ValueFromPipelineByPropertyName = $true)] [Alias('MachineName')] [System.String]$Rechnername ) process { "1. Die Vererbungshierarchie des Pipeline-Objektes (Wichtig für ByValue-Bindung) sieht wie folgt aus:" $InputObject.PSTypeNames "`n2. Das Pipeline-Objekt besitzt u.a. folgende relevante Eigenschaften (Wichtig für ByPropertyName-Bindung):" Get-Process -Name notepad | Get-Member -MemberType Properties | ForEach-Object -Process { if ($_.Name -in 'StartTime', 'Name') { $_.Definition } } # # $zerlegt = $_ -split " " # "`t[{0}]{1}" -f $zerlegt[0], $zerlegt[1] "`n3. Die daraus folgende Bindung (ByValue, ByPropertyName) gestaltet sich wie folgt:" [PSCustomObject]@{ ParameterName = 'InputObject' ParameterBindungsart = 'ValueFromPipeline' ParameterTyp = [Object] ArgumentTyp = $InputObject.GetType().FullName BindungErfolgreich = 'JA' } [PSCustomObject]@{ ParameterName = 'InputPSCustomObject' ParameterBindungsart = 'ValueFromPipeline' ParameterTyp = [PSCustomObject] ArgumentTyp = $InputPSCustomObject.GetType().FullName BindungErfolgreich = 'JA' } [PSCustomObject]@{ ParameterName = 'InputComponent' ParameterBindungsart = 'ValueFromPipeline' ParameterTyp = [System.ComponentModel.Component] ArgumentTyp = $InputComponent.GetType().FullName BindungErfolgreich = 'JA' } if($null -eq $InputProcess) {$argType = 'NULL'; $isBinding = 'NEIN'} else { $argType = $InputProcess.GetType().FullName; $isBinding = 'JA' } [PSCustomObject]@{ ParameterName = 'InputProcess' ParameterBindungsart = 'ValueFromPipeline' ParameterTyp = [System.Diagnostics.Process] ArgumentTyp = $argType BindungErfolgreich = $isBinding } if($null -eq $InputService) {$argType = 'NULL'; $isBinding = 'NEIN'} else { $argType = $InputService.GetType().FullName; $isBinding = 'JA' } [PSCustomObject]@{ ParameterName = 'InputService' ParameterBindungsart = 'ValueFromPipeline' ParameterTyp = [System.ServiceProcess.ServiceController] ArgumentTyp = $argType BindungErfolgreich = $isBinding } [PSCustomObject]@{ ParameterName = 'InputString' ParameterBindungsart = 'ValueFromPipeline' ParameterTyp = [System.String] ArgumentTyp = $InputString.GetType().FullName BindungErfolgreich = "JA (Value: '$InputString')" } if($null -eq $StartTime) {$argType = 'NULL'; $isBinding = "NEIN (Value: NULL)"} else { $argType = $StartTime.GetType().FullName; $isBinding = "JA (Value: '$StartTime')" } [PSCustomObject]@{ ParameterName = 'StartTime' ParameterBindungsart = 'ValueFromPipelineByPropertyName' ParameterTyp = [System.Diagnostics.Process] ArgumentTyp = $argType BindungErfolgreich = $isBinding } if($null -eq $StartType) {$argType = 'NULL'; $isBinding = "NEIN (Value: NULL)"} else { $argType = $StartType.GetType().FullName; $isBinding = "JA (Value: '$StartType')" } [PSCustomObject]@{ ParameterName = 'StartType' ParameterBindungsart = 'ValueFromPipelineByPropertyName' ParameterTyp = [System.ServiceProcess.ServiceStartMode] ArgumentTyp = $argType BindungErfolgreich = $isBinding } if($null -eq $Name) {$argType = 'NULL'; $isBinding = "NEIN (Value: NULL)"} else { $argType = $Name.GetType().FullName; $isBinding = "JA (Value: '$Name')" } [PSCustomObject]@{ ParameterName = 'Name' ParameterBindungsart = 'ValueFromPipelineByPropertyName' ParameterTyp = [System.String] ArgumentTyp = $argType BindungErfolgreich = $isBinding } if($null -eq $Rechnername) {$argType = 'NULL'; $isBinding = "NEIN (Value: NULL)"} else { $argType = $Rechnername.GetType().FullName; $isBinding = "JA (Value: '$Rechnername')" } [PSCustomObject]@{ ParameterName = 'Rechnername (Alias=MachineName)' ParameterBindungsart = 'ValueFromPipelineByPropertyName' ParameterTyp = [System.String] ArgumentTyp = $argType BindungErfolgreich = $isBinding } } } Get-Process -Name notepad # ! => notepad-Process Get-Process -Name notepad | Get-Member # ! => vom Typ [System.Diagnostics.Process] Get-Process -Name notepad | Test-PipelineBinding | Format-Table Get-Service -Name AudioSrv | Test-PipelineBinding | Format-Table #endregion # ? Aufklärung des Einführungsbeispiels Get-Process -Name notepad | Get-Member # 1. Analysieren des Rückgabe-Objektes bzgl. Type & Property # ! => System.Diagnostics.Process Get-ChildItem -Path c:\temp\ | Get-Member # 1. Analysieren des Rückgabe-Objektes bzgl. Type & Property # ! => System.IO.FileInfo Get-Help -Name Stop-Process -ShowWindow # 2. Welche Parameter lassen Pipelineeingabe zu und nach welchem Verfahren? # ! -InputObject <Process[]> ByValue # ! -Name <string[]> ByPropertyName # ! -Id <int32[]> ByPropertyName # 3. Was passt zw. 1. und 2. zusammen? #region Beispiele für den praktischen Nutzen #region z.Bsp.: Alle Fehler in einer MasterError.log sammeln Get-ChildItem -Path "$env:WinDir\Logs" -Recurse -File -Force | # IN: - OUT: FileInfo Where-Object -Property Extension -EQ -Value ".log" | # ByValue IN: FileInfo OUT: FileInfo Select-String -Pattern "error" | # ByValue IN: FileInfo OUT: MatchInfo Set-Content c:\temp\master_error.log # ByValue IN: MatchInfo OUT: - #endregion #region z.Bsp.: Über eine CSV-Datei neue Benutzer anlegen @" Benutzername;Passwort;Beschreibung p.lustig;P@ssw0rd;Peter Lustig (IT) e.gruen;Geh1imAbc;Eva Grün (HR) "@ | Set-Content -Path c:\temp\NewUsers.csv Get-Content -Path C:\temp\NewUsers.csv | ConvertFrom-Csv -Delimiter ";" -Header Name, Password, Description | Select-Object -Skip 1 | ForEach-Object -Process { $_.Password = $_.Password | ConvertTo-SecureString -AsPlainText -Force # ! ACHTUNG geht nur wenn die Property 'set' erlaubt return $_ } | New-LocalUser # vs. Get-Content -Path C:\temp\NewUsers.csv | ConvertFrom-Csv -Delimiter ";" -Header Name, Password, Description | Select-Object -Skip 1 | ForEach-Object -Process { $pwd = $_.Password | ConvertTo-SecureString -AsPlainText -Force $_ | Add-Member -Name Password -Value $pwd -MemberType NoteProperty -Force -PassThru } | New-LocalUser -WhatIf # vs. Get-Content -Path C:\temp\NewUsers.csv | ConvertFrom-Csv -Delimiter ";" -Header Name, Password, Description | Select-Object -Skip 1 -Property Name, ` Description, ` @{Label="Password"; Expression={$_.Password | ConvertTo-SecureString -AsPlainText -Force}} | New-LocalUser -WhatIf #endregion #endregion #endregion #region Splatting (Mehrere Parameter gleichzeitig an ein Cmdlet übergeben) Get-EventLog -LogName System -Newest 5 -EntryType Error, Warning # vs. $argument = @{ LogName = 'System' Newest = 5 EntryType = 'Error', 'Warning' } Get-EventLog @argument #endregion #region Übungen <# TODO Übung 1 (Pipelining) ? A) Die Sortierung bei der folgenden Zeile funktioniert nicht, warum? Get-ChildItem $env:WinDir\*.exe | Select-Object -Property Name, LastWriteTime | Sort-Object -Property Length ? B) Welche Variante ist die Ökologischste, warum und wie haben Sie das ermittelt? Get-EventLog -LogName System | Where-Object -Property EntryType -EQ 'Warning' Get-EventLog -LogName System | Where-Object -FilterScript { $_.EntryType -eq 'Warning' } Get-EventLog -LogName System -EntryType Warning ? C) Warum wird das Gast-Konto nicht gefunden? Get-CimInstance -ClassName Win32_UserAccount | Where-Object { $_.Name = 'Gast' } ? D) Warum funktioniert der folgende Befehl nicht? Get-Process | Format-Table -Property Name, Company | Sort-Object -Property Company ? E) Warum werden keine doppelten Objekt entfernt? 1,2,3,1,2,3,1,2,3 | Get-Unique ! TIPPS: - * MUSTERLÖSUNG #> <# TODO Übung 2 (Pipelining) ? A) Anhand einer ToDeletedFiles.csv-Datei sollen nur die darin enthaltenen Dateinamen im Temp-Ordner gelöscht werden. ! TIPPS: Get-Content; ConvertFrom-Csv; Remove-Item; Get-ChildItem; ForEach-Object; Add-Member * MUSTERLÖSUNG 76492d1116743f0423413b16050a5345MgB8AHAALwB1ADkAbQBvAGEAMwBYAHEAZAA0AG4AVgBsAE0AYgAvAEIANwBlAFEAPQA9AHwANQA2AGQANQA1ADEAYQA2ADEAMABlADMAMgA5ADMAYgBmADAAZAA0AGQAOAA4ADYAYwBlADcAOABmADcANAAzAGQAMwBjAGMAOAA1AGQAZQBhADAAYQBlADgAZQAyADIAYwBhADkAMwBlAGIAZAAzADYAOAAyAGEAZgA0ADQAMABjADUAZAAzADQAMwBjADIAYwAxADYAZABkAGIAYwBkAGEAYgA0AGQAMwBiAGQAMABlAGUAMAAzAGIANwA0AGIANQAzADMAMwBkADYAZQAwAGIANQBmADIAMwA3AGEANQBjADcAYQA2ADQAZgA1ADUAYQBjAGUANQBmAGIAOABhAGIAYwBkADIAYQBjADQAOQA1ADYANwBiAGIAMAAwAGYAMQAwADMAMQAwADAANQBhAGYAMAA1ADgAMwAzADMAZQAwADIAYwBlAGQAYwBkADUAOQA0ADgAZAA3ADcAYQBmAGEANAA4ADEAMQBmAGQAZAA1ADUAZQBhADQANAA3ADcAZgA4AGUANwBkADAAZQAyADkAMQBkADkAMgA4AGUAYQA5ADAAYwA2ADgAYQAyAGEANQAwADYAMgBlAGQAMQA1ADkAYQAwAGEAYgAwAGQAMQA0AGMAOQAwADkAOAA4AGYAMABlAGIAYgBjAGIAZQA4AGQAOABjADYAYgBkAGQAZQBhAGIAMAA0ADcAZAAxADYAYwBmADIAMQBiADQAYQAyADQAZgBkADAAZgBlAGEANQA2AGQAMQA1ADEAZgA1AGYANQBjAGMANwBjAGQANwAzADIANwA3AGUAZQBkAGIAOQBiADYAOABmADkANAA4AGQANAAwADAANAA5ADkAZgBlADQAZAAxAGMAZgA4ADYAOQBmAGIAYQAzADEAMAA4AGUANwA2AGMAOABmADQAYgA3ADgAYgAxADMAYgBmAGEAZAAwAGQAMgA2ADYAOABlADYAYgA5ADIAOQAyADgAZAA3AGUAZAAxADEAOQAxADkAYgAxAGUAZgBjAGUAYQBkADEANgBmADMAMgBhADQAOAAyADAANQBiAGQAMQBlAGIAZABmAGIAYgBlADcAYwAzADQAMQBiADgAOQA1ADEAYwA0ADkANwBiADQAZQBlADYAMAAyADYANwA0AGYAOQBkADgANwAzADgANgA0AGEAMQA2AGYAMQAyAGUAMQAwADEAZAA5AGMAYQBlADEAOAAyADEAYgAwADQAZABhAGEAYgBiAGUAMwA4ADAANwAxADcAOAA2ADgAZQA4ADIAZQBiADIAMABjADAAMwA5AGUANAA5AGIAYQA4ADgAYgBiADUANgAwADgANQA0ADgANwA4AGMAZQA0ADcAYgA0ADgAMwAwAGEAYwAxADMANwBhADYAOAA0ADcAZgBkAGYANwA4AGYANABjADUAMgA2ADMANwA5ADcAOAA5ADUAYwA1ADYAZQA2ADYAZQAyADQAZgAxADIAYQBhAGEAYwA4ADMAYQBkADkAOQBlADYAMQBkADgAYQA5ADYAYgAwADYAYgAzADMAYgAyAGYAMgBiAGMANgA1ADAANQAwADAAMAAyADgAYQBlADkANQAwADQANgA3ADYAMQA0AGUAYwAwADQAYQBjADYAZABhADMAYgBkADAANgA4ADUAZABkADkAYwA0AGEANQAwAGMAYQBiADMANQA3ADAAZAA3ADgANgA0AGUAYQA1AGUAYQA0ADYAMAAzADYAZAAwADAAZQA3ADYAOAA0ADUAYgAxAGMAZAAwADUAMwBmADAAMgA4ADAAMgA1AGIAMQAyADEAZgA0AGYAZABjADUAZgA0ADgAYgA3AGUAYwA1ADgAOQAxADYAYgBhADMANwA2AGMANgA1ADkAYQA0ADYAMQBmAGQAYgBkAGYAMQBmADYAOQAwAGIAMgAwAGYAMABiADkAYgA5ADMAOQAzAGYANgA0ADUAYwBiAGUAYQBhADAANAA3ADAAOQA1ADIAOQAzAGMAZQA5ADIAYwAxADkAZgA5AGMAMQA1ADMAYwBlADEANQAyAGMAMABmADkAMgBlADIAYwBkADIANQBmADUAMABiAGIAZABkAGUANwAyAGEAMgAzADEAZgA4ADIAMQA5AGYAMgBlADQAZQBjADkANAA2AGQAMwBmADUAOAAwADgANQA3AGIAYgAyAGUAMwBlAGMAOAA0ADIAOQBhADkAZgBmADkAOAA5ADEAOAA1AGQAMgAwADkAZgA0AGIAOAA4AGQANABkADQAMwBlADUAYwA4ADIAOQAzADkAYQAxADgAMQAzAGMAZAA4ADYAMQAxADEAMQBjADgAOQAzAGQAOABhAGEAYwA0ADkAYwBjAGMAYwAxADIAZgA2ADcANAA4AGIAMgA1ADQAOABjAGUAYgBlADYAYgBkAGUAZAA3ADgAOABhAGIAMQA2AGIAMgAzADEAMwA3ADgAMgAyADkAMAAwAGIANABhAGYAYwBhAGUAYQBmAGUAZQBkADEAZQA5ADIAMgAwAGIANwBiAGYAZQAzADQAZgBmADcAZQBkADQANAAwADQAZgA1ADUAMwBlAGEANQA3AGEAYwBkADcAMQAxADMANwAzADcAMQAwADkAMgAzADYANwAwAGQAMQBkAGQAZgBiADcAMAAxAGEAMQAxAGYANQA3AGUAZABkADQAZAAyADMAMQBhADYANwA3AGMAOABlAGMAMwAwADQANgBjADAANQAyADkAYgA2AGIANwA3AGYAMgA1ADYAYwA5ADUAMAA4ADMANABlADAAOABiAGUAMAA2ADgAZQBiAGIAZgBiAGQAZAA5ADgAYgBiADMAMQA5ADMAYwA4ADQAYgBkADEAOQAxADcAZgA4ADIAOQBiADAAMwBlADkAYQBjADgANwAwADcAMgAyADcAZQA5ADEAYgBlAGMAZABiADYAMgA0ADYAYgA1AGYAYQA1ADAAMAAzAGYAMwBkADcAZgAyADMAMgA5ADAAYQA3ADcAMQBkAGIAOQAyADgAOQA2ADcAYQA3ADEAOAAyADkANgAyAGYANABiADcAOQBmADIAMQBhAGYAMwA1ADcAOABlADIAZAA3ADUANgBmADIAMAAzADAAOQBhAGIANABjADYAMABjAGIAYQAxADEAOAA5ADQAZgA4ADUAMwBkADQAMQAwAGEAZABkAGYAYQBlADIAYgBiADgAMwA0ADQANAA3ADIANQA5ADcANABhADIAMQBkADUANgAyADcANABiAGIAZABmADkAMQA5ADkAYQAzADUAMABhAGMAOAA4AGEAYgAxADEAMwBlAGMAMAA0ADUAOABiAGEAMwA1ADMANAAxAGEAYQA2ADgANQBkAGUAYQA5AGYAOABhAGMANQBlADMAMgA2AGQAZQA1AGIANgA4AGMAMQBlAGEAMwBhADUAMAA2AGIANQA4AGUAZgAzADQAZQBmADQANABmAGMAOQBmADEANgA0ADkAMQBhAGQAYQAyAGMAMwA2AGEAOQAzADUAMgAwAGUAMwA2ADMAMwA0ADIAOQBjADIAMgBhAGIAZAA2ADcAOAA4ADAAYwA3AGYANQAwAGQANwAzADIAOQAxADcANwBhADAAMgBkADYANQBhADIAYwA4ADcAZgAwADEANgBmADEAZgA5AGMAYQBkAGYAYgAxAGUAYQBhAA== #> #endregion |