stefan4711 3 Geschrieben 13. November 2021 Melden Teilen Geschrieben 13. November 2021 Hallo werte Forengemeinde, ich beisse mich seit einigen Tagen an einem Problem fest, was wohl laut diverser Foren viele haben, dafür gab es auch schon haufenweise Lösungsvorschläge, aber nichts davon führte bei mir zum Erfolg. Es geht darum dass ich eine Inventarliste im CSV Format (kommagetrennt) habe, die sieht folgendermassen aus (Spaltenanzahl und Zeilenanzahl aus Komplexitätsgründen gekürzt) Zitat Hostname Timestamp Serial Number Manufacturer Model RTA190504 11.11.2021 14:25 S4JY3833 LENOVO 30C5003CGE RTA200601 11.11.2021 12:23 CZC02286W9 HP HP ProDesk 600 RTA201201 27.09.2021 08:39 33M6933 Dell Inc. OptiPlex 3070 RTX54011 15.07.2021 18:19 7739-6127 Microsoft Virtual Machine NTX210708 12.11.2021 21:02 PF2WCBGR LENOVO 82GN NTX210708 13.11.2021 11:31 PF2WCBGR LENOVO 82GN NTX210708 13.11.2021 11:32 PF2WCBGR LENOVO 82GN NTX210708 13.11.2021 11:30 PF2WCBGR LENOVO 82GN NTX210708 13.11.2021 11:31 PF2WCBGR LENOVO 82GN NTX210708 13.11.2021 11:33 PF2WCBGR LENOVO 82GN Wie hier deutlich zu sehen sind von NTX210708 mehere Einträge vorhanden. Ist es möglich per Batch oder auch per PS alle doppelten Zeilen zu löschen, Dabei sollen die Zeilen behalten werden die dem aktuellstzen Timestamp entsprechen. In dem Fall von NTX... also der letzte. Vielleicht hat ja einer eine Idee? lg und schönes we Stef Zitieren Link zu diesem Kommentar
testperson 1.707 Geschrieben 13. November 2021 Melden Teilen Geschrieben 13. November 2021 (bearbeitet) Hi, was hast du denn so an Lösungsvorschlägen bereits umgesetzt? Generell ist das mit "Import-CSV (Import-Csv (Microsoft.PowerShell.Utility) - PowerShell | Microsoft Docs)" und ein bisschen Logik flott erledigt. In quick'n'dirty: $CSVPath = "<Pfad zur CSV>" $objCSVInput = Import-Csv -Path $CSVPath ` -Delimiter "," $objHostnames = $objCSVInput | Select-Object Hostname -Unique $objCSVSorted = @() foreach($Hostname in $objHostnames.Hostname){ $objCSVSorted += $objCSVInput | Where-Object { $_.Hostname -eq $Hostname } | Sort-Object Timestamp | Select-Object -Last 1 } $objCSVSorted Gruß Jan bearbeitet 13. November 2021 von testperson Zitieren Link zu diesem Kommentar
cj_berlin 1.329 Geschrieben 13. November 2021 Melden Teilen Geschrieben 13. November 2021 Moin, brauchst Du die Einträge hinterher zwingend in der gleichen Reihenfolge oder ist es egal? Zitieren Link zu diesem Kommentar
cj_berlin 1.329 Geschrieben 13. November 2021 Melden Teilen Geschrieben 13. November 2021 (bearbeitet) @testperson Das würde funktionieren, wenn Import-CSV das Timestamp-Feld als [datetime] importieren würde. Da es aber ein String bleibt, ist '01.01.2021 12:30' < '12.12.1999 13:45' Mein Vorschlag wäre $data = Import-CSV C:\temp\machines.csv $lastTS = @{} $output = @{} for ($i=0; $i -lt $data.Count; $i++) { $curHostname = $data[$i].Hostname $curTS = $data[$i].Timestamp -as [datetime] if ($lastTS.ContainsKey($curHostname)) { if ($lastTS[$curHostname] -lt $curTS) { $lastTS[$curHostname] = $curTS $output[$curHostname] = $i } } else { $lastTS.Add($curHostname, $curTS) $output.Add($curHostname, $i) } } $outputSorted = New-Object System.Collections.Generic.List[PSObject] foreach($i in $output.Values) { $outputSorted.Add($data[$i]) } $outputSorted | Export-CSV -Path c:\temp\machines-sorted.csv -Delimiter ',' -NoTypeInformation Vermutlich ließe er sich bei sehr großen Datenmengen nochmal optimieren, aber er dürfte schneller sein als alles, was mit der Pipe und Sort-Object arbeitet. bearbeitet 13. November 2021 von cj_berlin Zitieren Link zu diesem Kommentar
testperson 1.707 Geschrieben 13. November 2021 Melden Teilen Geschrieben 13. November 2021 @cj_berlin Das sollte sich doch in meinem Code so lösen lasse: $CSVPath = "C:\install\test\test.csv" $objCSVInput = Import-Csv -Path $CSVPath ` -Delimiter "," $objHostnames = $objCSVInput | Select-Object Hostname -Unique $objCSVSorted = @() foreach($Hostname in $objHostnames.Hostname){ $objCSVSorted += $objCSVInput | Where-Object { $_.Hostname -eq $Hostname } | Sort-Object [datetime]::Timestamp | Select-Object -Last 1 } $objCSVSorted Zitieren Link zu diesem Kommentar
cj_berlin 1.329 Geschrieben 13. November 2021 Melden Teilen Geschrieben 13. November 2021 (bearbeitet) Funktional schon Und es erschließt sich aus Deinem Code für den Laien vermutlich auch besser, was der Code wo tut. Aber: ich habe hier eine Datei mit 100k Zeilen für insgesamt 1000 Hostnames, also quasi real-world data aus einem mittelständischen Unternehmen. Mein obiger Code war damit in unter zwei Sekunden fertig. Dahingegen hat auf demselben Rechner allein der Part mit Select -Unique 30-40 Sekunden in Anspruch genommen. Hier mit Hard Facts: bearbeitet 13. November 2021 von cj_berlin 1 Zitieren Link zu diesem Kommentar
stefan4711 3 Geschrieben 13. November 2021 Autor Melden Teilen Geschrieben 13. November 2021 Also ich hatte es folgendermaaßen probiert, nachdem ich mit Batch absolut nicht weiterkam: Zitat #Getting the Path of CSV file $inputCSVPath = 'Summary.csv' #The Import-Csv cmdlet creates table-like custom objects from the items in CSV files $inputCsv = Import-Csv $inputCSVPath | Sort-Object Timestamp -Unique #The Export-CSV cmdlet creates a CSV file of the objects that you submit. #Each object is a row that includes a comma-separated list of the object's property values. $inputCsv | Export-Csv "C:\Users\Riegert\Desktop\CSVmerge\Final.csv" -NoTypeInformation Die Reihenfolge ist im Prinzip ertmal egal, klar wärs schön wenns nach Host sortiert wäre. Danke aber nochmal für die interessanten Lösungsansätze, werde ich mich mal durcharbeiten, melde mich dann wieder lg Stef Also folgendes: Also prinipiell scheint er bei allen Lösungen etwas zu machen, also auch keine doppelten, aber es schreibt leider keine Ergennis CSV. Schon komisch dass ich in anderen Foren zu dem Thema nur "Müll" gefunden habe. @CJ Wie bekomme ich es bei Deinem Ansatz hin dass er eine neue Datei schreibt, so im Fenster kann ich damit nicht viel anfangen, bin leioder noch nicht ganz so firm in Powershell, obgleich ich zugeben muss, dass man damit schon mehr anfangen kann als mit Batch. lg Stef Zitieren Link zu diesem Kommentar
cj_berlin 1.329 Geschrieben 13. November 2021 Melden Teilen Geschrieben 13. November 2021 (bearbeitet) Moin, in beiden Varianten machst Du am Ende | Export-CSV -Path <Pfad> -Delimiter ',' -NoTypeInformation Aber ich ergänze mal den obigen Code um eine Sammlung. EDIT: Code inklusive CSV-Ausgabe ist drin. Wenn Du möchtest, dass die CSV in Excel mit Doppelklick aufgeht, musst Du den Delimiter auf ';' setzen. bearbeitet 13. November 2021 von cj_berlin Zitieren Link zu diesem Kommentar
stefan4711 3 Geschrieben 13. November 2021 Autor Melden Teilen Geschrieben 13. November 2021 Ich bin mir nicht sicher, ob ich dich richtig verstanden habe, du meintest sicher jeweils in den Zeilen mit Output: Zitat $data = Import-CSV C:\SC\CSVmerge\Summary.csv $lastTS = @{} $output = @{} for ($i=0; $i -lt $data.Count; $i++) { $curHostname = $data[$i].Hostname $curTS = $data[$i].Timestamp -as [datetime] if ($lastTS.ContainsKey($curHostname)) { if ($lastTS[$curHostname] -lt $curTS) { $lastTS[$curHostname] = $curTS $output[$curHostname] = $i | Export-CSV -Path C:\SC\CSVmerge\output.csv -Delimiter ',' -NoTypeInformation } } else { $lastTS.Add($curHostname, $curTS) $output.Add($curHostname, $i) | Export-CSV -Path C:\SC\CSVmerge\output.csv -Delimiter ',' -NoTypeInformation } } foreach($i in $output.Values) { $data[$i] } die Outputdatei ist 1kb groß und zeigt beim öffnen keinen Inhalt, vielleicht fehlen mir ja noch irgendwelche cmdlets, die ich erst isstallieren muss Zitieren Link zu diesem Kommentar
cj_berlin 1.329 Geschrieben 13. November 2021 Melden Teilen Geschrieben 13. November 2021 Nein, ich habe den Code doch für Dich fertig ergänzt Zitieren Link zu diesem Kommentar
stefan4711 3 Geschrieben 13. November 2021 Autor Melden Teilen Geschrieben 13. November 2021 (bearbeitet) da steht nur EDIT: Code inklusive CSV-Ausgabe ist drin. Wenn Du möchtest, dass die CSV in Excel mit Doppelklick aufgeht, musst Du den Delimiter auf ';' setzen. bearbeitet vor 48 Minuten von cj_berlin aber sehe leider nix:( achso da oben, jetzt seh ichs, ich probiers bearbeitet 13. November 2021 von stefan4711 Zitieren Link zu diesem Kommentar
cj_berlin 1.329 Geschrieben 13. November 2021 Melden Teilen Geschrieben 13. November 2021 In meiner ERSTEN Antwort in diesem Thread steht ein Codeblock. Den habe ich um die CSV-Ausgabe ergänzt. Das ist auch der einzige Codeblock, den ich in diesem Thread gepostet habe. Zitieren Link zu diesem Kommentar
stefan4711 3 Geschrieben 13. November 2021 Autor Melden Teilen Geschrieben 13. November 2021 Also jetzt hab ichs so, der Pfad zu Summary.csv stimmt, aber jetzt macht er gar nichts data = Import-CSV C:\SC\CSVmerge\Summary.csv $lastTS = @{} $output = @{} for ($i=0; $i -lt $data.Count; $i++) { $curHostname = $data[$i].Hostname $curTS = $data[$i].Timestamp -as [datetime] if ($lastTS.ContainsKey($curHostname)) { if ($lastTS[$curHostname] -lt $curTS) { $lastTS[$curHostname] = $curTS $output[$curHostname] = $i } } else { $lastTS.Add($curHostname, $curTS) $output.Add($curHostname, $i) } } $outputSorted = New-Object System.Collections.Generic.List[PSObject] foreach($i in $output.Values) { $outputSorted.Add($data[$i]) } $outputSorted | Export-CSV -Path C:\SC\CSVmerge\machines-sorted.csv -Delimiter ',' -NoTypeInformation :( lg stef Zitieren Link zu diesem Kommentar
cj_berlin 1.329 Geschrieben 13. November 2021 Melden Teilen Geschrieben 13. November 2021 Hier funktioniert der exakte Code (natürlich mit $ am Anfang) Zitieren Link zu diesem Kommentar
stefan4711 3 Geschrieben 13. November 2021 Autor Melden Teilen Geschrieben 13. November 2021 Ich nehme an $Data meinst Du und ja das war es, ich danke Dir recht herzlichst, das war das was ich wollte Wenn man das auch noch sortiert bekämme;) lg und schönen Abend noch Stef Zitieren Link zu diesem Kommentar
Empfohlene Beiträge
Schreibe einen Kommentar
Du kannst jetzt antworten und Dich später registrieren. Falls Du bereits ein Mitglied bist, logge Dich jetzt ein.