Powershell HTML body converting issue - powershell

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

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)

How to display server name and ping result only from powershell script in html web page

I am trying to create the script for checking if the servers are online, which will be displayed as HTML web page using "ConvertTo-Html" property. I also applied some small CSS into it.
Here is my code:
$Header = #"
<style>
table {
font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;
border-collapse: collapse;
width: 100%;
}
th {
padding-top: 12px;
padding-bottom: 12px;
text-align: left;
background-color: green;
color: white;
}
</style>
"#
$OS = Test-Connection -ComputerName Server1, Server2, Server3 | ConvertTo-Html
ConvertTo-Html -Body "$OS" -Title "Fragment" -Head $Header | Out-File StatusReport.html
Output result in the file "StatusReport.html" shows too much unnecessary information (photo attached). How can I display only few of them: Server name, ping result?
Ass Lee commented, you'll need to select the properties you want from the output. There are quite a few properties but none of them are Server or result.
To see a list of the properties, pipe the output to Get-Member
Test-Connection google.com -count 1 | Get-Member
You can also use Format-List * to see the properties and values
Test-Connection google.com -count 1 | Format-List *
Once you know the properties you're after you can select them by name
Test-Connection google.com -count 1 | Select-Object Address,IPv4Address,StatusCode
If you want to rename the properties, you can use calculated properties
Test-Connection google.com -count 1 |
Select-Object #{n='Server';e={$_.Address}},IPv4Address,#{n='Result';e={'Successful'}}
However this does not account for any failed ping results. Here's a bit of code that will gather the successes and failures, then combine the two. Note that the property names need to match.
$targets = 'server1', 'server2', 'server3', 'dontexist'
$success = Test-Connection -ComputerName $targets -Count 1 -ErrorAction SilentlyContinue -ErrorVariable errors |
Select-Object #{n='Server';e={$_.address}},IPv4Address,#{n='Result';e={'Successful'}}
$failed = $errors.exception.message |
Where-Object {$_ -match "computer '(.+?)'"} |
Select-Object #{n='Server';e={$matches.1}},
#{n='IPv4Address';e={"N/A"}},
#{n='Result';e={'Failed'}}
$success + $failed
You can use splatting to make the code easier to read and maintain.
$params = #{
ComputerName = 'server1', 'server2', 'server3', 'dontexist'
Count = 1
ErrorAction = 'SilentlyContinue'
ErrorVariable = 'errors'
}
$success = Test-Connection #params |
Select-Object #{n='Server';e={$_.address}},
IPv4Address,
#{n='Result';e={'Successful'}}
$failed = $errors.exception.message |
Where-Object {$_ -match "computer '(.+?)'"} |
Select-Object #{n='Server';e={$matches.1}},
#{n='IPv4Address';e={"N/A"}},
#{n='Result';e={'Failed'}}
$success + $failed
Combining this with a slightly modified version of your code we end up with this as the final script.
$Header = #"
<style>
table {
font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;
border-collapse: collapse;
width: 100%;
}
th {
padding-top: 12px;
padding-bottom: 12px;
text-align: left;
background-color: green;
color: white;
}
</style>
"#
$params = #{
ComputerName = 'server1', 'server2', 'server3', 'dontexist'
Count = 1
ErrorAction = 'SilentlyContinue'
ErrorVariable = 'errors'
}
$success = Test-Connection #params |
Select-Object #{n='Server';e={$_.address}},
IPv4Address,
#{n='Result';e={'Successful'}}
$failed = $errors.exception.message |
Where-Object {$_ -match "computer '(.+?)'"} |
Select-Object #{n='Server';e={$matches.1}},
#{n='IPv4Address';e={"N/A"}},
#{n='Result';e={'Failed'}}
$success + $failed |
ConvertTo-Html -Title "Fragment" -Head $Header |
Set-Content -Path StatusReport.html -Encoding UTF8

Include output from Write-Output in an email?

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"

Powershell email output not formatting correctly

I have spent the last few hours trying various ways to solve my problem below, adding parts from other working scripts that I have and researching on here, yet have reached the point where I need a fresh set of eyes to point the obvious out to me.
This is my script, which does the following:
Lists all folders in a certain location, puts the folder paths in a text file
In a loop, uses the text file to check the most recent file in each folder, then output the most recent 10 timestamps (denoted by '[')
Emails the results
All of the above works, I have the email with the correct information. The problem is that the email arrives all on the same line with no formatting.
I've taken my style tags from a previous working script that I had, so I'm not sure where I've gone wrong. Any ideas?
$style = "<style>BODY{font-family: Arial; font-size: 10pt;}"
$style = $style + "TABLE{border: 1px solid black; border-collapse:collapse;}"
$style = $style + "TH{border: 1px solid black; background: #dddddd; padding: 5px; }"
$style = $style + "TD{border: 1px solid black; padding: 5px; }"
$style = $style + "</style>"
$subject = "Processing Log Check at " + (Get-Date -Format g)
$logpaths = Get-Content -Path C:\Powershell\xxxx\scenariologlocation.txt
$output = foreach ($logpath in $logpaths)
{
Write-Output $logpath
Get-ChildItem -path $logpath | sort LastWriteTime | select -ExpandProperty FullName -last 1 | Out-File C:\Powershell\path.txt
$path = Get-Content -Path C:\Powershell\path.txt
Get-Content -Path $path | Select-String -SimpleMatch "[" | select Line -last 10 | format-table -HideTableHeaders | Out-String
}
$body = (ConvertTo-Html -Head $style -body $output | Out-String)
Send-MailMessage -From "xxxxxx" -To "xxxxxx" -Subject $subject -Body $body -BodyAsHtml -SmtpServer "xxxxxxx"
I think you shouldn't pass a string to $output and then pass it to Convertto-Html -body
In my eyes the last part of the script should look like
$output = foreach ($logpath in $logpaths)
{
Write-Output $logpath
Get-ChildItem -path $logpath | sort LastWriteTime | select -ExpandProperty FullName -last 1 | Out-File C:\Powershell\path.txt
$path = Get-Content -Path C:\Powershell\path.txt
Get-Content -Path $path | Select-String -SimpleMatch "[" | select Line -last 10
}
$body = ($output | ConvertTo-Html -Head $style) | Out-String
Send-MailMessage -From "xxxxxx" -To "xxxxxx" -Subject $subject -Body $body -BodyAsHtml -SmtpServer "xxxxxxx"
So that Convertto-Html could build the table over all objects in $output. I don't really know if it is necessary to pipe the HTML to Out-String. Have no Powershell here. But I think this should help.
After a lot of fiddling and fanoodling, I ended up re-writing the lot and got what I needed into an email another way.
I'm not 100% convinced what I needed could be achieved from my original code (without resorting to the re-write).