I found a script that logs all users of RDS servers which works great;
Link here
However I want to make it specific for 1 user, not all users.
I really don't know powershell so need some help.
Param(
[array]$ServersToQuery = (hostname),
[datetime]$StartTime = "January 1, 1970"
)
foreach ($Server in $ServersToQuery) {
$LogFilter = #{
LogName = 'Microsoft-Windows-TerminalServices-LocalSessionManager/Operational'
ID = 21, 23, 24, 25
StartTime = (get-date).adddays(-7)
}
$AllEntries = Get-WinEvent -FilterHashtable $LogFilter -ComputerName $Server
$AllEntries | Foreach {
$entry = [xml]$_.ToXml()
[array]$Output += New-Object PSObject -Property #{
TimeCreated = $_.TimeCreated
User = $entry.Event.UserData.EventXML.User
IPAddress = $entry.Event.UserData.EventXML.Address
EventID = $entry.Event.System.EventID
ServerName = $Server
}
}
}
$FilteredOutput += $Output | Select TimeCreated, User, ServerName, IPAddress, #{Name='Action';Expression={
if ($_.EventID -eq '21'){"logon"}
if ($_.EventID -eq '22'){"Shell start"}
if ($_.EventID -eq '23'){"logoff"}
if ($_.EventID -eq '24'){"disconnected"}
if ($_.EventID -eq '25'){"reconnection"}
}
}
$Date = (Get-Date -Format s) -replace ":", "."
$FilePath = "$env:USERPROFILE\Desktop\$Date`_RDP_Report.csv"
$FilteredOutput | Sort TimeCreated | Export-Csv $FilePath -NoTypeInformation
Write-host "Writing File: $FilePath" -ForegroundColor Cyan
Write-host "Done!" -ForegroundColor Cyan
So, you say …
(I really don't know powershell so need some help.)
..., but point to a very advanced PowerShell script you want to use.
It is vital that you do not use anyone's code that you do not fully understand what it is doing from anyone. You could seriously damage / compromise your system(s) and or you entire enterprise. Please ramp up to protect yourself, your enterprise and avoid unnecessary confusion, complications, issues, errors and frustration you are going to encounter:
Follow this link
As for your query...
However I want to make it specific for 1 user, not all users.
… Though the script returns all users, you can just filter / prompt for the one user you are after, without changing anything about the authors code.
Prompt for a user by adding an additional parameter in that param block
[string]$targetUser = (Read-Host -Prompt 'Enter a username')
In that $FilteredOutput section, is where you'd use the additional $targetUser parameter, using the Where-Object cmdlet or string matching there or in the ….
$FilteredOutput | Sort TimeCreated | Export-Csv $FilePath -NoTypeInformation
… section. Something like...
($FilteredOutput -match $TargetUser) | Sort TimeCreated | Export-Csv $FilePath -NoTypeInformation
I do not have an environment to test this, so, I'll leave that up to you.
$FilteredOutput | Sort TimeCreated | Export-Csv $FilePath -NoTypeInformation
This is all basic PowerShell 'using parameters' use case, and covered in all beginning PowerShell courses, books, websites, and built-in PowerShell help files.
I am new to powershell and found examples to display messages from the event log. The -match and -eq property don't seem to be working. Below is my script which does not return any results. When I use -notmatch or -ne it displays correctly. I’ve tried many different variations of the code, but nothing has worked.
$sysEvent = Get-EventLog -LogName Application -Newest 300
$sysError = $sysEvent | where {$_entryType -match "Information"}
$sysError | Sort-Object EventID | Format-Table EventID, EntryType, Source, TimeWritten, Message -AutoSize
I'm new to powershell and have been learning quite a bit. But still more to go. So my code isn't the tightest.
I've created an Event-log search tool. It allows me to search via ID, error level, key word, etc. For the most part, it works, with the exception of the keywords and provider name.
Currently, when trying to search the logs for a keyword or set of keywords, the script prompts the error message:
Get-WinEvent : The specified image file did not contain a resource section
At C:\Users\Rob\Google Drive\Powershell\Get-logs.ps1:65 char:9
+ Get-WinEvent -FilterHashtable #{Logname=$Log} -ComputerName $Computer | ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-WinEvent], EventLogException
+ FullyQualifiedErrorId : The specified image file did not contain a resource section,Microsoft.PowerShell.Commands.GetWinEventCommand
Problem is, I am not understanding the ps1.65 char:9 bit. The script then continues on and get's me old irrelevant data from the logs.
Here is the code for the two area's i'm having issue. Full code at the end.
Keyword Search:
elseif ($Kwrd -gt "a"){
foreach ($Kwrd in $Kwrd)
{
Get-WinEvent -FilterHashtable #{logname=$Log} -ComputerName $Computer | where-object { $_.Message -like "*$Kwrd*" } | Sort-Object TimeGenerated -Descending | Select-Object -First $Maxnum | Format-List
}
}
Provider Name Search:
elseif ($Prov.Length -gt 1){
Get-WinEvent -FilterHashtable #{Logname=$Log} -ComputerName $Computer | Where-Object {($_.ProviderName -like "*$Prov*")} | Sort-Object TimeGenerated -Descending|Select-Object -First $Maxnum | Format-List
}
So for example, if i wanted to search the application log for the provider name System Restore, (Which I have a few in there from the Revo application i ran recently) this is what the script does.
Enter Computer or EXIT to quit: office
Enter log set to retrieve: application
Enter Instance ID or leave blank:
Enter number of logs to retrieve: 10
Enter error level or leave blank:
Search logs by keyword or leave blank:
Search by Provider or leave blank: System Restore
Get-WinEvent : The specified image file did not contain a resource section
At C:\Users\Rob\Google Drive\Powershell\Get-logs.ps1:65 char:9
+ Get-WinEvent -FilterHashtable #{Logname=$Log} -ComputerName $Computer | ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-WinEvent], EventLogException
+ FullyQualifiedErrorId : The specified image file did not contain a resource section,Microsoft.PowerShell.Commands.GetWinEventCommand
PS C:\Users\Rob>
It's the same issue for the keyword search,. Same error message. Only difference is the line number changes from 65 to 61, since the code is on line 61.
It's not perfect, but i'm learning as I go. Here's the full script. Any idea's how I can get the information from the logs without the error?
Clear-Host
while (1 -ne 2){
$Computer = $Null
$IDNum = $Null
$Lvl = $Null
$Kwrd = $Null
$Prov = $Null
Write-Host ''
$Computer = Read-Host "Enter Computer or EXIT to quit"
if ($Computer -eq "EXIT") {exit;}
$Log = Read-Host "Enter log set to retrieve"
$IDNum = Read-Host "Enter Instance ID or leave blank"
$IDNum = $IDNum.Split(',')
$MaxNum = $MaxNum = Read-Host "Enter number of logs to retrieve"
$Lvl = Read-Host "Enter error level or leave blank"
$Lvl = $Lvl.Split(',')
$Kwrd = Read-Host "Search logs by keyword or leave blank"
$Kwrd = $Kwrd.Split(',')
$Prov = Read-Host "Search by Provider or leave blank"
if ($IDNum.Length -gt 1){
foreach ($IDNum in $IDNum)
{
Get-WinEvent -FilterHashTable #{LogName=$Log; ID=$IDNum} -ComputerName $Computer | Where-Object { ($_.ID -eq "*$IDNum*")} |Sort-Object TimeGenerated -Descending | Select-Object -First $Maxnum| Format-List
}
}
elseif ($Lvl -gt 1 ){
foreach ($Lvl in $Lvl)
{
Get-WinEvent -FilterHashTable #{LogName=$Log;Level=$lvl} -ComputerName $Computer -MaxEvents $MaxNum |Select-Object -First $MaxNum | Sort-Object TimeGenerated -Descending | Format-List
}
}
elseif ($Kwrd -gt "a"){
foreach ($Kwrd in $Kwrd)
{
Get-WinEvent -FilterHashtable #{logname=$Log} -ComputerName $Computer | where-object { $_.Message -like "*$Kwrd*" } | Sort-Object TimeGenerated -Descending | Select-Object -First $Maxnum | Format-List
}
}
elseif ($Prov.Length -gt 1){
Get-WinEvent -FilterHashtable #{Logname=$Log} -ComputerName $Computer | Where-Object {($_.ProviderName -like "*$Prov*")} | Sort-Object TimeGenerated -Descending|Select-Object -First $Maxnum | Format-List
}
else {
Get-WinEvent -LogName $Log -ComputerName $Computer | Sort-Object TimeGenerated -Descending| Select-Object -First $MaxNum | Format-List
}
} else{
Clear-Host
$log = $IDNum = $MaxNum = $Lvl = $Kwrd = $Prov = $Null
continue
Write-Host ''
Write-Host ''
}
Thanks.
Note: I'm Running ISE as admin.
Couple of comments
1) I can't recreate the error (your script ran fine on my machine) but it's behaving as though its trying to open/read an image file (very odd).
2) I tried running get-winevent with no parameters and I got many get-winevent : The data is invalid errors. When I researched this error, I learned thatget-winevent seems to be a buggy/problematic/fussy cmdlet. So, I suggest you try get-eventlog instead
3) You're invoking Get-WinEvent inside a loop which makes the program take much longer to run then necessary. I suggest you execute Get-EventLog (see comment #2 above) one time and pipe the output to out-gridview. For example:
Get-EventLog -LogName application | out-gridview -Title "App log events"
Then, use the out-gridview filters to display only the output you want to see.
Example output for the command above:
I have the following Powershell code that counts the number of errors occurring per Provider, based on Error ID and Message. What I am after is getting the count of each unique message per computer, log, provider, id and level.
However the issue that I'm having is that when I export this information to .csv the event message is being truncated. Or rather, I'm not able to quite grasp what I need to do to get the entire event message.
Here is the code that grabs the event logs and exports it to .csv.
$computername = 'mycomputer'
$logs = "application", "system"
$info = get-winevent -ComputerName $computername -FilterHashTable #{LogName=$logs; Level=1,2,3} |
sort MachineName,LogName,ProviderName,{$_.LevelDisplayName},ID |
Group MachineName, LogName, ProviderName, ID, {$_.LevelDisplayName}, Count, Message |
select #{N="Computer";E={$_.name.split(',')[0]}},#{N="Log";E={$_.name.split(',')[1]}}, #{N="Provider";E={$_.name.split(',')[2]}}, #{N="Error ID";E={$_.name.split(',')[3]}},`
#{N="Type";E={$_.name.split(',')[4]}}, count, #{N="Message";E={$_.name.split(',')[5 |
Export-Csv -notypeinformation -Path c:\Test\events.csv
If I comment out
#| Export-Csv -notypeinformation -Path c:\Test\events.csv
And output
$info
I see the complete message. I also can see more of the message if I continue to expand the array indexes. For example I get more of the message if I do this:
, #{N="Message1";E={$_.name.split(',')[6]}}, #{N="Message2";E={$_.name.split(',')[7]}}
What do I need to code correct to get the entire message out in the
#{N="Message";E={$_.name.split(',')[5]}}
selection?
I think you Can take a much easier approach, with the built-in ConvertFrom-Csv, Also the script would be much more Readable
$info = get-winevent -ComputerName $computername -FilterHashTable #{LogName=$logs; Level=1,2,3} |
sort MachineName,LogName,ProviderName,{$_.LevelDisplayName},ID |
Group MachineName, LogName, ProviderName, ID, {$_.LevelDisplayName}, Count, Message
$Array = #()
$Header = "Computer","Log","Provider","ErrorID","Type","Message","Count"
Foreach ($item in $Info)
{
$Count = $Item.Count
$CSV = $item.Name | ConvertFrom-Csv -Delimiter "," -Header $Header
$CSV.Count = $Count
$Array += $CSV
}
$Array | Export-CSV C:\Test\Events.csv -NoTypeInformation
I'm guessing you're not truncating. You've just got messages with commas in them, and Split() doesn't have any way to know what's a delimiter and what's part of the message.
Well, I suppose you could specify:
#{N="Message";E={($_.name.split(',')[5..($_.name.split(',').Count - 1)]) -join ','}}
But, honestly, this feels like some mighty gigantic hoops to jump through.
What's wrong with $_.Group[0].<item> instead of $_.name.split(',')[<num>]? Except count, you're grouping by all the fields you're pulling, aren't you? So the value on the first event should, by definition, be the same on every other event in the same group, right?
Also, why {$_.LevelDisplayName} instead of just LevelDisplayName?
And I think you'll find that Message won't work very well in a CSV unless you strip line feeds and carriage returns.
Try this:
$ComputerName = 'ComputerName';
$Logs = 'Application', 'System';
$Info = Get-WinEvent -ComputerName $ComputerName -FilterHashTable #{LogName=$Logs; Level=1,2,3} `
| Sort-Object MachineName, LogName, ProviderName, LevelDisplayName, ID `
| Group-Object MachineName, LogName, ProviderName, ID, LevelDisplayName, Count, Message `
| Select-Object #{N="Computer";E={$_.Group[0].MachineName}}, `
#{N="Log"; E={$_.Group[0].LogName}}, `
#{N="Provider";E={$_.Group[0].ProviderName}}, `
#{N="Error ID";E={$_.Group[0].ID}}, `
#{N="Type"; E={$_.Group[0].LevelDisplayName}}, `
count, `
#{N="Message"; E={$_.Group[0].Message.Replace("`r",' ').Replace("`n",' ')}} `
| Export-Csv -NoTypeInformation -Path c:\Test\events.csv;
How can I make this use a list of servers
Tried doing $ComputerList = gc <list location> but it doesnt seem to be working
correctly with one computer
$Start = (Get-Date).AddMinutes(-120)
$ComputerList = $env:ComputerName
$Events = gc C:\Temp\ErrorCodes.txt
# Getting all event logs
Get-EventLog -AsString -ComputerName $Computername |
ForEach-Object {
# write status info
Write-Progress -Activity "Checking Eventlogs on \\$ComputerName" -Status $_
# get event entries and add the name of the log this came from
Get-EventLog -LogName $_ -EntryType Error, Warning -After $Start -ComputerName $ComputerName -ErrorAction SilentlyContinue |
Add-Member NoteProperty EventLog $_ -PassThru | Where-Object {$Events -contains $_.eventid}
} |
# sort descending
Sort-Object -Property EventLog |
# select the properties for the report
Select-Object EventLog, EventID, TimeGenerated, EntryType, Source, Message
# output into grid view window
Out-GridView -Title "All Errors & Warnings from \\$Computername"
Force it to be an array.. Otherwise it will come in as a string if there is only one item
$ComputerList = #(gc c:\folder\computerlist.txt)
PowerShell: How can I to force to get a result as an Array instead of Object