PowerShell Zwei csv Dateien kombinieren

RFB18

Lieutenant
Registriert
Dez. 2021
Beiträge
771
Guten Morgen,

habe hier ein Problem, was sich mit PS definitiv lösen lässt. Leider kann ich nur kein PS...

Ich habe zwei csv Dateien, eine ist ein Abbild von Kundendaten. Das Trennzeichen ist leider die Pipe (|)
Nun wird täglich eine Delta Datei erstellt, welche nur Änderungen enthält.

Ziel ist es, die Änderungen aus der Delta in die komplette csv zu übernehmen, danach die Pipe durch ein , oder ; zu ersetzen.
Das muss dann automatisiert von der Aufgabenplanung auf nem Server laufen.

Die erste Spalte enthält eine eindeutige Kundennummer, anhand dieser kann entsprechend abgeglichen werden.

Testweise habe ich mal nen Generator für sowas befragt, da kam folgendes bei raus:
Code:
<#
.SYNOPSIS
Combines two CSV files and overrides duplicates based on the first row.

.DESCRIPTION
This function takes two CSV files as input and combines them into a single CSV file.
If there are any duplicate rows based on the first row (header) of the CSV files,
the function overrides the duplicates with the rows from the second CSV file.

.PARAMETER csvFile1
The path to the first CSV file.

.PARAMETER csvFile2
The path to the second CSV file.

.PARAMETER outputCsvFile
The path to the output CSV file.

.EXAMPLE
Combine-CSVFiles -csvFile1 "C:\file1.csv" -csvFile2 "C:\file2.csv" -outputCsvFile "C:\combined.csv"
Combines file1.csv and file2.csv into combined.csv, overriding duplicates based on the first row.
#>
function Combine-CSVFiles {
    param (
        [Parameter(Mandatory=$true)]
        [string]$csvFile1,

        [Parameter(Mandatory=$true)]
        [string]$csvFile2,

        [Parameter(Mandatory=$true)]
        [string]$outputCsvFile
    )

    # Read the contents of the first CSV file
    $csv1 = Import-Csv -Path $csvFile1

    # Read the contents of the second CSV file
    $csv2 = Import-Csv -Path $csvFile2

    # Create a hashtable to store the unique rows based on the first row (header)
    $uniqueRows = @{}

    # Add rows from the first CSV file to the hashtable
    foreach ($row in $csv1) {
        $key = $row | Select-Object -First 1 | ConvertTo-Json
        $uniqueRows[$key] = $row
    }

    # Add rows from the second CSV file to the hashtable, overriding duplicates
    foreach ($row in $csv2) {
        $key = $row | Select-Object -First 1 | ConvertTo-Json
        $uniqueRows[$key] = $row
    }

    # Convert the hashtable values back to an array of rows
    $combinedCsv = $uniqueRows.Values

    # Export the combined CSV to the output file
    $combinedCsv | Export-Csv -Path $outputCsvFile -NoTypeInformation
}

Eventuell hat ja jemand etwas Langeweile und kann sich hier austoben :D
 
Was du da gefragt hast ist halt Käse. Dein Skript vergleicht Zeilen (Rows) nicht Spalten (Columns).
 
Mittlerweise habe ich eine lauffähige Version (gehabt)

Irgendwie exportiert er die .csv nicht mehr mit dem hinterlegten Delimiter, sondern mit der Pipe |
Woran könnte das denn liegen?

Code:
$FullCsv | Export-Csv -Path $FullCsvPath -Delimiter ';' -NoTypeInformation -Encoding UTF8
 
Ich würd mir das Leben hier einfacher machen und sowas statt mit Powershell mit Python machen.

Alle Files als Pandas dataframe importieren. Dann zusammenfügen und wieder als csv speichern.
Wenn sie das selbe Layout haben sollte das sehr schmerzfrei sein.

Das ganze dann automatisieren indem immer wenn ein neues File reinkommt das script neu getriggert wird und das aktuelle csv + das neue zu einem neuen kombiniert.
 
Wie gesagt, das Skript steht und lief soweit auch. Ich brauche das schlicht und automatisiert.

Da ich keine Programmierkenntnisse habe, will ich da auch wenig bis gar dran rumbasteln. Entsprechend bräuchte ich nur einen Tipp, warum der die csv nicht mehr mit den Trennzeichen ; speichert, sondern mit | aus der originaldatei.
 
Export-Csv arbeitet mit Objekten, nicht mit Strings. Wenn deine $fullcsv so aussieht:
rowA|rowB|robC
macht Export-CSV mit Delimiter ; daraus nicht
rowA;rowB;rowC

Poste mal das komplette Skript.
 
Damit lief es ohne Probleme, aber auf einmal macht er aus der Pipe eben kein ; mehr.
Mein CTI Tool kann nicht mit Pipe umgehen, daher brauche ich eben irgendwas "klassisches".

Code:
# Settings
$FullCsvPath = "$PSScriptRoot\cti_full.csv"
$InputFolderPath = "$PSScriptRoot\Input"
$ProcessedFolderPath = "$PSScriptRoot\Processed"
# --------

Clear-Host

$FullCsv = Import-Csv -Path $FullCsvPath -Delimiter '|'

$InputFiles = Get-ChildItem -Path $InputFolderPath -Filter *.csv | Sort-Object -Property LastWriteTime

$InputFiles | ForEach-Object {
    $InputCsv = Import-Csv -Path $_.FullName -Delimiter '|'

    $OutputCsv = @()
    $FullCSV | ForEach-Object {
        $FullCsvRow = $_
        $InputCsv | ForEach-Object {
            $InputCsvRow = $_
            if ($FullCsvRow.gptnr -eq $InputCsvRow.gptnr) {
                Write-Host "Found match for $($FullCsvRow.gptnr)"
                Write-Host "Replaced $($FullCsvRow.strasse) with $($InputCsvRow.strasse)"
                $FullCsvRow = $InputCsvRow
            }
        }
        $OutputCsv += $FullCsvRow
    }

    $FullCsv = $OutputCsv

    $currentDate = Get-Date -Format dd-MM-yyyy

    Move-Item -Path $_.FullName -Destination ("C:\XPhone\Processed\"+$_.BaseName+"_"+$currentDate+$_.Extension)
}
 $FullCsv | Export-Csv -Path $FullCsvPath -Delimiter ';' -notypeinformation
 
Habe ich probiert, bringt nix. Vor allem weil ich davon ausgegangen bin, dass ich hier angeben muss wie die Datei aussieht.
 
RFB18 schrieb:
Vor allem weil ich davon ausgegangen bin, dass ich hier angeben muss wie die Datei aussieht.
Das stimmt natürlich. Da hab ich mich vertan.

Allerdings irritiert mich, dass es nach deiner Aussage bereits funktioniert hat. Das kann eigentlich nicht sein, da du einen String nicht an Export-Csv übergeben kannst, sondern nur Objekte.
Edit: Und wieder nicht richtig nachgedacht von mir. 🤦‍♂️
Import-Csv erzeugt bereits Objekte.

Es ginge eigentlich nur so:

$FullCsv | Select-Object Column1, Column2, Column3 | Export-Csv -Path "output.csv" -Delimiter ';' -NoTypeInformation
Du müsstest also die einzelnen Spalten als Objekt übergeben, die dann von Export-Csv mit dem eingestellten Delimiter ausgegeben werden.


Klappt denn die Ausgabe von $Fullcsv | Format-Table?
Sind die Objekte korrekt im Array gespeichert, solltest du so eine Ausgabe in Tabellenform in der Powershell sehen können.
 
Zuletzt bearbeitet:
Habe nun den Fehler gefunden, warum das Skript nicht mehr geht. Kann aber nicht sagen woher das kommt bzw wie das behoben werden kann. Der Ersteller hat mir das gesagt, aber es gab anfangs keine Probleme. Ebenso lässt sich der Fehler in Excel nicht darstellen, nur wenn ich die csv im Editor aufmache.

Nachdem das Skript gelaufen ist, setzt es (warum auch immer) um jedes Objekt " "

Vorher: Vorname | Nachname | Adresse ....
Nachher: "Vorname" | "Nachname" | "Adresse" ...

Damit kommt unser Tool nicht klar und haut irgendwann alles durcheinander.
Jemand eine Idee? Mit dem replace würde sowas ja bestimmt gehen, aber ich habe echt keine Ahnung wie ich das vernünftig einbaue.

Im Prinzip muss einfach
Rich (BBCode):
replace('"','')
rein
 
Zuletzt bearbeitet:
Und wo muss das im Code rein? Bin wie gesagt einfach 0 fit was programmieren angeht.
Weil der Code funktioniert so definitiv, habe es heute nochmal ne Stunde in zig Versionen getestet, der Fehler ist einfach nur das " im Ergebnis-File.
 
Zurück
Oben