Private/Wissen/C_Advance/C07_UserCmdlets.ps1
<#
# Benutzerdefinierte Cmdlets schreiben Eigene Cmdlets entwickeln - **Hashtags** Dynamic Parameter WhatIf Confirm Validation Function - **Version** 2020.6.12 #> # TODO Weiterführende und Nachschlage-Informationen Get-Help about_Comment_Based_Help -ShowWindow # Beschreibung der eigenen Cmdlet-Hilfe für das PS-Hilfesystem. Get-Help about_Functions -ShowWindow # Grundlagen zu benutzerdefinierten Funktion Get-Help about_Functions_Advanced -ShowWindow # Grundlagen zu benutzerdefinierten Cmdlet Get-Help about_Functions_Advanced_Methods -ShowWindow Get-Help about_Functions_Advanced_Parameters -ShowWindow # Beschreibung der eigenen Cmdlet-Parameter u.a. Validierung Get-Help about_Functions_CmdletBindingAttribute -ShowWindow # Beschreibung der eigenen Cmdlet-Parameter bzgl. Pipeline-Verarbeitung Get-Help about_Functions_OutputTypeAttribute -ShowWindow # Beschreibung von Rückgabe-Objekte wie PSCustomObject # ! "Alte Scripte" sollen durch den neuen PowerShell-Ansatz ersetzt werden, # ! d.h. es werden keine "langen" Skripte mehr entwickelt sonder der Inhalt # ! dieser auf viel kleine Cmdlets aufgeteilt. Das hat folgende Vorteile: # ! A) Zum Beispiel wird ein Anmelde-Skript durch Aufruf dieser kleinen Cmdlets # ! übersichtlicher. (=> Lesbarkeit) # ! B) Durch Parametrisierung und die Kombinationsmöglichkeiten von # ! Cmdlets, kann es dann unterschiedliche Anmelde-Skripte gebe. # ! C) Diese Cmdlets können mit anderen Cmdlets # ! per Pipeline kombiniert werden können. (=> Wiederverwendbarkeit) # ! D) Mittels Show-Command/Out-GridView können Cmdlets über eine GUI # ! bedient werden. # ! E) Mittels Pester können Cmdlets automatisch getestet werden. #region C#- vs. PowerShell-Cmdlets # ! Eigene Cmdlets können auf zwei Arten definiert werden: # ! 1. per C# oder VisualBasic.NET-Code über MS VisualStudio => MeineCmdlets.DLL Get-Command -CommandType Cmdlet | Measure-Object # ! 2. per PowerShell-Funktion mit dem Namen VERB-NOUN => MeineCmdlets.ps1 Get-Command -Name *-* -CommandType Function | Measure-Object # ? Cmdlets mittels CLR schreiben Start-Process https://docs.microsoft.com/en-us/powershell/scripting/developer/cmdlet/how-to-write-a-simple-cmdlet?view=powershell-6 #endregion # ! WICHTIG: Diese Cmdlets können erst genutzt werden, wenn sie im PSDrive 'function:' enthalten sind. # ! Dies geschieht z.B. durch das AUSFÜHREN der Funktions-Definition Get-ChildItem -Path Function:\Clear-Host | Format-List -Property Name, ScriptBlock # ! Wird die Session beendet wird die Funktion automatisch gelöscht Remove-Item -Path Function:\Clear-Host -Force #region Lernen von vorhanden Cmdlets anderer Programmierer D: Get-Alias -Name D: Get-Command -Name D: Get-ChildItem -Path Function:\D: | Format-List -Property Name, ScriptBlock Get-ChildItem -Path Function:\ | Where-Object ScriptBlock -Match 'Set-Location \$MyInvocation\.MyCommand\.Name' | Format-List -Property Name, ScriptBlock Get-ChildItem Function:\New-Guid | Select-Object -ExpandProperty ScriptBlock [GUID]::NewGuid() # Ah-ha, das führt das Cmdlet New-Guid aus. # ! ACHTUNG: Passwörter haben im Code nichts verloren!!!!! #endregion #region Herangehensweise eigene Cmdlets schreiben (4. Punkte-System) # ? 1. Das Problem/Lösung statisch lösen Get-Help -Name about_* | Sort-Object -Property Name | Out-GridView -Title "Bitte about-Seiten auswählen (CTRL + Mausklick)" -OutputMode Multiple | Get-Help -ShowWindow # ? 2. Die statische Lösung in eine dynamische (bzgl. Parameter) Lösung umwandeln $Keyword = "function" Get-Help -Name about_*$Keyword* | Sort-Object -Property Name | Out-GridView -Title "Bitte about-Seiten auswählen (CTRL + Mausklick)" -OutputMode Multiple | Get-Help -ShowWindow # ? 3. Aus dynamischen Lösung ein Cmdlet machen # TODO Cmdlet-Grundgerüst kann per GUI zusammen gebaut werden über https://poshgui.com/CmdletBuilder function Get-About { <# .SYNOPSIS about-Seiten über eine GUI benutzen. .DESCRIPTION Die about-Seiten über eine GUI benutzen. .EXAMPLE Get-About Alle about-Seiten werden angezeigt .EXAMPLE Get-About -Keyword remote Alle about-Seiten werden angezeigt die das Schlüsselwort Remote enthalten .INPUTS Nix .OUTPUTS Nix .PARAMETER Keyword Schlüsselwort nach dem die about-Seiten gefiltert werden. #> param ( [string]$Keyword ) Get-Help -Name about_*$Keyword* | Sort-Object -Property Name | Out-GridView -Title "Bitte about-Seiten auswählen (CTRL + Mausklick)" -OutputMode Multiple | Get-Help -ShowWindow } # ? 4. Das neue Cmdlet testen Get-About Get-About -Keyword remote Get-Help -Name Get-About -ShowWindow Show-Command -Name Get-About -NoCommonParameter -ErrorPopup Get-ChildItem -Path Function:\Get-About | Format-List -Property Name, ScriptBlock # ! Selektion der Definition + F8; Selektion des Test-Codes + F8 => NERVT! # ! LÖSUNG: Je Cmdlet eine .ps1-Datei mit nur noch dem Code aus 3. + eine Test-Zeile # ! und mit F5 die Datei ausführen! #endregion #region -WhatIf (Simulation) und -Confirm (Einzelbestätigung) in Cmdlets integrieren function Test-WhatIfConfirm { [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = [System.Management.Automation.ConfirmImpact]::High # High => Risikostufe Gefährlich, Undo unmöglich # Medium => Risikostufe Durchschnittlich, Undo bedingt unmöglich # Low => Risikostufe Ungefährlich, Undo möglich # None => Risikostufe unbekannt )] param() $target = Get-Service -Name Audiosrv $action = [System.ServiceProcess.ServiceControllerStatus]::Stopped $canDo = $PSCmdlet.ShouldProcess($target.Name, $action) if($canDo) { $target | Stop-Service -Force -PassThru } } Test-WhatIfConfirm Test-WhatIfConfirm -Confirm:$false Test-WhatIfConfirm -WhatIf $ConfirmPreference = [System.Management.Automation.ConfirmImpact]::None Test-WhatIfConfirm $WhatIfPreference = $true Test-WhatIfConfirm #endregion #region Autovervollständigung für Parameter enum Richtung { Unbekannt West Nord Ost Süd } function Test-ParameterAutoVervollständigung { param ( # Autovervollständigung per Datentyp [System.Management.Automation.ActionPreference]$ParameterA, # Autovervollständigung per ValidateSet [ValidateSet("Erde", "Mond", "Sonne", "Mars")] [String]$ParameterB, # Autovervollständigung per UserEnum [Richtung]$ParameterC, # Argumenten-Vervollständigung wie ValidateSet nur ohne Einschränkung, d.h. es können auch andere Argumente übergeben werden. [ArgumentCompleter({'Microsoft','Amazon','Google'})] [string] $ParameterD # Autovervollständigung per "Dynamik", s. weiter unten. ) } Test-ParameterAutoVervollständigung Test-ParameterAutoVervollständigung -ParameterA Continue -ParameterB Mond -ParameterC Süden -ParameterC Amazon Show-Command -Name Test-ParameterAutoVervollständigung #endregion #region Proxy-Funktionen $metadata = New-Object -TypeName System.Management.Automation.CommandMetadata -ArgumentList (Get-Command -Name Stop-Process) [System.Management.Automation.ProxyCommand]::Create($metadata) | Set-Clipboard #endregion #region Dynamische Parameter # ! Die Herausforderung besteht darin die dynamischen Parameter programmatisch abzubilden function Test-DynamicParameter { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [ValidateSet('Normal', 'Dynamic')] [string]$Mode ) dynamicparam { $parameters = New-Object -TypeName System.Management.Automation.RuntimeDefinedParameterDictionary if ($Mode -ceq "Dynamic") { # 1. dynamischer Parameter $attributes = New-Object -TypeName System.Collections.ObjectModel.Collection[System.Attribute] $parameterAttribute = New-Object -TypeName System.Management.Automation.ParameterAttribute $parameterAttribute.Mandatory = $true $attributes.Add($parameterAttribute) $parameter = New-Object -TypeName System.Management.Automation.RuntimeDefinedParameter -ArgumentList 'ID', System.Int32, $attributes $parameters.Add('ID', $parameter) # 2. dynamischer Parameter $attributes = New-Object -TypeName System.Collections.ObjectModel.Collection[System.Attribute] $parameterAttribute = New-Object -TypeName System.Management.Automation.ParameterAttribute $parameterAttribute.Mandatory = $false $attributes.Add($parameterAttribute) $vorschlagsliste = 'Erde', 'Mond', 'Sonne', 'Mars' # TODO z.B. aus dem AD, Exchange, Internet generieren $validateSetAttribute = New-Object -TypeName System.Management.Automation.ValidateSetAttribute -ArgumentList ($vorschlagsliste) $attributes.Add($validateSetAttribute) $parameter = New-Object -TypeName System.Management.Automation.RuntimeDefinedParameter -ArgumentList 'Planet', System.String, $attributes $parameters.Add('Planet', $parameter) } return $parameters } begin {} process { Set-Variable -Name Id -Value $PSBoundParameters.Id Set-Variable -Name Planet -Value $PSBoundParameters.Planet "Festgelegt wurde: Plant = $Planet | ID = $ID" } end {} } Test-DynamicParameter -Mode Normal -ID 4711 -Planet Mond Test-DynamicParameter -Mode Dynamic -ID 4711 -Planet Mond function Test-DynamicSoundParameter { [CmdletBinding()] param( ) dynamicparam { # ! ACHTUNG die PowerShell ruft die Auswertung dieses Bereiches automatisch und oft auf daher beachte Performance evtl. Daten Cachen! $player=New-Object -TypeName System.Media.SoundPlayer -ArgumentList C:\Windows\media\tada.wav $player.Play() } } Test-DynamicSoundParameter #endregion #region Beispiele #region BEISPIEL Get-Bios function Get-Bios { Param ( [String[]]$ComputerName = "localhost" ) Get-CimInstance -ClassName Win32_BIOS -ComputerName $ComputerName | ForEach-Object -Process { return [PSCustomObject]@{ PSComputerName = $_.PSComputerName Status = $_.Status Name = $_.Name Caption = $_.Caption SMBiosPresent = $_.SMBiosPresent BIOSVersion = $_.BIOSVersion CurrentLanguage = $_.CurrentLanguage Description = $_.Description Manufacturer = $_.Manufacturer PrimaryBIOS = $_.PrimaryBIOS SMBiosBiosVersion = $_.SMBiosBiosVersion Version = $_.Version } } } #endregion #region BEISPIEL Get-EuroExchange # ! Siehe Modul AKPT #endregion #region BEISPIEL Get-News function Get-News { <# .Synopsis Zeigt RSS-Feeds an. .DESCRIPTION Zeigt ATOM Version 1.0 RRS-Feeds aus dem Internet oder Dateisystem an. .EXAMPLE Get-News -Uri http://rss.golem.de/rss.php?feed=ATOM1.0 Liefert alle RSS-News-Feed von Golem.de. .EXAMPLE Get-News -Uri http://rss.golem.de/rss.php?feed=ATOM1.0 -First 3 .EXAMPLE "http://www.heise.de/newsticker/heise-top-atom.xml", "http://rss.golem.de/rss.php?feed=ATOM1.0", "http://rss.golem.de/rss.php?tp=wirtschaft&feed=ATOM1.0" | Get-News -First 3 .EXAMPLE Get-News -Uri "http://rss.golem.de/rss.php?feed=ATOM1.0" | ft .EXAMPLE Get-News -Uri "http://rss.golem.de/rss.php?feed=ATOM1.0" | where Titel -Like "E*" | ft .EXAMPLE Get-News -Uri "http://rss.golem.de/rss.php?feed=ATOM1.0" | Out-GridView .EXAMPLE Get-News -Uri "http://rss.golem.de/rss.php?feed=ATOM1.0" -First 2 -OpenLinkInBrowser #> Param ( [Parameter( Mandatory = $true, ValueFromPipeLine = $true)] [string] $Uri, [UInt32] $First = [System.UInt32]::MaxValue, [switch] [bool] $OpenLinkInBrowser = $false ) Begin # Zum Beginn 1x { $enUS = New-Object -TypeName System.Globalization.CultureInfo -ArgumentList "en-US" $xmlDokument = New-Object -TypeName System.Xml.XmlDocument } Process # Je Objekt was über die Pip kommt { $FirstTemp = $First $xmlDokument.Load($Uri) foreach ($item in $xmlDokument.feed.entry) { if ($FirstTemp -gt 0) { $FirstTemp-- $link = $item.link.href if($OpenLinkInBrowser) { [System.Diagnostics.Process]::Start($link) continue } $title = $item.title.InnerText $published = [datetime]::Parse($item.published, $enUS) $author = $item.author.name $summery = $item.summary.InnerText $result = @{"Titel"=$title; "StandUTC"=$published; "Autor"=$author; "Link"=$link; "Beschreibung"=$summery} New-Object PSCustomObject -Property $result | Select-Object Titel, StandUTC, Autor, Link, Beschreibung } else { break } } } End # Zum Ende 1x { } } #endregion #region BEISPIEL Get-BigFile function Get-BigFile { <# .SYNOPSIS Zeigt eine Übersicht von großen Dateien und deren Besitzer. .EXAMPLE Get-BigFile -Path C:\ -GE 100MB .EXAMPLE "C:\Users", "C:\Program Files" | Get-BigFile -GE 100MB #> [CmdletBinding( HelpUri = 'http://www.gfu.net/')] [Alias("gbf")] [OutputType([PSCustomObject])] Param ( # Pfad an dem große Dateien gefunden werden sollen [Parameter(ValueFromPipeLine = $true)] [string] $Path = ".", # Eine Datei ist Groß wenn sie größer gleich diesem Wert ist [Parameter(Mandatory = $true)] [UInt32] $GE = 10MB, [switch] [bool] $Recurse = $false ) Process { Get-ChildItem -Path $Path -Recurse:$Recurse -File -Force -ea SilentlyContinue | Where-Object -Property Length -GE -Value $GE | ForEach-Object -Process { [PSCustomObject]@{ Name = $_.Name; Length = $_.Length; Owner = $_ | Get-Acl -ea SilentlyContinue | Select-Object -exp Owner; LastAccessTime = $_.LastAccessTime; FullName = $_.FullName; } } } } New-Alias -Name gbf -Value Get-BigFile -Force #Get-Help Get-BigFile -ShowWindow #Show-Command Get-BigFile #Get-BigFile -Path c:\ -GE 100MB -Recurse #Get-BigFile -GE 100MB #"C:\Users", "C:\Program Files" | Get-BigFile -GE 100MB -Recurse | Out-GridView #endregion #region BEISPIEL Get-OldFile function Get-OldFile { <# .SYNOPSIS Ermittelt alte Dateien. .DESCRIPTION Ermittelt alte Dateien nach Anzahl Tage. .INPUTS .OUTPUTS Liefert ein ein PSObject mit folgenden Eigenschaften..... .EXAMPLE Get-OldFile -Path C:\Windows -OlderThanDays 180 Alle alte Datei aus c:\windows die älter sind als 180 Tage. .EXAMPLE Get-OldFile -Path C:\Windows -OlderThanDays 180 -Recurse Alle alte Datei aus c:\windows und Unterordner die älter sind als 180 Tage. #> param( [Parameter(ParameterSetName = "Days", ValueFromPipeline = $true)] [Parameter(ParameterSetName = "DateTime", ValueFromPipeline = $true)] [ValidateScript({Test-Path $_})] [string]$Path = ".", # Gültige Werte für Tag sind 1 bis 4000 [Parameter(Mandatory = $true, ParameterSetName = "Days")] [ValidateRange(1, 4000)] [UInt32]$OlderThanDays, [Parameter(ParameterSetName = "Days")] [Parameter(ParameterSetName = "DateTime")] [switch] [bool]$Recurse, [Parameter(Mandatory = $true, ParameterSetName = "DateTime")] [ValidateScript({$_ -le (Get-Date)})] [datetime]$OlderThan ) begin { # Initialisierungs-Code $lastAccessTime = $null switch ($psCmdlet.ParameterSetName) { 'Days' {$lastAccessTime = (Get-Date).AddDays($OlderThanDays * -1)} 'DateTime' {$lastAccessTime = $OlderThan} } } process { Get-ChildItem -Path $Path -Recurse:$Recurse -File -ErrorAction SilentlyContinue | Where-Object -Property LastAccessTime -lt $lastAccessTime | ForEach-Object -Process { $now = Get-Date $owner = $_ | Get-Acl | Select-Object -ExpandProperty Owner $result = [ordered]@{ Name = $_.Name; AgeInDays = [Math]::Round(($now - $_.LastAccessTime).TotalDays, 2); Owner = $owner; LastAccessTime = $_.LastAccessTime; FullName = $_.FullName} New-Object PSObject -Property $result } } } #Get-Help Get-OldFile -ShowWindow #Show-Command Get-OldFile Get-OldFile -Path c:\ -Recurse -OlderThanDays 1200 | Out-GridView Get-OldFile -Path c:\ -Recurse -OlderThan "2013-12-31" | Out-GridView # # KOMPONENTENTEST # #Get-OldFiles -Path C:\Windows -OlderThanDays 180 -Recurse #Get-OldFiles -Path C:\Windows -OlderThanDays 180 | Out-GridView #Get-OldFiles -OlderThanDays 180 -Path C:\Windows -Recurse #Get-help Get-OldFiles -ShowWindow #Get-OldFiles -Path C:\Windows -OlderThanDays 180 -OlderThan (Get-Date).AddMonths(-50) #Get-OldFiles -Path C:\Windows -OlderThanDays 180 #Get-OldFiles -Path C:\Windows -OlderThan (Get-Date) #Get-Help Where-Object -Online #"c:\windows", "C:\windows\System32" | Get-OldFiles -OlderThanDays 180 #endregion #region BEISPIEL Get-Product # ! Siehe Modul AKPT #endregion #region BEISPIEL Get-BingPicture # ! Siehe Modul AKPT #endregion # TODO Siehe auch weitere Beispiel in meinem Modul AKPT Install-Module -Name AKPT #endregion #region Übungen <# TODO ÜBUNG A ! VERTIEFUNG: Cmdlet lesen/verstehen ? Lesen Sie das Cmdlet 'Get-Product' (s. Modules\AKPT) und erklären Sie es! #> <# TODO ÜBUNG B ! VERTIEFUNG: Cmdlet lesen/verstehen ? Lesen Sie das Cmdlet 'Get-EuroExchange' (s. Modules\AKPT) und erklären Sie es! #> <# TODO Übung C ? Erstellen Sie ein Cmdlet 'Get-Hello'. ? A) Folgende Ausführungen sollen positive Ergebnisse auslösen: * Get-Hello -Name "Peter" -Culture "DE" # => Hallo Peter! * Get-Hello -Name "Peter" -Culture "US" # => Hello Peter! * Get-Hello -Name "Peter" -Culture "SP" # => Ola Peter! * Get-Hello -Name "Peter" # Default: DE d.h. => Hallo Peter! * "Peter", "Inge" | Get-Hello -Culture "SP" # => Ola Peter! Ola Inge! ? B) Folgende Ausführungen sollen auf einen Fehler laufen: * Get-Hello -Culture "SP" # ! => Fehler! * Get-Hello # ! => Fehler! * Get-Hello -Name "Peter" -Culture "XX" # ! Fehler! * Get-Hello -Name "" # ! => Fehler * Get-Hello -Name "Peter", "Inge" # ! => Fehler ! TIPPS Siehe Statisch Lösung => Dynamische Lösung => Cmdlet (s.u.a. Grundgerüst Get-EuroExchange.ps1) #> <# TODO ÜBUNG D ! VERTIEFUNG: Cmdlet erstellen ? Erstellen Sie das Cmdlet 'Add-DateTime' dessen Aufgabe es ist ? von einem DateTime-Objekt (z.B. Get-Date) einen Anzahl an Zahlen ? zu addieren für Jahr, Monat und Tag. ? Folgende Syntax soll implementiert werden: ? Add-DateTime -BaseDateTime (Get-Date) -Years 1 ? Add-DateTime -BaseDateTime (Get-Date) -Months 2 ? Add-DateTime -BaseDateTime (Get-Date) -Days 3 ? Add-DateTime -BaseDateTime (Get-Date) -Years 1 -Months 2 -Days 3 ? Add-DateTime -BaseDateTime (Get-Date) -Years 1 -Days 3 ? Get-Help -Name Add-DateTime -ShowWindow # ? Hilfe-Information i.O. ? Show-Command -Name Add-DateTime -ErrorPopup -NoCommonParameter # ? Bedienbar TIPPS: (Get-Date).AddYears(1); (Get-Date).Month(2); (Get-Date).Day(3) #> <# TODO ÜBUNG E ! VERTIEFUNG: Cmdlet erstellen ? Erstellen Sie das Cmdlet 'New-LocalUserFromCsv' dessen Aufgabe es ist ? neue lokale Windows-Benutzer über eine .CSV-Datei zu erstellen. ? Als Basis dient das Beispiel am Ende der 'B04_Pipelining.ps1'-Datei. ? Folgende Syntax soll implementiert werden: New-LocalUserFromCsv -CsvFile C:\temp\NewUsers.csv -WhatIf # Simuliert das erstellen => [switch]$WhatIf New-LocalUserFromCsv -CsvFile C:\temp\NewUsers.csv # Erstellt die Benutzer New-LocalUserFromCsv # ! FEHLER da der Parameter 'CsvDatei' obligatorisch sein muss Get-Help -Name New-LocalUserFromCsv -ShowWindow # ? Hilfe-Information i.O. Show-Command -Name New-LocalUserFromCsv -ErrorPopup -NoCommonParameter # ? Bedienbar #> <# TODO ÜBUNG F ! VERTIEFUNG: Cmdlet erstellen ? Erstellen Sie das Cmdlet 'Get-EmptyDirectory' dessen Aufgabe es ist ? leere Ordner in Form von DirectoryInfo-Objekte zurückzugeben. ? Folgende Syntax soll implementiert werden: Get-EmptyDirectory -Path c:\temp Get-EmptyDirectory # Aktueller Ordner Get-EmptyDirectory -Path c:\temp -Recurse Get-EmptyDirectory -Path Z:\DiesenOrdnerGibEsNicht # FEHLER ausgeben da der Ordner nicht vorhanden ist! Get-Help -Name Get-EmptyDirectory -ShowWindow # Hilfe-Information i.O.? Show-Command -Name Get-EmptyDirectory -ErrorPopup -NoCommonParameter # Bedienbar? #> <# TODO Übung G (about-Hilfe) ? Des öfteren vergessen Benutzer ihr Passwort. Daher muss der Administrator das Passwort zurücksetzen. Hierbei bekommt der Benutzer ein Initial-Passwort das er bei der nächsten Anmelden ändern muss. Um diesen Prozess zu vereinfachen erstellen SIE ein Cmdlet ** Reset-UserPassword** das wie folgt parametrisiert werden kann: Reset-UserPassword -Username pLustig ? WICHTIG: Der Output des Cmdlets enthält das zufällig generierte Passwort. ! TIPPS: Get-LocalUser ; Where-Object ; Set-LocalUser ; Get-Random ; New-LocalUser ; WIN+X => Computerverwaltung #> <# TODO ÜBUNG H ! VERTIEFUNG: Cmdlet erstellen ? Erstellen Sie das Cmdlet 'Reset-LocalUserPassword' dessen Aufgabe es ist ? das Passwort eines vorhanden Benutzers zur auf ein Initialpasswort zurückzusetzen ? was der Benutzer nur einmal verwenden kann um ein neues Passwort zu vergeben. ? Folgende Syntax soll implementiert werden: ? 1. Reset-LocalUserPassword -Name user1 -InitializePhrase P@ssw0rd ? 2. Reset-LocalUserPassword -Name user1 # ! Validieren, da der Parameter -InitializePhrase ? 3. Reset-LocalUserPassword -InitializePhrase P@ssw0rd # ! Validieren, da der Parameter -Name ? 4. Reset-LocalUserPassword -Name "" -InitializePhrase P@ssw0rd # ! Validieren, da min. 1 Zeichen nötig ist ? 5. Reset-LocalUserPassword -Name 123456789012345678901 -InitializePhrase P@ssw0rd # ! Validieren, da max. 20 Zeichen erlaubt sind ? 6. "user1", "user2" | Reset-LocalUserPassword -InitializePhrase P@ssw0rd ? 7. "user1,123", "user2,098" | ConvertFrom-Csv -Header Name, InitializePhrase | Reset-LocalUserPassword ? 8. Get-Help -Name Reset-LocalUserPassword -ShowWindow # ! Hilfe-Information i. O. ? ? 9. Show-Command -Name Reset-LocalUserPassword -ErrorPopup -NoCommonParameter # ! Bedienbar ? TIPPS: Get-Help -Name about_Comment_Based_Help -ShowWindow # * bzgl. Cmdlet eigen Hilfeinformationen Get-Help -Name about_Functions_Advanced_Parameters -ShowWindow # * bzgl. Mandatory, ValidateLength Get-Help -Name about_Functions_CmdletBindingAttribute -ShowWindow # * bzgl. ValueFromPipeline, ValueFromPipelineByPropertyName Get-Help -Name about_Functions_OutputTypeAttribute -ShowWindow # * bzgl. Output Get-Help -Name Set-LocalUser -Online # * bzgl. Passort zurücksetzen #> #region # ! MUSTERLÖSUNGEN <# * zu Übung E -----BEGIN CMS----- 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 K7QygbY0YNbMw7PP8deegNU+gebq4kM= -----END CMS----- #> <# * zu Übung F -----BEGIN CMS----- MIIFzAYJKoZIhvcNAQcDoIIFvTCCBbkCAQAxggKAMIICfAIBADBkMFAxJTAjBgkqhkiG9w0BCQEW FnMubWFuQGtyeXB0b24udW5pdmVyc2UxJzAlBgNVBAMMHl9BS1BUIFN1cGVybWFuIChEb2N0b3Ig Uy4gTWFuKQIQV5/kBauf95JOy7DMCzlZwzANBgkqhkiG9w0BAQcwAASCAgBWCmROtvB1IK5esmsn ZiWvhN9a3VH/k1Feeq2XEBCa7D6Z0Ji7osKE+0tTZ8Rn1UJciVahyvBHZ7rTEPy+qWsyHFUSjYfK CvxFADCvcFSP3/lqXveIN3UGyrVxvwQXXoV+YzKF3Pr1ULH81opcQViw3qYkhKGFMgv9RJ15kIlx LAR9wy7ybhvUy2+KBJKO/snxd7FBe6WGRAYSQGDncbHKA1VnJWhI9nE8/YVFNy/Pm40wkJftpDcB CbFK1G5TV2zEULLMbNViqUzfIwrhCBa+jDVIPU84EWggaF0f6HAoBKpUe0MvRN+4uhAOifn2vX2p HftFnrOsmT45unAg2Nxr1Pi737EQX8AxxlWfVUXRGM4UA5ZhwF9HyNfiKeazyceetJvQqzuFabp4 PmNNkUtSxM93rz+9nquu3amrSed4+mCd9RosieKmFGLnTnbwPP63yHMZMcg/rG0fYc/xy5Z9/9Az 8LLd5kTAH5nTAypFvBP9mgc3msJDLdZTcXdAGfmqd02uGEnMypoQfNu9Odb/On1ACnZF4EoHVWnh L/jhlyXdRbiUt5OEnO6rqpo6QpRxv15bk2k0Ts8+mtwC6vUHTVQfR9QYAJ56Jjspanw+XkS0tkHb 6BpLa9m8zOUoy0pap6oySYBTyvNj3GGtvwAFXTy5W5+V1LU3V+TNSXk6+TCCAy4GCSqGSIb3DQEH ATAdBglghkgBZQMEASoEEChxUtg4iy38GVzyCXGd51yAggMA4hrr/aZ0qChaiJEHx4GwQ8VlxeML nvrgA9/UpGZKY0050pX0GhXHaX5cLIm+tmKnIPNltUkf3lyt4FIXlNjvxxqZVfgaoseRs9ZLjfdu tzwg2KgFldviLbZl3iFaAZpK4BuL0NzU00PveusDjEctCQjllK0gUDXWVen+1Vhhk4J2vSn5VIYg qRJlTNd+OZW+QEPPbKe4zq0qDuF4sAivvuK9RfyjWHD+RvCrKo0QPeh08uT8tae0Ka65FxgYaSyv 8WeF/3IbZK+uSjuMrglF/y/wBlzRN7bOFYDmvh6sDTE1++NHFxZsuglQqFX4EpFr5+CLvMHJ320o 43K+SiwgcAuu1ECa2sbWFN+F50dAWgTVUHCKa0kvWrTyN60TkihNVlLn+pW+rI8H5HgJZFir9eQd GKPxAu2YhykeniuSFF6GOR1iMyG/q5hItoaZCqt072ePVhk7oSbdRYPFXJ+63dIHvQpxHzXFviQc j5BVw7I9SpqQLa2zzPB7cBl3+xi2Y+awt7KQ13ZNWfXja1ZPOM1CeizHyGs9hA/RLsPbOCP/AaWB Hu8oC1h1B+J8P3G55IqA9rA0+w0DjP1uHWVuMY8qXo4P4H/BbbU5VyVhI9tA3PThLVfXdgLIHsZz WUbcSrZkX9aByT+yk3CQvmPOeFj9KjqPplqJb5cQFlZrKimFg3mNsv5lNsOXEt8fHQ8X6hn1aKOQ ZFrkfRt3MxPq+ShVCRhpUM0RWnvTviGOTIovgxKq4a9RIonO8tGSyLFTW/Dy/+lfTou1F23ZgVHt sX6p0W3jNi07HSRwVUEWD+1qfAbYnNoeMFAZtkFO1ccQpSN9ggvziiZMsYk91RDi9lFuuAxiMcZ3 3VIiX9A2GiCIPCw7hpLM04hPulwY+dj1QAXbmu0I3uL/xsNGCMn2W/wQGFz4+gPcu9q590DjsDOd eoxYI5a/Y3DbQqxplt8vSxe8/zTcvu63PQ+ARlfirdxP6/yyzeoUwDxADpRW//W/iWlbp11bcHJm /p7i+Lnu -----END CMS----- #> <# * zu Übung G -----BEGIN CMS----- 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 -----END CMS----- #> <# * zu Übung H -----BEGIN CMS----- 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 -----END CMS----- #> #endregion #endregion |