How do I get only directories using Get-ChildItem?
Asked Answered
O

19

305

I'm using PowerShell 2.0 and I want to pipe out all the subdirectories of a certain path. The following command outputs all files and directories, but I can't figure out how to filter out the files.

Get-ChildItem c:\mypath -Recurse

I've tried using $_.Attributes to get the attributes but then I don't know how to construct a literal instance of System.IO.FileAttributes to compare it to. In cmd.exe it would be

dir /b /ad /s
Oleta answered 21/6, 2010 at 14:3 Comment(0)
J
380

For PowerShell 3.0 and greater:

Get-ChildItem -Directory

You can also use the aliases dir, ls, and gci


For PowerShell versions less than 3.0:

The FileInfo object returned by Get-ChildItem has a "base" property, PSIsContainer. You want to select only those items.

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

If you want the raw string names of the directories, you can do

Get-ChildItem -Recurse | ?{ $_.PSIsContainer } | Select-Object FullName
Janinejanis answered 21/6, 2010 at 14:31 Comment(6)
Wish that was aliased to "IsFolder".Janinejanis
xcud: Not every hierarchy represented by a PSDrive is folder-based.Larisa
The semantic gap between "container" and "folder" is not one you can drive a truck through.Janinejanis
@xcud: See iraSenthil's answer. -Directory and -File also works on Get-ChildItem. No need to use the PSIsContainer attribute directly.Klein
(Get-ChildItem | ?{ $_.PSIsContainer } | Select Name).NameSongful
@Janinejanis Just make it one. Update-TypeData -ErrorAction SilentlyContinue -TypeName "System.IO.DirectoryInfo" -MemberType ScriptProperty -MemberName "IsFolder" -Value {return $this.PSIsContainer} -Force (Don't really do this but if you really insisted on having it....it's an option)Decrepitate
G
213

In PowerShell 3.0, it is simpler:

Get-ChildItem -Directory #List only directories
Get-ChildItem -File #List only files
Gere answered 24/1, 2013 at 21:14 Comment(4)
dir is an alias to Get-ChildItemOverelaborate
@crashmstr Are you sure? I checked on my PS4.0. For me, dir was aliased to Get-ChildItem, and the -Directory and -File options worked as described. I used commands echo $PSVersionTable, help dir, dir -Directory and dir -File to come up with this comment.Oleta
This should be the answerTruelove
ls and dir are aliases of Get-ChildItem pick your poisonPersonnel
S
56

Use

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

If you prefer aliases, use

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

or

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

To recurse subdirectories as well, add -r option.

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

Tested on PowerShell 4.0, PowerShell 5.0 (Windows 10), PowerShell Core 6.0 (Windows 10, Mac, and Linux), and PowerShell 7.0 (Windows 10, Mac, and Linux).

Note: On PowerShell Core, symlinks are not followed when you specify the -r switch. To follow symlinks, specify the -FollowSymlink switch with -r.

Note 2: PowerShell is now cross-platform, since version 6.0. The cross-platform version was originally called PowerShell Core, but the the word "Core" has been dropped since PowerShell 7.0+.

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

Skilled answered 28/3, 2015 at 5:38 Comment(1)
This won't work in Powershell 2.0 which was the specific need of the OP. the -[/Dir/Directory] are not valid parameters in Powershell 2.0Strangury
E
24

A cleaner approach:

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

I wonder if PowerShell 3.0 has a switch that only returns directories; it seems like a logical thing to add.

Electrotonus answered 5/9, 2012 at 18:1 Comment(1)
FYI powershell 3.0 adds the -Directory and -File flagsNastassia
G
13

Use:

dir -r | where { $_ -is [System.IO.DirectoryInfo] }
Gariepy answered 5/9, 2012 at 7:34 Comment(0)
A
7

From PowerShell v2 and newer (k represents the folder you are beginning your search at):

Get-ChildItem $Path -attributes D -Recurse

If you just want folder names only, and nothing else, use this:

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

If you are looking for a specific folder, you could use the following. In this case, I am looking for a folder called myFolder:

Get-ChildItem $Path -attributes D -Recurse -include "myFolder"
Afrikander answered 24/10, 2013 at 20:30 Comment(2)
And using PS 3.0 o 4.0 ?Ensheathe
The Attributes parameter doesn't seem to be in PS2, it gives an error "A parameter cannot be found that matches parameter name 'Attributes'". It works ok in PS3.Frontal
N
6

Less text is required with this approach:

ls -r | ? {$_.mode -match "d"}
Northwesterly answered 22/4, 2013 at 8:15 Comment(5)
This is the one that I'd use.Gentlemanatarms
Even shorter: ls -r | ? { $_.mode -match "d" }Northwesterly
This doesn't find compressed foldersYamamoto
Because a compressed folder is a zip fileExplanatory
It is not always useful to recurse everything. You could have an extremely deep and bushy tree where you only are interested in directories exactly two levels down; searching thirty levels down is a waste of time.Unwarranted
H
5

The accepted answer mentions

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

to get a "raw string". But in fact objects of type Selected.System.IO.DirectoryInfo will be returned. For raw strings the following can be used:

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

The difference matters if the value is concatenated to a string:

  • with Select-Object suprisingly foo\@{FullName=bar}
  • with the ForEach-operator the expected: foo\bar
Hauler answered 13/8, 2014 at 11:10 Comment(1)
Select-Object will actually return objects of type PSCustomObject. While you can use % (which is ForEach-Object) to get the raw strings like you did, you can also use Select-Object -ExpandProperty FullNameGorged
W
4

Use:

dir -Directory -Recurse | Select FullName

This will give you an output of the root structure with the folder name for directories only.

Weis answered 11/7, 2014 at 22:34 Comment(0)
X
3

Use:

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

Which does the following

  • Get a list of directories in the target location: Get-ChildItem \\myserver\myshare\myshare\ -Directory
  • Extract only the name of the directories: Select-Object -Property name
  • Convert the output to CSV format: convertto-csv -NoTypeInformation
  • Save the result to a file: Out-File c:\temp\mydirectorylist.csv
Xe answered 20/10, 2014 at 2:35 Comment(2)
It would be great if you can explain each step so that more people can see what is going on.Jaunty
This won't work in Powershell 2.0 which was the specific need of the OP. the -[/Dir/Directory] are not valid parameters in Powershell 2.0Strangury
E
3

You'll want to use Get-ChildItem to recursively get all folders and files first. And then pipe that output into a Where-Object clause which only take the files.

# 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 ;
}
Eck answered 12/1, 2016 at 18:40 Comment(0)
H
2

A bit more readable and simple approach could be achieved with the script below:

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

Hope this helps!

Hydrochloride answered 27/8, 2013 at 23:3 Comment(2)
$_.Attributes -eq "Directory" will fail as soon as the Directory has any attribute other than Directory i.e. Hidden, System, ReadOnly etc. The right way to do it is $_.Attributes.HasFlag([System.IO.FileAttributes]::Directory)Fokine
"Directory" -in $_.Attributes would work as well.Delozier
R
1

My solution is based on the TechNet article Fun Things You Can Do With the Get-ChildItem Cmdlet.

Get-ChildItem C:\foo | Where-Object {$_.mode -match "d"}

I used it in my script, and it works well.

Rivers answered 3/2, 2015 at 8:7 Comment(0)
P
1

This question is well and truly answered but thought I'd add something extra as I've just been looking at this.

Get-ChildItem happens to produce two types of objects whereas most commands produce just one.

FileInfo and DirectoryInfo are returned.

You can see this by viewing the 'members' available to this command like so:

Get-ChildItem | Get-Member
  • TypeName: System.IO.DirectoryInfo
  • TypeName: System.IO.FileInfo

You'll see the various methods and properties available to each type. Note that there are differences. For example that the FileInfo object has a length property but the DirectoryInfo object doesn't.

Anyway, technically, we can return just the directories by isolating the DirectoryInfo object

Get-ChildItem | Where-Object {$_.GetType().Name -eq "DirectoryInfo"}

Obviously as the top answer states the most straightforward solution is to simply use Get-ChildItem -Directory but we now know how to work with multple object types in future :)

Peacoat answered 19/4, 2022 at 15:57 Comment(1)
This is probably not the easiest way, but it is a helpful insight, thanks!Geophyte
P
0

Use this one:

Get-ChildItem -Path \\server\share\folder\ -Recurse -Force | where {$_.Attributes -like '*Directory*'} | Export-Csv -Path C:\Temp\Export.csv -Encoding "Unicode" -Delimiter ";"
Plethoric answered 14/8, 2013 at 6:49 Comment(0)
D
0

To answer the original question specifically (using IO.FileAttributes):

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

I do prefer Marek's solution though:

Where-Object { $_ -is [System.IO.DirectoryInfo] }
Delozier answered 4/10, 2017 at 12:47 Comment(0)
D
0

You can try the PsIsContainer Object

Get-ChildItem -path C:\mypath -Recurse | where {$_.PsIsContainer -eq $true} 
Diapophysis answered 5/12, 2022 at 2:7 Comment(1)
Is this different from the answer https://mcmap.net/q/99511/-how-do-i-get-only-directories-using-get-childitem (2010)?Oleta
C
0

TRY THE FOLLOWING
dir -Directory -Name

Castlereagh answered 4/10, 2023 at 18:37 Comment(0)
E
0

Here is what I use which gives you both the directory and the filename:

Get-ChildItem "c:\mypath" -Recurse |  ForEach-Object {
    $directory = Split-Path $$_.Fullname -parent
    Write-Host "directory = $directory"
    $file = Split-Path $$_.Fullname -leaf
    Write-Host "file = $file"
}
Ehlers answered 27/3 at 21:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.