Private/Wissen/B_Basic/B61_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 #> # TODO siehe auch B63_Konvertierungen.ps1 #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.: Get-ChildItem -Path 'C:\' -Force Start-Process -FilePath "$env:WinDir\System32\WindowsPowerShell\v1.0\FileSystem.format.ps1xml" Start-Process -FilePath "$env:WinDir\System32\WindowsPowerShell\v1.0\" # ! 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*' Get-ChildItem -Path 'HKCU:\Software\Microsoft\Windows\CurrentVersion' | Select-Object -Property Name, PSChildName # 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) # ! Seit Windows PowerShell 5wird aber der 5 Property in die Listen-Darstellung gewechselt: Get-Process | Select-Object -Property 'Name', 'Company', 'CPU', 'TotalProcessorTime', 'WorkingSet64' Get-Process | Format-Table -Property 'Name', 'Company', 'CPU', 'TotalProcessorTime', 'WorkingSet64' | gm # ! 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 #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 | Format-List -Property 'Name' -GroupBy 'StartType' # TIPP - Besser so: Get-Service | Group-Object -Property '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 -Column 10 # -AutoSize Get-Alias | Select-Object -Property 'DisplayName' | 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' # ! 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: Write-Information -MessageData 'Zusätzliche Informationen.' # TIPP - Diese Meldungen interagieren mit dem Common-Parameter '-InformationAction Stop' und der Systemvariable $InformationPreference $InformationPreference = [System.Management.Automation.ActionPreference]::Continue # ! Weitreichende Informationen ausgeben: 'Weitreichende Informationen' | Write-Verbose # $VerbosePreference Test-NetConnection -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 $AllErrorsAndWarnings & { '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 # VT zu Out-File ist 1. Objekt i.d.R. besser Richtung Text umgewandelt wird und 2. können diverse PSProvider/PSDrive genutzt werden. Get-Process | Set-Content -Path 'C:\Temp\lfdProcs.txt' 'Protokoll-Meldung ....' | Add-Content -Path 'C:\temp\Xyz.log' #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: Get-PSReadLineOption Set-PSReadLineOption -EditMode ([Microsoft.PowerShell.EditMode]::Vi) # ! 2. Prüfen ob eine VT100-Ausgabe möglich ist: if ($host.UI.SupportsVirtualTerminal) { "[1mHallo[0m [31mWürzburg!" } else { 'Hallo Würzburg!' } # ! Kombinationen sind möglich: "[1;4mBold and Underlined[24m Bold Only [0mNormal Text" #region Mögliche VT100 Sequenzen # ! Allgemein "[!p" # Soft Reset Reset certain terminal settings to their defaults. "[0m" # Default Returns all attributes to the default state prior to modification "[1m" # Bold Applies brightness/intensity flag to foreground color "[21m" # Bold Reset "[4m" # Underline Adds underline "[24m" # No underline Removes underline "[7m" # Negative Swaps foreground and background colors "[27m" # No negative Returns foreground/background to normal # ! Vordergrund Farbe "[30m" # Black "[31m" # Red "[32m" # Green "[33m" # Yellow "[34m" # Blue "[35m" # Magenta "[36m" # Cyan "[37m" # White "[38m" # Extended "[39m" # Default # ! Vordergrund Farbe strahlend "[90m" # Black "[91m" # Red "[92m" # Green "[93m" # Yellow "[94m" # Blue "[95m" # Magenta "[96m" # Cyan "[97m" # White # ! Hintergrund Farbe "[40m" # Black "[41m" # Red "[42m" # Green "[43m" # Yellow "[44m" # Blue "[45m" # Magenta "[46m" # Cyan "[47m" # White "[48m" # Extended "[49m" # Default # ! Hintergrund Farbe strahlen "[100m" # Black "[101m" # Red "[102m" # Green "[103m" # Yellow "[104m" # Blue "[105m" # Magenta "[106m" # Cyan "[107m" # White # ! Musterfarben: @( "[30m30m Foreground Black[0m" "[90m90m Foreground Bright Black[0m" "[31m31m Foreground Red[0m" "[91m91m Foreground Bright Red[0m" "[32m32m Foreground Green[0m" "[92m92m Foreground Bright Green[0m" "[33m33m Foreground Yellow[0m" "[93m93m Foreground Bright Yellow[0m" "[34m34m Foreground Blue[0m" "[94m94m Foreground Bright Blue[0m" "[35m35m Foreground Magenta[0m" "[95m95m Foreground Bright Magenta[0m" "[36m36m Foreground Cyan[0m" "[96m96m Foreground Bright Cyan[0m" "[37m37m Foreground White[0m" "[97m97m Foreground Bright White[0m" "[97m[40m 40m Background Black [0m" "[97m[41m 41m Background Red [0m" "[97m[42m 42m Background Green [0m" "[97m[43m 43m Background Yellow [0m" "[97m[44m 44m Background Blue [0m" "[97m[45m 45m Background Magenta [0m" "[97m[46m 46m Background Cyan [0m" "[97m[47m 47m Background White [0m" "[30m[100m 100m Background Bright Black [0m" "[30m[101m 101m Background Bright Red [0m" "[30m[102m 102m Background Bright Green [0m" "[30m[103m 103m Background Bright Yellow [0m" "[30m[104m 104m Background Bright Blue [0m" "[30m[105m 105m Background Bright Magenta [0m" "[30m[106m 106m Background Bright Cyan [0m" "[30m[107m 107m Background Bright White [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-Mappe # Ü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 -PivotRows 'Company' -PivotData 'PM' -Show Start-Process -FilePath 'C:\Temp\CurrentProcesses.XlsX' -Wait #endregion #region 🔥 Emojis ❗ und ASCII-Art # https://emojipedia.org/ 🌵 🔥 🚒 😁 ❗ 🙋♀️ 🕹 🥳 <# ____ ____ ____ ____ /\ \/\ \/\ \/\ \ / \___\ \___\ \___\ \___\ \ / __/_/ / / / / / \/_/\ \__/\/___/\/___/ / \___\ / \___\ \ / __/_ _\ / / \/_/\ \/\ \/___/ / \__/ \___\ \ / _\ / / \/_/\ \/___/ / \___\ \ / / \/___/ ______________________ /\ \ / \ _________________\ \ \ \ / \ \ \__________ / \ \ \ / / / \ \ \ / / / \ \ \/ / / \ \ / / / \ \/ / / \ / / \ / / \ / / \/___/ #> #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 #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 |