christianrutz
Goto Top

Powershell Datei einlesen, Datensätze mit anderer Datei vergleichen und ändern

Hallo zusammen,

ich bin komplett neu in Powershell. Nun ist meine Aufgabe aus einer Excel datei eine Spalte mit ID´s einzulesen, und sie mit ID´s in einer Text Datei zu vergleichen, sind sie identisch muss in der Textdatei der eintrag unter der jeweiligen ID geändert werden. Ich habe absolut keine vorstellung wie ich das realisieren soll. Freue mich über jede Hilfe!

Content-Key: 214742

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

Ausgedruckt am: 29.03.2024 um 14:03 Uhr

Mitglied: Pope35i
Pope35i 20.08.2013 um 14:21:44 Uhr
Goto Top
Hallo,
ich arbeite mich auch gerade in PowerShell ein, eine Verbindung zum Excel habe ich schonmal.

Das funktioniert so:


$ExcelMappe = "C:\xxxx\NeueTestMappe.xlsx" #Deine XLSX Mappe.  

#Excel Objekt wird erstellt
echo "Excel Objekt wird erstellt.."  
$Excel = new-object -comobject Excel.application
$Excel.visible = $True


# Öffnet bestehende Excel Datei
echo "Bestehende Vorlage wird geoeffnet: $ExcelMappe"  
$WorkBook = $Excel.WorkBooks.open($ExcelMappe)
$Sheet = $WorkBook.ActiveSheet
$cells=$Sheet.Cells

#Spalte und Zeile Definieren
$Spalte = 1
$Zeile = 1

# Zum Auslesen der Felder:
$feld_inhalt = $Cells.Item($Spalte,$Zeile).value2

#Zum Ausgeben (Ob alles geklappt hat)
$feld_inhalt

Wenn du diesen Code übernimmst und deinen Pfad der Mappe anpasst, sollte er dir den Wert aus der 1. Spalte in der 1. Zeile ausgeben.
In dem Fall im Excel A1.

Weiter Arbeiten kannst du dann mit $feld_inhalt, wenn du alles richtig gemacht hast sollte dort nun die ID drin stehen.

Verknüpfung zu einer Text-Datei habe ich gerade nicht auf dem Schirm.

Viele Grüße.
Mitglied: christianrutz
christianrutz 20.08.2013 um 14:39:01 Uhr
Goto Top
Hi,
wow das ging ja schnell! Danke für die schnelle Antwort!
Hilft mir auf jedenfall schon etwas weiter. das ganze kann ich ja beliebig oft wiederholen lassen um die ganzen einträge der Spalte abzuarbeiten. (sind ca 10 Einträge)

Nun muss ich nurnoch wissen wie ich das mit den Zeilen bzw einträgen einer .txt datei vergleiche, wäre ja nicht so schwer wenn nicht das Problem wäre das in der .txt vor und hinter dem Wert der mich interessiert noch andere Sachen stehen. Bsp.
version_passport = "00d6bad0-a855-11da-9c8f-000088e68a62"
zum vergleichen interessiert mich aber nur diese Nummer (da auch nur diese Nummer in der xls Datei steht.
00d6bad0-a855-11da-9c8f-000088e68a62

Das weitere Problem:
Nach dem Vergleich (vorrausgestzt die Nummer stimmen überein) Soll ein Eintrag aus der 2. Spalte der Excel Tabelle, 2 Zeilen unter dieser Nummer in der .txt geschrieben werden.
Ich hoffe auf weitere Hilfen.

Danke!
Mitglied: Pope35i
Pope35i 20.08.2013 um 16:22:17 Uhr
Goto Top
Ja genau, das kannst du in einer einfachen While-Schleife wiederholen.

Wegen der ID aus deiner TXT File schau dir diesen Link:
blog.stefanrehwald.de/2013/02/27/powershell-03-1-strings-auf-bestimmten-inhalt-prufen-mit-dem-parameter-match/

mal an, dort geht es um -match, der vergleicht auch Sachen, egal was davor/dahinter steht.

Viele Grüße.
Mitglied: colinardo
colinardo 20.08.2013 aktualisiert um 18:29:30 Uhr
Goto Top
Hallo christianrutz,
alles kein Problem. Ohne weitere Informationen zu deiner Textdatei, gehe ich jetzt mal z.B. von folgendem Format deiner Textdatei aus:
version_passport = "00d6bad0-a855-11da-9c8f-000088e68a62" blablablablablablablablablablablabla
blablablabla
...
blablablabla
blablablabla
version_passport = "00d6bad0-a855-11da-9c8f-000088e68a64" dfskjfdglkjd sfglkj sdglkj dsfg
blablablabla
blablablabla
....
..
Dann kannst du mit folgendem Code arbeiten:
(Kommentare sind im Code abgelegt)
#Funktion zum vereinfachten Regular Expression Matching
Function Get-Matches($Pattern,$groupNumber = 0) {begin { $regex = New-Object Regex($pattern) };process { foreach ($match in ($regex.Matches($_))) { ([Object[]]$match.Groups)[$groupNumber].Value }}}

#Deine XLSX Mappe.
$ExcelMappe = "E:\Tempfolder\Scripte\test.xlsx"   
#Pfad zu deiner Textdatei
$pfadTextdatei = "E:\Tempfolder\Scripte\test.txt"  
$inhaltText = get-content $pfadTextdatei

echo "Excel Objekt wird unsichtbar erstellt.."  
$Excel = new-object -com Excel.Application
$Excel.visible = $false

echo "Bestehende Vorlage wird geoeffnet: $ExcelMappe"  
$WorkBook = $Excel.WorkBooks.open($ExcelMappe)
#Sheet 1 auswählen
$sheet = $WorkBook.Sheets.Item(1)

#Spalte in der die IDs stehen
$startColumn = 1
# Reihe in der die erste ID steht
$startRow = 1
#Anzahl der IDs
$maxRows = 10

echo "Suche nach übereinstimmenden IDs in der Textdatei"  
#Starte Schleife für alle IDs
for ($i = $startRow ; $i -le $maxRows ; $i++){
    #Starte Schleife über alle Zeilen der Textdatei
    for ($k = 0; $k -lt $inhaltText.Length; $k++){
        #Führe RegEx Pattern Matching der aktuellen Zeile in der Textdatei durch
        $match = $inhaltText[$k] | Get-Matches 'version_passport = "([^\s]*)"' 1  
        #wenn eine passende ID gefunden wurde setze den Inhalt der zweiten Zeile mit Wert aus Spalte 2 des Excel-Sheets
        #Hinweis: Der aktuelle Wert 2 Zeilen weiter in der Textdatei wird nicht überschrieben sondern in einer weiteren Zeile wieder angehängt
        if($sheet.Cells.Item($i,$startColumn).Value2 -eq $match){
            if ($k+1 -le $inhaltText.length){
                $inhaltText[$k+1] +=  "`r`n" + $sheet.Cells.Item($i,$startColumn + 1).Value2  
            } else {   #Für den Fall das eine gefundene ID in der letzen Zeile der Textdatei steht müssen wir den Text anhängen anstatt mit einem Index auf die Zeile zu verweisen
                $inhaltText +=  "`r`n" + $sheet.Cells.Item($i,$startColumn + 1).Value2  
            }
        } 
    }
}
echo "Speichere die geänderte Textdatei..."  
#Speichere den veränderten Textinhalt in der selben Textdatei
set-content -Path $pfadTextdatei -Value $inhaltText

echo "Beende Excel."  
#Beende Excel
$Excel.Quit()

#Beendet den Excel-Prozess, da dieser meistens trotzdem nach der 'Quit' Methode noch im Hintergrund weiter existiert (Liegt an der verzögerten COM Garbage Collection) 
spps -Name Excel
echo "Fertig."  
Die grundlegende Arbeitsweise zum finden der IDs ist folgende: Das Script arbeitet mit zwei verschachtelten FOR-Schleifen die äußere Schleife arbeitet die IDs in Excel nacheinander ab und die zweite durchläuft die Zeilen der Textdatei nacheinander und durchsucht dabei jede Zeile nach dem Vorkommen der jeweils aktuellen ID in der äußeren Schleife. Das finden der ID wird durch ein Regular Expression Matching gemacht. Dazu dient die Funktion am Anfang des Scripts, die dies vereinfacht.
Das RegEx-Pattern 'version_passport = "([^\s]*)"' kann man ausgespochen so verstehen:
Match the characters “version_passport = "” literally «version_passport = "»
Match the regular expression below and capture its match into backreference number 1 «([^\s]*)»
   Match a single character that is a “non-whitespace character” «[^\s]*»
      Between zero and unlimited times, as many times as possible, giving back as needed (greedy) «*»
Match the character “"” literally «"»
Mehr zu Regular Expressions findet sich zu hauf im Netz.
Wird eine ID gefunden setzt das Script die zweite Zeile nach der aktuellen mit dem Inhalt aus der Spalte hinter der ID in Excel. Dabei wird der vorhandene Text in dieser Zeile nicht gelöscht sondern eine Zeile weiter nach unten geschoben(das lässt sich anpassen wenn du das willst).

So, denke das ist erst mal genug Stoff zum verstehen für dich als Neuling in Powershell.

Grüße Uwe
Mitglied: christianrutz
christianrutz 21.08.2013 um 08:56:39 Uhr
Goto Top
Hallo,

erstmal vielen vielen Dank für diese superschnelle und echt großartige Antwort! Dieses Forum ist wirklich wahnsinnig gut!

Die Antwort hat mich schon viel weiter gebracht!

Die Textatei sieht wie folgt aus:


version = {
project = ""
library = ""
item_passport = "1134817842:937482499:1533"
version_passport = "00d6bad0-a855-11da-9c8f-000088e68a62"
type = "LIB PART"
intent = "reference"
version_number = 5
filename = "1215499_0119.prt"
name = "Scheibe Unterleg 5.3 DIN 125 A2"
part_number = "T1215499"
revision = "005"
version = {
project = ""
library = ""
item_passport = "1134817842:937482499:1533"
version_passport = "00d6bad0-a855-11da-9c8f-000088e68a62"
type = "LIB PART"
intent = "reference"
version_number = 5
filename = "1215499_0119.prt"
name = "Scheibe Unterleg 5.3 DIN 125 A2"
part_number = "T1215499"
revision = "005"

usw....

Wie oben beschrieben soll der eintrag "version_passport = "....." verglichen werden.

Funktioniert wunderbar!

Ersetzt werden soll:
version_number = 5
in diesem Fall steht in der Excel Tabelle z.B. eine 6
Das Ergebniss heißt dann:
version_number = 6

Wie sage ich ihm das er nur die Zahl ersetzen soll und nicht komplett alles?

Vielen Dank schonmal!
Mitglied: colinardo
colinardo 21.08.2013 aktualisiert um 09:34:37 Uhr
Goto Top
#Funktion zum vereinfachten Regular Expression Matching
Function Get-Matches($Pattern,$groupNumber = 0) {begin { $regex = New-Object Regex($pattern) };process { foreach ($match in ($regex.Matches($_))) { ([Object[]]$match.Groups)[$groupNumber].Value }}}

#Deine XLSX Mappe.
$ExcelMappe = "E:\Tempfolder\Scripte\test.xlsx"   
$pfadTextdatei = "E:\Tempfolder\Scripte\test.txt"  
$inhaltText = get-content $pfadTextdatei

echo "Excel Objekt wird unsichtbar erstellt.."  
$Excel = new-object -com Excel.Application
$Excel.visible = $false

echo "Bestehende Vorlage wird geoeffnet: $ExcelMappe"  
$WorkBook = $Excel.WorkBooks.open($ExcelMappe)
#Sheet 1 auswählen
$sheet = $WorkBook.Sheets.Item(1)

#Spalte in der die IDs stehen
$startColumn = 1
# Reihe in der die erste ID steht
$startRow = 1
#Anzahl der IDs
$maxRows = 10

echo "Suche nach übereinstimmenden IDs in der Textdatei"  
#Starte Schleife für alle IDs
for ($i = $startRow ; $i -le $maxRows ; $i++){
    #Starte Schleife über alle Zeilen der Textdatei
    for ($k = 0; $k -lt $inhaltText.Length; $k++){
        #Führe RegEx Pattern Matching der aktuellen Zeile in der Textdatei durch
        $match = $inhaltText[$k] | Get-Matches 'version_passport = "([^\s]*)"' 1  
        #wenn eine passende ID gefunden wurde setze den Inhalt drei Zeilen danach mit Wert aus Spalte 2 des Excel-Sheets
        if($sheet.Cells.Item($i,$startColumn).Value2 -eq $match){
            $inhaltText[$k+3] =  "version_number = " + $sheet.Cells.Item($i,$startColumn + 1).Value2  
        } 
    }
}
echo "Speichere die geänderte Textdatei..."  
#Speichere den veränderten Textinhalt in der selben Textdatei
set-content -Path $pfadTextdatei -Value $inhaltText

echo "Beende Excel."  
#Beende Excel
$Excel.Quit()

#Beendet den Excel-Prozess, da dieser meistens trotzdem nach der 'Quit' Methode noch im Hintergrund weiter existiert (Liegt an der verzögerten COM Garbage Collection) 
spps -Name Excel
echo "Fertig."  

alternativ ließe sich Zeile 34 auch so schreiben, wenn sich hinter dem Gleichheitszeichen immer eine Zahl befindet:
 $inhaltText[$k+3] = ($inhaltText[$k+3])  -replace "\d+", $sheet.Cells.Item($i,$startColumn + 1).Value2  
dann dürfte sich auch der Text **version_number" beliebig ändern.

Einen guten Artikel für Powershell mit dem Thema "Suchen und Ersetzen" findest du hier

Grüße Uwe
Mitglied: christianrutz
christianrutz 21.08.2013 um 09:41:00 Uhr
Goto Top
Hi,

echt stark! Vielen Dank!

Jetzt nurnoch etwas zum Verständniss.

Bei der Suche in der Excel Datei wird festgelegt wo die einträge genau stehen:

#Spalte in der die IDs stehen
$startColumn = 1
  1. Reihe in der die erste ID steht
$startRow = 1
#Anzahl der IDs
$maxRows = 10


Wo genau wird das beim ersetzen gesagt also das er die 2. Spalte nehmen soll. Die erste Zahl die ersetzt werden soll steht quasi in Spalte 2, Zeile 2.

Ich kann nicht genau rauslesen wo ich das festlege.

Danach müsste alles super sein.

Vielen Dank!
Mitglied: colinardo
colinardo 21.08.2013 um 09:45:38 Uhr
Goto Top
In Zeile 34 im Code:
$sheet.Cells.Item($i,$startColumn + 1).Value2
zu $startColumn wird eine 1 addiert.
Wenn deine ID also zum Beispiel in Spalte A steht und deine Werte in Spalte C addierst du 2 dazu.

Viel Erfolg
Uwe
Mitglied: christianrutz
christianrutz 21.08.2013 um 10:28:10 Uhr
Goto Top
Dieses Forum ist absolut Top und empfehlenswert! Jetzt verstehe ich es!

Vielen Dank an euch! Besonderen Dank an colinardo / Uwe!