Nov 252011
I wrote this PowerShell script to synchronize two folders with robocopy (each located on another physical hard disk) so I have a backup in case one hard disk fails.
The script will send the robocopy output log file as an attachment to the specified e-mail address.
# PowerShell Robocopy script with e-mail notification # Created by Michel Stevelmans - http://www.michelstevelmans.com # Change these values $SourceFolder = "C:\SourceFolder" $DestinationFolder = "C:\DestinationFolder" $Logfile = "C:\Robocopy.log" $EmailFrom = "michel.stevelmans@domain.com" $EmailTo = "michel.stevelmans@domain.com" $EmailBody = "Robocopy completed successfully. See attached log file for details" $EmailSubject = "Robocopy Summary" $SMTPServer = "smtp.domain.com" $SMTPPort = "25" # Copy Folder with Robocopy Robocopy $SourceFolder $DestinationFolder /E /ZB /R:1 /W:1 /PURGE /LOG:$Logfile /NP # Send E-mail message with log file attachment $Message = New-Object Net.Mail.MailMessage($EmailFrom, $EmailTo, $EmailSubject, $EmailBody) $Attachment = New-Object Net.Mail.Attachment($Logfile, 'text/plain') $Message.Attachments.Add($Attachment) $SMTPClient = New-Object Net.Mail.SmtpClient($SmtpServer, $SMTPPort) $SMTPClient.Send($Message)
If you want to use gmail, you have to use a different approach because gmail requires authentication, a different port and SSL.
The script below will allow you to let PowerShell use gmail to send the e-mail notification.
# PowerShell Robocopy script with e-mail notification
# Created by Michel Stevelmans - http://www.michelstevelmans.com
# Change these values
$SourceFolder = "C:\SourceFolder"
$DestinationFolder = "C:\DestinationFolder"
$Logfile = "C:\Robocopy.log"
$EmailFrom = "michel.stevelmans@domain.com"
$EmailTo = "michel.stevelmans@domain.com"
$EmailBody = "Robocopy completed successfully. See attached log file for details"
$EmailSubject = "Robocopy Summary"
$Username = "Your.GmailUsername"
$Password = "YourGmailPassword"
# Copy Folder with Robocopy
Robocopy $SourceFolder $DestinationFolder /E /ZB /R:1 /W:1 /PURGE /LOG:$Logfile /NP
# Send E-mail message with log file attachment
$Message = New-Object Net.Mail.MailMessage($EmailFrom, $EmailTo, $EmailSubject, $EmailBody)
$Attachment = New-Object Net.Mail.Attachment($Logfile, 'text/plain')
$Message.Attachments.Add($Attachment)
$SMTPClient = New-Object Net.Mail.SmtpClient("smtp.gmail.com", 587)
$SMTPClient.EnableSsl = $true
$SMTPClient.Credentials = New-Object System.Net.NetworkCredential($Username, $Password);
$SMTPClient.Send($Message)
Powershell 2.0 has a Send-MailMessage cmdlet which I think would be much easier to use.
So I tried the PS2 command and the above. With the above when I try to send to gmail (smtp.gmail.com – 465) – I get the following error
Exception calling “Send” with “1″ argument(s): “The operation has timed out.”
At C:\Users\dpeter\Desktop\Robo.ps1:23 char:17
+ $SMTPClient.Send <<<< ($Message)
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException
And wtih PS2 I get this
Send-MailMessage : The SMTP server requires a secure connection or the client was not authenticated. The server response was: 5.7.0 Must issue a STARTTLS command first. l18sm8274375an
b.22
I am pretty sure I am going around in a loop and confusing myself. So, just wondering if you ever had any success with sending through gmail? If so, what did you do?
Thanks
Hi dp,
I just updated my blogpost with a script that will allow you to use gmail.
Good luck!
Wow – I have been working on trying to get this to work with gmail for 2 days now and you just knocked it out. Thanks.
So, now I am wondering if it would be possible to set this script to only email on error. I have used some cmd files that will “notify” on error levels specified. Would it be possible to set the log file name as a date variable so each new day creates a log file with the date name?
If you can figure that out – This would be the ultimate script (well at least for me) and I would owe you!
Hi dp,
Replace the $Logfile line with the line below:
$Logfile = “C:\Robocopy-” + (Get-Date).tostring(“ddMMyyyy”) + “.log”
Nice script Michel!! Really helpfull!
What if I want to copy only files with a specific extension? ie .doc
Thanks!
Michel,
I already found the solution! Just let robocopy take care of that..
Thanks!
Thank you so much!
Excellent Script. Thanks for sharing with us.
you rock!
Hi,
This script is doing well for me. Thanks much..!
Also, I have couple of challenges.
1) Can we monitor the hard disk space, CPU usage, Memory Usage using PowerShell..?
2) I scheduled a batch script to perform daily image backups using wbadmin tool. How can I set a email notification with the job status as soon as the job completes.
Thanks,
Balu K
Hi Balu,
Monitoring of CPU, Disk etc can be done through PowerShell and WMI. If you google for this you’ll probably find lots of examples.
Hi Michel,
Thanks for the reply.
Yes, you are correct. I got many examples when I googled for the same. The best thing I got to monitor the disk space and to trigger alerts from http://www.microsoftpro.nl/2011/07/07/monitor-disk-space-using-powershell. This is working perfect. I am new to PowerShell and no idea on WMI
So, I am looking for a script, which can monitor and trigger alerts for RAM, CPU, Diskspace and probably Event Viewer Logs.
Thanks,
Balu K
i use this script but i can’t take any email….why?
my script is
# PowerShell Robocopy script with e-mail notification
# Created by Michel Stevelmans – http://www.michelstevelmans.com
$SourceFolder = “E:\TEST”
$DestinationFolder = “C:\Users\Giannis\Desktop\folder”
$Logfile = “C:\Logs\Robocopy.log”
$EmailFrom = “adfeedbk@otenet.gr”
$EmailTo = “it@ad-systems.gr”
$EmailBody = “Robocopy completed successfully. See attached log file for details”
$EmailSubject = “Robocopy Summary”
$SMTPServer = “mailgate.otenet.gr”
$SMTPPort = “25″
# Copy Folder with Robocopy
Robocopy E:\TEST C:\Users\Giannis\Desktop\folder /E /log+:C:\Logs\Robocopy.log /nfl /ndl
# Send E-mail message with log file attachment
$Message = New-Object Net.Mail.MailMessage($EmailFrom, $EmailTo, $EmailSubject, $EmailBody)
$Attachment = New-Object Net.Mail.Attachment($Logfile, ‘text/plain’)
$Message.Attachments.Add($Attachment)
$SMTPClient = New-Object Net.Mail.SmtpClient($SmtpServer, $SMTPPort)
$SMTPClient.Send($Message)
where is the problem?
Hi prelorentzos,
That is hard to say without any error messages.
Have you tried running the script through the PowerShell ISE to see the errors?
Hi Michel,
Excellent Script.
Is it possible to filter by status of the robocopy Skript.
Skript Status:
Error -> Send E-Mail
No Error -> ne Spam to me
Thanks
Tim
For the email status, I think I’ve got a solution. Thanks for Michael for a great script that with a little tweaking did exactly what I needed. Never used Powershell, but I’m liking it.
Add a variable at the top:
$SendEMail = “True”
Then after the robocopy command:
if ($LASTEXITCODE -eq 16)
{
$exit_code = “16″
$exit_reason = “***FATAL ERROR***”
}
elseif ($LASTEXITCODE -eq 8)
{
$exit_code = “8″
$exit_reason = “**FAILED COPIES**”
}
elseif ($LASTEXITCODE -eq 4)
{
$exit_code = “4″
$exit_reason = “*MISMATCHES*”
}
elseif ($LASTEXITCODE -eq 2)
{
$exit_code = “2″
$exit_reason = “EXTRA FILES”
}
elseif ($LASTEXITCODE -eq 1)
{
$exit_code = “1″
$exit_reason = “Copy Successful”
$SendEmail = “False”
}
elseif ($LASTEXITCODE -eq 0)
{
$exit_code = “0″
$exit_reason = “No Change”
$SendEmail = “False”
}
Then add this around the email section:
if ($SendEmail -eq “True”)
{
$EmailSubject = “$EmailSubject $exit_code $exit_reason”
…
…
…
}
Typo in my variable declaration.
$SendEMail = “True”
should be
$SendEmail = “True”
but powershell doesn’t appear to be case sensitive because it worked
I should also cite http://blog.pdurante.com/2010/11/10/adding-email-to-robocopy/ for the exit codes.
Thanks for sharing bscott!
Alright, so I had to take this and tweak it just a bit more, mostly just putting both bscott and Michel’s code together. So, I made it an option to send the log file as an attachment, make it the body, and check for the log size beforehand. I just wanted to put a copy of it here as a contribution of what you two already created. Great work!
I could break this down and make it more function like, or module, but it is useful enough in this form.
$SourceFolder = "C:\SourceFolder"
$DestinationFolder = "C:\DestinationFolder"
$Logfile = "C:\Robocopy.log"
$Subject = "Robocopy Results: Copy Purpose - Location to Location"
$SMTPServer = "smtp.server.com"
$Sender = "Server "
$Recipients = "User1 "
$Admin = "Admin "
$SendEmail = $True
$IncludeAdmin = $True
$AsAttachment = $False
Robocopy $SourceFolder $DestinationFolder /MIR /R:2 /W:5 /LOG:$Logfile /NP
Switch ($LASTEXITCODE)
{
16
{
$exit_code = "16"
$exit_reason = "***FATAL ERROR***"
#$IncludeAdmin = $False
}
8
{
$exit_code = "8"
$exit_reason = "**FAILED COPIES**"
#$IncludeAdmin = $False
}
4
{
$exit_code = "4"
$exit_reason = "*MISMATCHES*"
#$IncludeAdmin = $False
}
2
{
$exit_code = "2"
$exit_reason = "EXTRA FILES"
#$IncludeAdmin = $False
}
1
{
$exit_code = "1"
$exit_reason = "Copy Successful"
#$IncludeAdmin = $False
}
0
{
$exit_code = "0"
$exit_reason = "No Change"
#$SendEmail = $False
$IncludeAdmin = $False
}
}
$Subject += " : " + $exit_reason + " EC: " + $exit_code
If ((Get-ChildItem $Logfile).Length -lt 25mb)
{
If ($IncludeAdmin)
{
If ($AsAttachment)
{
Send-MailMessage -From $Sender -To $Recipients -Cc $Admin -Subject $Subject -Body "Robocopy results are attached." -Attachment $Logfile -DeliveryNotificationOption onFailure -SmtpServer $SMTPServer
} Else {
Send-MailMessage -From $Sender -To $Recipients -Cc $Admin -Subject $Subject -Body (Get-Content $LogFile | Out-String) -DeliveryNotificationOption onFailure -SmtpServer $SMTPServer
}
} Else {
If ($AsAttachment)
{
Send-MailMessage -From $Sender -To $Recipients -Subject $Subject -Body "Robocopy results are attached." -Attachment $Logfile -DeliveryNotificationOption onFailure -SmtpServer $SMTPServer
} Else {
Send-MailMessage -From $Sender -To $Recipients -Subject $Subject -Body (Get-Content $LogFile | Out-String) -DeliveryNotificationOption onFailure -SmtpServer $SMTPServer
}
}
} Else {
#Include Admin if log file was too large to email
Send-MailMessage -From $Sender -To $Recipients -Cc $Admin -Subject $Subject -Body "Logfile was too large to send, please verify it on the server." -DeliveryNotificationOption onFailure -SmtpServer $SMTPServer
#Exclude Admin if log file was too large to email
#Send-MailMessage -From $Sender -To $Recipients -Subject $Subject -Body "Logfile was too large to send, please verify it on the server." -DeliveryNotificationOption onFailure -SmtpServer $SMTPServer
}
Hey Raymond,
That’s a nice piece of code, thanks for sharing!
Hi,
When i run this on an sbs 2011 oin a powershell with admin rights I get this:
——————————————————————————-
ROBOCOPY :: Robust File Copy for Windows
——————————————————————————-
Started : Sat Sep 08 12:17:00 2012
2012/09/08 12:17:00 ERROR 3 (0×00000003) Getting File System Type of Destination z:\backup\
The system cannot find the path specified.
Source : C:\shares\
Dest – z:\backup\
Files : *.*
Options : *.* /S /E /COPY:DAT /PURGE /ZB /NP /R:1 /W:1
——————————————————————————
2012/09/08 12:17:00 ERROR 3 (0×00000003) Creating Destination Directory z:\backup\
The system cannot find the path specified.
Z:\ is a drive map to a NAS, what am I doing wrong ?
found a fix for this problem here: http://www.eversity.nl/blog/2011/07/robocopy-error-0×00003/
Thx for this script !
Hello!
First, thank you again for the cool script. I made some changes that looks like working, but I’m not sure if I’m right, only tested twice.
My problem was that I kept getting e-mails saying there was a mismatch or a failed copy, but when I looked at the two dirs, they were exactly the same size (in bytes). So I did some investigating at the robocopy exit codes, found this: http://support.microsoft.com/kb/954404
wich says “Any value greater than 8 indicates that there was at least one failure during the copy operation.” This means if I don’t want getting e-mails, I can ignore the other exitcodes. So I changed the script in the following:
I set the initial value of $SendEMail to False. After the robocopy command, my script looks like this:
if ($LASTEXITCODE -gt 7)
{
$exit_code = “$LASTEXITCODE”
$exit_reason = “ERROR or FAILURE”
$SendEMail = “True”
}
if ($SendEmail -eq “True”)
{
$EmailSubject = “$EmailSubject $exit_code $exit_reason”
$Message = New-Object Net.Mail.MailMessage($EmailFrom, $EmailTo, $EmailSubject, $EmailBody)
$Attachment = New-Object Net.Mail.Attachment($Logfile, ‘text/plain’)
$Message.Attachments.Add($Attachment)
$SMTPClient = New-Object Net.Mail.SmtpClient($SmtpServer, $SMTPPort)
$SMTPClient.Send($Message)
}
I’d like to run a batch file to check hard disk space on a computer, and if there is enough space available, run backup commands to copy files. and also If the amount of hard drive space on C is greater than 15 GB, then run this command
Michel and Raymond i say thank you. Was using a commercial package to create a backup of a archive disk and it was slow and to detailed. Looking around for a simple elegant robocopy option with email i stumbled upon this site.
Works like a charm. Many thanks!