hacktrist
Goto Top

CSV Datei in PS bearbeiten und wieder speichern

Hallo Liebe Administrator Gemeinde.

Ich habe folgendes Anliegen, ich habe eine immer wieder kehrende Aufgabe welche ich gern automatisieren möchte.

Es gibt eine Date welche zum Beispiel "Pfusch1.csv" heißt und im Ordner C:\ErstePSErfahrung\ liegt.
Die csv Datei hat ein ; als trennzeichen und ist mit folgendem Inhalt versehen.

Spalte1;Spalte2;;;Spalte5;Spalte6;
Spalte1;Spalte2;;;Spalte5;Spalte6;

daraus möchte ich nun den Inhalt der Spalte2 löschen (aber nicht die ganze Spalte).

Spalte1;;;;Spalte5;Spalte6;
Spalte1;;;;Spalte5;Spalte6;

Im Anschluss soll die Datei wieder im Ordner C:\ErstePSErfahrung\ gespeichert werden.

Ich könnte mir das unter Linux durch einen Import, den sed Befehl und anschließendem Export schreiben.
 sed -e 's,^\([^;]*\);[^;]*;\(.*\),\1;;\2,'  

Von Powershell haber ich bisher noch keine Erfahrungen sammeln können und hoffe auf Eure Unterstützung.

Beginnen würde ich das Skript mit
Get-Content C:\ErstePSErfahrung\Pfusch1.csv 

Content-ID: 665779

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

Ausgedruckt am: 24.11.2024 um 09:11 Uhr

TK1987
Lösung TK1987 15.04.2021 aktualisiert um 14:36:13 Uhr
Goto Top
Moin,

Zitat von @Hacktrist:
Beginnen würde ich das Skript mit
Get-Content C:\ErstePSErfahrung\Pfusch1.csv 
besser direkt mit Import-CSV, so kannst du die Spalten auch direkt ansteuern.
$CSV = Import-CSV -Delimiter ';' -Path 'C:\ErstePSErfahrung\Pfusch1.csv' -Header (1..6)  
Foreach ($Line in $CSV) { $Line.2 = '' }  
$CSV | Export-Csv -Delimiter ';' -NoTypeInformation 'C:\ErstePSErfahrung\Pfusch1_neu.csv'  

Von Powershell habe ich bisher noch keine Erfahrungen sammeln können und hoffe auf Eure Unterstützung.

Ein bisschen was zum lesen:

Gruß Thomas
Hacktrist
Hacktrist 15.04.2021 aktualisiert um 14:51:21 Uhr
Goto Top
Hallo Thomas, erstmal WOW und ein aufrichtiges Dankeschön für die schnelle Antwort.
Wenn ich das Skript so ausführe kommt bei mir folgendes.

Liegt das an meinem neuen Rechner? Entschuldige bitte da meine Erfahrungen in Powershell wie gesagt erst starten.

Set-ExecutionPolicy : Die Ausführungsrichtlinien wurden von Windows PowerShell erfolgreich aktualisiert, die
Einstellung wird jedoch von einer in einem spezielleren Bereich definierten Richtlinie überschrieben. Aufgrund der
Überschreibung wird die aktuelle geltende Ausführungsrichtlinie "RemoteSigned" für die Shell beibehalten. Geben Sie  
"Get-ExecutionPolicy -List" ein, um die Ausführungsrichtlinieneinstellungen anzuzeigen. Weitere Informationen erhalten  
Sie mit "Get-Help Set-ExecutionPolicy".  
In Zeile:1 Zeichen:46
+ ...  -ne 'AllSigned') { Set-ExecutionPolicy -Scope Process Bypass }; & 'C ...  
+                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : PermissionDenied: (:) [Set-ExecutionPolicy], SecurityException
    + FullyQualifiedErrorId : ExecutionPolicyOverride,Microsoft.PowerShell.Commands.SetExecutionPolicyCommand

Cmdlet Export-Csv an der Befehlspipelineposition 1
Geben Sie Werte für die folgenden Parameter an:
InputObject:

Drücke ich daraufhin [ENTER] wird mir eine Pfusch_neu.csv erstellt, jedoch nur mitr dem Inhalt "Lenght 1"
TK1987
TK1987 15.04.2021 aktualisiert um 15:00:50 Uhr
Goto Top
Wie genau hast du das Skript ausgeführt?

back-to-topGeht am einfachsten so:
1) Datei als .ps1-Datei abspeichern.
2) Von der Datei eine Verknüpfung machen (Rechtsklick > kopieren und dann Rechtsklick > Verknüpfung einfügen)
3) In den Verknüpfungseigenschaften sollte bei "Ziel" bereits der Pfad zum ps1-Skript stehen. Vor diesem musst du noch powershell -EP ByPass -File ergänzen. Vollständig sollte die Zeile dann so aussehen:
powershell -EP ByPass -File "C:\Pfad\zum\Skript.ps1"
Falls das Konsolenfenster auch nach Beenden des Skripts geöffnet bleiben soll, ergänzt man zusätzlich noch -NoExit
powershell -EP ByPass -NoExit -File "C:\Pfad\zum\Skript.ps1"
Ausgeführt wird dann immer die Verknüpfung

Zitat von @Hacktrist:
In Zeile:1 Zeichen:46
+ ...  -ne 'AllSigned') { Set-ExecutionPolicy -Scope Process Bypass }; & 'C ...
+                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Das ist aber nicht das Skript, welches ich gepostet habe.

back-to-topDie ExcecutionPolicy setzt man einmalig über folgenden Befehl...

back-to-top... entweder global für alle Benutzer (Powershell muss mit Administratorrechten gestartet werden):
Set-ExecutionPolicy RemoteSigned -Force
back-to-top... oder nur für den aktuell angemeldeten Benutzer:
Set-ExecutionPolicy -Scope CurrentUser RemoteSigned -Force

Wenn man die ExcecutionPolicy gesetzt hat, kann man bei der Verknüpfung das -EP ByPass weglassen.
Doskias
Doskias 15.04.2021 um 15:08:54 Uhr
Goto Top
Moin
Wenn man die ExcecutionPolicy gesetzt hat, kann man bei der Verknüpfung das -EP ByPass weglassen.

Aber Achtung es gibt 5 verschiedene Executions-Policies. Je nachdem wie du dein Skript ausführst, greift ggf. eine andere:

Get-ExecutionPolicy -list

Gruß
Doskias
Hacktrist
Hacktrist 15.04.2021 um 15:16:14 Uhr
Goto Top
Es erscheint folgendes:

Cmdlet Export-Csv an der Befehlspipelineposition 1
Geben Sie Werte für die folgenden Parameter an:
InputObject:
Doskias
Doskias 15.04.2021 um 15:20:31 Uhr
Goto Top
Dann fehlt ein Parameter. Wie sieht denn der Befehl aus, den du eingegeben hast?
TK1987
TK1987 15.04.2021 aktualisiert um 15:23:46 Uhr
Goto Top
Dann warst du zu flott beim kopieren, hatte meinen Kommentar oben noch nachträglich angepasst (Zeile 3) 😁.
Hacktrist
Hacktrist 15.04.2021 aktualisiert um 15:34:34 Uhr
Goto Top
face-smile Du hast recht, das $CSV am Anfang hatte gefehlt. Hätte mir aber auch auffallen können.

Meine Ursprüngliche CSV Datei hat jedoch keinen Header. Wenn ich jetzt in Zeile 1 Schaue wird ja jede Spalte mit 1, 2, 3, 4, 5, 6 gekennzeichnet.
Können wir das entfallen lassen, so dass die csv direkt mit dem Ursprünglichen Werten beginnt (ohne Header)?

Ich habe schon versucht das
-Header (1..6)
wegzulassen, was jedoch nicht funktioniert. Da läuft es auf Fehler und die Datei ist leer.
TK1987
Lösung TK1987 15.04.2021 um 15:37:58 Uhr
Goto Top
Zitat von @Hacktrist:
Meine Ursprüngliche CSV Datei hat jedoch keinen Header.
Richtig, hätte ich auch selbst drauf kommen können,sorry:
$CSV | ConvertTo-Csv -NoTypeInformation -Delimiter ';' | Select -Skip 1 | Set-Content 'C:\ErstePSErfahrung\Pfusch1_neu.csv'  
Hacktrist
Hacktrist 15.04.2021 um 15:45:14 Uhr
Goto Top
Thomas: Vielen Lieben Dank.

Vielleicht beschreibst Du mir noch kurz die genauen Dinge welche in Zeile 3 und 4 bei den Befehlen genau getan werden. Also als Kommentare, damit ich es auch verstehe und nicht nur copy paste nutze.
TK1987
Lösung TK1987 15.04.2021 aktualisiert um 17:37:46 Uhr
Goto Top
Vielleicht beschreibst Du mir noch kurz die genauen Dinge welche in Zeile 3 und 4 bei den Befehlen genau getan werden.
Der Befehl oben soll Zeile 3 eigentlich ersetzen - es gibt also keine Zeile 4.

Vielleicht fangen wir mal besser ganz vorne an...

back-to-topWarum Import-CSV statt Get-Content?
Get-Content liest eine Datei als Text-Datei ein. Import-CSV hingegen wandelt die CSV-Datei in ein Objekt um, mit den Spalten als Eigenschaften.

Zum besseren Verständnis, die einzelnen Befehlszeilen einfach mal in Powershell ausführen und sich den Inhalt der Variable anzeigen lassen:
$CSV = Import-CSV -Delimiter ';' -Path 'C:\ErstePSErfahrung\Pfusch1.csv' -Header (1..6)  
$CSV
als Ausgabe bekommst du sowas:
1       2       3 4 5       6
-       -       - - -       -
Spalte1 Spalte2     Spalte5 Spalte6
Spalte1 Spalte2     Spalte5 Spalte6
Hinweis: Lass dich nicht verunsichern, falls das Objekt bei dir als Liste angezeigt wird. Je nach Fenstergröße wechselt Powershell bei mehreren Spalten irgendwann zur Listenanzeige.
Möchte man explizit eine bestimmte Anzeige, kann man das Objekt einfach in Format-Table bzw. Format-List pipen.
$CSV | Format-Table

Der Vorteil eines Objekt, liegt darin, das wir nun die Zeilen, Spalten und Zellen unserer Tabelle einzeln ansprechen können:
$CSV     # Gibt die Zeile mit dem Index 0 aus ( Index = Zeilennummer -1 )
$CSV.5      # Gibt die Spalte mit dem Header 5 aus
$CSV[1].6   # Gibt von Zeile 2 die 6. Spalte aus (in Excel also Zelle "F2") 

back-to-topZeile 2
Foreach ($Line in $CSV) { $Line.2 = '' }  
Sollte denke ich selbsterklärend sein. Für jede Zeile unseres Objekts ersetzen wir die Spalte mit dem Header "2" mit einer leeren Zeichenkette.

Nun zu deinem Problem von eben:
Ich habe schon versucht das
-Header (1..6)
wegzulassen, was jedoch nicht funktioniert. Da läuft es auf Fehler und die Datei ist leer.
Wenn du den Header-Parameter bei Import-CSV weglässt, geht Powershell davon aus, dass in Zeile 1 deiner CSV-Datei Spaltenüberschriften stehen - und nimmt diese dann als Header.

Wenn deine CSV-Datei also z.B. so aussähe:
Vorname;Nachname;Telefon
Otto;Müller;12345
Hans;Dieter;67890
könntest du anschließend z.B. mit
$CSV.Nachname
die Spalte mit den Nachnamen aufrufen.

In deinem Fall führt das zu einem Fehler, da jede Spalte einen eindeutigen Namen haben muss. Zudem können wir dann natürlich nicht mehr die Spalte mit dem Namen "2" aufrufen, da es diese nicht gibt.

back-to-topDie Ausgabe...
Export-CSV Wandelt unser Objekt wieder in eine Textdatei in CSV-Formatierung um; und speichert diese ab - allerdings immer mit Überschriften.
ConvertTo-CSV wandelt das Objekt genauso um, jedoch ohne es abzuspeichern. Führe nur folgendes aus:
$CSV | ConvertTo-Csv -NoTypeInformation -Delimiter ';'  
Als Ergebnis erhälst du wieder deine Datei - auch hier derzeit noch mit Header. Hier kommt Select-Object ins Spiel, welches mit dem Parameter -Skip 1 die erste Zeile überspringt. Mit Set-Content wird die Datei dann abgespeichert.

Wir könnten die Schritte natürlich auch einzeln ausführen:
$CSV = $CSV | ConvertTo-CSV -nti -d ';'      # Objekt in Textdatei konvertieren  
$CSV = $CSV | Select-Object -Skip 1          # Erste Zeile überspringen
$CSV | Set-Content 'Neu.CSV'                 #Datei abspeichern  

back-to-topZur Vervollständigung:
Prinzipiell könnten wir natürlich auch - wie du es vor hattest - mit Get-Content arbeiten und wie mit sed einen regex-replace machen:
$Text = Get-Content 'C:\ErstePSErfahrung\Pfusch1.csv'  
$Text = $Text -replace '^([^;]*);[^;]*;(.*)','$1;;$2'  
$Text | Set-Content 'C:\ErstePSErfahrung\Neu.CSV'  
oder als Einzeiler:
(Get-Content 'C:\ErstePSErfahrung\Pfusch1.csv')  -replace '^([^;]*);[^;]*;(.*)','$1;;$2' | Set-Content  'C:\ErstePSErfahrung\Neu.CSV'  
Hacktrist
Hacktrist 15.04.2021 um 21:21:37 Uhr
Goto Top
Du bist der Beste.
Ich habe es verstanden. Danke.
Hacktrist
Hacktrist 16.04.2021 um 08:08:20 Uhr
Goto Top
Ich habe doch noch 1 Problem. Und zwar wenn ich das Skript über die CSV laufen lasse, sind plötlich alle Einträge mit "" gekennzeichnet.
Auch die leeren Spalten sind nun mit den Gänsefüßchen eingetragen.

Kann man das ändern?
TK1987
Lösung TK1987 16.04.2021 um 08:48:30 Uhr
Goto Top
Zitat von @Hacktrist:

Ich habe doch noch 1 Problem. Und zwar wenn ich das Skript über die CSV laufen lasse, sind plötzlich alle Einträge mit "" gekennzeichnet.
Jo, das entspricht allerdings auch dem Dateiaufbau des CSV-Formats, wird bei der Verwendung von Sonderzeichen sogar zwingend erforderlich.
Kann man das ändern?
Mit Regex kann man alles 😉
($CSV | ConvertTo-CSV -d ';' -nti) -replace '(?<=^|;)"|"(?=;|$)' | Select -Skip 1 | sc 'C:\ErstePSErfahrung\Neu.CSV'  
    • sc ist ein Alias für Set-Content
    • select ist ein Alias für Select-Object
Hacktrist
Hacktrist 16.04.2021 um 08:55:36 Uhr
Goto Top
Du bist der Beste
Hacktrist
Hacktrist 19.04.2021 aktualisiert um 08:31:34 Uhr
Goto Top
Hey Thomas,

ich habe wirklich lange gesucht, aber im NEtz nicht gefunden.

Wie gehe ich denn vor, um z.B. den Pfad C:\ErstePSErfahrung\ durch eine manuelle eingabe zu ersetzen?
Also so dass das Skript ausgeführt wird, dann der Order manuell eingegeben wird und zusätzlich noch das \Pfusch1.csv angehängt wird.

Gruß
Tristan
TK1987
TK1987 19.04.2021 aktualisiert um 08:57:07 Uhr
Goto Top
Moin,

das ginge mit Read-Host
$Ordner = Read-Host "Ordnername eingeben"  
anschließend mit Test-Path überprüfen, ob der Ordner existiert.

... oder man nutzt den grafischen Dialog:
# Klasse für grafische Oberflächen laden
Add-Type -AssemblyName System.Windows.Forms

# Öffnendialog erstellen
$Open = New-Object System.Windows.Forms.OpenFileDialog -Property @{
  Title  = "Öffne CSV-Datei"   
  Filter = 'CSV-Dateien|*.csv|Alle Dateien|*.*'  
  }
  
# Dialog starten
[void]$Open.ShowDialog()

# Ergebnis anzeigen
$Open.FileName

Gruß Thomas
Hacktrist
Hacktrist 19.04.2021 aktualisiert um 09:27:54 Uhr
Goto Top
O.k.
Und wie übergebe ich den $Ordner in den Import + Datei.csv? (hier Zeile 3)
Ich habs mal einfach mit -Path '$Ordner\datei.csv' versucht. Da crasht er aber.


$Ordner = Read-Host "Ordnername eingeben"  

#CSV Datei importieren
$CSV = Import-CSV -Delimiter ';' -Path '$Ordner\Vorlage.csv' -Header (1..14)  

#Spalte 2 leeren
Foreach ($Line in $CSV) { $Line.2 = '' }  

#CSV Datei unter neuen Namen speichern und Gänsefüßchen entfernen
($CSV | ConvertTo-CSV -d ';' -nti) -replace '(?<=^|;)"|"(?=;|$)' | Select -Skip 1 | sc 'H:\Arbeitsordner\Vorlage_neu.csv'  
TK1987
TK1987 19.04.2021 aktualisiert um 09:40:36 Uhr
Goto Top
Zitat von @Hacktrist:
O.k.
Und wie übergebe ich den $Ordner in den Import + Datei.csv? (hier Zeile 3)
Ich habs mal einfach mit -Path '$Ordner\datei.csv' versucht. Da crasht er aber.
Mit Single-Quotes übergibt er die Zeichenkette exakt so wie sie ist, also inklusive Dollarzeichen, ohne die Variable aufzulösen. Damit die Variable interpretiert wird, musst du Double-Quotes verwenden.
$CSV = Import-CSV -Delimiter ';' -Path "$Ordner\Vorlage.csv" -Header (1..14)  

Um das gleich vorweg zu nehmen: So werden nur Variablen selbst interpretiert, nicht aber Eigenschaften eines Objekts.
Wenn du z.B. den Ordnernamen auch aus einer CSV-Datei holst, musst du, um Eigenschaften ebenfalls auszuwerten, mit $() arbeiten (solltest du ja bereits von Bash kennen). Beispiel:
$CSV = Import-CSV -Delimiter ';' -Path "$($CSV.Ordner)\Vorlage.csv" -Header (1..14)  
Hacktrist
Hacktrist 19.04.2021 aktualisiert um 10:03:59 Uhr
Goto Top
Ich Habs raus gefunden. Der $Ordner muss direkt hinter -Path angegeben werden.

$CSV = Import-CSV -Delimiter ';' -Path $Ordner'\Vorlage.csv' -Header (1..14)  

Aber das mit den Doppelquotes würde auch funktionieren, ja.

Danke Thomas
Hacktrist
Hacktrist 19.04.2021 um 11:16:21 Uhr
Goto Top
Thomas kannst du mir als letztes noch zeigen wie ich direkt die Datei inkusive Ordnerangabe (durch manuelle Pfadangabe) lade und diese Datei dann mit der Endung _neu.csv in den gleichen Ordner speichern lasse?
TK1987
Lösung TK1987 19.04.2021 aktualisiert um 13:47:23 Uhr
Goto Top
Zitat von @Hacktrist:
Thomas kannst du mir als letztes noch zeigen wie ich direkt die Datei inkusive Ordnerangabe (durch manuelle Pfadangabe) lade
Wenn ich das richtig verstehe, also mit kompletter Dateipfad-Eingabe?
# Frage nach Dateipfad, bis ein gültiger Pfad eingegeben wurde. 
while ($true) {
  $Pfad = Read-Host "Dateipfad eingeben"  
  if (Test-Path -PathType Leaf $Pfad) {
    $Pfad = Get-Item $Pfad
    break
    }
  else {write-host -ForegroundColor 'red' "'$Pfad' ist kein gültiger Dateipfad. Bitte erneut versuchen. "}  
}

# CSV-Datei importieren (ipcsv ist ein Alias für Import-CSV)
$CSV = ipcsv -d ';' $Pfad.fullname -header (1..14)  

# Mache was auch immer mit der CSV
# ...

# Neuer Dateiname
$NewName = $Pfad.DirectoryName + '\' + $Pfad.Basename + '_neu' + $Pfad.Extension  

# CSV-Datei exportieren
($CSV | ConvertTo-CSV -nti -d ';') -replace '(?<=^|;)"|"(?=;|$)' | Select -Skip 1 | sc $NewName  

Die Sinnhaftigkeit stelle ich hier allerdings mal infrage. Sowas würde ich...
  • entweder, wie oben erwähnt, über einen grafischen Dialog lösen
  • oder über ein Kontextmenüeintrag. So bräuchtest du nur im Explorer auf eine CSV-Datei rechtsklicken und könntest diese Datei über einen Eintrag direkt an das Skript senden.
Hacktrist
Hacktrist 20.04.2021 um 14:03:26 Uhr
Goto Top
Hey Thomas, das mit der graphischen Oberfläche ist ja cool. Habe bisher noch nicht gewusst, dass Power Shell so mächtig ist.
Nur Interesse halber, wie kann ich das geladene Objekt an den Rest des Scripts übergeben?

In Linux würde ich einfach das Objekt wie folgt übergeben und dann die beiden Skripte verbinden.
$Open=$CSV (Zeile 16)

Aber ich vermute mal das ist totaler Quatsch!?!

# Klasse für grafische Oberflächen laden
Add-Type -AssemblyName System.Windows.Forms

# Öffnendialog erstellen
$Open = New-Object System.Windows.Forms.OpenFileDialog -Property @{
  Title  = "Öffne CSV-Datei"   
  Filter = 'CSV-Dateien|*.csv|Alle Dateien|*.*'  
  }
  
# Dialog starten
[void]$Open.ShowDialog()

# Ergebnis anzeigen
$Open.FileName

$Open=$CSV

# CSV-Datei importieren (ipcsv ist ein Alias für Import-CSV)
$CSV = ipcsv -d ';' $Pfad.fullname -header (1..14)  

#Spalte 2 leeren
Foreach ($Line in $CSV) { $Line.2 = '' }  

# Neuer Dateiname
$NewName = $Pfad.DirectoryName + '\' + $Pfad.Basename + '_neu' + $Pfad.Extension  

# CSV-Datei exportieren
($CSV | ConvertTo-CSV -nti -d ';') -replace '(?<=^|;)"|"(?=;|$)' | Select -Skip 1 | sc $NewName  
TK1987
TK1987 20.04.2021 aktualisiert um 14:38:02 Uhr
Goto Top
Zitat von @Hacktrist:
Hey Thomas, das mit der graphischen Oberfläche ist ja cool. Habe bisher noch nicht gewusst, dass Power Shell so mächtig ist.
Noch viel mächtiger, als du derzeit ahnst 😎. Auch das erstellen komplett eigener GUI-Oberflächen für ein Skript ist ganz leicht möglich.

Nur Interesse halber, wie kann ich das geladene Objekt an den Rest des Scripts übergeben?
Zu dem Zweck war das mit dem Ergebnis anzeigen gedacht. Also einfach:
$CSV = ipcsv -d ';' $Open.Filename -header (1..14)  

Beachte allerdings, das es auch möglich ist, das der User das Öffnen der CSV-Datei abbricht, ohne eine Datei ausgewählt zu haben.
Alle weiteren Schritte würden dann natürlich zu einem Fehler führen - um das auszuschließen, einfach vorweg:
if (! $Open.Filename) {Return}
Falls die Filename-Eigenschaft leer ist, wird das Skript so automatisch beendet.
Hacktrist
Hacktrist 20.04.2021 um 14:39:34 Uhr
Goto Top
Es hängt jetzt in Zeile 23 oder 26 mit dem Fehler Der Zugriff auf den Pfad "C:\_neu" wurde verweigert

# Klasse für grafische Oberflächen laden
Add-Type -AssemblyName System.Windows.Forms

# Öffnendialog erstellen
$Open = New-Object System.Windows.Forms.OpenFileDialog -Property @{
  Title  = "Öffne CSV-Datei"   
  Filter = 'CSV-Dateien|*.csv|Alle Dateien|*.*'  
  }
  
# Dialog starten
[void]$Open.ShowDialog()

# Ergebnis anzeigen
$Open.FileName

# CSV-Datei importieren (ipcsv ist ein Alias für Import-CSV)
$CSV = ipcsv -d ';' $Open.Filename -header (1..14)  

#Spalte 2 leeren
Foreach ($Line in $CSV) { $Line.2 = '' }  

# Neuer Dateiname
$NewName = $Open.DirectoryName + '\' + $Open.Basename + '_neu' + $Open.Extension  

# CSV-Datei exportieren
($CSV | ConvertTo-CSV -nti -d ';') -replace '(?<=^|;)"|"(?=;|$)' | Select -Skip 1 | sc $NewName  
TK1987
Lösung TK1987 20.04.2021 aktualisiert um 17:07:28 Uhr
Goto Top
Zitat von @Hacktrist:
Es hängt jetzt in Zeile 23 oder 26 mit dem Fehler Der Zugriff auf den Pfad "C:\_neu" wurde verweigert
# Neuer Dateiname
$NewName = $Open.DirectoryName + '\' + $Open.Basename + '_neu' + $Open.Extension  
Das Objekt in deiner $Open-Variable enthält auch keine Eigenschaft wie DirectoryName,BaseName oder Extension.

Deshalb sagte ich, guck dir am besten immer in Powershell den Inhalt deiner Variable an.

In den meisten Fällen reicht es, einfach den Variablennamen auszuführen:
$Open

gibt dir dann folgende Ausgabe zurück:
CheckFileExists              : True
Multiselect                  : False
ReadOnlyChecked              : False
ShowReadOnly                 : False
SafeFileName                 : Datei.csv
SafeFileNames                : {Datei.csv}
AddExtension                 : True
CheckPathExists              : True
DefaultExt                   :
DereferenceLinks             : True
FileName                     : C:\test\Datei.csv
FileNames                    : {C:\test\Datei.csv}
Filter                       : CSV-Dateien|*.csv|Alle Dateien|*.*
FilterIndex                  : 1
InitialDirectory             :
RestoreDirectory             : False
ShowHelp                     : False
SupportMultiDottedExtensions : False
Title                        : Öffne CSV-Datei
ValidateNames                : True
CustomPlaces                 : {}
AutoUpgradeEnabled           : True
Tag                          :
Site                         :
Container                    :

Das sind die Eigenschaften, die dein Objekt besitzt.

Hier bringt uns in dem Fall also lediglich die Filename-Eigenschaft weiter (oder die Filenames-Eigenschaft, wenn du vor dem starten des Dialogs die Multiselect-Eigenschaft auf $true setzt, um auch mehrere Dateien gleichzeitig auswählen zu können).

Nun sehen wir uns mal an, welcher Typ in der Eigenschaft Filename liegt:
$Open.Filename.GetType()
gibt folgende Ausgabe:
IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     String                                   System.Object

Die Eigenschaft ist nur vom Typ [string], also liegt der Pfad hier lediglich als Zeichenkette vor, nicht als Objekt mit Eigenschaften.

Also laden wir die Datei aus dem Dateisystem:
$File = Get-Item $Open.Filename
In dem Fall reicht ein einfaches aufrufen des Variablennamen nicht, um dir alle Eigenschaften anzeigen zu lassen.
Da ein Dateisystemobjekt recht viele Eigenschaften besitzt, wurden einige der Übersichtlichkeit halber ausgeblendet.

Man kann entweder mit Get-Member die Eigenschaften,Events und Methoden anzeigen lassen, die ein Objekt besitzt (allerdings nicht den Wert zu einer Eigenschaft)
$File | Get-Member

oder man verwendet wieder Select-Object, diesmal mit dem Parameter -Property *
$File | Select *
So werden alle Eigenschaften angezeigt, die nützlich sein könnten. Die Ausgabe zeigt hier
PSPath            : Microsoft.PowerShell.Core\FileSystem::C:\test\Datei.csv
PSParentPath      : Microsoft.PowerShell.Core\FileSystem::C:\test
PSChildName       : Datei.csv
PSDrive           : C
PSProvider        : Microsoft.PowerShell.Core\FileSystem
PSIsContainer     : False
Mode              : -a----
VersionInfo       : File:             C:\test\Datei.csv
                    InternalName:
                    OriginalFilename:
                    FileVersion:
                    FileDescription:
                    Product:
                    ProductVersion:
                    Debug:            False
                    Patched:          False
                    PreRelease:       False
                    PrivateBuild:     False
                    SpecialBuild:     False
                    Language:

BaseName          : Datei
Target            : {}
LinkType          :
Name              : Datei.csv
Length            : 322
DirectoryName     : C:\test
Directory         : C:\test
IsReadOnly        : False
Exists            : True
FullName          : C:\test\Datei.csv
Extension         : .csv
CreationTime      : 01.04.2021 12:25:25
CreationTimeUtc   : 01.04.2021 10:25:25
LastAccessTime    : 20.04.2021 11:40:41
LastAccessTimeUtc : 20.04.2021 09:40:41
LastWriteTime     : 19.04.2021 16:27:46
LastWriteTimeUtc  : 19.04.2021 14:27:46
Attributes        : Archive

Wie man sieht besitzt unser Objekt nun sowohl die Eigenschaft DirectoryName mit dem DateiPfad, sowie BaseName mit dem Dateinamen ohne Erweiterung, als auch Extension mit der Dateierweiterung.

Daher:
$File = Get-Item $Open.FileName
$NewName = $File.DirectoryName + '\' + $File.Basename + '_neu' + $File.Extension  

Du solltest wirklich mal den Anfängerleitfaden durchgehen, den ich oben gepostet habe. Da wird das alles noch viel verständlicher erklärt, als ich das hier mal eben runterbeten könnte.
Hacktrist
Hacktrist 21.04.2021 um 06:53:44 Uhr
Goto Top
O.k. Ich mache mich sofort an den Leitfaden von oben.

Danke
Hacktrist
Hacktrist 21.04.2021 um 08:40:38 Uhr
Goto Top
Hier nochmal die Lösung für Alle, die im Forum auf das gleiche Problem stoßen.

Sinn und Zweck des Codes ist es eine CSV Datei öffnen zu lassen, eine Spalte zu leeren und die Datei im gleichen Ordner wieder mit der Endung _neu.csv zu speichern.

Ein rießen Dank geht raus an @TK1987

# Klasse für grafische Oberflächen laden
Add-Type -AssemblyName System.Windows.Forms

# Öffnendialog erstellen
$Open = New-Object System.Windows.Forms.OpenFileDialog -Property @{
  Title  = "Öffne CSV-Datei"   
  Filter = 'CSV-Dateien|*.csv|Alle Dateien|*.*'  
  }
  
# Dialog starten
[void]$Open.ShowDialog()

# Ergebnis anzeigen
$Open.FileName

# CSV-Datei importieren (ipcsv ist ein Alias für Import-CSV)
$CSV = ipcsv -d ';' $Open.Filename -header (1..14)  

#Spalte 2 leeren
Foreach ($Line in $CSV) { $Line.2 = '' }  

# Neuer Dateiname
$File = Get-Item $Open.FileName
$NewName = $File.DirectoryName + '\' + $File.Basename + '_neu' + $File.Extension  

# CSV-Datei exportieren
($CSV | ConvertTo-CSV -nti -d ';') -replace '(?<=^|;)"|"(?=;|$)' | Select -Skip 1 | sc $NewName