Setting counter on Windows Event log for Email notification - windows

I am having below script:
$pattern = 'Unable to authenticate user!'
$events = Get-WinEvent -ea SilentlyContinue `
-ProviderName "Windows DB Controller - Task Manager Service"|
Where-Object { $_.TimeCreated -gt [datetime]::today -and $_.Message -match $pattern }
$events >> D:\Error.txt
if ($events) {
Send-MailMessage -SmtpServer smtp.domain.com -From No-reply#domain.com -To sunny#domain.com -Subject 'Error found in log' -Body $events
}
I had scheduled it to run on every 10 mins and purposely ,I wanted to achieve following point using above script:
Search the specified error message in the event viewer log only for current-date and as soon as the error message encountered send a email notification to me but didn't want to receive email notification for the error message which appreared today and for which I had already been notified (I mean , wanted to receive error-notification only once for a specific time of current day).
But problem I am facing here is: Getting multiple notifications for same error message for which already being notified.
I hope I am clear enough to put my exact problem.
Could you please help me out, how to resolve this problem ?

If you are running the script every 10 minutes, I would change the condition on the Where-Object so instead of getting all of the events that are "today"; I would change it to get only the events that happened in the last 10 minutes. i.e. the code becomes:
Where-Object { $_.TimeCreated -gt [datetime]::now.AddMinutes(-10) -and $_.Message -match $pattern }

Have a look at this thread:
Powershell - Tail Windows Event Log? Is it possible?
It's on tailing an event log, but the same method should work for what you're tyring to do. Just save the last index number to a file between runs.

How about the following approach:
Register-WmiEvent -Query "select * from __InstanceCreationEvent where TargetInstance ISA 'Win32_NTLogEvent' and TargetInstance.SourceName = 'Windows DB Controller - Task Manager Service' and TargetInstance.Message LIKE '%Unable to authenticate user!%'" -SourceIdentifier "MyEventListener" -Action {
#Your actions
write-host "$($eventargs.NewEvent.TargetInstance.RecordNumber) at $($eventargs.NewEvent.TargetInstance.TimeGenerated)"
}
It uses WMI to subscribe to the event that occurs when an eventlog entry is generated with your criterias. The action itself will only return the new object(so no more duplicates). I've included a sample action to help you understand how to access the object. This method will give you live monitoring.
Inside the action, $eventargs.NewEvent.TargetInstance will give you the object which is an instance of win32_ntlogevent. To see properties of this class, check out TechNet or run the following command:
([wmiclass]'win32_ntlogevent').Properties | ft Name
To make the script run forever, just call your script with powershell -file script.ps1 -noexit or include a while($true) loop at the end of your script. (I'm not sure how the while-loop will affect resource usage longterm, you'd have to test).

Related

Get hard drives SMART data with email notifications using PowerShell

if
I want to use internal Windows resources to follow server disks health. So, I would like to schedule a PowerShell script on several servers. The script should take each server hard drives SMART status and send appropriate emails (through my internal SMTP server) to me. Some servers could contain more than one HDD.
My initial script is Ok and works fine:
$emailto="admin#example.com"
$emailfrom="$env:COMPUTERNAME#example.com "
$emailserver="smtp.example.com "
$output = Get-WmiObject -query "Select * from Win32_diskdrive" | select Model, Status | out-string
function send-email
{
$EmailSubj = "Disks SMART report on $env:COMPUTERNAME"
$EmailBody = $output
Send-MailMessage -To "$emailto" `
-From "$emailfrom" `
-Subject "$EmailSubj" `
-Body "$EmailBody" `
-smtpServer "$emailserver"
}
send-email
Typical output is something like this:
Model Status
----- ------
ST2000NC000 OK
ST2000NC000 OK
ST2000NC000 OK
ST2000NC000 OK
The question is how to avoid a lot of spam and email only if BAD statuses available? I would like to filter Get-WmiObject results in order to get the mails ONLY if at least one HDD status will not be "OK". I am not sure but there should be also "Degraded" and "Pred Fail" statuses. I tried different foreach and If/Else combinations, but I cannot find method how to force PowerShell check "OK" string from the Status property (and also for each HDD) to get my goal. Can someone help me, please?
If you lose the out-string, you will have access to the object properties and will be able to filter on status not being OK.
But just a thought, I would rather have lots of emails as that way I would know the script is running or at least an email saying server 1 has no bad sectors etc...
$output = Get-WmiObject -query "Select * from Win32_diskdrive" | select Model, Status | where status -ne "OK"
$output = Get-WmiObject -query "Select * from Win32_diskdrive" | select Model, Status
| where-object {$_.Status -ne "OK"} | Out-String
Outputs drives if their status is not equal to "OK". This should account for any other status options, including "BAD".

Powershell script: List files with specific change date (Amount if possible)

For license porpuses I try to automate the counting process instead of having to login into every single server, go into directory, search a file name and count the results based on the change date.
Want I'm aiming for:
Running a powershell script every month that checks the directory "C:\Users" for the file "Outlook.pst" recursively. And then filters the result by change date (one month or newer). Then packing this into an email to send to my inbox.
I'm not sure if that's possible, cause I am fairly new to powershell. Would appreciate your help!
It is possible.
I dont know how to start a ps session on a remote computer, but I think the cmdlet Enter-PSSession will do the trick. Or at least it was the first result while searching for "open remote powershell session". If that does not work use the Invoke-Command as suggested by lit to get $outlookFiles as suggested below.
For the rest use this.
$outlookFiles = Get-ChildItem -Path "C:\Users" -Recurse | Where-Object { $_.Name -eq "Outlook.pst" }
Now you have all files that have this name. If you are not familiar with the pipe in powershell it redirects all objects it found with the Get-ChildItem to the next pipe section and here the Where-Object will filter the received objects. If the current object ($_) will pass the condition it is returned by the whole command.
Now you can filter these objects again to only include the latest ones with.
$latestDate = (Get-Date).AddMonths(-1)
$newFiles = $outlookFiles | Where-Object { $_.LastAccessTime -gt $latestDate }
Now you have all the data you want in one object. Now you only have to format this how you like it e.g. you could use $mailBody = $newFiles | Out-String and then use Send-MailMessage -To x#y.z -From r#g.b -Body $mailBodyto send the mail.

Receive-Job different than direct call

Needed to change my code from direct call to Start-Job precedure because of timeouts caused by Symantec Antivirus (SEP) v14, making my script hanging.
this snap was working fine so long:
$updateDaten = Get-HotFix -computername "myserver" | % { $_.psbase.properties["installedOn"].Value } | Group-Object | select-object Name
The change to a start-job preocedure completely messes up the resulting object. im googling and testing for two days now but cannot find out what's so complicatet in dealing with job objects:
function Get-HotfixesListAsJob($computer, $timeout){
$job = Start-Job { param($c) Get-HotFix -computername $c |
% { $_.psbase.properties["installedOn"].Value } | Group-Object
} -ArgumentList $computer
Wait-Job $job -Timeout $timeout
Stop-Job $job
Receive-Job $job
Remove-Job $job
}
$updateDaten = Get-HotfixesListAsJob -computer "myserver" -timeout 80
However I am not able to get the same result back using Receive-Job. I Always get some wired job-object and I am not able to just extract the data as it was before. Why is the result so completely different? is it possible to get just the data back in an object as it was before instead of a job object?
btw. this interesting article did not solve my problem:
https://learn-powershell.net/2014/06/27/quick-hits-did-i-really-lose-my-output-with-receive-job-by-not-usingkeep/
Thanks for your answers in advance
The issue what you are having is not because of the code. Its because Start-job or any PS Job session, basically, will have all the details, properties related to that job.
So, I can see in the first case you have done a grouping and finally selecting only the name which is not there in the later case.
So I would suggest you to add that to the Function also.
One more thing , Wait-job will also output the value in the console. Either redirect or pipe it to null in order to avoid that.
You can also receive the job using receive-job with the job id or the name. I think that will be better. Just check the status of the job; Once done receive it.

Powershell giving wrong output after scheduling with window's task scheduler

I have a PowerShell script to check the password expiry date of the a system user and send a mail if it is going to expire within 10 days. Script works fine when we run it stand alone. But it show abnormal behaviour after scheduling it with windows task scheduler. Sometimes it works perfectly fine and sometimes it's not.
Output: Password will Expire in -736235 Days.
Expected output: Password will Expire in Days.
It always give -736235 days when if runs incorrectly.
Here is the configuration,
1.General tab
- Run whether user logged in or not
- Run with highest Privilege
- Configure for : Windows server 2012 R2
Action Tab
Program/script: PowerShell
-Add Argument: .\ps.ps1
Start in: D:
Setting Tab(Following Options are checked)
-Allow task to run on demand
Stop task if it running from: 3 days
-if the running task doesn't stop when requested, force stop
If the task is already running then following rule will apply: Stop the existing instance.
Please let me know if you need any other details,
Thanks,
Navdeep
Script is,
$user = Get-ADUser -filter {Enabled -eq $True -and PasswordNeverExpires -eq $False -and Name -eq "<user_name>" } –Properties "DisplayName", "msDS-UserPasswordExpiryTimeComputed" | Select-Object -Property "Displayname",#{Name="ExpiryDate";Expression={[datetime]::FromFileTime($_."msDS-UserPasswordExpiryTimeComputed")}}
$DayCount = $user.ExpiryDate - (GET-DATE)
$DayAbsCount = $DayCount.Days
$message.body = "Password will Expire in $DayAbsCount Days.Please reset."
if ( $DayAbsCount -lt 10)
{
$smtp = new-object Net.Mail.SmtpClient($smtpserver)
$smtp.Send($message)
}
,
and the script is running from the same account whose pwd expiration date we needed.

How to detect if there is any file added in a folder?

Is it a way to detect if there is any file added in a folder? Include the sub-folder.
For example, check if any text file *.txt is added in folder c:\data-files\ or its sub-folders.
The folder can be shared folder of another machine too.
Perhaps you are confused on the types of events that are triggered:
http://msdn.microsoft.com/en-us/library/system.io.filesystemwatcher_events(v=vs.110).aspx
This should work, taken from the link above and modified for your requirements:
#By BigTeddy 05 September 2011
#This script uses the .NET FileSystemWatcher class to monitor file events in folder(s).
#The advantage of this method over using WMI eventing is that this can monitor sub-folders.
#The -Action parameter can contain any valid Powershell commands. I have just included two for example.
#The script can be set to a wildcard filter, and IncludeSubdirectories can be changed to $true.
#You need not subscribe to all three types of event. All three are shown for example.
# Version 1.1
$folder = '\\remote\shared' # Enter the root path you want to monitor.
$filter = '*.txt' # 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 = $true;NotifyFilter = [IO.NotifyFilters]'FileName, LastWrite'}
# Here, all three events are registerd. You need only subscribe to events that you need:
Register-ObjectEvent $fsw Created -SourceIdentifier FileCreated -Action {
$name = $Event.SourceEventArgs.Name
$changeType = $Event.SourceEventArgs.ChangeType
$timeStamp = $Event.TimeGenerated
Write-Host "The file '$name' was $changeType at $timeStamp" -fore green
Out-File -FilePath c:\scripts\filechange\outlog.txt -Append -InputObject "The file '$name' was $changeType at $timeStamp"}
Please note that once you close the powershell console the fileSystemWatcher is thrown away, and will no longer monitor the folder(s). So you have to make sure the powershell window stays open. In order to do that without it getting in your way I suggest a scheduled task http://blogs.technet.com/b/heyscriptingguy/archive/2011/01/12/use-scheduled-tasks-to-run-powershell-commands-on-windows.aspx

Resources