Categories
Middleware PowerShell

Umbenennung von Dateien per powershell

In Linux Umgebungen haben Administratoren für Logdateien von WebSphere Application Server, Tomcat und andere Middleware Produkte meist Skripte, um die Protokolle täglich oder wöchentlich umzubenennen (per crontab).

Unter Windows habe ich auf die schnelle keine vernünftige Scriptlösung gefunden. Meine Lösung stelle ich in meinem Azure DevOps Projekt pwshLogSwitch zur Verfügung.

Das kleine Script erwartet mindestens ein Startverzeichnis als Parameter. Alle Dateien in diesem Verzeichnis und darunter werden umbenannt, solange die Kriterien passen.

Die Auswahlkriterien werden mit den Parametern
-Filter
-IncludePattern
-ExcludePattern
definiert und entsprechen den gleichnamigen Parametern von Get-ChildItem. Es können auch reguläre Ausdrücke und Wildcards übergeben werden.

Als Verzeichnis können mehrere Verzeichnisnamen per : getrennt übergeben werden.

IncludePattern und ExcludePattern können ebenfalls mehrere Werte enthalten. Diese sind per Komma zu trennen.

Beispiele:

logswitch.ps1 -s -x *.ps1 -i ‘*.ot,*.out’ -d folder1:folder2:nonexistingFolder

logswitch.ps1 -simulate -ExcludePattern *.ps1 -IncludePattern ‘*.ot,*.out’ -Directories folder1:folder2:nonexistingFolder

logswitch.ps1 -x ‘[2][0][12][0-9]*,1.*’ -f *.log -d folder1:folder2:nonexistingFolder

Categories
PowerShell

Powershell Tail und Head vereint

Ausgabe der letzten und der ersten n-Zeilen in einemBefehl

In Unix/Linux Derivaten sind die Befehle tail und Head oft benutzte Werkzeuge zur Ausgabe der ersten/letzten Zeilen einer Datei oder der Ergebnisse eines Befehls. Direkt kombinieren kann man sie nicht. Hier sind sed/awk und andere Werkzeuge und Lösungen gefordert. Powershell bietet eine sehr effiziente Lösung.

Der erste Ansatz wäre die Ausgabe mit Select -Last und Select -First zu behandeln.

Get-ChildItem somefolder | Select -First 10

Get-ChildItem somefolder | Select -Last 10

Das geht aber nicht in einem Befehl (oder nur mit einer zu schreibenden Funktion). Damit haben wir das gleiche Problem wie mit head und tail in Unix.

Per Get-ChildItem und einem auf die Ausgabe angewendetem Sort Befehl erhält man eine Liste. Diese Ausgabe kann man als Array / Liste von Zeichenketten interpretieren und einzelne Elemente mit einen nachfolgenden Index in eckigen Klammern auswählen.

(Get-Content hashes.csv)[1]

Der “Trick” besteht darin, dass eine solche Powershell Liste auch einen Bereich adressieren kann und dieser Bereich “überlaufen” darf und dann von vorn anfängt. [0..10] gibt die ersten 11 Elemente aus. [10..-1] gibt alle Zeilen ab der 11. Zeile bis zur letzten (-1) aus.

[-10..10] gibt die letzten  10 und die ersten 11 Zeilen  aus (da 0 die erste Zeile ist). Das Ergebnis sieht etwas ungewöhnlich aus, da zuersrt die letzten Zeilen ausgegeben werden:

(gci $folder *jpg |Sort-Object LastWriteTime)[-10..10]

Dier zweite bis zehnte Zeile der Datei und die letzten sind sind in den blauen Rechtecken hervorgehoben, dier erste Zeile der Ausgabeliste ist in der Mitte.

Dieses Verfahren funktioniert für alle Listausgaben, wie Get-ChildIten, Get-Content, Get-Prozess und so weiter.

Categories
Middleware PowerShell

Powershell tail für Textdateien

In Powershell kann die Ausgabe der letzten n Zeilen in grossen Text/Ascii Dateien mit der -tail Option von Get-Content erfolgen:

Get-Content meineRiesigeDatei.csv -tail 25

Seit Powershell v3 bietet Get-Content (oder der zugehörige alias gc) die Option -tail. Leider gibt es keinen tail -f zur fortlaufenden Aktualisierung.

Categories
Middleware PowerShell

Powershell Equivalent zu Unix ‘ls -ltr | tail’

In Powershell kann die Ausgabe der neuesten n-Dateien mit diesem Befehl erfolgen:

  gci | sort LastWriteTime | select -last 60

In diesem Beispiel werden die Dateien im aktuellen Verzeichnis mit gci ausgegeben, nach letztem Schreibzugriff mit sort sortiert (neueste zuletzt) und dann werden nur die letzten 60 per select last 60 ausgegeben.

Categories
Debian Korn Shell / Bash Linux RedHat Ubuntu

Welcher Prozess belegt wieviel Swap?

Wenn die Kommandos (in den Linux Varianten Debian, Ubuntu, RedHat und ähnlich)

  free
  cat /proc/swaps
  swapon -s

eine hohe Auslastung des Swap Spaces anzeigen, kommt die Frage nach dem Verbraucher des Swap hoch.

Folgendes Miniskript gibt die Liste der Prozesse nach Größe des belegten Swap an. Mit der Variable THRESHOLD kann man die Liste auf die Verbraucher eingrenzen, die mehr als diesen Wert in kB an Swap belegen.

  THRESHOLD=5000
  for pid in `ls /proc`; do
    vmswap=`awk '/VmSwa/{print $2}' /proc/${pid}/status 2>/dev/null`;
    if [ ${vmswap} -gt ${THRESHOLD} ];then
      pName=`ps -ef|awk '$2=="'"${pid}"'" {print $8}'`;
      echo "PID ${pid}: ${vmswap} kB (${pName})";
    fi;
  done 2>/dev/null|sort -un -k3

Die Ausgabe sieht wie folgt aus:

  PID 123857: 7826 kB (/usr/bin/python)
  PID 768456: 9876 kB (/usr/bin/java)
  PID 6543: 11392 kB (/usr/bin/python)
  PID 367682: 12420 kB (/usr/bin/python)

Categories
PowerShell Windows

PowerShell Drive alias:

PowerShell nutzt das Konzept der Laufwerke (=PowerShell Drives) sehr ausgiebig. So werden die Umgebungsvariablen in env: verwaltet, die Windows Registry aber auch die “normalen” Laufwerke wie “C:”.

Auch Aliasse für Kommandos sind ein PowerShell Drive sind.

Get-ChildItem alias:

Categories
PowerShell Windows

Mehrfache Einträge in großen Konfigurationsdateien oder Protokollen finden (Windows Powershell Lösung)

Im Post Mehrfache Einträge in großen Konfigurationsdateien oder Protokollen finden(Linux/Unix) habe ich gezeigt, wie mehrfach vorkommende Zeilen in Textdateien gefunden und automatisch entfernt werden können.
Windows hat im Zuge der Powershell ein mächtiges Werkzeug, dass dies auch kann. (Seit dem Windows 10 1709 Update kann man natürlich auch einfach die eingebaute bash nehmen….)

Zur Demonstration verwende ich eine Datei duplicates.txt:

Get-Content -Path duplicates.txt

Zeile kommt nur einmal vor
Zeile kommt zweimal vor
Zeile kommt dreimal vor
Zeile kommt zweimal vor
Zeile kommt dreimal vor
Zeile kommt auch nur einmal vor
Zeile kommt dreimal vor

Mehrfache vorkommende identische Zeilen und deren Anzahl findet und zählt man wie mit Group-Object

Get-Content -Path duplicates.txt |Group-Object

Count Name Group
—– —- —–
1 Zeile kommt nur einmal… {Zeile kommt nur einmal vor}
2 Zeile kommt zweimal vor {Zeile kommt zweimal vor, Zeile kommt zweimal vor}
3 Zeile kommt dreimal vor {Zeile kommt dreimal vor, Zeile kommt dreimal vor, Zeile kommt dreimal vor}
1 Zeile kommt auch nur e… {Zeile kommt auch nur einmal vor}

Wenn die Reihenfolge der Zeilen keine Bedeutung hat, ist es einfach, doppelte oder mehrfache Zeilen zu entfernen:

Get-Content -Path duplicates.txt | Sort-object -Unique

Zeile kommt auch nur einmal vor
Zeile kommt dreimal vor
Zeile kommt nur einmal vor
Zeile kommt zweimal vor

oder

Get-Content -Path duplicates.txt | sort-object | Get-Unique

Zeile kommt auch nur einmal vor
Zeile kommt dreimal vor
Zeile kommt nur einmal vor
Zeile kommt zweimal vor

Die Ausgabe aller mehrfach vorkommenden Zeilen kann mit einer einfachen Abfrage geschehen:

Get-Content -Path duplicates.txt | Group | ? { $_.Count -gt 1 } |Select -ExpandProperty Name

Schwieriger wird es, die doppelten Zeilen zu entfernen, wenn die Reihenfolge in der Datei erhalten bleiben soll. Eine Hash Tabelle hilft an dieser Stelle weiter. Die zugrunde liegende Idee ist, für jede Zeile beim ersten Auftreten einen Eintrag in einer Hashtabelle vorzunehmen. Sollte dieser Zeile erneut auftreten, wird sie übersprungen. Das ist der Code:

$hash = $null
$hashTable = @{}
Get-Content .\duplicates.txt | ForEach-Object {
  if ($hashTable.Item($_) -eq $null) {
    $_
    $hashTable.Add($_,”found”)
  }
}

Zeile kommt nur einmal vor
Zeile kommt zweimal vor
Zeile kommt dreimal vor
Zeile kommt auch nur einmal vor

Die ersten beiden Zeilen initialisieren die Tabelle $hashTable. Dann wird für jede neue Zeile ein Eintrag mit dem Wert “found” hinzugefügt (eine 1, ein true oder ähnlich würden es auch tun, Hauptsache ein Eintrag für die Zeile existiert.).

Achtung: Die Ausgabe von $hashTable.Keys gibt die Reihenfolge nicht wie in der Datei aus:

$hashTable.Keys

Zeile kommt dreimal vor
Zeile kommt zweimal vor
Zeile kommt nur einmal vor
Zeile kommt auch nur einmal vor

Sehr hilfreich sind die Erklärungen zu Powershell Hash Tabellen von den Scripting Guys.

Categories
Korn Shell / Bash Shell Programmierung

Mehrfache Einträge in großen Konfigurationsdateien oder Protokollen finden (Linux/Unix Lösung)

Oft vermutet man in größeren Protokolldateien oder Konfigurationsdateien mehrfach vorhandene Einträge. Diese sollen schnell ermittelt und bei Bedarf entfernt werden.
Unter Linux gibt es das Werkzeug uniq. Der Parameter --count gibt alle Zeilen aus und die Häufigkeit Ihres Auftretens in der ersten Spalte. Es funktioniert nur nicht so intuitiv, wie erwartet. Ich versuche es an einem Beispiel:

uniq –count console.log

1 <?xml version=”1.0″ encoding=”UTF-8″ ?>
1 <Protokollzeile xxxyyyzzz >

Diese Datei hat offensichtlich zwei Zeilen insgesamt und beide unterscheiden sich. Das ist im Moment nicht sehr hilfreich. Daher verdoppele ich die Datei und füge eine einzeln vorkommende Zeile hinzu:

cat console.log >> consoleDup.log
cat console.log >> consoleDup.log
echo “Eine abweichende Zeile >> consoleDup.log

Eine erneute Überprüfung mit uniq zeigt das Problem:

uniq –count consoleDup.log

1 <?xml version=”1.0″ encoding=”UTF-8″ ?>
1 <Protokollzeile xxxyyyzzz >
1 <?xml version=”1.0″ encoding=”UTF-8″ ?>
1 <Protokollzeile xxxyyyzzz >
1 Eine abweichende Zeile

Genau, das wollten wir so nicht sehen. Die erste und dritte Zeile und die zweite und vierte Zeile sind identisch. Da sollte eine 2 stehen.
Aus dem gleichen Grund funktioniert uniq --unique nicht, solange die Datei nicht sortiert vorliegt. In den meisten Fällen (XML, JSON etc) Dazeien würde die Sortierung die Datei unbrauchbar machen.

Zur Lösung des Problems müssen die Zeilen sortiert werden.

sort consoleDup.log|uniq –count

1 Eine abweichende Zeile
2 <?xml version=”1.0″ encoding=”UTF-8″ ?>
2 <Protokollzeile xxxyyyzzz >

Schon besser. Der uniq Parameter --repeated gibt nur die mehrfach vorkommenden Zeilen aus:

sort consoleDup.log|uniq –count –repeated

2 <?xml version=”1.0″ encoding=”UTF-8″ ?>
2 <Protokollzeile xxxyyyzzz >
Doppelt oder noch häufiger vorkommende Zeilen in Textdaten können schnell und elegant mit awk entfernt werden:

awk ‘!seen[$0]++’ consoleDup.log >> console_noDupRecords.log
cat console_noDupRecords.log

<?xml version=”1.0″ encoding=”UTF-8″ ?>
<Protokollzeile xxxyyyzzz >

Eine Lösung für die Powershell zeige ich hier.

Categories
Shell Programmierung Windows Bash

Windows bash – Zugriff auf lokale Verzeichnisse

Lokale Verzeichnisse in der Windows Bash können über den automatischen eingebunden Mount /mnt/ gelesen und geändert werden.

[user1:/mnt/d/Cache] $ ls -ld /mnt/*

drwxrwxrwx 0 root root 512 Mar 19 10:17 /mnt/c
drwxrwxrwx 0 root root 4096 Mar 19 10:17 /mnt/d

Der Zugriff auf C:\Users\user1\Documents (= Eigene Dokumente des Benutzers user1) erfolgt beispielsweise per:

ls /mnt/c//Users/user1/Documents/

Categories
PowerShell Windows

Umgebungsvariablen in der PowerShell

Abfragen von Umgebungsvariablen
Die Anzeige der Umgebungsvariablen war in der “alten” Kommandozwile (cmd) einfach per env durchzuführen.

Die PowerShell bietet einen ähnlich einfachen Aufruf mit Get-ChildItem oder per Alias gci. Zu beachten ist, dass Get-ChildItem einen Pfad erwartet:

Get-ChildItem env:

Eine bestimmte Variable kann mit env: abgefragt werden:

gci env:PATH

Einfacher kann die Variable auch wie jeder Variable in Powershell angezeogt werden.

$Env:Path

Dieser Weg eignet sich besonders gut für Skripte. An dieser Stelle zeigt die PowerShell ihre Stärke. Die Variable kann mit Zeichenkettenoperationen weiter verarbeitet werden, da es ein STRING Objekt ist. Beispielsweise kann -replace zum Bearbeiten von Teilen der Variable verwendet werden:

$Env:myVar=”Toast”
$Env:myVar

Toast

$Env:myVar = $Env:myVar -replace(“oa”,”e”)
Env:myVar

Test
 
Setzen und Ändern von Umgebungsvariablen
Eine Umgebungsvariable kann einfach über eine Zuweisung mit “=” gesetzt oder überschrieben werden:

$env:myVar=”D:\TEMP”
gci env:myVar

Möchte man an eine bestehende Variable etwas anhängen, geschieht dies per +=:

Name Value
—- —–
myVar D:\TEMP

Achtung: Bei der Verknüpfung ist die Syntax selbst korrekt anzugeben. Pfad Variablen (wie $env:PATH) erwarten oft ein “;” als Trennzeichen.

$env:myVar+=”;D:\Cache”
gci env:myVar

Name Value
—- —–
myVar D:\TEMP;D:\Cache

Achtung: Diese Variablen sind nur auf Prozessebene, also in der aktuellen Sitzung gesetzt. Um eine Variable dauerhaft zu setzen, ist auf die Funktionen des .NET Frameworks zurückzugreifen.

[Environment]::SetEnvironmentVariable(“myVar”, “TestWert”, “User”)

Der obige Befehl setzt oder überschreibt die Variable myVar mit dem Wert “TestWert” dauerhaft in der Umgebung des Benutzers. Der dritte Parameter bietet die folgenden Optionen:

  • User (Benutzer-Ebene) – Die Variable wird dauerhaft für diesen Benutzer gesetzt.
  • Machine (Maschinen-Ebene = System) – gültig für alle Benutzer des Systems. Dieser Aufruf erfordert adminsitrative Berechtigungen.
  • Process (Process-Ebene) – Das ist der Standard und entspricht dem Verhalten von $env:myVar

[Environment]::GetEnvironmentVariable(“myVar”, “machine”)

TestWert

Löschen von Umgebungsvariablen

Remove-Item env:myVar
gci env:myVar

gci : Der Pfad “myVar” kann nicht gefunden werden, da er nicht vorhanden ist.
In Zeile:1 Zeichen:1
+ gci env:myVar
+ ~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (myVar:String) [Get-ChildItem], ItemNotFoundException
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand

Das Löschen von Variablen auf System-Ebene (“machine”) oder Benutzer-Ebene (“User”) erfolgt mit dem .NET Aufruf:

[Environment]::SetEnvironmentVariable(“myVar”,$null,”Machine”)