Jak uzyskać tylko katalogi za pomocą Get-ChildItem?

242

Korzystam z programu PowerShell 2.0 i chcę wyodrębnić wszystkie podkatalogi określonej ścieżki. Poniższe polecenie wyświetla wszystkie pliki i katalogi, ale nie mogę wymyślić, jak je odfiltrować.

Get-ChildItem c:\mypath -Recurse

Próbowałem użyć, $_.Attributesaby uzyskać atrybuty, ale nie wiem, jak skonstruować dosłowne wystąpienie, System.IO.FileAttributesaby je porównać. W cmd.exebyłoby

dir /b /ad /s
Peter Hull
źródło

Odpowiedzi:

292

Dla wersji PowerShell mniejszych niż 3.0:

FileInfoObiekt zwrócony przez Get-ChildItemposiada właściwość „baza”, PSIsContainer. Chcesz wybrać tylko te elementy.

Get-ChildItem -Recurse | ?{ $_.PSIsContainer }

Jeśli chcesz surowe ciągi znaków katalogów, możesz to zrobić

Get-ChildItem -Recurse | ?{ $_.PSIsContainer } | Select-Object FullName

W przypadku programu PowerShell 3.0 i nowszych:

dir -Directory
xcud
źródło
20
Życzenie, które było aliasowane do „IsFolder”
xcud
5
xcud: Nie każda hierarchia reprezentowana przez PSDrive jest oparta na folderach.
Joey
10
Różnica semantyczna między „kontenerem” a „folderem” nie jest tym, przez co można przejechać ciężarówką.
xcud
5
@xcud: Zobacz odpowiedź iraSenthil. -Directory i -File działa również na Get-ChildItem. Nie ma potrzeby bezpośredniego używania atrybutu PSIsContainer.
Wouter
(Get-ChildItem |? {$ _. PSIsContainer} | Wybierz nazwę) .Name
Jose Ortega
195

W PowerShell 3.0 jest to prostsze:

Get-ChildItem -Directory #List only directories
Get-ChildItem -File #List only files
iraSenthil
źródło
33
reż jest pseudonimem Get-ChildItem
Chip McCormick
1
@crashmstr Czy jesteś pewien? Sprawdziłem na PS4.0. Dla mnie dirzostał pseudonim Get-ChildItem, -Directorya -Fileopcje i działały zgodnie z opisem. Użyłem polecenia echo $PSVersionTable, help dir, dir -Directoryi dir -Filewymyślić ten komentarz.
Peter Hull,
3
To powinna być odpowiedź
Chris S
2
lsi dirpseudonimy Get-ChildItemwybierz swoją truciznę
Kanion Kolob
53

Posługiwać się

Get-ChildItem -dir #lists only directories
Get-ChildItem -file #lists only files

Jeśli wolisz aliasy, użyj

ls -dir #lists only directories
ls -file #lists only files

lub

dir -dir #lists only directories
dir -file #lists only files

Aby rekursować również podkatalogi, dodaj -ropcję.

ls -dir -r #lists only directories recursively
ls -file -r #lists only files recursively 

Testowane na PowerShell 4.0, PowerShell 5.0 (Windows 10), PowerShell Core 6.0 (Windows 10, Mac i Linux) oraz PowerShell 7.0 (Windows 10, Mac i Linux).

Uwaga : W programie PowerShell Core łącza symboliczne nie są przestrzegane po określeniu -rprzełącznika. Aby podążać za dowiązaniami symbolicznymi, określ -FollowSymlinkprzełącznik za pomocą -r.

Uwaga 2 : PowerShell jest teraz wieloplatformowy od wersji 6.0. Wersja wieloplatformowa pierwotnie nosiła nazwę PowerShell Core, ale słowo „Core” zostało porzucone od PowerShell 7.0+.

Dokumentacja Get-ChildItem: https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/get-childitem

Sachin Joseph
źródło
2
To nie zadziała w Powershell 2.0, co było specyficzną potrzebą PO. the - [/ Dir / Directory] nie są poprawnymi parametrami w Powershell 2.0
Ben Personick
21

Czystsze podejście:

Get-ChildItem "<name_of_directory>" | where {$_.Attributes -match'Directory'}

Zastanawiam się, czy PowerShell 3.0 ma przełącznik, który zwraca tylko katalogi; wydaje się logiczną rzeczą do dodania.

Carlos Nunez
źródło
1
FYI powershell 3.0 dodaje flagi -Directoryi-File
WickyNilliams 17.04.13
12

Posługiwać się:

dir -r | where { $_ -is [System.IO.DirectoryInfo] }
Marek Dzikiewicz
źródło
6

Z PowerShell v2 i nowszych (k reprezentuje folder, w którym zaczynasz wyszukiwanie):

Get-ChildItem $Path -attributes D -Recurse

Jeśli chcesz tylko nazwy folderów i nic więcej, użyj tego:

Get-ChildItem $Path -Name -attributes D -Recurse

Jeśli szukasz określonego folderu, możesz użyć następujących. W takim przypadku szukam folderu o nazwie myFolder:

Get-ChildItem $Path -attributes D -Recurse -include "myFolder"
Rachunek
źródło
I używasz PS 3.0 o 4.0?
Kiquenet,
5
Wydaje się, że parametr Atrybuty nie znajduje się w PS2, wyświetla błąd „Nie można znaleźć parametru pasującego do nazwy parametru„ Atrybuty ”. Działa dobrze w PS3.
WileCau
5

Przy takim podejściu wymagany jest mniej tekstu:

ls -r | ? {$_.mode -match "d"}
Jyggorath
źródło
To ten, którego użyłbym.
David Betz
2
Jeszcze krótszy: ls -r | ? {$ _. mode -match "d"}
Jyggorath
Nie można znaleźć skompresowanych folderów
Charles Lambert
7
Ponieważ folder skompresowany jest plikiem zip
użytkownik1594322
Nie zawsze przydatne jest powtarzanie wszystkiego. Możesz mieć wyjątkowo głębokie i krzaczaste drzewo, w którym interesują Cię katalogi dokładnie dwa poziomy niżej; szukanie trzydziestu poziomów w dół to strata czasu.
Ross Presser,
4

Posługiwać się:

dir -Directory -Recurse | Select FullName

To da ci wynik struktury głównej z nazwą folderu tylko dla katalogów.

Wesley
źródło
3

Posługiwać się:

Get-ChildItem \\myserver\myshare\myshare\ -Directory | Select-Object -Property name |  convertto-csv -NoTypeInformation  | Out-File c:\temp\mydirectorylist.csv

Który wykonuje następujące czynności

  • Uzyskaj listę katalogów w lokalizacji docelowej: Get-ChildItem \\myserver\myshare\myshare\ -Directory
  • Wyodrębnij tylko nazwy katalogów: Select-Object -Property name
  • Konwertuj dane wyjściowe na format CSV: convertto-csv -NoTypeInformation
  • Zapisz wynik w pliku: Out-File c:\temp\mydirectorylist.csv
Marty Gomez
źródło
2
Byłoby wspaniale, gdybyś mógł wyjaśnić każdy krok, aby więcej osób mogło zobaczyć, co się dzieje.
jazzurro,
To nie zadziała w Powershell 2.0, co było specyficzną potrzebą PO. the - [/ Dir / Directory] nie są poprawnymi parametrami w Powershell 2.0
Ben Personick
2

Trochę bardziej czytelne i proste podejście można osiągnąć za pomocą poniższego skryptu:

$Directory = "./"
Get-ChildItem $Directory -Recurse | % {
    if ($_.Attributes -eq "Directory") {
        Write-Host $_.FullName
    }
}

Mam nadzieję że to pomoże!

Zorayr
źródło
2

Będziesz chciał użyć Get-ChildItem do rekurencyjnego pobrania wszystkich folderów i plików w pierwszej kolejności. Następnie potokuj dane wyjściowe do klauzuli Where-Object , która pobiera tylko pliki.

# one of several ways to identify a file is using GetType() which
# will return "FileInfo" or "DirectoryInfo"
$files = Get-ChildItem E:\ -Recurse | Where-Object {$_.GetType().Name -eq "FileInfo"} ;

foreach ($file in $files) {
  echo $file.FullName ;
}
sonjz
źródło
1

Przyjęta odpowiedź wspomina

Get-ChildItem -Recurse | ?{ $_.PSIsContainer } | Select-Object FullName

aby uzyskać „nieprzetworzony ciąg”. Ale w rzeczywistości obiekty typu Selected.System.IO.DirectoryInfozostaną zwrócone. W przypadku ciągów surowych można użyć:

Get-ChildItem -Recurse | ?{ $_.PSIsContainer } | % { $_.FullName }

Różnica ma znaczenie, jeśli wartość jest konkatenowana do łańcucha:

  • z Select-Objectzaskakującofoo\@{FullName=bar}
  • z ForEachoperatorem oczekiwane:foo\bar
sevenforce
źródło
1
Select-Object faktycznie zwróci obiekty typu PSCustomObject. Chociaż możesz użyć% (który jest ForEach-Object), aby uzyskać nieprzetworzone ciągi, tak jak ty, możesz także użyćSelect-Object -ExpandProperty FullName
JamesQMurphy
0

Użyj tego:

Get-ChildItem -Path \\server\share\folder\ -Recurse -Force | where {$_.Attributes -like '*Directory*'} | Export-Csv -Path C:\Temp\Export.csv -Encoding "Unicode" -Delimiter ";"
Hansli
źródło
0

Aby konkretnie odpowiedzieć na oryginalne pytanie (przy użyciu IO.FileAttributes):

Get-ChildItem c:\mypath -Recurse | Where-Object {$_.Attributes -and [IO.FileAttributes]::Directory}

Wolę jednak rozwiązanie Marka ( Where-Object { $_ -is [System.IO.DirectoryInfo] }).

Nicolas Melay
źródło