internet2107
Goto Top

Powershell - Geschwindigkeit Dateisuche

Ich habe das Problem, dass eine Suche nach einer Datei extrem lange dauert, obwohl ich dem Befehl schon Grundsätze zur Einschränkung vorgebe.

Get-ChildItem -Path c:\suchverzeichnis -Recurse -ErrorAction SilentlyContinue -Force  -Filter "server.log"  | Select-Object -First 1  

Das Verzeichnis ist in der Regel so aufgebaut:
c:\suchverzeichnis\ordner1\ordner2\ordner3\log\server.log

Da sich die Namen ordner1\ordner2\ ändern können, beginne ich also nur bei c:\suchverzeichnis

Der komische Effekt ist, dass wenn man den Befehl absendet, die Datei innerhalb von circa 2 Sekunden gefunden wird, er die Suche dann aber nicht aufhört, sondern weitersucht. Der endliche Abbruch der Suche kann dann bis zu 5 Minuten dauern.
Warum?
Jemand einen Tipp?

Content-ID: 353957

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

Ausgedruckt am: 25.11.2024 um 09:11 Uhr

emeriks
emeriks 07.11.2017 um 14:08:13 Uhr
Goto Top
Hi,
er die Suche dann aber nicht aufhört, sondern weitersucht. Der endliche Abbruch der Suche kann dann bis zu 5 Minuten dauern.
Weil das de facto zwei unabhängige Kommando sind, welche nur in einer Pipe verkettet sind.
Select-Object -First 1
Sagt bloß aus, dass der nur das erste Objekt dessen liefern soll, was
Get-ChildItem -Path c:\suchverzeichnis -Recurse -ErrorAction SilentlyContinue -Force -Filter "server.log"
liefert. "Get-ChildItem" muss aber u.U. tausende Dateien/Verzeichnisse durchsuchen, um alle Ergebnisse zu liefern.

Man müsste also schon im ersten Kommando auf "Abbruch bei erstem Treffer" eingrenzen.

E.
NetzwerkDude
NetzwerkDude 07.11.2017 aktualisiert um 14:26:15 Uhr
Goto Top
hm, welche PS Version benutzt du?
(kann man z.B. rausfinden indem man die Variable $PSVersionTable abfragt)

Bei mir (PS v5.1) funktioniert es wie von dir "gewünscht": Bei | Select-Object -First 1 hört er nach dem ersten Treffer auf zu suchen.

Wenn man nur den Get-ChildItem befehl ausführt, werden die Ergebnisse eins nach dem anderen angezeigt d.h. eigentlich sollte es so mit der pipe funktionieren...
DerWoWusste
DerWoWusste 07.11.2017 um 14:40:58 Uhr
Goto Top
Auch bei mir (win10 v1709) funktioniert es wie geünscht und nur das erste .log wird ausgegeben.
internet2107
internet2107 07.11.2017 um 14:41:00 Uhr
Goto Top
Ich habe auch die Version 5.1. Jedoch sind in den einzelnen Verzeichnissen anchmal bis zu 2000 Dateien.
Ich verstehe nur nich, wieso er schon eine Vorgabe hat "such NUR nach der Datei: server.log". Denn diese ist definitiv nur einmal vorhanden.
Denn nach circa 5 Minuten hört er ja auf zu suchen *endlich*, obwohl er ja die gesuchte Datei wie beschrieben schon nach max. 2 Sekunden findet..
internet2107
internet2107 07.11.2017 um 14:44:32 Uhr
Goto Top
Halt, einen zurück.. noch eine Anmerkung. Die Datei "server.log" gibt es definitiv nur einmal. Jedoch sind im selben Verzeichnis alte Logdateien vorhanden, die sich nennen, Beispiel: server.log.2017-11-06
Und davon gibt es bis zu 1000, also für jeden Tag eine...

Beim Filter habe ich aber ja kein "*server.log*" angegeben... dann würde ich das ja noch verstehen.
134464
134464 07.11.2017 aktualisiert um 16:03:33 Uhr
Goto Top
Wer verstehen will wie die Pipeline arbeitet, sollte
https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell. ...
lesen, besonders den Abschnitt, One-At-a-time Processing.

Da sich die Namen ordner1\ordner2\ ändern können, beginne ich also nur bei c:\suchverzeichnis
Nicht nötig wenn du den Ordner so bei Get-Childitem angibst.
C:\suchverzeichnis\*\*
colinardo
Lösung colinardo 07.11.2017 aktualisiert um 15:14:20 Uhr
Goto Top
Servus,
die Powershell Version ist hier essentiell denn
Beginning in Windows PowerShell 3.0, Select-Object includes an optimization feature that prevents commands from creating and processing objects that are not used. When you include a Select-Object command with the First or Index parameter in a command pipeline, Windows PowerShell stops the command that generates the objects as soon as the selected number of objects is generated, even when the command that generates the objects appears before the Select-Object command in the pipeline. To turn off this optimizing behavior, use the Wait parameter.
https://docs.microsoft.com/de-de/powershell/module/Microsoft.PowerShell. ...
Ein Windows 7 ohne Update des Management Frameworks hätte diese Optimierungs als nicht, da es per Default mit PS 2.0 ausgeliefert wird.

Wichtig ist ebenfalls das keine Klammern um den Get-Childitem Befehl gesetzt werden da ansonsten erst das gesamte Array erstellt werden muss bevor es in der Pipe weitergeleitet wird.

Grüße Uwe
emeriks
emeriks 07.11.2017 um 15:13:25 Uhr
Goto Top
Danke @colinardo , gut zu wissen!
internet2107
internet2107 07.11.2017 um 15:50:18 Uhr
Goto Top
@uwe

Danke für den wichtigen Hinweis.
Mein blöder Fehler. Sorry. Ich habe vergessen zu erwähnen, dass die Suche und Abfrage per "invoke-command" auf einem Server 2008 R2 erfolgt, somit nur Version 2.0 enthalten ist. Ein Update auf eine höhere Version nicht möglich, da validiertes und reguliertes Umfeld.

Jemand jetzt noch eine Idee?

@specht
Der Einsatz von c:\suchverzeichnis\*\* usw.
bringt leider gar nichts.
emeriks
emeriks 07.11.2017 um 15:51:42 Uhr
Goto Top
Jemand jetzt noch eine Idee?
Lokal suchen lassen und dabei über Freigabe gehen?
Get-ChildItem -Path \\server\c$\suchverzeichnis -Recurse -ErrorAction SilentlyContinue -Force  -Filter "server.log"  | Select-Object -First 1  
internet2107
internet2107 07.11.2017 um 15:57:36 Uhr
Goto Top
C$ nicht möglich, weil keine Adminrechte vorhanden.
Praktisch ist es aber ja dasselbe wie der Befehl "invoke-command -computer Server -credential user -scriptblock {gci -path c:\suchverzeichnis usw}

Für das Ausführen des "invoke-command" und benötigten credentials sind jedoch entsprechende Rechte vorhanden.
emeriks
emeriks 07.11.2017 aktualisiert um 15:59:31 Uhr
Goto Top
C$ nicht möglich, weil keine Adminrechte vorhanden.
Na dann eine explizite Freigabe dafür einrichten.
Praktisch ist es aber ja dasselbe wie der Befehl "invoke-command -computer Server -credential user -scriptblock {gci -path c:\suchverzeichnis usw}
Nein. Wenn Du das über Netzwerk (Zugriff auf Freigabe) laufen lässt, dann gilt die Powershell-Version des Computers, wo das Script läuft. Darum ging es mir.
134464
134464 07.11.2017 um 16:02:36 Uhr
Goto Top
Zitat von @internet2107:
@specht
Der Einsatz von c:\suchverzeichnis\*\* usw.
bringt leider gar nichts.
Doch du machst es nur falsch.
gci 'c:\suchverzeichnis\*\*' -recurse -Filter 'server.log' -Force  
134464
Lösung 134464 07.11.2017 aktualisiert um 17:05:25 Uhr
Goto Top
Du kannst dir auch deine eigene Rekursive Funktion bauen das ist Versionsunabhängig.
function Find-FirstFile([string]$path,[string]$filter){
    $result = gci $path -Filter $filter -Force | select -First 1
    if ($result){
        return $result
    }else{
        gci $path | ?{$_.PSIsContainer} | %{Find-FirstFile $_.Fullname -Filter $filter}
    }
}

Find-FirstFile "C:\suchverzeichnis" "server.log"  
internet2107
internet2107 07.11.2017 um 18:00:50 Uhr
Goto Top
@specht
DANKE, du bist der Held des Tages. Suche dauert nun nur noch gut 3 Sekunden, mit deinem Script.
Schönen Abend noch.
colinardo
Lösung colinardo 07.11.2017 aktualisiert um 21:41:17 Uhr
Goto Top
@specht
Schön und gut, aber noch der wichtige Hinweis: Das wird nur so lange gute gehen bis Powershell sagt "Nope, mehr wie Rekursionstiefe 100 will ich nicht!". Deswegen sollte man diese Konstrukte in Powershell bei der Verarbeitung von unbekannten Dateisystem-Bäumen immer möglichst vermeiden und die Rekursion umbauen, z.B. in einen While Loop oder das vorherige enumerieren aller Ordner und dann mit Schleife darüber.
https://weblogs.asp.net/jongalloway/working-around-a-powershell-call-dep ...
Rekursive Funktionen sind mit eine der häufigsten Ursachen von Stack-Overflows, so please use with care!.