Share via


Copying files using the ForEach-Object commandlet

Question

Wednesday, July 31, 2013 10:26 PM

I want to create a script that copies files from a source directory on my local machine to a network drive that creates a folder path with the date in the name. I want to use a foreach loop to copy each file as a separate object. I'm sure there are some simpler ways to do this function but I am learning powershell and thought this would make for a good learning exercise for learning the ForEach-Object commandlet.

Here is what I have and the error I am getting, need help to figure out why? Thank You...

Script Starts Here

# Backup Script for Buddy's workstation
$dtoday = get-date -format "yyyyMMdd"
$sourcepath = "C:\Users\bfox\Desktop\Docs"
$destination = "\file1\users$\bfox\backups\dtoday"
$sourcefiles = get-childitem $sourcepath  -file -Recurse

foreach ($file in $sourcefiles)
{

Copy-Item $sourcefiles -Destination $destination

}

Script Ends here

Here is the error I get:

Copy-Item : Cannot find path 'C:\Users\bfox\Desktop\Docs\WTX_8.1 Delpoys.docx' because it does not exist.
At C:\Users\bfox\Desktop\Docs\scripts\bud_backup.ps1:13 char:2
+  Copy-Item $sourcefiles -Destination $destination
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (C:\Users\bfox....1 Delpoys.docx:String) [Copy-Item], ItemNotFoundException
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.CopyItemCommand

All replies (14)

Friday, August 9, 2013 7:00 PM ✅Answered | 1 vote

Thanks guys! I found a working solution with all your help. I actually figured something out for creating the folder paths first. Using an if statement and the test-path commandlet you can do something like this. This was a great learning project for me. Thanks!

foreach ($file in $sourcefiles)
    {
    $newdir = $file.DirectoryName.Replace( $sourcepath, $destination )
     
     If (-not (test-path $newdir))
     {
        md $newdir
     }
     
      Copy-Item -Path $file.FullName -Destination $newdir
     

     }


Friday, August 9, 2013 7:04 PM ✅Answered

The entire script looks like this now, and it works perfectly with Powershell 3.0. Now the reason I have for creating a foreach loop to begin with was to do some logging on this. I'll be working on that part next. In the end, robocopy is probably easier. But this below script will work!

++++++++++++++++++++++++++++

$dtoday = get-date -format "yyyyMMdd"
$sourcepath = "C:\Test\TestA"
$destination = "C:\Test\TestB\dtoday"
$sourcefiles = get-childitem $sourcepath -File -Recurse

foreach ($file in $sourcefiles)
    {
    $newdir = $file.DirectoryName.Replace( $sourcepath, $destination )
     
     If (-not (test-path $newdir))
     {
        md $newdir
     }
     
      Copy-Item -Path $file.FullName -Destination $newdir
      

     }

+++++++++++++++++++++++++++++++


Wednesday, July 31, 2013 10:43 PM | 2 votes

When you use foreach, in each iteration, it assigns the first variable the value of an element in the array. Try something like this:

# Backup Script for Buddy's workstation
$dtoday = get-date -format "yyyyMMdd"
$sourcepath = "C:\Users\bfox\Desktop\Docs"
$destination = "\\file1\users$\bfox\backups\$dtoday"
$sourcefiles = get-childitem $sourcepath  -file -Recurse

foreach ($file in $sourcefiles)
{

Copy-Item $file.FullName -Destination "$destination\$($file.Name)"

}

In this case, you use $file to access each item as it loops through the $sourcefiles collection. $file.FullName references the full path for each item. I've also added the name of the file to the destination.

Mike


Thursday, August 1, 2013 12:06 AM

Thanks Mike! I really appreciate the simple explanation.


Thursday, August 1, 2013 12:14 AM

Just to add to Mike's example, here's a link to my favorite command reference site:

http://ss64.com/ps/foreach.html

There's a few examples there to look over as well.

Don't retire TechNet!


Thursday, August 1, 2013 9:34 PM

OK - I'm still having a bit of trouble getting this to work. I"ve made some local test folders to simplify my source and destinations. Basically I just want to take all the subfolders and files of my source path and copy them to a dated folder on my destination retaining sub folders etc.

++++++++++++++++++

$dtoday = get-date -format "yyyyMMdd"
$sourcepath = "C:\Test\TestA"
$destination = "C:\Test\TestB\dtoday"
$sourcefiles = get-childitem $sourcepath  -file -Recurse

foreach ($file in $sourcefiles)
{
Copy-Item $file.FullName -Destination "$destination\($file.Name)"
}

+++++++++++++++++++

I am getting this error:

Copy-Item : Could not find a part of the path 'C:\Test\TestB\20130801\archive_060112.pst'.
At C:\Users\buddy\Desktop\Docs\scripts\buddy_backup.ps1:10 char:1

  • Copy-Item $file.FullName -Destination "$destination\($file.Name)"

    + CategoryInfo          : NotSpecified: (:) [Copy-Item], DirectoryNotFoundException
    + FullyQualifiedErrorId : System.IO.DirectoryNotFoundException,Microsoft.PowerShell.Commands.CopyItemCommand


Thursday, August 1, 2013 10:14 PM

Try this - in your destination, you have a partial path, but I put a directory separator in there. We'll just remove that:

$dtoday = get-date -format "yyyyMMdd"
$sourcepath = "C:\Test\TestA"
$destination = "C:\Test\TestB\$dtoday"
$sourcefiles = get-childitem $sourcepath  -file -Recurse

foreach ($file in $sourcefiles)
{
Copy-Item $file.FullName -Destination "$($destination)$($file.Name)"
}

Mike


Wednesday, August 7, 2013 9:04 PM

Hi Mike,

I just tried that again and I get no error message. However I don't get the folder structure on the destination path. I get each file renamed with the "yyyyMMdd" date on the front of it. So an example would be file "abc.txt". is now "20130807". What else do you think is going on? Do we need to utilize some .net in with the power-shell to split the file path? I am trying to do this without using .net.

Thanks a lot for the feed back its much appreciated!


Wednesday, August 7, 2013 10:13 PM

Buddy,

Try this.  It will replace the source root folder with the destination root folder, leaving the rest of the path intact.

$dtoday = get-date -format "yyyyMMdd"
$sourcepath = "C:\Test\TestA"
$destination = "C:\Test\TestB\$dtoday"
$sourcefiles = get-childitem $sourcepath  -file -Recurse

foreach ($file in $sourcefiles)
{
Copy-Item $file.FullName -Destination $file.FullName.Replace( $sourcepath, $destination )
}

Thursday, August 8, 2013 5:03 PM

OK, I believe were getting somewhere now. I do get the below error message when running the above script.

The interesting thing is if I manually create the 20130808 folder along with any subfolders those files will copy the right way. So I am wondering if we need to have the script copy just the empty folder structure first?

++++++++++++++++++++++++++++++

Copy-Item : Could not find a part of the path 'C:\Test\TestB\20130808\Deployment Traning Video\lib\thumb.1373579332499.png'.
At C:\Users\bfox\Desktop\Untitled2.ps1:8 char:9
+         Copy-Item $file.FullName -Destination $file.FullName.Replace( $sourcepat ...

    + CategoryInfo          : NotSpecified: (:) [Copy-Item], DirectoryNotFoundException
    + FullyQualifiedErrorId : System.IO.DirectoryNotFoundException,Microsoft.PowerShell.Commands.CopyItemCommand

+++++++++++++++++++++++++++++++


Thursday, August 8, 2013 7:22 PM

Buddy,

Ah, yes.  Forgot about that.  That's why I usually just use robocopy.

$dtoday = get-date -format "yyyyMMdd"
$sourcepath = "C:\Test\TestA"
$destination = "C:\Test\TestB\$dtoday"
$sourcefiles = get-childitem $sourcepath  -file -Recurse

foreach ($file in $sourcefiles)
{
Robocopy.exe $file.FullName $file.FullName.Replace( $sourcepath, $destination )
}

Thursday, August 8, 2013 7:26 PM | 2 votes

Or perhaps...

$dtoday = get-date -format "yyyyMMdd"
$sourcepath = "C:\Test\TestA"
$destination = "C:\Test\TestB\$dtoday"
$sourcefiles = get-childitem $sourcepath  -file -Recurse

foreach ($file in $sourcefiles)
{
Robocopy.exe $file.DirectoryName $file.DirectoryName.Replace( $sourcepath, $destination ) $File.Name
}

Sometimes I test these things before I post them.


Thursday, August 8, 2013 7:44 PM

Sometimes I test these things before I post them.

Bah, where's the fun in that? =]

Don't retire TechNet!


Thursday, November 9, 2017 2:16 PM

Thanks its working perfectly but inside for each is the pblm