Private/Wissen/B_Basic/B62_Eingabe.ps1

<#
 
# (Benutzer-)-eingabe
 
Daten vom Benutzer oder Fremdsysteme erhalten u.a. per (G)UI.
 
- **Hashtags** UI Read-Host Out-GridView Show-Command PromptForChoice MessageBox WinForm WPF Excel
 
- **Version** 2020.05.14
 
#>


#region Read-Host

# ? Benutzereingabe über die Console empfangen:
[datetime]$BenutzereingabeA = Read-Host -Prompt 'Bitte Datum eingeben (yyyy-MM-dd)'
$BenutzereingabeA | Get-Member
$BenutzereingabeA = 'Dieser Text ist kein DateTime-Text!'

$BenutzereingabeB = [datetime](Read-Host -Prompt 'Bitte Datum eingeben (yyyy-MM-dd)')
$BenutzereingabeB | Get-Member
$BenutzereingabeB = 'Dieser Text ist kein DateTime-Text!'

$SecurePassword = Read-Host -Prompt 'Bitte Passwort eingeben' -AsSecureString
$SecurePassword

# ! ACHTUNG - Dieses Rückgabe-Object ist immer ein String bzw. en SecureString

#endregion

#region Read-Window

Import-Module -Name '.\AKPT'
Read-Window -Title 'Alte Dateien finden' -Message 'Alte Dateien sind älter als?' -Default '01.01.2010'

#endregion

#region Out-GridView

# ? Anzuzeigende about_*-Seite auswählen:

Get-Help -Name 'about_*' | Out-GridView -OutputMode 'Multiple' | Get-Help -ShowWindow

# ? Wechselkurs per Get-EuroExchange als GUI abfragen:

Import-Module -Name '.\AKPT'

# per Console:

Get-EuroExchange -ListCurrency
Get-EuroExchange -Currency USD

# per Out-GridView:

Get-EuroExchange -ListCurrency | Out-GridView -OutputMode 'Multiple' | Get-EuroExchange | Out-GridView

# ? Out-GridView als InputBox verwenden:

$antwort = 'JA (Dateien archivieren)', 'NEIN (Dateien am Ort belassen)' | ConvertFrom-Csv -Header 'DateiVerfahren' | Out-GridView -OutputMode 'Single'
$antwort.DateiVerfahren.StartsWith('JA')

#endregion

#region Console-GUI (Nur PowerShell Core >= 6 und PowerShell >= 7)

Install-Module -Name 'Microsoft.PowerShell.ConsoleGuiTools' -Scope 'CurrentUser' -Verbose
Import-Module -Name 'Microsoft.PowerShell.ConsoleGuiTools' -Verbose
Get-Command -Module 'Microsoft.PowerShell.ConsoleGuiTools'
Get-Process | Out-ConsoleGridView -OutputMode 'Multiple' | Stop-Process -WhatIf

#endregion

#region Show-Command

Import-Module -Name '.\AKPT'

# per Console:

Get-EuroExchange -Currency USD -Euros 100

# per Show-Command:

Show-Command -Name 'Get-EuroExchange' -NoCommonParameter -ErrorPopup | Out-GridView
Show-Command -Name 'Test-NetConnection' -NoCommonParameter -ErrorPopup | Out-GridView

# TIPP - Durch das erstellen eigener Firmen-Cmdlets die und einem entsprechendem Firmen-Module kann so eine mächtige Tool-Box z.B. für den HelpDesk entstehen:

Show-Command -NoCommonParameter -ErrorPopup

function Get-About {
    param ($Keyword)
    Get-Help -Name "about_*$Keyword*" | Out-GridView -OutputMode Multiple | Get-Help -ShowWindow
}
Show-Command -Name 'Get-About' -ErrorPopup -NoCommonParameter

#endregion

#region PromptForChoice

using namespace System.Management.Automation.Host

$titel      = 'Aktion wählen'
$nachricht  = 'Wie lautet Ihre Entscheidung?'
$ja         = [ChoiceDescription]::new('&Ja'        , 'Hilfetext zu JA')
$nein       = [ChoiceDescription]::new('&Nein'      , 'Hilfetext zu NEIN')
$vielleicht = [ChoiceDescription]::new('&Vielleicht', 'Hilfetext zu VIELLEICHT')
$optionen   = [ChoiceDescription[]]($ja, $nein, $vielleicht)
$ergebnis   = $host.UI.PromptForChoice($titel, $nachricht, $optionen, 1)
switch ($ergebnis)
{
    0 {'Die Auswahl ist JA'}
    1 {'Die Auswahl ist NEIN'}
    2 {'Die Auswahl ist VIELLEICHT'}
}

#endregion

# ! Einfache grafische Benutzeroberflächen (GUI) sind mit der PowerShell und 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 MessageBox (.NET Framework)

# ? Eine einfach Message-Box:
using namespace System.Windows.Forms # ! Namespace bekannt machen - Sollte später in der ersten Zeile eines Scripts stehen
[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | Out-Null # ! DLL-Datei wird geladen
[MessageBox]::Show('Hallo Köln!')

# ? Eine ausführliche Message-Box:
using namespace System.Windows.Forms
[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | Out-Null
$title         = "Dateien archivieren"
$message       = "Alte Dateien archivieren? (Werden am Ursprungsort gelöscht auf ... kopiert)"
$buttons       = [MessageBoxButtons]::YesNo
$icon          = [MessageBoxIcon]::Question
$defaultButton = [MessageBoxDefaultButton]::Button1
$antwort       = [MessageBox]::Show($message, $title, $buttons, $icon, $defaultButton)
if($antwort -eq [DialogResult]::Yes) {
    "OK, die Dateien werden archiviert..."
}

#endregion

#region Common Dialogs (.NET Framework)

# ! Open File Dialog:

using namespace System.Windows.Forms
[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | Out-Null

$ofd                  = New-Object -TypeName "OpenFileDialog"
$ofd.Filter           = "PowerShell-Skripten (*.ps1)|*.ps1|Text-Dateien (*.txt)|*.txt|Alle Dateien (*.*)|*.*"
$ofd.InitialDirectory = "C:\Temp"
$dialogResult         = $ofd.ShowDialog()
if ($dialogResult -eq [DialogResult]::OK) {
    "Der Benutzer hat die Datei '$($ofd.Filename)' ausgewählt."
}

# ! FolderBrowserDialog:

using namespace System.Windows.Forms
[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | Out-Null

$fbd                     = New-Object -TypeName "FolderBrowserDialog"
$fbd.Description         = "Bitte Ordner für das Archivieren auswählen"
$fbd.RootFolder          = [Environment+SpecialFolder]::Desktop
$fbd.ShowNewFolderButton = $true
$dialogResult            = $fbd.ShowDialog()
if ($dialogResult -eq [DialogResult]::OK) {
    "Der Benutzer hat den Ordner '$($fbd.SelectedPath)' ausgewählt."
}

# TODO s.a. SaveAsDialog

#endregion

#region .NET Framework WinForms 'Euro Rechner'

# TODO WYSIWYG-Editor für ein WinForm-Grundgerüst => https://poshgui.com/Editor

using namespace System.Windows.Forms

Add-Type -AssemblyName "System.Windows.Forms"

$url = "https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml"
$xml = [xml](Invoke-WebRequest -Uri $url | Select-Object -ExpandProperty "Content")
$cubes = $xml.Envelope.Cube.Cube.Cube
$currencys = $cubes | Sort-Object -Property "currency" | Select-Object -ExpandProperty "currency"

function EuroRateRechnen() {
    try {
        $aktWährung    = $währungComboBox.SelectedItem
        [decimal]$rate = $cubes | Where-Object "currency" -eq $aktWährung | Select-Object -ExpandProperty "rate"
        $euro          = $euroTextBox.Text
        $ergebnis      = $rate * $euro
    }
    catch {
        $rate     = 0
        $ergebnis = 0
    }
    $eregbnisTextBox.Text = $ergebnis
    $rateTextBox.Text     = $rate
}

$währungLabel        = New-Object -TypeName "Label"
$währungLabel.Text   = "&Währung:"
$währungLabel.Top    = 15
$währungLabel.Left   = 15
$währungLabel.Height = 15

$währungComboBox                    = New-Object -TypeName "ComboBox"
$währungComboBox.Top                = $währungLabel.Top + $währungLabel.Height
$währungComboBox.Left               = 15
$währungComboBox.AutoCompleteSource = [AutoCompleteSource]::ListItems
$währungComboBox.AutoCompleteMode   = [AutoCompleteMode]::SuggestAppend
$währungComboBox.Items.AddRange($currencys)
$währungComboBox.Add_TextChanged({EuroRateRechnen})

$rateLabel        = New-Object -TypeName "Label"
$rateLabel.Text   = "&Rate:"
$rateLabel.Top    = $währungComboBox.Top + $währungComboBox.Height + 10
$rateLabel.Left   = 15
$rateLabel.Height = 15

$rateTextBox           = New-Object -TypeName "TextBox"
$rateTextBox.TextAlign = [HorizontalAlignment]::Right
$rateTextBox.ReadOnly  = $true
$rateTextBox.Top       = $rateLabel.Top + $rateLabel.Height
$rateTextBox.Left      = 15
$rateTextBox.Text      = "0"

$euroLabel        = New-Object -TypeName "Label"
$euroLabel.Text   = "&Euro(s):"
$euroLabel.Top    = $rateTextBox.Top + $rateTextBox.Height + 10
$euroLabel.Left   = 15
$euroLabel.Height = 15

$euroTextBox           = New-Object -TypeName "TextBox"
$euroTextBox.TextAlign = [HorizontalAlignment]::Right
$euroTextBox.Top       = $euroLabel.Top + $euroLabel.Height
$euroTextBox.Left      = 15
$euroTextBox.Add_TextChanged({
    EuroRateRechnen
})

$ergebnisLabel        = New-Object -TypeName "Label"
$ergebnisLabel.Text   = "&Ergebnis:"
$ergebnisLabel.Top    = $euroTextBox.Top + $euroTextBox.Height + 10
$ergebnisLabel.Left   = 15
$ergebnisLabel.Height = 15

$eregbnisTextBox           = New-Object -TypeName "TextBox"
$eregbnisTextBox.TextAlign = [HorizontalAlignment]::Right
$eregbnisTextBox.ReadOnly  = $true
$eregbnisTextBox.Top       = $ergebnisLabel.Top + $ergebnisLabel.Height
$eregbnisTextBox.Left      = 15

$HauptForm                 = New-Object -TypeName "Form"
$HauptForm.Text            = "€ FX V10"
$HauptForm.StartPosition   = [FormStartPosition]::CenterScreen
$HauptForm.Height          = 240
$HauptForm.Width           = 165
$HauptForm.FormBorderStyle = [FormBorderStyle]::FixedToolWindow
$HauptForm.TopMost         = $true
$HauptForm.Controls.AddRange(
    @(
        $währungLabel
        $währungComboBox
        $rateLabel
        $rateTextBox
        $euroLabel
        $euroTextBox
        $ergebnisLabel
        $eregbnisTextBox
    )
)

$währungComboBox.SelectedIndex = 0
$euroTextBox.Text = "1"
$HauptForm.ShowDialog()

#endregion

#region .NET Framework WPF 'Euro Rechner'

# Betr. Namespace bekannt machen; MUSS IN DATEIKOPF
using namespace System.PresentationFramework
using namespace System.Windows.Markup
using namespace System.Xml

Add-Type -AssemblyName PresentationFramework

$url = "https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml"
$xml = [xml](Invoke-WebRequest -Uri $url | Select-Object -exp "Content")
$cubes = $xml.Envelope.Cube.Cube.Cube
$currencys = $cubes | Sort-Object "currency" | Select-Object -exp "currency"

function EuroRateRechnen() {
    try {
        $aktWährung    = $WährungenCtrl.SelectedItem
        [decimal]$rate = $cubes | Where-Object -Property "currency" -EQ -Value $aktWährung | Select-Object -ExpandProperty "rate"
        $euro          = $eurosCtrl.Text
        $ergebnis      = $rate * $euro
    }
    catch {
        $rate     = 0
        $ergebnis = 0
    }
    $RateCtrl.Text     = "{0:#,##0.0000} {1}" -f $rate    , $WährungenCtrl.SelectedItem
    $ErgebnisCtrl.Text = "{0:#,##0.0000} {1}" -f $ergebnis, $WährungenCtrl.SelectedItem
}

[XML]$xaml = @"
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="€CALC" Width="220" Height="280" WindowStartupLocation="CenterScreen">
    <Grid Margin="20">
        <StackPanel>
            <Label Margin="-4 0 0 -2">Währungssymbol</Label>
            <ComboBox x:Name="Währungen" />
            <Label Margin="-4 8 0 -2">Rate</Label>
            <TextBox x:Name="Rate" IsReadOnly="True" TextAlignment="Right" />
            <Label Margin="-4 8 0 -2">€ (Euros)</Label>
            <TextBox x:Name="Euros" TextAlignment="Right" />
            <Label Margin="-4 8 0 -2">Ergebnis</Label>
            <TextBox x:Name="Ergebnis" IsReadOnly="True" TextAlignment="Right" FontWeight="Bold" />
        </StackPanel>
    </Grid>
</Window>
"@


$reader = New-Object -TypeName "XmlNodeReader" -ArgumentList $xaml
$window = [XamlReader]::Load($Reader)

$WährungenCtrl = $window.FindName('Währungen')
$RateCtrl      = $window.FindName('Rate')
$EurosCtrl     = $window.FindName('Euros')
$ErgebnisCtrl  = $window.FindName('Ergebnis')

$currencys | ForEach-Object -Process { $WährungenCtrl.Items.Add($_) | Out-Null }
$WährungenCtrl.Add_SelectionChanged({ EuroRateRechnen })
$WährungenCtrl.SelectedIndex = 0

$EurosCtrl.Add_TextChanged({ EuroRateRechnen })
$EurosCtrl.Text = "1"

$window.ShowDialog()


#endregion

# TODO QUIZ - https://forms.office.com/Pages/ResponsePage.aspx?id=DQSIkWdsW0yxEjajBLZtrQAAAAAAAAAAAAa__Yp1xwFURDdOTlFVMTJBODc1TUYxSjdWOFVDWDREWS4u