Pipeline ======== .. _loesung_pipeline: - Virtual Memory .. code-block:: sh Get-Process | Sort-Object WorkingSet | Select-Object -First 5 - Largest File .. code-block:: sh Get-ChildItem -Recurse | Where-Object { $_.Length -gt 10MB } | Sort-Object Length -Descending | Select-Object -First 10 - Foreach: Foreach-Objekt besrbeitet die Elemente der Pipeline sofort .. code-block:: sh # ForEach-Object lists each element in a pipeline: Dir C:\ -recurse | ForEach-Object { $_.name } - Alias: .. code-block:: sh Get-Alias | where-object { $_.definition -eq "get-process" } - 20 MByte-Prozesse .. code-block:: sh get-process | where-object {$_.WorkingSet64 -gt 20MB } ps | ? {$_.ws -gt 20MB } - Sortiert nach Größee .. code-block:: sh ps | ? {$_.ws -gt 20MB } | sort ws - Ausgabe Produktversion .. code-block:: sh ps | select company, name, product, productversion - Dateien .. code-block:: sh Get-Childitem h:\daten -filter *.doc -r | Where-Object { $_.Length -gt 40000 } | Select-Object Name, Length | Sort-Object Length | export-csv p:\GrosseWordDateien.csv -notype - Geben Sie alle Unterordner bis zu einer bestimmten Tiefe aus, ausgehend vom jeweils aktuellen Ordner $Cred = New-Object System.Management.Automation.PSCredential "Administrator", $Pw .. code-block:: sh gci -recurse | ? {$_.PSisContainer -eq $true} | where{ if(($_.fullname.split("\")).count -le 4) { write-host $_.fullname } } - Sie wollen prüfen, ob auf bestimmten Rechnern innerhalb ihres LANs Software bestimmter Hersteller vorhanden ist. Schreiben Sie ein entsprechendes Skript .. code-block:: sh ######################################## # The PowerShell script inventories the installed software # of a producer on n computer systems # (C) Dr. Holger Schwichtenberg ######################################## $Producer = "*Microsoft*" $EntryFilename = "computernames.txt" $OutputFilename = "Softwareinventory.csv" $pw = Read-Host -AsSecureString # Import of computer names $Computernames = Get-Content "computernames.txt" $Computernames | foreach { if (Ping($_)) { Write-Host "Inventorize software for computer $_ ..." # Fetching of installed MSI packages on all computers $Cred = New-Object System.Management.Automation.PSCredential $_\Administrator, $Pw $Software = foreach { get-wmiobject win32_product -computername $_ -credential $Cred } | where { $_.vendor -like $Producer } # Export in CSV $Software | export-csv $OutputFileName -notypeinformation } else { Write-Error "Computer not accessible!" } } # Execute Ping function Ping { $status = Get-WmiObject Win32_PingStatus -�lter "Address='$args[0]'" | select StatusCode return $status.Statuscode -eq 0 } Das Skript ist in mehrere Teile gegliedert: 1) Function Ping .. code-block:: sh # Execute Ping function Ping { $status = Get-WmiObject Win32_PingStatus -�lter "Address='$args[0]'" | select StatusCode return $status.Statuscode -eq 0 } Erhält als Parameter einen Computernamen, ermittelt den Statuscode und gibt true zurück, wenn der Computer erreichbar ist 2) Einstieg in das Skript .. code-block:: sh $Producer = "*Microsoft*" $Entry�lename = "computernames.txt" $Output�lename = "Softwareinventory.csv" # Import of computer names $Computernames = Get-Content "computernames.txt" Definition von einigen Variablen Lesen der zu überprüfenden Computernamen aus einer Textdatei 3) Informationsbeschaffung .. code-block:: sh $Computernames | foreach { if (Ping($_)) { Write-Host "Inventorize software for computer $_ ..." # Fetching of installed MSI packages on all computers $Software = foreach { get-wmiobject win32_product -computername $_ } | where { $_.vendor -like $Producer } # Export in CSV $Software | export-csv "Softwareinventar.csv" -notypeinformation } else { Write-Error "Computer not accessible!" } } Über eine Pipeline werden die Computernamen nacheinander aufgerufen Bei erfolgreichem Ping wird per WMI der Remote-Computer auf das Vorhandensein des Herstellernamens abgefragt. Bei Vorhandensein wird es als Ergebnis in eine CSV-Datei geschrieben. - Erweitern Sie obiges Skript um die Abfrage nach bestimmten Softwarenamen bzw. Versionsständen. .. code-block:: sh function Get-IsInstall($Application, $Computer, $Version) { $a = (Get-WmiObject -Class Win32_Product -Filter "Name='$Application' and Version='$Version'" -computername $Computer) return ($a -ne $null) } $e = Get-IsInstall "QuickTime" "E01" "7.2.0.240" if ($e) { "Software is installed!" } else { "Software is not installed!" } .. index:: Pipeline , Sort-Object, Where-Object, Filter, Select-Object - I needed to merge 365 CSV files that represent daily weather data sets into one CSV file that contains all the data accumulated during one year. Each of the daily CSV files had a header row. The yearly file should only have one. Filtering out rows is a perfect application of the PowerShell filter functions. Übersetzen Sie den anglischen Text sinngemä߸ und schreiben Sie ein entsprechendes Skript. This is where PowerShell's pipeline programming is shining. It only takes a Filter function definition, inserting it into an pre-existing pipeline and you are done. Here is the sample script: http://www.tellingmachine.com/post/Using-PowerShell-Filter-functions-to-filter-out-header-rows-CSV-file-merges.aspx .. code-block:: sh #Filter Function filters out records that start with "Time" Filter Filter-Header { if($_ -match "^Time") { $_ | out-null } else { $_ } } cd "C:\WeatherStation\FilterTest" #Initializing yearly file $YearlyFileName = "Weather2009.csv" #Set the header only once in the yearly file Set-Content -Path $YearlyFileName -value "Time,TemperatureF,DewpointF,PressureIn,WindDirectionDegrees,WindSpeedMPH,WindSpeedGustMPH,Humidity,HourlyPrecipIn" -force -encoding "UTF8" #Open all csv files get-content and add it to the yearly file $Files = dir -Path "C:\Users\Klaus\Desktop\TO PLANET\WeatherStation\FilterTest" -Filter "*.csv" #Filter in Action $Files | ForEach-Object ` { Get-Content -Path $_.Name -Encoding "UTF8" | Filter-Header | Add-Content -path $YearlyFileName -Encoding "UTF8" } - Suchen Sie die letzten 2000 Systemereignisse des Eventlogs, die vom Typ "Error" sind .. code-block:: sh # PowerShell script to find Error messages in the System eventlog. Get-EventLog system -newest 2000 | where {$_.entryType -match "Error"} - Sie schreiben ein Powershell-Skript, welches eine eigene Ereignisquelle im Eventlog schafft und darunter seine Ereignisse schreibt. .. code-block:: sh ## Step 1 - PowerShell Script to create eventlog source by David Stone Clear-Host if (!(test-path ` HKLM:\SYSTEM\CurrentControlSet\Services\Eventlog\Application\SampleApp )) ` {new-eventlog -logname Application -source SampleApp ` -ErrorAction SilentlyContinue} ## Step 2 - Create a 'Job start' entry in your event log $startTime = Get-date $startLog = 'Sample job started at ' +$startTime+ ' local time' write-eventlog -LogName Application -Message $startLog -Source SampleApp ` -id 1 -entrytype Information -Category 0 ## Step 3 - A production script would have a payload here. ## Step 4 - Write errors during processing (typically part of a if statement) write-eventLog -LogName Application -Message 'Message content' ` -Source SampleApp -id 100 -entrytype Warning -category 0 ## Step 5 - Write end of process entry in your event log $endTime = Get-date $endLog = 'Sample job ended at ' +$endTime+ ' local time' write-eventlog -LogName Application -Message $endLog -Source SampleApp ` -id 9 -entrytype Information -category 0 - Schreiben Sie die Einträge der obigen Quelle in eine CSV-Datei. Es soll nur die jeweils letzte Stunde eingetragen werden .. code-block:: sh ## Step 6 - Write the entries to a csv file Clear-Host $logtime=[DateTime]::Now.AddHours(-1) $CSVPath = "C:\SSource.csv" Get-EventLog -LogName application -Source 'SampleApp' ` -EntryType warning -After $logtime ` | select eventid, machinename, entrytype, source, message, timegenerated ` | Export-Csv $CSVPath -NoTypeInformation - A Real-life Example of Select-String My practical problem was that I wanted to search for instances a particular string in a directory with hundreds of file. If a file had duplicate entries, then I needed to know. The PowerShell problem is how to create a stream of the files, then compare each file with my string value. In the output I needed to know the filename. To solve the problem, I employed four main commands, which you can see in the following script: .. code-block:: sh Get-ChildItem - recurse foreach (loop) {what to do block} if (test) {output block} select-String -pattern to match my string value. .. code-block:: sh # A real-life example of PowerShell's Select-String $i=0 $File = Get-ChildItem "C:\html" -include *.html -recurse $StringVid = "msbuild" foreach ($Entry in $File) { $List = select-string -pattern $StringVid $Entry if ($List.LongLength -gt 1) { "{0,-8} {1,-4} {2,18}" -f "Files ", $List.LongLength, $Entry.FullName; $i++ } } - Namensauflösung einer IP-Range Die Programmfunktionalität wird mit Hilfe von 2 Funktionen realisiert. **Get-ComputerNameByIP** zeigt die Verwendung von Fehlerbehandlungscode, **Check-Online** zeigt die Verwendung von Hintergrundprozessen. Als Speicher für die IP-Adressen und Hostnamen wird die Datenstruktur eines **Hashes** verwendet, .. code-block:: sh <# .SYNOPSIS Gets a computer name .DESCRIPTION Resolve a computer name using an IP address .PARAMETER $IPAddress .EXAMPLE Get-ComputerNameByIP "192.168.1.1" .AUTHOR G.W. Scheppink #> function Get-ComputerNameByIP { param( $IPAddress = $null ) begin { } process { if ($IPAddress -and $_) { Throw "Please use either pipeline or input parameter" break } elseif ($IPAddress) { ([System.Net.Dns]::GetHostbyAddress($IPAddress)) } elseif ($_) { trap [Exception] { write-warning $_.Exception.Message continue; } [System.Net.Dns]::GetHostbyAddress($_) } else { $IPAddress = Read-Host "Please supply the IP Address" [System.Net.Dns]::GetHostbyAddress($IPAddress) } } end { } } # End function function Check-Online { param( $computername ) test-connection -count 1 -ComputerName $computername -TimeToLive 5 -asJob | Wait-Job | Receive-Job | Where-Object { $_.StatusCode -eq 0 } | Select-Object -ExpandProperty Address StatusCode } # This code pings an IP segment from 192.168.1.1 to 192.168.1.254 and returns only those IPs that respond. CLS $ip_name = @{} $Start = Get-Date $ips = 1..254 | ForEach-Object { "192.168.0.$_" } $online = Check-Online -computername $ips $online foreach ($PC in $online) { $pcname = Get-ComputerNameByIP $PC $ip_name+=@{$PC=$pcname.HostName} } $End = Get-Date Write-Host "`nStarted at: " $Start Write-Host "Ended at: " $End $ip_name #umständliches Schreiben der key-value-Paare aus einem Hash heraus $ip_name.GetEnumerator() | Sort-Object Name | ForEach-Object {"{0} , {1}" -f $_.Name,$_.Value} | Add-Content C:\temp\log.csv` - Laptop oder Desktop Sie sind die IT-Leiter einer kleinen mittelständischen Firma. Sie müssen Inventur machen und Sie brauchen dazu die Anzahl der zur Zeit sich im Netz befindlichen Laptop-und Desktop-Computer in ihrer Firma. .. code-block:: sh Following is the full script. <# .Synopsis helper function used by Get-HardwareType .EXAMPLE Example of how to use this cmdlet #> function Is-Laptop { [CmdletBinding()] [OutputType([boolean])] param ( [Parameter(Mandatory=$true)] [string] $strHostName ) $blnResult = $false $query = "select __SERVER,ChassisTypes from Win32_SystemEnclosure" $objWMI = Get-WmiObject -ComputerName $strHostName -Query $query -ErrorAction Stop switch ($objWMI.ChassisTypes) { 9 {$blnResult = $true} # Laptop 10 {$blnResult = $true} # Notebook 12 {$blnResult = $true} # Docking Station 14 {$blnResult = $true} # Sub Notebook default {} } return $blnResult } # end function <# .Synopsis function to determine chassis type using a WMI query .DESCRIPTION function to determine chassis type using a WMI query .EXAMPLE "pc01","pc02","pc03" | Get-HardwareType #> function Get-HardwareType { [CmdletBinding()] [OutputType([psobject])] Param ( [Parameter(Mandatory=$true,ValueFromPipeline=$true)] $strHostName ) process { try { $objHostName = [system.net.dns]::GetHostByName($strHostName) $query = "select __SERVER,ChassisTypes from Win32_SystemEnclosure" if (Test-Connection -ComputerName $objHostName.HostName -count 1 -erroraction silentlycontinue) { try { $objResult = New-Object -TypeName psobject -Property @{HostName=$objHostName.HostName;IsLaptop=(Is-Laptop -strHostName $objHostName.HostName)} return $objResult } catch { "Error trying to query $($objHostName.HostName)" } } else { write-host "error connecting to $($objHostName.HostName)" } } catch { write-host "Unable to resolve DNS address for $strHostName" } } } # end function $laptopCount = 0 $desktopCount = 0 $searcher = new-object directoryservices.directorysearcher([ADSI]"","(&(objectcategory=computer)(!operatingsystem=*server*))") [void]$searcher.PropertiesToLoad.Add("cn") $arrMachineName = $searcher.findall() | %{$_.properties.cn} $result = $arrMachineName | Get-HardwareType $result $result | ForEach-Object {if ($_.islaptop) {$laptopCount++} else {$desktopCount++}} "Laptop Total: $laptopCount" "Desktop Total: $desktopCount" ## beim Lesen aus Textdatei #$result = import-csv C:\temp\laptop_desktop.ps1 | Group-Object {$_.chassis} -noelement #$result = import-csv C:\temp\laptop_desktop.ps1 | Group-Object -property chassis -noelement #$result