Using Get-WinEvent to Query All Logs
You can use Get-WinEvent to get events from all logs. Let's say you wanted to get all the errors in all the logs for the past 24 hours, you would specify a wildcard (*) in the LogName.
Get-WinEvent -FilterHashtable @{LogName='*';StartTime=(Get-Date).AddDays(-1)}
Encountering the Invalid Data error with Get-WinEvent; a 256 log limit
Get-WinEvent : The data is invalid
At line:1 char:1
+ Get-WinEvent -FilterHashtable @{LogName="*";StartTime=(Get-Date).AddDays(-1)}
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-WinEvent], EventLogInvalidDataException
+ FullyQualifiedErrorId : The data is invalid,Microsoft.PowerShell.Commands.GetWinEventCommand
There seems to be a 256 log limit to searching the logs. If you created a Custom View in eventvwr.msc, the same limit would apply, and attempting to access more than 256 logs would result in a similar error.
On the Windows Server 2008 R2 and Windows 7 machines I have tested there are less than 200 logs, but on my Windows 8.1 machine there are 375. So using the wildcard for the Log Name parameter of Get-WinEvent results in an invalid data error on machines with more that 256 logs.
Workaround 1: The quick and dirty, likely, but not guaranteed, to work.
It turns out that most of the logs on my Windows 8.1 machine don't have events in them. So if we want to query all logs for events, we can reduce the amount of logs we query against by first getting a list of only the logs that have events in them. When I got only the logs with events in them, on my Windows 8.1 machine, there were only 122 logs.
$logs = Get-WinEvent -ListLog * |
Where-Object {$_.RecordCount} |
Select-Object -ExpandProperty LogName
Get-WinEvent -FilterHashtable @{LogName=$logs;StartTime=(Get-Date).AddDays(-1)}
Workaround 2: Get all the logs and break them into groups of 256
Now, if I assumed that there would always be more than 256 logs and never be more than 512 logs, I could manually break the list of logs up fairly easily like this, and loop over $log_sets.
$logs = Get-WinEvent -ListLog * | Select-Object -ExpandProperty LogName
$log_sets = @($arr[0..255],$arr[0..($arr.Length-1)])
But, instead, I created a function to split an array into a number of arrays based on a maximum size of 256.
Function Split-Array {
[CmdletBinding()]
Param(
[Parameter(
Position = 0,
Mandatory = $True,
ParameterSetName = "Array"
)]
[Object[]]
$Array,
[Parameter(
ValueFromPipeline = $True,
Mandatory = $True,
ParameterSetName = "Collect"
)]
[Object]
$InputObject,
[Int]
$Size = 256
)
Begin {
If($psCmdlet.ParameterSetName -eq 'Collect'){
$Array = @()
Write-Verbose "Collecting objects into an array."
}
}
Process {
If($psCmdlet.ParameterSetName -eq 'Collect'){
$Array += $InputObject
}
}
End {
$length = $Array.Length
Write-Verbose "Array length: $length."
$numberOfArrays = [Math]::Ceiling($length / $Size)
Write-Verbose "To be split into $numberOfArrays arrays."
$lengthOfArrays = [Math]::Ceiling($length / $numberOfArrays)
Write-Verbose "The maximum length of each array will be $lengthOfArrays."
ForEach($i in (1..$numberOfArrays)) {
$start = ($i - 1) * $lengthOfArrays
$end = $i * $lengthOfArrays - 1
If($end -gt ($length - 1)){
$end = $length - 1
}
Write-Verbose ("Returning array $i of $numberOfArrays from " +`
"original array's index $start to $end")
,$Array[$start..$end]
}
}
}
$log_sets = Get-WinEvent -ListLog * |
Select-Object -ExpandProperty LogName |
Split-Array
ForEach($log_set in $log_sets) {
Get-WinEvent -FilterHashtable @{LogName=$log_set;StartTime=(Get-Date).AddDays(-1)}
}