PowerShell to send email - powershell

I am running a Task Scheduler to execute my PowerShell every 30 minutes.
So
$users = Search-ADAccount -LockedOut -SearchBase
"OU=People,DC=Example,DC=com" -SearchScope Subtree | Select
SamAccountName
This returns a list of users. Now I want to create an emailbody with the users
$EmailBody = ForEach($user in $users) {"`r`n",$user}
Send-MailMessage -To $to -Subject "Locked Accounts" -BodyAsHtml $EmailBody -From $from -Credential $cred -SmtpServer $server -Debug
However my current code will send the email even if NO ONE is locked. Is there anyway I can check to see if the $users has at least 1 person?
(I haven't tested the $EmailBody but would like to know if this is acceptable for BodyAsHtml)
================
Updated Code
if ($users) {
if ($users.count -gt 0) {#even if there are users, this line always is false.
# send the email here
foreach($user in $users)
{
$message = $message + " " + $user + " is locked out" + "`r`n"
Write-Host $user
}
Send-MailMessage -To $to -Subject "Locked Accounts" -BodyAsHtml $message -From $from -Credential $cred -SmtpServer $server -Debug
} }

if ($users -ne $null) # lists can be empty as well, in which case the count fails
{
if ($users.count -gt 0) {
# send the email here
}
}

Related

Powershell get process script not working correctly

I want this script to show me WinWord processes which are running currently and to send an email alert out. Currently the 1st script works if there are WinWord processes running and lists them in an email BUT if they are no WinWord processes running the script fails advising parameter is empty or null, cannot find process.
The second script works if there are no processes and doesn’t throw the null or empty parameter if there are no WinWord processes running but only shows true or false by email. Not the list of processes running. Also would like to add some write host in the script for the email output to say. Below are the number of WinWord’s Processes running.
I am a newbie to PowerShell. I am learning as I go. I also used -erroraction silentlycontinue for the first script but when outputting to email it still fails with empty or null parameter.
Below are the scripts.
Doesn't work if process is not running, cannot accept argument which is null or empty. If process is running works perfect.
$winwords = (get-process -ComputerName Dummyserver -Name Winword |where-object { $_.Count -gt 0})| Out-String
Send-MailMessage -To "Dummyemail.co.uk" -From " Dummyemail.co.uk" -Subject "WinWord Check" -SmtpServer " Dummy.priv" -Body $winwords
Works if argument is null or empty but an email alert is out which says false or true BUT doesn't display the amount of processes running like the first script.
$processname = "Winword"
$instanceisrunning = (get-process -ComputerName Dummyserver| where-object { $_.Name -eq $processname }).count -gt 0 | Out-String
Send-MailMessage -To "Dummyemail co.uk" -From "Dummyemail.co.uk" -Subject "WinWord Check" -SmtpServer " Dummyemail.priv" -Body $isrunning
You have the right idea using where-object to limit the processes to just the name you want. The logic you are using for count greater than zero will return a boolean ($true or $false), which is why you are seeing that output.
If you want to always send a message when this is run, you can do this:
$instances = (get-process -ComputerName Dummyserver | where-object { $_.Name -eq $processname })
if($instances.count -gt 0)
{
$message = $instances | Out-String
}
else
{
$message = "No instances running"
}
Send-MailMessage -To "Dummyemail co.uk" -From "Dummyemail.co.uk" -Subject "WinWord Check" -SmtpServer " Dummyemail.priv" -Body $message
If you only want a message sent when instances are running:
$instances = (get-process -ComputerName Dummyserver | where-object { $_.Name -eq $processname })
if($instances.count -gt 0)
{
Send-MailMessage -To "Dummyemail co.uk" -From "Dummyemail.co.uk" -Subject "WinWord Check" -SmtpServer " Dummyemail.priv" -Body ($instances | Out-String)
}
Edit: Adding code to work of multiple computers with one email
$computers = #("dummyserver","otherserver","nextserver")
$processName = "WinWord"
$message = "$processName is running on the following:"
foreach ($computer in $computers)
{
$message += "Hostname: $computer"
$instances = (Get-Process -ComputerName $computers | Where-Object { $_.Name -eq $processName })
if($instances.count -gt 0)
{
$message += ($instances | Out-String)
}
else
{
$message += "No instances running"
}
}
Send-MailMessage -To "Dummyemail co.uk" -From "Dummyemail.co.uk" -Subject "WinWord Check" -SmtpServer " Dummyemail.priv" -Body $message
you can use ErrorAction as silentlyContinue which will make your script run even if there is an error "NO Winword instances".
$winwords = (get-process -ComputerName Dummyserver -Name Winword -ErrorAction
SilentlyContinue |where-object { $_.Count -gt 0})| Out-String
if($winwords -eq ""){
$winwords = "No Instances"
}
Send-MailMessage -To "Dummyemail.co.uk" -From " Dummyemail.co.uk" -Subject "WinWord
Check" -SmtpServer " Dummy.priv" -Body $winwords

Can't send powershell email to managers

I'm trying to create a PS script to email managers about employees with expiring accounts(NOT PASSWORDS) within the next 10 days.
I know this has been discussed already a few times but I was unable to find a suitable solution to this issue.
This is what I have so far:
$MyEmail = "email#domain.com"
$SMTP= "domain.com"
$To = "email#domain.com"
$Subject = "Account expiring"
$Body = "Hi_,
the following account is due to expire, please reply to this email if
you wish to extend the account for a further 3 months
Kind regards,
Tech Team"
$Users = Get-ADUser -filter * -SearchBase "OU=Powershell Test
OU,DC=domain,DC=com" -Properties emailaddress,
Manager,accountexpirationdate
$Users | Select
Name,emailaddress,accountexpirationdate,#{label="Manager";expression= .
{(Get-ADUser $_.Manager -Properties emailaddress).emailaddress}}
Send-MailMessage -To $to -From $MyEmail -Subject $Subject -Body $Body
-SmtpServer $SMTP
I believe I am missing a few pieces.
Can anyone help?
It would be much appreciated.
Thanks
So I've edited my previous comment, because I couldn't stand that is was still not very good:
$MyEmail = "email#domain.com"
$secpasswd = ConvertTo-SecureString "PlainTextPassword" -AsPlainText -Force
$SMTP= "domain.com"
$SMTPPort = "587"
$cred = New-Object System.Management.Automation.PSCredential ($MyEmail, $secpasswd)
$NeverExpires = 9223372036854775807;
$ExpireMin = (Get-Date).AddDays(0);
$ExpireMax = (Get-Date).AddDays(90);
$today = (Get-Date)
try{
$expiringsoon = Get-ADUser -Filter * -SearchBase "OU=Powershell Test OU,DC=domain,DC=com" -Properties accountExpires | Where-Object {$_.accountExpires -ne $NeverExpires -and [datetime]::FromFileTime([int64]::Parse($_.accountExpires)) -lt $ExpireMax -and [datetime]::FromFileTime([int64]::Parse($_.accountExpires)) -gt $ExpireMin }
}catch{
throw $_
}
foreach($user in $expiringsoon){
try{
$userDetails = Get-ADUser $user -Properties AccountExpirationDate,accountExpires,manager
}catch{
Write-Host "Error while searching for user '$user'" -ForegroundColor Red
}
$ExpiryDate = $userDetails.AccountExpirationDate
$DaysLeft = ($ExpiryDate-$today).days
$DateStr = $ExpiryDate.AddDays(-1).ToString("dd/MM/yyyy")
$name = $user.Name
$manager = $userDetails.manager
try{
$managerEmail = (Get-ADUser $manager -Properties emailAddress).emailAddress
if(!$managerEmail){
$managerEmail = $MyEmail
}
}catch{
$managerEmail = $MyEmail
}
# Set Greeting based on Number of Days to Expiry.
# Check Number of Days to Expiry
$messageDays = $DaysLeft
if (($DaysLeft) -gt "1")
{
$messageDays = "in " + "$DaysLeft" + " days"
}
ElseIf (($DaysLeft) -eq "1")
{
$messageDays = "in 1 day"
}
else
{
$messageDays = "today"
}
# Email Subject Set Here
$subject="The account of $name will expire $messageDays "
# Email Body Set Here, Note You can use HTML, including Images.
$body ="
Hi,
<p>the following account '$name' is due to expire, please reply to this email if you wish to extend the account for a further 3 months<br>
<p>Kind regards, <br>
Tech Team
</P>"
#----- Show Details of sent mail -----#
try{
Send-MailMessage -to $managerEmail -from $MyEmail -SmtpServer $SMTP -subject $subject -body $body -bodyasHTML -priority High –Credential $cred -port $SMTPPort -UseSsl
Write-Host "An e-mail has been send to $managerEmail about $name" -ForegroundColor Green
}catch{
Write-Host "Email to $managerEmail for $name failed with error: $($_.exception.message)" -ForegroundColor Red
}
}
Okay, because I couldn't help but wanting to get the script right. Here my present to you. A perfectly working script that sends emails to managers of whom the user expires within 90 days. I also included error handling. Please take this script as a guide to create your own and if you have any questions, feel free.

AD Password expiry notification from technet gallery

I try edit powershell password email notification from
- https://gallery.technet.microsoft.com/Password-Expiry-Email-177c3e27
or
- https://blogs.technet.microsoft.com/askpfeplat/2015/05/04/how-to-setup-a-password-expiration-notification-email-solution/
I like to send log in html file and I try add 2 new column $sent, $expireson.
I add 2 columns to get-aduser query but results in this columns is bad.
I don't know what can I do to make the code work properly.
My code below:
$smtpServer="mail.company.com"
$expireindays = 52
$from = "Company Administrator <support#mycompany.com>"
$logging = "Enabled" # Set to Disabled to Disable Logging
$logFile = "C:\scripts\test.html" # ie. c:\mylog.csv
$testing = "Enabled" # Set to Disabled to Email Users
$testRecipient = "testuser#company.com"
$filecontent = (Get-Content $logfile | Out-String)
# System Settings
$textEncoding = [System.Text.Encoding]::UTF8
$date = Get-Date -format ddMMyyyy
# End System Settings
# Get Users From AD who are Enabled, Passwords Expire and are Not Currently Expired
Import-Module ActiveDirectory
$users = get-aduser -filter * -properties Name, ``PasswordNeverExpires, PasswordExpired, PasswordLastSet, EmailAddress |
where ($_.Enabled -eq "True") | where {$_.PasswordNeverExpires -eq $false} | where {$_.passwordexpired -eq $false} |
#{N="column1";E= {$expireson}}, #{N="column1";E= {$sent}} |
Convertto-html | out-file $logfile
# Process Each User for Password Expiry
foreach ($user in $users)
{
$Name = $user.Name
$emailaddress = $user.emailaddress
$passwordSetDate = $user.PasswordLastSet
$PasswordPol = (Get-AduserResultantPasswordPolicy $user)
$sent = "" # Reset Sent Flag
# Check for Fine Grained Password
if (($PasswordPol) -ne $null)
{
$maxPasswordAge = ($PasswordPol).MaxPasswordAge
}
else
{
# No FGP set to Domain Default
$maxPasswordAge = $DefaultmaxPasswordAge
}
$expireson = $passwordsetdate + $maxPasswordAge
$today = (get-date)
$daystoexpire = (New-TimeSpan -Start $today -End $Expireson).Days
# Set Greeting based on Number of Days to Expiry.
# Check Number of Days to Expiry
$messageDays = $daystoexpire
if (($messageDays) -gt "1")
{
$messageDays = "in " + "$daystoexpire" + " days."
}
else
{
$messageDays = "today."
}
# Email Subject Set Here
$subject="Your password will expire $messageDays"
# Email Body Set Here, Note You can use HTML, including Images.
$body ="
Dear $name,
<p> Your Password will expire $messageDays<br>
To change your password on a PC press CTRL ALT Delete and choose Change Password <br>
<p>Thanks, <br>
</P>"
# If Testing Is Enabled - Email Administrator
if (($testing) -eq "Enabled")
{
$emailaddress = $testRecipient
} # End Testing
# If a user has no email address listed
if (($emailaddress) -eq $null)
{
$emailaddress = $testRecipient
}# End No Valid Email
# Send Email Message
if (($daystoexpire -ge "0") -and ($daystoexpire -lt $expireindays))
{
$sent = "Yes"
# If Logging is Enabled Log Details
if (($logging) -eq "Enabled")
{
Add-Content $logfile "$date,$Name,$emailaddress,$daystoExpire,$expireson,$sent"
}
# Send Email Message
#Send-Mailmessage -smtpServer $smtpServer -from $from -to $emailaddress -subject $subject -body $body -bodyasHTML -priority High -Encoding $textEncoding
} # End Send Message
else # Log Non Expiring Password
{
$sent = "No"
# If Logging is Enabled Log Details
if (($logging) -eq "Enabled")
{
Add-Content $logfile "$date,$Name,$emailaddress,$daystoExpire,$expireson,$sent"
}
}
} # End User Processing
#Send-Mailmessage -smtpServer $smtpServer -from $from -to $emailaddress -subject $subject -body $body -bodyasHTML -priority High -Encoding $textEncoding
# End
I fix my issue converting CSV to HTML and add some CSS. Now i have log in html table sending it to email.
$info = Import-Csv $logFile | ConvertTo-Html -head $style
$mailBody =
"
$info
"
Send-Mailmessage -smtpServer $smtpServer -from $from -to $emailaddress -subject test -body $mailBody -bodyasHTML -priority High -Encoding $textEncoding

I am trying to create a script in powershell that will send a email based off of results of a command and have no idea where to start

This is all in powershell 4.0
We currently have this script that we manually run once a week that tells us all the users on the network who's password will expire in <=7 days.
#get max password age policy
$maxPwdAge=(Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge.Days
#expiring in 7 days
$7days=(get-date).AddDays(7-$maxPwdAge).ToShortDateString()
Get-ADUser -filter {Enabled -eq $True -and PasswordNeverExpires -eq $False - and PasswordLastSet -gt 0} –Properties * | where {($_.PasswordLastSet).ToShortDateString() -le $7days} | Select-Object -Property "Displayname"
This displays a list of names when run. I then want to take the list of names it generates, add the string "#example.com" to have a string "user.name#example.com"
I thien want to send an email to that email address
$EmailFrom = "noreply#domain.com"
$EmailTo = "destinyemail#domain.com"
The EmailTo needs to change for each person. It could even be emailed to all the users the above outputs in one email.
$EmailSubject = "PasswordExpiring"
$emailbody = " body message "
$SMTPServer = "smtpserver.company.com"
Send-MailMessage -Port 587 -SmtpServer $SMTPServer -From $EmailFrom -To $EmailTo -Attachments $emailattachment -Subject $EmailSubject -Body $emailbody -Bodyashtml;
Assuming that Displayname format is "FirstName LastName" (e.g. "Jon Doe") and email address format is "FirstName.LastName#example.com":
$displayNames = Get-ADUser ...
foreach ($sdisplayName in $displayNames ) {
$Parts = $sdisplayName -split ' '
$EmailTo = $Parts[0] + '.' + $Parts[-1]
Send-MailMessage -To $EmailTo ...
}

Get PrimaryStatus of DCIM_PhysicalDiskView and Put it in a variable in Powershell

I am trying to use the primaryStatus from the DCIM_PhysicalDiskView and compare it to 3 (degraded hard disk). If there is a match, an email will be sent to notify the admin. Here is the code:
$computerNames = Get-Content -Path C:\scripts\nameTest.txt
foreach ($computer in $computerNames) {
write-host "$computer"
$value = "3"
$smtpserver = "mailserver.xxxx.com" # your mail server here
$smtpFrom = "xx#xxxx.com" # your from address, mail server will most likely allow any
$smtpTo = "xx#xxxx.com" #your email address here. can also be an array and will send to all
$MessageSubject = "Testing Failed Disk in $computer" #whatever you want the subject to be.
gwmi -Namespace root\dcim\sysman -computername $computer -Class DCIM_PhysicalDiskView | ForEach {$name = $_.Name; $primaryStatus = $_.PimaryStatus}
if( $primaryStatus -contains $value )
{
Send-MailMessage -SmtpServer $smtpserver -from $smtpFrom -to $smtpto -subject $messageSubject
Write-Host "error message sent"
}
}
My problem is that the command is not piping to the foreach. The $name and $primaryStatus are staying null, therefore not going through the if statement.
Any help on this will be greatly appreciated. Thanks!
The below is your code with the braces changed for the foreach loop. Note that you will still need to have the closing brace from your opening foreach-object.
gwmi -Namespace root\dcim\sysman -computername $computer -Class DCIM_PhysicalDiskView | ForEach-Object {
$name = $_.Name
$primaryStatus = $_.PrimaryStatus
if( $primaryStatus -eq $value )
{
Send-MailMessage -SmtpServer $smtpserver -from $smtpFrom -to $smtpto -subject $messageSubject
Write-Host "error message sent"
}
}
Fixed the typo for $_.PrimaryStatus as well. Is $primaryStatus an array? -Contains only works with arrays. I think you wanted -eq? I dont have access to that namespace so i cannot test my theory. Also, I think that you could change this a little with a Where-Object.
gwmi -Namespace root\dcim\sysman -computername $computer -Class DCIM_PhysicalDiskView |
Where-Object { $primaryStatus -eq $value } | ForEach-Object{
Send-MailMessage -SmtpServer $smtpserver -from $smtpFrom -to $smtpto -subject $messageSubject
Write-Host "error message sent"
}
disclaimer: I do not have that namespace so I cannot test this but the logic looks sounds so it should work.