powershell: get-winevent has no message data? - powershell

When I run the script below to retrieve log files, the get-winevent "message" field is blank, but has data if I run get-eventlog. Any ideas why?
#has message data
Get-Eventlog -LogName application -Newest 10
#date 10 days ago
$EventStartDate = get-date("10 May 2012")
$EventEndDate = get-date("11 May 2012")
$EventLogNames = #("Application", "system")
#critea for winevent
$EventCritea = #{logname = $EventLogNames; StartTime=$EventStartDate; EndTime=$EventEndDate}
#Retrieves the event log
$RetreivedEvents = Get-WinEvent -computername localhost -FilterHashtable $EventCritea
$RetreivedEvents | fl id, logname, MachineName, Message, TimeCreated

What locale are you running under?
There is a .NET bug where the underlying .NET method (that Get-WinEvent uses) fails to populate localised fields (like Message) in some locales (like en-GB).
Fix is to switch to en-US for the command:
$orgCulture = Get-Culture
[System.Threading.Thread]::CurrentThread.CurrentCulture = New-Object "System.Globalization.CultureInfo" "en-US"
# Perform Get-WinEvent
[System.Threading.Thread]::CurrentThread.CurrentCulture = $orgCulture

I believe this is because the messages are hidden in a property value. To display all messages, pipe the get-winevent to the select statement with the following expressions:
#{Label='Messages';Expression={$_.properties.Value}}
If you wish to display a specific message, for instance Logon Process (In security logs), use the expression:
#{Label='Logon Process';Expression={$_.properties.Value[3]}}

I know I have seen get-winevent not work on Windows Server 2003 in the past when I have tried it. Basically the PS environment said get-winevent didn't work for 2003. That may have been PS v1 then, so I am not sure if that was resolved with newer versions of PS: I am on 2K8 R2 now.
On my

What PSHost are you running under?
I am experiencing a problem on PS V2.0 running on windows 7 accessing W2k8. If run within a Powershell console or within Powershell ISE it retrieves all data. However if running within a runspace or from PowerGUI (pro) it returns only a partial subset which does not include the Message property.
[EDIT]
Richard's post allows me to work around the problem but it is very strange because the culture in the working PS console is 'en-GB' and the culture in the non working PowerGui Script Editor is 'en-GB' which only works if I change the culture to 'en-US'.
Freaky

Adding the following line at the top of my script worked for me (taken from Richards code Snippet) ;
[System.Threading.Thread]::CurrentThread.CurrentCulture = New-Object "System.Globalization.CultureInfo" "en-US"

[PS 2.0] Note that a culture change is only valid for the current pipeline.
See Culture Gotchas
So the command to temporarily change culture + get-winevent need to be grouped either in a script block (enclosed within "{...}") or on one line separated by ";".
I discovered this when trying to use get-winevent on system log on Server 2008. Messages came up empty, and I needed to change the culture from nl-BE to en-US.

Related

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

How do I use Get-EventLog to get the same result of Get-WinEvent in PowerShell?

I am working on Windows Server 2003 and I need to get something like the following by using this command Get-WinEvent -ListLog Application, Security, System
LogMode MaximumSizeInBytes RecordCount LogName
------- ------------------ ----------- -------
Circular 33554432 15188 Application
Circular 201326592 298459 Security
Circular 33554432 10074 System
I need the result of the property MaximumSizeInBytes but Get-WinEvent is not supported on Server 2003
I see that Get-EventLog has a property called MaximumKilobytes but the result I get is different
I would like to know if there is a command can be ran locally to get the same result
First why are you still on WS2K3? --- ;-}
Before you respond, I know, I know, some orgs... right!? ;-}
Yet, unless someone on this site has WS2K3, there is no way for them to validate stuff.
This cmdlet not supported on WS2K3 is not a bug or missing thing. cmdlets are OS version and PowerShell version specific.
All that being said. Just because a command does not exist on your system, does not mean you cannot try use it.
This is why implicit PSRemoting exists.
Remoting the Implicit Way
Using implicit PowerShell remoting to import remote modules
Mostly you see this used for ADDS, Exchange, O365 cmdlets and the like, but you can do it for any module / cmdlet on a remote host to use on your local session. Using implicit remoting the cmdlet really does not run on your system it is proxied. Just be sure to use the -prefix argument so to not end up with duplicate cmdlets being listed.
Example
$RemoteSession = New-PSSession -ComputerName 'RemoteHost' -Credential (Get-Credential -Credential "$env:USERDOMAIN\$env:USERNAME")
Import-PSSession -Session $RemoteSession -Prefix RS
So, no you call the cmdlets using the prefix when you want to use one from that session.
Get-RSWinEvent
Now, as I said, I have no WS2K3 boxes to mess with as I am all WS2K12R2/16/19. Yet, give it a shot.
As no one has provided a satisfying answer yet I will just post the answer I found online here. The following command saved my life:
Get-WmiObject -Class Win32_NTEventLogFile | Select-Object -Property MaxFileSize, LogfileName, Name, NumberOfRecords
I will not choose my own answer as the final answer just yet so if you can think of a better solution please feel free to add it :)
Thank you for viewing my post and tried to help

View recent remote powershell connections

Is there an event log of some kind that is made when a remote pssession is initiated on a computer? I need to be able to see where a remote session has originated from.
Currently I am running
Get-EventLog -LogName "Windows powershell" -newest 100 | Format-List -Property * | where {$_.UserID -eq "username"}
But it is not filtering and/or showing remote connections.
We are here to help you with code issues. This is really not a code issue, but a understanding of how to set up and where correlate such detail. So, it's potentially a question for another forum.
Anyway, to get you close to what you are after, there are extra steps you need to employ to get such information. More on that in a bit.
Now, once you get this all setup and you write your script to pull / look at such info and you are having issues with that, then post that back here for folks to see what can be done
So, that leads us to here:
There are three general areas for logging available:
• Module Logging
• Script Block Logging
• PowerShell Transcription
If you have not done so, I would advise enabling on PS auditing and script logging for more insight into this use case and well as transcript logging (which can capture all commands / code executed on a host machine). If you set all this up properly, you fist look to the transcript log for details and well as the log name you reference in your post for other details.
Set this enterprise wide via GPO or DSC.
There is lot's of guidance on how to set this up.
For Example:
Audit PowerShell Usage using Transcription and Logging
Get-Command -Name '*transcript*'
CommandType Name Version Source
----------- ---- ------- ------
Cmdlet Get-TRSTranscriptionJob 3.3.234.0 AWSPowerShell
Cmdlet Get-TRSTranscriptionJobList 3.3.234.0 AWSPowerShell
Cmdlet Start-Transcript 3.0.0.0 Microsoft.PowerShell.Host
Cmdlet Start-TRSTranscriptionJob 3.3.234.0 AWSPowerShell
Cmdlet Stop-Transcript 3.0.0.0 Microsoft.PowerShell.Host
https://learn.microsoft.com/en-us/powershell/wmf/5.0/audit_overview
Practical PowerShell Security: Enable Auditing and Logging with DSC
https://blogs.technet.microsoft.com/ashleymcglone/2017/03/29/practical-powershell-security-enable-auditing-and-logging-with-dsc
More New Stuff in PowerShell V5: Extra PowerShell Auditing
Get-Module Microsoft.* | Select Name, LogPipelineExecutionDetails
Get-Module Microsoft.* | ForEach { $_.LogPipelineExecutionDetails = $True }
(Import-Module ActiveDirectory).LogPipelineExecutionDetails = $True
Get-WinEvent -FilterHashtable #{LogName='Windows PowerShell';Id ='800'} -MaxEvents 1 | Select -Expand Message
https://learn-powershell.net/2014/08/26/more-new-stuff-in-powershell-v5-extra-powershell-auditing
Investigating PowerShell: Command and Script Logging
https://www.crowdstrike.com/blog/investigating-powershell-command-and-script-logging

Querying Windows Update Errors using PowerShell Get-WinEvent or Get-WMIObject

Trying to create a simple Windows Update error query using Get-WinEvent (although I would prefer querying a WMI Object for use with SCUP):
get-winevent -logname System| Where-Object {$_.ProviderName -eq "Microsoft-Windows-WindowsUpdateClient"}
This seems to work for the most part. However, it only returns informational events and not errors. Are these located somewhere else and, if so, how would I query them? For some background, there is a specific update failure occurring on approximately 10% of Windows 10 machines in my environment (missing assembly file) and I want to target it so that I can deploy a solution.
A solution using Get-WinEvent is fine, though I would prefer using Get-WMIObject if possible.
You can use the Win32_NTLogEvent like this:
Get-WmiObject Win32_NTLogEvent |?{($_.LogFile -eq 'System') -and ($_.SourceName -eq 'Microsoft-Windows-WindowsUpdateClient') }
Note: You can further filter with Type which will tell you about information or error or warning.
Hope it helps.
I cannot find anything that actually states this but it looks like Get-WinEvent by default only returns information messages. If you want to see the other then you need to tell it to return those. One way to do it is with -FilterHashtable.
Get-WinEvent -FilterHashtable #{LogName='System';Level=1,2}
That would return only warnings and error.
1 - Error
2 - Warning
4 - Information
You can look at the enum [System.Diagnostics.EventLogEntryType] to see where I got the numbers from.
Looking at MS you can see what the hashtable filter supports..
LogName=<String[]>
ProviderName=<String[]>
Path=<String[]>
Keywords=<Long[]>
ID=<Int32[]>
Level=<Int32[]>
StartTime=<DateTime>
EndTime=<DataTime>
UserID=<SID>
Data=<String[]>
*=<String[]>
If your WMI queries are having similar issues then you can do something like this
Get-WmiObject -class Win32_NTLogEvent -filter "(logfile='Application') AND (type='error')"
You can find some tangential examples here
Write a WMI query (this overrides weird event type filters):
Get-WmiObject -Query "Select * from Win32_NTLogEvent" |?{(($_.LogFile -eq 'System') -and ($_.Type -in ("Error", "Warning"))) -and ($_.SourceName -eq 'Microsoft-Windows-WindowsUpdateClient') }
Okay, so after doing some additional research, I stumbled upon this website that sheds some light on the issue I'm running into. Essentially, while most, if not all Windows Events are logged in the C:\Windows\System32\Winevt\logs folder, not all Windows Events are replicated in WMI by default.
In PowerShell, Get-WinEvent appears to use the above folder when querying its event data, whereas Get-EventLog uses the Win32_WinNTLogEvent WMI class.
In my original question, I mentioned that I was unable to query Windows Update error events using Get-WinEvent. This is because I was pointing to the System log file, which does not contain the information. The Microsoft-Windows-WindowsUpdateClient/Operational log file (literal path being C:\Windows\System32\Winevt\logs\Microsoft-Windows-UpdateClient%4Operational.evtx) does contain this information, so my query can simply be changed up using something similar to the following:
Get-WinEvent -logname "Microsoft-Windows-WindowsUpdateClient/Operational" | Where-Object {$_.LevelDisplayName -eq "Error"}
In order to query the same data returned by Get-WinEvent using the Win32_NTLogEvent WMI class, the registry must first be modified. Again, the link I posted in this answer describes the process in greater detail, but essentially I performed the following registry mod:
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\Microsoft-Windows-WindowsUpdateClient/Operational]
"File"="%SystemRoot%\\System32\\Winevt\\Logs\\Microsoft-Windows-WindowsUpdateClient%4Operational.evtx"
"Primary Module"="Microsoft-Windows-WindowsUpdateClient/Operational"
"Microsoft-Windows-WindowsUpdateClient/Operational"=hex(2):25,00,53,00,79,00,73,00,74,\
00,65,00,6d,00,52,00,6f,00,6f,00,74,00,25,00,5c,00,73,00,79,00,73,00,74,00,\
65,00,6d,00,33,00,32,00,5c,00,77,00,65,00,76,00,74,00,61,00,70,00,69,00,2e,\
00,64,00,6c,00,6c,00,00,00
Note: The "Microsoft-Windows-WindowsUpdateClient/Operational" Expanded String (REG_EXPAND_SZ) at the end there is pointing to %SystemRoot%\system32\wevtapi.dll
Once the registry was modified, I was able to query the error events as follows:
Get-WmiObject -query "SELECT * FROM Win32_NTLogEvent WHERE LogFile='Microsoft-Windows-WindowsUpdateClient/Operational' AND Type='Error'"
Somewhat of a pain considering that Windows Update errors should probably be present in the Win32_NTLogEvent WMI class by default (ah, Microsoft). Still, this essentially resolves my question.
One additional point to mention. The website above states that, upon editing the registry, you'd be able to query the new events immediately. I had to reboot my machine first.

Measure 'Idle' time between CTRL-ALT-DEL and user typing in password and loging on -Windows 7

Windows 7 has the built in 'Boot Performance Diagnostics' and judging by the numerous reboots i've done, it does generate every now and then a detailed log on the user's login process and possible slowness.
That is not good enough for what I'm after though.
I want to measure EVERY Boot on a given machine.
There is little information however available on how to force it, except fiddling with registry keys that are System Protected so you don't tamper with them.
Some of the information can be found in the eventlogs so i switched to tracing the eventid 12
$yesterday = (get-date) - (New-TimeSpan -day 2)
$startuplog= Get-WinEvent -FilterHashTable #{LogName='System'; ID=12;
StartTime=$yesterday} -ErrorAction SilentlyContinue
But does anyone know how one can measure when the system was ready (ctrl-alt-del) and when the user hit the enter button after typing in the password? Is there a flag that can be set to raise such an event in a (diagnostics) event log?
You can compare the power state timestamp to the "Last Interactive Logon" feature of AD DS. That feature requires a domain functional level (DFF) of Windows Server 2008 r2 to work and workstation infrastructure of windows vista or later. The "msDS-LastSuccessfulInteractiveLogonTime" attribute is what you want. It's the time stamp of the last successful interactive logon (ctrl+alt+del).
To enable Last Interactive Logon on your domain:
http://technet.microsoft.com/en-us/library/dd446680(v=ws.10).aspx
Command to query attribute:
$Computer = 'hostname'
Get-ADComputer -Filter "name -eq $Computer" -Properties * | Select msDS-LastSuccessfulInteractiveLogonTime
P.S. Try to get away from using "-ErrorAction". In it's place, use Try/Catch/Finally code blocks.
http://blogs.technet.com/b/heyscriptingguy/archive/2010/03/11/hey-scripting-guy-march-11-2010.aspx