4

I found this wonderful script that outputs the status of the current DFS backlog to the powershell console. This works great, but I need the script to email me so I can schedule it to run nightly. I have tried using the Send-MailMessage command, but can't get it to work. Mainly because my powershell skills are very weak. I believe most of the issue revolve around the script using the Write-Host command. While the coloring is nice I would much rather have it email me the results. I also need the solution to be able to specify a mail server since the dfs servers don't have email capability.

Any help or tips are welcome and appreciated.

Here is the code.

$RGroups = Get-WmiObject -Namespace "root\MicrosoftDFS" -Query "SELECT * FROM DfsrReplicationGroupConfig"
$ComputerName=$env:ComputerName
$Succ=0
$Warn=0
$Err=0

foreach ($Group in $RGroups)
{
$RGFoldersWMIQ = "SELECT * FROM DfsrReplicatedFolderConfig WHERE     ReplicationGroupGUID='" + $Group.ReplicationGroupGUID + "'"
$RGFolders = Get-WmiObject -Namespace "root\MicrosoftDFS" -Query  $RGFoldersWMIQ
$RGConnectionsWMIQ = "SELECT * FROM DfsrConnectionConfig WHERE ReplicationGroupGUID='"+     $Group.ReplicationGroupGUID + "'"
$RGConnections = Get-WmiObject -Namespace "root\MicrosoftDFS" -Query  $RGConnectionsWMIQ
foreach ($Connection in $RGConnections)
{
$ConnectionName = $Connection.PartnerName.Trim()
if ($Connection.Enabled -eq $True)
{
if (((New-Object System.Net.NetworkInformation.ping).send("$ConnectionName")).Status -eq "Success")
{
foreach ($Folder in $RGFolders)
{
$RGName = $Group.ReplicationGroupName
$RFName = $Folder.ReplicatedFolderName

if ($Connection.Inbound -eq $True)
{
$SendingMember = $ConnectionName
$ReceivingMember = $ComputerName
$Direction="inbound"
}
else
{
$SendingMember = $ComputerName
$ReceivingMember = $ConnectionName
$Direction="outbound"
}

$BLCommand = "dfsrdiag Backlog /RGName:'" + $RGName + "' /RFName:'" + $RFName + "' /SendingMember:" + $SendingMember + " /ReceivingMember:" + $ReceivingMember
$Backlog = Invoke-Expression -Command $BLCommand

$BackLogFilecount = 0
foreach ($item in $Backlog)
{
if ($item -ilike "*Backlog File count*")
{
$BacklogFileCount = [int]$Item.Split(":")[1].Trim()
}
}

$Emailbody += "$BacklogFileCount files in backlog $SendingMember->$ReceivingMember for $RGName
"

} # Closing iterate through all folders
} # Closing  If replies to ping
} # Closing  If Connection enabled
} # Closing iteration through all connections
} # Closing iteration through all groups

$emailFrom = "sender@foobar.com"
$emailTo = "recipient@foobar.com"
$subject = "DFS Backlog Report"
$smtpServer = "MailServer"
$smtp = new-object Net.Mail.SmtpClient($smtpServer)
$smtp.Send($emailFrom, $emailTo, $subject, $Emailbody)
Gordon Carlisle
  • 41
  • 1
  • 1
  • 3
  • What version of PowerShell are you running? if (test-path variable:psversiontable) {$psversiontable.psversion} else {[version]"1.0.0.0"} – pk. Apr 13 '12 at 15:15

6 Answers6

2

This is but one possible solution; there are many.

[string]$emailBody = ""
$emailBody += "This is line 1<br />"
$emailBody += "This is line 2<br />"
$emailBody += "This is line 3<br />"
Send-MailMessage -From "$senderName <$senderAddr>" -To "$recptName <$recptAddr>" -Subject "$emailSubject" -Body $emailBody -SMTPServer $smtpServer -BodyAsHTML

Does that make sense?

jscott
  • 24,204
  • 8
  • 77
  • 99
Ryan Ries
  • 55,011
  • 9
  • 138
  • 197
  • Thanks the $emailBody += was helpful in finding a solution to the problem. I have updated the code to reflect how I got the report to email. – Gordon Carlisle Apr 13 '12 at 17:40
  • @GordonCarlisle If you were able to resolve this, you should post the details as an answer *and* mark it as "accepted". – jscott Apr 13 '12 at 17:53
2

If you wanted to branch out of powershell, you could redirect the output of the script to a text file and use a 3rd party command line mailer like blat to send the text file as the body (or attachment) of an email and specify the smtp server to bounce off of.

Rex
  • 7,815
  • 3
  • 28
  • 44
  • 1
    The `Send-MailMessage` cmdlet can do all of this without relying on other binaries. – jscott Apr 12 '12 at 02:24
  • 1
    I know.. but some people aren't fully comfortable in powershell and can copy/paste a script but don't want to edit it more than necessary. I was just providing another option for those people. :) – Rex Apr 12 '12 at 02:25
  • 1
    Certainly, and +1 for the suggestion. But it seems, to me, it would be "cleanest" to keep all operations within the scope of the same script. – jscott Apr 12 '12 at 02:29
  • Yup - it would be better to keep it all in one script. I just know I've worked with people that have an unnatural fear of even breathing on the computer running the script let alone modify a script they know works no matter how minor the change might be. :) – Rex Apr 12 '12 at 02:33
1

My solution isn't pretty, and doesn't use powershell, but I've been using it for years to do exactly what you are trying to achieve.

@echo off
set s1=dfsrsrvr1
set s2=dfsrsrv2

set output=%TEMP%\dfsr.txt
echo DFS Replication Backlog Report>%OUTPUT%
echo.>>%OUTPUT%
echo For each DFS replicated share, any backlog is displayed below.>>%OUTPUT%
echo The first value is the backlog from %S2% to %S1%, the second value is the reverse>>%OUTPUT%
echo.>>%OUTPUT%

echo Accounts>>%OUTPUT%
echo ========>>%OUTPUT%
dfsrdiag backlog /rgname:Accounts /rfname:Accounts /sendingmember:%S2% /receivingmember:%S1% | head -n 2 | tail -n 1 | cut -d: -f2>>%OUTPUT%
dfsrdiag backlog /rgname:Accounts /rfname:Accounts /sendingmember:%S1% /receivingmember:%S2% | head -n 2 | tail -n 1 | cut -d: -f2>>%OUTPUT%

echo.>>%OUTPUT%

blat "%OUTPUT%" -to logs@example.com -server mta.example.com -f user@example.com -subject "DFS Replication Report %DATE% %TIME:~0,5%"

It relies upon head, cut and tail from GNU Unix Utils, and blat command line mailer.

It also uses the dfsrdiag utility (which should be on your server) to get the required stats from the DFSR service. In the example, the replication group name is Accounts, adjust to taste/add more replication groups as required.

Bryan
  • 7,538
  • 15
  • 68
  • 92
0

Using the Send-MailMessage is probably the easiest and best way to proceed.

Its not available in the earlier versions of PowerShell, so as an alternative you could use the .NET mail objects directly (see http://vblog.strutt.org.uk/2011/09/sending-email-from-powershell/ for more info).

Simon
  • 41
  • 3
0

One method of sending this via email would be to redirect the console output to a file:

$timeStamp = [DateTime]::Now.ToString("yyyyMMddHHmmss") #configure a timestamp variable
$attachFile = c:\temp\attach$timestamp.txt #configure txt file to which we'll redirect the console output.  Using the timestamp variable to generate a unique file name
Write-Host "Some output here" >> $attachFile

Then use send-mailmessage employing the -Attachments parameter ...documentation is here:

http://technet.microsoft.com/en-us/library/dd347693.aspx

Common gotcha's:

  • Exchange relay not configured to allow sending of mails from the box running the script
  • Anti-virus mass-mailing worm protection can prevent scripted emails
nimizen
  • 276
  • 3
  • 9
0

I was able to work with several of the answers provided to come up with a solution. The key was that you can not pipe a Write-Host to a file. I added the following code to write the output directly into the body of an email. Works like a charm.

$Emailbody += "$BacklogFileCount files in backlog $SendingMember->$ReceivingMember for $RGName
"
$emailFrom = "sender@foobar.com"
$emailTo = "recipient@foobar.com"
$subject = "DFS Backlog Report"
$smtpServer = "MailServer"
$smtp = new-object Net.Mail.SmtpClient($smtpServer)
$smtp.Send($emailFrom, $emailTo, $subject, $Emailbody)
  • @Admin - Somehow I asked the original question under an account that I can't gain access too. Can you please make the question answered. - Thanks – Gordon Carlisle Apr 13 '12 at 18:39