I am trying to create an alert that will look at directories and email a listing of all files that are 1kb or less. Currently it is sending one email for every file. I want the offending files to be in one email.
$date= Get-Date -Format yyyyMMdd
$path= "c:\test\$date"
$files = Get-ChildItem -Path $path -Recurse
$body = "These files are too small."
$body += "<table><tr><td><b>Filename</b></td></tr>";
foreach ($file in $files) {
if ($file.Length -lt 1kb) {
$body += "<tr><td>" + $($file.Name) + "</td></tr>"
}
};
$body += "</table>"
foreach ($item in [System.IO.Directory]::GetFiles($path)) {
$a=get-item($item)
if ($a.Length -lt 1kb) {
Send-MailMessage -From noreply#email.com -To person#email.com -Subject "Files small" -Body $body -BodyAsHtml -SmtpServer 0.0.0.0
}
}
You're looping twice. Simply remove the loop around Send-MailMessage:
$body += "<table><tr><td><b>Filename</b></td></tr>"
foreach ($file in $files) {
if ($file.Length -lt 1kb) {
$body += "<tr><td>" + $($file.Name) + "</td></tr>"
}
}
$body += "</table>"
Send-MailMessage -From noreply#email.com -To person#email.com -Subject "Files small" -Body $body -BodyAsHtml -SmtpServer 0.0.0.0
You can add a flag variable to indicate whether files were found or not:
$body += "<table><tr><td><b>Filename</b></td></tr>"
foreach ($file in $files) {
if ($file.Length -lt 1kb) {
$fileFound = $true
$body += "<tr><td>" + $($file.Name) + "</td></tr>"
}
}
$body += "</table>"
if ($fileFound) {
Send-MailMessage -From noreply#email.com -To person#email.com -Subject "Files small" -Body $body -BodyAsHtml -SmtpServer 0.0.0.0
}
Related
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!"
}
I am trying to set up a PowerShell script which reads out a UNC path on Windows and searches for longfiles/paths. After it has found the file it needs to send a mail to the owner of the file.
I have found already a script and tweaked it a bit but it doesn't seems to work yet. The following script can find the long file path now but the mail is not working properly.
$limit = 90
$testpath = "C:\test"
$resultpath = "c:\test"
$admins = "moh#test.com"
$from = "moh#test.com"
$smtpserver = "smtp.office365.com"
Get-ChildItem -Path $testpath -Recurse | ?{$_.fullname.length -gt $limit} |
Select-Object fullname,
#{n="owner";e={
$_.GetAccessControl().GetOwner('System.Security.Principal.NTAccount')}},
#{n="namelength"; e={$_.fullname.length}} |
%{
Out-File -FilePath "$resultpath\Longfiles of $($_.owner -replace "\\","-").txt" -Append -InputObject "$($_.namelength) - $($_.fullname)"
}
Get-ChildItem $resultpath -Filter "longfiles of *" | % {
if($_.name -match "Longfiles\sof\s(.+)\.txt"){
$user = $matches[1] -replace "-","\"
$ntacc = New-Object System.Security.Principal.NTAccount($user)
$sid = $ntacc.Translate([System.Security.Principal.SecurityIdentifier])
$aduser = [ADSI]"LDAP://<SID=$sid>"
$email = $aduser.Properties.mail
if($email) {Send-MailMessage -Attachments $_.fullname -Body "Please change the filenames of the files listed in the attached file to shorter!"
-From $from -SmtpServer $smtpserver -Subject "System notice" -To
$email -cc $admins
}
else {
Send-MailMessage -Attachments $_.fullname -Body "email coudn't be sent to owner" `
-From $from -SmtpServer $smtpserver -Subject "System notice" -To $admins
}
}
else {Write-Host "Some error with file $_"}
}
EDIT: This is what i see, after running the script... it is asking me to fill in the fields, while the fields are already filled in in the script such as (From: moh#test.com to moh#test.com)
[]
You issue was because of line breaks in the middle of a command. In some lines, you had a backtick character which escapes the end of the line. But as you found these are really easy to break and that's why it's best practice to use splatting on commands with many parameters.
I also changed your Select-Object calculated properties into a more readable [pscustomobject] since they are hard to format in a readable way, but this does require PS3+.
$limit = 90
$testpath = "C:\test"
$resultpath = "c:\test"
$admins = "moh#test.com"
$from = "moh#test.com"
$smtpserver = "smtp.office365.com"
Get-ChildItem -Path $testpath -Recurse |
Where-Object {$_.fullname.length -gt $limit} |
ForEach-Object {
[PSCustomObject]#{
'fullname' = $_.fullname
'owner' = $_.GetAccessControl().GetOwner('System.Security.Principal.NTAccount')
'namelength' = $_.fullname.length
}
} |
ForEach-Object {
Out-File -FilePath "$resultpath\Longfiles of $($_.owner -replace "\\","-").txt" -Append -InputObject "$($_.namelength) - $($_.fullname)"
}
Get-ChildItem $resultpath -Filter "longfiles of *" | ForEach-Object {
if ($_.name -match "Longfiles\sof\s(.+)\.txt") {
$user = $matches[1] -replace "-", "\"
$ntacc = New-Object System.Security.Principal.NTAccount($user)
$sid = $ntacc.Translate([System.Security.Principal.SecurityIdentifier])
$aduser = [ADSI]"LDAP://<SID=$sid>"
$email = $aduser.Properties.mail
if ($email) {
$mailparams = #{
'Attachments' = $_.fullname
'Body' = "Please change the filenames of the files listed in the attached file to shorter!"
'From' = $from
'SmtpServer' = $smtpserver
'Subject' = "System notice"
'To' = $email
'cc' = $admins
}
Send-MailMessage #mailparams
} else {
$mailparams = #{
'Attachments' = $_.fullname
'Body' = "email coudn't be sent to owner"
'From' = $from
'SmtpServer' = $smtpserver
'Subject' = "System notice"
'To' = $admins
}
Send-MailMessage #mailparams
}
} else {
Write-Host "Some error with file $_"
}
}
Remove the line breaks or escape them with a backtick: `. Your script must actually look like this:
if ($email) {
Send-MailMessage -Attachments $_.fullname -Body "Please change the filenames of the files listed in the attached file to shorter!"
-From $from -SmtpServer $smtpserver -Subject "System notice" -To
$email -cc $admins
}
else {
Send-MailMessage -Attachments $_.fullname -Body "email coudn't be sent to owner" `
-From $from -SmtpServer $smtpserver -Subject "System notice" -To $admins
}
And Powershell doesn't know that the line beginning with -From is part of Send-MailMessage.
I have this code:
Clear-Host
$file = "c:\Mail-content.txt"
if (test-path $file)
{
$from = "afgarciact#gmail.com"
$to = "<slopez#comfama.com.co>","<carloscu#comfama.com.co>"
$pc = get-content env:computername
$subject = "Test message " + $pc
$smtpserver ="172.16.201.55"
$body = Get-Content $file | Out-String
[System.Net.ServicePointManager]::SecurityProtocol = 'Tls,TLS11,TLS12'
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = { return $true }
foreach ($recipient in $to)
{
Write-Host "Sent to $to"
Send-MailMessage -SmtpServer $smtpserver -UseSsl -From $from -To $recipient -Subject $subject -BodyAsHtml $body -Encoding ([System.Text.Encoding]::UTF8)
}
}
else
{
Write-Host "ConfiguraciĆ³n"
}
I want to know if I can use a CRT certificated instead of setting ServerCertificateValidationCallback = TRUE.
This is a test environment.
The CRT certificate was already added to the SMTP server.
I have written a script which monitors specific folder space monitoring and it alerts me once it crosses the threshold. Issue what i am facing is with multiple servers in place i am getting multiple emails so is it possible that we can consolidate the results in one mail having all servers which having issue. Below is script:-
$servers = Get-Content C:\server.txt
$folder = "D$\store\"
$smtpserver = "XXXXXX"
#(
foreach ($Server in $Servers)
{
$folderSize = ( Get-ChildItem -path \\$server\$folder -Recurse -Force | Measure-Object -Property Length -Sum ).Sum
if ($folderSize -gt '60Gb') {
Write-output "Folder size exceeded 60 GB on server:-$Server. Current size on $server is $folderSize. Please review and take further action." | Out-file -FilePath "C:\reslt.txt"
Send-MailMessage -to abc#abc.com -from xx#xx.com -Subject "Limit Alert" -SmtpServer $smtpserver -Attachments "C:\reslt.txt"
}
else { Write-output "Folder size is within 60GB on $server." }})
You should post what you've tried. That being said, here's a start, written in notepad, so excuse any slight issues. You should probably just take results and instead of iterating over them, make them into a table, set the email to be HTML, and put the result of the table converted into an HTML snippet into the body of the message.
$servers = Get-Content C:\server.txt
$folder = "D$\store\"
$smtpserver = "XXXXXX"
$results = #()
foreach ($Server in $Servers) {
$folderSize = ( Get-ChildItem -path \\$server\$folder -Recurse -Force | Measure-Object -Property Length -Sum ).Sum
if ($folderSize -gt '60Gb') {
Write-Output "Folder size exceeded limit on $server"
$results += New-Object -TypeName PSObject -Property #{
ServerName = $Server
FolderSize = $folderSize
}
}
else { Write-output "Folder size is within 60GB on $server." }
}
if ($results.Count -gt 0){
$bodyString = "Servers over limit:"
#I'd get fancy here and take $results, format it as a table, and then convert to HTML and put the snippet in the body...
$results | % {$bodyString += "The server "+$_.ServerName+"is over the limit and is currently at "+$_.FolderSize+"GB`r`n"}
Send-MailMessage -to abc#abc.com -from xx#xx.com -Subject "Limit Alert" -SmtpServer $smtpserver -Body $bodyString
}
else {
Send-MailMessage -to abc#abc.com -from xx#xx.com -Subject "Limit Alert - no results" -SmtpServer $smtpserver -Body "No results were found for servers over the limit"
}
I have two different folders containing two text files, the goal is to send both txt files in an email using PowerShell.
The first file is stored in log and the other one in Error. I found a helpful PowerShell script to do so, however I was not sure how to add both attachments in same email and in the body having two lines for each of the attachments. Below is the script, any help is appreciated:
# Date values to find related log file for the day and hour or the run
$y = Get-Date -format yyyy
$m = Get-Date -format MM
$d = Get-Date -format dd
$h = Get-Date -format 05
# Modify the log path
$LogPath = "C:\Program Files\Logs\"
$LogFile = $LogPath + "Log_" + $y + $m + $d + "_" + $h + "*.txt"
$LogFileName = $LogFile | ? {Test-Path $LogFile} | Get-ChildItem | Where-Object { $_ -is [System.IO.FileInfo] }
$LogPath1 = "C:\Program Files\ERROR\"
$LogFile1 = $LogPath1 + "Log_" + $y + $m + $d + "_" + $h + "*.txt"
$LogFileName1 = $LogFile1 | ? {Test-Path $LogFile} | Get-ChildItem | Where-Object { $_ -is [System.IO.FileInfo] }
$MessageBodyNA = "Email from scheduler. No log file found " + $LogFile
$MessageBodyA = "Email from scheduler. File" + $LogFileName + " found and attached"
$MessageBodyNA1 = "Email from scheduler. No log file found " + $LogFile1
$MessageBodyA1 = "Email from scheduler. File(s) " + $LogFileName1 + " found and attached"
$FromAddress = "test#gmail.com"
$ToAddress = "test1#gmail.com"
$Subject = "test"
$SMTPserver = "SMTPServerName.com"
if ( $LogFileName | Where-Object { $_ -is [System.IO.FileInfo] })
{
send-mailmessage -from $FromAddress -to $ToAddress -subject $Subject -body $MessageBodyA -smtpServer $SMTPserver -Attachments $LogFileName
}
else
{
send-mailmessage -from $FromAddress -to $ToAddress -subject $Subject -body $MessageBodyNA -smtpServer $SMTPserver
}
if ( $LogFileName1 | Where-Object { $_ -is [System.IO.FileInfo] })
{
send-mailmessage -from $FromAddress -to $ToAddress -subject $Subject -body $MessageBodyA1 -smtpServer $SMTPserver -Attachments $LogFileName1
}
else
{
send-mailmessage -from $FromAddress -to $ToAddress -subject $Subject -body $MessageBodyNA1 -smtpServer $SMTPserver
}
When in doubt, read the documentation. The -Attachment parameter accepts a string array, so you can attach multiple files like this:
Send-MailMessage -From $FromAddress -To $ToAddress -Subject $Subject `
-Body $MessageBodyA -SmtpServer $SMTPserver `
-Attachments $LogFileName, $logFileName1
A multiline body can easily be created by using a multiline string:
$MessageBody = #"
This is line 1.
This is line 2.
"#
or by concatenating multiple lines:
$line1 = "This is line 1."
$line2 = "This is line 2."
$MessageBody = "$line1`n`n$line2"
This shows how to attach multiple files and multiple lines in mail body (please note that I didn't tested this)
function sendMail{
#SMTP server name and other mail parameters
$smtpServer = "smtp.bethanie.com.au"
$OFS = "`r`n`r`n"
$a = get-date
$SourceDir = "C:\Source\"
$DestDir = "C:\Dest\"
$files = get-childitem $SourceDir | where name -like "*.txt"
$attachments = #()
$msgFrom = "abc#abc.com"
$msgTo = "abc#abc.com"
$msgsubject = "Automated Task(" + $a + " )"
$msgBody = "This is an automated mail" + $OFS + "Check the attached file"
# Attach files of specific types
foreach($file in $files){
$filename = [system.io.path]::GetFileName($file.FullName)
$attachments += $file.fullname
}
Send-MailMessage -to $msgTo -From $msgFrom -SmtpServer $smtpServer -Subject $msgsubject -BodyAsHtml $msgBody -Attachments $attachments
}
#Calling function
sendMail