ilRobby
ilRobby

Reputation: 81

Get-EventLog loop for psobjects, strange results

I've to collect certain events for sharing it by mail; I'm missing something because the script, take a lot of time for only 2 servers and, the result is absurd!

Server1 events count:

    $Etype = @( "Warning", "Error" )
    $Source = "Cisco Systems Inc. ICM"
    $StartDate = ((Get-Date).AddDays(-2))
    $EndDate = Get-Date
    (Get-EventLog -LogName Application -After $StartDate -Before $EndDate -EntryType $Etype -Source $Source).Count
}
$rEVT
2576

Server2 events count:

$rEVT2 = Invoke-Command -ComputerName $Srv2 -scriptblock {
    $Etype = @( "Warning", "Error" )
    $Source = "Cisco Systems Inc. ICM"
    $StartDate = ((Get-Date).AddDays(-2)) 
    $EndDate = Get-Date
    (Get-EventLog -LogName Application -After $StartDate -Before $EndDate -EntryType $Etype -Source $Source).Count
}
$rEVT2
3853

My script:

$HostsTable = @()
foreach ( $Srv in $MyList ) {
$rEVT_ALL = Invoke-Command -ComputerName $Srv -scriptblock {
    $Etype = @( "Warning", "Error" )
    $Source = "Cisco Systems Inc. ICM"
    $StartDate = ((Get-Date).AddDays(-2)) 
    $EndDate = Get-Date
    Get-EventLog -LogName Application -After $StartDate -Before $EndDate -EntryType $Etype -Source $Source | Select-Object -Property TimeGenerated, EntryType, Category, Message
    }| ForEach-Object { 
        [PSCustomObject]@{
            HN = $Srv
            TimeCreated = [DateTime]$_.TimeGenerated
            Category = $_.Category
            Level = $_.EntryType
            Message = $_.Message
        }
        $HostsTable +=  $rEVT_ALL
    }
}

Mesaure command:

(Get-History)[-1].EndExecutionTime - (Get-History)[-1].StartExecutionTime


Days              : 0
Hours             : 0
Minutes           : 18    <--------
Seconds           : 35
Milliseconds      : 898
Ticks             : 11158982764
TotalDays         : 0,0129154893101852
TotalHours        : 0,309971743444444
TotalMinutes      : 18,5983046066667
TotalSeconds      : 1115,8982764
TotalMilliseconds : 1115898,2764

Result:

$HostsTable.count
10011624      <------ :D

$HostsTable | select -First 1


HN          : SRV1    <--------
TimeCreated : 18/06/2024 19:10:56
Category    : Message Delivery
Level       : Error
Message     : Client: clgr, state transfer operation aborted.



$HostsTable | select -Last 1


HN          : SRV1    <--------
TimeCreated : 16/06/2024 19:55:43
Category    : Call Router
Level       : Error
Message     : PG has reported that peripheral: CC_VRU_1 (ID: 5001) is not operational.

After, I've to export-excel, but at the moment something goes wrong...

Please, help me! Roberto

Upvotes: 0

Views: 52

Answers (1)

Mathias R. Jessen
Mathias R. Jessen

Reputation: 174455

You're currently re-adding all the results from the previous iteration of the foreach loop to $HostsTable for every new event returned by the query against the next server.

Move this assignment statement $HostsTable += $rEVT_ALL outside the pipeline:

foreach ($srv in $MyList) {
    $rEVT_ALL = Invoke-Command -ComputerName $Srv -scriptblock {
        $Etype = @( "Warning", "Error" )
        $Source = "Cisco Systems Inc. ICM"
        $StartDate = ((Get-Date).AddDays(-2)) 
        $EndDate = Get-Date
        Get-EventLog -LogName Application -After $StartDate -Before $EndDate -EntryType $Etype -Source $Source | Select-Object -Property TimeGenerated, EntryType, Category, Message
    } | ForEach-Object { 
        [PSCustomObject]@{
            HN          = $Srv
            TimeCreated = [DateTime]$_.TimeGenerated
            Category    = $_.Category
            Level       = $_.EntryType
            Message     = $_.Message
        }
    }
    # wait to update `$hostsTable` until after the query returns
    $HostsTable += $rEVT_ALL
}

This will ensure you save a reference to each event only once, and will improve execution time and memory footprint significantly.

You could also simplify your code further by passing the server list directly to Invoke-Command and then use Select-Object for the property selection/renaming, like so:

$HostsTable = Invoke-Command -ComputerName $MyList -scriptblock {
    $Etype = @( "Warning", "Error" )
    $Source = "Cisco Systems Inc. ICM"
    $StartDate = ((Get-Date).AddDays(-2)) 
    $EndDate = Get-Date
    Get-EventLog -LogName Application -After $StartDate -Before $EndDate -EntryType $Etype -Source $Source | Select-Object -Property TimeGenerated, EntryType, Category, Message
} | Select-Object -Property @{Name='HN';Expression={$_.PSComputerName}},TimeCreated,Category,@{Name='Level';Expression={$_.EntryType}},Message

This will also make it faster overall, since the $HostsTable array doesn't have to be resized multiple times, and you won't be blocking when a remote server is slow to respond.


One last trick to make the code a little more readable - splat your arguments, in turn reducing the amount of horizontal scrolling required when looking at the code:

$winEventQueryArgs = @{
  LogName = 'Application'
  Entrytype = @( 
    'Warning'
    'Error' 
  )
  Source = "Cisco Systems Inc. ICM"
  After = (Get-Date).AddDays(-2)
  Before = Get-Date
}

Get-EventLog @winEventQueryArgs | Select-Object -Property TimeGenerated, EntryType, Category, Message

Upvotes: 3

Related Questions