Automatic conversion of evtx to plaintext logs - powershell

I have a Windows Server 2008 running MicroSoft Exchange. The Audit Logs are stored in evtx and I am trying to export the logs to a 3rd party collector. The agents we have used (Snare Epilog, open source among them) do not recognized the evtx format and do not forward them to the collecting server.
I am attempting to implement a workaround via Powershell and Task Scheduler. The problem I am facing is that while I can access the evtx and save it as a .txt, I am reparsing the entire log every time. However, I would like to only send the new events every 5 minutes or less.
The code I am using is this:
$File = "C:\text.txt; Get-WinEvent -Path C:\test.evtx | Format-Table -AutoSize | Out-File $File -append -width 750
I really appreciate the help!

You could use Get-EventLog, rather than Get-WinEvent, then use the After parameter to only get the last five minutes of events or better still keep track of the most recent event message you have seen.
Here's how to get the last five minutes of the Application log.
Get-EventLog -LogName Application -After $((Get-Date).AddMinutes(-5))

Related

Scheduling a Powershell process does not yield the same results as when I run it manually

I wrote a small PowerShell script that I am using to query the Server Log, clean the return values and use some of the results to perform some server maintenance. However, when I schedule the save to file piece is not writing the whole content to the file and it is getting truncated, just like what I ma posting below, exactly. As you can observe, the end of the file is truncated with three dots added to replace the missing values:
Login failed for user 'sa'. Reason: An error occurred while evaluating the password. [CLIENT: 2...
However, if I run the code manually with Local Admin access, the content gets saved to the local file like this, exactly:
Login failed for user 'sa'. Reason: An error occurred while evaluating the password. [CLIENT: 112.103.198.2]
Why is this the case when I schedule the process or PS file to run under a schedule. BTW, I tried to run it under the SYSTEM context with full or highest privileges and even used the same Admin account that I use to run it manually to schedule and still do nt get the full content of the event that I save.
This is creating an issue and I am not able to use the content to process the IP.
Here is the PS code that I am using to query and save the content to file:
$SQL = 'C:\SQL.txt'
Remove-Item $SQL -ErrorAction Ignore
Get-EventLog -LogName Application | Where-Object {$_.EventID -eq 18456} |
Select-Object -Property Message | Out-File $SQL
The problem lies with out-file because it has a default character limit of 80 per line.
You can change it with -width property and give a value of say 200. However set-content doesn't have these limits set in. So it might be a more suitable option.
All that being said, I am not sure why it does it one way when ran manually vs another when the system runs it.
Out-file defaults to unicode when writing files
set-file defaults to ascii when writing files

Is there a way to find which user run what application on a server using Powershell

I am trying to find a way to find out who has ran an application (for example SQL) on a server, just to get some idea.
I tried Get-Process but this doesn't give me historic information, I want to get historical information
Get-Process -IncludeUserName *
what I want the return resule is "name of application", "user who ran it" and the last datetime it was ran by that user'
As for ...
I am trying to find a way to find out who has ran an application (for
example SQL) on a server, just to get some idea.
What you are asking for here is software metering.
SQL is a service that is always running once it is installed, so, no individual user is ever going to be running it. So, that is a bad example. MS Word for example would be a better example.
Yet there is nothing native in PowerShell that does this, software metering, but of course PowerShell can look at event logs. Yet if your auditing is not setup correctly then it's moot. This is better for a software metering tool, and there are several out there. So, why try and reinvent the wheel.
As for ...
I tried Get-Process but this doesn't give me historic information, I
want to get historical information
That is not what a process is nor what Get-Process is for. It, Get-Process only checks for and lists whatever process is currently running, regardless of what/who launched it.
As for...
what I want the return resule is "name of application", "user who ran
it" and the last datetime it was ran by that user'
As long as the process is running, you can get this, with that cmdlet.
However, what are you trying to accomplish by this?
Again, there are purpose built tools to meter software use.
https://learn.microsoft.com/en-us/sccm/apps/deploy-use/monitor-app-usage-with-software-metering
If you must go down this reinvent the wheel road, using scripting, then you need a task watcher on the target machines, which watches for the WinWord process to appear.
Get-Process -IncludeUserName |
Where ProcessName -EQ 'Winword'
... you then write those results to a file or database or your own event log each time you see that process.
Use PowerShell to Create and to Use a New Event Log
New-EventLog -LogName ScriptingGuys -Source scripts
When the command runs, no output appears to the Windows PowerShell console. To ensure the command actually created a new event log, I use
the Get-EventLog cmdlet with the –List parameter. Here is the command
and the associated output.
Write-EventLog -LogName ScriptingGuys -Source scripts -Message “Dude, it works … COOL!” -EventId 0 -EntryType information
Or just to a file
Get-Process -IncludeUserName |
Where ProcessName -EQ 'Winword' |
Select-Object -Property Name, StartTime, Username |
Export-Csv -Path 'F:\Temp\AppLaunchLog.csv' -Append
Import-Csv -Path 'F:\Temp\AppLaunchLog.csv'
# Results
Name StartTime UserName
---- --------- --------
WINWORD 5/23/2019 9:02:53 PM WS01\LabUser001

Sent mail based on time that previous mail was sent

I have a script that checks if a site is online and sends a mail if it's down.
The script is configured with a scheduled task that runs every 30 minutes.
The problem is the following:
If the site is down during the weekend or evening (or a day when i'm not monitoring the mailbox), the mails keep being sent.
I was wondering, what method could I use to only send mails if the last time a mail was sent was 3 hours before?
Based on this way, i can send a mail only once every 3 hours.
I have researched the use of registry keys but was wondering if this would be the correct approach.
Rather than the registry, I'd use a simple configuraiton file stored in ProgramData (or AppData should you need a per user configuration)
This make the process of loading / saving parameters and adding new ones very easy.
Also, should you need to save logs and / or other data, you can just put them inside that same folder.
$ConfigFullPath = "$env:APPDATA\My Monitoring solution\config.json"
# This create the config file if none is present.
if (-not (Test-Path $ConfigFullPath)) {
New-Item -ItemType File -Path $ConfigFullPath -Value ([PSCustomObject]#{'LastEmailSent' = [datetime]::MinValue}| ConvertTo-Json) -Force
}
$ConfigFileParams = ConvertFrom-Json -InputObject (get-content "$env:APPDATA\My Monitoring solution\config.json" -raw)
$SendEmail = ([Datetime]::UtcNow - ([DateTime]$ConfigFileParams.LastEmailSent)).TotalHours -ge 3
if ($SendEmail) {
try {
# Send-MailMessage -ErrorAction Stop
# Once email is sent, we update the config
$ConfigFileParams.LastEmailSent = [DateTime]::UtcNow
$ConfigFileParams | ConvertTo-Json | Out-File $ConfigFullPath
}
Catch {
#Manage what to do in case of failure
}
}
That being said, you can definitely use the registry to do the same.
For convenience and ease of use though, I strongly suggest a simpler json file based approach.
I think the best option would be to write the starting hour in a file saved on the disk and everytime you run the script to test if
(currentHour-hourFirstSent)%3==0 && currentMinute<30
You put the name of the file yyyy-mm-dd and if that file exist you read the starting hour from it, if not you create it and save the starting hour in it.

Get-EventLog not parsing Message when run by SYSTEM user

Problem
I am trying to schedule a job that monitors events on remote machines.
I wrote the script based on the Get-EventLog command and it works properly when run by my account. But when I run the Get-EventLog as SYSTEM user, the .Message attribute of the returned objects shows the following error:
The description for Event ID '4724' in Source 'Microsoft-Windows-Security-Auditing' cannot be found. The local computer may not have the necessary registry information or message DLL files to display the message, or you may not have permission to access them. The following information is part of the event: {somedata}
When I use the Get-WinEvent command as SYSTEM user, the problem does not appear and the .Message part displays properly.
I would stick with Get-WinEvent, especially since the data is much easier to parse (thanks to the ToXML() method), but the Get-EventLog happens to be terribly faster :(
Question
Does anyone have any idea why the Get-EventLog fails to render .Message when run by SYSTEM user and perhaps how to fix it?
To avoid obvious answers:
the COMPUTER$ account is member of DOMAIN\Event Log Readers group,
the COMPUTER$ account does have the read privileges over the HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\Security on remote machines,
obviously, the registry entries for Microsoft-Windows-Security-Auditing and related DLL's are identical on both the source and target computers.
Try:
Get-WinEvent -LogName “Microsoft-Windows-Security-Auditing” | where ID -eq 4724 | select-object -ExpandProperty Message

check for last number of users logged in to machine?

I'm trying to come up with a powershell script thatcan determine the last number of users that logged on to a machine. I'm stuck on to how to approach it. If I'm correct, using a get-wmiobject call will only get the last user. I'm wondering if maybe there is a call I can do to get the history of something like the user folder and get the last users that modified that?Or is there some simpler way?
http://social.technet.microsoft.com/Forums/en/winserverpowershell/thread/c61dc944-6c40-4ab8-93f8-8c345c37b0d4
Basically, all user logins are saved in the security log of each windows server. These are set in the log with the following eventIDs: 528 and 540. These two IDs are for a direct or a remote login to a machine. For my specific need, I have to following line in my script. If you have a similar need, be sure to read up on windows eventIDs on a site like this one
Get-EventLog -logname security -ComputerName $svr -Newest 100 | where {$_.eventID -eq 528
-or 540} | select time,user
enjoy!