diff --git a/Get-UserLogonActivity.ps1 b/Get-UserLogonActivity.ps1 index 4707ad8..cb8e989 100644 --- a/Get-UserLogonActivity.ps1 +++ b/Get-UserLogonActivity.ps1 @@ -36,6 +36,33 @@ Function Test-ActivityDateRangeValue { Return $true } +Function Get-UserLogonActivityErrorMessage { + Param( + [AllowNull()] + [object]$ErrorRecord, + + [string]$FallbackMessage = 'Unknown error.' + ) + + $Message = '' + + If ($null -ne $ErrorRecord) { + If ($null -ne $ErrorRecord.Exception) { + $Message = [string]$ErrorRecord.Exception.Message + } + + If ([string]::IsNullOrWhiteSpace($Message)) { + $Message = [string]$ErrorRecord + } + } + + If ([string]::IsNullOrWhiteSpace($Message)) { + $Message = $FallbackMessage + } + + Return $Message +} + $StartHasValue = ($null -ne $StartVariable -and (Test-ActivityDateRangeValue -Value $StartVariable.Value)) $EndHasValue = ($null -ne $EndVariable -and (Test-ActivityDateRangeValue -Value $EndVariable.Value)) @@ -585,13 +612,38 @@ Function Write-UserLogonActivityOutput { Write-Output (($Rows | Format-Table -AutoSize | Out-String -Width 240).TrimEnd()) } +Function Test-RedundantSessionReconnectUnlock { + Param( + [Parameter(Mandatory=$true)] + [object]$ActivityEvent, + + [AllowNull()] + [object[]]$ActivityEvents + ) + + If ($ActivityEvent.Activity -ne 'unlock' -or $ActivityEvent.Source -ne 'Security 4624 type 7') { + Return $false + } + + ForEach ($CandidateEvent in @($ActivityEvents)) { + If ( + $CandidateEvent.Activity -eq 'session reconnect' -and + [Math]::Abs(($CandidateEvent.TimeCreated - $ActivityEvent.TimeCreated).TotalSeconds) -le 5 + ) { + Return $true + } + } + + Return $false +} + Function Get-PossibleUseWindow { Param( [AllowNull()] [object[]]$ActivityEvents ) - $OpenWindows = @{} + $OpenWindow = $null $UseWindows = New-Object System.Collections.Generic.List[object] $OpeningActivities = @('logon', 'unlock', 'remote logon', 'session reconnect', 'screensaver dismiss') $ImpliedClosureDescriptions = @{ @@ -600,19 +652,19 @@ Function Get-PossibleUseWindow { 'screensaver dismiss' = 'implied prior screensaver before' } - ForEach ($ActivityEvent in (@($ActivityEvents) | Where-Object { $null -ne $_ } | Sort-Object -Property TimeCreated)) { + $OrderedActivityEvents = @($ActivityEvents | Where-Object { $null -ne $_ } | Sort-Object -Property TimeCreated) + + ForEach ($ActivityEvent in $OrderedActivityEvents) { $User = [string]$ActivityEvent.User - $UserKey = [string]$ActivityEvent.UserKey $Activity = [string]$ActivityEvent.Activity $Source = [string]$ActivityEvent.Source - If ([string]::IsNullOrWhiteSpace($UserKey)) { - $UserKey = Get-UserLogonActivityKey -Sid $null -User $User + If (Test-RedundantSessionReconnectUnlock -ActivityEvent $ActivityEvent -ActivityEvents $OrderedActivityEvents) { + Continue } - If ($Activity -in @('sleep', 'shutdown', 'restart')) { - ForEach ($OpenUserKey in @($OpenWindows.Keys)) { - $OpenWindow = $OpenWindows[$OpenUserKey] + If ($Activity -in @('logoff', 'lock', 'session disconnect', 'sleep', 'shutdown', 'restart')) { + If ($null -ne $OpenWindow) { $UseWindows.Add([PSCustomObject]@{ StartTime = $OpenWindow.StartTime Start = $OpenWindow.StartTime.ToString('yyyy-MM-dd HH:mm:ss') @@ -621,7 +673,7 @@ Function Get-PossibleUseWindow { StartedBy = $OpenWindow.StartedBy EndedBy = "${Activity} / ${Source}" }) | Out-Null - $OpenWindows.Remove($OpenUserKey) + $OpenWindow = $null } Continue @@ -632,8 +684,7 @@ Function Get-PossibleUseWindow { } If ($Activity -in $OpeningActivities) { - If ($OpenWindows.ContainsKey($UserKey) -and $ImpliedClosureDescriptions.ContainsKey($Activity)) { - $OpenWindow = $OpenWindows[$UserKey] + If ($null -ne $OpenWindow -and $ImpliedClosureDescriptions.ContainsKey($Activity)) { $UseWindows.Add([PSCustomObject]@{ StartTime = $OpenWindow.StartTime Start = $OpenWindow.StartTime.ToString('yyyy-MM-dd HH:mm:ss') @@ -642,35 +693,20 @@ Function Get-PossibleUseWindow { StartedBy = $OpenWindow.StartedBy EndedBy = "$($ImpliedClosureDescriptions[$Activity]) ${Activity} / ${Source}" }) | Out-Null - $OpenWindows.Remove($UserKey) + $OpenWindow = $null } - If (-not $OpenWindows.ContainsKey($UserKey)) { - $OpenWindows[$UserKey] = [PSCustomObject]@{ + If ($null -eq $OpenWindow) { + $OpenWindow = [PSCustomObject]@{ StartTime = $ActivityEvent.TimeCreated User = $User StartedBy = "${Activity} / ${Source}" } } } - ElseIf ($Activity -in @('logoff', 'lock', 'session disconnect')) { - If ($OpenWindows.ContainsKey($UserKey)) { - $OpenWindow = $OpenWindows[$UserKey] - $UseWindows.Add([PSCustomObject]@{ - StartTime = $OpenWindow.StartTime - Start = $OpenWindow.StartTime.ToString('yyyy-MM-dd HH:mm:ss') - End = $ActivityEvent.TimeCreated.ToString('yyyy-MM-dd HH:mm:ss') - User = $OpenWindow.User - StartedBy = $OpenWindow.StartedBy - EndedBy = "${Activity} / ${Source}" - }) | Out-Null - $OpenWindows.Remove($UserKey) - } - } } - ForEach ($OpenUserKey in @($OpenWindows.Keys)) { - $OpenWindow = $OpenWindows[$OpenUserKey] + If ($null -ne $OpenWindow) { $UseWindows.Add([PSCustomObject]@{ StartTime = $OpenWindow.StartTime Start = $OpenWindow.StartTime.ToString('yyyy-MM-dd HH:mm:ss') @@ -769,7 +805,7 @@ Try { } } Catch { - Write-Error $_.Exception.Message + Write-Error (Get-UserLogonActivityErrorMessage -ErrorRecord $_ -FallbackMessage 'Unable to resolve the activity date range.') Exit 1 } @@ -817,4 +853,11 @@ ForEach ($PowerFilter in $PowerFilters) { $OutputEvents = @(Get-UniqueUserLogonActivity -ActivityEvents $ActivityEvents | Sort-Object -Property TimeCreated) Write-UserLogonActivityOutput -ActivityEvents $OutputEvents -Write-PossibleUseWindowOutput -ActivityEvents $OutputEvents +Try { + Write-PossibleUseWindowOutput -ActivityEvents $OutputEvents +} +Catch { + $PossibleUseWindowError = Get-UserLogonActivityErrorMessage -ErrorRecord $_ -FallbackMessage 'Unable to infer possible use windows.' + Write-Output '' + Write-Output "Possible use windows inferred from returned events: unavailable. ${PossibleUseWindowError}" +}