0

I need to get the email alert with the event ID 4202, 4204, 4206, 4208, 4212 for the past 24 hrs, from multiple servers.

How can I get that using the Powershell like below which is working for a local computer only?

Script:

$HtmlHead = @"
<style>
    body {
        font-family: Arial;
    }
    table {
        width: 100%;
        border-collapse: collapse;
        border: 1px solid;
    }
    th {
        background-color: green;
        border: 1px solid;
        padding: 1px;
    }
    td {
        border: 1px solid;
        padding: 1px;
    }
</style>
"@

$mailArgs = @{
    SmtpServer  = 'mail.domain.com'
    From        = 'SystemAdmin@domain.com'
    To          = 'Manager@domain.com'
    Subject     = '{0} DFS report'
    Attachments = 'C:\Logs\DFS-Events_{0}.csv'
}

$EventIDs = 4202, 4204, 4206, 4208, 4212

Get-DfsrMember | Select-Object -ExpandProperty ComputerName -Unique | Sort-Object | ForEach-Object {
    Write-Host "Processing $($_) ..."
    Try
    {
        $splat = $mailArgs.psobject.Copy()
        $splat['Attachments'] = $splat['Attachments'] -f $_
        Get-WinEvent -FilterHashTable @{ LogName = 'System'; StartTime = (Get-Date).AddHours(-24); ID = $EventIDs } |
        Select-Object -Property TimeCreated, Id, Message |
        Sort-Object -Property TimeCreated |
        Export-Csv -NoTypeInformation -UseCulture -Path $splat['Attachments']
        $splat['Body'] = "$($_) DFS Replication Related Events | ForEach-Object { "$($upTime.$_) $_" })"
    }
    Catch
    {
        Write-Error -ErrorRecord $_
        $splat['Body'] = "$($_) query failed:`r`n$($_.Exception.Message)"
        $splat.Remove('Attachments')
    }
    # Send the result for each server as email
    $splat['Subject'] = $splat['Subject'] -f $_
    Send-MailMessage @splat
}
halfer
  • 19,824
  • 17
  • 99
  • 186
Senior Systems Engineer
  • 1,061
  • 2
  • 27
  • 63

1 Answers1

1

I think you'll just need a second loop to go through all computers.

Change

$ComputerName = Get-DfsrMember | ...

into

$computers = Get-DfsrMember | ...

and then wrap your ForEach ( $LogType in $Logs ) { ... } loop inside another loop like

foreach ( $computerName in $computers ) {
    foreach ( $LogType in $Logs ) {
        ..
    }
}

P.S. I like to write lowercase for foreach ($thingy in $collection) {} and use camel-case in $collection | ForEach-Object {} to help visualizing the difference between the two


As per your comment, the results should also be in a HTML table for email.

For that, add BodyAsHtml = $true in your $mailArgs hashtable and Capture the results from the Get-WinEvent call so you can export to CSV and afterwards convert to a nice HTML table.

Your code slighlty adjusted for this:

$HtmlHead = @"
<style>
    body {
        font-family: Arial;
    }
    table {
        width: 100%;
        border-collapse: collapse;
        border: 1px solid;
    }
    th {
        background-color: green;
        border: 1px solid;
        padding: 1px;
    }
    td {
        border: 1px solid;
        padding: 1px;
    }
</style>
"@

$mailArgs = @{
    SmtpServer  = 'mail.domain.com'
    From        = 'SystemAdmin@domain.com'
    To          = 'Manager@domain.com'
    Subject     = '{0} DFS report'
    Attachments = 'C:\Logs\DFS-Events_{0}.csv'
    BodyAsHtml  = $true
}

$EventIDs = 4202, 4204, 4206, 4208, 4212

Get-DfsrMember | Select-Object -ExpandProperty ComputerName -Unique | Sort-Object | ForEach-Object {
    Write-Host "Processing $($_) ..."
    Try
    {
        $splat = $mailArgs.psobject.Copy()
        $splat['Attachments'] = $splat['Attachments'] -f $_
    
        $result = Get-WinEvent -FilterHashTable @{ LogName = 'System'; StartTime = (Get-Date).AddHours(-24); ID = $EventIDs } -ErrorAction Stop |
                    Select-Object -Property TimeCreated, Id, Message |
                    Sort-Object -Property TimeCreated
        # export to csv file
        $result | Export-Csv -NoTypeInformation -UseCulture -Path $splat['Attachments']
        # create the HTML body
        $splat['Body'] = ($result | ConvertTo-Html -Head $HtmlHead -PreContent "<h3>$($_) DFS Replication Related Events</h3>")
    }
    Catch
    {
        Write-Error -ErrorRecord $_
        # don't forget you're sending HTML, so use "<br />" instead of "`r`n"
        $splat['Body'] = "$($_) query failed:<br />$($_.Exception.Message)"
        $splat.Remove('Attachments')
    }
    # Send the result for each server as email
    $splat['Subject'] = $splat['Subject'] -f $_
    Send-MailMessage @splat
}
Theo
  • 57,719
  • 8
  • 24
  • 41
  • thanks for the reply, I have updated the code with the proper Send Mail splatting and with your suggestion. I appreciate your assistance and inspirations Theo. – Senior Systems Engineer Sep 01 '20 at 11:57
  • 1
    @SeniorSystemsEngineer Thanks for the nice feedback. Your code now looks great, but I think it is missing the `-ComputerName $_` on the `Get-WinEvent` call ? – Theo Sep 01 '20 at 13:51
  • Hi @Theo, one minor issue with the above code. The result table is not displayable on the email body as a table? But the attachment works great. How to fix that Minor issue ? – Senior Systems Engineer Sep 01 '20 at 14:02
  • 1
    @SeniorSystemsEngineer I have updated my answer in order to both output the results to CSV and also create a HTML body for sending in email. (I used '

    ' for the title in the `PreContent` parameter, but you can choose from

    up to

    what you like best. See [here](https://www.w3schools.com/tags/tryit.asp?filename=tryhtml_headers))
    – Theo Sep 01 '20 at 14:40
  • 1
    @SeniorSystemsEngineer P.S. I have also added ` -ErrorAction Stop` to the Get-WinEvent call in order to make sure you will enter the catch block when an error occurs. – Theo Sep 01 '20 at 14:46
  • that's great, many thanks to you, @Theo, I've learned more from you. – Senior Systems Engineer Sep 01 '20 at 23:34