Get-PastEvents.psm1

<#
.SYNOPSIS
    Gather Last Event Logs with Parameter DaysPast
.DESCRIPTION
    Gets Eventlogs based on System.Diagnostics.Eventing.Reader.EventLogQuery same as Eventvwr.msc, offers the Option to specify DaysPast
    to get All events that happend in the specified past timeframe
.PARAMETER LogName
    Specify LogName to Search in
.PARAMETER Type
    Specify Type (Error, Warning, Information)
.PARAMETER EventID
    Specify Event ID for Results
.PARAMETER DaysPast
    Specify Days Past in which Event happened
.INPUTS
    One of the Above Parameter
.OUTPUTS
    Event Logs applying to filter
.EXAMPLE
    Get-EventLog -LogName Microsoft-ServerManagementExperience -Type Error,Warning -DaysPast 0.5
.EXAMPLE
    Get-EventLog -Type Error -DaysPast 0.1
.EXAMPLE
    Get-EventLog -LogName System -Type Error,Warning -EventID 610 -DaysPast 3
.NOTES
    Full Script and Function by CZ
#>

#Get-EventLog v3

function Get-PastEvents {
    Param(
        [CmdletBinding()]
        #LogName
        [Parameter(Mandatory=$false,
        Position=0,
        HelpMessage="Log Name")]
        [Alias("Log")]
        [string[]]$LogName,
        #$Filters
        #Type
        [Parameter(Mandatory=$false,
        HelpMessage="Entry Type")]
        [ValidateSet("Error","Warning","Information")]
        [string[]]$Type,
        #EventID
        [Parameter(Mandatory=$false,
        HelpMessage="Event ID")]
        [string[]]$EventID,
        #DaysPast
        [Parameter(Mandatory=$false,
        HelpMessage="Days Past")]
        [decimal]$DaysPast
    )

    #Check for Administrator rights
    $currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
    IF (($currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) -eq $false) {
        Write-Host "Get-EventLog: You do not have the required permission to complete this task. Contact the administrator of the authorization policy for the computer '$($Env:COMPUTERNAME)'." -ForegroundColor Red
        break
    }

    #Update Format data to support custom view (EventLogRecordView) for type: System.Diagnostics.Eventing.Reader.EventLogRecord
    Update-FormatData -AppendPath $PSScriptRoot\EventLogRecordView.ps1xml

    #Gather All Event Logs (rly not the way to do it)
    $AllEventLogs = (Get-ChildItem "C:\Windows\System32\winevt\Logs" -Filter "*.evtx" | Where-Object {$_.Length -gt 69632 -and $_.Name -notlike "*Operational.evtx"}).Name -replace "%4","/" -replace ".evtx",""
    #$AllEventLogs = [System.Diagnostics.Eventing.Reader.EventLogQuery]::new("Application",[System.Diagnostics.Eventing.Reader.PathType]::LogName).Session.GetLogNames()

    #Init
    $Filter=@();$level=@();$EventIDs=@();$Select=@()

    #Build Filter
    #Type
    IF ($null -ne $PSBoundParameters.Type){
        $PSBoundParameters.Type | ForEach-Object {
            IF ($_ -eq "Error") {$level += "Level=2"}
            IF ($_ -eq "Warning") {$level += "Level=3"}
            IF ($_ -eq "Information") {$level += "Level=4"}
        }
        $Filter += $level | Join-String -OutputPrefix "*[System[(" -Separator " or " -OutputSuffix ")]]"
    }
    #EventID
    IF ($null -ne $PSBoundParameters.EventID){
        $PSBoundParameters.EventID | ForEach-Object {
            $EventIDs += "EventID=$_"
        }
        $Filter += $EventIDs | Join-String -OutputPrefix "*[System[(" -Separator " or " -OutputSuffix ")]]"
    }
    #DaysPast
    IF ($null -ne $PSBoundParameters.DaysPast){
        #1Day = 86400000 (ms)
        $DPms = $PSBoundParameters.DaysPast * 86400000
        $Filter += "*[System[TimeCreated[timediff(@SystemTime) &lt;= $DPms]]]"
    }

    #Build Filter
    $Script:Filter = $Filter
    $QueryFilter = $Filter | Join-String -Separator " and "
    #Write-Debug $QueryFilter

    #LogName
    IF ($null -ne $PSBoundParameters.LogName){
        #$LogNameCount = $PSBoundParameters.LogName.count
        $PSBoundParameters.LogName | ForEach-Object {
            #$Select += $_ | Join-String -OutputPrefix
            $LogNameS = $_ | Join-String -FormatString '"{0}"'
            $Select += "<Select Path=$LogNameS>$QueryFilter</Select>"
            #Write-Debug $Select[-1]
        }
    } else {
        $AllEventLogs | ForEach-Object {
            $LogNameT = $_ | Join-String -FormatString '"{0}"'
            $Select += "<Select Path=$LogNameT>$QueryFilter</Select>"
            #Write-Debug $Select[-1]
        }
    }

    #Build Query
    $QueryID = 0 | Join-String -FormatString '"{0}"'
    $QueryPath = "Application" | Join-String -FormatString '"{0}"'
    [string]$Query = "<QueryList><Query Id=$QueryID Path=$QueryPath>$Select</Query></QueryList>"
    $Script:FunctionQuery = $Query
    #Write-Debug $Query

    #Event Reader, execute query
    $EventReader = [System.Diagnostics.Eventing.Reader.EventLogReader]::new(
        [System.Diagnostics.Eventing.Reader.EventLogQuery]::new(
            "Application",[System.Diagnostics.Eventing.Reader.PathType]::LogName,$Query
        )
    )

    #Gather EventLog Query Results
    $EventLog = @()
    $Continue = $true
    while ($Continue -eq $true) {
        try {
            $Entry = $EventReader.ReadEvent()
            IF ($Entry.Id -ne 0) {
                $EventLog += $Entry
                IF ($EventLog.count -gt 200 -and $choice -eq -1){UserConfirmation}
            }
        } catch {
            $Continue = $false
            #Write-Debug "Catch, end of results reached"
        }
    }

    #Format Output
    $EventLog | Sort-Object -Property TimeCreated -Descending #| Select-Object Level, TimeCreated, ID, ProviderName, Message

}
#Helper Functions
#Promt for User Confirmation
function UserConfirmation {
    [int]$DefaultChoice = 1
    $Yes = [System.Management.Automation.Host.ChoiceDescription]::new("&Yes", "Continue, might take a while")
    $No = [System.Management.Automation.Host.ChoiceDescription]::new("&No", "Stop")
    $options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no)
    $choice = $host.ui.PromptForChoice("$($EventLog.count), Results","Continue? `nMight take a while", $options,$DefaultChoice)
    if ($choice -eq 0) {
    } else {
        break
    }
}
#New Auto Completeion Result
function New-CompletionResult {
    param(
        [Parameter(Mandatory)]
        [string]$CompletionText,
        [string]$ListItemText = $CompletionText,
        [System.Management.Automation.CompletionResultType]$CompletionResultType = [System.Management.Automation.CompletionResultType]::ParameterValue,
        [string]$ToolTip = $CompletionText
    )

    New-Object System.Management.Automation.CompletionResult $CompletionText, $ListItemText, $CompletionResultType, $ToolTip
}
#Auto Completeion Provider for LogName
function LogNameCompletion {
    param (
        $commandName,
        $ParameterName,
        $WordToComplete,
        $CommandAst,
        $FakeBoundParameter
    )
    $AllEventLogs = (Get-ChildItem "C:\Windows\System32\winevt\Logs" -Filter "*.evtx" | Where-Object {$_.Length -gt 69632 -and $_.Name -notlike "*Operational.evtx"}).Name -replace "%4","/" -replace ".evtx",""
    $AllEventLogs |
    Where-Object { $_.StartsWith($wordToComplete); } |
    ForEach-Object { New-CompletionResult -CompletionText $_ }
}

#Register Argument Completer
Register-ArgumentCompleter -CommandName Get-EventLog -ParameterName LogName -ScriptBlock $function:LogNameCompletion