I would like to ask for help if there is a way to send an e-mail notification when a scheduled ms access macro in task scheduler is in "Running" state for more than 20 minutes?
First thing that comes to mind is writing a second scheduled tasks to poll the runtime of the MS Access macro task.
If the task is over 20 minutes send out an email.
Another option might be to start a background job (Start-Job) in the MS Access code that will send the email after 20 minutes. And in your code, if the MS Access job succeeds you can cancel (Stop-Job) the email background task.
(There are many ways to skin a cat so just finding the best solution for the problem really)
Finally got it using powershell.
$ScheduledTaskName = "full path of your scheduled task e.g Folder1\Folder2\taskname"
$Result = (schtasks /query /FO LIST /V /TN $ScheduledTaskName | findstr "Result")
$Result = $Result.substring(12)
$Code = $Result.trim()
If ($Code -gt 0) {
$From = "MacroFails#DoNotReply.com"
$To = "Admin#Domain.com"
$Subject = "Scheduled task 'AppendCreatedSO' failed on SERVER"
$Body = "Error code: $Code"
$SMTPServer = "your SMTP Server"
$SMTPPort = "SMTP erver port"
Send-MailMessage -From $From -to $To -Subject $Subject -Body $Body -BodyAsHtml -SmtpServer $SMTPServer -Port $SMTPPort #-UseSsl -Credential (Get-Credential) #-Attachments $Attachment
}
Related
I'm creating a PS script to automate email blast to 17k users. Our exchange security baseline is set to only accept 60 requests per minute. Because I'm looping through the email list (CSV) line by line (sleep 1 sec), it took hours for my script to complete. What I'm trying to achieve now is to send the email to 100 users per request. I'm figuring out how to store the emails in an array of 100 & send the mail before going for the next 100. Any suggestion?
$recipients = Get-Content "mailinglist.csv"
foreach($rcpt in $recipients)
{
Write-Host "Attempt sending email to $rcpt ..."
Send-MailMessage -ErrorAction SilentlyContinue -ErrorVariable SendError -From $From -to $rcpt -Subject $Subject -SmtpServer $SMTPServer -port $SMTPPort -UseSsl -Credential $Cred -BodyAsHtml ($Body -f $Subject, $Date, $Venue, $Description, $Image)
$ErrorMessage = $SendError.exception.message
If($ErrorMessage)
{
Write-Host "Failure - $ErrorMessage" -ForegroundColor Red
Start-Sleep -Seconds 60
Send-MailMessage -ErrorAction SilentlyContinue -ErrorVariable SendError -From $From -to $rcpt -Subject $Subject -SmtpServer $SMTPServer -port $SMTPPort -UseSsl -Credential $Cred -BodyAsHtml ($Body -f $Subject, $Date, $Venue, $Description, $Image)
}
ElseIf($SendError.exception.message -eq $null)
{
Write-Host "Email has been sent to $rcpt" -ForegroundColor Green
Start-Sleep -Seconds 1
$n++
}
}
Write-Host "Total sent = $n"
You could use a traditional for loop and access your array elements by index.
$recipients = Get-Content "mailinglist.csv"
$To = <SomeValidEmailAddress>
$LastIndex = $recipients.GetUpperBound(0)
for ($i = 0; $i -le $LastIndex; $i+=100) {
$upperRange = [Math]::Min(($i+99),$LastIndex)
$Params = #{
ErrorAction = 'SilentlyContinue'
ErrorVariable = 'SendError'
Bcc = $recipients[$i..$upperRange]
To = $To
From = $From
Subject = $Subject
SmtpServer = $SMTPServer
Port = $SMTPPort
Credential $Cred
Body = $Body -f $Subject, $Date, $Venue, $Description, $Image
BodyAsHTML = $true
UseSsl = $true
}
"Attempt sending email to $($recipients[$i..$upperRange]) ..." # You may want to alter this to be more readable
Send-MailMessage #Params
# Other code
}
Explanation:
I've opted to use Splatting here for readability and manageability with the $Params hash table. It is entirely optional.
The -bcc parameter of Send-MailMessage supports a string array (string[]). Using this over the -To parameter will preserve privacy of the recipients. You can then easily send an email to multiple recipients provided you pass it an array. However, -To is required for Send-Mailmessage to work. It is recommended to make the email address passed into -To something that can be spammed or has a way of handling these types of emails. I have set up the $To variable for you to provide that email address. If privacy is of no concern whatsoever, -Bcc can just be replaced with -To.
Since $recipients is an array, you can access its elements by index, which supports the range operator ... $recipients[0..99] would be the first 100 items in the list.
$LastIndex stores the last index of the list, which is the value returned by the Array.GetUpperBound(Int32) method with dimension 0. Since the array is one-dimensional, 0 is the only dimension.
$upperRange is the beginning index ($i) plus 99. Should $upperRange ever be larger than $LastIndex, it will be set to $LastIndex. Depending on your PowerShell version, the $i+99 and $LastIndex comparison may not be necessary. Accessing an upperbound range beyond the size of the array, will just return all of the remaining elements of the array without throwing an error. This is likely just for completeness.
We (our company) are runnning several scheduled tasks on a server. Recently some of the tasks started to fail on running. We'd like to query all the scheduled jobs reporting anyone whose last run result isn't 0x0 using powershell.
I've tried a lot of research for finding an easy way to do so, but only found scripts, that can query scheduled task by name (only to check one single task) but not by last run result. It wouldn't be helpful to add a new codeline for every newly intstalled scheduled task.
There is a quite similar entry on that topic, but as described above with the task name as parameter. (How to send email when SPECIFIC scheduled task fails to run)
$ScheduledTaskName = "Taskname"
$Result = (schtasks /query /FO LIST /V /TN $ScheduledTaskName | findstr "Result")
$Result = $Result.substring(12)
$Code = $Result.trim()
If ($Code -gt 0) {
$User = "admin#company.com"
$Pass = ConvertTo-SecureString -String "myPassword" -AsPlainText -Force
$Cred = New-Object System.Management.Automation.PSCredential $User, $Pass
$From = "Alert Scheduled Task <task#servername>"
$To = "Admin <admin#company.com>"
$Subject = "Scheduled task 'Taskname' failed on SRV-001"
$Body = "Error code: $Code"
$SMTPServer = "smtp.company.com"
$SMTPPort = "25"
Send-MailMessage -From $From -to $To -Subject $Subject `
-Body $Body -SmtpServer $SMTPServer -port $SMTPPort -UseSsl `
-Credential $Cred
}
The code should be something like that, I guess
Get-ScheduledTask | where LastTaskResult -NE "0x0"
Use Get-ScheduledTaskInfo.
Get-ScheduledTask -TaskPath "\" | Where State -ne "Disabled" | Get-ScheduledTaskInfo | Where LastTaskResult -ne 0
In my example, I've just assumed you want tasks in the Task root, not any in the MS subfolders. If you store or care about tasks in the subfolders, then obviously modify the taskpath or identify the tasks you want some other way.
Get-ScheduledTaskInfo returns a bunch of properties that you can search/select. Excluding the Cim (WMI) properties, they are:
TaskName,TaskPath,LastRunTime,LastTaskResult,NextRunTime,NumberofMissedRuns
Sorry I am just starting out writing a PowerShell scripts. I am trying to use a script to send a email once an event (error) comes across the Event Viewer. I do not want to use the feature that is incorporated in Event Viewer because it does not work on all Operating Systems. Here is what I have in my script now but I cannot import the Message or Data from the error that cut.
$event = Get-EventLog -LogName Application -Source "My Script-1" | where {$_.eventID -eq 1}
if ($event.EntryType -eq "Error")
{
[string]$EmailBody = Event.Data
$EmailFrom = "Test#google.com"
$EmailTo = "lmill130#kent.edu"
$EmailSubject = "This was sent from a PowerShell Script"
$SMTPServer = "Example Server SMTP"
Write-host "Sending Email Test"
Send-MailMessage -From $EmailFrom -To $EmailTo -Subject $EmailSubject -Body $EmailBody -SmtpServer $SMTPServer
}
else
{
write-host "No error found"
write-host "Here is the log entry that was inspected:"
$event
}
If I put my own string in $EmailBody then it works with no issue but when I try to grab data from the Event I have no luck.
This is the script I use to create the test event.
#New-EventLog -LogName Application -Source "My Script-1"
Write-EventLog -LogName Application -Source "My Script-1" -EntryType Error -
EventId 1 -Message "This is a test Entry."
I have a task created that when that event cuts then it runs the first script.
I have searched all over the internet and I have had no luck. Help please.
Thats probaly because Event.Data doesn't return anything.
It has to be $event.Data, but I think you should maybe use $event.Message to get the info message of the error.
So all together would look like this:
$event = Get-EventLog -LogName Application -Source "My Script-1" | where {$_.eventID -eq 1}
if ($event.EntryType -eq "Error")
{
[string]$EmailBody = $event.Data
#or [string]$EmailBody = $event.Message
$EmailFrom = "Test#google.com"
$EmailTo = "lmill130#kent.edu"
$EmailSubject = "This was sent from a PowerShell Script"
$SMTPServer = "Example Server SMTP"
Write-host "Sending Email Test"
Send-MailMessage -From $EmailFrom -To $EmailTo -Subject $EmailSubject -Body $EmailBody -SmtpServer $SMTPServer
}
else
{
write-host "No error found"
write-host "Here is the log entry that was inspected:"
$event
}
Replace [string]$EmailBody = Event.Data
with [string]$EmailBody = $Event.Data
And its always better to use Message rather than data cause you are more bothered about the error message not the data which is going to be get captured.
Hope it helps.
I am new to powershell and I am trying to write a script that will email me whenever someone moves or deletes a file or folder from a shared drive. I already set up the task scheduler to execute the script when one of those events happen. The problem that I have is that I execute script from the shell it provides me with all the information regarding the last entry in the event logs. However, when it runs from the task scheduler it does not execute. I believe that it has to do with the body line. Any suggestions or insights will be greatly appreciated.
This is my code:
$events = Get-EventLog -Logname Security -Newest 1
$From = $env:COMPUTERNAME + "#company.com"
$To = "me#company.com"
$Subject = $env:COMPUTERNAME + " " + $env:UserName + " " + $_.eventID
$Body = $events | format-list -property * | out-string
$SMTPServer = "exch"
Send-MailMessage -From $From -to $To -Subject $Subject -Body $Body -SMTPServer $SMTPServer
I am working on a PowerShell script which sends emails multiple times with different subject and body each time.
I am trying to move Send-MailMessage into a function or something that I could use to reduce the code lines.
$Sender = 'jones#example.com'
$text = "<html><body>"
$text += "<p>Welcome</p>"
### A cmdlet that would give recipient email address
$Recipient = (Get-Details -user $user).email
$smtp = "server.example.com"
$subject = "welcome email"
Send-MailMessage -BodyAsHtml $text -from $Sender -SmtpServer $smtp -Priority high -to $Recipient -Subject $subject
Write-Output "executing commands to capture results"
Write-Output ""
### Few Commands executed in this step
Write-Output "Analyzing results"
### Few commands executed in this step
$newtext = "<html><body>"
$newtext += "Congrats, you are selected"
$newsubject = "results email"
Send-MailMessage -BodyAsHtml $newtext -from $Sender -SmtpServer $smtp -Priority high -to $Recipient -Subject $subject
You could create a function like this:
Function Send-Email($text,$subject,$recipient)
{
Send-MailMessage -BodyAsHtml $text -From "jones#example.com"
-SmtpServer "server.example.com" -Priority High -To $recipient -Subject $subject
}
You can call it like:
Send-Email -text "Hello" -subject "Test" -recipient "test#example.com"
You can add or remove arguments depending on what will change though. Assuming the smtp server won't change for example, this isn't needed as a parameter.
I am trying to move Send-MailMessage into a function or something that I could use to reduce the code lines.
Writing a function for one line can be useful if the options are many and never change. However you do have one that changes. There is another PowerShell feature that would work here just as well. Splatting!
$emailParameters = #{
From = $Sender
SmtpServer = $smtp
Priority = "high"
To = $Recipient
Subject = $subject
}
Send-MailMessage -BodyAsHtml $text #emailParameters
# ... other code and stuff
Send-MailMessage -BodyAsHtml $newtext #emailParameters
Now you still only have to make changes in one place and the code is arguably more terse.
Another point is that when you are making multi-line strings all at once, as supposed to building over the course of the script you can always use here strings. You only have two lines but if you code evolves over time it is a good tactic to start early instead of many $object += "string" lines
$text = #"
<html><body>
<p>Welcome</p>
"#
Note that indentation is preserved in the resulting here-string. The "# has to appear on its own line with no leading whitespace. Using double quotes means you can still expand variables as well in there.