From 5db14dc60e5471fbf157216fc226495f28752a79 Mon Sep 17 00:00:00 2001 From: Roger Rutishauser Date: Mon, 14 Oct 2024 22:37:09 +0200 Subject: [PATCH] powershell --- powershell/README.md | 691 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 691 insertions(+) create mode 100644 powershell/README.md diff --git a/powershell/README.md b/powershell/README.md new file mode 100644 index 0000000..0c9b2ca --- /dev/null +++ b/powershell/README.md @@ -0,0 +1,691 @@ +--- +gitea: none +include_toc: true +--- +# PowerShell + +## Installation Ubuntu + +https://learn.microsoft.com/en-us/powershell/scripting/install/install-ubuntu?view=powershell-7.4 + +## Einführung + +### get version + +``` +Get-Host | Select-Object Version +``` + +### Objekte mit Properties und Methoden + +Alle Cmdlets (Commandlets) sind Objekte. Da die PowerShell auf dem .NET Framework basiert, arbeitet sie durchgehend mit Objekten. Jedes Resultat eines ausgeführten Cmdlets ist ein Objekt, also eine Instanz einer .NET-Klasse oder einer .NET-Collection. Somit kann mit der bekannten Punktnotation auf Members des Objekts, wie Properties oder Methoden, zugegriffen werden. + +Gibt das Datum in voller Länge aus. Es ist ein Objekt: + +``` +Get-Date +``` + +Zeigt alle Properties und Methoden des Objekts an: + +``` +Get-Date | Get-Member +``` + +Zugriff auf Property Year: + +``` +(Get-Date).Year +``` + +Zugriff auf Methode ToLongTimeString() + +``` +(Get-Date).ToLongTimeString() +``` + +### Kommentare + +``` +# einzeilig + +<# ein +block #> +``` + +### PS Special-Characters + +[Alle Special-Charakter von Powershell auf einen Blick](http://www.neolisk.com/techblog/powershell-specialcharactersandtokens) + +## PowerShell-Provider + +### Auflisten aller Provider, wie Registry, Umgebungsvariablen, Variablen, Funktionen etc. + +``` +Get-PSProvider + + +Name Capabilities Drives +---- ------------ ------ +Registry ShouldProcess, Transactions {HKLM, HKCU} +Alias ShouldProcess {Alias} +Environment ShouldProcess {Env} +FileSystem Filter, ShouldProcess, Credentials {C, H, J, K...} +Function ShouldProcess {Function} +Variable ShouldProcess {Variable} +Certificate ShouldProcess {Cert} +WSMan Credentials {WSMan} +``` + +Sie werden wie Drives verwendet. Man kann z.B. wechseln mit `cd Env: # immer mit Doppelpunkt` + +## Datentypen + +Datentypen müssen nicht zwingend angegeben werden, können aber: + +``` +[Array] Array +[Bool] Wert ist TRUE oder FALSE +[DateTime] Datum und Zeit +[Guid] Global eindeutige 32-Byte ID +[HashTable] Hash-Tabelle, Sammlung von Schlüssel-Wert-Paaren +[Int32], [Int] 32-bit Integer +[PsObject] PowerShell-Objekt +[Regex] Regular expression +[ScriptBlock] PowerShell script block +[Single], [Float] Fließkommazahlen +[String] Zeichenkette +[Switch] PowerShell Switch-Parameter +[TimeSpan] Zeitintervall +[XmlDocument] XML-Dokument +``` + +### Datentyp ermitteln + +``` +$t = "bla"; $t.getType() +``` + +## Variablen und Arrays + +### Variable + +Variablen beginnen mit Dollar `$` + +#### Zuweisung mit `=` + +``` +$files = Get-ChildItem c:\xampp\htdocs -Recurse | Sort-Object Length -Descending | Select-Object Fullname, Length -First 5 +``` + +#### $() + +Anweisung in () werden zuerst ausgeführt. + +``` +$name = "Kevin"; "Hello, $name, there are $($name.length) characters in your name" +``` + +#### $_ + +THIS, typischerweise in einer foreach Schleife + +#### ${} + +Declare or use a variable with non-standard characters in it + +``` +${,&} = 5 +``` + +### Arrays + +Siehe auch [hier](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_arrays?view=powershell-6) + +#### leeres Array erstellen + +``` +$t = @() +``` + +#### Werte an Array zuweisen + +``` +# vermischte Datentypen: +$t = "a","b",22 + +# Alternativ ("richtig"): +$t = @("a","b",22) + +# mit Typenbegrenzung: +[Int[]]$t=2,1 +``` + +Bei Strings wird ohne Angabe des Datentyps ein Object gemacht. Siehe `$variable.getType()` + +#### Array erweitern + +``` +$t += 3 +``` + +#### Länge eines Arrays + +``` +$t.Length +``` + +#### 2 Arrays zusammenführen + +``` +$u = "a","b","c"; $u2 = "d","e"; $u += $u2 +``` + +#### Element in Array über Index ansprechen + +``` +$t[0] +$t[0,3,5] +$t[1..3] +``` + +#### Array Element finden + +``` +$a = "aaa","bbb","ccc","ddd" +$a -contains "aaa" # liefert TRUE. -ccontains berücksichtigt Gross-/Kleinschreibung + +# oder + +$a -like "aa*" # gibt Wert zurück (kein Boolean wie oben) + +# oder + +$a.Where{$_ -like "bbb"} +# siehe Where Parameter wie skipUntil oder last. +``` + +#### Array Elemente sortieren + +``` +$t | sort +``` + +#### Array Elemente löschen + +Möchte man einzelne Elemente entfernen, dann muss man den Umweg über das Filtern und Neuzuweisen gehen: + +``` +$a = $a | where {$_ -ne "aaa"} +``` + +#### Array löschen + +``` +$t = $null +``` + +#### Array ausgeben + +``` +$a[0] -join ',' +#oder +$array -join '|' +``` + +## Ausgabe + +`echo` und `Write-Output` ist das selbe. Kann für Weiterverarbeitung verwendet werden. `Write-Host` nur für Ausgabe in Console. + +### Vorbereitung für dieses Tutorial + +``` +$files = Get-ChildItem c:\xampp\htdocs -Recurse | Sort-Object Length -Descending | Select-Object Fullname, Length, CreationTime -First 5 +$files2 = Get-ChildItem c:\xampp\htdocs -Recurse | Sort-Object Length -Descending | Select-Object -First 25 +``` + +### Txt Datei auslesen + +``` +Get-Content -Path C:\Test\ServerNames.txt +# UTF-8 encodiert: +Get-Content -Encoding UTF8 -Path C:\Test\ServerNames.txt +``` + +### Ausgabe in TXT speichern + +``` +Write-Output "hallÖ" | Out-File c:\Roger\hallo.txt -Encoding UTF8 + +# oder einfacher: +"hallÖ" > C:\Roger\hallo.txt +``` + +### Ausgabe als CSV speichern + +``` +$files | Export-Csv c:\Roger\files.csv +``` + +### Ausgabe als JSON speichern + +``` +$files | ConvertTo-Json | Out-File c:\Roger\files.json +``` + +### Ausgabe als HTML speichern + +``` +$files | ConvertTo-Html | Out-File c:\Roger\files.html +``` + +### Ausgabe in Windows-Presentation-Foundation (WPF) + +``` +$files | Out-GridView +``` + +### Ausgabe filtern + +Im Beispiel sollen alle Windows-Services angezeigt werden, welche den Status Running besitzen und den Text Network im Namen enthalten: + +``` +Get-Service | Where-Object {($_.Status -eq "Running") -and ($_.Name -match "wpn")} +$files | Where-Object {$_.Length -lt 20000000} +$files | Where-Object {(Get-Date $_.CreationTime) -lt (Get-Date 20.05.2015)} +``` + +(`$_` enthält den Wert des in der Schlaufe durchlaufenen Objekts) + +Filtermöglichkeiten: + +``` +Gleich (equal): -eq +Ungleich (not equal): -ne +Kleiner (less than): -lt +Kleiner oder gleich (less than or equal): -le +Größer (greater than): -gt +Größer oder gleich (greater than or equal): -ge +Enthält (contains): -contains +Enthält nicht (not contains): -notcontains +Ähnlich (like): -like, -notlike +Match (match/notmatch) für regex: -match, -notmatch +Ersetzen (replace): -replace +``` + +### Sortierung (Alternativ zu Sortierung bei der Abfrage, bei "Vorbereitung") + +``` +$files2 | Sort-Object CreationTime | Format-List Fullname, Length, CreationTime +``` + +### Sortierung mit Unique + +``` +$files2 | Sort-Object CreationTime -Unique | Format-List Fullname, Length, CreationTime +``` + +### Gruppierung + +``` +$files2 | Format-List Fullname, Length, CreationTime -GroupBy CreationTime +``` + +### Ausgabe formatieren + +``` +# Ausgabe als Tabelle (Standard). Hierzu ist es nötig, die Felder bei der Abfrage schon angegeben zu haben (Fullname, Length, CreationTime) +$files # ist das gleiche wie: +$files | Format-Table # oder +$files | ft +# Ausgabe als Liste +$files | Format-List # oder, wenn Felder bei Abfrage noch nicht angegeben: +$files2 | Format-List # Standard-Felder +$files2 | Format-List * # Alle möglichen Felder +$files2 | Format-List Fullname, Length, CreationTime # nur die benötigten Felder +``` + +### Write-Host + +#### Formatierung + +Mit Write-Host kann die Ausgabe noch weiter formatiert werden + +``` +# Farben: +Get-Content -Encoding UTF8 -Path C:\Roger\regex-examples.txt | Write-Host -BackgroundColor("DarkGray") + +# ohne neue Linien: +Write-Host "aaaaa" -NoNewline; Write-Host "bbbbbb" + +# Separator für Array Elemente: +Write-Host (1,44,"abc",9) -Separator "|" +``` + +#### Ausgabe von Zeichen, die als PS Befehle interpretiert werden könnten + +``` +# mit --% +Write-Host --% %USERNAME%,this=$something{weird} + +# zum Vergleich: +Write-Host %USERNAME%,this=$something{weird} +``` + +## Vergleichsoperatoren + +### Zahlen + +``` +-eq gleich +-ne ungleich +-lt kleiner +-le kleiner oder gleich +-gt größer # bsp: "Dies ist ein Text".length -gt 10 # ergibt TRUE +-ge größer oder gleich +``` + +### Strings + + - `-like` / `-notlike` mit oder ohne Wildcards `"PowerShell" -like "Pow*"` + - `-contains` / `-notcontains` für Arrays. `"Dezember","Januar","Februar" -contains "Februar"` + - `-match` / `-notmatch` `"PowerShell" -match "ower"` + +## Arbeiten mit Text + +### Letztes Zeichen löschen + +``` +$a = $a.Substring(0, $a.Length - 1) + +# falls noch geprüft werden muss, ob das letzte Zeichen ein | ist: +if ($a.LastIndexOf("|") -eq ($a.Length - 1)) { + $a = $a.Substring(0, $a.Length - 1) +} +``` + +### Random String aus Buchstaben/Zahlen generieren + +``` +# mit 12 Zeichen: +$randomString = -join (((48..57)+(65..90)+(97..122)) * 80 |Get-Random -Count 12 |%{[char]$_}) +``` + +### Erhalte Text zwischen zwei Zeichen in einem String + +``` +$b = $FolderPath.LastIndexOf("/") +$b = $FolderPath.LastIndexOf("/", $b - 1) +$a = $FolderPath.LastIndexOf("/", $b - 1) +$a++ +$derGesuchteText = $FolderPath.SubString($a, $b - $a) +``` + +### Lese Datei aus und zeige alle 2-stelligen Zahlen an (regex) + +``` +$regex = [regex]"\b\d\d\b" +Select-String -Path C:\Roger\zahlentest.txt -Pattern $regex -AllMatches | % { $_.Matches } | % { $_.Value } + +# oder regex direkt in Anweisung: +Select-String -Path C:\Roger\zahlentest.txt -Pattern "\b\d\d\b" -AllMatches | % { $_.Matches } | % { $_.Value } + +# zusätzlich als Datei speichern: +Select-String -Path C:\Roger\zahlentest.txt -Pattern "\b\d\d\b" -AllMatches | % { $_.Matches } | % { $_.Value } > C:\Roger\zahlentest_output.txt +``` + +### IPs oder URLs aus TXT herauslesen und auflisten (regex) + +``` +# Erstellen wir zuerst eine TXT-Datei, z.B. aus einem tracert.exe Befehl: +TRACERT.EXE fuw.ch | Out-File c:\Roger\tracert-fuw-ch.txt -Encoding UTF8 + +# Nun das Auslesen: +Select-String -Path C:\Roger\tracert-fuw-ch.txt -Pattern '\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b' -AllMatches | % { $_.Matches } | % { $_.Value } > C:\Roger\tracert-fuw-ch-only-ips.txt + +## URL's +$regex = '([a-zA-Z]{3,})://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)*?' +``` + +## Arbeiten mit Zahlen + +### Modulo (Remainder of a Division) + +``` +5 % 2 +``` + +## Kontrollstrukturen + +### if then else + +``` +if($test) { + echo "Value of test: " $test} +else { + echo "Value of test is zero or undefined" +} + +# Boolean gegenteilig prüfen: mit ! davor. + +$a="xyz"; $b="b" +if($a -like "a") { + echo "a OK" +} elseif($b -like "b") { + echo "b OK" +} else { + echo "else" +} +``` + +### switch + +switch is used for testing *equality* only. Thus, you can't use comparison operators in switch statements. + +``` +switch(Read-Host "Select a menu item"){ + 1 {"File will be deleted"} + 2 {"File will be displayed"} + 3 {"File is write protected"} + default {"Invalid entry"} +} +# wenn bei einem match nicht mehr weiter gesucht werden soll, muss break angefügt werden: + 1 {"File will be deleted"; break} +# switch mit wildcards +switch -wildcard("PowerShell"){ + "Power*" {echo "'*' stands for 'shell'"} + "*ersh*" {echo "'*' replaces 'Pow' and 'ell'"} + "PowerShe?" {echo "Pattern matches because ?? replaces two 'l' "} +} +``` + +### for loop + +``` +$colors = @("Red","Orange","Yellow","Green","Blue","Indigo","Violet") +For ($i=0; $i -lt $colors.Length; $i++) { + $colors[$i] +} +``` + +### foreach loop + +``` +$myDocuments = Get-ChildItem C:\Roger -File + +# Ausgabe mit foreach: +foreach($ele in $myDocuments) { $ele.FullName } + +# Ausgabe mit Pipe: +$myDocuments | ForEach-Object {$_.FullName} + +# oder Ausgabe mit -InputObject: +ForEach-Object -InputObject $myDocuments {$_.FullName} + +# Shorthands: +Get-WMIObject Win32_LogicalDisk | ForEach-Object {$_.FreeSpace} +Get-WMIObject Win32_LogicalDisk | ForEach {$_.FreeSpace} +Get-WMIObject Win32_LogicalDisk | % FreeSpace + +# gleich wie +foreach($ele in Get-WMIObject Win32_LogicalDisk) { $ele.FreeSpace } +``` + +### all loops explained + +https://www.gngrninja.com/script-ninja/2016/4/20/powershell-getting-started-part-5-loop-the-loop#dountil + +### Objekt zählen + +``` +($svgs | measure).Count +``` + +## Datum / Zeit + +### Anzahl Tage von einem bestimmten Datum bis heute + +``` +[DateTime]$Date = "28. February 2015" +$Today = Get-Date +$Days = ($Today - $Date).Days +Write-Host "Vergangene Tage seit" $Date":" $Days +``` + +## Dateien + +### Hash aus Datei generieren + +``` +get-filehash -algorithm sha512 .\SAB_2018-03-29_Einzelstuecke.pdf +``` + +### Die 5 grössten Dateien in einem Verzeichnis auflisten (rekursiv) + +``` +Get-ChildItem c:\xampp -Recurse | Sort-Object Length -Descending | Select-Object Fullname, Length -First 5 +``` + +### Show files larger than X + +``` +Get-ChildItem -Path C:\ -File -Recurse -ErrorAction SilentlyContinue | Where-Object {$_.Length -gt 2GB} | Sort-Object length -Descending | Select-Object Name,Directory,@{n='GB';e={"{0:N2}" -F ($_.length / 1GB)}} | Out-GridView -Title "Large Files" +``` + +### Datei-Liste, sortiert + +``` +# This command sorts text files in descending order by the time span between CreationTime and LastWriteTime. +Get-ChildItem -Recurse -Path C:\Roger\*.txt | Sort-Object -Property @{Expression = {$_.CreationTime - $_.LastWriteTime}; Descending = $True} | Format-Table CreationTime, LastWriteTime, FullName +``` + +## Klassen + +### Aufruf von Static Methode einer Klasse + +The class name must be enclosed in square brackets. + +``` +[string]::Equals("a", "b") +``` + +## Powershell als Datei + +Dateiendung `.ps1` + +### Aufruf + +``` +& script.ps1 + +# oder als Verknüpfung +powershell.exe -File c:\roger\script.ps1 + +# Allenfalls noch Rechte setzen: +Set-ExecutionPolicy RemoteSigned + +# Restricted — Stops any script from running. +# RemoteSigned — Runs scripts created on the device. However, scripts created on another computer won't run unless they include a signature of a trusted publisher. +# AllSigned — All the scripts will run as long as they've been signed by a trusted publisher. +# Unrestricted — Runs any script without any restrictions. + +# in konsole dauerhaft (pro session): +Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass +``` + +### Externes Script einbinden + +``` +#line 1 of your script +. ./script.ps1 #include from current directory +#line 2 +#use function or variable from script.ps1 +``` + +## Beispiel PS-Schnippsel + +### Find encrypted files + +``` +$path=$args[0] +Write-Host "checking: $path" +$p = Get-ChildItem -Path $path -Recurse -Force -Attributes Encrypted + +if ($p) { + Write-Host "Found" $p.Name.Count "encrypted files" + Write-Output $p.Name + exit 1 +} +else { + Write-Host "No encrypted files found" + exit 0 +} +``` + +### Find password protected zip files + +``` +# check for password protected ZIP archives +Get-ChildItem -Path $path -Recurse -Filter *.zip | Where-Object { ` | 7z t $_.FullName *>$null; if ($LASTEXITCODE -ge 1) { Write-Host "$_ ! password protected zip archive"} } +$LASTEXITCODE +if ($LASTEXITCODE -ge 1) { + Exit 1 +} +``` + +### find corrupt data in fedora objectStore + +``` +Get-ChildItem -Path "\\gds-ms-vbas025.media.int\Archive_Fedora\fedora-data\objectStore" -File -Recurse | +Foreach-Object { + $fullname = $_.FullName + $lastmod = $_.LastWriteTime + try { + $content = Get-Content $fullname -ErrorAction Stop + } + catch { + Add-Content -Path C:\docuteam\apps\corrupt-fedora-data.txt -Value $lastmod" - "$fullname + } +} +``` + +### file convert to utf8 + +``` +(Get-Content -path static-fileformat-triples.nt) | Set-Content -Encoding UTF8NoBOM -Path static-fileformat-triples.nt +``` + +### MD5 checksum of a string + +``` +$md5 = New-Object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider +$utf8 = New-Object -TypeName System.Text.UTF8Encoding +$String = "Hello, world!" +$Hash = ([System.BitConverter]::ToString($md5.ComputeHash($utf8.GetBytes($String)))).replace("-","").ToLower() +``` + +### MD5 checksum of a file + +``` +Get-FileHash -Algorithm MD5 +```