WinFuture-Forum.de: Problem: Aufwändiges Batchscript - WinFuture-Forum.de

Zum Inhalt wechseln

Alle Informationen zum Thema Windows 7 in unserem Special. Windows 7 Download, FAQ und neue Funktionen im Überblick.
Seite 1 von 1

Problem: Aufwändiges Batchscript Entpacken, Textdatei auslesen, ursprüngliche zip umbennenen


#1 Mitglied ist offline   FridayThe13 

geschrieben 18. Februar 2019 - 21:07

Guten Abend liebe Leser,

ich benötige Hilfe, da meine bescheidenen Kenntnisse und mehrere umfangreiche Suchen mir nur bedingt weiter helfen konnten und die Komplexität der Aufgabe mich in den schieren Wahnsinn treibt.

Folgende Situation: Ich habe viele zip Dateien, welche das Format DATUM-ZEIT.abc haben. Korrekt, keine .zip Endung! Wenn man diese Dateien entpackt, findet man einen Order und eine Textdatei.json vor.

Ich benötige ein Script, welches die DATUM-ZEIT.abc entpackt, die Textdatei.json öffnet, dort einen bestimmten Wert ausliest (immer an der gleichen Stelle vorzufinden), die DATUM-ZEIT.abc in AUSGELESENER.WERT-DATUM-ZEIT.abc umbenennt und die entpackten Daten löscht.

Das i-Tüpfelchen wäre, wenn zusätzlich bei dem Vorgang nicht nur ein Wert aus der Textdatei.json ausgelesen wird, sondern gleich ~15 Werte und diese ordentlich in eine Tabelle übertragen werden.

Das Ganze soll letzten Endes auf Windows 7 & 10 laufen.

Vorab vielen Dank für eure Mithilfe!
0

Anzeige



#2 Mitglied ist offline   RalphS 

  • Gruppe: VIP Mitglieder
  • Beiträge: 8.681
  • Beigetreten: 20. Juli 07
  • Reputation: 1.075

geschrieben 18. Februar 2019 - 22:12

Wieviele Win7-Kisten sind denn das? Existiert da jeweils eine aktuell PowerShell (5.x) drauf, oder ließe die sich ggf nachinstallieren?

Hintergrund: Im Gegensatz zu Batch ist so ein Unterfangen in PowerShell relativ einfach umzusetzen. Allerdings gibts die JSON-Unterstützung erst ab Version 3 und Win7 hat von Haus aus nur Version 2 dabei. Neuere Versionen muß man selber installieren (kommen nicht über Windows Update).

Und "einfach" auch nur dahingehend, daß es mit PS einen klaren Weg zum Ziel gibt.

* Die Zipdateien zusammensammeln ist anhand von Get-ChildItem und Where-Object -Match (regex) Filtern kein Problem, wenn die alle einem Namensschema folgen oder wenn es außer den Zips nichts anderes dort gibt.

* Von da an geht es allerdings ans Eingemachte.
#Jeweils die Datei als Zipdatei öffnen und Inhalt kriegen geht mit [system.ío.compression.ziparchive]::Open() oder ::OpenRead()
#dann hat man unter .Entries die einzelnen Eintragsobjekte, die man wieder einzeln öffnen kann (Dateiname gibt's als Eigenschaft für jeden ZipEntry gratis dazu, sodaß man die JSON gezielt raussuchen kann).

Allerdings kriegt man so pro Zipeintrag einen einfachen Datenstrom, den man irgendwo in eine Datei schreiben muß, bevor man ihn auswerten kann.

Jene Datei kann man dann mit GetContent -Path ... |ConvertFrom-Json direkt als Objekt in die Umgebung holen. Dann die Zip-Datei wieder schließen zum Umbenennen. Das JSON-Objekt befindet sich an der Stelle noch im Speicher, ggf kann man dessen Eigenschaften jetzt irgendwie weiter auswerten oder irgendwo hinschreiben oder sonstwas. Den einen Attributwert zum Umbenennen bräuchte man eh. Löschen ist auch kein Ding mehr, schließlich mußten wir den Datenstrom irgendwo hinschreiben und jenes "irgendwo" haben wir uns hoffentlich gemerkt.



Natürlich gehen auch andere Scriptumgebungen - JS/VBS im Windows Script Host oder sogar PHP mit Kommandozeilentool oder sonstwas. (Okay, VBS wohl eher weniger.) WSH(plus Javascript) hätte zumindest den Vorteil, daß es überall bereits vorhanden sein sollte.

Und mit ein bißchen Glück gibt's auch in der PSGallery irgendwo ein Modul oder fünf, was dem Umgang mit Zipdateien etwas handlicher macht.


Nur Batch ist etwas schlecht, weil man damit auf die benötigten Informationen keinen zuverlässigen Zugriff bekommt. Spätestens die Auswertung von JSON geht mit Batch schief, selbst wenn man den Rest noch hinbekommen kann.

Dieser Beitrag wurde von RalphS bearbeitet: 18. Februar 2019 - 22:14

"If you give a man a fish he is hungry again in an hour. If you teach him to catch a fish you do him a good turn."-- Anne Isabella Thackeray Ritchie

Eingefügtes Bild
Eingefügtes Bild
1

#3 Mitglied ist offline   FridayThe13 

geschrieben 19. Februar 2019 - 17:48

Es sollten maximal 3 Rechner sein, 2 mit Windows 7, eventuell einer mit Win 10.

Im schlimmsten Fall wäre es auch kein Beinbruch, wenn das Ganze sauber auf einem einzigen Win7 Rechner funktioniert.

Auf dem eben genannten Win7 Rechner habe ich gerade die PS Version von 2.0 auf 5.1 gebracht. Damit sollte sich das Problem mit der json erledigt haben. Wobei ich mich frage, ob ein simples umbenennen in eine txt nicht ausreichen würde.

Ich werde mir die von dir genannten Befehle zur Gemüte führen und ein bisschen tüfteln, aber PS ist für mich Neuland und ich habe nicht einmal die Hälfte von dem was du geschrieben hast verstanden. Falls du mit deinem Wissen nicht geizen möchtest, wäre ich um eine ausführlichere Anweisung äußerst dankbar!
0

#4 Mitglied ist offline   RalphS 

  • Gruppe: VIP Mitglieder
  • Beiträge: 8.681
  • Beigetreten: 20. Juli 07
  • Reputation: 1.075

geschrieben 19. Februar 2019 - 20:59

Naja, das Problem mit Batch ist einfach, daß JSON nicht-linear strukturiert ist (sondern hierarchisch) und daß auch die Reihenfolge der Schlüssel/Wertepaare egal ist. Da stößt Batch ganz schnell an seine Grenzen.


PS's cmdlet (ausführbarer Befehl in PS) ConvertFrom-Json nimmt hingegen einfach den Inhalt einer JSON-Datei her (den man mit Get-Content bekommt; unter Batch wäre es type gewesen) und macht einfach "richtiges" Objekt daraus, so wie es durch JSON beschrieben wurde.

Am Besten schaust Du Dir mal in Ruhe an, was mit PowerShell wie geht. Dazu einfach mal powershell_ise.exe ausführen (oder im Startmenü PowerShell ISE raussuchen). ISE = "Integrated Scripting Environment" in Anlehnung an IDE (integrierte Entwicklungsumgebung).

Die ISE kennt Autovervollständigen. Einfach Tabtaste drücken (nach "-" für Parameter oder, wenn's nicht schon automatisch passiert, nach Punkten/Doppelpunkten).

Den ganzen Inhalt des Scriptfensters (oben, weiß) kann man mit F5 ausführen. Bestimmten Text kann man markieren und dann mit F8 ausführen. Oder man schreibt's unten rein (blau) und drückt einfach Enter.

Interessante Befehle:

Get-Childitem -Path <pfad> liefert Datei- und Ordnerobjekte zurück.

$variable = Get-Item <Pfad zu einer Datei> beschafft eine Referenz auf die benannte Datei und steckt sie in die Variable. Das Ergebnis ist ein (Datei-)Objekt, welches mehr oder weniger alle Dateieigenschaften mitbringt.

PowerShell kennt zwar, benötigt aber kein explizites "Echo". Ausgaben landen alle in der "Pipeline" und wenn man Enter drückt, landet die letzte Ausgabe auf der Konsole.

Einfach mal $variable.Length eingeben (cf ein bißchen weiter höher; $variable sollte ein Dateiobjekt beinhalten).
Das gibt die Größe in Bytes.
$variable.BaseName gibt den blanken Dateinamen ohne Endung.
$Variable.Fullname gibt den vollständigen Pfad zur Datei.

Wie gesagt, einfach mal mit Tab durchgehen was da was ist.

$variable | fl * zeigt alle Eigenschafts*werte* an, die das Objekt so mitbringt. Zum Beispiel Length mit Wert 5 für fünf Bytes.
$variable | gm * zeigt alle Eigenschaften und Methoden an samt ihre(n) Signatur(en), die das Objekt mitbringt. Zum Beispiel Property long Length (get): Das sagt, es gibt eine Eigenschaft Length, der Rückgabetyp ist long, und man kann das nur lesen (get). Andere Eigenschaften haben dort auch ein set zu stehen: Dann kann man hier was reinschreiben und zB das Dateidatum ändern, oder den Namen, oder Dateiattribute.



Objektklassen gehen mit [] zu beschreiben, zB [string] $variable = "Text".
Statische Methoden (solche, die der Klasse gehören, nicht dem Objekt selbst) gehen mit [klassenname]::Methode().
Statische Eigenschaften, hauptsächlich Enumerationen, gehen mit [klassename]::Auflistungselement (wobei der Klassenname hier der Name der Enumeration ist).
Methodensignaturen bekommt man mit dem reinen Namen der Methode (ohne Klammern), zB mit dem $Variable von oben als $Variable.Open liefert:

System.IO.FileStream Open(System.IO.FileMode mode)
System.IO.FileStream Open(System.IO.FileMode mode, System.IO.FileAccess access)
System.IO.FileStream Open(System.IO.FileMode mode, System.IO.FileAccess
access, System.IO.FileShare share)


Open() liefert also immer ein FileStream-Objekt, das ich später auswerten kann/muß, und je nach Bedarf reicht es den Modus anzugeben - zB [System.IO.Filemode]::OpenOrCreate um die Datei öffnen bzw neu zu erstellen und DANN zu öffnen, wenn es sie nicht gibt; oder ich geb zusätzlich noch den Zugriff an (lesen, schreiben, ...) und wenn ich will kann ich außerdem noch sagen, ob die Datei für den Zugriff gesperrt werden soll, während ich damit arbeite.

Genaue Beschrewibungen und Beispiele liefert die MSDN, unter PowerShell und auch unter .NET, wobei man bei letzterem die Beispiele noch in Powershell-Syntax "übersetzen" muß.


Add-Type -Assemblyname <assemblyname> fügt dem Script vorhandene Funktionalität aus .NET hinzu. Beispiel:

[system.io.compression.ziparchive] <enter> gibt einen Fehler, weil die Referenz aufs Ziparchiv noch fehlt.
WEnn man jetzt aber Add-Type -Assemblyname system.io.compression <enter> sagt und dann [system.io.compression.ziparchive] <enter> nochmal sagt, bekommt man was anderes, nämlich eine Referenz auf diese Objektklasse. (Für Ziparchive ist es sinnnvoll, außer system.io.compression auch noch system.io.compression.filesystem auf diese Art und Weise einzubinden.)



Kontrollstrukturen. PowerShell hat die faszinierende Eigenschaft, daß alles und jedes Konstrukt ein Funktional ist, ähnlich FORTRAN. Man kann einfach 5 da hinschreiben. Man kann auch $variable = if(true) {1} else {0} hinschreiben. Funktioniert. Außer if/then/else hat man noch Foreach und Where (siehe weiter unten) als Filterfunktionen.


Wie bereits angedeutet: Powershell arbeitet mit Pipelines. Ausgaben eines Befehls werden in die Eingabe des nächsten Befehls durchgereicht. Man muß dabei nicht warten, bis der erste Befehl fertig ist, sondern sobald der was liefert, landet es auch schon im nächsten.


Powershell arbeitet (seit PS3) mit Listen. Man muß nicht jedes Ergebnis einzeln anfassen, sondern man nimmt einfach die Liste her. Beispiel: Get-ChildItem -Path C:\Temp -Recurse | Remove-Item sammelt alle Dateien und Ordner unter C:\Temp zusammen und löscht diese. C:\Temp bleibt über, aber es bleibt nichts drinnen (Schreibrechte vorausgesetzt natürlich).


Manchmal nimmt aber der nächste Befehl die Liste nicht, und manchmal will man nicht alle Elemente aus der Liste haben.

Dafür gibts Foreach und Where. Innerhalb dieser Funktionen bezeichnet der Platzhalter $_ das aktuelle angeschaute Objekt. Beispiel:
Get-Childitem -Patch C:\ | Where {$_.Length -lt 1024} liefert **alle Dateien** unter C:\ , **die KLEINER als ein Kilobyte sind**
Get-ChildItem -Path C:\|Foreach {$_.Length -lt 1024} liefert **für jede Datei einen Wahrheitswert** (true oder false) je nachdem, ob "diese" Datei kleiner als 1kB war oder eben nicht.



Powershell verwendet eigene Operatoren, insbesondere Vergleichsoperatoren. Operatoren sind auch oft überladen (aber nicht immer). Muß man ggf. aufpassen. Beispiel:

1 + 1 => 2 (beides Zahlen; Zahl + Zahl = Zahl)
1,2 + 3,4 => 1,2,3,4 (beides Arrays/Listen; Liste + Liste = Liste)
1,2 + 3 => 1,2,3 Liste + Zahl = Liste
1 + 2,3 => FEHLER: Zahl plus Liste geht nicht.

Wichtige Vergleichsoperationen: -lt, -le, -eq, -ge, -gt ==>
less than (kleiner als);
less/equal (kleiner gleich);
equal (gleich)
sowie größer gleich und größer als.





Pfüh... so, das muß zum Anfang reichen. :wink:
"If you give a man a fish he is hungry again in an hour. If you teach him to catch a fish you do him a good turn."-- Anne Isabella Thackeray Ritchie

Eingefügtes Bild
Eingefügtes Bild
1

#5 Mitglied ist offline   FridayThe13 

geschrieben 19. Februar 2019 - 23:09

Vielen, vielen Dank für deine Mühe! Ich mache mich dran, sollte ich auf Schwierigkeiten oder Unklarheiten stoßen melde ich mich hier noch mal zu Wort.
0

Thema verteilen:


Seite 1 von 1

1 Besucher lesen dieses Thema
Mitglieder: 0, Gäste: 1, unsichtbare Mitglieder: 0