Include output from Write-Output in an email? - powershell

Write-Output $details gives the output as a table, I want that output in my email, but when I add it to body part it throws me an error:
Cannot validate argument on parameter 'Body'. The argument is null or empty. Provide an argument that is not null or empty, and then try the command again
$date = Get-Date -DisplayHint Date -UFormat "%d/%m/%Y"
$time = Get-Date -DisplayHint Time
$ThresholdFileCount = 1
$smtp = "address"
$to = "ok#mail.com"
$from = "abc#def.com"
$subject = "Number of files is above threshold - $date"
$style = "<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>"
function filecount {
param ([string]$path)
$body += "<body style='font-family: Cambria; font-size: 16pt;'><b><u><a
name='Monitor'>Monitor</a></u></b></body><br>"
if (-not (Test-Path $path)) {Throw "Path: $path not found"}
$count = 0
$count = Get-ChildItem -Path $path | where {!$_.PSIsContainer} | Measure-
Object | select -ExpandProperty count
if ($count -gt $ThresholdFileCount) {
$details = Get-Item -Path $path| Select-Object PSDrive, #{N = "Parent"; E =
{($_.PSParentPath -split "FileSystem::")[1]}
}, Name, #{N = "FileCount"; E =
{$count}
}
$body += $details |ConvertTo-Html
Write-Output $details
}
}
Send-MailMessage -FROM $from -To $to -Subject $subject -Body $body BodyAsHtml -Priority High -SmtpServer $smtp
filecount "address"

Related

HTML error with creating VM snapshot report to email it to my self

I got the below PS script Idea online to create a VM Snapshot report and email it to myself every morning, once I run the script it will get the below error message, can someone help me with that? Thanks
#Variables
$vCenter = "qwe-2019.wer.com"
$vCenterUser = "wer\adm-myuser"
$vCenterPass = "balabala"
$SMTPServer = "***********.com"
$To = "************.com"
$From = "***********.com"
#HTML formatting
$style = "BODY{font-family: Arial; font-size: 10pt;}" $style = $style + "TABLE{border: 1px solid red; border-collapse: collapse;}" $style = $style + "TH{border: 1px solid; background-color: #4CAF50; color: white; padding: 5px; }" $style = $style + "TD{border: 1px solid; padding: 5px; }" $style = $style + ""
$date = Get-Date -Format "dddd dd/MM/yyyy HH:mm K"
#Connect to vCenter"
CLS
Write-Host "Connecting to $vCenter" -ForegroundColor Blue
Connect-VIServer -Server $vCenter -User $vCenterUser -Password $vCenterPass -Force | Out-Null
Write-Host " Connected to $vCenter" -ForegroundColor Green
#Get list of VMs with snapshots
Write-Host "Generating VM snapshot report" -ForegroundColor Blue
$SnapshotReport = Get-vm | Get-Snapshot | Select-Object VM,Description,PowerState,SizeGB | Sort-Object SizeGB | ConvertTo-Html -Head $style | Out-String
Write-Host " Completed" -ForegroundColor Green
#Sending email report
Write-Host "Sending VM snapshot report" -ForegroundColor Blue
$htmlbody = #"
$SnapshotReport
"#
Send-MailMessage -smtpserver $SMTPServer -From $From -To $To -Subject "Snapshot Email Report for $Date" -BodyAsHtml -Body $htmlbody
Write-Host " Completed" -ForegroundColor Green
#Disconnecting vCenter
Disconnect-VIServer -Server $vCenter -Force -Confirm:$false
Write-Host "Disconnecting to $vCenter" -ForegroundColor Blue
**Error message from #HTML formatting section is **
At line:10 char:55
+ $style = "BODY{font-family: Arial; font-size: 10pt;}" $style = $style ...
+ ~~~~~~
Unexpected token '$style' in expression or statement.
At line:10 char:132
+ ... LE{border: 1px solid red; border-collapse: collapse;}" $style = $styl ...
+ ~~~~~~
Unexpected token '$style' in expression or statement.
At line:10 char:231
+ ... kground-color: #4CAF50; color: white; padding: 5px; }" $style = $styl ...
+ ~~~~~~
Unexpected token '$style' in expression or statement.
At line:10 char:289
+ ... yle = $style + "TD{border: 1px solid; padding: 5px; }" $style = $styl ...
+ ~~~~~~
Unexpected token '$style' in expression or statement.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : UnexpectedToken
As commented, use a Here-String to create the style part of the Html.
Also, don't forget to enclose it in <style>..</style> tags.
Then for cmdlets like Send-MailMessage that potentially take a lot of parameters, I would use Splatting
$style = #'
<style>
body {font-family: Arial; font-size: 10pt;}
table {border: 1px solid red; border-collapse: collapse;}
th {border: 1px solid; background-color: #4CAF50; color: white; padding: 5px;}
td {border: 1px solid; padding: 5px;}
</style>
'#
$SnapshotReport = Get-Vm | Get-Snapshot | Select-Object VM,Description,PowerState,SizeGB |
Sort-Object SizeGB | ConvertTo-Html -Head $style | Out-String
#Sending email report
Write-Host "Sending VM snapshot report" -ForegroundColor Blue
# code is nicer/better maintainable if you use splatting
$params = #{
SmtpServer = $SMTPServer
From = $From
To = $To
Subject = "Snapshot Email Report for $Date"
Body = $SnapshotReport
BodyAsHtml = $true
# more parameters can go here
}
Send-MailMessage #params
Write-Host " Completed" -ForegroundColor Green

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)

Powershell HTML body converting issue

I have a script that reads a list on a Sharepoint 2019 OnPremise site. The idea is to capture certifcates that are about to expire.
Problem is I can't conver it properly to a html-table however I do. I done converting before but not in PNP and with camel querys.
Script:
$smtpserver = "-"
$mailsender ="-"
$mailReceiver = "-"
$mailSubject = "Certificates about to expire"
$Header = #"
<style>
TABLE {border-width: 1px; border-style: solid; border-color: black; border-collapse: collapse;}
TD {border-width: 1px; padding: 3px; border-style: solid; border-color: black;}
</style>
"#
Import-Module "C:\PNP\SharePointPnPPowerShell2019\3.6.1902.2\SharePointPnPPowerShell2019.psd1"
if ($cred -eq $null)
{
$cred = Get-Credential
}
Connect-PnPOnline "-" -Credentials $cred
$list = Get-PnPList "-"
$listitems = Get-PnPListItem -List $list -Query "<View><Query><Where><Lt><FieldRef Name='Utg_x00e5_r' Type='DateTime'/><Value Type='DateTime'><Today OffsetDays='60'/></Value></Lt></Where></Query></View>" | Select-object {$_["Title"], $_["Farm"], $_["Server"] , $_["Utg_x00e5_r"]} | ConvertTo-Html -Head $header | Out-String
Send-MailMessage -From $mailsender -to $mailReceiver -subject $mailSubject -body ($listitems | Out-String) -SmtpServer $smtpServer -Port 25 -BodyAsHtml
What am I missing?
The Select-Object statement currently creates objects with only 1 property, hence the single column in your output.
Change it to something like:
...| Select-Object #{Name='Title';Expression={$_["Title"]}},#{Name='Farm';Expression={$_["Farm"]}},#{Name='Server';Expression={$_["Server"]}},#{Name='Utg_x00e5_r';Expression={$_["Utg_x00e5_r"]}} |ConvertTo-Html ...
... which will create objects with 4 separate properties, which will in turn translate into a 4-column HTML table

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
}

Outputting DHCP script into body of email

I have asked a question similar to the one I'm about to post. I tried using the solution to create my own version but I've had no success. I have the below script that I have found on another website and it's perfect for what I'm looking for, but rather the output be sent in as the body of the email rather than output to a file. How would I go about doing it? Also if anyone has the patience to explain a little It would be greatly appreciated :).
$a = (netsh dhcp server 172.20.102.1 scope 172.20.104.0 show clients 1)
$lines = #()
foreach ($i in $a){
if ($i -match "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"){
If ($i -match "[0-9a-f]{2}[:-][0-9a-f]{2}[:-][0-9a-f]{2}[:-][0-9a-f]{2}[:-][0-9a-f]{2}[:-][0-9a-f]{2}"){
$lines += $i.Trim()
}
}
}
$csvfile = #()
foreach ($l in $lines){
$Row = "" | select Hostname,IP
$l = $l -replace '[0-9a-f]{2}[:-][0-9a-f]{2}[:-][0-9a-f]{2}[:-][0-9a-f]{2}[:-][0-9a-f]{2}[:-][0-9a-f]{2}', ''
$l = $l -replace ' - ',','
$l = $l -replace '\s{4,}',''
$l = $l -replace '--','-'
$l = $l -replace '-D-','-'
$l = $l -replace '[-]{1}\d{1,2}[/]\d{1,2}[/]\d{4}',''
$l = $l -replace '\d{1,2}[:]\d{2}[:]\d{2}',''
$l = $l -replace 'AM',''
$l = $l -replace 'PM',''
$l = $l -replace '\s{1}',''
$l = $l + "`n"
$l = $l -replace '[,][-]',','
$Row.IP = ($l.Split(","))[0]
#Subnet mask not used, but maybe later
#$Row.SubNetMask = ($l.Split(","))[1]
$Row.Hostname = ($l.Split(","))[2]
$csvfile += $Row
}
$csvfile | sort-object Hostname | Export-Csv "Out_List.csv"
$a = "<style>"
$a = $a + "body {margin: 10px; width: 600px; font-family:arial; font-size: 12px;}"
$a = $a + "TABLE{border-width: 1px;border-style: solid;border-color: black;border-collapse: collapse;}"
$a = $a + "TH{border-width: 1px;padding: 2px;border-style: solid;border-color: black;background-color: rgb(179,179,179);align='left';}"
$a = $a + "TD{border-width: 1px;padding: 2px;border-style: solid;border-color: black;background-color: white;}"
$a = $a + "</style>"
$html = $csvfile | sort-object Hostname | ConvertTo-HTML | out-string
Send-MailMessage -SmtpServer "exchange" -Body $html -BodyAsHtml -From "DHCP#.com.au" -To "#.com.au" -Subject "DHCP Report"
Thanks in advance,
Daniel
As an addition to #Tim's answer:
you can even add CSS to the converted html like this :
$style = #"
<style>
table {
width: 50%;
margin: auto;
border-collapse: collapse;
}
th, td {
text-align: left;
padding: 8px;
border-bottom: 1px solid #fff;
}
tr:nth-child(even){background-color: #f2f2f2}
th {
background-color: #4CAF50;
color: white;
}
</style>
"#
$html =import-Csv "Out_List.csv" |ConvertTo-Html -head $style |out-string
Could you try:
$html = $csvfile | sort-object Hostname | ConvertTo-HTML | out-string
Send-MailMessage -SmtpServer "mail server" -Body $html -BodyAsHtml -From "noreply#mailserver.com.au" -To "me#mailserver.com" -Subject "DHCP Report"
Thanks, Tim.