Script to copy and move files

We are implementing a scheduled task to check the presence of a file type on a folder and if present copy the files to a backup folder and then move them to network share on another server. After successful copy and move, an email must be sent as confirmation. In case any error faces during the copy phase, further steps should not be processed and send an email that the copy failed. If copy success but the move fails, an email must be sent that the move has been failed. We tried our best to do it with below script but could not succeed. Anyone can help to correct the script?

If (Test-Path D:\SHARE\SRC\* -Filter *.xyz) {
    $fileName = (Get-Item D:\SHARE\SRC\* -Filter *.xyz).Name
    Copy-Item -Path D:\SHARE\SRC\* -Filter *.xyz -Destination D:\SHARE\SRC\SRCBAK\ -ErrorVariable CopyFailed
    Get-ChildItem D:\SHARE\SRC\* -Filter *.xyz | Move-Item -Destination \\SERVER1\DEST\FILES\ -Force -ErrorAction Stop;Send-MailMessage -To name@company.com -From name@company.com   -Subject “File Copy Status” -Body “File move filed to \\SERVER1\DEST\FILES\” -SmtpServer “relay.company.com” -Port 25;Exit
    Send-MailMessage -To name@company.com -From name@company.com  -Subject “File Copy Status” -Body “$fileName processed successfully!” -SmtpServer “relay.company.com” -Port 25
if ($CopyFailed {
    Send-MailMessage -To name@company.com -From name@company.com  -Subject “File Copy Status” -Body “File move filed to \\SERVER1\DEST\FILES\” -SmtpServer “relay.company.com” -Port 25;Exit
}
}

Please go back, edit your question once again and fix the formatting of your code.

When you post code, sample data, console output or error messages please format it as code using the preformatted text button ( </> ). Simply place your cursor on an empty line, click the button and paste your code.

Thanks in advance

How to format code in PowerShell.org 1 <---- Click :point_up_2:t4: :wink:

( !! Sometimes the preformatted text button hides behind the settings gear symbol. :wink: )

What exactly is your question? What does not work as expected?

1 Like

Hi,
Code has been formatted.

What I face is, in an error condition where file copy is failed, an email has been sent indicating the failure, but it goes to the next line where the move command is. Thats why we use error variable. But it was throwing an error. So need help on how to send an email when an error condition met, and stops further processing.

Quite a few issues. The big one is your code doesn’t run as you copied. You’re missing a closing paren that makes this error out to begin with. That’s definitely going to cause problems

if ($copyFailed {

is not going to work. you need a ) to close that out.

So you might want to fix that first.

Next, it sounds like you need to clarify what you want to happen. It sounds like once you attempt to copy something, if that doesn’t work you want to terminate the script. That’s not happening. THat’s probably because it’s not a terminating error: Terminating Errors - PowerShell | Microsoft Learn. TLDR it’s going to continue to run the script. If you don’t want to do so, you need to make it a terminating error and explain what you want to happen. Try catch statements are great for this kind of thing.

My suggestion is to implement try catch instead about Try Catch Finally - PowerShell | Microsoft Learn and force the errors to terminating errors by using `-ErrorAction ‘Stop’, then in your ‘Catch’ block, you can send out your email. I know this works because we have 100s of scheduled tasks that do similar stuff.

any particular reason why you’re using semicolons to break commands and forcing them on the same line? It makes the code harder to read and shouldn’t be necessary. Also you do realize that your code has an exit statement at the end of a line right after your first send mail message:

Maybe I’m missing something but how does the rest of your code run once it hits that exit statement? The way it’s written it doesn’t seem like if ($copyfailed) would ever process, or the second Send-MailMessage. It also seems a bit redundant anyway. That all looks really strange to me.

Also a couple other notes… the formatting of that code makes it hard to troubleshoot. Very long lines. Look into splatting: about Splatting - PowerShell | Microsoft Learn . Use variables to reference the same path over and over so you can have one point to update the path instead of several. I’d probably rework this script after identifying exactly what you want to happen and writing code to match that.

Thanks for the feedback, my original script was below and it worked.

If (Test-Path D:\SHARE\SRC\* -Filter *.xyz) {
    $fileName = (Get-Item D:\SHARE\SRC\* -Filter *.xyz).Name
    Copy-Item -Path D:\SHARE\SRC\* -Filter *.xyz -Destination D:\SHARE\SRC\SRCBAK\
    Get-ChildItem D:\SHARE\SRC\* -Filter *.xyz | Move-Item -Destination \\SERVER1\DEST\FILES\
    Send-MailMessage -To name@company.com -From name@company.com  -Subject “File Copy Status” -Body “$fileName processed successfully!” -SmtpServer “relay.company.com” -Port 25}

But later we had a second thought that what if there is failure either in copy or move. In that case, the script should stop and alert us by sending a failure email. We have reworked the script to achieve this and ended up with the script attached earlier.

In short, I am trying to achieve this.
We have an application that put the files on a drive. We need achieve the presence of the file every 30 minutes. If the file is present, first action is to copy to a backup location for retention purpose. If any error comes during the copy, we must receive an error email and should not process the next command whoch is move the file. If the copy is success, it should execute the next command which is move. If any errors while move, we must receive an error email as well. If both copy and move successful, we must receive an email saying the file process successfully.

Your original script and the script you shared in your last message aren’t the same. I can only base my feedback off the code you shared, so I feel like adding your script that worked previously isn’t necessarily relevant as it’s not the same code. My original point still stands that the code you shared was not valid PS code. Load it into VSCode with the PS extension, it’ll throw show you ‘problems’ at the bottom, and if you try to excecute it, it won’t work because of that mistake.

As my previous response indicates, you have several things that you can do.

  1. look into implementing try catch statements
  2. Read about terminating errors to better understand them
  3. Rework your code to be more readable so people who try to attempt to help you don’t have to pull it apart to try and figure out what’s actually happening.
try {
    Copy-Item -Path $Path-Filter *.xyz -Destination D:\SHARE\SRC\SRCBAK\ -ErrorVariable CopyFailed -ErrorAction Stop
    Send-MailMessage -To name@company.com -From name@company.com   -Subject "File Copy Status" -Body "File move filed to \\SERVER1\DEST\FILES\" -SmtpServer "relay.company.com" -Port 25
} catch {
# Do some stuff when any error happens, like Send-MailMessage like a failed message
Send-MailMessage -To name@company.com -From name@company.com  -Subject "File Copy Status" -Body "File move filed to \\SERVER1\DEST\FILES\" -SmtpServer "relay.company.com" -Port 25;Exit

}

Please do read all of the suggestions. We’re here to help not write the code, I just provided another quick example of how you might accomplish what you’re after but you may need to change to meet your needs.

Hi,

Thanks for the try catch suggestion. I have updated the script like below.

If (Test-Path D:\SHARE\SRC\* -Filter *.xyz)
{$fileName = (Get-Item D:\SHARE\SRC\* -Filter *.xyz).Name
Try{
    Copy-Item -Path D:\SHARE\SRC\* -Filter *.xyz -Destination D:\SHARE\SRC\SRCBAK\ -ErrorAction Stop
    }
Catch{
	Add-Content D:\SHARE\SRC\CopyStatus.txt -Value "File copy failed"
	Exit
	}
Try{
	Get-ChildItem D:\SHARE\SRC\* -Filter *.xyz | Move-Item -Destination D:\DEST\FILES\ -Force -ErrorAction Stop
	}
Catch{
	Add-Content D:\SHARE\SRC\CopyStatus.txt -Value "File move failed"
	Exit
	}
Add-Content D:\SHARE\SRC\CopyStatus.txt -Value "$fileName processed successfully"
}

Script is working fine except while simulating a move error. I have renamed the folder D:\DEST\FILES\ to D:\DEST\FILES1\ so that the move will fail. But the script created a file with the name D:\DEST\FILES.

Any suggestions?

If I’m understanding what you are stating, in order to simulate an error to make sure its working, you are renaming the folder so Move-Item fails. Instead it creates D:\Dest\Files. This is by design and is how the Move-Item cmdlet works. The Move-Item lets you also rename, so this is what it’s doing I think.

Move-Item (Microsoft.PowerShell.Management) - PowerShell | Microsoft Learn

See the very first example.

I think you need to play around with Move-Item some more and review the docs a bit on it.

For example, when I do `Get-ChildItem’ against a SINGLE item

Get-ChildItem -Path .\test.txt | Move-Item -Destination .\DoesNotExist

All this does is rename test.txt to DOesnotExist with no extension.

Furthemore, When I do get-childitem and have multiple file in scope, and then I feed it a folder that doesn’t exist:

Get-Childitem -Path .\ -Filter *.txt | Move-Item -Destination '.\Stuff 3\'

The first file in the pipeline gets renamed to Stuff 3 with no extension, and the rest of the files fail because they can’t create a file that already exists. if you add -force to i think it does continue without errors, it just repeats it ‘x’ times where x is the # of files you are trying to ‘move’ in the pipeline.

one approach may be to determine what errors you’ve ran into during testing (actual errors) and add logic to handle those. But when testing to try and replicate, you need to ensure you’re actually replicating the error you are trying to catch.

For example, if you are worried someone may rename the path you are moving an item too, you can use Test-Path to do a check, and if it fails that check you can send a mail message

if (Test-Path blah) {#Do your normal stuff} else { #do stuff like mail and report something is wrong!}