Wie mit Powershelle alle Ordner durchsuchen

standi

Lt. Junior Grade
Registriert
Nov. 2009
Beiträge
406
Hallo,

ich will das gesamte Dateiverzeichnis C: durchsuchen. Einmal, alle Dateien größer als 9MB, einmal alle Dateiendungen mit .log4.

Das würde dann so aussehen:
Code:
get-childitem -hidden c:\* -recurse | Where-Object -FilterScript {($_.Length -ge 9mb)} | Select-Object Fullname | Export-Csv ergebnis_alle.txt -NoTypeInformation

Und so:
Code:
get-childitem c:\* -include *.log -recurse | Select-Object Fullname | Export-Csv ergebnis_log.txt -NoTypeInformation

1. Ich sehe aber, dass ausgeblendete Ordner, wie zum Beispiel "C:\Benutzer\name\AppData" garnicht durchsucht werden. Wie kann man das realisieren? Der Befehl "-hidden" bringt noch wenigere Ergebnisse

2. PowerShell habe ich als Administrator gestartet. Ich erhalte in der Shell-Ausgabe aber trotzdem so Fehlermeldung wie:
Code:
get-childitem : Der Zugriff auf den Pfad "C:\Windows\System32\LogFiles\WMI\RtBackup" wurde verweigert.
Könnte man die Suche daher auch auf diese Ordner ausweiten?
 
Ich hatte mal einen Ordner betreten, wo ich irgendwie davor gefragt, "ob ich mir sicher bin einzutreten", bzw. "als Administrator rein" oder sowas ähnliches. Kenne den genauen Wortlaut nicht mehr. Dort hatte ich auch mal Dateien reinkopiert
 
Zuletzt bearbeitet:
Nur zur Info:
- Systemrechte sollten nicht erforderlich sein, wohl aber Adminrechte. Get-Childitem ist freundlich genug und wirft Ausnahmen, wenn was nicht angeschaut werden kann, also entweder diese einfangen (try/catch) oder einfach den Bildschirm angucken.

- Dateisystem angucken dauert naturgemäß eine Weile. Daher ist es sinnvoll, das so weit wie möglich zu stauchen.
=> Where-Object kann, wie bereits festgestellt wurde, ein Filterscript verarbeiten. Das ist nicht nur einfach wie bei Batch "*.xyz" , sondern es ist buchstäblich eine eigene Funktion, welche einfach nur $True zurückgeben muß, wenn der Kandidat im Ergebnis auftauchen soll.
Daher einfach die beiden Anforderungen "mindestens neun MB" einerseits und "alles was *.log4 ist" andererseits in ein Filterscript stecken. Ergebnis, 100% schneller fertig. :daumen:
ZB so:

PowerShell:
[string[]] $filepath = get-childitem -force -path c:\ -recurse -File |
 Where-Object -FilterScript {
( $_.Length -ge 9mb ) -or ( $_.Extension -eq  '.log4' ) 
} |
 Select-Object Fullname

Jetzt steckt die Liste aller Dateinamen (mit absolutem Pfad) in $FilePath. Das kann man dann weiterverarbeiten. Und weil diese Liste (a) im RAM steht und (b) vergleichsweise sehr kurz ist, kann man sie auch bedenkenlos weiterverarbeiten, zB nochmal nachfiltern mit Where-Object, wenn die Ausgabe tatsächlich in verschiedenen Dateien landen soll.


Note: Ich habe Get-Childitem noch den Parameter -File mitgegeben. Der sorgt dafür, daß Ordner nicht berücksichtigt werden, zB C:/Ordner.log4 oder.... auch wenn es sicherlich nicht zu erwarten ist... Order mit mindestens 9'437'184 Dateien da drinnen.
 
  • Gefällt mir
Reaktionen: Art Vandelay
Nur als Hinweis, bei meinem "select-object fullname" sollte noch irgendwo ein -Expandproperty mit dazu, damit das Ergebnis nicht in einem Objekt mit der einzelnen Eigenschaft .Fullname landet.

Best practice ist auch, Select-Object nach Möglichkeit wegzulassen und es nur zu verwenden, wenn es auch wirklich benötigt wird. Denn Select-Object dupliziert Ergebnisse und löst das sogenannte Lazy Loading auf, sodaß man am Ende mehr Ressourcen statt weniger benötigt.
 
Ein andere Vorschlag:

Wenn nur die Dateien, ohne Pfadangabe, ausgegeben werden sollen:
PowerShell:
$Files = (Get-ChildItem -Recurse -Force "C:\*" | Where {$_.Length -Ge 9mb -Or $_.Extension -Eq ".log4"}).Name
$Files

Wenn die Dateien, mit Pfadangabe, ausgegeben werden sollen:
PowerShell:
$PathAndFiles = (Get-ChildItem -Recurse -Force "C:\*" | Where {$_.Length -Ge 9mb -Or $_.Extension -Eq ".log4"}).FullName
$PathAndFiles
 
Na okay, da landen wir schnell beim Stil.

Inzwischen gibt es auch über "sowas wie Linq in Powershell" die Möglichkeit, Methoden .Where und auch .Foreach in IEnumerables aufzurufen.
Unter Powershell wollen diese einen Scriptblock als Argument. Also zB
PowerShell:
$Liste.Where({$_ -eq xyz})
was eine gefilterte Liste zurückgibt. Dasselbe mit .Foreach(scriptblock), was mehr oder weniger identisch zu .Select(variable => funktionsobjekt) ist. Der Scriptblock ist dann exakt derselbe Scriptblock, den man auch für Where-Object bzw. Foreach-Object verwendet hätte, mit $_ als Iterator.

Aber keine Ahnung wie da das Laufzeitverhalten in Bezug aufs klassische "where-object" ist.
"Profi Powersheller" vermeiden allerdings foreach-object. Das ist um den Faktor 10 langsamer als foreach($element in $list).
 
Zurück
Oben