Private/Wissen/B_Basic/B2_PowerShell.ps1

<#
 
# PowerShell
 
Worum handelt es bei der PowerShell und wie stellt sich der historische Hintergrund dar.
 
- **Hashtags** Einführung Version Geschichte PowerShell Host Runspace PSVersionTable Transcript Protokoll Enumeration Limit
 
- **Version** 2020.5.22
 
#>


using namespace System.Diagnostics.CodeAnalysis

[SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')]
[SuppressMessageAttribute('PSAvoidUsingCmdletAliases', '')]
param()

#region Was ist die PowerShell?

# ! Die Windows PowerShell ist ein Kommandozeileninterpreter von Microsoft.

C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -?

# ! Die auf dem Microsoft .NET-Framework basierende PowerShell verbindet die aus Unix-Shells bekannte Philosophie von Pipes und Filtern mit dem Paradigma der objektorientierten Programmierung (OOP):

Get-Service | Where-Object Status -EQ Running 
Get-Service | Where-Object Status -EQ Running | Get-Member

# ! Die PowerShell ist objektorientiert und mit .NET erweiterbar bzw. kann selber .NET zu 100% benutzen.

$file = Get-ChildItem -Path 'C:\Windows\notepad.exe'
$file.LastAccessTime
$file.Length
$file.CopyTo("c:\temp\notepad.exe")
$file | Add-Member -MemberType 'ScriptProperty' -Name LengthKb -Value { $this.Length / 1KB }
$file.LengthKb

# ! Die PowerShell steht als 32bit und 64bit Anwendung zur Verfügung. Mit der 32bit Version können Sie nur auf 32bit Treiber/-Anwendungen zugreifen.

C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
C:\Windows\syswow64\WindowsPowerShell\v1.0\powershell.exe

# !Die PowerShell steht für Windows, MacOS und Linux zur Verfügung. Die "Windows PowerShell" für Windows Systeme, "PowerShell Core" für Windows/Unix/Linux Systeme und "PowerShell 7" für Windows, MacOS und Linux.

#endregion

#region PowerShell-Versionen / -History

# Seit Windows 7 / Server 2008 ist die PowerShell fester Bestandteil des Betriebssystems

# ? Welche Version ist installiert?
$PSVersionTable

#region Windows PowerShell 1.0 - 4.0

# 1.0 = Markteinführung
# 2.0 = Remoting via RPC
Get-Help -Name * -Parameter ComputerName # Nur diese Cmdlets können remote zugreifen
# 3.0 = Default in: Windows7 / Windows Server 2008 R2; Min. OS: >XP, >VISTA
# 3.0 = Remoting via WinRM, Workflows, Scheduled[Jobs], Windows PowerShell Web Access, Netzlaufwerke verbinden (New-PSDrive), Aktualisierbare Hilfe, Web Cmdlet's
# 3.0 = Vereinfachte Syntax:
Get-Process | Where-Object -FilterScript {$_.Handles -gt 500}
Get-Process | Where-Object -Property Handles -GT -Value 500
# 4.0 = DEFAULT: Windows 8, Windows Server 2012, Desired State of Configuration (DSC)

#endregion

#region Windows PowerShell 5.0, 5.1

# Default OS: Windows 10, Windows Server 2016

# Softwarepakete installieren
# Switch-Verwaltung
# OOP

#region Details zu Neuerungen

# Alle Details zur 5.0 Version unter:
Get-Help about_Windows_PowerShell_5.0 -ShowWindow
Start-Process http://msdn.microsoft.com/de-de/powershell/scripting/whats-new/what-s-new-in-windows-powershell-50

#region Get-ItemPropertyValue

#NEU: Get-ItemPropertyValue
#FRÜHER:
(Get-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\PowerShell\3\PowerShellEngine -Name ApplicationBase).ApplicationBase
#JETZT:
Get-ItemPropertyValue -Path HKLM:\SOFTWARE\Microsoft\PowerShell\3\PowerShellEngine -Name ApplicationBase

#endregion

#region Einfache String-Operationen
"Hallo Welt" | ConvertFrom-String
"Hallo Welt" | ConvertFrom-String -Delimiter "ll"
"Hallo Welt" | ConvertFrom-String -PropertyNames FirstWord, SecondWord

"Lee Holmes", "Steve Lee", "Jeffrey Schmitt" | Convert-String -Example "Bill Gates=Gates, B.","John Smith=Smith, J."

"Hallo Welt" | Format-Hex
#endregion

#region ZIP-Archive

#
#Test-Daten erzeugen
#
New-Item -Path C:\temp\ZipMich -ItemType Directory -Force
1..1MB -join ";" | Set-Content -Path "C:\temp\ZipMich\LogFile1.txt" -Force
1..1MB -join ";" | Set-Content -Path "C:\temp\ZipMich\LogFile2.txt" -Force

#
# Compress-Archive
#
"C:\temp\ZipMich" | Compress-Archive -DestinationPath C:\temp\ZipMich.zip -CompressionLevel Optimal -Force
Get-Help Compress-Archive -ShowWindow

#
# Expand-Archive
#
"C:\temp\ZipMich.zip" | Expand-Archive -DestinationPath C:\temp\Backup -Force
Get-Help Expand-Archive -Full

#endregion

#region Software-Installation

Set-ExecutionPolicy -ExecutionPolicy AllSigned

Get-Command -Module PowerShellGet, PackageManagement

Find-Package | Out-GridView
Install-Package -Name AKPT -Force
Get-Module -ListAvailable 
Get-Command * -Module AKPT
Get-AKAbout
Uninstall-Package -Name AKPT

Register-PSRepository -Name "myNuGetSource" â€“SourceLocation "https://www.myget.org/F/powershellgetdemo/api/v2" -PublishLocation "https://www.myget.org/F/powershellgetdemo/api/v2/Packages" -InstallationPolicy Trusted
Get-PSRepository
Unregister-PSRepository -Name "myNuGetSource"

#endregion

#region Kryptographie

Get-Command -Module Microsoft.PowerShell.Security 

$MyCertInf = @"
[Version]
Signature = "$Windows NT$"
 
[Strings]
szOID_ENHANCED_KEY_USAGE = "2.5.29.37"
szOID_DOCUMENT_ENCRYPTION = "1.3.6.1.4.1.311.80.1"
 
[NewRequest]
Subject = "cn=me@example.com"
MachineKeySet = false
KeyLength = 2048
KeySpec = AT_KEYEXCHANGE
HashAlgorithm = Sha1
Exportable = true
RequestType = Cert
 
KeyUsage = "CERT_KEY_ENCIPHERMENT_KEY_USAGE | CERT_DATA_ENCIPHERMENT_KEY_USAGE"
ValidityPeriod = "Years"
ValidityPeriodUnits = "1000"
 
[Extensions]
2.5.29.37="{text}1.3.6.1.4.1.311.80.1"
"@

Set-Content -Path C:\temp\MyCert.inf -Value $MyCertInf
CertReq -new C:\temp\MyCert.inf C:\temp\MyCert.cer
$cert = Get-ChildItem -pv Cert:\CurrentUser\My | Where-Object -Property Subject -EQ -Value "cn=me@example.com"

$crypt = "Hallo Welt" | Protect-CmsMessage -To $cert
Unprotect-CmsMessage -Content $crypt -To $cert

#endregion

#region OOP

Get-Help about_Classes -ShowWindow

enum Farbe
{
    Blau
    Grün
    Rot
}
$meineFarbe = [Farbe]::Grün
$meineFarbe 

class Auto
{
    [Farbe]$Farbe
    $PS
}

$meinAuto = New-Object -TypeName Auto

$meinAuto.Farbe = [Farbe]::Grün
$meinAuto.PS = 100
$meinAuto | Get-Member

#endregion

#region Weitere neue Cmdlet's

Set-Clipboard -Value "Hallo Köln!"
Get-Clipboard

Clear-RecycleBin -DriveLetter c: -Confirm:$false

New-TemporaryFile

New-Guid

# symbolischer Verknüpfungen
New-Item -ItemType SymbolicLink -Name MySymLinkDir -Target $pshome 

# -Depth 2
Get-ChildItem c:\ -Recurse -Depth 2 -Force

#endregion

#region DataCenter Abstraction Layer (DAL)

<#
    Mit dieser Technologie können Sie direkt auf bestimmte
    Netzwerkkomponenten wie Switches und Router zugreifen.
 
    Dazu muss die Hardware diese Technik aber auch unterstützen.
    In diesem Bereich spielen vor allem
    Cisco und Huawei eine wichtige Rolle.
#>


$Session = New-CimSession -ComputerName $MyNetworkSwitchName
Get-NetworkSwitchFeature -CimSession $Session

<#
    Name IsEnabled InstanceID PSComputerName
    ---- --------- ---------- --------------
    SSH True Contoso:Feature:2 10.19.26.49
    Tacacs True Contoso:Feature:3 10.19.26.49
    BGP False Contoso:Feature:4 10.19.26.49
    VLAN True Contoso:Feature:5 10.19.26.49
    LACP True Contoso:Feature:6 10.19.26.49
    DHCP False Contoso:Feature:7 10.19.26.49
    LLDP True Contoso:Feature:8 10.19.26.49
#>


Get-Help Get-NetworkSwitchFeature -Full

Get-Command -Module NetworkSwitchManager | Out-GridView

#endregion

#region Open Data Protocol

<# Das Open Data Protocol, kurz OData ist ein von Microsoft veröffentlichtes HTTP-basiertes Protokoll
   für den Datenzugriff zwischen kompatiblen Softwaresystemen. Aufbauend auf älteren Protokollen wie
   ODBC und JDBC kann OData u.a. innerhalb von Cloud-Diensten (Azure), MySQL, Java und Rails
   eingebunden werden und ist in der Lage, in der Client-Server-Kommunikation eine einheitliche Semantik
   für den Datenaustausch zur Verfügung zu stellen.
#>


Export-ODataEndpointProxy -Uri 'http://services.odata.org/v3/(S(snyobsk1hhutkb2yulwldgf1))/odata/odata.svc' `
                          -MetadataUri 'http://services.odata.org/v3/(S(snyobsk1hhutkb2yulwldgf1))/odata/odata.svc/$metadata' `
                          -AllowUnsecureConnection `
                          -OutputModule C:\Temp\GeneratedScript.psm1 `
                          -ResourceNameMapping @{Products = 'Merchandise'}

#endregion

#region Optimierte Unterstützung für 'Desired State Configuration' (DSC)

<#
    Weitere Neuerungen in der PowerShell betreffen die mit der
    PowerShell 4.0 eingeführte Technologie Desired State Configuration (DSC).
     
    Hauptsächlich gibt es neue Optionen um festzulegen auf wievielen Computern
    gleichzeitig die Änderungen implementiert werden sollen.
      
    Mit dem Modul 'PowerShellGet' können Sie DSC-Ressourcen in der
    'PowerShell Resource Gallery' nutzen, installieren oder hochladen.
#>


#endregion

#endregion

#region PowerShell Core 6.0

#endregion

# ! # Neue Funktionen in diesem Modul
Get-Command -Module Microsoft.PowerShell.LocalAccounts
Get-Command -Module PowerShellGet
Get-Command -Module PackageManagement 
Get-ComputerInfo # Neu

# ! Besseres Debugging für DSC und PowerShell-Klassen

#endregion

#region PowerShell 7

# BESCHREIBUNG :: PowerShell 7 - Die neue Version :: Windows PowerShell (für Windows) und PowerShell Core (für Windows, MacOS und Linux) wurden in PowerShell 7 zusammengeführt und bilden deren Nachfolger. PowerShell 7 basiert auf und ist kompatibel mit .NET Core 3.1 (LTS). PowerShell 7 ist abwärtskompatibel und kann auch parallel zu Windows PowerShell genutzt werden. PowerShell 7 ist auch für .NET-Entwickler attraktiv, da man in einer einzigen Skriptsprache plattformübergreifend .NET-­Anwendungen schreiben kann. Die Neuerungen und Änderungen der PowerShell 7 beziehen sich auf folgende Bereich: Allgemeine und übergreifende Änderungen, Cmdlet, System-Variablen und Operatoren, PowerShell Verhalten und Handling & Dokumentation. Ich zeige Ihnen in diesem Slot die Neuerungen im Detail mit praktischen Beispiel.

# ! STAND :: PowerShell 7 GA vom 4. März 2020 (Generally Available)

# ! DOWNLOAD :: https://github.com/PowerShell/PowerShell/releases/tag/v7.0.0

# ! What's New in PowerShell 7.0 - https://docs.microsoft.com/en-us/powershell/scripting/whats-new/what-s-new-in-powershell-70

# ! PowerShell-Dokumentation - https://aka.ms/powershell

# ! Release-Verlauf von Modulen und Cmdlets - https://docs.microsoft.com/de-de/powershell/scripting/whats-new/cmdlet-versions?view=powershell-7

#region 1. Welche Betriebssysteme unterstützte, PowerShell 7

# ! Windows 7, 8.1 und 10
# ! Windows Server 2008 R2, 2012, 2012 R2, 2016 und 2019
# ! macOS 10.13+
# ! Red Hat Enterprise Linux (RHEL) / CentOS 7+
# ! Fedora 29+
# ! Debian 9+
# ! Ubuntu 16.04+
# ! openSUSE 15+
# ! Alpine Linux 3.8+

#endregion

#region Kurzbeschreibung

# ! Windows PowerShell (für Windows) und PowerShell Core (für Windows, MacOS und Linux) wurden in PowerShell 7 **zusammengeführt** und bilden deren Nachfolger.

# ! PowerShell 7 basiert und ist **kompatibel mit .NET Core 3.1** (LTS).

# ! PowerShell 7 ist **abwärtskompatibel** und kann auch parallel zu Windows PowerShell produktiv genutzt werden.

# ! PowerShell 7 ist auch für **.NET-Entwickler** attraktiv, da man in einer einzigen Skriptsprache plattformübergreifend .NET-Anwendungen schreiben kann.

# ? Standard-Installationsort der PowerShell 7 in Windows:
& 'C:\Program Files\PowerShell\7\PwSh.exe'

#endregion

#region TODO's nach der Installation

# TODO Module aktualisieren:

Update-Module -Name '*' -Scope 'AllUsers' -AcceptLicense -Force
Update-Module -Name '*' -Scope 'CurrentUser' -AcceptLicense -Force

# TODO Hilfe aktualisieren:

Update-Help -Name '*' -UICulture 'en-US' -Scope 'AllUsers' -Force

#endregion

#region Lektüren und Wissen

# TODO Wichtige neue about_*-Seiten lesen:

# PSReadLine bietet eine verbesserte Bearbeitungsfunktion für Befehlszeilen in der PowerShell-Konsole.
Get-Help -Name "about_PSReadLine" -ShowWindow

# Multiplikatorsuffixe für Ganzzahl und Real
Get-Help -Name "about_Numeric_Literals" -ShowWindow

# Konfigurationsdateien für PowerShell, die Registrierungs-Konfiguration ersetzen.
Get-Help -Name "about_PowerShell_Config" -ShowWindow

# Erläutert die Verwendung des PwSh-Befehlszeilentools.
Get-Help -Name "about_PwSh" -ShowWindow

# Beschreibt die in PowerShell gesammelte Telemetrie und das Deaktivieren.
Get-Help -Name "about_Telemetry" -ShowWindow

# TODO Für Einsteiger:

# Listet die Cmdlets auf, die für die Verwendung mit PowerShell-Anbietern vorgesehen sind.
Get-Help -Name "about_Core_Commands" -ShowWindow

# Beschreibt die Schlüsselwörter in der PowerShell-Skriptsprache.
Get-Help -Name "about_Language_Keywords" -ShowWindow

# Beschreibt das Bearbeiten von Befehlen an der PowerShell-Eingabeaufforderung.
Get-Help -Name "about_Line_Editing" -ShowWindow

# Listet die PowerShell-Operatoren in der Rangfolge auf.
Get-Help -Name "about_Operator_Precedence" -ShowWindow

# Beschreibt, wie PowerShell Befehle analysiert.
Get-Help -Name "about_Parsing" -ShowWindow

# Beschreibt die vollständigen und relativen Pfadnamenformate in PowerShell.
Get-Help -Name "about_Path_Syntax" -ShowWindow

# Beschreibt Regeln für die Verwendung von einfachen und doppelten Anführungszeichen in PowerShell.
Get-Help -Name "about_Quoting_Rules" -ShowWindow

# Listet die reservierten Wörter auf, die nicht als Bezeichner verwendet werden können.
Get-Help -Name "about_Reserved_Words" -ShowWindow

# TODO zum Thema OOP:

# Beschreibt das Schlüsselwort Hidden, mit dem Klassenmitglieder vor den Standardergebnissen für Get-Member ausgeblendet werden.
Get-Help -Name "about_Hidden" -ShowWindow

# TODO zum Thema Unit-Testing-Framework (Pester):

# Pester ist ein Test-Framework für Windows PowerShell.
Get-Help -Name "about_Pester" -ShowWindow

# Bietet Assertion Convenience-Methoden zum Vergleichen von Objekten und zum Auslösen von Testfehlern, wenn die Testerwartungen fehlschlagen.
Get-Help -Name "about_Should" -ShowWindow

# Beschreibt die Befehle BeforeEach und AfterEach, mit denen eine Reihe von Befehlen ausgeführt wird, die Sie vor oder nach jedem It-Block angeben.
Get-Help -Name "about_BeforeEach_AfterEach" -ShowWindow

# Pester bietet eine Reihe von Mock-Funktionen, mit denen sich Abhängigkeiten leicht vortäuschen und das Verhalten überprüfen lassen.
Get-Help -Name "about_Mocking" -ShowWindow

# Ein PSDrive für Datei-Aktivitäten, das auf den Umfang eines einzelnen Beschreibungs- oder Kontextblocks beschränkt ist.
Get-Help -Name "about_TestDrive" -ShowWindow

#endregion

#region Experimentelle Funktionen

# Die Unterstützung für experimentelle Funktionen in PowerShell bietet einen Mechanismus, mit dem experimentelle Funktionen mit vorhandenen stabilen Funktionen koexistieren können.
Get-Help -Name "about_Experimental_Features" -ShowWindow 

# ? Funktionen die sich noch Experimentierstatus befinden ein- / ausschalten:

Get-ExperimentalFeature | Enable-ExperimentalFeature
Get-ExperimentalFeature | Disable-ExperimentalFeature

Get-ExperimentalFeature

# ! Command-Vorschläge bei nicht gefunden Schlüsselwörter (Command not found Suggestion):

# READ Get-Help -Name 'about_Experimental_Feature' -ShowWindow
Enable-ExperimentalFeature -Name 'PSCommandNotFoundSuggestion'
get
# TODO Kann auch in eigenen Module implementiert werden.

#endregion

#region Allgemeine und übergreifende Änderungen in PowerShell 7

# ! Beim starten des PowerShell-7-Host informiert dieser über das Vorhandensein von Updates:

Get-Help -Name "about_Update_Notifications" -ShowWindow

& PwSh.exe

# ! Neue Module-Installationsorte (C:\Program Files\PowerShell\7\Modules):

$env:PSModulePath -split ";"

# ! Windows-PowerShell-Module stehen durch den "Windows Compatibility Wrapper" auch in PowerShell 7 zur Verfügungen. Windows PowerShell 5.1 ist jedoch **zusätzlich nötig**. Wenn das Module-Manifest nicht angibt ob dass Modul mit Core kompatibel ist, wird das Modul in einen Windows PowerShell-Prozess geladen und mittels Remoting in die aktuell PowerShell 7-Sitzung gespiegelt:

# Beschreibt die Windows PowerShell-Kompatibilitätsfunktion für PowerShell 7:
Get-Help -Name "about_Windows_PowerShell_Compatibility" -ShowWindow

Get-Module -ListAvailable -SkipEditionCheck

Import-Module -Name "Microsoft.PowerShell.Archive" -UseWindowsPowerShell

Install-Module -Name "WindowsCompatibility" -Scope "CurrentUser" -AllowClobber -SkipPublisherCheck -Force

Get-Command -Module "WindowsCompatibility"

Get-WinModule -Name "*"

Import-WinModule -Name "Microsoft.PowerShell.LocalAccounts"

Get-LocalUser

# ! Ein neues PS-Laufwerk um benutzerbezogene temporäre Dateien abzulegen:

Get-PSDrive -Name "Temp"
Get-ChildItem -Path "Temp:\"

# ! Invoke-DscResource arbeit jetzt OS-übergreifende (experimental):

Get-ExperimentalFeature -Name "PSDesiredStateConfiguration.InvokeDscResource" | Enable-ExperimentalFeature

# ! PowerShell Remoting-Zugriff über SSH:

# Siehe https://docs.microsoft.com/de-de/powershell/scripting/learn/remoting/ssh-remoting-in-powershell-core?view=powershell-7

# ! Write-Progress: Fortschritts-Balken wird nun in Visual Studio Code angezeigt:

1..100 | ForEach-Object -Process { Write-Progress -Activity "Test-Fortschritt" -PercentComplete $_ ; Start-Sleep -Milliseconds 20 }

#endregion

#region Neue und geänderte Cmdlets in PowerShell 7

# ! Das neue Cmdlet Clear-RecycleBin leert den Papierkorb:

Clear-RecycleBin -Force

# ! Für die Fehler-Analyse/-Auswertung liefert das neue Cmdlet 'Get-Error' wichtige Informationen:

# * Fehler provozieren!
Get-Process -FileVersionInfo

# Der letzte Fehler:
Get-Error 

# Die letzten 2 Fehler:
Get-Error -Newest 2

# oder so:
Get-Process -FileVersionInfo -ErrorAction "SilentlyContinue" -ErrorVariable "gpErrors"
$gpErrors | Get-Error

# ! 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
Show-Command -Name "Update-List" -NoCommonParameter -ErrorPopup
Get-Help -Name "Update-List" -ShowWindow

# ! JSON Schema-Validierung (Test-Json):

$schema = @'
{
  "definitions": {},
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "http://example.com/root.json",
  "type": "object",
  "title": "The Root Schema",
  "required": [
    "name",
    "age"
  ],
  "properties": {
    "name": {
      "$id": "#/properties/name",
      "type": "string",
      "title": "The Name Schema",
      "default": "",
      "examples": [
        "Ashley"
      ],
      "pattern": "^(.*)$"
    },
    "age": {
      "$id": "#/properties/age",
      "type": "integer",
      "title": "The Age Schema",
      "default": 0,
      "examples": [
        25
      ]
    }
  }
}
'@

"{'name': 'Ashley', 'age': '25'}" | Test-Json -Schema $schema

# ! Parallele Verarbeitung mittels ForEach-Object -Parallel ist möglich:

Get-Help -Name "ForEach-Object" -ShowWindow

# ! Langsam !
1..8 | ForEach-Object -Process { "Verarbeite Schritt $_" | Write-Warning ; Start-Sleep -Seconds 1 }

# ? Schnell !
1..8 | ForEach-Object -Parallel { "Verarbeite Schritt $_" | Write-Warning ; Start-Sleep -Seconds 1 } -ThrottleLimit 4

# ! Markdown Umsetzung:

Get-Command -Noun 'Markdown', 'MarkdownOption' -Module 'Microsoft.PowerShell.Utility'

$md = @'
# Überschrift 1
 
## Überschrift 2
 
Markdown ist eine vereinfachte **Auszeichnungssprache**. Ein Ziel von Markdown ist, dass schon die *Ausgangsform* ohne weitere Konvertierung **leicht lesbar** ist.
 
- [ ] Aufgabe 1
- [X] Aufgabe 2
- [ ] Aufgabe 3
 
```powershell
 
Get-Command -Noun 'markdown' -Module 'Microsoft.PowerShell.Utility'
 
 
```
'@
 
$md | ConvertFrom-Markdown -AsVT100EncodedString | Select-Object -ExpandProperty 'VT100EncodedString'
$md | ConvertFrom-Markdown  | Select-Object -ExpandProperty 'Html'
$md | ConvertFrom-Markdown | Show-Markdown -UseBrowser
Get-MarkdownOption

# ! Das Cmdlet Where-Object erhält einen -Not Switch-Parameter:

Get-Service | Where-Object -Not -Property "DependentServices"       

# ! Für die hexadezimale Darstellung von unterschiedlichen Pipeline-Objekten wurde Format-Hex verbessert:

123, "Hallo Würzburg!", (Get-Item "C:\Windows\win.ini") | Format-Hex -Encoding unicode

# ! 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.

# ! Das neue Cmdlet Update-List aktualisiert Listen-Einträge (Add / Remove) von Listen-Objekt-Eigenschaften:

class OsDetails {
    [System.Collections.ArrayList]$ProcessItems
    OsDetails() {
        $this.ProcessItems = New-Object -TypeName "System.Collections.ArrayList"
    }
}

$osd = New-Object -TypeName "OsDetails"
$osd.ProcessItems.AddRange((Get-Process | Select-Object -First 3))
$osd.ProcessItems

$notepad = Start-Process "notepad" -PassThru

$osd | Update-List -Property "ProcessItems" -Add $notepad | Out-Null
$osd.ProcessItems

$osd | Update-List -Property "ProcessItems" -Remove $notepad | Out-Null
$osd.ProcessItems

#endregion

#region Neue und geänderte PowerShell-Variable

# ! Standard-Fehlerausgabe-Menge über $ErrorView bestimmen:

Get-help -Name "ABOUT_PREFERENCE_VARIABLES" -ShowWindow

$ErrorView

# ? Umfassende Fehler-Ausgabe:
$ErrorView = [System.Management.Automation.ErrorView]::NormalView
Get-Item -Path "C:\GibtEsNicht" # * Fehler provozieren!

# ? Fehler-Ausgabe enthält nur eine Kurzfassung (DEFAULT):
$ErrorView = [System.Management.Automation.ErrorView]::ConciseView
Get-Item -Path "C:\GibtEsNicht" # * Fehler provozieren!

# ? Fehler-Ausgabe enthält nur die Kategorie:
$ErrorView = [System.Management.Automation.ErrorView]::CategoryView
Get-Item -Path "C:\GibtEsNicht" # * Fehler provozieren!

# ! Wird der Variable $ErrorActionPreference bzw. dem Parameter -ErrorAction der neue Enum-Wert 'Break' zugewiesen, hält die Ausführung an und es wird in den DEBUG-Modus gewechselt:

$ErrorActionPreference = [System.Management.Automation.ActionPreference]::Break
Get-Process -FileVersionInfo -ErrorAction "Break"

#endregion

#region Neue und geänderte PowerShell-Operatoren

# ! Split-Operator wurde erweitert:

# * ALT: Splittet nur 3 Elemente von Links:
"a b c d e" -split " ",  3

# NEU: Splittet nur 3 Elemente von Rechts:
"a b c d e" -split " ", -3

# ! Ein dreiteiliger Inline-If-Operator (Ternary-Operator (a ? b : c)):

# WENN ? DANN : SONST
  ($PSCulture -ieq "de-DE" ? "Die PS-Sprache steht auf deutsch-Deutschland." : "Die PS-Sprache steht auf $PSCulture.") | Write-Warning

# ! Pipeline-Verkettung-Operatoren && und || (Pipeline chain operators):

# Beschreibt die Verkettung von Pipelines mit && und || Operatoren:
Get-Help -Name "about_Pipeline_Chain_Operators" -ShowWindow

1/0.1 && "Ich werde ausgeführt wenn die vorherige Anweisung ERFOLGREICH war." | Write-Warning

1/0   || "Ich werde ausgeführt wenn die vorherige Anweisung ERFOLGLOS war."   | Write-Warning

# ! NULL-Sammel-Operator ?? (Null-coalescing operator):

Get-Help -Name "about_Operators" -ShowWindow

# In Abhängigkeit von einem NULL-Wert soll eine Fallunterscheidung statt finden, was bist dato wie folgt implementiert werden musste:

$a = $null # bzw. $a = 'Dies ist der Inhalt von $a'
if($null -ne $a) {
    $a | Write-Warning
} 
else {
    '$a ist ohne Inhalt!' | Write-Warning
}

# TODO Dieses Konstrukt lässt sich nun vereinfacht wie folgt implementieren:

$a = $null # bzw. $a = 'Dies ist der Inhalt von $a'
# Sollte $a gleich NULL sein, wird anstelle dessen der String zurückgegeben:
$a ?? '$a ist ohne Inhalt!' | Write-Warning

# * Die NULL-Sammeloperatoren sind rechtsassoziativ d.h. $a ?? $b ?? $c wird wie folgt abgearbeitet:

$a = $null
$b = $null
$c = 3
$a ?? $b ?? $c
# identisch mit:
$a ?? ($b ?? $c)

# ! NULL-Zuweisungs-Operatoren ??=, ?. (Null-conditional operators):

Get-Help -Name "about_Operators" -ShowWindow

# Sollte eine Variable NULL enthalten, soll dieser einen Default-Wert zugewiesen werden, was bist dato wie folgt implementiert werden musste:

$a = $null # bzw. $a = 123
if($null -eq $a) {
    $a = 'Diesen String als Default-Wert setzen, wenn $a gleich NULL ist.'
}
$a | Write-Warning

# TODO Dieses Konstrukt lässt sich nun vereinfacht wie folgt implementieren:

$a = $null # bzw. $a = 123
$a ??= 'Diesen String als Default-Wert setzen, wenn $a gleich NULL ist.'
$a | Write-Warning

# ! NULL-Bedingung-Operator (${a}?.MemberName):

Get-ExperimentalFeature -Name "PSNullConditionalOperators" | Enable-ExperimentalFeature

$t = Get-Process -Name "SvcHost" | Select-Object -First 1
$t.ToString() # Geht!

$t = Get-Process -Name "GibtEsNicht" | Select-Object -First 1
# * ALT: Problematisch, da eine Exception ausgelöst wird ($t = NULL)
$t.ToString()

# NEU: Lösung: Löst keinen Exception aus, wenn $t gleich NULL ist
${t}?.ToString()

#endregion

#region Änderungen im PowerShell-Handling und der Objekt-Dokumentation

# ! Anzeige von Methoden-Signaturen von COM-Objekten:

$excel = New-Object -ComObject "Excel.Application"

# TODO Methode ohne Klammern d.h. unvollständig ausführen um so weitere Details zu erhalten:
$excel.Save

# ! Es gibt eine Autovervollständigung (CTRL + SPACE) für das Zuweisen von Aufzählungs-Werten (Enum) zu Variablen:

$ErrorActionPreference = 'Stop'
# ? ^ An dieser Stelle in der Console CTRL+SPACE drücken.

#endregion

#endregion

#endregion

#region Informationen über den akt. PowerShell-Host ermitteln

$PSVersionTable
$Host
$Host.PrivateData
$Host.Runspace

#endregion

#region Konsolen-Ein-/Ausgabe protokollieren

Start-Transcript -Path 'C:\Temp\PowerShellConsole.log'
Get-Process | Stop-Process -Force -WhatIf
Remove-Item 'c:\' -Recurse -Force -WhatIf
Stop-Transcript
Get-Content -Path 'C:\Temp\PowerShellConsole.log'

#endregion

#region max. Anzeige von Enumerationen (-1 ohne Grenze, Default: 4)

# TODO # Siehe Eigenschaft: Parameters:

$FormatEnumerationLimit # ! Default = 4
Get-Command -Name ForEach-Object | Select-Object -First 1 | Format-List *

$FormatEnumerationLimit = 5
Get-Command -Name ForEach-Object | Select-Object -First 1 | Format-List * 

$FormatEnumerationLimit = -1 # ! Alle werden angezeigt!
Get-Command -Name ForEach-Object | Select-Object -First 1 | Format-List * 

#endregion