PowerShell provides powerful cmdlets for managing files and folders, making it an essential tool for system administrators and developers. The three core cmdlets—Get-ChildItem, Copy-Item, and Remove-Item—form the foundation of file system management in PowerShell. This comprehensive guide explores these cmdlets with practical examples and real-world scenarios.

Understanding Get-ChildItem: Listing Files and Folders

Get-ChildItem is PowerShell’s equivalent to the dir or ls commands. It retrieves items from specified locations, typically files and folders, and offers extensive filtering capabilities.

Basic Syntax and Usage

The simplest form of Get-ChildItem lists all items in the current directory:

Get-ChildItem

Visual output:

Directory: C:\Users\YourName\Documents

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d-----        10/15/2025   2:30 PM                Projects
d-----        10/18/2025   9:45 AM                Scripts
-a----        10/20/2025   1:15 PM           2048 report.txt
-a----        10/22/2025  10:30 AM          15360 data.xlsx

The alias gci or traditional dir and ls can also be used:

gci
dir
ls

Specifying Paths and Locations

Target specific directories by providing a path:

Get-ChildItem -Path "C:\Windows\System32"
Get-ChildItem -Path ".\Projects"  # Relative path

Recursive Directory Traversal

The -Recurse parameter searches through all subdirectories:

Get-ChildItem -Path "C:\Projects" -Recurse

This searches the entire directory tree, listing all nested files and folders.

Managing Files and Folders with PowerShell: Complete Guide to Get-ChildItem, Copy-Item, and Remove-Item

Filtering by File Type and Name

Use the -Filter parameter for efficient wildcard matching:

# Find all PowerShell scripts
Get-ChildItem -Path "C:\Scripts" -Filter "*.ps1"

# Find all text files
Get-ChildItem -Filter "*.txt"

# Find files starting with "report"
Get-ChildItem -Filter "report*"

Example output:

Directory: C:\Scripts

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----        10/10/2025   3:20 PM           1024 backup.ps1
-a----        10/12/2025   4:15 PM           2560 deploy.ps1
-a----        10/20/2025  11:00 AM            768 cleanup.ps1

Advanced Filtering with -Include and -Exclude

For multiple patterns or exclusions, use -Include and -Exclude:

# Include multiple file types
Get-ChildItem -Path "C:\Projects" -Recurse -Include "*.ps1", "*.json", "*.xml"

# Exclude specific patterns
Get-ChildItem -Path "C:\Logs" -Exclude "*.tmp", "*.bak"

# Combine both
Get-ChildItem -Recurse -Include "*.log" -Exclude "*debug*"

Filtering by Attributes

Filter files based on attributes like hidden, system, or read-only:

# Find hidden files
Get-ChildItem -Hidden

# Find directories only
Get-ChildItem -Directory

# Find files only
Get-ChildItem -File

# Find read-only files
Get-ChildItem -Attributes ReadOnly

Working with File Properties

Access detailed properties using the pipeline:

# Get files larger than 1MB
Get-ChildItem -File | Where-Object { $_.Length -gt 1MB }

# Find files modified in the last 7 days
Get-ChildItem -File | Where-Object { $_.LastWriteTime -gt (Get-Date).AddDays(-7) }

# Sort by size descending
Get-ChildItem -File | Sort-Object Length -Descending | Select-Object Name, Length

Example output with size filtering:

Name                Length
----                ------
database.bak      52428800
archive.zip       15728640
backup.tar         8388608

Copy-Item: Copying Files and Folders

Copy-Item duplicates files and directories from one location to another, supporting wildcards and recursive operations.

Basic File Copying

# Copy a single file
Copy-Item -Path "C:\Source\report.txt" -Destination "C:\Backup\"

# Copy and rename
Copy-Item -Path ".\config.json" -Destination ".\config.backup.json"

# Copy using alias
cp "file.txt" "file_copy.txt"
copy "document.docx" "D:\Backup\"

Copying Multiple Files

# Copy all text files
Copy-Item -Path "C:\Source\*.txt" -Destination "C:\Backup\"

# Copy specific file types
Copy-Item -Path ".\*.ps1" -Destination "D:\Scripts\"

Recursive Directory Copying

Copy entire directory structures with -Recurse:

# Copy folder and all contents
Copy-Item -Path "C:\Projects\WebApp" -Destination "C:\Backup\WebApp" -Recurse

# Copy contents of a folder
Copy-Item -Path "C:\Source\*" -Destination "C:\Destination\" -Recurse

Managing Files and Folders with PowerShell: Complete Guide to Get-ChildItem, Copy-Item, and Remove-Item

Force and Overwrite Options

Handle existing files with the -Force parameter:

# Overwrite existing files without prompting
Copy-Item -Path ".\source.txt" -Destination ".\dest.txt" -Force

# Copy hidden/system files
Copy-Item -Path "C:\Source\*" -Destination "C:\Backup\" -Force -Recurse

Filtering During Copy

Combine Copy-Item with filtering:

# Copy only specific file types
Get-ChildItem -Path "C:\Source" -Filter "*.log" | Copy-Item -Destination "C:\Logs\"

# Copy files modified in last 24 hours
Get-ChildItem -File | Where-Object { $_.LastWriteTime -gt (Get-Date).AddHours(-24) } | 
    Copy-Item -Destination "C:\Recent\"

Container and Literal Path Options

# Copy just the files, not the container folder
Copy-Item -Path "C:\Source\*" -Destination "C:\Dest\" -Recurse

# Use literal path for special characters
Copy-Item -LiteralPath "C:\Folder[1]\file.txt" -Destination "C:\Backup\"

Practical Copy Scenarios

# Backup script files with timestamp
$timestamp = Get-Date -Format "yyyyMMdd_HHmmss"
Copy-Item -Path "C:\Scripts\*.ps1" -Destination "C:\Backup\Scripts_$timestamp\"

# Copy and maintain directory structure
Get-ChildItem -Path "C:\Projects" -Include "*.config" -Recurse | 
    ForEach-Object {
        $dest = $_.FullName.Replace("C:\Projects", "C:\Backup")
        $destDir = Split-Path $dest
        if (!(Test-Path $destDir)) { New-Item -ItemType Directory -Path $destDir -Force }
        Copy-Item $_.FullName -Destination $dest
    }

Remove-Item: Deleting Files and Folders

Remove-Item permanently deletes files and folders. Use with caution as deletions are typically not recoverable from the command line.

Basic File Deletion

# Delete a single file
Remove-Item -Path "C:\Temp\oldfile.txt"

# Delete using alias
rm "file.txt"
del "document.docx"

Warning: Files deleted with Remove-Item bypass the Recycle Bin and are permanently removed.

Deleting Multiple Files

# Delete all text files
Remove-Item -Path "C:\Temp\*.txt"

# Delete specific patterns
Remove-Item -Path ".\temp_*"
Remove-Item -Path ".\*.tmp", ".\*.bak"

Recursive Deletion

Delete directories and all contents:

# Delete folder and everything inside
Remove-Item -Path "C:\OldProject" -Recurse

# Delete contents but keep folder
Remove-Item -Path "C:\Logs\*" -Recurse

Managing Files and Folders with PowerShell: Complete Guide to Get-ChildItem, Copy-Item, and Remove-Item

Force Deletion

Override read-only and hidden attributes:

# Force delete read-only files
Remove-Item -Path ".\readonly.txt" -Force

# Force delete hidden files and folders
Remove-Item -Path "C:\HiddenFolder" -Recurse -Force

Confirmation and WhatIf

Preview or confirm deletions before executing:

# Preview what would be deleted (doesn't actually delete)
Remove-Item -Path "C:\Temp\*" -Recurse -WhatIf

# Prompt for confirmation
Remove-Item -Path ".\important_*" -Confirm

Example -WhatIf output:

What if: Performing the operation "Remove File" on target "C:\Temp\file1.txt".
What if: Performing the operation "Remove File" on target "C:\Temp\file2.log".
What if: Performing the operation "Remove Directory" on target "C:\Temp\OldFolder".

Safe Deletion Patterns

# Delete files older than 30 days
Get-ChildItem -Path "C:\Logs" -Recurse -File | 
    Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-30) } | 
    Remove-Item -Force

# Delete empty directories
Get-ChildItem -Path "C:\Projects" -Recurse -Directory | 
    Where-Object { (Get-ChildItem $_.FullName).Count -eq 0 } | 
    Remove-Item -Force

# Delete specific file types older than a date
Get-ChildItem -Path ".\Temp" -Filter "*.tmp" | 
    Where-Object { $_.CreationTime -lt (Get-Date "2025-01-01") } | 
    Remove-Item -WhatIf  # Use -WhatIf first to verify

Exclude Patterns During Deletion

# Delete all except certain files
Get-ChildItem -Path "C:\Temp" -Exclude "*.config", "*.json" | Remove-Item -Recurse

# Delete logs but keep the latest
Get-ChildItem -Path ".\Logs\*.log" | 
    Sort-Object LastWriteTime -Descending | 
    Select-Object -Skip 5 | 
    Remove-Item

Combining Cmdlets for Advanced Operations

The real power of PowerShell emerges when combining these cmdlets with pipelines and other commands.

Move Operation (Copy + Remove)

PowerShell has Move-Item, but you can achieve it with copy and remove:

# Move files (using Move-Item)
Move-Item -Path ".\source.txt" -Destination ".\Archive\"

# Manual move with validation
$source = "C:\Source\file.txt"
$dest = "C:\Archive\file.txt"
Copy-Item -Path $source -Destination $dest
if (Test-Path $dest) {
    Remove-Item -Path $source
}

Backup and Cleanup Workflow

# Create dated backup folder
$backupPath = "C:\Backups\Backup_$(Get-Date -Format 'yyyyMMdd')"
New-Item -ItemType Directory -Path $backupPath -Force

# Copy important files
Get-ChildItem -Path "C:\Projects" -Include "*.config", "*.json" -Recurse | 
    Copy-Item -Destination $backupPath -Force

# Remove old backups (older than 30 days)
Get-ChildItem -Path "C:\Backups" -Directory | 
    Where-Object { $_.CreationTime -lt (Get-Date).AddDays(-30) } | 
    Remove-Item -Recurse -Force

Organize Files by Extension

# Organize downloads by file type
$extensions = @("*.pdf", "*.docx", "*.xlsx", "*.jpg", "*.png")
$basePath = "C:\Users\YourName\Downloads"

foreach ($ext in $extensions) {
    $folderName = $ext.Replace("*.", "").ToUpper() + "_Files"
    $destPath = Join-Path $basePath $folderName
    
    if (!(Test-Path $destPath)) {
        New-Item -ItemType Directory -Path $destPath
    }
    
    Get-ChildItem -Path $basePath -Filter $ext | 
        Move-Item -Destination $destPath
}

Managing Files and Folders with PowerShell: Complete Guide to Get-ChildItem, Copy-Item, and Remove-Item

Synchronization Script

# Simple sync: copy newer files from source to destination
$source = "C:\Projects\Active"
$dest = "C:\Backup\Projects"

Get-ChildItem -Path $source -Recurse -File | ForEach-Object {
    $sourcePath = $_.FullName
    $destPath = $sourcePath.Replace($source, $dest)
    $destDir = Split-Path $destPath
    
    # Create destination directory if needed
    if (!(Test-Path $destDir)) {
        New-Item -ItemType Directory -Path $destDir -Force | Out-Null
    }
    
    # Copy if destination doesn't exist or source is newer
    if (!(Test-Path $destPath) -or $_.LastWriteTime -gt (Get-Item $destPath).LastWriteTime) {
        Copy-Item -Path $sourcePath -Destination $destPath -Force
        Write-Host "Synced: $($_.Name)" -ForegroundColor Green
    }
}

Find and Archive Large Files

# Find files larger than 100MB and move to archive
$threshold = 100MB
$archivePath = "D:\Archive"

Get-ChildItem -Path "C:\Projects" -Recurse -File | 
    Where-Object { $_.Length -gt $threshold } | 
    ForEach-Object {
        Write-Host "Archiving: $($_.Name) ($([math]::Round($_.Length/1MB, 2)) MB)"
        Move-Item -Path $_.FullName -Destination $archivePath
    }

Error Handling and Best Practices

Using Try-Catch Blocks

try {
    Get-ChildItem -Path "C:\NonExistent" -ErrorAction Stop
} catch {
    Write-Host "Error: $_" -ForegroundColor Red
}

# Copy with error handling
$files = Get-ChildItem -Path "C:\Source" -Filter "*.txt"
foreach ($file in $files) {
    try {
        Copy-Item -Path $file.FullName -Destination "C:\Backup\" -ErrorAction Stop
        Write-Host "Copied: $($file.Name)" -ForegroundColor Green
    } catch {
        Write-Host "Failed to copy $($file.Name): $_" -ForegroundColor Red
    }
}

Testing Path Existence

# Check before operations
if (Test-Path "C:\Source\file.txt") {
    Copy-Item -Path "C:\Source\file.txt" -Destination "C:\Backup\"
} else {
    Write-Host "Source file not found" -ForegroundColor Yellow
}

# Ensure destination directory exists
$destPath = "C:\Backup\NewFolder"
if (!(Test-Path $destPath)) {
    New-Item -ItemType Directory -Path $destPath -Force
}
Copy-Item -Path ".\files\*" -Destination $destPath

Performance Considerations

# Efficient: Use -Filter at cmdlet level
Get-ChildItem -Path "C:\Large" -Filter "*.log" -Recurse

# Less efficient: Filtering after retrieval
Get-ChildItem -Path "C:\Large" -Recurse | Where-Object { $_.Extension -eq ".log" }

# Batch operations for better performance
$files = Get-ChildItem -Path "C:\Source" -Filter "*.txt"
$files | Copy-Item -Destination "C:\Backup\" -Force

Logging Operations

# Create operation log
$logFile = "C:\Logs\file_operations_$(Get-Date -Format 'yyyyMMdd').log"

function Write-Log {
    param($Message)
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    "$timestamp - $Message" | Add-Content -Path $logFile
}

# Use in operations
Get-ChildItem -Path "C:\Source" | ForEach-Object {
    try {
        Copy-Item -Path $_.FullName -Destination "C:\Backup\" -Force
        Write-Log "SUCCESS: Copied $($_.Name)"
    } catch {
        Write-Log "ERROR: Failed to copy $($_.Name) - $_"
    }
}

Real-World Automation Scripts

Daily Backup Script

# Daily automated backup with rotation
$sourcePath = "C:\Important"
$backupRoot = "D:\Backups"
$date = Get-Date -Format "yyyyMMdd"
$backupPath = Join-Path $backupRoot "Backup_$date"

# Create backup directory
New-Item -ItemType Directory -Path $backupPath -Force | Out-Null

# Copy files
Write-Host "Starting backup..." -ForegroundColor Cyan
Get-ChildItem -Path $sourcePath -Recurse | 
    Copy-Item -Destination $backupPath -Recurse -Force

# Remove backups older than 7 days
Get-ChildItem -Path $backupRoot -Directory | 
    Where-Object { $_.Name -match "Backup_\d{8}" -and $_.CreationTime -lt (Get-Date).AddDays(-7) } | 
    Remove-Item -Recurse -Force

Write-Host "Backup completed: $backupPath" -ForegroundColor Green

Log Cleanup Script

# Clean old log files
$logPaths = @("C:\Logs\Application", "C:\Logs\System", "C:\Logs\Security")
$retentionDays = 30

foreach ($path in $logPaths) {
    if (Test-Path $path) {
        Write-Host "Cleaning logs in $path..." -ForegroundColor Cyan
        
        $deletedCount = 0
        $deletedSize = 0
        
        Get-ChildItem -Path $path -Filter "*.log" -Recurse | 
            Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-$retentionDays) } | 
            ForEach-Object {
                $deletedSize += $_.Length
                $deletedCount++
                Remove-Item -Path $_.FullName -Force
            }
        
        Write-Host "Deleted $deletedCount files ($([math]::Round($deletedSize/1MB, 2)) MB)" -ForegroundColor Green
    }
}

Directory Structure Report

# Generate directory size report
$targetPath = "C:\Projects"
$reportPath = "C:\Reports\directory_report_$(Get-Date -Format 'yyyyMMdd').csv"

$report = Get-ChildItem -Path $targetPath -Directory | ForEach-Object {
    $size = (Get-ChildItem -Path $_.FullName -Recurse -File | 
        Measure-Object -Property Length -Sum).Sum
    
    [PSCustomObject]@{
        Directory = $_.Name
        FullPath = $_.FullName
        FileCount = (Get-ChildItem -Path $_.FullName -Recurse -File).Count
        SizeMB = [math]::Round($size / 1MB, 2)
        LastModified = $_.LastWriteTime
    }
} | Sort-Object SizeMB -Descending

$report | Export-Csv -Path $reportPath -NoTypeInformation
$report | Format-Table -AutoSize

Common Patterns and Shortcuts

Quick Reference Commands

# List files by size
gci | sort Length -Descending | select Name, @{N="Size(MB)";E={[math]::Round($_.Length/1MB,2)}}

# Count files by extension
gci -File | group Extension | select Name, Count | sort Count -Descending

# Find duplicate filenames
gci -Recurse -File | group Name | where Count -gt 1 | select Name, Count

# Get total directory size
(gci -Recurse -File | measure Length -Sum).Sum / 1GB

# Find empty folders
gci -Recurse -Directory | where { (gci $_.FullName).Count -eq 0 }

# Recent files (last 24 hours)
gci -Recurse -File | where LastWriteTime -gt (Get-Date).AddHours(-24)

Useful Aliases

# Get-ChildItem aliases
gci, dir, ls

# Copy-Item aliases
copy, cp, cpi

# Remove-Item aliases
del, erase, rd, ri, rm, rmdir

# Example usage
ls | where Name -like "*.txt" | cp -Destination C:\Backup\
dir *.log | where Length -gt 1MB | rm -Force

Security Considerations

Always validate paths and implement safeguards when working with file operations:

# Validate user input
function Remove-SafeFolder {
    param(
        [Parameter(Mandatory)]
        [string]$Path
    )
    
    # Prevent deletion of critical paths
    $protectedPaths = @("C:\Windows", "C:\Program Files", "C:\Users")
    
    foreach ($protected in $protectedPaths) {
        if ($Path -like "$protected*") {
            Write-Host "Cannot delete protected path: $Path" -ForegroundColor Red
            return
        }
    }
    
    if (Test-Path $Path) {
        Remove-Item -Path $Path -Recurse -Force -Confirm
    }
}

# Always use -WhatIf for destructive operations in scripts
$dryRun = $true
if ($dryRun) {
    Remove-Item -Path $targetPath -Recurse -WhatIf
} else {
    Remove-Item -Path $targetPath -Recurse -Force
}

Summary and Key Takeaways

Mastering Get-ChildItem, Copy-Item, and Remove-Item provides a solid foundation for PowerShell file management:

  • Get-ChildItem is your primary tool for discovering and filtering files with extensive options for recursion, filtering, and attribute-based selection
  • Copy-Item handles file and directory duplication with support for wildcards, recursion, and force operations
  • Remove-Item permanently deletes files and folders—always use -WhatIf first with recursive operations
  • Combine cmdlets through pipelines for powerful automation workflows
  • Implement error handling and logging for production scripts
  • Use -Filter at the cmdlet level for better performance on large directories
  • Always validate paths and implement safety checks for destructive operations

These three cmdlets form the cornerstone of file system automation in PowerShell. By combining them with conditional logic, loops, and other PowerShell features, you can create robust scripts for backup, cleanup, organization, and maintenance tasks. Practice with -WhatIf first, implement proper error handling, and your PowerShell file management skills will serve you well in system administration and development workflows.