Send Email of PowerShell Output - powershell

I'm new to PowerShell, I'm running Windows Server 2012 R2. The following Script gives me Output what I want but in the message the output is not appearing and it saying the Body cannot be "null" or "empty".
$fileToLocate = "*"
$Directories = #(
"C:\CtvFTPSite\AE1\ASN\Undelivered\",
"C:\CtvFTPSite\AE1\Invoices\Undelivered\",
"C:\CtvFTPSite\AE1\SO\Undelivered\",
"C:\CtvFTPSite\AE2\ASN\Undelivered\",
"C:\CtvFTPSite\AE2\Invoices\Undelivered\",
"C:\CtvFTPSite\AE2\SO\Undelivered\",
"C:\CtvFTPSite\BH1\ASN\Undelivered\",
"C:\CtvFTPSite\BH1\Invoices\Undelivered\",
"C:\CtvFTPSite\BH1\SO\Undelivered\",
"C:\CtvFTPSite\KW1\ASN\Undelivered\",
"C:\CtvFTPSite\KW1\Invoices\Undelivered\",
"C:\CtvFTPSite\KW1\SO\Undelivered\",
"C:\CtvFTPSite\OM1\ASN\Undelivered\",
"C:\CtvFTPSite\OM1\Invoices\Undelivered\",
"C:\CtvFTPSite\OM1\SO\Undelivered\",
"C:\CtvFTPSite\SA1\ASN\Undelivered\",
"C:\CtvFTPSite\SA1\Invoices\Undelivered\",
"C:\CtvFTPSite\SA1\SO\Undelivered\"
)
$filesUndelivered = Join-Path -Path $Directories -ChildPath $fileToLocate | Where-Object{Test-Path $_} | ForEach-Object{
Get-ChildItem $Directories -Recurse | % { Write-Host $_.FullName }
}
$Max_mins = "-5"
$Curr_date = get-date
$username = "myusername#myemail.com"
$password = Get-Content C:\security\string.txt | ConvertTo-SecureString
$cred = new-object -typename System.Management.Automation.PSCredential `
-argumentlist $username, $password
$localIpAddress = $(ipconfig | where {$_ -match 'IPv4.+\s(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' } | out-null; $Matches[1])
[string]$messagebody ="$filesUndelivered"
[string]$titlefailed ="Urgent You Have Files in Undelivered Folder in $localIpAddress in $env:computername"
$portno = "25"
$smtpsrv = "mail.server.com"
$smtpto = "myusername#myemail.com"
$smtpfrom ="myusername#myemail.com"
if ($filesfailed.Count)
{
foreach ($file in $filesUndelivered) {[string]$messagebody += $file.FullName + "`r`n"}
Send-MailMessage -To $smtpto -From $smtpfrom -port $portno -SmtpServer $smtpsrv -Credential $cred -Subject $titlefailed -Body $messagebody
}

Fixed
$fileToLocate = "*"
$failedpath = #(
"C:\CtvFTPSite\AE1\ASN\Undelivered\",
"C:\CtvFTPSite\AE1\Invoices\Undelivered\",
"C:\CtvFTPSite\AE1\SO\Undelivered\",
"C:\CtvFTPSite\AE2\ASN\Undelivered\",
"C:\CtvFTPSite\AE2\Invoices\Undelivered\",
"C:\CtvFTPSite\AE2\SO\Undelivered\",
"C:\CtvFTPSite\BH1\ASN\Undelivered\",
"C:\CtvFTPSite\BH1\Invoices\Undelivered\",
"C:\CtvFTPSite\BH1\SO\Undelivered\",
"C:\CtvFTPSite\KW1\ASN\Undelivered\",
"C:\CtvFTPSite\KW1\Invoices\Undelivered\",
"C:\CtvFTPSite\KW1\SO\Undelivered\",
"C:\CtvFTPSite\OM1\ASN\Undelivered\",
"C:\CtvFTPSite\OM1\Invoices\Undelivered\",
"C:\CtvFTPSite\OM1\SO\Undelivered\",
"C:\CtvFTPSite\SA1\ASN\Undelivered\",
"C:\CtvFTPSite\SA1\Invoices\Undelivered\",
"C:\CtvFTPSite\SA1\SO\Undelivered\"
)
$Max_mins = "-5"
$Curr_date = get-date
$username = "username#email.com"
$password = Get-Content C:\security\string.txt | ConvertTo-SecureString
$cred = new-object -typename System.Management.Automation.PSCredential `
-argumentlist $username, $password
$filesfailed = Get-ChildItem -Path $failedpath | Where{$_.CreationTime -lt ($Curr_date).addminutes($Max_mins)}
$localIpAddress = $(ipconfig | where {$_ -match 'IPv4.+\s(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' } | out-null; $Matches[1])
[string]$messagebody =""
[string]$titlefailed ="Urgent You Have Files in Undelivered Folder in $localIpAddress in $env:computername"
$portno = "25"
$smtpsrv = "mail.server.net"
$smtpto = "username#email.com"
$smtpfrom ="username#email.com"
if ($filesfailed.Count)
{
foreach ($file in $filesfailed) {[string]$messagebody += $file.FullName + "`r`n"}
Send-MailMessage -To $smtpto -From $smtpfrom -port $portno -SmtpServer $smtpsrv -Credential $cred -Subject $titlefailed -Body $messagebody
}

Related

PowerShell Email Attachment: Could not find file 'D:\20201124131044\TRACS-20201124034849\error.log environment.log RACS-20201124034849.sterr.stdout

I am trying to send out an email with only the attachments that exist in the directory. There are three sets of files i am monitoring: error.log, environment.log and a .stdout. I want to check whether each one of the files exist and if they do then add it in a list and send it out as attachments. I dont want to do anything if the files dont exist. I attempted to loop through the list of files (this is in windows) and then if the files exist send them out. My code below:
$PSEmailServer = "xxxxxxxxxxx"
$Password ="xxxxxxxxx"
$mypassword = ConvertTo-SecureString $Password -AsPlainText -Force
$mycredential = New-Object System.Management.Automation.PSCredential ("xxxxx", $mypassword)
$EmailSubject ="test"
$filepath ="D:\20201124131044\TRACS-20201124034849\"
$files = #('error.log','environment.log','TRACS-20201124034849.sterr.stdout')
$FromEmail ="xxxxxxxxxx"
if(($files | foreach{Test-path $filepath }) -contains $True){
$newfile = $filepath + $files
Send-MailMessage -From $FromEmail -To "xxxxxxx" -Subject $EmailSubject -Body "test" -Credential $mycredential -Attachments $newfile
}
else {
echo "nothing"
exit
}
when i run the above i get the following error:
Send-MailMessage : Could not find file 'D:\20201124131044\TRACS-20201124034849\error.log environment.log TRACS-20201124034849.sterr.stdout'. At C:\Users\Downloads\powershell.ps1:22 char:1
+ Send-MailMessage -From $FromEmail -To "xxxxxxx" -Subje ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Send-MailMessage], FileNotFoundException
+ FullyQualifiedErrorId : > System.IO.FileNotFoundException,Microsoft.PowerShell.Commands.SendMailMessage
I think I need to iterate the list to attach each filename to the it's filepath and then store it in a list and then send out the email? Please advise.
You can simply use -contains or -in to find filenames in an array.
Also, I would recommend using splatting for the parameters to Send-MailMessage:
$filepath = "D:\20201124131044\TRACS-20201124034849"
$files = 'error.log','environment.log','TRACS-20201124034849.sterr.stdout'
# find files with names that can be found in the $files array
$attachments = #(Get-ChildItem -Path $filepath -File | Where-Object { $files -contains $_.Name })
# if we have any files to send
if ($attachments.Count) {
$Password = "xxxxxxxxx"
$mypassword = ConvertTo-SecureString $Password -AsPlainText -Force
$mycredential = New-Object System.Management.Automation.PSCredential ("xxxxx", $mypassword)
# use splatting for better readability
$mailParams = #{
To = "xxxxxxx"
From = "xxxxxxxxxx"
Subject = "test"
Body = "test"
Credential = $mycredential
Attachments = $attachments.FullName
SmtpServer = "xxxxxxxxxxx"
# more parameters can be added here
}
# send the email
Send-MailMessage #mailParams
}
else {
Write-Host 'Nothing to send..'
}
Try
$PSEmailServer = "xxxxxxxxxxx"
$Password ="xxxxxxxxx"
$mypassword = ConvertTo-SecureString $Password -AsPlainText -Force
$mycredential = New-Object System.Management.Automation.PSCredential ("xxxxx", $mypassword)
$EmailSubject ="test"
$attachments = Get-ChildItem "D:\20201124131044\TRACS-20201124034849" | Where-Object {$_.Name -match "error.log|environment.log|TRACS-20201124034849.sterr.stdout"}
$FromEmail ="xxxxxxxxxx"
if($attachments){
Send-MailMessage -From $FromEmail -To "xxxxxxx" -Subject $EmailSubject -Body "test" -Credential $mycredential -Attachments $attachements
}
else {
echo "nothing"
exit
}

Script for sending e-mail

I found one script online, which does quite simple work - sends e-mail to the specified address after the trigger is hit.
In the example below script should scan the path which I stated for the trigger which is: #task, then it expected that it should send e-mail with the text after #td.
It should be correct, but when I run it nothing happens - what I'm doing wrong?
I've got the following message in powershell:
enter image description here
# Unregister-Event FileCreated
Unregister-Event FileChanged
# Email-settings
$loginuser = 'xxx#gmail.com'
$loginpassword = 'password;'
$smtpserver = 'smtp.gmail.com'
$smtpport = 587
$sendfrom = 'xxx#gmail.com'
$sendto = 'add.task.9270372.1523940684#todoist.net'
# Folder-settings
$folder = 'D:\Google Drive\Other\Nirvana' # Enter the root path you want to monitor.
$filter = '*.*' # You can enter a wildcard filter here.
# In the following line, you can change 'IncludeSubdirectories to $true if required.
$fsw = New-Object IO.FileSystemWatcher $folder, $filter -Property #{IncludeSubdirectories = $false; NotifyFilter = [IO.NotifyFilters]'FileName, LastWrite' }
# Trigger-settings
$trigger = '#task'
$lookfor = '#td'
$replaceto = '#intasklist'
Register-ObjectEvent $fsw Changed -SourceIdentifier FileChanged -Action {
$name = $Event.SourceEventArgs.Name
$changeType = $Event.SourceEventArgs.ChangeType
$timeStamp = $Event.TimeGenerated
$fileContent = (Get-Content $folder$name)
# Write-Host "The file '$name' was $changeType at $timeStamp" -fore green
if ($fileContent -match $trigger) {
$fileContent | Select-String -Pattern ".*$($lookfor)" -AllMatches | ForEach-Object { $_.Matches } | ForEach-Object { $secpasswd = ConvertTo-SecureString $loginpassword -AsPlainText -Force; $cred = New-Object System.Management.Automation.PSCredential ($loginuser, $secpasswd); Send-MailMessage -To $sendto -From $sendfrom -Subject $_.Value -Body $name -SmtpServer $smtpserver -Port $smtpport -Credential $cred -UseSsl
$fileContent | ForEach-Object { $_ -replace $lookfor, $replaceto -replace " $($trigger)", '' -replace $trigger, '' } | Set-Content $folder$name }
}}
# To stop the monitoring, run the following commands:
# Unregister-Event FileChanged

Powershell: Using send-mailmessage after PSFTP in script

I have written a small script that are using PSFTP to connect to a FTP server, download some files and conclude by sending an email with a summary of downloaded files.
I get a problem with the send-mailmessage part, which fails with this error:
Send-MailMessage : The remote certificate is invalid according to the validation procedure.
When running the send-mailmessage alone, it works flawlessly, it is only when using it combined with PSFTP, it fails. I am guessing, that it is the due to having made a session with the ftpserver, that somehow interferes, but that session should be ended when we come to the send mail. I can't figure this out, can anybody help?
My script:
#--------- FTP server variables here ------
$User = "XXX"
$Pass = "XXX"
$EncryptedPass = ConvertTo-SecureString -String $Pass -asPlainText -Force
$Credentials = New-Object System.Management.Automation.PSCredential($User,$EncryptedPass)
$Server = "XXX"
#-------- Mail credentials here -----------
$User_ = "XXX"
$Pass_ = "XXX"
$EncryptedPass_ = ConvertTo-SecureString -String $Pass_ -asPlainText -Force
$Mailcredentials = New-Object System.Management.Automation.PSCredential($User_,$EncryptedPass_)
#$mailcredentials =
$Subject ="'bowkerdownload'"
$To = "XXX"
$From = "XXX"
$body = (get-content -path g:\resultout.txt) -join "`n"
$SMTP = "smtp.office365.com"
#---------File variables here --------------
$month = (Get-Date).AddMonths(-8).ToString('MMM')
$year = (Get-date).addyears(-1).ToString('yyyy')
$filesequential="_*_"
$filesize = "lc"
$filetype = ".txt"
$samlevar=($month + ''+$year + ''+$filesequential + ''+$filesize + ''+$filetype)
$filename = $samlevar.tostring()
#------ The script---------
Set-FTPConnection -Credentials $Credentials -Server $server -Session defaultftpsession -UsePassive
$Session = Get-FTPConnection -Session defaultftpsession
Get-FTPChildItem -Path /Download -filter "$filename" |
Get-FTPItem -session $Session -LocalPath g:\ -Overwrite |
Convertfrom-string -PropertyNames Kode, Status, Action, fil |
Select-Object -Property Status, action, Fil |
Out-file g:\resultout.txt;
Send-MailMessage -To $To -Subject $Subject -Body $Body -SmtpServer $SMTP -From $From -Credential $Mailcredentials -port 587 -UseSsl``

Sending a properly email with line breaks

I am attempting to send the log files contents in the body of an email using Send-MailMessage. I tried using `r`n to no effect.
My email in outlook looks like the following....
My desired mail output :
Here is my script :
$SourceDir = "C:\Temp\"
#$GCI_Fiter = '*.txt'
$Include=#("*.log","*.txt")
$FileList = Get-ChildItem -LiteralPath $SourceDir -Include "$Include" -File
$myvar = #()
foreach ($FL_Item in $FileList) {
#$FLI_Content = Get-Content -LiteralPath $FL_Item.FullName
#$ExceptionLines = $FLI_Content | Select-String 'Exception' | ForEach-Object {$_.ToString().Trim()}
#if ($FLI_Content Get-Content -Path $file.FullName | Select-String "Exception" )
#){
$results = Get-Content -Path $FL_Item.FullName | Select-String "Exception"
if ($results) {
Write-Host "$($FL_Item.FullName) Exception found." -BackgroundColor Cyan
#$myvar += $results
$LINE = "$($FL_Item.Name)" + ":"
$EMAILBODY = $LINE + "`r`n"
$myvar += $EMAILBODY + $results + "`r`n"
Write-Output "Exception found"
}
else {
Write-Host "$($FL_Item.FullName) No exception found." -BackgroundColor Green
Write-Output "No exception found"
}
#}
#$ExceptionLines = $FLI_Content | Select-String -SimpleMatch 'Exception olustu'
#$ExceptionLines = $FLI_Content | Select-String -SimpleMatch 'Exception' | ForEach-Object {$_.ToString().Trim()}
#$FLI_Content
}
return $myvar
$MailBody = "Hi,`r
Exception logs. `r
"+$myvar+"
`r
`r
Regards,
"
Send-MailMessage -to $emailto -Subject $subject -SmtpServer $smtp -From $fromaddress -Body $MailBody -Encoding ([System.Text.Encoding]::UTF8) -Credential $creds
Another way is to use $Outlook = New-Object -ComObject Outlook.Application. I have come across a similar case. If you are using Outlook for example use the below code, however you format the email in the $Mail.Body, that is how they will receive the email.
$Outlook = New-Object -ComObject Outlook.Application
$Mail = $Outlook.CreateItem(0)
$Mail.To = "usermail#something.com"
$Mail.Subject = "Powershell"
$Mail.Body ="email text here"
$Date = (Get-Date).tostring("yyyyMMdd")
$File = "C:\Users\user\Desktop\log$Date.csv"
$Mail.Attachments.Add($File)
$Mail.Send()

Powershell Event Log Reporting

I'm working on a PS script to collect on certain Event IDs and spit them back every hour or so. I'm doing this because I want to spit it out to email for ease of reading.
My problem right now is that the script will run up to a certain point and hang. If I remove the date filters, it runs well. As soon as I re-add them (either through variables or hard-coded) it does it's hanging thing again. I need the date filters, however, because otherwise I'm getting everything when I'm looking for hourly chunks.
Looking for advice as I'd like to use variables for the one-offs or modifications! I'd also like to use spinoffs for other side reporting as well.
$filedate = (get-date).ToString("MM_dd_yy-hh_mm")
$filename = "bad_logins_DC01 " + $filedate + "_log.txt"
$after = (get-date).addhours(-1)
$before = (get-date)
$eventlog = Get-EventLog -ComputerName DC01 -LogName Security -After $after -Before $before
$eventlog | ?{$_.EventID -eq 4771 -or $_.EventID -eq 4776 } | Select #{Name="Event ID";Expression={$_.InstanceID}},#{Name="UserName";Expression={$_.ReplacementStrings[0]}},#{Name="Failure Code";Expression={$_.ReplacementStrings[4]}},#{Name="Host";Expression={$_.ReplacementStrings[6]}},#{Name="Port";Expression={$_.ReplacementStrings[7]}}, #{Name="Time";Expression={$_.TimeGenerated}} | ft | Out-File $filename -append -noclobber
$to = itsupport#ourdomain.com
$from = itsupport#ourdomain.com
$subject = $filename
$smtp = exchange.ourdomain.com
$contents = cat $filename
$body = $contents
Send-MailMessage -SmtpServer $smtp -To $to -From $from -Subject $subject -Body $body -Attachments $filename
Got it!
Big thanks to TheMadTechnicial for the assist on Get-WinEvent instead of Get-EventLog
$query_sec = #"
<QueryList>
<Query Id="0" Path="Security">
<Select Path="Security">*`
[System[Provider[#Name='Microsoft-Windows-Security-Auditing'] and `
TimeCreated[timediff(#SystemTime) <= 7200000] and `
(EventID=4771 or EventID=4776)]]</Select>
</Query>
</QueryList>
"#
$time = (Get-Date).ToString("dd-MM_hh-mm")
$to = "itsupport#mydomain.com"
$from = "me#mydomain.com"
$smtpServer = "mxserver.mydomain.com"
Try
{
$domain_controller = "DC01","C02","DC03"
ForEach ($dc in $domain_controller)
{
$Events = Get-WinEvent -ComputerName $dc -FilterXml $query_sec -ErrorAction Stop
ForEach ($event in $Events)
{
$eventXML = [xml]$Event.ToXml()
For ($i=0; $i -lt $eventXML.Event.EventData.Data.Count; $i++)
{
Add-Member -InputObject $Event -MemberType NoteProperty -Force `
-Name $eventXML.Event.EventData.Data[$i].Name `
-Value $eventXML.Event.EventData.Data[$i].'#text'
}
}
$filename = "C:\temp\"+$dc+"_failed_logins_"+$time+".txt"
$Events | Select-Object #{Name="UID";Expression={$_.TargetUserName}},`
ServiceName,`
#{Name="Error";Expression={$_.Status}},`
#{Name="IP";Expression={$_.IpAddress}},`
#{Name="Port";Expression={$_.IpPort}},`
#{Name="Event ID";Expression={$_.ID}},`
#{Name="Source";Expression={$_.MachineName}}`
| FT `
| Out-File $filename
$subject = "Bad Logins on " + $dc + " at " + $time
$body = Get-Content -Path $filename -Raw
Send-MailMessage -To $to -Subject $subject -From $from -SmtpServer $smtpServer -Body $body
}
}
Catch [Exception]
{
Write-Output " "
Write-Output "$dc has no relevant event logs!"
}