Add-member giving output with multiple header - powershell

I am having a code which is giving me output like below
ESXi Datastore ReadIOPS WriteIOPS ReadLatency[ms] WriteLatency[ms] ReadRate[KBps] WriteRate[KBps]
---- --------- -------- --------- --------------- ---------------- -------------- ---------------
999_TEST8AP EV_8190 0 1 0 3 0 13
ESXi Datastore ReadIOPS WriteIOPS ReadLatency[ms] WriteLatency[ms] ReadRate[KBps] WriteRate[KBps]
---- --------- -------- --------- --------------- ---------------- -------------- ---------------
999_TANS2AP DEV_8190 0 2 0 1 0 14
I need to write this output in html. please let me know how to display only one header instead of multiple header for each server.
Also please help me with writing this to html. going forward there will be multiple datastore and VM's on which I need to execute this code
This is the code
[CmdletBinding()]
param(
[String]$vcenter=""
)
Begin {
#Ignore invalid certificate
Set-PowerCLIConfiguration -InvalidCertificateAction Ignore -Confirm:$false -Verbose
try {
#Connect to VCSA
Connect-VIServer -Server $vcenter
}
catch {
Write-Host "Incorrect vCenter creds!"
$PSCmdlet.ThrowTerminatingError($PSItem)
}
#Collect list of datastore names
if (-not (test-path -path C:\datastore_list.txt)) {
Disconnect-VIServer $vcenter -Confirm:$false
Write-Error 'The file datastore_list.txt does not exist!' -ErrorAction Stop
}
else {
$list1 = Get-Content C:\datastore_list.txt
}
#Collect list of ESXi servers
if (-not (test-path -path C:\esxi_list.txt)) {
Disconnect-VIServer $vcenter -Confirm:$false
Write-Error 'The file esxi_list.txt does not exist!' -ErrorAction Stop
}
else {
$list2 = Get-Content C:\esxi_list.txt
}
}
Process {
#Function to collect datastore performance stats
Function datastore_perf ($host_name) {
$stat_array =#()
For ($i = 0; $i -lt $list1.count; $i++){
$datastore_name = $list1
if($datastore_name) {
$instance_id = (Get-Datastore $datastore_name).ExtensionData.Info.Vmfs.Uuid
$t1 = Get-Stat -Entity $host_name -Stat datastore.numberReadAveraged.average -MaxSamples 1 -Realtime -Instance $instance_id
$t2 = Get-Stat -Entity $host_name -Stat datastore.numberWriteAveraged.average -MaxSamples 1 -Realtime -Instance $instance_id
$t3 = Get-Stat -Entity $host_name -Stat datastore.totalReadLatency.average -MaxSamples 1 -Realtime -Instance $instance_id
$t4 = Get-Stat -Entity $host_name -Stat datastore.totalWriteLatency.average -MaxSamples 1 -Realtime -Instance $instance_id
$t6 = Get-Stat -Entity $host_name -Stat datastore.read.average -MaxSamples 1 -Realtime -Instance $instance_id
$t7 = Get-Stat -Entity $host_name -Stat datastore.write.average -MaxSamples 1 -Realtime -Instance $instance_id
$stat_object = New-Object System.Object
$read_iops = $t1[0].Value
$write_iops = $t2[0].Value
$read_latency = $t3[0].Value
$write_latency = $t4[0].Value
$read_avg = $t6[0].Value
$write_avg = $t7[0].Value
$stat_object | Add-Member -Type NoteProperty -Name ESXi -Value "$host_name"
$stat_object | Add-Member -Type NoteProperty -Name Datastore -Value "$datastore_name"
$stat_object | Add-Member -Type NoteProperty -Name ReadIOPS -Value "$read_iops"
$stat_object | Add-Member -Type NoteProperty -Name WriteIOPS -Value "$write_iops"
$stat_object | Add-Member -Type NoteProperty -Name ReadLatency[ms] -Value "$read_latency"
$stat_object | Add-Member -Type NoteProperty -Name WriteLatency[ms] -Value "$write_latency"
$stat_object | Add-Member -Type NoteProperty -Name ReadRate[KBps] -Value "$read_avg"
$stat_object | Add-Member -Type NoteProperty -Name WriteRate[KBps] -Value "$write_avg"
$stat_array += $stat_object
}
}
cls
$Header = #"
<style>
TABLE {border-width: 1px; border-style: solid; border-color: black; border-collapse: collapse;}
TH {border-width: 1px; padding: 3px; border-style: solid; border-color: black; background-color: #6495ED;}
TD {border-width: 1px; padding: 3px; border-style: solid; border-color: black;}
</style>
"#
$stat_array | ConvertTo-Html -head $Header | Out-File -FilePath C:\stat_report.html -Append
}
}
}
End {
$result = $list2 | ForEach-Object { datastore_perf -host_name $PSItem }
}
html sample

A few things I would change in your code:
$datastore_name = $list1 --> $datastore_name = $list1[$i]
do not use += to add to an array because this is time and memory costly (on each iteration the entire array needs to be built that way). Instead, have your function simply output a PsCustomObject and gather all in variable $result
join the string array from ConvertTo-Html with newlines and do not use -Append to write the output HTML file
Prefer Set-Content over Out-File, because in PowerShell up to and including version 5.1, the encoding for Out-File is Unicode (UTF16-LE) which is probably not what you want.
Try
[CmdletBinding()]
param(
[String]$vcenter=""
)
Begin {
#Ignore invalid certificate
Set-PowerCLIConfiguration -InvalidCertificateAction Ignore -Confirm:$false -Verbose
try {
#Connect to VCSA
Connect-VIServer -Server $vcenter
}
catch {
Write-Host "Incorrect vCenter creds!"
$PSCmdlet.ThrowTerminatingError($PSItem)
}
#Collect list of datastore names
if (-not (test-path -Path 'C:\datastore_list.txt')) {
Disconnect-VIServer $vcenter -Confirm:$false
Write-Error 'The file datastore_list.txt does not exist!'
}
else {
$list1 = Get-Content -Path 'C:\datastore_list.txt'
}
#Collect list of ESXi servers
if (-not (test-path -path C:\esxi_list.txt)) {
Disconnect-VIServer $vcenter -Confirm:$false
Write-Error 'The file esxi_list.txt does not exist!'
}
else {
$list2 = Get-Content 'C:\esxi_list.txt'
}
}
Process {
#Function to collect datastore performance stats
function datastore_perf ($host_name) {
for ($i = 0; $i -lt $list1.count; $i++){
$datastore_name = $list1[$i]
if($datastore_name) {
$instance_id = (Get-Datastore $datastore_name).ExtensionData.Info.Vmfs.Uuid
$t1 = Get-Stat -Entity $host_name -Stat datastore.numberReadAveraged.average -MaxSamples 1 -Realtime -Instance $instance_id
$t2 = Get-Stat -Entity $host_name -Stat datastore.numberWriteAveraged.average -MaxSamples 1 -Realtime -Instance $instance_id
$t3 = Get-Stat -Entity $host_name -Stat datastore.totalReadLatency.average -MaxSamples 1 -Realtime -Instance $instance_id
$t4 = Get-Stat -Entity $host_name -Stat datastore.totalWriteLatency.average -MaxSamples 1 -Realtime -Instance $instance_id
$t6 = Get-Stat -Entity $host_name -Stat datastore.read.average -MaxSamples 1 -Realtime -Instance $instance_id
$t7 = Get-Stat -Entity $host_name -Stat datastore.write.average -MaxSamples 1 -Realtime -Instance $instance_id
# simply output an object with the properties you need
# this output will be collected below in variable $result
[PsCustomObject]#{
'ESXi' = $host_name
'Datastore' = $datastore_name
'ReadIOPS' = $t1[0].Value
'WriteIOPS' = $t2[0].Value
'ReadLatency[ms]' = $t3[0].Value
'WriteLatency[ms]' = $t4[0].Value
'ReadRate[KBps]' = $t6[0].Value
'WriteRate[KBps]' = $t7[0].Value
}
}
}
}
$result = $list2 | ForEach-Object { datastore_perf -host_name $_ }
$Header = #"
<style>
TABLE {border-width: 1px; border-style: solid; border-color: black; border-collapse: collapse;}
TH {border-width: 1px; padding: 3px; border-style: solid; border-color: black; background-color: #6495ED;}
TD {border-width: 1px; padding: 3px; border-style: solid; border-color: black;}
</style>
"#
# write the HTML file
($result | ConvertTo-Html -Head $Header) -join [environment]::NewLine | Set-Content -Path 'C:\stat_report.html'
}

Related

Powershell - Get-WinEvent - send email with message from Event

I am new in powershell.
I want to get the events from Task Scheduler/Operational with code of failure, and send an email with all events in the body.
# Get all events from yesterday with ID=103 and Text, put in table and send email
# Get the event entries.
$eventEntries = & {Get-WinEvent -FilterHashtable #{ LogName='Microsoft-Windows-TaskScheduler/Operational'; StartTime=(Get-Date).AddDays(-1); ID='103'} |
Where {$_.Message.Contains('Task Scheduler failed to start instance')} |
select -Property ID,TimeCreated,Message |ft -wrap}
# Create a table row for each entry.
$array = #()
foreach ($eventEntry in $eventEntries)
{
$array += $eventEntry
}
$array | Format-table
# Create the email.
$MailFrom = "helpdesk#mydomain.com"
$MailTo = "myemail#mydomain.com"
$Subject = "EventLogAlert"
$email = New-Object System.Net.Mail.MailMessage( $MailFrom , $MailTo )
$email.Subject = $Subject
$email.IsBodyHtml = $true
$email.Body = #"
<table style="width:100%;border">
<tr>
<th style="text-align: center; padding: 5px;">ID</th>
<th style="text-align: center; padding: 5px;">TimeCreated</th>
<th style="text-align: center; padding: 5px;">Message</th>
</tr>
$array
</table>
"#
# Send the email.
$SmtpServer = "smtp.mail.outlook.com"
$SmtpPort = 587
$SmtpUser = "helpdesk#mydomain.com"
$SmtpPassword = "passwordexample"
$SMTPClient=New-Object System.Net.Mail.SmtpClient($SmtpServer,$SmtpPort)
$SMTPClient.EnableSsl=$true
$SMTPClient.Credentials= New-Object System.Net.NetworkCredential($SmtpUser,$SmtpPassword);
$SMTPClient.Send($email)
The $array is created with values in it, can viewed with echo $eventEntries
The result $email is not with values from table, it give this text
Microsoft.PowerShell.Commands.Internal.Format.FormatStartData Microsoft.PowerShell.Commands.Internal.Format.GroupStartData Microsoft.Powershell.Commands.Internal.Format.FormatEntryData Microsoft.PowerShell.Commands.Internal.Format.FormatEntryData Microsoft.PowerShell.Commands.Internal.Format.FormatEntryData Microsoft.PowerShell.Commands.Internal.Format.FormatEntryData Microsoft.PowerShell.Commands.Internal.Format.FormatEntryData Microsoft.PowerShell.Commands.Internal.Format.FormatEntryData Microsoft.PowerShell.Commands.Internal.Format.FormatEntryData Microsoft.PowerShell.Commands.Internal.Format.GroupEndData Microsoft.PowerShell.Commands.Internal.Format.FormatEndData
Can somebody help me to write correct code to view all events in email.
And additionally, to create for each event an email separately.
Thanks in advance!
You should not use Format-Table if you plan on using the data any further, because that cmdlet is only meant for display purposes.
Try the code below:
$yesterday = (Get-Date).AddDays(-1).Date # set to midnight
$filter = #{LogName='Microsoft-Windows-TaskScheduler/Operational'; StartTime=$yesterday; ID='103'}
$events = Get-WinEvent -FilterHashtable $filter -ErrorAction SilentlyContinue |
Where-Object {$_.Message -like '*Task Scheduler failed to start instance*'} |
Select-Object -Property TaskDisplayName,ID,TimeCreated,Message
$style = #'
<style>
body {font-family: Calibri, Tahoma, Helvetica, sans-serif; color: black;}
table {width: 100%; border-width: 1px; border-style: solid; border-color: black; border-collapse: collapse;}
th {text-align: center; padding: 5px; background-color: #6495ED; color: white;}
td {border-width: 1px; padding: 3px; border-style: solid; border-color: black;}
</style>
'#
# to use for both the email as the subject for this email
$subject = 'EventLogAlert {0:yyyy-MM-dd HH:mm:ss}' -f (Get-Date)
# create the email body using the style above for the table
$body = $events | ConvertTo-Html -Head $style -PreContent "<h2>$subject</h2>"
# Create the email.
$MailFrom = "helpdesk#mydomain.com"
$MailTo = "myemail#mydomain.com"
$email = New-Object System.Net.Mail.MailMessage($MailFrom, $MailTo)
$email.Subject = $subject
$email.IsBodyHtml = $true
$email.Body = $body -join [environment]::NewLine
# Send the email.
$SmtpServer = "smtp.mail.outlook.com"
$SmtpPort = 587
$SmtpUser = "helpdesk#mydomain.com"
$SmtpPassword = "passwordexample"
$SMTPClient = New-Object System.Net.Mail.SmtpClient($SmtpServer, $SmtpPort)
$SMTPClient.EnableSsl = $true
$SMTPClient.Credentials = New-Object System.Net.NetworkCredential($SmtpUser, $SmtpPassword);
$SMTPClient.Send($email)
Notes:
I'm using the -like operator rather than the .Contains() string method, because the latter is case-sensitive
I have set yesterda's date to midnight by appending .Date
The styling is all up to you, this is just an example you may or may not like..
We do something similar with a script that sends a weekly count of our Office 365 license allocation to a couple of distribution groups. Perhaps this might help you get your script up and running:
Import-Module AzureAD
$username = "user#tenant.onmicrosoft.com"
$pwd = Get-Content "c:\scripts\LicenseCheckPW.txt" | ConvertTo-SecureString -Key (1..32)
$cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $username, $pwd
Connect-MsolService -Credential $cred
$outarray = #()
foreach($sku in (Get-MsolAccountSku))
{
$name = $sku.AccountSkuID
$partno = $sku.SkuPartNumber
$active = $sku.ActiveUnits
$used = $sku.ConsumedUnits
$remaining = ($sku.ActiveUnits - $sku.ConsumedUnits)
if($active -eq 0)
{
$premaining = 0
}
else
{
$premaining = [math]::Round(100-($sku.ConsumedUnits / $sku.ActiveUnits * 100), 2)
}
$outobj = New-Object Object
$outobj | Add-Member -Type Noteproperty -Name "Name" $name
$outobj | Add-Member -Type Noteproperty -Name "Part No" $partno
$outobj | Add-Member -Type Noteproperty -Name "Active Units" $active
$outobj | Add-Member -Type Noteproperty -Name "Consumed Units" $used
$outobj | Add-Member -Type Noteproperty -Name "Remaining Units" $remaining
$outobj | Add-Member -Type Noteproperty -Name "Percentage Remaining" $premaining
$outarray += $outobj
}
$style = "<head><title>Office365 License Check</title></head><style>"
$style += "BODY{background-color:peachpuff; text-align: center;}"
$style += "TABLE{border-width:1px; border-style: solid; border-color: black; border-collapse: collapse; text-align: center;}"
$style += "TH{border-width: 1px; padding: 5px; border-style: solid; border-color: black; background-color: thistle;}"
$style += "TD{border-width: 1px; padding: 5px; border-style: solid; border-color: black; background-color: palegoldenrod;}"
$style += "</style>"
$body = "<h2>Office365 License Check</h2><p>Output generated: " + (Get-Date -Format D)
$html = ($outarray | ConvertTo-HTML -head $style -body $body)
$server = "smtp.exchange.server.com"
$msg = New-Object Net.Mail.MailMessage
$smtp = New-Object Net.Mail.SmtpClient($server)
$msg.From = "sender#domain.com"
$msg.To.Add("recipientgroup1#domain.com")
$msg.To.Add("managementteam#domain.com")
$msg.Subject = "Corporate O365 License Check"
$msg.Body = $html
$msg.IsBodyHtml = $true
$smtp.Send($msg)

How to collect and send the specific event ID (past 24 hrs) from multiple computers and send as email?

I need to get the email alert with the event ID 4202, 4204, 4206, 4208, 4212 for the past 24 hrs, from multiple servers.
How can I get that using the Powershell like below which is working for a local computer only?
Script:
$HtmlHead = #"
<style>
body {
font-family: Arial;
}
table {
width: 100%;
border-collapse: collapse;
border: 1px solid;
}
th {
background-color: green;
border: 1px solid;
padding: 1px;
}
td {
border: 1px solid;
padding: 1px;
}
</style>
"#
$mailArgs = #{
SmtpServer = 'mail.domain.com'
From = 'SystemAdmin#domain.com'
To = 'Manager#domain.com'
Subject = '{0} DFS report'
Attachments = 'C:\Logs\DFS-Events_{0}.csv'
}
$EventIDs = 4202, 4204, 4206, 4208, 4212
Get-DfsrMember | Select-Object -ExpandProperty ComputerName -Unique | Sort-Object | ForEach-Object {
Write-Host "Processing $($_) ..."
Try
{
$splat = $mailArgs.psobject.Copy()
$splat['Attachments'] = $splat['Attachments'] -f $_
Get-WinEvent -FilterHashTable #{ LogName = 'System'; StartTime = (Get-Date).AddHours(-24); ID = $EventIDs } |
Select-Object -Property TimeCreated, Id, Message |
Sort-Object -Property TimeCreated |
Export-Csv -NoTypeInformation -UseCulture -Path $splat['Attachments']
$splat['Body'] = "$($_) DFS Replication Related Events | ForEach-Object { "$($upTime.$_) $_" })"
}
Catch
{
Write-Error -ErrorRecord $_
$splat['Body'] = "$($_) query failed:`r`n$($_.Exception.Message)"
$splat.Remove('Attachments')
}
# Send the result for each server as email
$splat['Subject'] = $splat['Subject'] -f $_
Send-MailMessage #splat
}
I think you'll just need a second loop to go through all computers.
Change
$ComputerName = Get-DfsrMember | ...
into
$computers = Get-DfsrMember | ...
and then wrap your ForEach ( $LogType in $Logs ) { ... } loop inside another loop like
foreach ( $computerName in $computers ) {
foreach ( $LogType in $Logs ) {
..
}
}
P.S. I like to write lowercase for foreach ($thingy in $collection) {} and use camel-case in $collection | ForEach-Object {} to help visualizing the difference between the two
As per your comment, the results should also be in a HTML table for email.
For that, add BodyAsHtml = $true in your $mailArgs hashtable and Capture the results from the Get-WinEvent call so you can export to CSV and afterwards convert to a nice HTML table.
Your code slighlty adjusted for this:
$HtmlHead = #"
<style>
body {
font-family: Arial;
}
table {
width: 100%;
border-collapse: collapse;
border: 1px solid;
}
th {
background-color: green;
border: 1px solid;
padding: 1px;
}
td {
border: 1px solid;
padding: 1px;
}
</style>
"#
$mailArgs = #{
SmtpServer = 'mail.domain.com'
From = 'SystemAdmin#domain.com'
To = 'Manager#domain.com'
Subject = '{0} DFS report'
Attachments = 'C:\Logs\DFS-Events_{0}.csv'
BodyAsHtml = $true
}
$EventIDs = 4202, 4204, 4206, 4208, 4212
Get-DfsrMember | Select-Object -ExpandProperty ComputerName -Unique | Sort-Object | ForEach-Object {
Write-Host "Processing $($_) ..."
Try
{
$splat = $mailArgs.psobject.Copy()
$splat['Attachments'] = $splat['Attachments'] -f $_
$result = Get-WinEvent -FilterHashTable #{ LogName = 'System'; StartTime = (Get-Date).AddHours(-24); ID = $EventIDs } -ErrorAction Stop |
Select-Object -Property TimeCreated, Id, Message |
Sort-Object -Property TimeCreated
# export to csv file
$result | Export-Csv -NoTypeInformation -UseCulture -Path $splat['Attachments']
# create the HTML body
$splat['Body'] = ($result | ConvertTo-Html -Head $HtmlHead -PreContent "<h3>$($_) DFS Replication Related Events</h3>")
}
Catch
{
Write-Error -ErrorRecord $_
# don't forget you're sending HTML, so use "<br />" instead of "`r`n"
$splat['Body'] = "$($_) query failed:<br />$($_.Exception.Message)"
$splat.Remove('Attachments')
}
# Send the result for each server as email
$splat['Subject'] = $splat['Subject'] -f $_
Send-MailMessage #splat
}

Powershell - Reading CSV File as Individual Lines

I have this powershell script to get some email counts which works fine if I only have one user in the csv file but when I put two or more it reads it all as one line and then I get an invalid SMTP address error. I can't for the life of me figure out how to get it to read each line individually. Could someone take a look at this powershell script and help me out?
############ Start Import the Exchange 2010 modules if available, otherwise import 2007.
if (Get-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010 -Registered -ErrorAction SilentlyContinue) {
Add-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010
} else {
Add-PSSnapin -Name Microsoft.Exchange.Management.PowerShell.Admin
}
############ Start Variables
[Int] $intSent = $intRec = 0
$emails = Get-Content "C:\Test.csv"
$dt = (get-date).adddays(-1)
$tab2 = #()
$tabInfo = #()
############ End variables
############ Start HTML Style
$head = #'
<style>
body { background-color:#FFFFFF;
font-family:Tahoma;
font-size:11pt; }
td, th { border:1px solid black;
border-collapse:collapse;
text-align:center;
background+color:#e0e0e0;
width:300px;}
th { color:#ffffff;
background-color:#20a000;
text-align:center;}
table, tr, td, th { padding: 1px; margin: 0px }
table { margin-left:15px; }
</style>
'#
############ End HTML Style
############ Start retrieve email address + NB sent/received mails
foreach ($i in $emails) {
$intRec = 0 #Number of received mails
$intSent = 0 #Number of sent mails
$intTotalSentInt = 0 #Number of sent internal mails
$intTotalSentExt = 0 #Number of sent external mails
$intTotalRecInt = 0 #Number of received internal mails
$intTotalRecExt = 0 #Number of received external mails
$address = $emails #Email address
$object = new-object Psobject #Create the object
$objectInfo = new-object Psobject #Create the object info
############ Sent mails
Get-TransportService | Get-MessageTrackingLog -ResultSize Unlimited -Start $dt -Sender $emails -EventID RECEIVE | ? {$_.Source -eq "STOREDRIVER"} | ForEach {
If ($_.Recipients -match "domain.com") {
$intTotalSentInt++
}
If ($_.Recipients -notmatch "domain.com") {
$intTotalSentExt++
}
}
############ Received mails
Get-TransportService | Get-MessageTrackingLog -ResultSize Unlimited -Start $dt -Recipients $emails -EventID DELIVER | ForEach {
If ($_.Sender -match "domain.com") {
$intTotalRecInt += [Int] $_.RecipientCount
} Else {
# From an external sender
$intTotalRecExt += [Int] $_.RecipientCount
}
}
############ Insert address + number of sent/received mails
$object | Add-member -Name "User" -Membertype "Noteproperty" -Value $emails
$object | Add-member -Name "Internal Emails Sent" -Membertype "Noteproperty" -Value $IntTotalSentInt
$object | Add-member -Name "External Emails Sent" -Membertype "Noteproperty" -Value $IntTotalSentExt
$object | Add-member -Name "Internal Emails Received" -Membertype "Noteproperty" -Value $intTotalRecInt
$object | Add-member -Name "External Emails Received" -Membertype "Noteproperty" -Value $intTotalRecExt
$tab2 += $object
}
############ Sort by number of sent emails
$tab2 = $tab2 | Sort-Object Sent -descending
############ ConvertTo-HTML
$body = $tabInfo | ConvertTo-HTML -head $head
$body += $tab2 | ConvertTo-HTML -head $head
############ Send emails with results
send-mailmessage -to "email#domain.com" -from "email#domain.com" -subject "Emails Sent and Received from $dt" -body ($body | out-string) -BodyAsHTML -SmtpServer "x.x.x.x"
############ end of Script
Sample CSV file that just contains email addresses
Line 45, inside the foreach ($i in $emails), you're doing $address = $emails which puts the entire list of emails in $address. I assume you meant $address = $i ?
Edit: and I missed the one which is probably the problematic one, line 50, you're passing $emails which is an array whereas -Sender takes a string.

Output to HTML issue

Hello newish to PS and i am having an issue getting the Output data to output.
The HTM file is created but no data, what am I missing here, again im newish!
This is to check TSM backup report and to start service if down.
Here is the script
$serverlist = gc servers.txt
$SvcName = '*tsm*scheduler*'
$filepath = "C:\Scripts\"
$date = "{0:yyy_MM_dd-HH_mm}" -f (get-date)
$file = $filepath + "Results_" + $date + ".htm"
New-Item $filepath -type directory -force -Verbose
$Header = #"
<style>
TABLE {border-width: 1px;border-style: solid;border-color: black;border-collapse: collapse;}
TH {border-width: 1px;padding: 3px;border-style: solid;border-color: black;background-color: #6495ED;}
TD {border-width: 1px;padding: 3px;border-style: solid;border-color: black;}
</style>
<title>
TSM Report
</title>
"#
ForEach ($server in $serverlist)
{
$Tsm = Get-Service -ComputerName $server| Where {$_.name -Like $SvcName}
If ($Tsm.StartType -ne 'Automatic')
{
Set-Service -InputObject $Tsm -StartupType Automatic
}
If ($Tsm.Status -ne 'Running')
{
$output = "Starting the service."
Start-Service -InputObject $Tsm
}
$Tsm2 = Get-Service -ComputerName $SysName | Where {$_.name -Like $SvcName}
}
$pre= "Here are the results for $date"
$Tsm2 | Select-Object DisplayName, Status, StartupType | ConvertTo-HTML -Head $Header -PreContent $pre | Out-File $file
Invoke-Item $file

Convert size value to TeraBytes (TB)

Hello Could someone please take a look at my code and suggest how to convert the following line to TeraBytes.
$totalmbdata = ($allstats | Select-Object 'Archive.Mailbox.Total.GB' | Measure-Object 'Archive.Mailbox.Total.GB' -Sum).Sum
Best Regards
Mike.W
#=====================================
#Get system date and store to variable
#=====================================
$Date = Get-Date -format D
#====================
#Setting up variables
#====================
$allstats = #()
$archivedbstats = #()
#==========================================================
#Set the archive database statistcs variables and grab data
#==========================================================
$arcservers = Get-MailboxServer | Where-Object {$_.Name -like 'Server*' -or $_.Name -like 'Server*'}
$databases = Get-MailboxDatabase UK-ARC-0*
ForEach ($db in $databases){
$numarcs= (Get-MailboxStatistics -Database $db).count
$dbstats = Get-MailboxDatabase -Identity $db -status | Select-Object Name,#{l="dbfilesize";e={"$([math]::round($_.DatabaseSize.Tobytes() /1Gb, 0))"}}`
,#{l="availablespace";E={"$([math]::Round($_.AvailableNewMailboxSpace.ToBytes() /1GB,2))"}}
$archMBsizes = Get-MailboxStatistics -database $db | Select #{l="Size";e={$([math]::Round($_.TotalItemSize.Value.ToBytes() /1GB,0))}} | Measure-Object Size -Sum
[int]$totalbocks = $archMBsizes.Sum /2
#$archMBsizesTB = Get-MailboxStatistics -database $db | Select #{l="SizeTB";e={$([math]::Round($_.TotalItemSize.Value.ToBytes() /1TB,1))}}
#==========================================================================================
#Greate new Object and populate information from variables, add table column names and data
#==========================================================================================
$archivedbstats = New-Object PSObject
$archivedbstats | Add-Member -MemberType 'NoteProperty' -Name 'Database.Name' -Value $db.Name
$archivedbstats | Add-Member -MemberType 'NoteProperty' -Name 'Database.Size.GB' -Value $dbstats.dbfilesize
$archivedbstats | Add-Member -MemberType 'NoteProperty' -Name 'Archive.Mailbox.Total.GB' -Value $archMBsizes.Sum
$archivedbstats | Add-Member -MemberType 'NoteProperty' -Name 'Archive.Count' -Value $archMBsizes.Count
$archivedbstats | Add-Member -MemberType 'NoteProperty' -Name 'Usable.Database.Space.GB' -Value $dbstats.availablespace
$archivedbstats | Add-Member -MemberType 'NoteProperty' -Name 'DB.in.Blocks' -Value $totalbocks
$allstats += $archivedbstats
}
#====================================================
#Sum the total archive data size and save to variable
#====================================================
$totalmbdata = ($allstats | Select-Object 'Archive.Mailbox.Total.GB' | Measure-Object 'Archive.Mailbox.Total.GB' -Sum).Sum
#===============================================================================================================
#Colourize the table cells by passing the HTML file through the function located in the Set-CellColor.ps1 script
#===============================================================================================================
$dbstatshtml = $allstats | ConvertTo-Html -Fragment | Set-CellColor Database.Size.GB -Color red -Filter "Database.Size.GB -eq 550 -or Database.Size.GB -gt 550" -Row
$dbstatshtml = $dbstatshtml | Set-CellColor Database.Size.GB -Color yellow -Filter "Database.Size.GB -eq 400 -or Database.Size.GB -lt 550" -Row
$dbstatshtml = $dbstatshtml | Set-CellColor Database.Size.GB -Color green -Filter "Database.Size.GB -lt 400" -Row
#=============================================
#Formatting HTML page imcluding table and text
#=============================================
$htmlbody = #"
<html>
<head>
<meta http-equiv=Content-Type content="text/html; charset=windows-1252">
<style>
TABLE {
border: 0px solid black;
border-collapse: collapse;
font-family: helvetica;
font-size: 10.5pt;
}
TH {
border: 0px solid black;
background: #dddddd; padding: 5px;
}
TD {
border: 0px solid black;
padding: 5px;
}
/* List Definitions */
ol
{margin-bottom:0cm;}
ul
{margin-bottom:0cm;}
-->
</style>
</head>
<body>
<!-- This is the Company Header image -->
<p class=MsoNormal style='margin-left:4.5pt'>
<a href="https://www.domain.com/">
<span style='color:windowtext'>
<img border=0px width=640 height=69 id="Picture 1" src="cid:HeaderImage" alt="header_white">
</span>
</a>
</br>
<p><b>Total Email data is $totalmbdata GB on the $Date</br>
</br>
<p><b>Legend</br>
<SPAN style="BACKGROUND-COLOR: #FF0000">Do Not create Archive Mailboxes on these databases.</SPAN></br>
<SPAN style="BACKGROUND-COLOR: #FFFF00">Create Achive Mailboxes for users with a total pst size of 3GB or less.</SPAN></br>
<SPAN style="BACKGROUND-COLOR: #008000">Create Archive Mailboxes for users with a total pst size greater than 3GB and up to 5GB.</SPAN></br>
For PST totals over 5GB please contact the IT Team</br>
</br>
</p>
$dbstatshtml
</body>
</html>
"#
#===============================================
#Configure email settings build and send message
#===============================================
$smtpServer = "smtpfor.domain.local.com"
$recipients = "user#domain.local.com, suser#domain.local.com"
$msg = New-Object Net.Mail.MailMessage
$smtp = New-Object Net.Mail.SmtpClient($smtpServer)
$msg.From = "user#domain.local.com"
$msg.IsBodyHTML = $true
$msg.Subject = $Subject
$msg.Body = $htmlbody
$msg.to.add($recipients)
$HeaderImage = "C:\Scripts\Images\Header.png"
$att1 = New-Object Net.Mail.Attachment($HeaderImage)
$att1.ContentType.MediaType = "image/png"
$att1.ContentId = "HeaderImage"
$msg.Attachments.Add($att1)
$smtp.Send($msg)
#====================End=========================
Since you're already collecting it in GB (tip: don't convert to GB, TB, etc. until the point where you're going to display to a user), divide the number of GB by 1024 to get the number of TB.
$totalmbdata = (($allstats | Select-Object 'Archive.Mailbox.Total.GB' | Measure-Object 'Archive.Mailbox.Total.GB' -Sum).Sum) / 1024;
However, it would be much better to sum up the raw number of bytes earlier in the script (don't convert to GB), and then just divide by 1TB when you get to this point. Each time you do this conversion mid-stream, you lose some fidelity.
Also (and this is unsolicited advice), at the end where you're using Net.Mail.SmtpClient - use Send-Mailmessage instead. You've got PowerShell v3 and it's been available since v2.