How to Apply Formatting to my Table? - html

I'm trying to apply a table formatting to my table when it is emailed out, but cannot seem to figure how to do so. I'm pretty sure the problem is related to how the $html variable is set, or maybe when I try to set $EmailTable to $html with $a as the table formatting. Any help is appreciated!
$ProgramA = "A-1"
$MonikerA = "A-2"
$CountA = "1"
$ProgramB = "B-1"
$MonikerB = "B-2"
$CountB = "2"
$ProgramC = "C-1"
$MonikerC = "C-2"
$CountC = "3"
# Create a DataTable
$table = New-Object system.Data.DataTable "TestTable"
$col1 = New-Object system.Data.DataColumn Program,([string])
$col2 = New-Object system.Data.DataColumn Moniker,([string])
$col3 = New-Object system.Data.DataColumn Cases,([string])
$table.columns.add($col1)
$table.columns.add($col2)
$table.columns.add($col3)
# Add content to the DataTable
$row = $table.NewRow()
$row.Program = $ProgramA
$row.Moniker = $MonikerA
$row.Cases = $CountA
$table.Rows.Add($row)
$row = $table.NewRow()
$row.Program = $ProgramB
$row.Moniker = $MonikerB
$row.Cases = $CountB
$table.Rows.Add($row)
$row = $table.NewRow()
$row.Program = $ProgramC
$row.Moniker = $MonikerC
$row.Cases = $CountC
$table.Rows.Add($row)
$row = $table.NewRow()
# Create an HTML version of the DataTable
$html = "<table><tr><td>Program</td><td>Moniker</td><td>Cases</td></tr>"
foreach ($row in $table.Rows)
{
$html += "<tr><td>" + $row[0] + "</td><td>" + $row[1] + "</td><td>" + $row[2] + "</td></tr>"
}
$html += "</table>"
# Here is the formatting I'm trying to apply (which doesn't work)
$a = "<style>BODY{font-family: Verdana; font-size: 9pt;}"
$a = $a + "BODY{background-color:white;}"
$a = $a + "TABLE{border-width: 1px;border-style: solid;border-color: black;border-collapse: collapse; }"
$a = $a + "TH{border-width: 2px;padding: 7px;border-style: solid;border-color: black;background-color:lightblue;padding-right: 2px;}"
$a = $a + "TD{border-width: 2px;padding: 5px;border-style: solid;border-color: black;background-color:white; padding-right: 2px;}"
$a = $a + "</style>"
$EmailTable = $html ConvertTo-HTML -head $a

$EmailTable = $html ConvertTo-HTML -head $a
This is not how ConvertTo-Html works. Not only is the statement missing a | before ConvertTo-Html, but $html already contains a (manually constructed) HTML table. The purpose of ConvertTo-Html is to do the conversion of a list of objects into an HTML table for you. Change the above to this:
$EmailTable = $table | ConvertTo-Html -Head $a

Related

No mapping exists objecttype: Arraylist to native type

I have an arraylist filled with data from a cmdlet (from the BEMCLI module) and want to store the data in a database. Declaring every column is just to specify the error.
There are some questions about a similar error code but I don't know how to get the solution work for me.
Errorcode:
No mapping exists from object type System.Data.Arraylist to a known managed
provider native type
In C:\**\test.ps1:68 Zeichen:1
+ $SqlCmd.executenonquery()
+ ~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : ArgumentException
Script:
$JobHistory = Invoke-Command -ComputerName $ServerName -ScriptBlock {
Import-Module BEMCLI;
Get-BEJobHistory -FromStartTime (Get-Date).AddDays(-1)
}
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Server = $SQLServer; Database = $SQLDBName; Integrated Security = True;"
$SqlConnection.Open()
for ($i=0; $i -lt $JobHistory.Length; $i++) {
$SqlCmd.Parameters.Add("#Name", [System.Data.SqlDbType]::string).Value = $JobHistory[$i].Name
$SqlCmd.Parameters.Add("#ID", [System.Data.SqlDbType]::UniqueIdentifier).Value = $JobHistory[$i].ID
$SqlCmd.Parameters.Add("#JobName", [System.Data.SqlDbType]::String).Value = $JobHistory[$i].JobName
$SqlCmd.Parameters.Add("#JobStatus", [System.Data.SqlDbType]::String).Value = $JobHistory[$i].JobStatus
$SqlCmd.Parameters.Add("#Job", [System.Data.SqlDbType]::String).Value = $JobHistory[$i].Job
$SqlCmd.Parameters.Add("#JobId", [System.Data.SqlDbType]::UniqueIdentifier).Value = $JobHistory[$i].JobId
$SqlCmd.Parameters.Add("#JobType", [System.Data.SqlDbType]::String).Value = $JobHistory[$i].JobType
$SqlCmd.Parameters.Add("#StartTime", [System.Data.SqlDbType]::DateTime).Value = $JobHistory[$i].StartTime
$SqlCmd.Parameters.Add("#ElapsedTime", [System.Data.SqlDbType]::TimeSpan).Value = $JobHistory[$i].ElapsedTime
$SqlCmd.Parameters.Add("#EndTime", [System.Data.SqlDbType]::DateTime).Value = $JobHistory[$i].EndTime
$SqlCmd.Parameters.Add("#PercentComplete", [System.Data.SqlDbType]::Real).Value = $JobHistory[$i].PercentComplete
$SqlCmd.Parameters.Add("#AgentServer", [System.Data.SqlDbType]::String).Value = $JobHistory[$i].AgentServer
$SqlCmd.Parameters.Add("#AgentServerIdList", [System.Data.SqlDbType]::String).Value = $JobHistory[$i].AgentServerIdList
$SqlCmd.Parameters.Add("#BackupExecServerName", [System.Data.SqlDbType]::String).Value = $JobHistory[$i].JobLogFilePath
$SqlCmd.Parameters.Add("#JobLogFilePath", [System.Data.SqlDbType]::String).Value = $JobHistory[$i].JobLogFilePath
$SqlCmd.Parameters.Add("#DeduplicationRatio", [System.Data.SqlDbType]::Real).Value = $JobHistory[$i].DeduplicationRatio
$SqlCmd.Parameters.Add("#JobRateMBPerMinute", [System.Data.SqlDbType]::Real).Value = $JobHistory[$i].JobRateMBPerMinute
$SqlCmd.Parameters.Add("#StorageName", [System.Data.SqlDbType]::String).Value = $JobHistory[$i].StorageName
$SqlCmd.Parameters.Add("#TotalDataSizeBytes", [System.Data.SqlDbType]::BigInt).Value = $JobHistory[$i].TotalDataSizeBytes
$SqlCmd.Parameters.Add("#ErrorCategory", [System.Data.SqlDbType]::Int).Value = $JobHistory[$i].ErrorCategory
$SqlCmd.Parameters.Add("#ErrorCode", [System.Data.SqlDbType]::Int).Value = $JobHistory[$i].ErrorCode
$SqlCmd.Parameters.Add("#ErrorCategory", [System.Data.SqlDbType]::String).Value = $JobHistory[$i].ErrorCategory
$SqlCmd.Parameters.Add("#ErrorMessage", [System.Data.SqlDbType]::Int).Value = $JobHistory[$i].ErrorMessage
$SqlQuery = "INSERT INTO JobHistory(Nr,Name,ID,JobName,JobStatus,Job,JobId,JobType,StartTime,ElapsedTime,EndTime,PercentComplete,AgentServer,AgentServerIdList,BackupExecServerName,JobLogFilePath,DeduplicationRatio,JobRateMBPerMinute,StorageName,TotalDataSizeBytes,ErrorCategory,ErrorCode,ErrorCategory,ErrorMessage) VALUES (#Nr,#Name,#ID,#JobName,#JobStatus,#Job,#JobId,#JobType,#StartTime,#ElapsedTime,#EndTime,#PercentComplete,#AgentServer,#AgentServerIdList,#BackupExecServerName,#JobLogFilePath,#DeduplicationRatio,#JobRateMBPerMinute,#StorageName,#TotalDataSizeBytes,#ErrorCategory,#ErrorCode,#ErrorCategory,#ErrorMessage)"
$SqlCmd.CommandText = $SqlQuery
$SqlCmd.Connection = $SqlConnection
$SqlCmd.ExecuteNonQuery()
}
Thanks to Richard for giving the right hint.
Collections cause the problem (AgentServer and AgentServerIdList)
i fixed the code from above, adding $SqlCmd.Parameters.Clear() in the loop to clear the parameters in every loop. It was something like 'cannot declare #Variable twice'.
Commandline gave me another error - so i decided to switch to .Parameters.AddWithValue-Command.
Script works fine now. Thank you!
$JobHistory = invoke-command -ComputerName $ServerName -ScriptBlock { import-module BEMCLI; Get-BEJobHistory -FromStartTime (get-date).AddDays(-1) }
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Server = $SQLServer; Database = $SQLDBName; Integrated Security = True;"
$SqlCmd.Connection = $SqlConnection
$SqlConnection.Open()
for($i=0; $i -lt $JobHistory.Length; $i++){
$SqlCmd.Parameters.Clear()
$SqlCmd.Parameters.AddWithValue("#Nr", $JobHistory[$i].Nr)
$SqlCmd.Parameters.AddWithValue("#Name",$JobHistory[$i].Name)
$SqlCmd.Parameters.AddWithValue("#ID", $JobHistory[$i].ID)
$SqlCmd.Parameters.AddWithValue("#JobName", $JobHistory[$i].JobName)
$SqlCmd.Parameters.AddWithValue("#JobStatus", $JobHistory[$i].JobStatus)
$SqlCmd.Parameters.AddWithValue("#Job", $JobHistory[$i].Job)
$SqlCmd.Parameters.AddWithValue("#JobId", $JobHistory[$i].JobId)
$SqlCmd.Parameters.AddWithValue("#JobType", $JobHistory[$i].JobType)
$SqlCmd.Parameters.AddWithValue("#StartTime", $JobHistory[$i].StartTime)
$SqlCmd.Parameters.AddWithValue("#ElapsedTime", $JobHistory[$i].ElapsedTime)
$SqlCmd.Parameters.AddWithValue("#EndTime", $JobHistory[$i].EndTime)
$SqlCmd.Parameters.AddWithValue("#PercentComplete", $JobHistory[$i].PercentComplete)
$SqlCmd.Parameters.AddWithValue("#BackupExecServerName", $JobHistory[$i].BackupExecServerName)
$SqlCmd.Parameters.AddWithValue("#JobLogFilePath", $JobHistory[$i].JobLogFilePath)
$SqlCmd.Parameters.AddWithValue("#DeduplicationRatio", $JobHistory[$i].DeduplicationRatio)
$SqlCmd.Parameters.AddWithValue("#JobRateMBPerMinute", $JobHistory[$i].JobRateMBPerMinute)
$SqlCmd.Parameters.AddWithValue("#StorageName", $JobHistory[$i].StorageName)
$SqlCmd.Parameters.AddWithValue("#TotalDataSizeBytes", $JobHistory[$i].TotalDataSizeBytes)
$SqlCmd.Parameters.AddWithValue("#ErrorCode", $JobHistory[$i].ErrorCode)
$SqlCmd.Parameters.AddWithValue("#ErrorCategory", $JobHistory[$i].ErrorCategory)
$SqlCmd.Parameters.AddWithValue("#ErrorCategoryType", $JobHistory[$i].ErrorCategoryType)
$SqlCmd.Parameters.AddWithValue("#ErrorMessage", $ValueForJobHistory[$i].ErrorMessage)
$SqlQuery = "Insert into JobHistory(Nr,Name,ID,JobName,JobStatus,Job,JobId,JobType,StartTime,ElapsedTime,EndTime,PercentComplete,BackupExecServerName,JobLogFilePath,DeduplicationRatio,JobRateMBPerMinute,StorageName,TotalDataSizeBytes,ErrorCode,ErrorCategory,ErrorCategoryType) Values(#Nr,#Name,#ID,#JobName,#JobStatus,#Job,#JobId,#JobType,#StartTime,#ElapsedTime,#EndTime,#PercentComplete,#BackupExecServerName,#JobLogFilePath,#DeduplicationRatio,#JobRateMBPerMinute,#StorageName,#TotalDataSizeBytes,#ErrorCode,#ErrorCategoryType,#ErrorCategory)"
$SqlCmd.CommandText = $SqlQuery
$SqlCmd.executenonquery()
}

Color-code cells in HTML mail based on criteria [duplicate]

This question already has answers here:
Convertto-Html: Highlight the cells with special values?
(2 answers)
Closed 6 years ago.
I have a simple script which checks disk space on remote servers, it's got a simple output format which is as follows
What I'd like to do, is color code the individual cells based on their values. Specifically, I'd like to have the cell shaded RED if the free space is less than 300 on any of the drives. What's the easiest means to do this based on the results being sent by PowerShell Send-MailMessage in HTML format?
Here's the code i've got that collects the data from the remote servers:
function Set-AlternatingRows {
[CmdletBinding()]
Param(
[Parameter(Mandatory,ValueFromPipeline)]
[string]$Line,
[Parameter(Mandatory)]
[string]$CSSEvenClass,
[Parameter(Mandatory)]
[string]$CSSOddClass
)
Begin {
$ClassName = $CSSEvenClass
}
Process {
if ($Line.Contains("<tr><td>")) {
$Line = $Line.Replace("<tr>","<tr class=""$ClassName"">")
if ($ClassName -eq $CSSEvenClass) {
$ClassName = $CSSOddClass
} else {
$ClassName = $CSSEvenClass
}
}
return $Line
}
}
foreach ($Item in $InputCSV) {
Write-Host "Checking $($Item.Server) now"
$ShortDate = (Get-Date).ToString('MM/dd/yyyy')
$Ping = PingEM $Item.Server
### Check if server is online before proceeding
if ($Ping -eq "Online") {
Write-Host "$($Item.Server) is Online" -ForegroundColor Green
$FreeSpaceAll = Get-WmiObject Win32_LogicalDisk -filter "DriveType=3" -Computer $($Item.Server) |
Select SystemName, DeviceID, VolumeName,
#{Name="Total Size (GB)";E={"{0:N1}" -f($_.Size/1gb)}},
#{Name="Free Space (GB)";E={"{0:N1}" -f($_.Freespace/1gb)}}
$FreeSpaceC = $FreeSpaceAll | Where {$_.DeviceID -eq "C:"} | Select -expand "Free Space (GB)"
$FreeSpaceD = $FreeSpaceAll | Where {$_.DeviceID -eq "D:"} | Select -expand "Free Space (GB)"
$FreeSpaceE = $FreeSpaceAll | Where {$_.DeviceID -eq "E:"} | Select -expand "Free Space (GB)"
} # Ping
$outarray += New-Object PsObject -Property #{
Server = $Item.Server
FreeSpaceAll = $FreeSpaceAll
FreeSpaceC = $FreeSpaceC
FreeSpaceD = $FreeSpaceD
FreeSpaceE = $FreeSpaceE
PingResults = $Ping
} # OutArray New-Object
} # For
$Head = Get-Content "$Dir\CSS.txt"
$Pre = "This email contains info on C/D/E free space on remote servers<br> <br>"
$Pre += "The below report data is available in Excel .CSV format $Link1. After 7 days, the reports will be moved $Link2 <br><br>"
$Output = $OutArray |
Select Server, PingResults, #{E={$_.FreeSpaceC};Label="Free Space C: (GB)"},
#{E={$_.FreeSpaceD};Label="Free Space D: (GB)"},
#{E={$_.FreeSpaceE};Label="Free Space E: (GB)"} |
ConvertTo-Html -Head $Head -PreContent $Pre -As Table | Set-AlternatingRows -CSSOddClass odd -CSSEvenClass even |
Out-String
$Subject = "($ScriptVer) - file server C/D/E free space report"
$TSBody = ""
$TSBody += "<font face ='arial' color='black'>$Output </font><br><br>"
Send-NailMessage $To -Subject $Subject -Body $TSbody -BodyAsHtml -From $From -SmtpServer $Mailer
I have written this so that it generally does what you want. It is already set to go with HTML tables and an free relay server email provider. This script takes one text input file that you can specify at the top. This text file will contain all of the server names that you want to check, on their own line. Example below. If you want to use your own email provider, you can just replace all the smtp info. Otherwise, it DOES REQUIRE admin priviledges to be run successfully. These credentials can be entered at the top of the script where $cred is specified. You will also need to change the $servers variable to point to your list of server names to check against. It currently only selects the C drive, but you can easily edit that as well as add a column for ping results.
Example of C:\temp\servers.txt
hqdc01
hqdc02
hqdc03
hqfile01
hqfile02
hqmail01
hqservices01
hqsql01
hqsql02
The .ps1 script:
$cred = Get-Credential -Credential 'domain\domainadminuser'
$ServerName = Get-Content "C:\temp\servers.txt"
$ConvertToGB = (1024 * 1024 * 1024)
$enter1 = "`r"
$enter2 = "`r`n"
# Smtp deets
$smtpServer = "relay.appriver.com"
$smtpPort = "2525"
$smtpFrom = "from#from.com"
$smtpTo = "myself#myself.com"
$messageSubject = "Daily Server Report"
# Set up an SmtpClient
$smtpClient = New-Object Net.Mail.SmtpClient
$smtpClient.Host = $smtpServer
$smtpClient.Port = $smtpPort
# Create the MailMessage
$mailMessage = New-Object Net.Mail.MailMessage
$mailMessage.From = $smtpFrom
$mailMessage.To.Add($smtpTo)
$mailMessage.Subject = $messageSubject
$mailMessage.IsBodyHtml = $true
# style
$htmlReport += "<style>"
$htmlReport += "BODY{background-color:white;}"
$htmlReport += "TABLE{border-width: 1px;border-style: solid;border-color: black;border-collapse: collapse;}"
$htmlReport += "TH{border-width: 1px;padding: 0px;border-style: solid;border-color: black;}"
$htmlReport += "TD{border-width: 1px;padding: 0px;border-style: solid;border-color: black;}"
$htmlReport += "</style>"
# table
$htmlReport += "<table>"
$htmlReport += "`n"
$htmlReport += "<tr>"
$htmlReport += "<th>ServerName</th>"
$htmlReport += "<th>Total C:</th>"
$htmlReport += "<th>Free C:</th>"
$htmlReport += "<th>% Free C:</th>"
$htmlReport += "<th>Total D:</th>"
$htmlReport += "<th>Free D:</th>"
$htmlReport += "<th>% Free D:</th>"
$htmlReport += "<th>Total E:</th>"
$htmlReport += "<th>Free E:</th>"
$htmlReport += "<th>% Free E:</th>"
$htmlReport += "</tr>"
foreach($Server in $ServerName)
{
#Get info on all C: drives
$diskC = Get-WmiObject -Credential $cred Win32_LogicalDisk -ComputerName $Server -Filter "DeviceID='C:'" | Select-Object Size,FreeSpace
$htmlReport += "<tr>"
$htmlReport += "<td>$($Server)</td>"
try
{
$htmlReport += "<td>$([Math]::Truncate($diskC.Size / $ConvertToGB)) GB </td>"
}
catch
{
$htmlReport += "<td>NA</td>"
}
try
{
$htmlReport += "<td>$([Math]::Truncate($diskC.FreeSpace / $ConvertToGB)) GB </td>"
}
catch
{
$htmlReport += "<td>NA</td>"
}
try
{
if([Math]::Truncate(($diskC.FreeSpace / $diskC.size) * 100) -le 10)
{
$htmlReport += "<td><font color=red> $([Math]::Truncate(($diskC.FreeSpace / $diskC.size) * 100)) % </font></td>"
}
if([Math]::Truncate(($diskC.FreeSpace / $diskC.size) * 100) -gt 10 -and [Math]::Truncate(($diskC.FreeSpace / $diskC.size) * 100) -le 20)
{
$htmlReport += "<td><font color=orange> $([Math]::Truncate(($diskC.FreeSpace / $diskC.size) * 100)) % </font></td>"
}
if([Math]::Truncate(($diskC.FreeSpace / $diskC.size) * 100) -gt 20)
{
$htmlReport += "<td><font color=green> $([Math]::Truncate(($diskC.FreeSpace / $diskC.size) * 100)) % </font></td>"
}
}
catch
{
$htmlReport += "<td>NA</td>"
}
#Get info on all D: drives
$diskD = Get-WmiObject -Credential $cred Win32_LogicalDisk -ComputerName $Server -Filter "DeviceID='D:'" | Select-Object Size,FreeSpace
try
{
$htmlReport += "<td>$([Math]::Truncate($diskD.Size / $ConvertToGB)) GB </td>"
}
catch
{
$htmlReport += "<td>NA</td>"
}
try
{
$htmlReport += "<td>$([Math]::Truncate($diskD.FreeSpace / $ConvertToGB)) GB </td>"
}
catch
{
$htmlReport += "<td>NA</td>"
}
try
{
if([Math]::Truncate(($diskE.FreeSpace / $diskE.size) * 100) -le 10)
{
$htmlReport += "<td><font color=red> $([Math]::Truncate(($diskD.FreeSpace / $diskD.size) * 100)) % </font></td>"
}
if([Math]::Truncate(($diskE.FreeSpace / $diskE.size) * 100) -gt 10 -and [Math]::Truncate(($diskD.FreeSpace / $diskD.size) * 100) -le 20)
{
$htmlReport += "<td><font color=orange> $([Math]::Truncate(($diskD.FreeSpace / $diskD.size) * 100)) % </font></td>"
}
if([Math]::Truncate(($diskE.FreeSpace / $diskE.size) * 100) -gt 20)
{
$htmlReport += "<td><font color=green> $([Math]::Truncate(($diskD.FreeSpace / $diskD.size) * 100)) % </font></td>"
}
}
catch
{
$htmlReport += "<td>NA</td>"
}
#Get info on all E: drives
$diskE = Get-WmiObject -Credential $cred Win32_LogicalDisk -ComputerName $Server -Filter "DeviceID='E:'" | Select-Object Size,FreeSpace
try
{
$htmlReport += "<td>$([Math]::Truncate($diskE.Size / $ConvertToGB)) GB </td>"
}
catch
{
$htmlReport += "<td>NA</td>"
}
try
{
$htmlReport += "<td>$([Math]::Truncate($diskE.FreeSpace / $ConvertToGB)) GB </td>"
}
catch
{
$htmlReport += "<td>NA</td>"
}
try
{
if([Math]::Truncate(($diskE.FreeSpace / $diskE.size) * 100) -le 10)
{
$htmlReport += "<td><font color=red> $([Math]::Truncate(($diskE.FreeSpace / $diskE.size) * 100)) % </font></td>"
}
if([Math]::Truncate(($diskE.FreeSpace / $diskE.size) * 100) -gt 10 -and [Math]::Truncate(($diskE.FreeSpace / $diskE.size) * 100) -le 20)
{
$htmlReport += "<td><font color=orange> $([Math]::Truncate(($diskE.FreeSpace / $diskE.size) * 100)) % </font></td>"
}
if([Math]::Truncate(($diskE.FreeSpace / $diskE.size) * 100) -gt 20)
{
$htmlReport += "<td><font color=green> $([Math]::Truncate(($diskE.FreeSpace / $diskE.size) * 100)) % </font></td>"
}
}
catch
{
$htmlReport += "<td>NA</td>"
}
$htmlReport += "</tr>"
}
$htmlReport += "</table>"
# Now create an AlternateView from the HTML contents
$messageBody = [Net.Mail.AlternateView]::CreateAlternateViewFromString($htmlReport, 'text/html')
# Add the HTML view to the MailMessage
$mailMessage.AlternateViews.Add($messageBody)
# And finally send the message
$smtpClient.Send($mailMessage)
pause
And last but not least, here is a picture of the sample email that you will get with this embedded table:

Powershell get disk space, convert to HTML and compare a value and if it is less than 15% change the color of the entire row

i have created a PowerShell script that reads from a list of servers, use the Get-WmiObject to get the drive capacity, freespace and then calculates the free space percentage and the converts it all to a nice little HTML.
the question is that i need to figure out how to have it look at the Percentage of free space and if it is below 15% color the entire row of the html table red.
is this even possible?
can anyone help with this?
below is my powershell
$servers = GC XX:\myservers.txt
$date = get-date -Format yyyyMMdd
$time = get-date -Format hhmm
$a = "<style>"
$a = $a + "BODY{background-color:white;}"
$a = $a + "TABLE{border-width: 2px;border-style: solid;border-color: black;border-collapse: separate;width:800px}"
$a = $a + "TH{border-width: 1px;padding: 0px;border-style: solid;border-color: black;background-color:lightblue}"
$a = $a + "TD{border-width: 1px;padding: 0px;border-style: solid;border-color: black;background-color:White}"
$a = $a + "</style>"
Foreach ($s in $servers)
{
Get-WmiObject -Class win32_volume -cn $s |
Select-Object #{LABEL='Computer';EXPRESSION={$s}},
driveletter, #{LABEL='GBfreespace';EXPRESSION={"{0:N2}" -f ($_.freespace/1GB)}},
#{LABEL='Capacity';EXPRESSION={"{0:N2}" -f ($_.capacity/1GB)}},
#{LABEL='Percentage';EXPRESSION={"{0:N2}" -f ($_.freespace/$_.capacity*100)+"%"}} |
ConvertTo-Html -head $a | Out-File -append "D:\Users\PLACE\Desktop\diskspace\Freespace$date-$time.htm"
}
I think you have two options: You can either create the HTML using the ConvertTo-Htmlcmdlet and format the rows afterwards, or you create the html for yourself using some string formats:
$html =
#'
<!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>
<style>BODY{{background-color:white;}}TABLE{{border-width: 2px;border-style: solid;border-color: black;border-collapse: separate;width:800px}}TH{{border-width: 1px;padding: 0px;border-style: solid;border
-color: black;background-color:lightblue}}TD{{border-width: 1px;padding: 0px;border-style: solid;border-color: black;background-color:White}}</style>
</head><body>
<table>
<colgroup><col/><col/><col/><col/><col/></colgroup>
<tr><th>Computer</th><th>driveletter</th><th>GBfreespace</th><th>Capacity</th><th>Percentage</th></tr>
{0}
</table>
</body></html>
'#
$trTemplate ='<tr><td>{0}</td><td>{1}</td><td>{2:N2}</td><td>{3:N2}</td><td {4}>{5:N2}%</td></tr>'
$redStyle = 'style="background-color:Red"'
$tr = #()
$servers = GC XX:\myservers.txt
Foreach ($s in $servers)
{
Get-WmiObject -Class win32_volume -cn $s | Where Capacity | ForEach-Object {
$freespaceInPercent = ($_.freespace/$_.capacity*100)
$red = ''
if ($freespaceInPercent -lt [double]15)
{
$red = $redStyle
}
$tr += ($trTemplate -f $s, $_.driveletter, ($_.freespace/1GB), ($_.capacity/1GB), $red, $freespaceInPercent)
}
}
$html -f ($tr -join '') | Out-File -append "D:\Users\<Your username here>\Desktop\diskspace\Freespace$date-$time.htm"
here is what i ended up with and it works exactly like i need it to
$server_file = "D:\location\Windowsservers.txt"
$html_file_dir = "\\netwolocation\DiskSpace"
$background_color = "#FFFFFF" # can be in rgb format (rgb(140,166,193)) or hex format (#FFFFFF)
$server_name_font = "Tahoma"
$server_name_font_size = "20px"
$server_name_bg_color = "#FFFFFF" # can be in rgb format (rgb(77,108,145)) or hex format (#FFFFFF)
$heading_font = "Tahoma"
$heading_font_size = "14px"
$heading_name_bg_color = "#0099FF" # can be in rgb format (rgb(95,130,169)) or hex format (#FFFFFF)
$data_font = "Tahoma"
$data_font_size = "11px"
$Critical_space = "#FF0000" # (Red) Critical low space
$very_low_space = "#FFFF00" # (Yellow) very low space
$low_space = "#FF9900" # (Orange) low space
$medium_space = "#99CC66" # (Green) medium
$ErrorActionPreference = "SilentlyContinue"
$date = Get-Date -UFormat "%Y%m%d-%H%m"
$html_file = New-Item -ItemType File -Path "$html_file_dir\WindowsServerDiskSpaceCheck_$date-$time.html" -Force
$html_file
Function ConvertBytes {
param($size)
If ($size -lt 1MB) {
$drive_size = $size / 1KB
$drive_size = [Math]::Round($drive_size, 2)
[string]$drive_size + ' KB'
}elseif ($size -lt 1GB){
$drive_size = $size / 1MB
$drive_size = [Math]::Round($drive_size, 2)
[string]$drive_size + ' MB'
}ElseIf ($size -lt 1TB){
$drive_size = $size / 1GB
$drive_size = [Math]::Round($drive_size, 2)
[string]$drive_size + ' GB'
}Else{
$drive_size = $size / 1TB
$drive_size = [Math]::Round($drive_size, 2)
[string]$drive_size + ' TB'
}
}
$html_header = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html lang="en-US" xml:lang="en-US" xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Server Drive Space</title>
<style type="text/css">
.serverName { text-align:center; font-family:"' + $server_name_font + '"; font-size:' + $server_name_font_size + `
'; font-weight:bold; background-color: ' + $server_name_bg_color + '; border: 1px solid black; width: 150px; }
.headings { text-align:center; font-family:"' + $heading_font + '"; font-size:' + $heading_font_size + `
'; font-weight:bold; background-color: ' + $heading_name_bg_color + '; border: 1px solid black; width: 150px; }
.data { font-family:"' + $data_font + '"; font-size:' + $data_font_size + '; border: 1px solid black; width: 150px; }
#dataTable { border: 1px solid black; border-collapse:collapse; }
body { background-color: ' + $background_color + '; }
#legend { border: 1px solid black; position:absolute; right:500px; top:10px; }
</style>
<script language="JavaScript" type="text/javascript">
<!--
function zxcWWHS(){
if (document.all){
zxcCur=''hand'';
zxcWH=document.documentElement.clientHeight;
zxcWW=document.documentElement.clientWidth;
zxcWS=document.documentElement.scrollTop;
if (zxcWH==0){
zxcWS=document.body.scrollTop;
zxcWH=document.body.clientHeight;
zxcWW=document.body.clientWidth;
}
}
else if (document.getElementById){
zxcCur=''pointer'';
zxcWH=window.innerHeight-15;
zxcWW=window.innerWidth-15;
zxcWS=window.pageYOffset;
}
zxcWC=Math.round(zxcWW/2);
return [zxcWW,zxcWH,zxcWS];
}
window.onscroll=function(){
var img=document.getElementById(''legend'');
if (!document.all){ img.style.position=''fixed''; window.onscroll=null; return; }
if (!img.pos){ img.pos=img.offsetTop; }
img.style.top=(zxcWWHS()[2]+img.pos)+''px'';
}
//-->
</script>
</head>
<body>'
$html_footer = '</body>
</html>'
Add-Content $html_file $html_header
Get-Content $server_file |`
ForEach-Object {
$hostname = Get-WmiObject -Impersonation Impersonate -ComputerName $_ -Query "SELECT Name From Win32_ComputerSystem"
$name = $hostname.Name.ToUpper()
Add-Content $html_file ('<Table id="dataTable"><tr><td colspan="3" class="serverName">' + $name + '</td></tr>
<tr><td class="headings">Drive Letter</td><td class="headings">Total Size</td><td class="headings">Free Space</td><td class="headings">Percent Free</td></tr>')
$drives = Get-WmiObject Win32_LogicalDisk -Filter "drivetype=3" -ComputerName $_ -Impersonation Impersonate
ForEach ($drive in $drives) {
$space_color = ""
$free_space = $drive.FreeSpace
$percent = ($drive.FreeSpace/$drive.size*100)
$percent = [Math]::Round($percent, 2)
If ($percent -le 1) {
$space_color = $Critical_space
}elseif ($percent -le 5) {
$space_color = $very_low_space
}elseif ($percent -le 10) {
$space_color = $low_space
}elseif ($percent -le 15) {
$space_color = $medium_space
}
Add-Content $html_file ('<tr><td class="data">' + $drive.deviceid + '</td><td class="data">' + (ConvertBytes $drive.size) + `
'</td><td class="data" bgcolor="' + $space_color + '">' + (ConvertBytes $drive.FreeSpace) + '</td><td class="data" bgcolor="' + $space_color + '">' + $percent + '</td></tr>')
}
Add-Content $html_file ('</table></br><div id="legend">
<Table><tr><td style="font-size:12px">Less then or equal to 1% Free Space</td><td bgcolor="' + $Critical_space + '" width="10px"></td></tr>
<tr><td style="font-size:12px">1% to 5% Free Space</td><td bgcolor="' + $very_low_space + '" width="10px"></td></tr>
<tr><td style="font-size:12px">5% to 10% Free Space</td><td bgcolor="' + $low_space + '" width="10px"></td></tr>
<tr><td style="font-size:12px">10% to 15% Free Space</td><td bgcolor="' + $medium_space + '" width="10px"></td></tr>
</table></div>')
}
Add-Content $html_file $html_footer

Converting Body to HTML Not Working

I am trying to make my body of text convert to HTML so it does not show as plain text in my email.
Here is the code
$From = ""
$To = ""
$SMTPServer = ""
$SMTPPort = "587"
$Username = ""
$Password = ""
$subject = "Test Powershell"
$body = $htmlreport
$bodyAsHtml = $true
$smtp = New-Object System.Net.Mail.SmtpClient($SMTPServer, $SMTPPort);
$smtp.EnableSSL = $true
$smtp.Credentials = New-Object System.Net.NetworkCredential($Username, $Password);
$smtp.Send($From, $To, $subject, $body);
I cant see to get the report to send as HTML.
Instead of passing the individual strings to $smtp.Send(), you should create a MailMessage object and send that instead:
$msg = New-Object System.Net.Mail.MailMessage
$msg.From = $From
$msg.To = $To
$msg.Subject = $subject
$msg.Body = $body
$msg.IsBodyHtml = $true # this is where the magic happens
$smtp = New-Object System.Net.Mail.SmtpClient($SMTPServer, $SMTPPort)
$smtp.EnableSSL = $true
$smtp.Credentials = New-Object System.Net.NetworkCredential($Username, $Password)
$smtp.Send($msg) # and then send the message we just composed above
$bodyAs contains `enter code here`. You should remove that. You also don't set it anywhere.
Maybe try the Send-MailMessage cmdlet instead:
Send-MailMessage -SmtpServer $SMTPServer -To $To -From $From -Subject $subject -Body $body -BodyAsHtml

Script Exporting Policies and Conditions

I would like to automatically script out all SQL Server 2008 policies and conditions on a server each night and compare the files to my version control system. In the UI, I can script out individual policies by right-clicking the policy and selecting Export Policy. Is it possible to script out policies and conditions via SMO or PowerShell?
Ideally, I would like to incorporate this into my existing PowerShell script that generates scripts for all of my other server and database objects. Here's the script that currently does this action:
# Load needed assemblies
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO") | out-null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMOExtended")| Out-Null;
#Specify target server and databases.
$sql_server = "SomeServerName"
$SMOserver = New-Object -TypeName Microsoft.SqlServer.Management.Smo.Server -ArgumentList "$sql_server"
$databases = $SMOserver.Databases
$BaseSavePath = "T:\SomeFilePath\" + $sql_server + "\"
#Remove existing objects.
Remove-Item $BaseSavePath -Recurse
#Script server-level objects.
$ServerSavePath = $BaseSavePath
$ServerObjects = $SMOserver.BackupDevices
$ServerObjects += $SMOserver.Endpoints
$ServerObjects += $SMOserver.JobServer.Jobs
$ServerObjects += $SMOserver.LinkedServers
$ServerObjects += $SMOserver.Triggers
foreach ($ScriptThis in $ServerObjects | where {!($_.IsSystemObject)})
{
#Need to Add Some mkDirs for the different $Fldr=$ScriptThis.GetType().Name
$scriptr = new-object ('Microsoft.SqlServer.Management.Smo.Scripter') ($SMOserver)
$scriptr.Options.AppendToFile = $True
$scriptr.Options.AllowSystemObjects = $False
$scriptr.Options.ClusteredIndexes = $True
$scriptr.Options.DriAll = $True
$scriptr.Options.ScriptDrops = $False
$scriptr.Options.IncludeHeaders = $False
$scriptr.Options.ToFileOnly = $True
$scriptr.Options.Indexes = $True
$scriptr.Options.Permissions = $True
$scriptr.Options.WithDependencies = $False
<#Script the Drop too#>
$ScriptDrop = new-object ('Microsoft.SqlServer.Management.Smo.Scripter') ($SMOserver)
$ScriptDrop.Options.AppendToFile = $True
$ScriptDrop.Options.AllowSystemObjects = $False
$ScriptDrop.Options.ClusteredIndexes = $True
$ScriptDrop.Options.DriAll = $True
$ScriptDrop.Options.ScriptDrops = $True
$ScriptDrop.Options.IncludeHeaders = $False
$ScriptDrop.Options.ToFileOnly = $True
$ScriptDrop.Options.Indexes = $True
$ScriptDrop.Options.WithDependencies = $False
<#This section builds folder structures. Remove the date folder if you want to overwrite#>
$TypeFolder=$ScriptThis.GetType().Name
if ((Test-Path -Path "$ServerSavePath\$TypeFolder") -eq "true") `
{"Scripting Out $TypeFolder $ScriptThis"} `
else {new-item -type directory -name "$TypeFolder"-path "$ServerSavePath"}
$ScriptFile = $ScriptThis -replace ":", "-" -replace "\\", "-"
$ScriptDrop.Options.FileName = $ServerSavePath + "\" + $TypeFolder + "\" + $ScriptFile.Replace("]", "").Replace("[", "") + ".sql"
$scriptr.Options.FileName = $ServerSavePath + "\" + $TypeFolder + "\" + $ScriptFile.Replace("]", "").Replace("[", "") + ".sql"
#This is where each object actually gets scripted one at a time.
$ScriptDrop.Script($ScriptThis)
$scriptr.Script($ScriptThis)
} #This ends the object scripting loop at the server level.
#Script database-level objects.
foreach ($db in $databases)
{
$DatabaseObjects = $db.ApplicationRoles
$DatabaseObjects += $db.Assemblies
$DatabaseObjects += $db.ExtendedStoredProcedures
$DatabaseObjects += $db.ExtendedProperties
$DatabaseObjects += $db.PartitionFunctions
$DatabaseObjects += $db.PartitionSchemes
$DatabaseObjects += $db.Roles
$DatabaseObjects += $db.Rules
$DatabaseObjects += $db.Schemas
$DatabaseObjects += $db.StoredProcedures
$DatabaseObjects += $db.Synonyms
$DatabaseObjects += $db.Tables
$DatabaseObjects += $db.Triggers
$DatabaseObjects += $db.UserDefinedAggregates
$DatabaseObjects += $db.UserDefinedDataTypes
$DatabaseObjects += $db.UserDefinedFunctions
$DatabaseObjects += $db.UserDefinedTableTypes
$DatabaseObjects += $db.UserDefinedTypes
$DatabaseObjects += $db.Users
$DatabaseObjects += $db.Views
#Build this portion of the directory structure out here. Remove the existing directory and its contents first.
$DatabaseSavePath = $BaseSavePath + "Databases\" + $db.Name
new-item -type directory -path "$DatabaseSavePath"
foreach ($ScriptThis in $DatabaseObjects | where {!($_.IsSystemObject)})
{
#Need to Add Some mkDirs for the different $Fldr=$ScriptThis.GetType().Name
$scriptr = new-object ('Microsoft.SqlServer.Management.Smo.Scripter') ($SMOserver)
$scriptr.Options.AppendToFile = $True
$scriptr.Options.AllowSystemObjects = $False
$scriptr.Options.ClusteredIndexes = $True
$scriptr.Options.DriAll = $True
$scriptr.Options.ScriptDrops = $False
$scriptr.Options.IncludeHeaders = $False
$scriptr.Options.ToFileOnly = $True
$scriptr.Options.Indexes = $True
$scriptr.Options.Permissions = $True
$scriptr.Options.WithDependencies = $False
<#Script the Drop too#>
$ScriptDrop = new-object ('Microsoft.SqlServer.Management.Smo.Scripter') ($SMOserver)
$ScriptDrop.Options.AppendToFile = $True
$ScriptDrop.Options.AllowSystemObjects = $False
$ScriptDrop.Options.ClusteredIndexes = $True
$ScriptDrop.Options.DriAll = $True
$ScriptDrop.Options.ScriptDrops = $True
$ScriptDrop.Options.IncludeHeaders = $False
$ScriptDrop.Options.ToFileOnly = $True
$ScriptDrop.Options.Indexes = $True
$ScriptDrop.Options.WithDependencies = $False
<#This section builds folder structures. Remove the date folder if you want to overwrite#>
$TypeFolder=$ScriptThis.GetType().Name
if ((Test-Path -Path "$DatabaseSavePath\$TypeFolder") -eq "true") `
{"Scripting Out $TypeFolder $ScriptThis"} `
else {new-item -type directory -name "$TypeFolder"-path "$DatabaseSavePath"}
$ScriptFile = $ScriptThis -replace ":", "-" -replace "\\", "-"
$ScriptDrop.Options.FileName = $DatabaseSavePath + "\" + $TypeFolder + "\" + $ScriptFile.Replace("]", "").Replace("[", "") + ".sql"
$scriptr.Options.FileName = $DatabaseSavePath + "\" + $TypeFolder + "\" + $ScriptFile.Replace("]", "").Replace("[", "") + ".sql"
#This is where each object actually gets scripted one at a time.
$ScriptDrop.Script($ScriptThis)
$scriptr.Script($ScriptThis)
} #This ends the object scripting loop.
} #This ends the database loop.
You have a couple of choices from SMO/Powershell.
1: SQLPS/PowerShell with SQL loaded
SQLSERVER:\SQLPolicy\\DEFAULT\Policies
you can then dig through it, i didnt see an "export" but you can certianly get the info out of it.
2: SMO
basically SMO has a Microsoft.SqlServer.Management.DMF namespace that has severial policy objects (what you end up with in the PowerShell side of things) Policy, PolicyStore, PolicyCondition etc, rather than write out an example, you can find one here.
http://rdbmsexperts.com/Blogs/archives/295
again i didnt see an "export" method anywhere, but you could probably spit out what you needed easily enough.