PowerShell: Copy/Move Files based on a regex value, retaining the folder structure, etc
The first one should ideally work. It does preserve the directory structure. But you have to be careful about copying folders. Assuming you want just the files in the pattern that you want in and you don't care about the folders being there, you can do below:
$source = "W:\IIS"$destination = "C:\Temp\DevTest" if(-not (Test-Path $destination)) { mkdir $destination | out-null}foreach ($i in Get-ChildItem -Path $source -Recurse){ if (($i.Name -notmatch "_\d{8,10}$") -and (-not $i.PsIsContainer)) { continue; } Copy-Item -Path $i.FullName -Destination $i.FullName.Replace($source,$destination).Trim($i.Name)}
You can play around with the following, which seems to get the job done (though it can use some refactoring). The core is ProcessFolder(…)
which gets called recursively.
function Log{ param($Error) if(!$script:log) { $script:log = join-path $dst "log$timestamp.txt" } $timestamp $timestamp >> $script:log $Error $Error >> $script:log}function CopyFile{ param($Path) $tmp = join-path $dst $Path.Substring($src.Length) write-host "File src: $Path" write-host "File dst: $tmp" Try { #copy the file copy $Path $tmp -Force } Catch { Log "ERROR copying file $Path to $tmp`:` $_" }}function ProcessFolder{ param($Path) $tmp = join-path $dst $Path.Substring($src.Length) write-host "Dir. src: $Path" write-host "Dir. dst: $tmp" Try { #create target directory New-Item $tmp -itemtype directory -force > $null #process files if they match dir $Path | ?{!$_.PsIsContainer -and $_.Name -match "_\d{8,10}$" } | sort | %{ CopyFile $_.FullName } #process subdirectories dir $Path | ?{$_.PsIsContainer} | sort | %{ ProcessFolder $_.FullName } #remove target directory if it contains no files on any level if( !(dir $tmp -recurse | ?{!$_.PsIsContainer}) ) { del $tmp -recurse } } Catch { Log "ERROR copying folder $Path to $tmp`:` $_" }}cls$src = "W:\IIS\"$dst = "C:\Temp\DevTest\"$log = $null$timestamp = '{0:yyyyMMddHHmmssfffffff}' -f (Get-Date)ProcessFolder $src'''DONE!'if( $log ){ echo "Check the log file: $log"}Read-Host
For me Copy-Item
is a mess you can read other StackOverflow answers this one or this other one . Here is a solution which is a kind of 'bricolage'.
$source = "W:\\IIS" # Really double \Get-ChildItem -Path $source -Recurse | Where-Object{($_.Name -match ""_\d{8,10}$") -or ($_.psiscontainer)} | % {copy-item $_.fullname ($_.fullname -replace $source,'C:\Temp\DevTest') }