Private/Wissen/B_Basic/B18_Ausgabe.ps1
<#
# Objekt-Ausgabe In der PowerShell erzeugte Objekte ausgeben um diese in anderen System weiter zu verarbeiten. - **Hashtags** Format Write Out Excel CSV XML HTML WinForms Chart Diagram VT100 - **Version** 2020.05.28 #> #region Default-Ausgabe # ! Die visuelle Ausgabe in der PowerShell-Console zeigt nur einen Teil der tatsächlichen Objekt-Informationen. Diese Default-Ausgabe wird über .PS1XML-Dateien gesteuert, die entweder in Modules enthalten sind oder direkt im PowerShell-PFad, z.B.: Start-Process -FilePath "$env:WinDir\System32\WindowsPowerShell\v1.0\FileSystem.format.ps1xml" # ! ACHTUNG: Eine Spaltenüberschrift dieser Default-Ausgabe muss nicht immer identisch sein mit dem Eigenschaftsnamen des Objektes, z.B. die Default-Ausgabe von Registry-Key. Hier wird der Inhalt der Objekt-Property 'PSChildName' unter der Überschrift 'Name' angezeigt. 'Name' jedoch gibt es auch als Objekt-Property. Was zu Folge hat das folgende Filterung nicht funktioniert: Get-ChildItem -Path 'HKCU:\Software\Microsoft\Windows\CurrentVersion' | Where-Object -Property 'Name' -iLike -Value 'Run*' # TIPP - Korrekt müsste die Filterung wie folgt lauten: Get-ChildItem -Path HKCU:\Software\Microsoft\Windows\CurrentVersion | Where-Object -Property 'PSChildName' -iLike -Value 'Run*' # * Siehe dazu: Start-Process -FilePath "$env:WinDir\System32\WindowsPowerShell\v1.0\Registry.format.ps1xml" #endregion #region Format-* Cmdlets # Die Format-*-Cmdlets bereitet die Objekte für eine End-Ausgabe auf. # ! ACHTUNG => I.d.R. ist danach ein weiteres Bearbeiten von Objekten nicht mehr möglich! # READ Weiterführende und Nachschlage-Informationen: Get-Command -Verb 'Format' -Module 'Microsoft.PowerShell.*' #region Besonderheiten zu Format-Table (Tabellarische Anzeige) # ! Spalten-Breite optimal anpassen: Get-Process | Format-Table -Property 'Name', 'Company', 'CPU', 'TotalProcessorTime', 'WorkingSet64' -AutoSize # ! Inhalt der auf '...' endet in weitere Zeilen umbrechen: Get-EventLog -LogName 'System' -Newest 8 -EntryType 'Error' | Format-Table -Wrap # ! Benutzerdefinierte Spalten hinzufügen Basis-Template: @{ Label='' ; Expression={ $_ } }: Get-Process | Format-Table -Property 'Name', @{ Label='WS (MB)'; Expression={ '{0,7:0.0}' -f ($_.WorkingSet64 / 1MB) } } #endregion #region Besonderheiten zu Format-List (Listen Anzeige) # ! Den Inhalt ALLER Properties übersichtlich anzeigen: Get-Process | Sort-Object -Property 'WorkingSet64' -Descending | Select-Object -First 1 | Format-List -Property '*' Get-Process | Sort-Object -Property 'WorkingSet64' -Descending | Select-Object -First 1 -Property '*' # TIPP # ! Eine gruppierte Anzeige: Get-Service | Sort-Object -Property 'StartType' | Format-List -Property 'Name' -GroupBy 'StartType' # ! Berechnungsfehler anzeigen: Get-Date | Format-List -Property 'DayOfWeek', { $_ / $null } -DisplayError #endregion #region Besonderheiten zu Format-Wide, fw (Kurzübersicht) # ! Eine visuell komprimierte Anzeige von vielen kurzen Property-Werten Get-ChildItem -Path 'C:\Windows\System32' -File -Force -Recurse -ErrorAction 'Ignore' | Select-Object -Property 'Extension' -Unique | Sort-Object -Property 'Extension' | Format-Wide -AutoSize Get-Alias | Select-Object -Property 'Name' | Format-Wide -AutoSize #endregion #endregion #region Write-* Cmdlets # Die Write-*-Cmdlets erzeugen eine Ausgabe im Informations-Stream. Diese Ausgabe stört nicht die Objekt-Weitergabe bzw. vermischt sich mit dieser. Diese Cmdlets hab i.d.R. noch weitere Sonderaufgaben. # READ Weiterführende und Nachschlage-Informationen: Get-Command -Verb 'Write' -Module 'Microsoft.PowerShell.Utility' # ! ACHTUNG - 'Write-Host' nicht mehr benutzen, da dieses Cmdlet als veraltet gekennzeichnet ist und in PowerShell 7 durch den bereits vorhanden Nachfolger 'Write-Output' ersetzt wurde. # ! Fehler-Meldung ausgeben: 'Achtung ich bin ein Fehler.' | Write-Error # TIPP - Diese Meldungen interagieren mit dem Common-Parameter '-ErrorAction Stop' und der Systemvariable $ErrorActionPreference # ! Warn-Meldung ausgeben: 'Upps ich bin eine Warnung' | Write-Warning # TIPP - Diese Meldungen interagieren mit dem Common-Parameter '-WarningAction Stop' und der Systemvariable $WarningPreference # ! Zusätzliche Informationen ausgeben: 'Zusätzliche Informationen.' | Write-Information # TIPP - Diese Meldungen interagieren mit dem Common-Parameter '-InformationAction Stop' und der Systemvariable $InformationPreference # ! Weitreichende Informationen ausgeben: 'Weitreichende Informationen' | Write-Verbose # ! Bei langer Laufzeit den Fortschritt visualisieren: 0..100 | ForEach-Object -Process { Write-Progress -Activity 'Verarbeite Daten' -Status '$_ Prozent' -PercentComplete $_ Start-Sleep -Milliseconds 100 } #endregion #region Ausgabe-Streams verstehen # ! Stream-Überblick: <# | STROM | ID | SYS-VARIABLE-NAME | DEFAULT-VALUE | CMDLET | | :---------- | :---: | :--------------------- | :--------------- | :---------------- | | Debug | 5 | $DebugPreference | SilentlyContinue | Write-Debug | | Error | 2 | $ErrorActionPreference | Continue | Write-Error | | Information | 6 | $InformationPreference | SilentlyContinue | Write-Information | | Verbose | 4 | $VerbosePreference | SilentlyContinue | Write-Verbose | | Warning | 3 | $WarningPreference | Continue | Write-Warning | | Output | 1 | - | - | Write-Output | | Host | 6 | - | - | Write-Host | #> # ! Streams umleiten - Standardmäßig wird Variablen nur der Ausgabe-Stream zugewiesen. Alle anderen Streams werden entweder direkt an die Konsole gesendet oder ausgeblendet. # TODO ID 2 und 3 auf 1 umleiten: $AllErrorsAndWarnings = Get-Process -FileVersionInfo 2>&1 3>&1 & { 'Write-Error' | Write-Error 'Write-Warning' | Write-Warning 'Write-Verbose' | Write-Verbose -Verbose Write-Information -MessageData 'Write-Information' -InformationAction 'Continue' 'Write-Output' | Write-Output 'Write-Host' | Write-Host } *>$null # 2>$null 3>$null 4>$null 5>$null 6>$null # ! Write-Output vs. Write-Information: # Write-Output - Verwenden Sie dieses Cmdlet für Nachrichten, die ein Benutzer immer **sehen sollte**. Obwohl Write-Output den Informations-Stream verwendet, wird er von keiner Voreinstellungs-Variable beeinflusst: 'Ich bin eine Write-Output-Meldung' | Write-Output # Write-Information - Verwenden Sie dieses Cmdlet für Nachrichten, die ein Benutzer standardmäßig **nicht sehen sollte**, die ein Benutzer jedoch möglicherweise aktivieren möchte: Write-Information -MessageData 'Ich bin eine Write-Information-Meldung' # ! -InformationAction 'Continue' # ! Streams verwerfen: Write-Warning 'A Warning' 3>$null # ? Warum manche Befehle hässlich sind: # Gelegentlich stoßen Sie auf Befehle die nicht den Regeln entsprechen und schreiben trotz dem unterdrücken in den Ausgaben-Stream. Zum Beispiel Get-WindowsUpdateLog ist ein Cmdlet der Informationen von .ETL-Dateien extrahiert und in eine Protokolldatei schreibt: Get-WindowsUpdateLog # Wenn Sie diesen Befehl ausführen wird eine Menge an Informationen ausgegeben und es scheint keine Möglichkeit zu geben, diese Informationen auszublenden oder zu verwerfen: $null = Get-WindowsUpdateLog *>&1 # Selbst wenn Sie alle Streams (*) umleiten und alles an $null senden, werden die Nachrichten weiterhin in der Konsole angezeigt. Dieses Problem tritt immer dann auf, wenn Befehle direkt in die Konsole schreiben und so den Stream-Mechanismus umgehen: & { [Console]::WriteLine('Hallo Würzburg!') } *>$null # ! Sämtliche Ausgaben stumm schalten: # Um die direkte Konsolenausgabe stummzuschalten und sämtliche Ausgaben zu verwerfen, können Sie das Cmdlet Out-Default vorübergehend deaktivieren: function Out-Default { } # TODO Test: Get-WindowsUpdateLog # TODO Out-Default wiederherstellen: Remove-Item -Path 'function:\Out-Default' #endregion #region OUT-* # Diese Cmdlets leiten die Ausgabe um. # READ Weiterführende und Nachschlage-Informationen: Get-Command -Verb 'Out' -Module 'Microsoft.PowerShell.*' # ? Ausgabe seitenweise anzeigen: Get-ChildItem -Path 'C:\' -Recurse | Out-Host -Paging # ! 'more' ist unbrauchbar # ? Ausgabe in eine Datei umleiten: Get-Process | Out-File -FilePath 'C:\Temp\Process.txt' -Encoding 'ASCII' -Width '50' # ? Ausgabe zum Drucker umleiten: Get-ChildItem -Path 'C:\Windows' -File | Select-Object -First 10 | Out-Printer # ? Ausgabe in ein Windows-Fenster umleiten: Get-Process | Out-GridView # ? Ausgabe unterbinden: $al = New-Object -TypeName 'System.Collections.ArrayList' $al.Add('Hallo') $al.Add('Würzburg') | Out-Null #endregion #region Set-Content, Add-Content # TODO .... #endregion #region VT100 Host Format # READ Weiterführende und Nachschlage-Informationen: # ANSI escape code https://en.wikipedia.org/wiki/ANSI_escape_code # ! 1. Virtual Terminal aktivieren: New-ItemProperty -Path 'HKCU:\Console' -Name 'VirtualTerminalLevel' -Value 1 -PropertyType 'DWord' Set-PSReadlineOption -EditMode Vi # ! 2. ESC-Zeichen festlegen: New-Variable -Name 'ESC' -Value ([char]0x1b) -Description 'Escape sequences' -Option 'ReadOnly' -Visibility 'Public' -Scope 'Global' -Force # ! 3. Prüfen ob eine VT100-Ausgabe möglich ist: if ($host.UI.SupportsVirtualTerminal) { "$esc[1mHallo$esc[0m $esc[31mWürzburg!" } else { 'Hallo Würzburg!' } # ! Kombinationen sind möglich: "$esc[1;4mBold and Underlined$esc[24m Bold Only $esc[0mNormal Text" #region Mögliche VT100 Sequenzen # ! Allgemein "$ESC[!p" # Soft Reset Reset certain terminal settings to their defaults. "$ESC[0m" # Default Returns all attributes to the default state prior to modification "$ESC[1m" # Bold Applies brightness/intensity flag to foreground color "$ESC[21m" # Bold Reset "$ESC[4m" # Underline Adds underline "$ESC[24m" # No underline Removes underline "$ESC[7m" # Negative Swaps foreground and background colors "$ESC[27m" # No negative Returns foreground/background to normal # ! Vordergrund Farbe "$ESC[30m" # Black "$ESC[31m" # Red "$ESC[32m" # Green "$ESC[33m" # Yellow "$ESC[34m" # Blue "$ESC[35m" # Magenta "$ESC[36m" # Cyan "$ESC[37m" # White "$ESC[38m" # Extended "$ESC[39m" # Default # ! Vordergrund Farbe strahlend "$ESC[90m" # Black "$ESC[91m" # Red "$ESC[92m" # Green "$ESC[93m" # Yellow "$ESC[94m" # Blue "$ESC[95m" # Magenta "$ESC[96m" # Cyan "$ESC[97m" # White # ! Hintergrund Farbe "$ESC[40m" # Black "$ESC[41m" # Red "$ESC[42m" # Green "$ESC[43m" # Yellow "$ESC[44m" # Blue "$ESC[45m" # Magenta "$ESC[46m" # Cyan "$ESC[47m" # White "$ESC[48m" # Extended "$ESC[49m" # Default # ! Hintergrund Farbe strahlend "$ESC[100m" # Black "$ESC[101m" # Red "$ESC[102m" # Green "$ESC[103m" # Yellow "$ESC[104m" # Blue "$ESC[105m" # Magenta "$ESC[106m" # Cyan "$ESC[107m" # White # ! Musterfarben: @( "$ESC[30m30m Foreground Black$ESC[0m" "$ESC[90m90m Foreground Bright Black$ESC[0m" "$ESC[31m31m Foreground Red$ESC[0m" "$ESC[91m91m Foreground Bright Red$ESC[0m" "$ESC[32m32m Foreground Green$ESC[0m" "$ESC[92m92m Foreground Bright Green$ESC[0m" "$ESC[33m33m Foreground Yellow$ESC[0m" "$ESC[93m93m Foreground Bright Yellow$ESC[0m" "$ESC[34m34m Foreground Blue$ESC[0m" "$ESC[94m94m Foreground Bright Blue$ESC[0m" "$ESC[35m35m Foreground Magenta$ESC[0m" "$ESC[95m95m Foreground Bright Magenta$ESC[0m" "$ESC[36m36m Foreground Cyan$ESC[0m" "$ESC[96m96m Foreground Bright Cyan$ESC[0m" "$ESC[37m37m Foreground White$ESC[0m" "$ESC[97m97m Foreground Bright White$ESC[0m" "$ESC[97m$ESC[40m 40m Background Black $ESC[0m" "$ESC[97m$ESC[41m 41m Background Red $ESC[0m" "$ESC[97m$ESC[42m 42m Background Green $ESC[0m" "$ESC[97m$ESC[43m 43m Background Yellow $ESC[0m" "$ESC[97m$ESC[44m 44m Background Blue $ESC[0m" "$ESC[97m$ESC[45m 45m Background Magenta $ESC[0m" "$ESC[97m$ESC[46m 46m Background Cyan $ESC[0m" "$ESC[97m$ESC[47m 47m Background White $ESC[0m" "$ESC[30m$ESC[100m 100m Background Bright Black $ESC[0m" "$ESC[30m$ESC[101m 101m Background Bright Red $ESC[0m" "$ESC[30m$ESC[102m 102m Background Bright Green $ESC[0m" "$ESC[30m$ESC[103m 103m Background Bright Yellow $ESC[0m" "$ESC[30m$ESC[104m 104m Background Bright Blue $ESC[0m" "$ESC[30m$ESC[105m 105m Background Bright Magenta $ESC[0m" "$ESC[30m$ESC[106m 106m Background Bright Cyan $ESC[0m" "$ESC[30m$ESC[107m 107m Background Bright White $ESC[0m" ) -join " | " # ! Der Rest: # Console Virtual Terminal Sequences https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences #endregion #endregion #region Select-String # ! PowerShell 7 :: Verbesserung von Select-String um eine visuelle Hervorhebung von Fundstellen: Get-ChildItem -Path 'C:\Windows\Logs\DISM\dism.log' | Select-String -Pattern 'Error' | Select-Object -First 10 # READ Der Switch-Parameter -NoEmphasis deaktiviert die Hervorhebung. #endregion #region Console-GUI # Wie Out-GridView nur in der Console. # TODO - Erst ab PowerShell 6.2 Install-Module -Name 'Microsoft.PowerShell.ConsoleGuiTools' -Scope 'CurrentUser' -Force -Verbose Import-Module -Name 'Microsoft.PowerShell.ConsoleGuiTools' -Verbose Get-Command -Module 'Microsoft.PowerShell.ConsoleGuiTools' Get-Process | Out-ConsoleGridView #endregion #region PowerShell 7-Module 'Microsoft.PowerShell.GraphicalTools' # ! PowerShell 7 :: Ein neues Module (Microsoft.PowerShell.GraphicalTools, Version 0.2.0) für OS-Übergreifende GUI's (Out-GridView, Show-Command, Get-Help -ShowWindow): Install-Module -Name 'Microsoft.PowerShell.GraphicalTools' -Scope 'CurrentUser' -AllowClobber -SkipPublisherCheck -AllowPrerelease -AcceptLicense -Force Remove-Alias -Name 'ogv' -Force Import-Module -Name 'Microsoft.PowerShell.GraphicalTools' -Force Get-Command -Module 'Microsoft.PowerShell.GraphicalTools' Get-Process | Out-GridView #endregion #region Export in eine Excel # Über das Module ImportExcel können Daten nach oder von Excel importiert / exportiert werden OHNE das Excel selber installiert sein muss. # TIPP - Videos https://www.youtube.com/watch?v=U3Ne_yX4tYo&list=PL5uoqS92stXioZw-u-ze_NtvSo0k0K0kq Install-Module -Name 'ImportExcel' -Scope 'CurrentUser' -SkipPublisherCheck -Force Get-Command -Module 'ImportExcel' Remove-Item -Path 'C:\temp\CurrentProcesses.XlsX' -Force Get-Process | Export-Excel 'C:\Temp\CurrentProcesses.XlsX' -WorksheetName 'Processes' -ChartType 'PieExploded3D' -IncludePivotChart -IncludePivotTable -Show -PivotRows 'Company' -PivotData 'PM' Start-Process -FilePath 'C:\Temp\CurrentProcesses.XlsX' -Wait #endregion # ! Einfache grafische Benutzeroberflächen (GUI) sind mit der PowerShell und .NET mit geringen Aufwand möglich. Bei komplexen GUI's stößt die PowerShell schnell an ihre Grenzen da der Aufwand unverhältnismäßig groß ist. # TIPP - WinForm-Grundgerüst per GUI bauen über https://poshgui.com/Editor #region Eine WPF ALARM-Meldung using namespace 'System.Xml' using namespace 'System.IO' using namespace 'System.Windows.Markup' using namespace 'System.Speech.Synthesis' Add-Type -AssemblyName 'PresentationFramework' Add-Type -AssemblyName 'System.Speech' $xaml = @' <Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" Title="MainWindow" WindowStartupLocation="CenterScreen" ResizeMode="NoResize" SizeToContent="WidthAndHeight"> <Grid Background="Red"> <TextBlock Name="MyFadingText" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="50" FontFamily="Consolas" FontSize="100" FontWeight="ExtraBold" Foreground="White" Text="A L A R M !"> <TextBlock.Triggers> <EventTrigger RoutedEvent="TextBlock.Loaded"> <BeginStoryboard> <Storyboard> <DoubleAnimation Storyboard.TargetName="MyFadingText" Storyboard.TargetProperty="(TextBlock.Opacity)" From="1.0" To="0.0" Duration="0:0:1" AutoReverse="True" RepeatBehavior="Forever" /> </Storyboard> </BeginStoryboard> </EventTrigger> </TextBlock.Triggers> </TextBlock> </Grid> </Window> '@ $reader = [XmlReader]::Create([StringReader]$xaml) $window = [XamlReader]::Load($reader) $window.Topmost = $true $window.Add_Loaded({ $speaker = New-Object -TypeName 'SpeechSynthesizer' -Property @{ Rate = 2; Volume = 100 } $speaker.SpeakAsync('ALARM! ALARM! ALARM! ALARM!') }) $window.ShowDialog() | Out-Null #endregion #region Diagramm erstellen per DataVisualization using namespace System.Windows.Forms.DataVisualization.Charting using namespace System.Windows.Forms using namespace System.Drawing Add-Type -AssemblyName "System.Windows.Forms.DataVisualization" $chartTitle = "Top Memory Usage" $axisYTitle = "Memory (MB)" $axisXTitle = "Process Name" $dataSource = Get-Process | Sort-Object "PrivateMemorySize" -Descending | Select-Object -First 8 | ForEach-Object -Process { [PSCustomObject]@{ Name = $_.Name PrivateMemorySizeMB = [int]($_.PrivateMemorySize / 1MB) VirtualMemorySizeMB = [int]($_.VirtualMemorySize / 1MB) } } $chart1 = New-Object -TypeName "Chart" $chart1.Width = 1200 $chart1.Height = 1000 $chart1.BackColor = [Color]::White $chart1.Dock = [DockStyle]::Fill $chart1.Titles.Add($chartTitle) | Out-Null $chart1.Titles[0].Font = "Arial,13pt" $chart1.Titles[0].Alignment = [ContentAlignment]::TopCenter $chartArea = New-Object -TypeName "ChartArea" $chartArea.Name = "ChartArea1" $chartArea.AxisY.Title = $axisYTitle $chartArea.AxisX.Title = $axisXTitle $chartArea.AxisY.Interval = 100 $chartArea.AxisX.Interval = 1 $chart1.ChartAreas.Add($chartArea) $legend = New-Object -TypeName "Legend" $legend.name = "Legend1" $chart1.Legends.Add($legend) $chart1.Series.Add("VirtualMem") | Out-Null $chart1.Series["VirtualMem"].ChartType = "Column" $chart1.Series["VirtualMem"].BorderWidth = 3 $chart1.Series["VirtualMem"].IsVisibleInLegend = $true $chart1.Series["VirtualMem"].ChartArea = "ChartArea1" $chart1.Series["VirtualMem"].Legend = "Legend1" $chart1.Series["VirtualMem"].color = [Color]::LightGreen $dataSource | ForEach-Object -Process { $chart1.Series["VirtualMem"].Points.AddXY( $_.Name, $_.VirtualMemorySizeMB) | Out-Null } $chart1.Series.Add("PrivateMem") | Out-Null $chart1.Series["PrivateMem"].ChartType = "Column" $chart1.Series["PrivateMem"].IsVisibleInLegend = $true $chart1.Series["PrivateMem"].BorderWidth = 3 $chart1.Series["PrivateMem"].ChartArea = "ChartArea1" $chart1.Series["PrivateMem"].Legend = "Legend1" $chart1.Series["PrivateMem"].color = [Color]::Orange $dataSource | ForEach-Object -Process { $chart1.Series["PrivateMem"].Points.AddXY( $_.Name, $_.PrivateMemorySizeMB) | Out-Null } # ! z.B. zusätzlich als PNG speichern: $chart1.SaveImage("c:\temp\$chartTitle.png", "png") # ! z.B. im Fenster anzeigen: $Form = New-Object -TypeName "Form" $Form.Width = 1300 $Form.Height = 800 $Form.StartPosition = [FormStartPosition]::CenterScreen $Form.controls.add($chart1) $Form.Add_Shown({ $Form.Activate() }) $Form.ShowDialog() #endregion # TODO QUIZ - https://forms.office.com/Pages/ResponsePage.aspx?id=DQSIkWdsW0yxEjajBLZtrQAAAAAAAAAAAAa__Yp1xwFUNldPRUxFSExFTDkzQVRQUENQMFFTMUhTMi4u |