Skip to content

PowerShell Listing Folder Contents

How to use Get-ChildItem in PowerShell to list files, filter by type, recursively search directories, and handle hidden/system items efficiently.

The Get-ChildItem cmdlet is the primary tool for listing folder contents, including files and subfolders. When working with other providers, it can also display items like registry keys or environment variables. It supports powerful filtering options for narrowing down large directory listings and emits strongly-typed .NET objects (System.IO.FileInfo and System.IO.DirectoryInfo) down the pipeline rather than plain text.

PowerShell also provides built-in aliases for this cmdlet: gci, dir, and ls. Scripts intended for sharing or long-term use should use the full cmdlet name for clarity.

Basic Usage of Get-ChildItem

list-folder-contents.ps1powershell
Get-ChildItem -Path "C:\Reports"

where -Path specifies the folder whose contents should be listed.

Consolepowershell
./list-folder-contents.ps1
Outputplaintext
    Directory: C:\Reports

Mode                 LastWriteTime         Name
----                 -------------         ----
d-----          3/10/2026  9:14 AM         Archive
-a----          3/12/2026 11:02 AM         Q1-Summary.csv
-a----          3/12/2026 11:05 AM         Q2-Summary.csv

Filtering by Item Type: -Directory and -File

To constrain results specifically to directories or files, use the mutually exclusive dynamic switch parameters -Directory (alias -ad) and -File (alias -af).

list-basic-contents.ps1powershell
$targetPath = "C:\inetpub\logs"

Write-Host "--- Directories in $targetPath ---" -ForegroundColor Cyan
$directories = Get-ChildItem -Path $targetPath -Directory
foreach ($dir in $directories) {
    [PSCustomObject]@{
        Name         = $dir.Name
        Mode         = $dir.Mode
        LastModified = $dir.LastWriteTime
    }
}

Write-Host "`n--- Files in $targetPath ---" -ForegroundColor Cyan
$files = Get-ChildItem -Path $targetPath -File
foreach ($file in $files) {
    [PSCustomObject]@{
        Name     = $file.Name
        LengthKB = [math]::Round($file.Length / 1KB, 2)
        Mode     = $file.Mode
    }
}

where:

  • -Path $targetPath: The path to the folder being enumerated. If omitted, Get-ChildItem defaults to the current working location.
  • -Directory: Filters output to return only System.IO.DirectoryInfo container objects.
  • -File: Filters output to return only System.IO.FileInfo leaf objects.
  • $file.Length: The file size in bytes, divided by 1KB using PowerShell's built-in numeric multiplier and rounded to 2 decimal places.
Consolepowershell
./list-basic-contents.ps1
Outputplaintext
--- Directories in C:\inetpub\logs ---

Name      Mode  LastModified
----      ----  ------------
FailedReq d---- 2026-03-15 08:30:12 AM
LogFiles  d---- 2026-03-30 06:00:22 AM

--- Files in C:\inetpub\logs ---

Name             LengthKB Mode
----             -------- ----
app_offline.htm      1.42 -a---
meta_config.xml      8.15 -a---

Recursive Listing with -Recurse and -Depth

The -Recurse parameter lists contents of the target folder and all of its subfolders, drilling down through the entire directory tree.

recurse-listing.ps1powershell
Get-ChildItem -Path "C:\Reports" -Recurse

where -Recurse instructs Get-ChildItem to traverse into every subfolder, listing all nested files and folders.

Outputplaintext
    Directory: C:\Reports

Mode                 LastWriteTime         Name
----                 -------------         ----
d-----          3/10/2026  9:14 AM         Archive
-a----          3/12/2026 11:02 AM         Q1-Summary.csv
-a----          3/12/2026 11:05 AM         Q2-Summary.csv

    Directory: C:\Reports\Archive

Mode                 LastWriteTime         Name
----                 -------------         ----
-a----          2/01/2026  8:45 AM         2024-Q4-Summary.csv

Constraining Traversal Depth

To prevent performance issues or deep stack traversals across large file systems, limit recursion boundaries using the -Depth parameter.

list-recursive-depth.ps1powershell
$baseDirectory = "C:\Application"

$items = Get-ChildItem -Path $baseDirectory -Recurse -Depth 1

foreach ($item in $items) {
    [PSCustomObject]@{
        RelativePath = $item.FullName.Replace($baseDirectory, "")
        Type         = if ($item.PSIsContainer) { "Directory" } else { "File" }
        Size         = if (-not $item.PSIsContainer) { $item.Length } else { $null }
    }
}

where:

  • -Recurse: Instructs Get-ChildItem to follow child subdirectories iteratively.
  • -Depth 1: Restricts traversal to the base directory (depth 0) and its immediate subdirectories (depth 1), ignoring deeper levels.
  • $item.PSIsContainer: Identifies whether the current item in the iteration is a directory or a file.
Consolepowershell
./list-recursive-depth.ps1
Outputplaintext
RelativePath            Type      Size
------------            ----      ----
\bin                    Directory
\config                 Directory
\app.config             File      1024
\bin\ServiceHost.exe    File      154880
\bin\ServiceHost.pdb    File      45056
\config\production.json File      512

Filtering Results: -Filter vs. -Include and -Exclude

PowerShell provides two primary mechanisms for filtering items returned by Get-ChildItem:

  1. Provider-Level Filtering (-Filter): Passes the search pattern directly to the underlying file system provider API. This is significantly faster because non-matching items are discarded before .NET objects are constructed in memory. However, -Filter supports only a single string pattern with standard wildcards (* and ?).
  2. Engine-Level Filtering (-Include and -Exclude): Processed by the PowerShell engine after reading items from the provider. While slower on large volumes, -Include and -Exclude accept arrays of multiple search patterns.

Using -Filter

filter-csv-files.ps1powershell
Get-ChildItem -Path "C:\Reports" -Filter "*.csv"

where -Filter "*.csv" only returns items whose name matches the pattern, in this case files ending in .csv.

Outputplaintext
    Directory: C:\Reports

Mode                 LastWriteTime         Name
----                 -------------         ----
-a----         3/12/2026 11:02 AM         Q1-Summary.csv
-a----         3/12/2026 11:05 AM         Q2-Summary.csv

Using -Include and -Exclude

-Include and -Exclude provide more flexible filtering options, such as supporting multiple patterns. However, they require -Recurse (or a wildcard path) to function properly, as they apply filtering after items are retrieved.

include-multiple-patterns.ps1powershell
Get-ChildItem -Path "C:\Reports\*" -Include "*.csv", "*.xlsx" -Recurse

where:

  • -Include "*.csv", "*.xlsx" returns items matching any of the listed patterns.
  • -Path "C:\Reports\*" where the trailing \* is required for -Include/-Exclude to correctly evaluate items inside the folder.
Outputplaintext
    Directory: C:\Reports

Mode                 LastWriteTime         Name
----                 -------------         ----
-a----         3/12/2026 11:02 AM         Q1-Summary.csv
-a----         3/12/2026 11:05 AM         Q2-Summary.csv

    Directory: C:\Reports\Archive

Mode                 LastWriteTime         Name
----                 -------------         ----
-a----         2/01/2026  8:45 AM         2024-Q4-Summary.csv
-a----         2/03/2026  9:10 AM         Budget.xlsx
exclude-pattern.ps1powershell
Get-ChildItem -Path "C:\Reports\*" -Exclude "*.csv" -Recurse

where -Exclude "*.csv" returns every item except those matching the pattern.

Outputplaintext
    Directory: C:\Reports\Archive

Mode                 LastWriteTime         Name
----                 -------------         ----
-a----         2/03/2026  9:10 AM         Budget.xlsx

Listing Hidden and System Items with -Force

By default, Get-ChildItem does not display hidden or system files. The -Force parameter reveals them, similar to dir /a in Command Prompt or ls -a in Bash.

list-hidden-files.ps1powershell
Get-ChildItem -Path "C:\Reports" -Force

where -Force includes hidden and system files/folders in the results.

Outputplaintext
    Directory: C:\Reports

Mode                 LastWriteTime         Name
----                 -------------         ----
d-----          3/10/2026  9:14 AM         Archive
-a-h--          3/11/2026  4:30 PM         .config
-a----          3/12/2026 11:02 AM         Q1-Summary.csv
-a----          3/12/2026 11:05 AM         Q2-Summary.csv

Inspecting Hidden Attributes Programmatically

list-hidden-items.ps1powershell
$repoPath = "C:\Source\Project"

$allItems = Get-ChildItem -Path $repoPath -Force

foreach ($item in $allItems) {
    $attributes = $item.Attributes.ToString()
    $isHidden = ($item.Attributes -band [System.IO.FileAttributes]::Hidden) -ne 0

    [PSCustomObject]@{
        Name       = $item.Name
        IsHidden   = $isHidden
        Attributes = $attributes
    }
}

where:

  • -Force: Overrides the default suppression of hidden and system files/directories.
  • $item.Attributes: An enum flags property representing the low-level NTFS file attributes.
  • -band [System.IO.FileAttributes]::Hidden: Performs a bitwise AND comparison against the Hidden attribute flag to verify whether the item is hidden.
Consolepowershell
./list-hidden-items.ps1
Outputplaintext
Name         IsHidden Attributes
----         -------- ----------
.git             True Directory, Hidden
.gitignore      False Archive
README.md       False Archive
src             False Directory

Practical Usage: Auditing Storage Consumption

A common administrative task involves searching recursively for files that meet specific criteria. For example, you might need to locate all .log files larger than 10 MB or audit storage consumption across deeply nested directory trees to free up space.

The following script performs a recursive audit across a directory tree, including hidden items, and identifies the top five largest files larger than a specified threshold:

audit-large-files.ps1powershell
param (
    [string]$AuditDirectory = "C:\DataStorage",
    [int64]$MinimumSizeMB = 10
)

$thresholdBytes = $MinimumSizeMB * 1MB

Write-Host "Scanning '$AuditDirectory' for files larger than $MinimumSizeMB MB..." -ForegroundColor Cyan

$largeFiles = Get-ChildItem -LiteralPath $AuditDirectory -File -Recurse -Force -ErrorAction SilentlyContinue |
    Where-Object { $_.Length -gt $thresholdBytes } |
    Sort-Object -Property Length -Descending |
    Select-Object -First 5

if ($largeFiles.Count -eq 0 -and $null -eq $largeFiles) {
    Write-Host "No files found exceeding the $MinimumSizeMB MB threshold." -ForegroundColor Green
    return
}

$largeFiles | Select-Object @(
    @{ Name = "FileName";    Expression = { $_.Name } },
    @{ Name = "Size(MB)";    Expression = { [math]::Round($_.Length / 1MB, 2) } },
    @{ Name = "IsHidden";    Expression = { ($_.Attributes -band [System.IO.FileAttributes]::Hidden) -ne 0 } },
    @{ Name = "Directory";   Expression = { $_.DirectoryName } }
) | Format-Table -AutoSize

where:

  • -LiteralPath $AuditDirectory: Reads paths containing special characters (such as brackets []) verbatim without wildcard expansion.
  • -ErrorAction SilentlyContinue: Suppresses non-terminating permission errors on protected directories.
  • Where-Object { $_.Length -gt $thresholdBytes }: Filters out any file smaller than the byte threshold.
  • Sort-Object -Property Length -Descending: Sorts files in descending order by size.
  • Select-Object -First 5: Limits results to the top 5 largest files.
Consolepowershell
./audit-large-files.ps1 -AuditDirectory "C:\DataStorage" -MinimumSizeMB 50
Outputplaintext
Scanning 'C:\DataStorage' for files larger than 50 MB...

FileName            Size(MB) IsHidden Directory
--------            -------- -------- ---------
database_backup.bak   512.45    False C:\DataStorage\Backups
memory_dump.dmp       256.00     True C:\DataStorage\CrashReports
virtual_disk.vmdk     180.20    False C:\DataStorage\VMs
transaction.log        95.12    False C:\DataStorage\Databases
installer_cache.msi    64.88     True C:\DataStorage\Installers