robdox
Goto Top

PS-Skript in Batch umwandeln

Hallo zusammen,

ich stehe wieder vor einem Problem, welches mir enorme Zeit raubt. Durch ein externes Softwareprogramm, muss ein Dateiinhalt umgewandelt werden. Das Programm kann nur Batch-Skripte ausführen. Ich muss deswegen also ein bisschen Tricksen um den Dateiinhalt zu verändern, via Powershell. Leider gibt es hier einige Probleme weswegen ich mich gezwungen fühle alles in einer Batch umzusetzen.

Hierbei gibt es folgenden Datei aufbau:

Quelldatei (eig CSV, wird aber normal als Txt behandelt)
"A,B,C,D,E,""F1,F2,F3"",G,H,I"  
...
...

Diese Konvention is jedoch falsch und müsste in:
A,B,C,D,E,"F1,F2,F3",G,H,I  
...
...

umgeändert werden. Sprich: das Erste " einer Zeile und letzte " einer Zeile muss entfernt werden, sowie das "" durch ein " ersetzt werden.

In PowerShell habe ich es so gelöst:

param($Data1, $Data2)
$check=(Get-Content $Data1)

foreach($i in $check){
 if($i.Substring(0,1) -eq '"')  
    {
    (Get-Content $Data1)| 
    %{$_.replace("(?'name'"")",'"').remove(0,1)}|   
    %{$_.replace(',""',',"')}|  
    %{$_.replace('"",','",')}|   
    %{$_.remove($_.length-1,1)}| 
    Set-Content $Data2
    }
}

Und in der Batch übergeben:
@echo off
Powershell.exe -Command "& {Start-Process Powershell.exe -ArgumentList '-ExecutionPolicy Bypass -File "CHECK.ps1 -Data1 "%1", -Data2 "%2""'}  

Leider kommt es wie oben erwähnt dazu, dass das Programm ungern ein Powershellcommand umsetzen möchte.

Wie schreibe ich die Logik von PowerShell in ein Batch-Skript um? Schon das arbeiten mit Zeichenketten kann sehr unintuitiv bei Batch werden.

Ich bedanke mich vorab recht herzlichst!

Content-ID: 568065

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

Ausgedruckt am: 22.11.2024 um 12:11 Uhr

143728
143728 28.04.2020 aktualisiert um 10:17:29 Uhr
Goto Top
@echo off
set "file=%~1"  
powershell -EP ByPass -C "((gc '%file%') -replace '^\x22|\x22$','') -replace '\x22{2}','\"' | sc '%file%'"  

mybatch.cmd "C:\mytextfile.txt"  
robdox
robdox 28.04.2020 um 10:25:29 Uhr
Goto Top
Danke für die schnelle Hilfe.

Könntest du mir die einzelnen Zeilen erklären?

Des Weiteren liefert die Konsole zurück das "sc" unbekannt ist. Also interpretiert er die Zeile nicht sauber.

Wichtig wäre dass die veränderte Datei in eine neue Ausgespuckt wird, deswegen habe ich mit %1 und %2 gearbeitet, da wir die originale nicht verändern wollen.

PS:

Heftig, das meine Zeilen code - in so einem kurzen Befehel komprimiert werden können.
143728
Lösung 143728 28.04.2020 aktualisiert um 11:54:44 Uhr
Goto Top
Zitat von @robdox:

Danke für die schnelle Hilfe.

Könntest du mir die einzelnen Zeilen erklären?

(gc '%fileIN%')  
Holt sich den Inhalt aus der Eingabedatei, (gc ist ein Alias für Get-Content)

-replace '^\x22|\x22$','')  
Ersetzt das erste Anführungszeichen am Zeilenanfang (^) und das letzte am Zeilenende ($) per Regex durch nichts. Das \x22 ist der Hex-Ascii-Code für das Anführungszeichen (Dezimal 34)

-replace '\x22{2}','\"'  
Dann noch die doppelten Anführungszeichen durch ein einzelnes ersetzen.

Des Weiteren liefert die Konsole zurück das "sc" unbekannt ist. Also interpretiert er die Zeile nicht sauber.
Das ist ein Alias für Set-Content. Wenn das deine Shell nicht kennt ist deine PS entweder zu alt, oder du hast den Alias entfernt, du kannst aber auch die anderen cmdlets wie out-file nehmen usw.
Wichtig wäre dass die veränderte Datei in eine neue Ausgespuckt wird, deswegen habe ich mit %1 und %2 gearbeitet, da wir die originale nicht verändern wollen.
Kein Problem

@echo off
set "fileIN=%~1"  
set "fileOUT=%~2"  
powershell -EP ByPass -C "((gc '%fileIN%') -replace '^\x22|\x22$','') -replace '\x22{2}','\"' | out-file '%fileOUT%'"  


Plain Batch geht auch

@echo off &setlocal enabledelayedexpansion
:: Eingabedatei aus Parameter 1 Variablen zuweisen
set "fileIN=%~1"  
:: Ausgabedatei aus Parameter 2 Variablen zuweisen
set "fileOUT=%~2"  
:: Ausgabe der FOR-Schleife an Ausgabedatei senden (FOR-Schleife verarbeitet alle nicht leeren Zeilen)
:: erste Anweisung weist den Inhalt der Zeile der Variablen "line" zu 
:: zweite Anweisung entfernt erstes und letztes Zeichen
:: dritte Anweisung ersetzt doppelte Anfürhungszeichen durch einfache
:: vierte Anweisung gibt die modifizierte Zeile aus
>"%fileOUT%" (for /f "usebackq delims=" %%a in ("%fileIN%") do (  
	set "line=%%a"  
	set "line=!line:~1,-1!"  
	set "line=!line:""="!"  
	echo.!line!
))
robdox
robdox 28.04.2020 um 11:49:26 Uhr
Goto Top
Wow! Danke face-smile

Das PowerShell versteht die aktuelle Umgebung nicht, irgendwie ist es veraltet.

Das Batch an sich klappt wunderbar, danke auch für die obige Erklärung, damit nehm ich noch was mit für die Zukunft.

Dürfte ich noch um die Auflösung vom Batch-Skript bitten? Möchte die Zeilen auch verstehen können. Danke jedoch für alles schonmal vorab!
143728
Lösung 143728 28.04.2020 aktualisiert um 11:56:09 Uhr
Goto Top
Zitat von @robdox:
Dürfte ich noch um die Auflösung vom Batch-Skript bitten? Möchte die Zeilen auch verstehen können. Danke jedoch für alles schonmal vorab!
Kommentare sind dort oben im Beitrag noch ergänzt, für die Erläuterung der Details einer FOR-Schleife einfach mal for /? in deine Konsole eingeben.
Danke jedoch für alles schonmal vorab!
Bitte, keine Ursache.
StefanKittel
StefanKittel 28.04.2020 aktualisiert um 12:12:54 Uhr
Goto Top
Moin,

Du kannst ja auch "tricksen".
Deine Batch schreibt die ps-Datei und führt sie aus.

echo "param($Data1, $Data2)" > c:\temp\convert.ps1
echo "$check=(Get-Content $Data1)" >> c:\temp\convert.ps1
Powershell.exe -executionpolicy remotesigned -File c:\temp\convert.ps1

Stefan
robdox
robdox 28.04.2020 um 12:01:39 Uhr
Goto Top
Perfekt! Danke!
robdox
robdox 28.04.2020 um 13:26:59 Uhr
Goto Top
Noch einen Nachtrag:

Es kann vorkommen das Dateien ohne das " am Anfang oder Ende auftauchen. Ich würde dies mit einer IF abprüfen, jedoch liege ich Syntaktisch etwas falsch, könnt Ihr mir hiermit noch auf die Sprünge helfen? Ich weiß nicht ob ich das " richtig maskiert habe.

@echo on &setlocal enabledelayedexpansion
set "fileIN=%~1"  
set "fileOUT=%~2"  
>"%fileOUT%" (for /f "usebackq delims=" %%a in ("%fileIN%") do (  
	set "line=%%a"	  
	if "!line:~0!" equ "^"" ( ::falls ein " an erster Stelle, dann führe die Modifikation aus, ansonsten schreibe einfach den Orginaltext in die 2. Datei.  
	set "line=!line:~1,-1!"  
	set "line=!line:""="!"  
	echo.!line!
	) else (
	echo.!line!	
	)	
))
143728
143728 28.04.2020 aktualisiert um 14:55:10 Uhr
Goto Top
Für die Prüfung in der Condition kannst du auch andere Zeichen nehmen die die Variablen umschließen, du musst dort nicht zwingend Anführungszeichen nutzen ... Du hast hier aber in der Zeichenextraktion aber auch einen Fehler eingebaut...

>"%fileOUT%" (for /f "usebackq delims=" %%a in ("%fileIN%") do (  
	set "line=%%a"  
        echo.!line!|findstr /b """" >nul 2>&1 && (  
            set "line=!line:~1,-1!"  
            set "line=!line:""="!"  
        )
  echo.!line!
))

Zm Escaping siehe
https://www.robvanderwoude.com/escapechars.php
mayho33
mayho33 28.04.2020 um 14:18:24 Uhr
Goto Top
Hi!

Eine Alternative zum Umwandeln von . ps1 zu .cmd oder .bat wäre, dem Batch einfach die Ausführung der PS-Scripte zu befehlen:

Powershell.Exe -ExecutionPolicy Bypass -File "Pfad zum PS-Script"  

So würdest du dir viel Zeit ersparen wegen des Umwandeln des PS-Codes und den vielen Eventualitäten die da auftreten könnten.

Grüße!
robdox
robdox 28.04.2020 um 14:26:13 Uhr
Goto Top
Hallo Cabrinha,

danke für Deine Geduld und Input! Sehr interessante dass man auch die [ ] verwenden kann. Warum kann jedoch die Condition nicht bearbeitet werden? - Sah für mich so perfekt aus...

C:\PROJEKTE\DATEN\Skripte>IDENT.bat 1a.csv 1b.csv
"1!]" kann syntaktisch an dieser Stelle nicht verarbeitet werden.  

@echo off &setlocal enabledelayedexpansion
set "fileIN=%~1"  
set "fileOUT=%~2"  
>"%fileOUT%" (for /f "usebackq delims=" %%a in ("%fileIN%") do (  
	set "line=%%a"  
	if [!line:~0,1!] == ["] (  
	  set "line=!line:~1,-1!"  
	  set "line=!line:""="!"  
	)
	echo.!line!
))

Wiedermal danke für Deine Mühe!
robdox
robdox 28.04.2020 um 14:29:14 Uhr
Goto Top
Hallo mayho33,

diese Alternativen habe ich leider schon alle durch. Hierbei liegt es nicht am Batch sondern eher an dem externen Programm was die weitere verarbeitung einer zusätzlichen Shell nicht zulässt.
143728
143728 28.04.2020 aktualisiert um 14:57:24 Uhr
Goto Top
Ach nee das gibt Kuddel, mach den FOR-Teil besser so
>"%fileOUT%" (for /f "usebackq delims=" %%a in ("%fileIN%") do (  
	set "line=%%a"  
        echo.!line!|findstr /b """" >nul 2>&1 && (  
            set "line=!line:~1,-1!"  
            set "line=!line:""="!"  
        )
        echo.!line!
))
robdox
robdox 28.04.2020 um 15:17:49 Uhr
Goto Top
Das klappt super! Kann man bei einer Batchauch "pipen"? mit | ?
Und: Das kurze warten von 2 sek, wieso müssen wir dies tun in der Verarbeitung? Damit er erstmal alle Zeilen überprüft und dann verändert ggf.?

Danke vorab! face-smile
143728
Lösung 143728 28.04.2020 aktualisiert um 15:53:38 Uhr
Goto Top
Zitat von @robdox:

Das klappt super! Kann man bei einer Batchauch "pipen"? mit | ?
Ja.
Und: Das kurze warten von 2 sek, wieso müssen wir dies tun in der Verarbeitung? Damit er erstmal alle Zeilen überprüft und dann verändert ggf.?
Du sprichst in Rätseln ??
Ausgeben lassen kannst du dir alles mit echo und Abfragen kannst du machen mit set /p oder choice. Einfach mal das Manual lesen face-smile. So denn, tschö mit ö.
robdox
robdox 28.04.2020 um 19:01:33 Uhr
Goto Top
face-smile Danke Dir! Ja hab den Code falsch interpretiert. Wahnsinnig kompetent, danke für Deinen Support!! Konnte einiges lernen!