I received an email but the body is just blank. There is no text or message. Below is my code.
$servers = @("Server1","Server2","Server1","Server3")
##### Function to send mail #####
function sendMail([string]$msgbody) {
$smtpServer = "SMTP.myDomain.com"
$mailer = new-object Net.Mail.SMTPclient($smtpserver)
$From = "noreply@myDomain.com"
$To = "myName@myDomain.com"
$subject = "SSL Certificate Expiring Soon"
$msg = new-object Net.Mail.MailMessage($from,$to,$subject,$msgbody)
$msg.IsBodyHTML = $true
$mailer.send($msg)
}
##### Loop through all servers in the server array #####
foreach($server in $servers) {
try{
$expiredCert += Invoke-Command -ComputerName $server -ScriptBlock {Get-ChildItem -Path Cert:\localmachine\my | ?{$_.NotAfter -lt (get-date).AddDays(30)} | Select Thumbprint,FriendlyName,NotAfter, NotBefore}
} catch {
$ErrorMessage = $_.Exception.Message
$currentTime = Get-Date
sendMail("There was a problem connecting to and/or querying "+ $server +" for the failed Server login attempts. Specific error:`n`n" + $ErrorMessage + "`n`n Timestamp: " + $currentTime + "")
}
}
if ($expiredCert){
sendMail($expiredCert)
Write-Output $expiredCert
}
The Write-Output does show the value of the $expiredCert variable just not the email body that I got in my inbox. Any help is much appreciated.
The main item is that you are appending to a variable $expiredCert (e.g. +=), but do not see you setting the variable in the code (e.g. $expiredCert = @()). Also, you are sending a HTML email, but you are not converting the object to HTML, so if the variable would work, you would get a email body like SYSTEM.OBJECT.
Regardless, that isn’t the best method to really roll up objects into a variable. Additionally, would recommend a different approach. Regardless of the scenario, an error, certs meet criteria and exist or if there are no certs expiring, that is valuable data to capture to make sure all bases are covered. If a standard object schema is used, we can capture all results in a standard format to perform queries against or send an email. Here is a sample, but first you should test that you are getting back results from all server, all scenarios and then work on the email portion. There is also Send-MailMessage that is already a cmdlet rather than using the Net.Mail.Message directly.
$servers = @("Server1","Server2","Server1","Server3")
##### Loop through all servers in the server array #####
$results = foreach($server in $servers) {
try{
Invoke-Command -ComputerName $server -ErrorAction Stop -ScriptBlock {
$results = Get-ChildItem -Path Cert:\localmachine\my |
Where-Object -FilterScript {$_.NotAfter -lt (get-date).AddDays(30)} |
Select-Object -Property @{Name='Server';Expression={$env:ComputerName}},
Thumbprint,
FriendlyName,
NotAfter,
NotBefore,
@{Name='Status';Expression={'Success'}}
if (!$results) {
[PSCustomObject]@{
Server = $env:ComputerName
ThumbPrint = $null
FriendlyName = $null
NotAfter = $null
NotBefore = $null
Status = "Success - No Expiring Certs Found."
}
}
else {
$results
}
}
} catch {
[PSCustomObject]@{
Server = $server
ThumbPrint = $null
FriendlyName = $null
NotAfter = $null
NotBefore = $null
Status = "There was a problem connecting to and/or querying {0} for the failed Server login attempts. <br><br>Specific error: {1} <br><br>Timestamp: {2}" -f $server, $_, (Get-Date)
}
}
}
$results
$sendMailMessageSplat = @{
To = "myName@myDomain.com"
From = "noreply@myDomain.com"
Subject = "SSL Certificate Expiring Soon"
SmtpServer = "SMTP.myDomain.com"
Body = ($results | ConvertTo-Html) | Out-String
BodyAsHtml = $true
}
Send-MailMessage @sendMailMessageSplat
Thank you so much for help, much appreciated! The code and email works just fine. I got the code to show the following but couldn’t figure out how to filter out the PSComputerName and PSShowComputerName properties. I don’t need to include these two columns or properties in my report.
This is the code.
Invoke-Command -ComputerName $server -ErrorAction Stop -ScriptBlock {
$results = Get-ChildItem -Path Cert:\localmachine\my |
Where-Object -FilterScript {$_.NotAfter -lt (get-date).AddDays(30)} |
Select-Object -Property @{Name='Server';Expression={$env:ComputerName}},
FriendlyName,
Thumbprint,
NotAfter
This is what I have.
$servers = @("database1")
##### Loop through all servers in the server array #####
$reports = foreach ($server in $servers) { # changed name to avoid confusion with the $results variable inside the Invoke-Command scriptblock
try {
Invoke-Command -ComputerName $server -ErrorAction Stop -ScriptBlock {
$results = Get-ChildItem -Path Cert:\localmachine\my |
Where-Object -FilterScript { $_.NotAfter -lt (Get-Date).AddDays(30) } |
Select-Object -Property @{n='Server';e={$Using:Server}},
FriendlyName,
NotAfter,
Thumbprint
#@{n='Status';e={'Expiring Certs Found.'}}
if (!$results) {
$dataReturned = [PSCustomObject]@{
Server = $Using:Server
FriendlyName = $null
NotAfter = $null
ThumbPrint = $null
#Status = "Success - No Expiring Certs Found."
}
#$dataReturned.GetType()
$dataReturned.PSObject.Properties.Remove("RunspaceId")
$dataReturned.PSObject.Properties.Remove("PSComputerName")
$dataReturned.PSObject.Properties.Remove("Status")
$dataReturned.PSObject.Properties.Remove("PSShowComputerName")
}
$results # send this back to the invoking machine and placed into the $reports variable outside the scriptblock
}
}
catch {
[PSCustomObject]@{
Server = $server
FriendlyName = $null
NotAfter = $null
ThumbPrint = $null
Status = "There was a problem connecting to and/or querying {0} for the failed Server login attempts. <br><br>Specific error: {1} <br><br>Timestamp: {2}" -f $server, $_, (Get-Date)
}
}
}
$reports
I tried to remove those four pair values from the custom object but I don’t think I did it right because it’s not removing from the $reports output.