Powershell Event Log Reporting - powershell

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!"
}

Related

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()

Sending foreach output via email

I have a script that is checking mirror status of databases. Output in Powershell is fine, but when I try to send it via mail, I'm getting "Microsoft.PowerShell.Commands.Internal.Format.FormatEntryData" instead of data itself. I've tried to change it to Out-String but then I'm getting all results in one line. How this could be done to have formated output the same way as it is formated directly in PowerShell?
# rozszerzenie do obslugi
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo") | Out-Null;
$mail_from = "xxx";
$mail_to = "xxx";
$mail_subject = "Status mirrorowanych baz";
$mail_encoding = "UTF8";
$mail_smtp = "xxx";
# lista serwerow
$list = #("SERVER01V",
"SERVER02V"
);
$output = foreach($server in $list)
{
$srv = New-Object "Microsoft.SqlServer.Management.Smo.Server" $server;
# pokaz tylko mirrorowane
$databases = $srv.Databases | Where-Object {$_.IsMirroringEnabled -eq $true};
Write-Output "<br>==================================<br>";
Write-Output $server;
Write-Output "<br>==================================<br>";
$databases | Select-Object -Property Name, MirroringStatus | Format-Table -AutoSize | Out-String;
Write-Output "<br>";
}
$mail_body = $output;
Send-MailMessage -To $mail_to -From $mail_from -Subject $mail_subject -SmtpServer $mail_smtp -Encoding $mail_encoding -Body $mail_body -BodyAsHtml
You're currently sending a HTML mail. As such line breaks won't matter. If you want line breaks in your mail you either need to use text format or replace line breaks with a <br /> or something similar. It's probably going to be wise to have manually add <br /> in your look to have a consistent pattern and replace.
Try gather all data into an array, then use ConvertTo-HTML cmdlet, and the 'BodyAsHTML' switch in Send-MailMessage
$DatabaseArray=#()
ForEach ($server in $list) {
$srv = New-Object "Microsoft.SqlServer.Management.Smo.Server" $server
$DatabaseArray += $srv.Databases | Where-Object {$_.IsMirroringEnabled -eq $true} | Select-Object Name,MirroringStatus
}
$HTMLBody = $DatabaseArray | ConvertTo-HTML
Send-MailMessage -subject x -body $HTMLBody -BodyAsHTML

Powershell search for longfile path names and send the owner of a file a mail to do something about it

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.

Powershell Script to Monitor Folder Space

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"
}

Sending multi line of body and multiple attachments

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