Link to home
Create AccountLog in
Avatar of David Megnin
David MegninFlag for United States of America

asked on

Simple example of sending SQL query result as HTML formatted table in an email using Powershell

I tried piecing together a couple scripts, one that send a single value to an email address and another that writes a query result to a text file, but I don't know Powershell well enough to get it to work.

I want to send the result of an SQL query of just a few columns as an HTML formatted table in an email message using Send-MailMessage.

Here is what I've got.  It prints the table to the console and the output file, but the email fails with an error.

<# connection string and SQL command to execute #>
[String] $now = Get-Date
[String] $to = 'dmegnin@careersourcebroward.com'
[String] $connectionString = 'Server=MSQLServ; Database=ITASync; Integrated Security=SSPI;'
[String] $query = @'
  SELECT Provider, LoginDate, DATEDIFF(day, LoginDate, GetDate()) as Diff
    FROM Logins
    WHERE DATEDIFF(day,LoginDate, GetDate()) IN (37)
'@


$connection = New-Object System.Data.SqlClient.SqlConnection
$connection.ConnectionString = $connectionString
$connection.Open()
$command = $connection.CreateCommand()
$command.CommandText = $query

$result = $command.ExecuteReader()

$table = new-object “System.Data.DataTable”
$table.Load($result)

$format = @{Expression={$_.Provider};Label="Provider Name";width=30},@{Expression={$_.LoginDate};Label="Login Date"; width=25},@{Expression={$_.Diff};Label="Days"; width=8}

$table | Where-Object {$_.Provider -like "*PROFESSOR" -and $_.Diff -lt 100} | format-table $format

$table | Where-Object {$_.Provider -like "*PROFESSOR" -and $_.Diff -lt 100} | format-table $format | Out-File C:\Temp\ee\Providers.txt

Send-MailMessage -BodyAsHtml -Body "$table | Where-Object {$_.Provider -like "*PROFESSOR" -and $_.Diff -lt 100} | format-table $format" -SmtpServer mail.careersourcebroward.com -From "Contract Expiration Database <csbd@careersourcebroward.com>" -To $to -Subject "Provider: $($_.Provider) logged in $($_.Diff) days ago."

$connection.Close()

Open in new window


If there's a cleaner or better with to do this, I'd like to learn it.  Thank you!
Avatar of David Megnin
David Megnin
Flag of United States of America image

ASKER

Perhaps... Maybe take something like this and eliminate the unnecessary complications so it simply puts the table result of a query into the body of the email?  I'm looking for something that would be easy for me to modify for multiple uses as a general "mail me that report" script.  Maybe to schedule as an automated thing.  Thanks.

#Get SQL Database objects and places them into array $ServerBook
$ServerBook = New-Object System.Data.DataSet "myDataSet"
	$sqlConn = New-Object System.Data.SqlClient.SqlConnection("Data Source=<Database Server>;Initial Catalog=ServerBook;Integrated Security=True")
	$adapter = New-Object System.Data.SqlClient.SqlDataAdapter("SELECT ServerName,Owner,SupportContact,SupportExternal,ServerDescription FROM v_ServerBook_BasicInfo", $sqlConn)
	$adapter.Fill($ServerBook)	


$ServerBook = $ServerBook.Tables[0] | Sort-Object -Property Owner #reorganizes $serverBook by owner
$owners = ($ServerBook.owner | Get-Unique) #stores list of unique owners and eliminates duplicates
$owners = $owners | where{$_ -ne "" -and $_ -ne $null -and $_ -ne [dbnull]::value} #eliminates null values from the list of owners

foreach($owner in $owners){
#Get the servers for the current owner
$servers = $ServerBook | where{$_.owner -eq $owner}

#Add to server list for current owner to an array
$ServerList = $servers | select ServerName, Owner, SupportContact, SupportExternal, ServerDescription

#copies the server owners name to $ownername variable
$ownerName = $owner 

#Changes the format of the name to lastname, firstname is only needed if that is the format of the display name in AD
$Username = "$($Owner.Split(" ")[1]), $($Owner.Split(" ")[0])"

#pulls email address of the $username
$EmailAddress = Get-ADuser -Filter "Name -eq '$Username'" -properties emailaddress -server ads.domain.com | select-object emailaddress

#splits the $emailAddress vaiable to help eliminate extra text
$emailaddress = $emailaddress -split '[=}]' ,0 

#removes extra text at the beginning of the variable
$emailaddress = $emailaddress.TrimStart("@{emailaddress") 

#created CSS for formatting the table in the HTML email body
$style = "<style>BODY{font-family: Arial; font-size: 10pt;}"
$style = $style + "TABLE{border: 1px solid black; border-collapse: collapse;}"
$style = $style + "TH{border: 1px solid black; background: #dddddd; padding: 5px;}"
$style = $style + "TD{border: 1px solid black; padding: 5px;}"
$style = $style + "</style>"

#creates the HTML email body with static text and adds the dynamic table with the formatting to the middle
$message = "<html>
<p>Hello $ownername,</p>
<p></p>                                 
<p>Static Text</p><hr>

<body>$($ServerList | ConvertTo-Html -Head $style | Out-String)</body>
<p></p> 
<hr>
<p></p> 
<p>Thank You,</p>
<p>Signature Block</p>
</html>
"

Send-MailMessage -To "$EmailAddress" -Subject "Bi-Annual Server Review" -Body $message -BodyAsHtml -SmtpServer "smtp1.domain.com" -Priority High -DeliveryNotificationOption OnSuccess -From "email@email.com"
}

Open in new window

SOLUTION
Avatar of David Johnson, CD
David Johnson, CD
Flag of Canada image

Link to home
membership
Create a free account to see this answer
Signing up is free and takes 30 seconds. No credit card required.
See answer
ASKER CERTIFIED SOLUTION
Link to home
membership
Create a free account to see this answer
Signing up is free and takes 30 seconds. No credit card required.
Hi footech,
Unfortunately, I'm not on my way to working anything out.  ;-)  I found both of those examples and they just look like they are either close to what I'm looking for or at least contain part of what I need.  I only started trying to learn Powershell last week when I was asked to find a way to send email alerts when our companies contracts were nearing their expiration dates.

Anyway, I didn't know a "-Fragment" parameter existed.   It makes sense to me though.

David, I don't understand your sentence fragment "two entirely different questions."  I'm asking for a simple example of a Powershell script to send the result of a query in an email and I provide what I have so far but that doesn't work.
Then I provide an example that I found, while googling around, that looks like it contains mostly what I want, but also has a bunch of stuff that I don't need, but don't know Powershell well enough (at all, really) to remove what doesn't fit with with I need.  Thanks for understanding.
If your first does everything you want and you're just concerned about the error you get when you try to send an email, then you should post the error.  But just looking at it I would say the below would work.  And if so, then other changes as shown previously are just formatting choices.
Send-MailMessage -BodyAsHtml -Body ($table | Where-Object {$_.Provider -like "*PROFESSOR" -and $_.Diff -lt 100} | ConvertTo-HTML | Out-String) -SmtpServer mail.careersourcebroward.com -From "Contract Expiration Database <csbd@careersourcebroward.com>" -To $to -Subject "Provider: $($_.Provider) logged in $($_.Diff) days ago."

Open in new window

footech,  that worked.  It displays the three column table in the console window and also sends me an email with a similar table, with the correct three columns... plus columns for; "RowError", "RowState", "Table", "ItemArray", and "HasErrors."
I don't really need those extra columns, and I don't know how to suppress them.

It's not a huge thing if the extra columns can't be suppressed, but it would be nice if the email was formatted just like the console output.

Thanks.
David, thank you for taking the time to strip out the unnecessary bits from that example.  I think I like the way the HTML seems to be formatted in that example so I'll have to add in the information for my database, etc. to see what it actually looks like.  That was an unedited example I found in another forum, so it's not in a "testable" state, yet.
footech, I found this while Googling for how to suppress those extra columns:

You should be able to simply select the data from your table that you do want when defining $body.

$body = $DataSet.Tables[0] | Select bug_id,Status,Resolution,Summary,Deadline | convertto-html | out-string
Or, you can select everything, and then specify what you want to exclude:

$body = $DataSet.Tables[0] | Select * -ExcludeProperty RowError, RowState, Table, ItemArray, HasErrors | convertto-html | out-string

But, I'm not using that particular method of creating the table, so I'm not sure how to incorporate that into the script you are helping me with.  The table you created looks beautiful.  I just would like to exclude those exact columns shown in the example above.  Thanks again.
Got it!  I added "| Select -property" and the column names I want to keep into the <body> and it's perfect.

Here is the whole working script.  Thank you so much for your help.  David, thanks for your input as well!

<# connection string and SQL command to execute #>
[String] $now = Get-Date
[String] $to = 'david@domain.com'
[String] $connectionString = 'Server=SQLServer; Database=OurDatabase; Integrated Security=SSPI;'
[String] $query = @'
  SELECT Provider, LoginDate, DATEDIFF(day, LoginDate, GetDate()) as Diff
    FROM Logins
    WHERE DATEDIFF(day,LoginDate, GetDate()) < (37)
'@

$connection = New-Object System.Data.SqlClient.SqlConnection
$connection.ConnectionString = $connectionString
$connection.Open()
$command = $connection.CreateCommand()
$command.CommandText = $query

$result = $command.ExecuteReader()

$table = new-object “System.Data.DataTable”
$table.Load($result)

$head = @"
<style>
TABLE{border-width: 2px;border-style: solid;border-color: black;border-collapse: collapse;}
TH{border-width: 2px;padding: 4px;border-style: solid;border-color: black;background-color:lightblue;text-align:left;font-size:14px}
TD{border-width: 1px;padding: 4px;border-style: solid;border-color: black;font-size:12px}
</style>
"@

$prebody = @"
<H4>SQL query results</H4>
"@

$message =  @"
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
$head
</head>
<body>
$($table | Select -property Provider, LoginDate, Diff | Where-Object {$_.Provider -like "*PROFESSOR" -and $_.Diff -lt 100} | ConvertTo-Html -Fragment -PreContent $prebody -PostContent "<p>footer</p>" | Out-String)
<hr>
<p></p> 
<p>Thank You,</p>
<p>Signature Block</p>
</body>
</html>
"@

Send-MailMessage -BodyAsHtml -Body $message -SmtpServer mail.domain.com -From "Contract Expiration Database <csbd@domain.com>" -To "david@domain.com" -Subject "neat stuff"

$connection.Close()

Open in new window

Thank you, both, for your help!