Moving files between directories or storage drives is performed using the Move-Item cmdlet (aliases: move, mv, mi). It relocates files and folders from one location to another, removing them from the source path entirely. It supports wildcard patterns for bulk moves and works transparently across different drives, including mapped network drives, PSDrives, and UNC paths.
Move-Item Basics
Basic Syntax
Move-Item -Path <String[]> -Destination <String> [-Force] [-PassThru] [-WhatIf] [-Confirm]Move-Item -Path "C:\Downloads\report.pdf" -Destination "C:\Archive\report.pdf"When the file is moved, there is no output to indicate success. The operation occurs silently.Verify the move:
Test-Path "C:\Downloads\report.pdf"
Test-Path "C:\Archive\report.pdf"False
TrueWhere:
-Pathspecifies the source file to move.-Destinationspecifies the target location, which can be a full file path or an existing folder.-PassThruinstructsMove-Itemto emit the resultingFileInfoobject to the pipeline.-Forceallows overwriting read-only files in the destination or replacing files if conflicts exist.
Moving to a Folder Without Renaming
If -Destination points to an existing folder rather than a full file path, the file keeps its original name.
Move-Item -Path "C:\Downloads\report.pdf" -Destination "C:\Archive\"Relocating and Renaming a Single File
$SourceFile = "$env:TEMP\Staging\app.log"
$DestFolder = "$env:TEMP\Archive"
if (-not (Test-Path -Path $DestFolder -PathType Container)) {
$null = New-Item -ItemType Directory -Path $DestFolder -Force
}
Move-Item -Path $SourceFile -Destination $DestFolder -PassThru Directory: C:\Users\Tom\AppData\Local\Temp\Archive
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 10/24/2024 11:30 PM 10240 app.logMoving Files with Wildcards
Move-Item accepts wildcard patterns (*, ?) in the -Path parameter to move batches of files matching specific naming conventions or extensions.
When moving multiple files with wildcards, the -Destination parameter must be an existing directory.
Move-Item -Path "C:\Downloads\*.pdf" -Destination "C:\Archive\"Get-ChildItem "C:\Archive" Directory: C:\Archive
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 3/14/2024 8:30 AM 102400 invoice.pdf
-a--- 3/14/2024 8:31 AM 88320 report.pdfBatch Move Example
$SourceDir = "$env:TEMP\Processing"
$TargetDir = "$env:TEMP\Completed"
Move-Item -Path "$SourceDir\*.csv" -Destination $TargetDir -Force
Get-ChildItem -Path $TargetDir -Filter "*.csv" | Select-Object -Property Name, LengthName Length
---- ------
customers-q3.csv 15420
orders-q3.csv 84200Where:
"$SourceDir\*.csv"matches all CSV files in the source directory.-Destination $TargetDirmoves all matching items into the destination folder.-Forceallows overwriting read-only files in the destination or replacing files if conflicts exist.
Combining with Get-ChildItem and Where-Object for Precision
For more selective moves than a simple wildcard allows, pipe filtered results into Move-Item.
Get-ChildItem -Path "C:\Downloads" -Filter "*.csv" |
Where-Object { $_.LastWriteTime -gt (Get-Date).AddDays(-1) } |
Move-Item -Destination "C:\Data\Recent\"Where only .csv files modified within the last day are moved, leaving older files untouched.
Cross-Drive Moves
The Move-Item cmdlet works seamlessly across various drive types, including local drives, mapped network drives, and PSDrives, without requiring any extra syntax.
Move-Item -Path "C:\Projects\output.zip" -Destination "D:\Backups\output.zip"Test-Path "C:\Projects\output.zip"
Test-Path "D:\Backups\output.zip"False
TrueMoving to a Network Share (UNC Paths)
Move-Item -Path "C:\Reports\quarterly.xlsx" -Destination "\\FileServer01\Shared\Reports\quarterly.xlsx"Where, even though the source (C:\) and destination (D:\ or a UNC share) are on different physical or logical drives, Move-Item handles the underlying copy-then-delete operation automatically.
Same-Drive vs. Cross-Drive Mechanics
Same-Volume Move (C:\Staging ──► C:\Archive):
[File Clusters on Disk] (Unchanged)
└── Master File Table (MFT) Pointer Updated ──► Instantaneous (Atomic)
Cross-Volume Move (C:\Staging ──► D:\Archive):
[File Clusters on C:] ──► Read Data ──► Write to D: ──► Verify ──► Delete from C:| Dimension | Same-Volume Move (C: to C:) |
Cross-Volume Move (C: to D: or UNC) |
|---|---|---|
| Operation Type | Metadata pointer update (atomic). | Data copy followed by source deletion. |
| Execution Speed | Near instantaneous regardless of file size. | Dependent on network/disk transfer throughput. |
| Interruption Risk | Low; filesystem updates pointer in a single transaction. | Moderate; if aborted mid-transfer, destination may hold partial files. |
| NTFS Permissions | Retains original permissions by default. | Inherits permissions of the destination parent folder. |
Practical Examples
Archiving Processed Files
A common automation pattern moves files out of an "incoming" folder once they've been processed, preventing them from being processed again on the next script run.
$incomingFolder = "C:\Data\Incoming"
$archiveFolder = "D:\Data\Archive"
if (-not (Test-Path $archiveFolder)) {
New-Item -ItemType Directory -Path $archiveFolder | Out-Null
}
Get-ChildItem -Path $incomingFolder -Filter "*.csv" | ForEach-Object {
Write-Output "Processing $($_.Name)..."
$destination = Join-Path $archiveFolder $_.Name
Move-Item -Path $_.FullName -Destination $destination
Write-Output "Archived $($_.Name) to $archiveFolder"
}Processing january.csv...
Archived january.csv to D:\Data\Archive
Processing february.csv...
Archived february.csv to D:\Data\ArchiveWhere:
- Moving each file to a separate drive (
D:\) after processing ensures theIncomingfolder only ever contains new, unprocessed files. Join-Pathsafely builds the destination path without manual string concatenation.
Automated Staging to Storage Ingestion Engine
The following production script processes an inbound staging folder, creates a destination archive directory if needed, moves all matching log and text files, and emits a structured audit report using -PassThru:
param (
[string]$SourceDirectory = "$env:TEMP\SourceDrop",
[string]$TargetDirectory = "$env:TEMP\ArchiveStore"
)
if (-not (Test-Path -Path $SourceDirectory -PathType Container)) {
Write-Error "Source directory '$SourceDirectory' does not exist."
exit 1
}
if (-not (Test-Path -Path $TargetDirectory -PathType Container)) {
Write-Output "Destination folder not found. Creating: $TargetDirectory"
$null = New-Item -ItemType Directory -Path $TargetDirectory -Force
}
$FilesToMove = Get-ChildItem -Path $SourceDirectory -File |
Where-Object { $_.Extension -in @(".log", ".txt", ".csv") }
if ($FilesToMove.Count -eq 0) {
Write-Output "No eligible files found to relocate."
exit 0
}
Write-Output "Relocating $($FilesToMove.Count) file(s) to destination..."
$MoveResults = foreach ($file in $FilesToMove) {
try {
$movedItem = Move-Item -Path $file.FullName -Destination $TargetDirectory -Force -PassThru -ErrorAction Stop
[PSCustomObject]@{
FileName = $movedItem.Name
SizeBytes = $movedItem.Length
SourcePath = $file.DirectoryName
NewLocation = $movedItem.DirectoryName
Status = "Success"
MovedTimestamp = (Get-Date -Format "yyyy-MM-dd HH:mm:ss")
}
}
catch {
[PSCustomObject]@{
FileName = $file.Name
SizeBytes = $file.Length
SourcePath = $file.DirectoryName
NewLocation = $TargetDirectory
Status = "Failed: $($_.Exception.Message)"
MovedTimestamp = (Get-Date -Format "yyyy-MM-dd HH:mm:ss")
}
}
}
$MoveResults | Format-Table -AutoSizeWhere:
Test-Pathvalidates both the source directory and ensures the target directory is available.Where-Object { $_.Extension -in ... }filters for specific supported file types.Move-Item -PassThru -ErrorAction Stopmoves each file and captures the resultingFileInfoobject.try/catchcatches locked-file errors or permission failures without aborting the loop for remaining files.[PSCustomObject]builds an audit trail of all moved files.
Execute the script from the console:
pwsh ./relocate-staging-files.ps1Destination folder not found. Creating: C:\Users\Tom\AppData\Local\Temp\ArchiveStore
Relocating 2 file(s) to destination...
FileName SizeBytes SourcePath NewLocation Status MovedTimestamp
-------- --------- ---------- ----------- ------ --------------
app-trace.log 4210 C:\Users\Tom\AppData\Local\Temp\SourceDrop C:\Users\Tom\AppData\Local\Temp\ArchiveStore Success 2024-10-24 23:58:10
orders-batch.csv 18450 C:\Users\Tom\AppData\Local\Temp\SourceDrop C:\Users\Tom\AppData\Local\Temp\ArchiveStore Success 2024-10-24 23:58:10Quick Reference
| Task | Command |
|---|---|
| Move a single file | Move-Item -Path "C:\Temp\file.txt" -Destination "C:\Archive\file.txt" |
| Move into an existing folder | Move-Item -Path "C:\Temp\file.txt" -Destination "C:\Archive\" |
| Move and rename | Move-Item -Path "C:\Temp\old.txt" -Destination "C:\Archive\new.txt" |
| Move with wildcards | Move-Item -Path "C:\Downloads\*.pdf" -Destination "C:\Archive\" |
| Move with pipeline filter | Get-ChildItem ... | Where-Object { ... } | Move-Item -Destination ... |
| Preview a move | Move-Item -Path ... -Destination ... -WhatIf |
| Overwrite destination conflicts | Move-Item -Path ... -Destination ... -Force |
| Emit moved object info | Move-Item -Path ... -Destination ... -PassThru |