Powershel Email Failures in Task Scheduler
Powershell opens up a lot of doors for admins and the amount of tasks you automate with it is endless especially when paired with the Windows task scheduler. I recently automated a task that involved sending an email to confirm whether the task ran successfully or failed. The task ran successfully during testing, however, I encountered a lot of errors when I placed it in the task scheduler to run on a schedule. The email would not send.
Security Best Practice
You will need to provide the credentials of the account sending the email. For my process I utilize SMTP and I need to authenticate against our on-prem exchange server. Here are the security issues with including plain text passwords in your script.
Unauthorized Access: If someone gains access to the script, they can read the password and use it to access sensitive systems, services, or data. This can lead to data breaches, system compromises, and unauthorized activities.
Insider Threats: Even trusted employees or contractors might misuse the credentials if they are easily accessible within scripts. This can lead to intentional or unintentional security incidents.
Version Control Exposure: If the script is stored in a version control system like Git, especially if it’s pushed to a remote repository (e.g., GitHub, GitLab), the password becomes accessible to anyone with access to the repository. Public repositories make this even more dangerous.
Backup and Recovery Risks: Scripts are often included in backups. If backups are not properly secured, the passwords within them can be extracted by unauthorized parties.
Malware Exploitation: Malware or malicious actors that infiltrate your system might scan for files containing passwords. Plain text passwords make it easy for them to escalate their access.
Compliance Violations: Storing passwords in plain text can violate organizational policies and industry regulations (e.g., GDPR, HIPAA, PCI DSS), leading to legal consequences and penalties.
Lack of Auditability: Plain text passwords make it difficult to track who used the credentials and when, complicating incident response and forensic analysis.
The Issues
With that being said, here is the issue that I face. When I ran my script during testing everything worked great, however, when I placed it in the task scheduler the email would not run. To authenticate against my Exchange server to send the email I used the following script to to encrypt my password
$Credential = Get-Credential -UserName “[email protected]” -Message “Enter SMTP Password”
$Credential | Export-Clixml -Path “C:\Scripts\SMTP_Credentials.xml”
This will prompt you to enter your password, after entering your credentials it will create an XML file in the specified path. I then called the created XML file in my script while sending the email.
# Import the encrypted password file
$smtpPassword = Get-Content “C:\Scripts\SMTP_Credentials.xml” | ConvertTo-SecureString
# Credentials
$smtpUsername =”[email protected]”
$credentials = New-Object System.Management.Automation.PSCredential($smtpUsername, $smtpPassword)
This method should’ve worked and it does if you’re manually running the script.
The Fix
I stored the credentials in “Windows Credential Manager” and called the credentials within the script. You need to run the following code in PS to install the Credential manger module prior
Install-Module -Name CredentialManager
Here the actual script to send the email
# Define email parameters
$smtpServer = “server”
$smtpFrom = “[email protected]”
$smtpTo = “[email protected]”
$messageSubject = “subject here”
$messageBody = “Message Body”
# Function to write to log
function Log-Message {
param (
[string]$message)
$timestamp = Get-Date -Format “yyyy-MM-dd HH:mm:ss”
“$timestamp : $message” | Out-File -Append -FilePath $Log
}
# Retrieve SMTP credentials from Windows Credential Manager
Import-Module -Name CredentialManager
$Target = “SMTP_Credentials” #This is the name credentials in credentials manager
$credentials = Get-StoredCredential -Target $Target
if ($credentials -eq $null) {
Log-Message “Failed to retrieve SMTP credentials from Windows Credential Manager.”
exit
}
# Function to send email with retry mechanism
function Send-AlertEmail {
param (
[string]$subject,
[string]$body)
$emailSuccess = $false
$maxRetries = 3
$retryDelaySeconds = 10
for ($attempt = 1; $attempt -le $maxRetries; $attempt++) {
try {
Log-Message “Attempting to send email (Attempt $attempt)…”
# Send the email directly
Send-MailMessage -SmtpServer $smtpServer -Credential $credentials -From $smtpFrom -To $smtpTo `
-Subject $subject -Body $body -Port 25
Log-Message “Email sent successfully: $subject”
$emailSuccess = $true
break
} catch {
$ErrorMessage = $_.Exception.Message
Log-Message “Failed to send email on attempt ${attempt}: $ErrorMessage”
}
if (!$emailSuccess) {
Start-Sleep -Seconds $retryDelaySeconds
}
}
if (!$emailSuccess) {
Log-Message “Failed to send email after $maxRetries attempts. Giving up.”
}
}
Important
Make sure the user that is running the task is the user that has the credentials stored in Windows credentials manager.
If you are still having issues, I suggest looking at the user permissions