Hello the following is related to this email but I am stuck in rounding the numbers
Powershell/PowerCLI Dynamic Email Message Body
I am getting an email with the following info:
Datastore HealthCheck vCenter
Datastore Space Available
Datastore UsedGB Free GB Perc Free
name1 273.30078125 274.25 99%
name2 273.30078125 274.25 99%
name3 268.466796875 274.25 99%
name4 273.30078125 274.25 99%
Three things that I am stuck: First, the UsedGB value, woud like to have it with only two decimal points, instead of having 273.30078125, nice to have 273.30. Second I am not getting the right percentage. Third: How do i sort the the Perf Free values from the lowest to the bigger percentage? Thanks for your help
Code:
$msg.Subject = "vCenter Datastore Health CompanyvCenter" |
#Here configure your paraneters
$SMTPServer = "Exchange"
$MailSubject = "vCenter Datastore Health CompanyvCenter"
$Email = "Enter@yourmail.com"
function Set-AlternatingCSSClasses {
param(
[string]$HTMLFragment,
[string]$CSSEvenClass,
[string]$CssOddClass
)
[xml]$xml = $HTMLFragment
$table = $xml.SelectSingleNode('table')
$classname = $CSSOddClass
foreach ($tr in $table.tr) {
if ($classname -eq $CSSEvenClass) { $classname = $CssOddClass }
else { $classname = $CSSEvenClass }
$class = $xml.CreateAttribute('class')
$class.value = $classname
$tr.attributes.append($class) | Out-null
}
$xml.innerxml | out-string
}
Function Report-Datastore {
$output = @()
Get-Datastore | % {
$props = [ordered]@{'Name'=$_.Name;
'UsedSpace'=[math]::Round(($_.CapacityGB - $_.FreeSpaceGB),2);
'PercFree'=[math]::Round((100 * ($_.FreeSpaceGB/$_.CapacityGB)),0)}
$output += New-Object -TypeName PSCUstomObject -Property $props
}
$output
}
$style = @"
<style>
body {
color:#333333;
font-family:Calibri,Tahoma;
font-size: 10pt;
}
h1 {
text-align:center;
}
h2 {
border-top:1px solid #666666;
}
th {
font-weight:bold;
color:#eeeeee;
background-color:#333333;
}
.odd { background-color:#ffffff; }
.even { background-color:#dddddd; }
</style>
"@
#Connect to Vcenter
Connect-VIServer $vcserver
# Trnasform the Object in HTML code
$html_DS = Report-Datastore |
Sort-Object PercFree |
ConvertTo-HTML -Fragment |
Out-String |
Set-AlternatingCSSClasses -CSSEvenClass 'even' -CssOddClass 'odd'
$html_DS = "<h2>Datastores</h2>$html_DS"
$params = @{'Head'="<title>vCenter Datastore Health CompanyvCenter</title>$style";
'PreContent'="<h1>Datastore HealthCheck CompanyvCenter</h1>";
'PostContent'=$html_DS}
# Send email
Send-MailMessage -To $Email -Subject $MailSubject -BodyAsHtml -Body (ConvertTo-HTML @params) -SmtpServer $SMTPServer
# DIsconnect Vcenter
Disconnect-VIServer $vcserver -Confirm:$false
You can try this..; i can't test it at home, but it should work without few minors modifications
function Set-AlternatingCSSClasses {
param(
[string]$HTMLFragment,
[string]$CSSEvenClass,
[string]$CssOddClass
)
[xml]$xml = $HTMLFragment
$table = $xml.SelectSingleNode('table')
$classname = $CSSOddClass
foreach ($tr in $table.tr) {
if ($classname -eq $CSSEvenClass) {
$classname = $CssOddClass
} else {
$classname = $CSSEvenClass
}
$class = $xml.CreateAttribute('class')
$class.value = $classname
$tr.attributes.append($class) | Out-null
}
$xml.innerxml | out-string
}
Function Report-Datastore {
$output = @()
Get-Datastore | % {
# | Select-Object -ExpandProperty Name
# $array1 += Get-Datastore | Select-Object -ExpandProperty FreeSpaceGB
# $array2 += Get-Datastore | Select-Object -ExpandProperty CapacityGB
$props = [ordered]@{'Name'=$_.Name;
'UsedSpace'=[math]::Round(($_.CapacityGB - $_.FreeSpaceGB),2);
'PercFree'=[math]::Round((100 * ($_.FreeSpaceGB/$_.CapacityGB)),0)}
$output += New-Object -TypeName PSCUstomObject -Property $props
}
$output
}
$msg.Subject = "vCenter Datastore Health CompanyvCenter"
$style = @"
<style>
body {
color:#333333;
font-family:Calibri,Tahoma;
font-size: 10pt;
}
h1 {
text-align:center;
}
h2 {
border-top:1px solid #666666;
}
th {
font-weight:bold;
color:#eeeeee;
background-color:#333333;
}
.odd { background-color:#ffffff; }
.even { background-color:#dddddd; }
</style>
"@
Connect-VIServer $vcserver
$html_DS = Report-Datastore |
Sort-Object PercFree |
ConvertTo-HTML -Fragment |
Out-String |
Set-AlternatingCSSClasses -CSSEvenClass 'even' -CssOddClass 'odd'
$html_DS = "<h2>Datastores</h2>$html_DS"
$params = @{'Head'="<title>vCenter Datastore Health CompanyvCenter</title>$style";
'PreContent'="<h1>Datastore HealthCheck CompanyvCenter</h1>";
'PostContent'=$html_DS}
$msg.Body = ConvertTo-HTML @params
$msg.Attachments.Add($att1)
$msg.IsBodyHTML = $true
$smtp.Send($msg)
$att1.Dispose()
Disconnect-VIServer $vcserver -Confirm:$false
Fabien,
Thank you very much. But, i am getting the following error:
The string starting:
At C:\scripts\VMware\DatastoreCheck.ps1:34 char:14
+ $style = <<<< @"
is missing the terminator: "@.
At C:\scripts\VMware\DatastoreCheck.ps1:67 char:1
+ <<<<
+ CategoryInfo : ParserError: ( <style>
body...onfirm:$false
:String) [], ParseException
+ FullyQualifiedErrorId : TerminatorExpectedAtEndOfString
The "@ has to be at the very start of the line in order to work
here is a version without CSS...
Function Report-Datastore {
$output = @()
Get-Datastore | % {
$props = [ordered]@{'Name'=$_.Name;
'UsedSpace'=[math]::Round(($_.CapacityGB - $_.FreeSpaceGB),2);
'PercFree'=[math]::Round((100 * ($_.FreeSpaceGB/$_.CapacityGB)),0)}
$output += New-Object -TypeName PSCUstomObject -Property $props
}
$output
}
$msg.Subject = "vCenter Datastore Health CompanyvCenter"
Connect-VIServer $vcserver
$html_DS = Report-Datastore |
Sort-Object PercFree |
ConvertTo-HTML -Fragment |
Out-String
$html_DS = "<h2>Datastores</h2>$html_DS"
$params = @{'Head'="<title>vCenter Datastore Health CompanyvCenter</title>";
'PreContent'="<h1>Datastore HealthCheck CompanyvCenter</h1>";
'PostContent'=$html_DS}
$msg.Body = ConvertTo-HTML @params
$msg.Attachments.Add($att1)
$msg.IsBodyHTML = $true
$smtp.Send($msg)
$att1.Dispose()
Disconnect-VIServer $vcserver -Confirm:$false
nada...I got the following:
Property 'Subject' cannot be found on this object; make sure it exists and is settable.
At C:\scripts\VMware\DatastoreCheck.ps1:35 char:6
+ $msg. <<<< Subject = "vCenter Datastore Health CompanyvCenter"
+ CategoryInfo : InvalidOperation: (Subject:String) [], RuntimeException
+ FullyQualifiedErrorId : PropertyNotFound
and bunch of messages like the following:
Unable to find type [ordered]: make sure that the assembly containing this type is loaded.
At C:\scripts\VMware\DatastoreCheck.ps1:17 char:27
+ $props = [ordered] <<<< @{'Name'=$_.Name;
+ CategoryInfo : InvalidOperation: (ordered:String) [], RuntimeException
+ FullyQualifiedErrorId : TypeNotFound
New-Object : Cannot validate argument on parameter 'Property'. The argument is null or empty. Supply an argument that is not null or empty and then try the command again.
At C:\scripts\VMware\DatastoreCheck.ps1:23 char:65
+ $output += New-Object -TypeName PSCUstomObject -Property <<<< $props
+ CategoryInfo : InvalidData: (:) [New-Object], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.NewObjectCommand
The property subject was the one you used before... i can't do anything about it. Remove [ordered] in the script, it seems you don't have powershell v3 😉
I fix the Subject think. And, I think I do have powershell v3. How do i know ?
You don't have, [ordered] is a new hastable format 😉 In PowerShell console user $PSVersionTable to know you version 😉
You were right. I just installed 3.
Name | Value |
---- | ----- |
WSManStackVersion | 3.0 |
PSCompatibleVersions | {1.0, 2.0, 3.0} |
SerializationVersion | 1.1.0.1 |
BuildVersion | 6.2.9200.16398 |
PSVersion | 3.0 |
CLRVersion | 4.0.30319.1 |
PSRemotingProtocolVersion | 2.2 |
Now I got the following errors: Exception calling "Add" with "1" argument(s): "Value cannot be null. Parameter name: item" At C:\scripts\VMware\DatastoreCheck.ps1:74 char:1 + $msg.Attachments.Add($att1) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [], MethodInvocationException + FullyQualifiedErrorId : ArgumentNullException You cannot call a method on a null-valued expression. At C:\scripts\VMware\DatastoreCheck.ps1:78 char:1 + $smtp.Send($msg) + ~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (:) [], RuntimeException + FullyQualifiedErrorId : InvokeMethodOnNull
it's your mail sender which is fucked. I presumed you had a working script bu i bet no. You should take a look look at Send-MailMessage
Send-MailMessage -To <yourmail> -Subject <yoursbuject> -Body (ConvertTo-HTML @params) -BodyAsHtml -SmtpServer <Your_SMTP_Server>
But ar first you should learn to use PowerShell/PowerCLi bascis in order to understand better your problems, the variable $msg isn't declared or builded anywhere in your script !
Hmm, this is what I have:
clear-host
$vcserver = "vcenter"
$mailto = "Me"
$SMTPServer = "exchange"
$msg = new-object Net.Mail.MailMessage
Function Report-Datastore {
$output = @()
Get-Datastore | % {
$props = [ordered]@{'Name'=$_.Name;
'UsedSpace'=[math]::Round(($_.CapacityGB - $_.FreeSpaceGB),2);
'PercFree'=[math]::Round((100 * ($_.FreeSpaceGB/$_.CapacityGB)),0)}
$output += New-Object -TypeName PSCUstomObject -Property $props
}
$output
}
$msg.Subject = "vCenter Datastore Health CompanyvCenter"
Connect-VIServer $vcserver
$html_DS = Report-Datastore |
Sort-Object PercFree |
ConvertTo-HTML -Fragment |
Out-String
$html_DS = "<h2>Datastores</h2>$html_DS"
$params = @{'Head'="<title>vCenter Datastore Health CompanyvCenter</title>";
'PreContent'="<h1>Datastore HealthCheck CompanyvCenter</h1>";
'PostContent'=$html_DS}
$msg.Body = ConvertTo-HTML @params
#$msg.Attachments.Add($att1)
$msg.IsBodyHTML = $true
$smtp.Send($msg)
#$att1.Dispose()
Disconnect-VIServer $vcserver -Confirm:$false
Got the following error:
You cannot call a method on a null-valued expression.
At C:\scripts\VMware\DatastoreCheck.ps1:31 char:1
+ $smtp.Send($msg)
+ ~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
You use the $msg variable to build your .NET mail send object -> $msg = new-object Net.Mail.MailMessage Your declare the object with a wrong "method" This is more something like $emailFrom = somemail@bloh.com # $smtp.Send($msg) Before using this you have to declare this object $emailSmtpServer = "exchange" $emailSmtpServerPort = "587" $SMTP= New-Object System.Net.Mail.SmtpClient( $emailSmtpServer , $emailSmtpServerPort ) And if there are credentials required... $emailSmtpUser = "username" $emailSmtpPass = "password" $SMTPClient.Credentials = New-Object System.Net.NetworkCredential( $emailSmtpUser , $emailSmtpPass );
Hmm, I think I am lost in space. Now, I have the following:
Property 'Subject' cannot be found on this object; make sure it exists and is settable.
At C:\scripts\VMware\DatastoreCheck.ps1:17 char:1
+ $msg.Subject = "vCenter Datastore Health CompanyvCenter"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : PropertyAssignmentException
Name Port User
---- ---- ----
vcenter.company.com 443 domain\domainadmin
Property 'Body' cannot be found on this object; make sure it exists and is settable.
At C:\scripts\VMware\DatastoreCheck.ps1:29 char:1
+ $msg.Body = ConvertTo-HTML @params
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : PropertyAssignmentException
Property 'IsBodyHTML' cannot be found on this object; make sure it exists and is settable.
At C:\scripts\VMware\DatastoreCheck.ps1:31 char:1
+ $msg.IsBodyHTML = $true
+ ~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : PropertyAssignmentException
You cannot call a method on a null-valued expression.
At C:\scripts\VMware\DatastoreCheck.ps1:32 char:1
+ $smtp.Send($msg)
+ ~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
I'll make a complet working script tomorrow at work 😉
Thank you sir. I will really appreciate.
#Here configure your paraneters
$SMTPServer = "Exchange"
$MailSubject = "vCenter Datastore Health CompanyvCenter"
$Email = "Enter@yourmail.com"
function Set-AlternatingCSSClasses {
param(
[string]$HTMLFragment,
[string]$CSSEvenClass,
[string]$CssOddClass
)
[xml]$xml = $HTMLFragment
$table = $xml.SelectSingleNode('table')
$classname = $CSSOddClass
foreach ($tr in $table.tr) {
if ($classname -eq $CSSEvenClass) { $classname = $CssOddClass }
else { $classname = $CSSEvenClass }
$class = $xml.CreateAttribute('class')
$class.value = $classname
$tr.attributes.append($class) | Out-null
}
$xml.innerxml | out-string
}
Function Report-Datastore {
$output = @()
Get-Datastore | % {
$props = [ordered]@{'Name'=$_.Name;
'UsedSpace'=[math]::Round(($_.CapacityGB - $_.FreeSpaceGB),2);
'PercFree'=[math]::Round((100 * ($_.FreeSpaceGB/$_.CapacityGB)),0)}
$output += New-Object -TypeName PSCUstomObject -Property $props
}
$output
}
$style = @"
<style>
body {
color:#333333;
font-family:Calibri,Tahoma;
font-size: 10pt;
}
h1 {
text-align:center;
}
h2 {
border-top:1px solid #666666;
}
th {
font-weight:bold;
color:#eeeeee;
background-color:#333333;
}
.odd { background-color:#ffffff; }
.even { background-color:#dddddd; }
</style>
"@
#Connect to Vcenter
Connect-VIServer $vcserver
# Trnasform the Object in HTML code
$html_DS = Report-Datastore |
Sort-Object PercFree |
ConvertTo-HTML -Fragment |
Out-String |
Set-AlternatingCSSClasses -CSSEvenClass 'even' -CssOddClass 'odd'
$html_DS = "<h2>Datastores</h2>$html_DS"
$params = @{'Head'="<title>vCenter Datastore Health CompanyvCenter</title>$style";
'PreContent'="<h1>Datastore HealthCheck CompanyvCenter</h1>";
'PostContent'=$html_DS}
# Send email
Send-MailMessage -To $Email -Subject $MailSubject -BodyAsHtml -Body (ConvertTo-HTML @params) -SmtpServer $SMTPServer
# DIsconnect Vcenter
Disconnect-VIServer $vcserver -Confirm:$false
Got the following:
Send-MailMessage : Cannot convert 'System.Object[]' to the type 'System.String' required by parameter 'Body'. Specified method is not supported.
At C:\scripts\VMware\DatastoreCheck.ps1:76 char:69
+ Send-MailMessage -To $Email -Subject $MailSubject -BodyAsHtml -Body (ConvertTo-H ...
+ ~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Send-MailMessage], ParameterBindingException
+ FullyQualifiedErrorId : CannotConvertArgument,Microsoft.PowerShell.Commands.SendMailMessage
Send-MailMessage : Cannot convert 'System.Object[]' to the type 'System.String' required by parameter 'Body'. Specified method is not supported.
My bad i did'tn check the variable type used by -Body parameter...
Replace the Send mail part by this one, it should work (but not tested)
# Send email
$MailBody = ConvertTo-HTML @params | Out-String
$ReportingMail = "esx@lab.local"
Send-MailMessage -To $Email -From $ReportingMail -Subject $MailSubject -BodyAsHtml -Body $MailBody -SmtpServer $SMTPServer
Amost but nada
I will check, but did you try by yourself to understand the script and find where is the error ?