paul123
Goto Top

Powershell - .txt Datei auslesen und Wert ausgeben

Hallo Community,

Meine Codezeilen:

$DateiA=Get-content -Path ("C:\Benutzer\Datenlöschung_A_"+(get-date).ToString(‘yyyyMMdd’)+"*.txt")  
$DateiB=Get-content -Path ("C:\Benutzer\Datenlöschung_B_"+(get-date).ToString(‘yyyyMMdd’)+"*.txt")   
$DateiC=Get-content -Path ("C:\Benutzer\Datenlöschung\Neuer Ordner\loeschen-C-"+(get-date).ToString(‘dd.MM.yyyy’)+"*.txt")  


[int]$löschen_A = ($DateiA -match '^# Anzahl zu löschender Dateien: ') -replace '.*\D(?=\d+$)'  
[int]$gelöscht_A = ($DateiA -match '^# Anzahl gelöschter Dateien  : ') -replace '.*\D(?=\d+$)'  

[int]$löschen_B = ($DateiB -match '^# Anzahl zu löschender Dateien: ') -replace '.*\D(?=\d+$)'  
[int]$gelöscht_B = ($DateiB -match '^# Anzahl gelöschter Dateien   : ') -replace '.*\D(?=\d+$)'  

if ($löschen_A -ne $gelöscht_A) { $DateiA -match 'Warnung' | set-content Error.txt}  
if ($löschen_A -eq $gelöscht_A) {"Datenlöschung_A_"+(get-date).ToString(‘yyyyMMdd’)+".txt: Die Datenlöschung war erfolgreich" | Set-Content Error.txt}  

if ($löschen_B -ne $gelöscht_B) {$DateiB -match 'Warnung' | Add-content Error.txt}  
if ($löschen_B -eq $gelöscht_B) {"Dateilöschung_B_"+(get-date).ToString(‘yyyyMMdd’)+".txt: Die Datenlöschung war erfolgreich" | Add-Content Error.txt}  

Einfach übersetzt:

Vergleiche die Werte in der DateiA.
- Wenn die Werte übereinstimmen, schreib in die Error.txt "Die Datenlöschung war erfolgreich"
- Wenn die Werte nicht übereinstimmen, such in der Datei nach "Warnung" und gib die Zeile in der Error.txt aus

Das Gleiche gilt für DateiB

Meine Frage:

Ich möchte dass wenn die Werte nicht übereinstimmen und er KEIN "Warnung" in der DateiX findet, dass er dann nochmal in der DateiC nach "Warnung" sucht und die Zeile dann auch in der Error.txt-Datei ausgibt.

An welcher Stelle muss ich das ergänzen und was genau muss ergänzt werden ?


Ich hoffe das war sinnvoll erläutert.

Vielen Dank für die Antworten.

Content-ID: 665708

Url: https://administrator.de/contentid/665708

Ausgedruckt am: 24.11.2024 um 02:11 Uhr

TK1987
Lösung TK1987 14.04.2021 um 10:57:47 Uhr
Goto Top
Moin,

Zitat von @Paul123:
if ($löschen_A -ne $gelöscht_A) ...
if ($löschen_A -eq $gelöscht_A) ...
Für sowas gibt es else. So braucht der Wert nur einmal geprüft zu werden.

Ich möchte dass wenn die Werte nicht übereinstimmen und er KEIN "Warnung" in der DateiX findet, dass er dann nochmal in der DateiC nach "Warnung" sucht und die Zeile dann auch in der Error.txt-Datei ausgibt.
if ($löschen_A -ne $gelöscht_A) {
  if ( $DateiA | Where-Object { $_ -match '^.*warnung.*$' } ) { $Matches.0 | Set-Content Error.txt }  
  else { $DateiC | Where-Object { $_ -match '^.*warnung.*$' } | %{ $Matches.0 | Set-Content Error.txt } }  
}
else {"Datenlöschung_A_"+(get-date).ToString(‘yyyyMMdd’)+".txt: Die Datenlöschung war erfolgreich" | Set-Content Error.txt}  
tio.run

Gruß Thomas
Paul123
Paul123 23.04.2021 um 09:51:32 Uhr
Goto Top
Hallo Thomas,

das hat mal wieder super funktioniert. Ich danke dir.

Das kleine Projekt geht jetzt langsam zuende.

Ich habe mir noch überlegt der Datei "error.txt" einen Zeitstempel hinzuzufügen.

Alles was ich gegooglet habe, sah eher kompliziert aus.

Gibt es eine einfache Möglichkeit der "error.txt" einen Timestamp im Namen zu verpassen?

Da dann bei einer täglichen Routine jeden Tag eine neue error.txt erstellt werden würde, würde ich dann auch gerne ein Limit von 7 Tagen einbauen.

Ungefähr:

Wenn eine Datei in dem Ordner älter als 7 Tage ist dann lösche diese.

Dann hätte man die die Dateien der letzten 7 Tage sortiert mit einem Zeitstempel.

Gibt es da eine simple Lösung?

Ich hoffe ich nerve mit meinen Fragen nicht.

Vielen Dank im Voraus.
TK1987
TK1987 23.04.2021 aktualisiert um 10:21:46 Uhr
Goto Top
Zitat von @Paul123:
Gibt es eine einfache Möglichkeit der "error.txt" einen Timestamp im Namen zu verpassen?
Kinderspiel, einfach Error.txt durch folgendes ersetzen:
"error_$(Get-Date -f 'yyyy-MM-dd').txt"  
Da dann bei einer täglichen Routine jeden Tag eine neue error.txt erstellt werden würde, würde ich dann auch gerne ein Limit von 7 Tagen einbauen.

Ungefähr:

Wenn eine Datei in dem Ordner älter als 7 Tage ist dann lösche diese.
Get-Childitem error*.txt | Where-Object LastWriteTime -lt (Get-Date).AddDays(-7) | Remove-Item
Ich hoffe ich nerve mit meinen Fragen nicht.
Würde ich es nicht gerne tun, würde ich es gar nicht tun 😉.

Gruß Thomas
Paul123
Paul123 23.04.2021 um 11:29:48 Uhr
Goto Top
Super! face-smile

Get-Childitem error*.txt | Where-Object LastWriteTime -lt (Get-Date).AddDays(-7) | Remove-Item

habe ich als letzte Zeile unten angefügt - funktioniert aber nicht. Ich habe 8 Dateien mit einem fortlaufenden Datum erstellt und trotzdem löscht er dir Dateien nicht. Muss das an eine bestimmte Stelle geschrieben werden?
TK1987
Lösung TK1987 23.04.2021 aktualisiert um 11:51:34 Uhr
Goto Top
Zitat von @Paul123:
habe ich als letzte Zeile unten angefügt - funktioniert aber nicht. Ich habe 8 Dateien mit einem fortlaufenden Datum erstellt und trotzdem löscht er dir Dateien nicht.
Richtig, weil der Befehl die Dateien nicht nach dem Datum im Dateinamen löscht, sondern nach dem Letzen Änderungsdatum der Dateien.

Wenn du das Ganze testen willst, gehe im Explorer in den Ordner, wo die Dateien hin sollen, klicke Oben auf "Datei", wähle "Windows Powershell öffnen" und führe dort folgende Zeile aus:
0..9 | %{$d=(Get-Date).AddDays(-$_);$f=ni -f "error_$($d.Tostring('yyyy-MM-dd')).txt";set-Itemproperty $f LastWriteTime $d}  
so wird für jeweils die Letzten 10 Tage eine Error-Datei erstellt, die auch ein dementsprechendes Änderungsdatum besitzen.
Paul123
Paul123 28.04.2021 um 11:26:34 Uhr
Goto Top
Hallo Thomas,

alles klar da weiß ich da bescheid!

Eine weitere Frage:

Ich möchte wenn mein Skript durchgelaufen ist, dass am Ende die error_28.04.2021.txt-Datei geprüft wird.

Wenn in der Datei dann das Wort "Warnung" vorkommt soll alles so bleiben.

Wenn nicht dann soll alles in der Datei ersetzt werden durch den Satz:

"Die Datenlöschung war vollständig O.K". Ist quasi nur ein optische Sache um die Kontrolle am Ende zu erleichtern.

Ich habe es so versucht:

$datei=Get-Content -Path ("C:\Pfad\zurDatei\error_"+$(Get-Date -f 'dd.MM.yyyy')+".txt")  

if ( $datei | Where-Object { $_ -notmatch '^.*warnung*$' } ) { "Die Datenlöschung war vollständig O.K" | Set-Content "error_$(Get-Date -f 'dd.MM.yyyy').txt" }  

In diesem Fall wird die error.txt immer überschrieben, egal ob das Wort "Warnung" drin vorkommt oder nicht. Das ist aber nicht Sinn der Sache.

Und kann ich das denn überhaupt in diesem einem Script so abbilden? Dass erst die Datei erstellt wird und dann nochmal überprüft?
TK1987
TK1987 28.04.2021 aktualisiert um 12:55:02 Uhr
Goto Top
Set-Content überschreibt immer die komplette Datei.

Eine Zeile an eine vorhandene Datei anfügen geht
  • entweder mit Add-Content
  • oder mit Out-File und dem zusätzlichen Parameter -Append

Hinweis: Der Vorteil von Set-Content ist, dass die Datei immer vollständig zu Ende geschrieben wird. Wenn also noch andere Programme oder Skripte auf diese Datei zugreifen, können diese so nicht dazwischen funken.

Und kann ich das denn überhaupt in diesem einem Script so abbilden? Dass erst die Datei erstellt wird und dann nochmal überprüft?
Man kann so ziemlich alles abbilden. Allerdings stelle ich hier die Sinnhaftigkeit mal infrage, erst eine Datei schreiben zu lassen und diese hinterher wieder einzulesen und zu überprüfen.
Ich würde die Überprüfung bereits vor dem Anlegen der Error-Datei durchführen.

Ich habe es so versucht:

$datei=Get-Content -Path ("C:\Pfad\zurDatei\error_"+$(Get-Date -f 'dd.MM.yyyy')+".txt")  

if ( $datei | Where-Object { $_ -notmatch '^.*warnung*$' } ) { "Die Datenlöschung war vollständig O.K" | Set-Content "error_$(Get-Date -f 'dd.MM.yyyy').txt" }  
In diesem Fall wird die error.txt immer überschrieben, egal ob das Wort "Warnung" drin vorkommt oder nicht. Das ist aber nicht Sinn der Sache.
Liegt daran, dass du mit Where-Object die Datei Zeilenweise durchsuchst - es gibt ja allerdings immer Zeilen ohne Warnung, daher ergibt das If-Statement auch immer $true.
Wenn du einfach nur die Ganze Datei durchsuchen möchtest, lass das Where-Object einfach weg
if ( $datei -notmatch 'warnung' ) { "Die Datenlöschung war vollständig O.K" | Add-Content  "error_$(Get-Date -f 'dd.MM.yyyy').txt" }   
Paul123
Paul123 28.04.2021 um 13:15:33 Uhr
Goto Top
Okay.

Naja, der Sinn dahinter ist folgender:

Es werden in die Error.txt die Ergebnisse des Vergleichs geschrieben:

Wenn Vergleich OK, schreib -> Datei 1 = Alles OK
Wenn Vergleich OK, schreib -> Datei 2 = Alles OK

Was du an dieser Stelle nicht wissen kannst, es werden weitaus mehrere Werte verglichen und ich möchte nicht, dass X-Mal "Datei X = Alles OK" in der error.txt steht sondern einfach nur "Vollständig OK" wenn alle zu vergleichenden Werte "OK" sind. Wenn aber ein Vergleich "nicht OK" ist und eben stattdessen in der Zeile die "Warnung" ausgegeben wird, soll nicht "Vollständig OK" ausgegeben werden, sondern eben die Datei mit den mehreren Zeilen in denen "Datei X = Alles OK" steht damit ich sehen kann in welcher Datei die "Warnung" auftritt.

Verstehst du was ich meine?

Deswegen auch Set-Content, weil die "Datei X = Alles Okay"-Meldungen alle überschrieben werden können aber nur wenn wirklich ALLE Meldungen OK sind.

Letztendlich war es nur eine Überlegung. Wenn es eine Bessere Lösung gibt, vielleicht zum Beispiel eine 2. TXT-Datei dann bin ich dafür offen.
TK1987
TK1987 28.04.2021 aktualisiert um 15:15:15 Uhr
Goto Top
Zitat von @Paul123:
Wenn es eine Bessere Lösung gibt, vielleicht zum Beispiel eine 2. TXT-Datei dann bin ich dafür offen.
# Datei für Fehlerausgabe
$Ausgabe = "Error_$(get-date -f 'yyyy-MM-dd').txt"  

# Für jede Textdatei
Foreach ($File in (Get-Childitem "C:\Benutzer\Datenlöschung*.txt")) {  

  # Datei lesen
  $Content = Get-Content $File

  # Werte laden
  [int]$löschen  = ($Content -match '^# Anzahl zu löschender Dateien: ') -replace '.*\D(?=\d+$)'  
  [int]$gelöscht = ($Content -match '^# Anzahl gelöschter Dateien  : ' ) -replace '.*\D(?=\d+$)'  
  
  # Wenn Werte nicht übereinstimmen, Zeile zur Fehlervariable hinzufügen
  if ($löschen -ne $gelöscht) { [Array]$Fehler += "Warnung: Die Werte in '$File' stimmen nicht überein!" }  

} # Ende der Foreach-Schleife

# Falls die Fehlervariable existiert, schreibe die Fehler in die Ausgabe-Datei, sonst Schreibe alles OK.
If ($Fehler) { $Fehler | Set-Content $Ausgabe }
else { "Die Datenlöschung war vollständig O.K" | Set-Content $Ausgabe }  
Paul123
Paul123 04.05.2021 aktualisiert um 10:53:29 Uhr
Goto Top
Hallo Thomas,

hier ist mir noch etwas aufgefallen.

Wenn ich in der ersten $DateiA mehrere Zeilen mit dem Wort "Warnung" beschrieben sind, wird immer nur die letzte Zeile mit "Warnung" ausgegeben.

Das Problem ist auch in der tio.run nachvollziehbar.

Wie kann ich ihm denn sagen, dass er alle Zeilen die ein "Warnung" enthalten untereinander in der Error.txt ausgeben soll?

Ich beziehe mich hier auf deinen Kommentar vom 14.04.2021 um 10:57 Uhr
TK1987
Lösung TK1987 04.05.2021 um 11:20:30 Uhr
Goto Top
Zitat von @Paul123:
Wie kann ich ihm denn sagen, dass er alle Zeilen die ein "Warnung" enthalten untereinander in der Error.txt ausgeben soll?
Dann so:
if ($löschen_A -ne $gelöscht_A) {
  if     ( $DateiA -match 'Warnung' ) { $DateiA -match 'Warnung' | Set-Content Error.txt }  
  elseif ( $DateiC -match 'Warnung' ) { $DateiC -match 'Warnung' | Set-Content Error.txt }  
}
else {"Datenlöschung_A_"+(get-date).ToString(‘yyyyMMdd’)+".txt: Die Datenlöschung war erfolgreich" | Set-Content Error.txt}  

Wieso löschst du die Daten eigentlich in einer seperaten Instanz? Es wäre doch einfacher, gleich während der Datenlöschung meckern zu lassen, wenn er ein Element nicht löschen konnte - und vorallem wieso er es nicht konnte.
Paul123
Paul123 04.05.2021 um 12:22:08 Uhr
Goto Top
Super, das funktioniert jetzt.

Das ist eine komplizierte Geschichte, ich weiß dass das einfacher wäre allerdings kann ich das jetzt nicht so ohne Weiteres erklären.

Wir können davon ausgehen, dass ich nur die Protokolle der Auswertung zur Verfügung habe.

if ($löschen_A -ne $gelöscht_A) {
  if     ( $DateiA -match 'Warnung' ) { $DateiA -match 'Warnung' | Set-Content Error.txt }  
  elseif ( $DateiC -match 'Warnung' ) { $DateiC -match 'Warnung' | Set-Content Error.txt }  
}
else {"Datenlöschung_A_"+(get-date).ToString(‘yyyyMMdd’)+".txt: Die Datenlöschung war erfolgreich" | Set-Content Error.txt}  

1. Frage dazu:

Gibt es die Möglichkeit wenn mir die Zeile mit "Warnung" in meiner Error.txt ausgegeben wird diese durch den Dateinamen zu ergänzen ?

Bsp.:

Datenlöschung_A: Dies ist die gefundene Zeile mit der Warnung

2. Frage:
Wie füge ich am Ende einer Ausgabe ein Absatz hinzu? Ich habe es mit `n probiert aber das hat bei mir mal wieder nicht funktioniert
TK1987
TK1987 04.05.2021 aktualisiert um 13:25:08 Uhr
Goto Top
Zitat von @Paul123:
1. Frage dazu:
Gibt es die Möglichkeit wenn mir die Zeile mit "Warnung" in meiner Error.txt ausgegeben wird diese durch den Dateinamen zu ergänzen?
Sicher. Willst du das dann für jede Zeile mit Warnung... oder Pro Datei je einmal?
Pro Zeile:
($DateiA -match 'Warnung' | %{ "DateiA: $_" }),""  | sc Error.txt  
Hinweis:
% ist ein Alias für Foreach-Object
sc ist ein Alias for Set-Content

Je Datei:
"DateiA:",($DateiA -match 'Warnung'),"" | sc Error.txt  

2. Frage:
Wie füge ich am Ende einer Ausgabe ein Absatz hinzu? Ich habe es mit `n probiert aber das hat bei mir mal wieder nicht funktioniert
Du musst strikt unterscheiden zwischen...
    • Einem Raw-Text: Dieser ist quasi wie eine 1-zeilige-Zeichenkette - und kann Zeilenumbruchzeichen ("`n") enthalten, die ein Texteditor später als Umbruch interpretiert.
    • Einem Array: Ein echter, Mehrzeiliger Text.
Für die spätere Ausgabedatei macht dies keinen Unterschied, da der Array bei der Ausgabe wieder in einen Raw-Text umgewandelt wird - während der Bearbeitung mit Powershell macht dies jedoch einen gewaltigen Unterschied. So kann z.B. nur ein Array Zeilenweise durchsucht werden, bei einem Raw-Text hingegen ist es leichter, Abschnitte zu untersuchen, die sich über mehrere Zeilen erstrecken.

Beispel:
# Raw-Text mit 2-Zeilen:
"Zeile1`nZeile2"  

# Array aus 2-Zeilen
"Zeile1","Zeile2"  
Beide Ausgaben wirkt auf den ersten Blick gleich, sind jedoch Grundverschieden in den Anwendungsmöglichkeiten.

Zurück zu deinem Fall:
Du liest eine Datei mit gc (Alias für Get-Content) ein. Ohne Angabe des Parameters -Raw wird die Datei an den Zeilenumbruchzeichen in einen Array gesplittet. Dies ist für dich von Vorteil, da du aus deiner Textdatei ja nur einzelne Zeilen mit "Warnung" erhalten möchtest.
Entsprechend fügst du eine Leerzeile einfach ein, indem du eine Leere Zeichenkette mit einem Komma anfügst:
$DateiA,""  
oder nur für die Zeilen mit Warnung:
($DateiA -match "Warnung"),""  

Hoffe das war verständlich, ansonsten einfach fragen.