PowerShell 2 min read

PowerShell: Speed Up Get-ChildItem to Scan Files in a Large File System

Michael Wu ·

I wrote a PowerShell script for scanning PST files in a large file system. It took about 19–21 hours to scan PST files in the 28 TB file system.

The Slow Way

$stamp = Get-Date

$location = "\\deptshare\shares"
$csvfile  = "C:\temp\pstfiles\" + $(Get-Date -Format yyyyMMddHmm) + "deptshare-pst.csv"
$pstarray = @()

ForEach ($share in Get-ChildItem $location) {
    Write-Host "Scanning $share..."
    Get-ChildItem $share.FullName -recurse -file -force -ErrorAction SilentlyContinue |
        Where-Object { $_.extension -eq ".pst" } |
        ForEach-Object {
            $pstobj = New-Object PSObject
            $pstobj | Add-Member NoteProperty Directory $_.DirectoryName
            $pstobj | Add-Member NoteProperty Name $_.Name
            $pstobj | Add-Member NoteProperty Owner ((Get-ACL $_.FullName).Owner)
            $pstobj | Add-Member NoteProperty CreationTime $_.CreationTime
            $pstobj | Add-Member NoteProperty LastWriteTime $_.LastWriteTime
            $pstobj | Add-Member NoteProperty Length $_.Length
            $pstarray += $pstobj
        }
}

The key slowdown was the Get-ChildItem cmdlet combined with Where-Object.

Measure-Command Experiment (60 GB scan)

Old way — took 307 seconds:

Get-ChildItem $share.FullName -recurse -file -force -ErrorAction SilentlyContinue |
    Where-Object { $_.extension -eq ".pst" }

New way — took only 19 seconds:

Get-ChildItem $share.FullName -recurse -file -force -Include *.pst -ErrorAction SilentlyContinue

Using -Include *.pst instead of Where-Object { $_.extension -eq ".pst" } provides a massive speed improvement.

After applying this change in production, the scan time reduced to 14 hours from 21 hours. Massive improvement!