This PowerShell script allows you to set up an automated database backup alert email for your Exchange Server environment.

get-dailybackupalerts

The components of this solution are:

  • The PowerShell script itself, Get-DailyBackupAlerts.ps1
  • The Settings.xml file for customizing SMTP and other settings
  • Task Scheduler for automatically running the script each day

This script is available on the TechNet Script Gallery or Github. Comments are welcome below. If you find a bug please consider raising it as an issue on Github.

Here is a demonstration of the script in action. This video is based of earlier versions of the script, but should give you an idea of what the script is intended to do.

About the Author

Paul Cunningham

Paul is a former Microsoft MVP for Office Apps and Services. He works as a consultant, writer, and trainer specializing in Office 365 and Exchange Server. Paul no longer writes for Practical365.com.

Comments

  1. shawn

    How do i run the script with schedule task ?

    1. Vinicius Sampaio

      Config to task schedule:

      1-General:

      Run Whether user is logged on or not

      Run with highest privileges

      2-Triggers

      Daily às 07:00AM

      3-Action

      Start a program

      4-Program/Script : C:\Windows\system32\WindowsPowerShell\v1.0> .\powershell.exe

      5-Add arguments: -PSConsoleFile “H:\Program Files\Microsoft\Exchange Server\V15\Bin\exshell.psc1” -command “. c:\scripts\ExchangeServerHealth.ps1 -reportmode –SendEmail”

      1. Vinicius Sampaio

        “. c:\scripts\Get-DailyBackupAlerts.ps1 -AlwaysSend -log -Verbose”

        1. Eslam

          Hello Vinicuis
          i tried the same command but it doesn’t work with me

  2. Bianca

    Hi Paul

    I tried to schedule a Task in Task schedular to run the script daily.
    but i can’t get it running.
    so I wrote a batch, which starts the Get-DailyBackupAlerts.ps1
    so, this works

    What do i have to addjust in the script to get the mail everyday, even if there are noch failures in Backup. When I call the Script manually, I add the switch -alwaysSend.
    But how can I realize this when I start it automatically per batch in the task-scheduler?

  3. Naveen

    hi Paul, How to get the output in CSV file, i tried export-csv not working.
    In our environment, we dont allow anonymous connection. So we cant get output email in HTML.

    Regards,
    Naveen

  4. Tony

    Hi Paul, getting there, the Exchange 2010 DB’s I have excluded don’t appear.

    The db01 , db02 and so forth are Exchange 2007 Databases, while I want to report on the ones I manage, it would be handy to remove the ones I don’t. Some of those DB names are unique, but even those when added as an exclusion they still show in the report.

    I got the database names using get-mailboxdatabase , any idea where I am going wrong ?

    1. Avatar photo
      Paul Cunningham

      I’m not even sure this script works properly for Exchange 2007. You might need to include the storage group name. But I don’t have any Exchange 2007 servers running to test this.

  5. Tony

    Whoops, it stripped out some of the post, lets try again

    EG, a server and dag I want to exclude is apex10m821, the dag APEX01DAG

    I have tried adding the DB, then in desperation, the server name, but they are still reported on

    “Exclusions>APEX01DAGAPEX10M821”

    Is it something in the format of how I have added the exclusion,

    1. Tony

      the post keeps stripping out the DB15 , for the example I have added spaces so you can see I am putting them in the right format :-0

      1. Tony

        ok, it won’t let me use the < as it sees them as tags in these posts

          1. Tony

            for some reason it does not, for example, plenty across the org are called “DB01” , I add that into the settings.xml file, so it reads (as this reply will strip the tags, I will write it)

            less than DBName greater thanDB01less than /DBName greater than

            and it still reports on all those, I should just be slotting the dag name in the space between the examples ?

          2. Avatar photo
            Paul Cunningham

            Not sure what you mean by “plenty across the org are called DB01”. Each database name in an organization must be unique.

            I’ve just tested it in my lab and it’s working fine when I add each database name on its own line in the config file. All you need to add is the database name. No server names or DAG names required.

            You can run the script with -Verbose to see some more information in the output. Perhaps that will give you a clue.

  6. Tony

    Hi Paul, the script runs fine, but I cannot get the exclusions to work, we have a big environment, but I only want to report on certain servers.
    I have tried:

    DB15DB16DB17

    and as a test, the server name

    Exclusions>APEX01DAGAPEX10M821

    But still getting everything in the report, what am I doing wrong ?

  7. Mohammed Gayasuddin

    I have configured the script the one year ago and it was working fine. now we have change the backup policy from daily full to daily incremental after that I am getting alert that backup is failed how ever if I check from backup console or from exchange it shows backup is completed. Any idea ?

  8. Brette

    great script thank you
    Getting error
    ObjectNotFound: (C:\Scripts\DailyBackupAlerts.ps1-1.09\Get-DailyBackupAlerts.ps1:100 char:20
    + [xml]$ConfigFile = Get-Content “$MyDir\Settings.xml”

    any help would be appreciated

    1. Brette

      ok I got it very long day. thanks again for the script

  9. Jorn

    Hi, thanks for this report..BUt I have one question,
    getting this at the end with -verbose

    Sending email report
    Cannot validate argument on parameter ‘From’. The argument is null or empty. Provide an argument that is not null or empty, and then try the command again.

    I have edit the settings xlm file for my enviroment

    1. Jorn

      I did run with
      .\Get-DailyBackupAlerts.ps1 -AlwaysSend -Log -Verbose and without verbose
      and my settings are like this in the xlm file

      

      smtp.xxxxx.xx
      25
      replay@xxx.xx
      xxxxx@xxxxxx.xx

      48
      24

    2. Avatar photo
      Paul Cunningham

      You need to use a valid SMTP address in the XML file. If you’re trying to send the report to multiple recipients I recommend using a distribution group.

  10. Chetan G

    when i run the script, it runs fine, but in the end it gives an error
    Cannot validate argument on parameter ‘From’. The argument is null or empty

    1. Avatar photo
      Paul Cunningham

      I can’t offer any suggestions if you don’t tell me how you’re running the script. What is the command line you’re running? Did you edit the Settings.xml file correctly?

  11. Gareth Briggs

    Hi Paul,

    Have you ever merged the Test-ExchangeServerHealth and Get-DailyBackupAlerts scripts so it produces one email?

    Thanks Gareth.

    1. Avatar photo
      Paul Cunningham

      No. The main reason is because they were developed separately at different times and for different audiences.

  12. Abhishek

    how can I change the UTC Time Stamp to local time stamp

  13. Stuart

    Does anyone know why all my backup report as Full backups when i know they are incremental?

      1. Stuart

        This is last nights on one database. It was an incremental but reports as full. We use BackupExec14 to do the Exchange backups. Its not an issue just a strange.

        SnapshotLastFullBackup : True
        SnapshotLastIncrementalBackup :
        SnapshotLastDifferentialBackup :
        SnapshotLastCopyBackup :
        LastFullBackup : 30/11/2016 20:25:16
        LastIncrementalBackup :
        LastDifferentialBackup :
        LastCopyBackup :

        1. Avatar photo
          Paul Cunningham

          If those are the results that Get-MailboxDatabase returns, then Exchange thinks it is a full backup. Perhaps your backup software is actually taking a full backup. Either way, I suggest you open a case with Symantec to determine why it’s saying one thing and Exchange is saying a different thing.

          1. Stuart

            I thought it was the backup software . It is definitely doing an incremental we have 23mdb and all but two report full backups.

            I will speak to symantec.

            Thanks

  14. Roy

    Hi Paul,
    Great script but now getting the error “Cannot convert value “Never” to type “System.Int32”…”. as well now.
    Many thanks
    Roy

    1. feriber

      SOLVED:

      This happens when you have a database with no Incremental backups.
      As a workaround i’ve replaced $LastInc = “Never” with $LastInc = 2147483647.

      Technical explanation as i see it: Sorting an array with different types of values string, int has unpredictable results.

      Regards.

  15. Preston

    When I run the scripts it gives me a bunch of user accounts that it says have been corrupt or isn’t compatible with Microsoft Support Requirements…

    What is it doing?

    1. Avatar photo
      Paul Cunningham

      If you run Get-Mailbox and see a bunch of the same warnings then you’ve probably got some mailboxes with invalid attributes.

  16. Sanjay Jaswal

    Hi Paul,

    Thanks for this wonderful script.

    Please advsie on below error coming after running the script at PowerShell prompt .

    I have recived the report of all the database successfully via email.

    Kind regards

    Sanjay

    You cannot call a method on a null-valued expression.
    At C:ScriptsBackupAlertsGet-DailyBackupAlerts.ps1:389 char:48
    + $LatestBackup = ($LastBackups.GetEnumerator <<<< () | Sort-Object -Property Value)[0]
    + CategoryInfo : InvalidOperation: (GetEnumerator:String) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

  17. Jens Herden

    Hey Paul, script works also for me like a charm. Great work.
    is it possible to get the output sorted by databasename? because we have db´s with numbering from 001 to 999 in the name.
    also i have the problem, that on publicfolder database i get same error message like above:
    “Cannot convert value “Never” to type “System.Int32”…”.
    any ideas?
    Thanks
    Jens

  18. Jobish George

    When I run the command with -AlwaysSend and -Log parameters, I get the below error. I downloaded the script today. Hope I am using the latest available script. Please advice

    [PS] C:Get-DailyBackupAlerts.ps1-1.09>.Get-DailyBackupAlerts.ps1 -AlwaysSend -Log
    Cannot convert value “Never” to type “System.Int32”. Error: “Input string was not in a correct format.”
    At C:Get-DailyBackupAlerts.ps1-1.09Get-DailyBackupAlerts.ps1:336 char:21
    + $LastInc <<<< = "Never"
    + CategoryInfo : MetadataError: (:) [], ArgumentTransformationMetadataException
    + FullyQualifiedErrorId : RuntimeException

    You cannot call a method on a null-valued expression.
    At C:Get-DailyBackupAlerts.ps1-1.09Get-DailyBackupAlerts.ps1:474 char:133
    + "Incremental" { $dbObj | Add-Member NoteProperty -Name "UTC Time Stamp" -Value $db.LastIncrementalBackup.
    ToUniversalTime <<<< () }
    + CategoryInfo : InvalidOperation: (ToUniversalTime:String) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

    WARNING: Unable to connect to the remote server
    Out-File : The process cannot access the file 'C:Get-DailyBackupAlerts.ps1-1.09Get-DailyBackupAlerts.log' because it
    is being used by another process.
    At C:Get-DailyBackupAlerts.ps1-1.09Get-DailyBackupAlerts.ps1:154 char:35
    + "$timestamp $logentry" | Out-File <<<< $logfile -Append
    + CategoryInfo : OpenError: (:) [Out-File], IOException
    + FullyQualifiedErrorId : FileOpenFailure,Microsoft.PowerShell.Commands.OutFileCommand

    Out-File : The process cannot access the file 'C:Get-DailyBackupAlerts.ps1-1.09Get-DailyBackupAlerts.log' because it
    is being used by another process.
    At C:Get-DailyBackupAlerts.ps1-1.09Get-DailyBackupAlerts.ps1:154 char:35
    + "$timestamp $logentry" | Out-File <<<

      1. Jobish George

        Exchange Server 2010
        Version: 14.03.0123.003

        1. Avatar photo
          Paul Cunningham

          I get the file lock error on Exchange 2010 as well, so I’ve raised a bug for that in Github. I think it’s being caused by the SMTP connection failing:

          WARNING: Unable to connect to the remote server

          The other errors I can’t reproduce. Please run the script with -Log and send the log file to feedback@practical365.com so I can take a look.

          1. Jobish George

            Dear paul,

            Thanks for the quick response.

            I had issue with smtp configuration. I do not get the warning anymore after I fixed it. With this the file lock error also got vanished. I get the report properly now. However, I still do have the error shown in the EMS, while I run the script.

            Cannot convert value “Never” to type “System.Int32”. Error: “Input string was not in a correct format.”
            At C:Get-DailyBackupAlerts.ps1-1.09Get-DailyBackupAlerts.ps1:378 char:23
            + $LastInc <<<< = "Never"
            + CategoryInfo : MetadataError: (:) [], ArgumentTransformationMetadataException
            + FullyQualifiedErrorId : RuntimeException

            You cannot call a method on a null-valued expression.
            At C:Get-DailyBackupAlerts.ps1-1.09Get-DailyBackupAlerts.ps1:532 char:134
            + "Incremental" { $dbObj | Add-Member NoteProperty -Name "UTC Time Stamp" -Value $db.LastIncrementalBackup
            .ToUniversalTime <<<< () }
            + CategoryInfo : InvalidOperation: (ToUniversalTime:String) [], RuntimeException
            + FullyQualifiedErrorId : InvokeMethodOnNull

          2. John

            What happen to this issue? I’m also have same problem. I couldn’t run well, and I got the latest version Exchange 2010 SP3

            Version: 14.03.0210.002

            What is the fix for this? Thank you.

          3. John

            What happen to this issue? I’m also have same problem. I couldn’t run well, and I got the latest version Exchange 2010 SP3

            Version: 14.03.0210.002

            What is the fix for this? Thank you.

  19. Ron Bramblett

    OK, so I read the rest of the postings after I posted this and there was someone else with the same problem and Paul suggested downloading the new script.
    I did and now I see the two servers that were backed up 102 hours ago in Red like they should be.

  20. Ron Bramblett

    Paul,
    I am running your latest Backup report script on Exchange 2010 with about 25 databases. I have 2 DAGS.
    I noticed this in the email this morning.
    I have 2 databases that are showing last full backup 102 hours ago but the script is not reporting the error.

    When I manually ran the script this morning I get the following Error
    Method invocation failed because [System.String] doesn’t contain a method named ‘ToInt32’. At D:ScriptsBackupsGet-BackupAlerts.ps1:424 char:39
    elseif ($($LatestBackup.Value.ToInt32 <<<< ($null)) -gt $threshold) {

    Thanks

  21. Scott

    I ran this script and it doesn’t send the message. I am running this script from the mail server after the backup occurs. I do not get any errors when running the script so I am not sure what is happening. I do understand that relaying has to be enabled from the IP address of the server itself but I am not able to add the receive connector to allow this. I am getting another exchange error that it is duplicate to another connector.

    Any help would be greatly appreciated.

    1. Avatar photo
      Paul Cunningham

      Depends which version of Exchange, and every environment is different, but generally no special connectors required if you’re sending the reports to an internal email address. Some things to try – running the script on the Exchange server itself, telnet from the backup server to the Exchange server to verify that port 25 is accessible, run the script with -Log and check the log file, double check your SMTP settings in Settings.xml are correct.

      1. Scott

        Wow. This is crazy!! The script runs perfect. I used the -Log and everything was good in it. The problem has to be the exchange server. I can telnet to it from the backup and the email address is an internal one, and the xml settings are all correct. I don’t know where to look at this point.

        1. Avatar photo
          Paul Cunningham

          Possible that the SMTP connection is successful but delivery is failing. Turn on protocol logging on the receive connectors and try again. Look at connections coming from the backup server IP to see whether they’re being rejected. You can also perform a message tracking search to see if Exchange is discarding the email for some reason.

          Also if you can Telnet from the backup server to Exchange, keep going and perform SMTP testing via the Telnet session.

          1. Scott

            It is not even hitting the receive log once I enable logging. The message is also not in the message tracking.

            Also the backup server is the exchange server. I am pushing the backup to a NAS.

          2. Scott

            I should have mentioned earlier that this is part of a DAG. Does that make a difference?

          3. Avatar photo
            Paul Cunningham

            If you think of a variable, test that variable. So if the script isn’t working from your Exchange server, try installing the Exchange management tools on a workstation or server and run the script from there.

            You also didn’t say whether your Telnet testing worked.

          4. Scott

            The mail sends from the telnet commands. I did this from another domain machine. I also installed the exchange tools on this machine and tried the power shell script. I get the same result as before the script seems to run but the mail never gets delivered. Since everything’s working from the telnet command from that same machine I assume that it is not the exchange server.

          5. Scott

            Sorry, I am not following, “your report email”

          6. Avatar photo
            Paul Cunningham

            Ah yeah, your report email isn’t working… just send me the log and settings.xml file.

          7. Scott

            I am a total idiot!!! I just noticed that you must add the -AlwaysSend if you want an email everytime the script is run. Thank you for all your help and the great script you provided us.

      2. Scott

        BTW it is Exchange 2016 Enterprise.

  22. Surendhar.j

    Ji Paul,

    Am getting same Error Msg..

    Please Advice on this

  23. Surendhar.j

    Hi Paul

    Am getting error, while uploading this script

    Please help me

    Error msg:
    Method invocation failed because [System.String] doesn’t contain a method named ‘ToInt32’.
    At C:Users_umaganesh.subbiahDesktopGet-DailyBackupAlerts.ps1-1.07Get-DailyBackupAlerts.ps1:424 char:39
    + elseif ($($LatestBackup.Value.ToInt32 <<<< ($null)) -gt $threshold) {
    + CategoryInfo : InvalidOperation: (ToInt32:String) [], RuntimeException
    + FullyQualifiedErrorId : MethodNotFound

    Method invocation failed because [System.String] doesn't contain a method named 'ToInt32'.
    At C:Users_umaganesh.subbiahDesktopGet-DailyBackupAlerts.ps1-1.07Get-DailyBackupAlerts.ps1:424 char:39
    + elseif ($($LatestBackup.Value.ToInt32 <<<< ($null)) -gt $threshold) {
    + CategoryInfo : InvalidOperation: (ToInt32:String) [], RuntimeException
    + FullyQualifiedErrorId : MethodNotFound

    Method invocation failed because [System.String] doesn't contain a method named 'ToInt32'.
    At C:Users_umaganesh.subbiahDesktopGet-DailyBackupAlerts.ps1-1.07Get-DailyBackupAlerts.ps1:424 char:39
    + elseif ($($LatestBackup.Value.ToInt32 <<<< ($null)) -gt $threshold) {
    + CategoryInfo : InvalidOperation: (ToInt32:String) [], RuntimeException
    + FullyQualifiedErrorId : MethodNotFound

    Method invocation failed because [System.String] doesn't contain a method named 'ToInt32'.
    At C:Users_umaganesh.subbiahDesktopGet-DailyBackupAlerts.ps1-1.07Get-DailyBackupAlerts.ps1:424 char:39
    + elseif ($($LatestBackup.Value.ToInt32 <<<< ($null)) -gt $threshold) {
    + CategoryInfo : InvalidOperation: (ToInt32:String) [], RuntimeException
    + FullyQualifiedErrorId : MethodNotFound

    Method invocation failed because [System.String] doesn't contain a method named 'ToInt32'.
    At C:Users_umaganesh.subbiahDesktopGet-DailyBackupAlerts.ps1-1.07Get-DailyBackupAlerts.ps1:424 char:39

  24. riggsy

    My backup software says the daily differential backups are successful but your script only shows the last successful backup as being our weekly full. Is that by design or is something up with my backup software?

    1. Avatar photo
      Paul Cunningham

      The script doesn’t check the last diff time stamp, only full and inc. That’s just due to the nature of the environment I first wrote it in. I plan to make an update that will include diffs, it’s just not my top priority right now 🙂

      1. riggsy

        ok, looking forward to the update. Thank you!

  25. Khalil Naseer

    Hi Pual,

    Thank you , This is exactly I was looking for I run it from exchange powershell & I have got an error as below.

    [PS] C:Get-DailyBackupAlerts>.Get-DailyBackupAlerts.ps1 -Verbose -Log -AlwaysSend
    VERBOSE: Threshold for this check is 24 hours
    VERBOSE: Loading the Exchange Server PowerShell snapin
    Update-TypeData : The following error occurred while loading the extended type data file:
    Microsoft.PowerShell, C:Program FilesMicrosoftExchange ServerV14binexchange.types.ps1xml : File skipped because i
    t was already present from “Microsoft.PowerShell”.
    At C:Program FilesMicrosoftExchange ServerV14binRemoteExchange.ps1:94 char:17
    + Update-TypeData <<<< -PrependPath $typeFilePath
    + CategoryInfo : InvalidOperation: (:) [Update-TypeData], RuntimeException
    + FullyQualifiedErrorId : TypesXmlUpdateException,Microsoft.PowerShell.Commands.UpdateTypeDataCommand

    Update-TypeData : The following error occurred while loading the extended type data file:
    Microsoft.PowerShell, C:Program FilesMicrosoftExchange ServerV14binExchange.partial.Types.ps1xml : File skipped b
    ecause it was already present from "Microsoft.PowerShell".
    Microsoft.PowerShell, C:Program FilesMicrosoftExchange ServerV14binexchange.types.ps1xml : File skipped because i
    t was already present from "Microsoft.PowerShell".
    At C:Program FilesMicrosoftExchange ServerV14binRemoteExchange.ps1:104 char:16
    + Update-TypeData <<<< -PrependPath $partialTypeFile
    + CategoryInfo : InvalidOperation: (:) [Update-TypeData], RuntimeException
    + FullyQualifiedErrorId : TypesXmlUpdateException,Microsoft.PowerShell.Commands.UpdateTypeDataCommand

    Welcome to the Exchange Management Shell!

  26. m momin

    Hello
    I get output as Zero hours

    How do I change that to real time please

  27. Ortaç Demirel

    did you test for Exchange 2016? I can not get the result of test in 2016

  28. pascal

    hi paul

    unable to escape “M a i l T o” and “/ M a i l T o” as required in the XML file when posting here. please remove my posts or adapt my first post accordingly

    1. Avatar photo
      Paul Cunningham

      You’re trying to post a tip about sending to multiple recipients, so I’m going to repeat the same advice I’ve given everyone above – just use a distribution list. It’s really that simple.

  29. pascal

    is removed as well as

  30. Kenny Kim

    Hi Paul,

    How can I send the report to multiple recipients? I’ve tried below combinations in Settings.xml file with no luck. Thank you.

    “recipient1@mail.com”,”recipient2@mail.com”
    “recipient1@mail.com”;”recipient2@mail.com”
    recipient1@mail.com,recipient2@mail.com
    recipient1@mail.com;recipient2@mail.com

    1. Avatar photo
      Paul Cunningham

      Use a distribution list. Then you don’t need to modify the script files any time the list of recipients changes, you can just change membership of the DL.

    2. xhark

      It’s possible, you must add one line per recipient :

          recipient-1@demo.com
          recipient-2@demo.com
          recipient-3@demo.com
      
  31. shabber

    yes, its working in shell…thanks Paul

  32. shabber

    hipaul,
    is this output stored anyware n the system??

  33. shabber

    Hi Paul,

    i have changed the XML settings but still its not working on exchange 2010. once goto the path and enter the its just showing started… after that no results..

  34. NashTek

    This is a superb script !!! Thank U Paul!

    I receive this one error randomly anytime I run the script for at least 1 of my 3 DAG member servers. Has anyone encountered this and can provide details to resolve it?

    WARNING: Windows Failover Clustering encountered a transient error. Trying the operation again may be successful.
    Error: ‘IsNodeClustered’.
    Add-Member : Cannot bind argument to parameter ‘Name’ because it is null.
    At E:SourcescriptsTest-ExchangeServerHealth.ps1:1553 char:53
    + $memberObj | Add-Member NoteProperty -Name <<<< $($healthitem.Check) -Value $healthitemresult -Force
    + CategoryInfo : InvalidData: (:) [Add-Member], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.AddMemberCommand

    Regards

  35. Todd Lemmiksoo

    I tried to run the script this morning while my DAG backup was running and the script failed with unable to connect to server. Is this correct.

    1. Avatar photo
      Paul Cunningham

      No. The script should work while backups are in progress. What do you use for backups?

      1. Todd

        We use EMC Avamar/Data domain.

  36. pravin

    It was very nice script Paul!!!

  37. Rachid

    Hello there,

    I can’t find how to download this script 🙁

    Is there a download link?

    Thanks in advance,

    Best regards,

    Rachid

  38. ravi

    i made changes only on SMTP setting nothing else. just to let you know i am running this on exchange 2013 will it work?

    1. Avatar photo
      Paul Cunningham

      It will work on 2013.

      I think by the looks of your error message you’ve made the XML syntax invalid with your edits, and you should try again.

  39. ravi

    this is what i am getting in begging of the script.

    Cannot convert value “System.Object[]” to type “System.Xml.XmlDocument”. Error: “The ‘DBName’
    start tag on line 9 position 6 does not match the end tag of ‘JournalDB’. Line 9, position 15.”
    At C:ScriptsGet-DailyBackupAlerts-v1.06-2Get-DailyBackupAlerts.ps1:91 char:1
    + [xml]$ConfigFile = Get-Content “$MyDirSettings.xml”
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : MetadataError: (:) [], ArgumentTransformationMetadataException
    + FullyQualifiedErrorId : RuntimeException

    and i am getting following at the end also not be able to receive report in my email

    WARNING: Cannot validate argument on parameter ‘From’. The argument is null or empty. Supply an arg
    ument that is not null or empty and then try the command again.

    1. Avatar photo
      Paul Cunningham

      Have you made any edits to the script file? Often people miss a closing quote or bracket when they do that.

      Edit: or the XML file. The syntax of that file has to be perfect or it will all fall apart very quickly.

  40. Nicola P

    Ignore previous comment. Realised that by removing the ThresholdMonday line instead of changing the hours caused this issue.

    However, still would like confirmation that the output shows successful completed backups as opposed to commenced.

    Thank you

  41. Nicola P

    Ran the script successfully using the -Verbose method. My databases have backed up within the last 24 hours but the email output shows them with an Alert status. I notice from the email output that the alert is set to 0 hours.

    “This is the Exchange database backup status for the last 0 hours.
    There are 21 database backup alerts today.
    The following databases have not been backed up in the last 0 hours.”

    I haven’t amended the script. If I need to, can you confirm where.
    I have removed the 48 from the Settings.xml but left the 24

    Also, can you confirm that the output from the Exchange shell shows completed backups as opposed to commenced?

    Thanks

  42. Aravind

    Hi Paul,

    Do we have any option to add last backup size for the each database in the script.

    Thanks,
    Aravind

  43. Walid A. Razek

    Hi Paul,

    I need your help to display in the report table which sent to me by email, Red color as backgroundcolor for Alerts in the status and Green color for OK in the Status. can you please modify the script and send it to my email.

  44. louis

    hi Paul,

    I’m looking for results on my exchange servers if a server name start with *sox*. is there a way i can just search for that? other than that a great script! thank you!

    1. Avatar photo
      Paul Cunningham

      Have you opened the script in a PowerShell editor and looked at the code?

      1. Louis

        got it sorted thanks! added *sox* to the script.

  45. Andrey Ganimedov

    Nice script. Thank you Paul.
    One comment. In large environment it takes quite long to execute. In my case about 20 minutes.
    So I removed command to get list of all mailboxes (longest command in my case)
    And slightly modified mailbox counting (where that list had been used):

    [int]$mbcount = 0
    [int]$mbcount = (Get-MailboxStatistics -Database $db.name | ?{$_.ObjectClass -notlike “*ExOleDbSystemMailbox*”} | Measure-Object).Count
    #[int]$archivecount = 0
    #[int]$archivecount = ($mailboxes | Where-Object {$_.ArchiveDatabase -eq $($db.name)}).count

    #[int]$mbcount = $mbcount + $archivecount

    It saved in my case more than 15 minutes

  46. Allan Tobey

    Love the idea for the script. But I can’t get it to work. I get this error

    Exception calling “Send” with “1” argument(s): “Failure sending mail.”
    At C:scriptsGet-DailyBackupAlerts.ps1:322 char:12
    + $smtp.Send <<<< ($message)
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : DotNetMethodException

    1. Avatar photo
      Paul Cunningham

      It is likely that the SMTP server you specified is rejecting the mail. The article mentions that this may require you to set up a relay connector.

      1. Allan Tobey

        Had the incorrect smtp server entered. Thanks.

  47. Enda Scully

    I keep getting the error

    Exception calling “Send” with “1” argument(s): “Mailbox unavailable. The server response was: 5.7.1 Unable
    to relay”
    At C:Install.SetScriptsGet-DailyBackupAlerts.ps1:329 char:12
    + $smtp.Send <<<< ($message)
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : DotNetMethodException

    1. Avatar photo
      Paul Cunningham

      From the article: “If the SMTP server you specify is valid but no emails are being sent you may need to configure a relay connector or add the IP address of the workstation/server that is running the script to an existing relay connector.”

  48. Mike

    Hi,
    Your script works OK, but something is bothering me.
    When script results shows the last full/incremental backup, the command

    get-mailboxdatabase [database_name] |fl last*backup*

    shows nothing.

    LastFullBackup :
    LastIncrementalBackup :
    LastDifferentialBackup :
    LastCopyBackup :

    When I go to the Exchange console and right clikc the same database, I can see the date of the last backup.

    Can you tell me why the get-mailboxdatabase doesn’t show it?

    BR
    Mike

    1. Mike

      Got it. The right command is

      get-mailboxdatabase [database_name] -status |fl last*backup*

      than it shows the dates OK.

  49. Michael Britt

    Is it possible to add one more field to the report?

    Database Size

    When i backup my databases it would be nice to see the size of each database that got backed up.

    Thanks.

    1. Avatar photo
      Paul Cunningham

      I’ll try and include something like that for the next version.

  50. Robb

    Paul,

    Aswesome! Thanks for sharing. One request when you make your next revision… Would it be possible to include database size in the report? That would be great to have as we send this report regardless of backup status for history.

    THX!

  51. gugi

    HI

    Will this script work with Exchange 2013?

    What changes have to make?

    Tnx.

  52. Richard Voogt

    Hello Paul,

    there is a slight mix up from some word :

    First you give the example with alwayssend, in the send it is missing.
    Also the schedule is not working until changing into this :
    -command “c:scriptsget-dailybackupalerts.ps1″ -AlwaysSend

    Thanks for this great script !

    original text :
    On the Actions tab click New and add an action of Start a program. Configure the program of powershell.exe and the arguments -command “c:scriptsget-dailybackupalerts.ps1 -AlwaysSend” instead.
    If you would prefer the script always sends the report even if there are no alerts, then use the arguments -command “c:scriptsget-dailybackupalerts.ps1″

  53. Jerome

    Hi Paul,

    I think I’m going to love this report, if I can get it to send the mail message.

    It seems to run just fine in WindowsPowershell or Exchange Powershell until the very end. I get this error:
    VERBOSE: Alert email will be sent
    VERBOSE: Report summary: Alerts 130, OK 99
    VERBOSE: Sending email report
    Exception calling “Send” with “1” argument(s): “Failure sending mail.”
    At H:ExchangeScriptsDatabaseGet-DailyBackupAlerts.ps1:322 char:12
    + $smtp.Send <<<< ($message)
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : DotNetMethodException

    Any ideas would be appreciated.

    1. Avatar photo
      Paul Cunningham

      Refer to the note in the article above about configuring a relay connector.

  54. Mark

    Hi Paul, thanks for the script. I’ve been using Data Protection Manager to manage my backups for Exchange 2013. Noticed I’d stopped getting email and found the reason was my disk was full. DPM was reporting everything was ok, but upon closer inspection it showed the last backup was over a week prior. Just goes to show nothing compares to a bit of human monitoring. Hoping your script will prevent this happening again.

    1. Avatar photo
      Paul Cunningham

      Precisely the type of situation the script was written to avoid 🙂

  55. Karthik

    Hi Paul,

    This is a great script. My environment has Exchange 2003 and Exchange 2010 databases. I have around 128 databases in Exchange 2003 which I want to exclude from this script. I thought that rather than typing the name of all of them, it would be easy to remove the -IncludePreExchange2010 switch from the command in the script. However it did not help. Can you please help me with a way to exclude all Exchange 2003 databases from the scope of this script?

    1. Avatar photo
      Paul Cunningham

      I would suggest modifying that line so it pipes in a Get-ExchangeServer command that excludes the Exchange 2003 servers.

      So instead of what you see in the script, perhaps try:

      $ex2010servers = get-exchangeserver | where {$_.AdminDisplayVersion -like “Version 14.*”}
      $dbs = @($ex2010servers | Get-MailboxDatabase | Where {$_.Recovery -ne $true})

      1. Mitchell

        I have tried to adding in the lines as stated for $ex2010servers = get-exchangeserver | where {$_.AdminDisplayVersion -like “Version 14.*”}
        $dbs = @($ex2010servers | Get-MailboxDatabase | Where {$_.Recovery -ne $true}) , but when i do the output comes out like this:

        Last Backup Type Hrs Ago Time Stamp
        Never/Unknown Never/Unknown Never/Unknown
        Never/Unknown Never/Unknown Never/Unknown
        Never/Unknown Never/Unknown Never/Unknown
        Never/Unknown Never/Unknown Never/Unknown
        Never/Unknown Never/Unknown Never/Unknown
        Never/Unknown Never/Unknown Never/Unknown
        Never/Unknown Never/Unknown Never/Unknown

        When i remove this and change back to the way the script is by default, my outputs are correct again. My entry to the script is below, please let me know if something looks incorrect. I am trying to exclude anything that is 2003/2007 as well.

        #Add Exchange 2010 snapin if not already loaded
        if (!(Get-PSSnapin | where {$_.Name -eq “Microsoft.Exchange.Management.PowerShell.E2010”}))
        {
        Write-Verbose “Loading Exchange 2010 Snapin”
        Add-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010 -ErrorAction SilentlyContinue
        }

        Write-Verbose “Initializing variables”
        $report = @()
        $alertdbs = @()
        $okdbs = @()
        [bool]$alertflag = $false

        #Current time is used in alert calculations
        $now = [DateTime]::Now
        Write-Verbose “Current date/time is $now”

        Write-Verbose “Retrieving list of mailboxes for use in mailbox count later”
        $mailboxes = $(Get-Mailbox -IgnoreDefaultScope -ResultSize Unlimited)

        #……………………………..
        # Script
        #……………………………..

        #Get all Mailbox and Public Folder databases
        Write-Verbose “Retrieving database list”
        $ex2010servers = get-exchangeserver | where {$_.AdminDisplayVersion -like “Version 14.*”}
        $dbs = @($ex2010servers | Get-MailboxDatabase | Where {$_.Recovery -ne $true})
        if ($dbs)

  56. Shane Hart

    Hi Paul,

    Script works perfectly when run manually with -Verbose or -AlwaySend (also changed $threshold to 1 for testing and all ok).
    However, when scheduled, the script does not send email regardless of -AlwaySend switch setting or $threshold 1 set in the script.
    Windows Server 2008 R2 SP1, Exchange Server 2010 SP2 RU6, Powershell Version 2.0.
    Any ideas?
    Many thanks.

    1. Avatar photo
      Paul Cunningham

      Usually this is either a mistake in the scheduled task’s command line, or a permissions issue with the scheduled task.

  57. Rene

    Hi Paul,

    Is there a simple way to run the /powershell-script-health-check-report-exchange-2010/ from another computer to be able to monitor my exchange servers ?
    I would like to be able to monitor them and if the server where the script is installed is out of service, i would like to know the state of it.(?)

    1. Avatar photo
      Paul Cunningham

      You can run the script from any server or workstation that has the Exchange management tools installed.

  58. SREEJITH

    Paul,

    Please help me still i am facing this issue.

    Thank You
    Sreejith

  59. SREEJITH VU

    Hi Paul,

    I run this command on a 2007 Box and i am getting the full report except Mailbox count. All DB’s Mailbox count showing as “0”. Rest all details correct. Please help me on this.

    Thank You
    Sreejith

  60. Leonid

    Hi, Paul!
    Thank you for your job! But script don’t work on Russian Exchange 2010 🙁
    1. Get-DailyBackupAlerts.ps1 -Verbose
    for 8 of 13 databases it shows errors
    ——————–
    Не удается преобразовать значение “1 647” в тип “System.Int32”. Ошибка: “Входная строка имела неверный формат.”
    C:ScriptsGet-DailyBackupAlerts.ps1:189 знак:12
    + [int]$ago <<<< = "{0:N0}" -f $ago
    + CategoryInfo : MetadataError: (:) [], ArgumentTransformationMetadataException
    + FullyQualifiedErrorId : RuntimeException
    ———————
    What in English is smth like this:
    ———————
    Can not convert the value "1 647" to type "System.Int32". Error: "Input string was invalid."
    C:ScriptsGet-DailyBackupAlerts.ps1:189 char:12
    + [int]$ago <<<< = "{0:N0}" -f $ago
    + CategoryInfo : MetadataError: (:) [], ArgumentTransformationMetadataException
    + FullyQualifiedErrorId : RuntimeException
    ———————

    2. Running in English EMS (without verbose):
    ———————-
    Cannot convert value "1 578" to type "System.Int32". Error: "Input string was not in a correct format."
    At C:TEMPGet-DailyBackupAlerts.ps1:189 char:3
    + [int]$ago = "{0:N0}" -f $ago
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : MetadataError: (:) [], ArgumentTransformationMetadataException
    + FullyQualifiedErrorId : RuntimeException

    Cannot convert value "1 600" to type "System.Int32". Error: "Input string was not in a correct format."
    At C:TEMPGet-DailyBackupAlerts.ps1:189 char:3
    + [int]$ago = "{0:N0}" -f $ago
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : MetadataError: (:) [], ArgumentTransformationMetadataException
    + FullyQualifiedErrorId : RuntimeException
    ——————– … and so on 8 times

  61. SREEJITH

    Hi Paul,

    Again one help for this script.

    I am running this script in 2007 Exchange Shell

    Script is runningfine and it’s generating the email aswell.

    Only thing is Mailboxes count showing 0 for all DB’s.

    Thank you
    Sreejith

  62. Keith

    Is there a way to color code the background of the Status ?
    Alert = Red
    OK = Green

  63. RZ

    Hello Paul,

    Is het Possible to send a mail to more then one mailaccount?
    I use a mailgroup, because we arre using this for more scripts and I want to add a single user that only receives the results of this script.
    I tried to add the account with a semicolon (;) but this only gives errors.

    1. RZ

      Hello Paul,
      After trying some things, I discoverd the answer. I had to use a comma between the emailadresses.Then the script works.

  64. Keith K.

    How can I color code the Status background?
    Alert = Red
    OK = Green

  65. NS

    For whatever reason, the script has started to work and there arent any errors anymore.

    thank you.

  66. NS

    Yeah I am using a valid email address, server, etc.. I just modified the below to suit with my details.

    $smtpServer = “smtp.exchangeserverpro.net”
    $smtpFrom = “exchangeserver@exchangeserverpro.net”
    $smtpTo = “administrator@exchangeserverpro.net”

  67. NS

    Great Script Paul. It runs on screen but get the below errors right at the end.

    I used the -verbose -alwayssend options.

    New-Object : Exception calling “.ctor” with “2” argument(s): “The specified string is not in the form required for an e
    -mail address.”
    At C:appsBackupAlert.ps1:314 char:23
    + $message = New-Object <<<< System.Net.Mail.MailMessage $smtpfrom, $smtpto
    + CategoryInfo : InvalidOperation: (:) [New-Object], MethodInvocationException
    + FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand

    Property 'Subject' cannot be found on this object; make sure it exists and is settable.
    At C:appsBackupAlert.ps1:315 char:11
    + $message. <<<< Subject = $messageSubject
    + CategoryInfo : InvalidOperation: (Subject:String) [], RuntimeException
    + FullyQualifiedErrorId : PropertyNotFound

    Property 'IsBodyHTML' cannot be found on this object; make sure it exists and is settable.
    At C:appsBackupAlert.ps1:316 char:11
    + $message. <<<< IsBodyHTML = $true
    + CategoryInfo : InvalidOperation: (IsBodyHTML:String) [], RuntimeException
    + FullyQualifiedErrorId : PropertyNotFound

    Property 'Body' cannot be found on this object; make sure it exists and is settable.
    At C:appsBackupAlert.ps1:317 char:11
    + $message. <<<< Body = ConvertTo-Html -Body "$intro $summary $alertintro $alerthtml $okintro $okhtml $outro" -Head
    $style
    + CategoryInfo : InvalidOperation: (Body:String) [], RuntimeException
    + FullyQualifiedErrorId : PropertyNotFound

    VERBOSE: Sending email report
    Exception calling "Send" with "1" argument(s): "Value cannot be null.
    Parameter name: message"
    At C:appsBackupAlert.ps1:322 char:12
    + $smtp.Send <<<< ($message)
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : DotNetMethodException

    1. Avatar photo
      Paul Cunningham

      “The specified string is not in the form required for an e -mail address.”

      Are you using a string that is a valid email address?

  68. Raj

    Paul,

    How can I exclude pre ex2010 databases only?

    thanks

  69. Dimka

    Yes, it’s great script.. A question only.. it’s possible to include and size of last backup session..?

    1. Avatar photo
      Paul Cunningham

      That info would normally come from your backup product. It isn’t stored in Exchange.

  70. Johnny

    Paul,

    Great script. This was exactly what I was looking for. Just one question on the latest version. I have about 68 existing Exchange 2007 DBs I would like to exclude, but have not been able to successfully exclude them in the script unless I type out the entire “serversgdb” format in the exclude DBs section. I do not want to type out all 68 2007 DBs. Is there another way to exclude these DBs from the report?

    Thanks,
    Johnny

    1. Avatar photo
      Paul Cunningham

      Whether you type them in the script or type them in a txt file that the script references, one way or the other you’re still typing them out.

      Unless you have some other criteria you can filter them out with (eg a common string in their names or which server they sit on).

    2. Louis

      i want to do similar, but i only want results on 6 servers of my 58. and those six have sox in their name. any suggestions?

  71. Carl

    Is there a way to use a variable so that the script takes the SMTP server settings from the local exchange server it is running on?
    Ex.
    $smtpServer = “localhost”
    $smtpFrom = “administrator@%Domain%”

    Thanks,
    Carl

  72. ismat

    should it work on windows server 2008 R2 for both Active Director and File Server Backup?

  73. kurt

    Can some one post a working exchange 2007 version of this script?

  74. erbin baquero

    The powershell script does not work for me because getting database list show all databases of my organization, how I can only get report of my servers ?
    Thanks.

  75. Simon Craner

    Running the script seperately against e2k7 boxes sends the alert as required, but tge currently running status column is blank even when the backup is running please advise.

  76. Jeremy Bradshaw

    Hi Paul,

    Thanks for the script, it is very well laid out and concise. One thing I’ll add is that the LastFullBackup timestamp (and the LastIncrementalBackup’s, LastDiff..’s, etc.) is actually from when the last successful backup started, not when the last backup was finished. In other words it’s saying your data is good and safe up until that time.

    Many thanks, this is going into my scheduler.

  77. Davor Niksic

    Should you have problems executing this script via task scheduler, modify -command switch:
    powershell -command “. ‘C:scriptsGet-DailyBackupAlerts.ps1′”

  78. Leon

    Hi Paul, Thanks for the script, works like a charm… when you say that the databases haven’t been backed up… what do you mean by that?

    If a daily Windows Server Backup is performed… should this reflect it? Or still there is a better procedure to backup the Exchange databases?

    Thanks.

  79. Raxit

    Hi Paul, I would like to know, in which language this screept has been written ?

  80. Paul

    This works great but I have a database that is currently being backed up but is not being reported. I’d like to convert this to more of a database backup report. Database xyz has not been backed up database abc backup is in progress and then database 123 was completed on…

    My problem is that I am not that versed in power shell. Any guidance would be welcome.

    Thanks

    Paul

  81. Sudoraptor

    I got the script to work for testing purposes with the threshold set to 1hr. But now when I change the script’s threshold to 10, it checks the databases and does not send an email.

    I ran the powershell commands manually and have databases that were last backed up over 24 hours ago.

    Shouldn’t the script still send an email?

    1. Avatar photo
      Paul Cunningham

      There was a bug with the script that should fix that. I recommend trying the latest version.

  82. Ytsejamer1

    I just came across this and am attempting to shoehorn this into my Exchange 2007 environment. I’ve got it to run and email without a problem. I’ve loaded the Exchange 2007 PS addin to PS. However, the report neglects to include the server/dag and database type in those sections.

    When I run the commands to get the list of databases and their status…it lists everything as expected. Any hints?

    Thanks again for a wonderful script!

    1. Ytsejamer1

      I got it going. Exchange 2007 doesn’t allow have IsMailboxDatabase/IsPublicFolderDatabase equals True/False as a valid database property. I manually used:
      db.Name -eq “Name of my Mailbox Database”) {$dbtype = “Mailbox”}
      and
      db.Name -eq “Name of my PF Database”) {$dbtype = “Public Folder”}

      At that point, I ignored some of the logic for what gets set in the server/dag value column of the report. db.MasterServerOrAvailabilityGroup isn’t a valid property for me, so I simply used used db.Server to fill in the Server/DAG value.

      I then included:
      $dbObj | Add-Member NoteProperty -Name “Storage Group” -Value $db.StorageGroup.Name
      to give me the Storage Group Name where my Mailbox Database resides.

      Seems to work great. i adjusted the Monday threshold to 48 hours and all other days’ threshold to 24. updated the comments to match..”This will go out if a backup hasn’t been done in more than 24 hours”.

      One thing to note…i have a couple spam mailboxes that I don’t back up…i keep rolling logs on it. That mailbox database hasn’t been backed up…even though it would come back with never, the email never goes out. Shouldn’t it email if a database (MB or PF) hasn’t been backed up?

  83. Hein Traag

    When i try to run this script it says it is not signed.. i can ofcourse lower my guard and have exection policy set to unrestricted but it would be neater to have this script trusted by my servers.. how do i set that option?

  84. David Nicholls

    Paul, a brilliant script, who hasn’t been caught out with logs files at some point!!!

  85. Wally Hass

    Hello,
    If I run manually it works great. If run from a batch file or via scheduler, the email does not list the db and is generally blank. Suggestions?

    Wally Hass

    1. Avatar photo
      Paul Cunningham

      Possible that the credentials being used to run the scheduled task do not have access to Exchange.

  86. starchaser

    Will this script work with Exchange 2007?

    1. Avatar photo
      Paul Cunningham

      Should work pretty well, possibly just need a few modifications around the Server/DAG name detection and how it handles public folders vs mailbox databases.

      Could just simplify that If/Else block down to just use $db.Server regardless of whether it is PF or MB database.

Leave a Reply