Home > other >  Powershell to bulk move files from local directory to network drive taking folder names
Powershell to bulk move files from local directory to network drive taking folder names

Time:08-05

Forgive me but i am VERY new to Powershell, i.e. this is the first script I've ever tried to write. I want to move files from sub-directories of the folder \Export on one drive, to the same folder name on a network drive location. I'm using my local drive for both locations in the test (-WHatIf) example below but i was trying as a test something like;

$_SourcePath = "C:\exports"
$_dest = "c:\temp\exports\"
$_FileType= @("*.xml")
# Get all files and group by base name
$_command =  Get-ChildItem -recurse ($_sourcePath) -include ($_FileType) | Where-Object {$_.CreationTime -lt (Get-Date).AddMinutes(-5)} | ForEach-Object {
   "move-Item -Path $($_sourcepath)\$($_.Directory.Name)\$($_.Name) -Destination $($_dest)$($_.Directory.Name)\$($_.Name) -WHatif"   }
$_command | ForEach-Object { $_ 
Invoke-Expression $_command  }

so the script should (eventually once I've removed the -WhatIf) move all .xml files from \export\folder, \export\folder2 etc. into temp\export\folder1, temp\export\folder2 etc. whilst retaining the same filenames.

The issue is that the -destination object will not take the (what looks like a valid) string value being passed into it. I'm sure there's 1001 other ways to do this, but having tried several, I'm now at the sum extent to my Googling & knowledge skills. Thanks all.

CodePudding user response:

When I run your code as written, I get this error:

Invoke-Expression : Cannot convert 'System.Object[]' to the type 'System.String' required by parameter 'Command'.

This is because Invoke-Expression needs to take $_ as its argument in order to run each command.

When correcting that problem, I then ran into the issue of the target directory not existing - but I'm sure you've already created your target directory C:\temp\exports?

It is possible to reduce your code further by simply having the Move-Item -WhatIf command run inside the first loop, meaning there's no need to build a list of commands to run with invoke-expression - however I can see the benefit of generating a list of commands should you wish to log them somewhere or review them before executing (but the -WhatIf sort of provides that functionality). Here's the single loop version:

$_SourcePath = "C:\exports"
$_dest = "c:\temp\exports\"
$_FileType= @("*.xml")

# Get all files and group by base name
Get-ChildItem -recurse ($_sourcePath) -include ($_FileType) | `
Where-Object {$_.CreationTime -lt (Get-Date).AddMinutes(-5)} | `
ForEach-Object {
   move-Item -Path "$_.FullName" `
   -Destination "$($_dest)$($_.Directory.Name)\$($_.Name)" `
   -WHatif   
}

Other changes:

  • Wrapped paths in quotes to avoid paths-with-spaces issues
  • Changed the input path in Move-Item to $_.FullName as the Get-ChildItem command provides the full path property as part of its output
  • Added some backticks to split long commands over lines
  • Removal of $_command variable - no longer required
  • Related