Powershell Needful Things put that in your pipeline


Exchange 2007 Audit Script – Version 3

I have updated the Exchange 2007 audit script yet again!

Included in this update are two MAJOR changes, firstly, the script uses and publishes information using the new HTML format, as created by Virtu-Al.

This script, and the functions which create its HTML output are far more efficient and literally cut the number of lines in the script down by half. Not only is the code leaner, but it is also infinitely more legible, and adding new tests to the current script is a breeze. This version of the HTML output is also compatible with multiple browsers, including Mozilla and Chrome.

Secondly, the script will now detect pipeline input. You can still use a server list as a parameter to the script, but now, you can also pipe content to the script. This content can include your server list, or output from Exchange commands such as get-transportserver or get-mailboxserver etc. Be careful though, because commands like get-exchangeserver could include Exchange 2003 servers.
If no server list is specified or piped, the script will still get all Exchange 2007 servers.

As another minor addition, I have added an additional test (Test-OutlookWebServices) to the CAS servers.

As always, your comments and feedback is always welcome.

Complete version and download information can be found here:

Comments (42) Trackbacks (0)
  1. Great script and I love the output 😉

  2. Thanks Alan!

  3. I am having problems getting this scrupt to run. all I get is the following error

    Missing file specification after redirection operator.
    At C:\utils\test-exchange2k7_V3.ps1:1 char:122
    + <<<<

    Any ideas?

  4. Hi Shaun,

    Thanks for downloading the script. Did you pipe a server list to the script, or are you specifying a server list?

    Also, when you are in the c:\utils folder, start typing the name of the script, test- and press tab.

    The tab completion will have the path as .\test-exchange2k7_V3.ps1

    You can then specify a server list as a parameter.

    • Hi,

      CAN you please where you CAN specify the list of servers???? Tanks in advance

      • Amghar, you have to pipe a list of severs to the script from cmdlets liek get-exchangeserver or get-mailboxserver. If that is not an option, you can use a text file to specify specific server names.

  5. Hi,

    I ran script and it's cool stuff, but output coming on multiple HTML file.
    i.e we have 30 exchange 2007 servers and we are getting 30 files, is it possible in the single report all servers need to include.


  6. Hi Rugi,

    I had a version that does exactly that, but I was working on an option, to use a parameter to specify weather or not to use the single file option. I have your email, and I will send you a script which does exactly that on Monday.


    • Rugi/Jean, Request you to please share the script to create single file.

      • Hi there Mark,

        Thanks for using the script, I am glad it could help you. During the upgrade of my blog, for some odd reason I lost that script. I do have the code somewhere that can do that, I just need to find the time to re-write the script.

        I do however run my own business as well, so the blog scripting is something I do more as a hobby if and when my free time allows.

        I will re-wite it, but I cannot commit to a time and date, as my revenue generating activities take preference over the free work I do on the blog.

        I trust that you understand.


  7. Hi.

    I have specified the script as follows:

    .\test-exchange2k7_V3.ps1 exchange.txt

    The text file then contains a list of 4 exchange servers.

    Is this the correct method?

  8. Hi Shaun,

    When you specify the text file, you can start typing the name exc.. and press TAB it will complete the name for you (C:\utils\excange.txt or .\exchange.txt)

    That should work. Let me know if it doesnt.

  9. Yeah I tried this also. This gives the same result I'm afraid

  10. Shaun,

    Could you try run the script with no text file?

    I have just downloaded the file and tested it in my VM at home, and it works without problems.

    Also, please send me a screen shot of the error screen to jeanlouw at gmail.

    I will try to reproduce the error on my side.

  11. Thanks for your assistance – I have emailed you the details.


  12. Hi Jean,

    You mentioned that you were working on an option, to use a parameter to specify weather or not to use the single file option. Could I get a ciopy of that as well? I have many Exchange servers as well.

    Also, to get the out emailed to me would adding this to the end of the .ps1 file work:

    $smtpServer = “”
    $msg = new-object Net.Mail.MailMessage
    $att = new-object Net.Mail.Attachment($filename)
    $smtp = new-object Net.Mail.SmtpClient($smtpServer)
    $msg.From = “exchange@domain.com”
    $msg.Subject = “Exchange Audit Summary”
    $msg.Body = “This is an automated message from Exchange.”

  13. YB,

    Thanks for your comment.

    I have a script which will report into a single file. I will upload / post a copy of that script soon. It does however have a few html related problems I need to get resolved first.

    If you are happy to deal with those for now, you can email me directy at jeanlouw at gmail dot com, and I will gladly send you a copy. This new script also includes some public folder information in the report.

    As far as your send mail function is concerned, if you are using Powershell V2 I would suggest the following:

    $messageParameters = @{
    Subject = "Exchange 2007 Audit Report – $((Get-Date).ToShortDateString())"
    Body = $fullReport
    Attachments = $Filename
    From = "report@domain.com"
    To = "rcpt@domain.com"
    SmtpServer = ""

    Send-MailMessage @messageParameters -BodyAsHtml

    You can then have the report as the message body / or as an attachment to the message.

    I hope this answers your question, and again thanks for you interest in the script!

  14. HI Jean,

    Thanks for the response and for your hard work!

    I can wait for the finished product, I'm really looking forward to it!

    I'll try the suggestion you mentioned for sending the email.

    Thanks a bunch!

  15. Hi Jean,

    Excellent script…looks very useful.

    We are running a CCR Win2008 failover cluster using mointpoints for the storage groups. At the moment the script only shows the logical disks. Is it possible to add the functionality so it also shows the mounted volumes?



  16. Hi Jean,

    When I run the script on our mailbox and cas/hub servers the result only show basic server info, installed rollups, logical disk info, exchange services and event logs. Nothing about mailbox stores, mapi connectivity etc. I have tried running it on the virtual mbx server and on the physical nodes but the results are the same. Can you guide me in the right direction on why this is happening?

    With thanks in advance.


  17. Hi Steffen,

    Thanks for your interest in the script!

    Are you running the script from the server? Does the script display any errors on the console while running?

    Also, you can email me directly at jeanlouw-at-gmail-dot-com.

    Using email seems a little faster when troubleshooting issues like these.


  18. Has anyone thought of adding the top 20 mailboxes by DB???? This would allow you to identify why or whom has filled the mailstore ????

  19. Hi Tony,

    Thanks for your suggestion, and sorry for the late reply. I have recently changed jobs, and with the Easter weekend I have not had a chance to read my comments or reply.

    Well, I have settled in now, and I have had some time to look at the blog, and your suggestion is great. Would you suggest this as a separate heading?


  20. Yep i sould i've also created something sort of seperate to yours well a mini version that also displays the Active/passive server for a cluster.
    Get-ClusteredMailboxServerStatus -identity $target | select-object Identity, State , OperationalMachines

    Couple of other things.

    1. Could you set the result size on the script to always be unlimited??? Always have to go through and change.

    2. Am finding that when the new version hits the checking queues part can take upwards of an hour for one server. With the V1 version (which is what i am playing with) it takes maybe 30 seconds per cluster. My clusters have upwards of 1000 user's per SG across 4 SG's.

  21. Tony,

    Thanks for your feedback. As always it is much appreciated.

    I will certainly incorporate your suggestions in the next release.

    The first version of the script had a small bug with the event log, where it failed to collect all Exchange related information from the log. That version still used WMI to gather log data.

    If the event log parsing is taking extremely long it could be due to a large event log on that specific server.

    If possible you could try to reduce the size of the log in question?

    The resultsize and the cluster services are great suggestions and I will add it to be list of enhancements.

    Thanks again for your comments and suggestions.

  22. Excellent script! The piece that reports on the CAS, does this require a specific user name to be created?

    • Jim, sorry for the late reply, I have been out of town. You need to enable the CAS test user with a script from Microsoft. If you need help locating the test user setup, let me know and Ill do a nice post on it. Thnx for the great feedback!

  23. Is a test user required for each CAS server? Looking around I thought this might be the answer, enabled the CAS test user with the MS script. I get the same error as before with a different CAS_…. user in the error.

  24. I see, it is one CAS test user per MB server.

  25. Jean,
    Great work on the script. A few requests:

    1) Add some quick usage info in the comments at the top of the script (ie. valid command-line arguments and such).
    2) Link to the CAS test user docs in the script header. Like Jim, I’m not sure how to enable the test user.
    3) In the Mailbox Stores section, add “(MB)” to the Whitespace header.
    4) In the Mailbox Stores section, consider adding info about Total DB Size, Retained Itemse (event ID 1207), and Retained Deleted Mailboxes (event ID 9535). Found some sample code here: http://gsexdev.blogspot.com/2008/07/show-exchange-whitespace-retained-items.html

    Looking forward to seeing your Ex2010 version since we will be migrating to 2010 over the Christmas break. Thanks

    • Hi Cameron,

      Thanks for the feedback and for using the script. I am really busy working on the 2010 version, but I think its worthwhile doing a post with information about the test user for the CAS server.

      Thanks for the other suggestions, I will certainly add them to the wish list for the next release, and for the 2010 script.
      If time allows I will work them into the scripts.



    • Cameron,

      I have made a detailed post, explaining how to create the CAS test mailbox.

      Please see http://www.powershellneedfulthings.com/?p=124 for more information, and do not hesitate to ask should anything be unclear.

  26. Good info on creating the test user! Your get-mailboxServer command simplifies the process if there are mulitplel mb servers.

    The only issue I have now (and I imagine there is something I’ll learn about PS from your answer) is I get a number of these errors
    You cannot call a method on a null-valued expression.
    At e:\scripts\weekly\audit-exchange.ps1:266 char:37
    + $rollUps = $baseKey.GetSubKeyNames( <<<< )
    You cannot call a method on a null-valued expression.
    At e:\scripts\weekly\audit-exchange.ps1:273 char:37
    + $values = $childKey.GetValueNames( <<<< )________________

    • Hi Jim,

      I am glad that it helped. Are you running the script from Windows 7 remotely, or are you running it from the Exchange server?

      I have seen that error when running the script from 64 bit Windows 7, where it is unable to read that registry key over the network. You can test this by running regedit, and connecting to the remote registry of the server, and see if you can read the key.

  27. That is the problem! Thanks. I wasn’t running them from 7 but from a non- Exchange 2003 server with exchange admin console / shell. So, same situation. now I need to decide if it is worth setting up remote registry to run this script. I have a script that I run weekly – all at once- it calls this script, and others from this server.

  28. but – I’m not sure why my server doens’t have remote registry permissions.

  29. Hello jean,

    I like this script verry much, thanks fot sharing.

    I was trying to add add storagegroupcopystatus info and inputted the following code into the script:
    Write-Host “..getting StorageGroupCopyStatus information”
    $MyReport += Get-CustomHeader “2” “StorageGroupCopyStatus”
    $colStorageGroupCopyStatus = Get-StorageGroupCopyStatus | Sort-Object Name
    $StorageGroupCopyStatus = @()
    Foreach ($objStorageGroupCopyStatus in $colStorageGroupCopyStatus)
    $StorageGroupCopyStatusDetail = “” | select Name, SummaryCopyStatus, CopyQueueLength, ReplayQueueLength, LastInspectedLogTime
    $StorageGroupCopyStatusDetail.name = $objStorageGroupCopyStatus.Name
    $StorageGroupCopyStatusDetail.SummaryCopyStatus = $objStorageGroupCopyStatus.SummaryCopyStatus
    $StorageGroupCopyStatusDetail.CopyQueueLength = $objStorageGroupCopyStatus.CopyQueueLength
    $StorageGroupCopyStatusDetail.ReplayQueueLength = $objStorageGroupCopyStatus.ReplayQueueLength
    $StorageGroupCopyStatusDetail.LastInspectedLogTime = $objStorageGroupCopyStatus.LastInspectedLogTime
    $MyReport += Get-HTMLTable ($StorageGroupCopyStatus)
    $MyReport += Get-CustomHeaderClose
    This gives me the table header but no contents in the table on the ouput html
    Can you give me a clue on why My table is not showing content?

    I also want to include a section for test-replicationhealt if it succeeds.

    thanks in advance and have a nice christmas and all

    • Hi Jean,
      I found my mistake already:

      the inputted part needed to be like:
      Write-Host “..getting StorageGroupCopyStatus information”
      $MyReport += Get-CustomHeader “2” “StorageGroup CopyStatus”
      $colStorageGroupCopyStatus = Get-StorageGroupCopyStatus | Sort-Object Name
      $StGrCopyStatTable = @()
      Foreach ($objStGrCopyStat in $colStorageGroupCopyStatus)
      $StGrCopyStatDetail = “” | select Name, SummaryCopyStatus, CopyQueueLength, ReplayQueueLength, LastInspectedLogTime
      $StGrCopyStatDetail.Name = $objStGrCopyStat.Name
      $StGrCopyStatDetail.SummaryCopyStatus = $objStGrCopyStat.SummaryCopyStatus
      $StGrCopyStatDetail.CopyQueueLength = $objStGrCopyStat.CopyQueueLength
      $StGrCopyStatDetail.ReplayQueueLength = $objStGrCopyStat.ReplayQueueLength
      $StGrCopyStatDetail.LastInspectedLogTime = $objStGrCopyStat.LastInspectedLogTime
      $StGrCopyStatTable += $StGrCopyStatDetail
      $MyReport += Get-HTMLTable ($StGrCopyStatTable)
      $MyReport += Get-CustomHeaderClose

      Only thing I now need to solve is why the column “name” does not show the specific names but seems to be empty.

      Regards PrinceR

Leave a comment

No trackbacks yet.