robdox
Goto Top

SQL Abfrage in Array Laden und Damit nach Dateien suchen

Hallo alle zusammen,

ich bin noch relativ neu im PS Geschäft. Ich habe folgendes Konzept, welches ich gern damit lösen möchte und auch weiss das dies funktioniert, jedoch scheitert es an meinem Syntax- und Befehlswissen hierbei.

Was soll geschehen? Es wird per SQL innerhalb des PS-Skripts eine Abfrage getätigt. Hiebei wird mit eine Liste ausgespuckt. Die Werte der Liste, sind auch in verschiedenen Dateinnamen enthalten, welche ich in einem Bestimmten Ordner und Unterordner suchen möchte. Wenn ich diese gefunden habe, soll diese Datei in einen anderen Ordner "kopiert" werden.

Beispiel:

Ergebnis der Tabelle

20191234
20191235
20191236
...
diese Werte möchte ich in einem Array, Zeile, für Zeile einlesen. Ergebnis sollte sein:

$array=20191234
$array[1]=20191235
$array[2]=20191236

Nächster Schritt, Suche alle *.txt Dateien, welche diese Zahlenkombination enthalten. Dateiname wäre: "V_INV_04032019_20191234_M.txt", befinden können sich die Datein aber in verschiedenen Unterordnern.

Wurde diese Datei gefunden, soll sie in einen anderen Ordner kopiert werden bspw. "C:\Ordner\Datei". Fertig.

Ich habe es hinbekommen die Tabelle zu generieren und auch Dateien mit Endung *.txt in einer CSV auszugeben, als Testdatensatz (dient jedoch eher zu Kontrolle) - jedoch nicht die Verbindung der einzelnen Schritte.

Ich bedanke mich vorab, für jegliche Hilfe!

Mein bisheriges Script:

$vPfad="C:\xxx\xxx"  
$vDatum=get-date
$vCommand='select left(mc,len(mc)-5) as Datei from fBasis where Num2>0 and (C_DATE < GETDATE()-2) and TableMC like ''2019%'' order by C_DATE desc'  

function querySQL {
    Param(
        [string]$cSQL
    )
    
    $connectionString = "Data Source=SERVER\db; Initial Catalog=db_TST; user id=admin; pwd=xxx"  
    $connection = new-object system.data.SqlClient.SQLConnection($connectionString)
    $command = new-object system.data.sqlclient.sqlcommand($cSQL,$connection)
    $connection.Open()
    $adapter = New-Object System.Data.sqlclient.sqlDataAdapter $command
    $dataset = New-Object System.Data.DataSet
    $adapter.Fill($dataSet) | Out-null
    $connection.Close()
    $dataSet.Tables
}

querySQL -cSQL $vCommand

#Liste der Dateien druchgehen

    Get-ChildItem -Path $vPfad -Include *.txt -Recurse | 
       Where-Object -FilterScript {($_.LastWriteTime -lt $vDatum.tostring("MM/dd/yyyy HH:mm:ss"))}|  
    Select-Object Name | 
       Export-Csv "$vPfad\test.csv" -NoTypeInformation  

Content-Key: 473680

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

Printed on: April 25, 2024 at 15:04 o'clock

Mitglied: 140447
Solution 140447 Jul 16, 2019 updated at 16:08:34 (UTC)
Goto Top
# Da du Ein Tables-Object in der SQL-Funktion zurückgibst nimmst du die erste Table und darin die Spalte mit dem Namen "Datei" da du ja in deiner Query nur diese Spalte abfragst 
$result = (querySQL -cSQL $vCommand).Datei
# Alle möglichen Dateien in Array speichern
$files =  Get-ChildItem -Path $vPfad -Include *.txt -Recurse | ?{$_.LastWriteTime -lt $vDatum}
# regex OR-Pattern aller SQL-Ergebnisse erzeugen
$pattern = ($result | %{[regex]::escape($_)}) -join "|"  
# Aus den Dateien die ausfiltern die dem Pattern entsprechen und in den Zielordner kopieren.
$files | ?{$_.Basename -match $pattern} | copy-item -Destination 'C:\Ordner' -verbose  
Member: robdox
robdox Jul 17, 2019 at 06:03:54 (UTC)
Goto Top
Vielen lieben Dank! hätte nicht gedacht dass es doch so "einfach" geht.

Wozu diente das $_ grundlegend? Ich habe dies bis jetzt noch nicht verstanden, trz mehrmaligen nachlesen.
Mitglied: 140447
Solution 140447 Jul 17, 2019 updated at 06:48:03 (UTC)
Goto Top
Zitat von @robdox:
Wozu diente das $_ grundlegend? Ich habe dies bis jetzt noch nicht verstanden, trz mehrmaligen nachlesen.
Das ist das aktuelle Objekt in der Pipeline, einfach Doku lesen:
https://itknowledgeexchange.techtarget.com/powershell/using-_/
Member: robdox
robdox Jul 24, 2019 at 10:16:43 (UTC)
Goto Top
Hallo,

ich nochmal - ich habe das Skript lokal bei mir ohne Probleme mit Simulationsdaten testen können. Jedoch funktioniert die angepasste Version nicht wie ich möchte.

Hierbei greift der Pattern nicht mit -matches. Es werden mir alle Dateien aufgelistet, nicht die, welche ich in der SQL Abfrage ausgelesen habe.

Der Dateiname ist bei wie folgt: "2019107870-9313.csv.Agent.19-04-24-11-08-59-07"
In der SQL Abfrage bekomme ich folgende Werte "2019107870" welcher nun mit dem Dateinamen abgeglichen werden soll und dann entsprechend in den Zielordner kopiert wird.

Hab ich ein Denkfehler? Oder warum werden alle Datein in den Unterordnern kopiert, nicht jene, die ich vorhrer mit SQL Abfrage?

Vielen Dank wieder an alle für eure Hilfe!

# Variablen festlegen
$vPfad="D:\"  
$vArchivPfad="D:\bak"  
$vDatum=get-date
$vCommand="select left(mc, charindex('-', right(mc,len(mc)-1))) as Datei from faktura_b where alfanw2 is null and (datediff(day, c_date, current_timestamp) <= 30)"  

# SQL Funktion zum zusammenstellen der Prüftabelle
function querySQL {
    Param(
        [string]$cSQL
    )
    # Connectionstring aus m3.config
    $connectionString = "Data Source=XXX; Initial Catalog=XXX; user id=XXX; pwd=XXX"  

    # SQL Verbindung aufbauen
    $connection = new-object system.data.SqlClient.SQLConnection($connectionString)
    $command = new-object system.data.sqlclient.sqlcommand($cSQL,$connection)
    $connection.Open()
    $adapter = New-Object System.Data.sqlclient.sqlDataAdapter $command
    $dataset = New-Object System.Data.DataSet
    
    # Tabelle erstellen
    $adapter.Fill($dataSet) | Out-null
    $connection.Close()
    $dataSet.Tables
}

# SQL Tabelle in Array speichern
$result = (querySQL -cSQL $vCommand).Datei

# Liste aller Dateien durchsuchen, welche älter als heute sind
$files = Get-ChildItem -Path $vPfad -Include *.csv.* -Recurse | ? {($_.LastWriteTime -lt $vDatum.tostring("MM/dd/yyyy HH:mm:ss"))}  


# Entsprechend der Belegnummer, existierende Dateien auslesen
$pattern=($result | %{[regex]::escape($_)}) -join "|"  

#das Pattern wird richtig ausgelasen, jedoch versehen mit einem "\" welches ich ersetze  
$pattern=$pattern.Replace("\ "," ")  


# Gefundene Dateien für Agenten bereitstellen
$files | ?{$_.Basename -match $pattern} | Copy-Item -Destination $vArchivPfad -Verbose

# --- DEBUG ---
if(($files -eq $null) -or ($result -eq $null)) { write-host "Fehler bei Prüftabelle / Dateien" }  
Mitglied: 140447
140447 Jul 24, 2019 updated at 10:45:39 (UTC)
Goto Top
#das Pattern wird richtig ausgelasen, jedoch versehen mit einem "\" welches ich ersetze
$pattern=$pattern.Replace("\ "," ")
FALSCH !! Die Backslashes müssen dahin weil in Regular Expressions bestimmte Zeichen escaped werden müssen!!! Deswegen ja die Regex.Escape Funktion.

Beschäftige dich erst mal mit Regular Expressions:
https://danielfett.de/2006/03/20/regulaere-ausdruecke-tutorial/

Hab ich ein Denkfehler? Oder warum werden alle Datein in den Unterordnern kopiert, nicht jene, die ich vorhrer mit SQL Abfrage?
Wenn du es nicht wie vorgesehen anwendest und deinen eigenen Wurscht reinverwurstest kein Wunder face-big-smile.

Btw. jetzt für den simplen Schmuh schon wieder einen neuen Thread verschwenden??
Member: robdox
robdox Jul 24, 2019 at 13:33:29 (UTC)
Goto Top
Hey,

danke Dir face-smile - Ja habe ich verstanden mit dem Pattern, jedoch bekomme ich das selbige Ergebnis zurückgeliefert. Pattern stimmt, das Ganze mit dem Basename von den Files abzugleichen leider nicht.

BTW: Neuer Thread gelöscht.

Warum funktioniert das Match nicht?
Mitglied: 140447
140447 Jul 24, 2019 updated at 14:24:07 (UTC)
Goto Top
Schau mal genau hin, du hast noch mehr meines Codes einfach abgeändert und nicht so übernommen wie ich es dir vorgespielt habe. Ist also kein Wunder, dein Datumsvergleich kann so niemals klappen wenn du Birnen mit Äpfeln vergleichst. Meine Variante klappt hier übrigens einwandfrei.
Man man man die Hitze setzt euch aber zu Leute, schafft euch mal ne vernünftige Klima an!
Member: robdox
robdox Aug 05, 2019 at 09:05:21 (UTC)
Goto Top
Grüß Dich!

also die Hitze wird's nicht gewesen sein wegen der Klima, jedoch komme ich auf kein brauchbares Ergebnis. Ich habe für diese simple Sache nun schon einige Stunden geopfert, mir entzieht sich aber mittlerweile jede verständnisvolle Reproduzierbarkeit.

Die letzten Zeilen habe ich mehrmals analysiert. Ich hatte vermutet, das der Dateiname etwas kryptisch ist (Z.b. "19.03.030-92975.csv.Agent.19-04-02-10-08-07-60" - und dieser mit dem Match nichts vergleichbares findet.

Mittlerweile ist es so, das mein Skript keine Dateien findet, bzw. keine Dateien kopiert. Ich habe hierbei lediglich den Basename welcher "19.03.030-92975.csv.Agent" heißt, abgeändert auf "19.03.030-92975" da dieser Wert im Pattern auch "19.03.030-92975" vorhanden ist. Anscheinend ist das aber auch nicht der richtige Weg.

So abstrus bzw labidar Dir das auch vorkommen mag, für mich stellt dies hier ein unerklärbares Phänomen dar, zudem das Skript mit normalen *.txt - Endungen funktioniert hatte auf meinem Testsystem.

Hier nochmal die entscheidende Code-Stelle

# Liste aller Dateien durchsuchen, welche älter als heute sind
$files = Get-ChildItem -Path $vPfad -Include *.csv.* -Recurse | ? {($_.LastWriteTime -lt $vDatum)}

# Entsprechend der Belegnummer, existierende Dateien auslesen
$pattern=($result | %{[regex]::escape($_)}) -join "|"  

# Gefundene Dateien für Agenten bereitstellen
$trimfiles = $files.Basename 
$trimfiles = $trimfiles.trimend(".csv.M3Agent ")  

$finalfiles | ?{$trimfiles -match $pattern} | Copy-Item -Destination $vArchivPfad -Verbose

Ich danke Dir für Deine Mühe wieder vorab!
Mitglied: 140447
140447 Aug 05, 2019 updated at 09:14:25 (UTC)
Goto Top
Klappt hier wie gesagt auch mit ungewöhnlichen Namen problemlos. Du wendest es offensichtlich nur falsch
$finalfiles
gibbet ned.
$finalfiles | ?{$trimfiles -match $pattern}
Und das macht überhaupt keinen Sinn, denk doch mal nach!!
$vDatum
Den Inhalt davon sieht hier auch keiner, also sinnlos hier weiter zu machen wenn du hier solche Durcheinander hier postest.

Wie es geht steht ganz oben in der Lösung!

Ich bin raus, ist ja als gelöst markiert, ciao.
Member: robdox
robdox Aug 05, 2019 at 10:46:28 (UTC)
Goto Top
Hallo,

jetzt sei mal nicht so ;)

ich habe nun noch etwas herausgefunden. Das Skript dem Ursprung angepasst und parallel auf Testsystem und Livesystem, mit identischen Daten getestet.

Auf dem Testsystem funktionierte das Skript mit den neuen Dateien einwandfrei, auf dem Livesystem jedoch nicht.

Ich habe bei der Patternvariable folgenden Unterschied und das ist auch der einzige den es in der Ausgabe gibt, gefunden:

Ergebnis mit
Write-Host $pattern
auf dem Testsystem:
"2019104377-9313|2019104378-9313|2019104379-9313 ... " dabei funktioniert das
-match
einwandfrei und die entsprechenden Dateien werden kopiert.

Auf dem Livesystem (Server) wird mit gleichen Daten, Abfrage, Skript, folgendes Pattern zurückgeliefert:
"2019104377-9313\ 2019104378-9313\ 2019104379-9313\ \ ..."

Kanns sich das / oder du (sofern du nicht wieder genervt bist ;) ) erklären?

Wenn ich es zum Bsp. mit einem Replace "zurechtrücke" werden wieder ALLE Dateien, statt jene, die sich in $Result befinden, kopiert.

Was ist hier das Problem? - der
-join "|"  
- Befehl wird schlichtweg ignoriert auf dem Livesystem...

Vielen Dank vorab!
Mitglied: 140447
Solution 140447 Aug 05, 2019 updated at 11:14:39 (UTC)
Goto Top
2019104377-9313\ 2019104378-9313\ 2019104379-9313\
Ist doch eindeutig, du als Ausgabe der SQL Funktion kein Array sondern hast nur Leerzeichen zwischen den Nummern face-wink. Am LiveSystem entweder veraltete PS , Variable vorher als String statt Array benutzt oder Arraytrenner falsch eingestellt. Deswegen kann das ja nicht laufen, weil kein kein Array und damit keine korrekte Trennung mit dem regex Operator |.
Member: robdox
robdox Aug 05, 2019 at 11:49:08 (UTC)
Goto Top
Tja, genau das hat mir geholfen! Ich musste die $result - Variable explizit als array definieren- nun klappts auch im Livesystem! Ich danke Dir!