more clarity
This commit is contained in:
+119
-35
@@ -682,21 +682,57 @@ Function Write-UserLogonActivityOutput {
|
|||||||
Write-PlainTextTable -Rows $Rows -Columns @('Date', 'Time', 'User', 'Activity', 'Source', 'Details')
|
Write-PlainTextTable -Rows $Rows -Columns @('Date', 'Time', 'User', 'Activity', 'Source', 'Details')
|
||||||
}
|
}
|
||||||
|
|
||||||
Function Get-PossibleUseWindowAction {
|
Function Get-LocalUnlockedWindowAction {
|
||||||
Param(
|
Param(
|
||||||
[AllowNull()]
|
[AllowNull()]
|
||||||
[string]$Activity
|
[string]$Activity
|
||||||
)
|
)
|
||||||
|
|
||||||
Switch ($Activity) {
|
Switch ($Activity) {
|
||||||
'session reconnect' { Return 'reconnect' }
|
'session reconnect' { Return 'RDP reconnect' }
|
||||||
'session disconnect' { Return 'disconnect' }
|
'session disconnect' { Return 'session disconnect' }
|
||||||
'screensaver dismiss' { Return 'screensaver dismiss' }
|
'screensaver dismiss' { Return 'screensaver dismiss' }
|
||||||
'screensaver start' { Return 'screensaver start' }
|
'screensaver start' { Return 'screensaver start' }
|
||||||
Default { Return $Activity }
|
Default { Return $Activity }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Function Format-LocalUnlockedDuration {
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[datetime]$StartTime,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[datetime]$EndTime,
|
||||||
|
|
||||||
|
[switch]$Maximum
|
||||||
|
)
|
||||||
|
|
||||||
|
$Duration = $EndTime - $StartTime
|
||||||
|
If ($Duration.TotalSeconds -lt 0) {
|
||||||
|
$Duration = [TimeSpan]::Zero
|
||||||
|
}
|
||||||
|
|
||||||
|
If ($Duration.Days -gt 0) {
|
||||||
|
$Text = '{0}d {1}h {2}m' -f $Duration.Days, $Duration.Hours, $Duration.Minutes
|
||||||
|
}
|
||||||
|
ElseIf ($Duration.Hours -gt 0) {
|
||||||
|
$Text = '{0}h {1}m' -f $Duration.Hours, $Duration.Minutes
|
||||||
|
}
|
||||||
|
ElseIf ($Duration.Minutes -gt 0) {
|
||||||
|
$Text = '{0}m {1}s' -f $Duration.Minutes, $Duration.Seconds
|
||||||
|
}
|
||||||
|
Else {
|
||||||
|
$Text = '{0}s' -f $Duration.Seconds
|
||||||
|
}
|
||||||
|
|
||||||
|
If ($Maximum) {
|
||||||
|
Return "up to ${Text}"
|
||||||
|
}
|
||||||
|
|
||||||
|
Return $Text
|
||||||
|
}
|
||||||
|
|
||||||
Function Test-RedundantOpeningUnlock {
|
Function Test-RedundantOpeningUnlock {
|
||||||
Param(
|
Param(
|
||||||
[Parameter(Mandatory=$true)]
|
[Parameter(Mandatory=$true)]
|
||||||
@@ -712,7 +748,10 @@ Function Test-RedundantOpeningUnlock {
|
|||||||
|
|
||||||
ForEach ($CandidateEvent in @($ActivityEvents)) {
|
ForEach ($CandidateEvent in @($ActivityEvents)) {
|
||||||
If (
|
If (
|
||||||
$CandidateEvent.Activity -in @('logon', 'session reconnect') -and
|
(
|
||||||
|
$CandidateEvent.Activity -eq 'logon' -or
|
||||||
|
(Test-RemoteSessionReconnect -ActivityEvent $CandidateEvent)
|
||||||
|
) -and
|
||||||
[Math]::Abs(($CandidateEvent.TimeCreated - $ActivityEvent.TimeCreated).TotalSeconds) -le 5
|
[Math]::Abs(($CandidateEvent.TimeCreated - $ActivityEvent.TimeCreated).TotalSeconds) -le 5
|
||||||
) {
|
) {
|
||||||
Return $true
|
Return $true
|
||||||
@@ -722,23 +761,56 @@ Function Test-RedundantOpeningUnlock {
|
|||||||
Return $false
|
Return $false
|
||||||
}
|
}
|
||||||
|
|
||||||
Function Get-PossibleUseWindow {
|
Function Get-ActivityEventDetailValue {
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[object]$ActivityEvent,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[string]$Name
|
||||||
|
)
|
||||||
|
|
||||||
|
$Details = [string]$ActivityEvent.Details
|
||||||
|
If ([string]::IsNullOrWhiteSpace($Details)) { Return $null }
|
||||||
|
|
||||||
|
ForEach ($Part in ($Details -split ';')) {
|
||||||
|
$TrimmedPart = $Part.Trim()
|
||||||
|
|
||||||
|
If ($TrimmedPart -match "^$([regex]::Escape($Name))=(.*)$") {
|
||||||
|
Return $Matches[1].Trim()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Return $null
|
||||||
|
}
|
||||||
|
|
||||||
|
Function Test-RemoteSessionReconnect {
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[object]$ActivityEvent
|
||||||
|
)
|
||||||
|
|
||||||
|
If ($ActivityEvent.Activity -ne 'session reconnect') { Return $false }
|
||||||
|
|
||||||
|
$Address = Get-ActivityEventDetailValue -ActivityEvent $ActivityEvent -Name 'Address'
|
||||||
|
If ([string]::IsNullOrWhiteSpace($Address)) { Return $false }
|
||||||
|
If ($Address -eq '-' -or $Address -ieq 'LOCAL') { Return $false }
|
||||||
|
|
||||||
|
Return $true
|
||||||
|
}
|
||||||
|
|
||||||
|
Function Get-LocalUnlockedWindow {
|
||||||
Param(
|
Param(
|
||||||
[AllowNull()]
|
[AllowNull()]
|
||||||
[object[]]$ActivityEvents
|
[object[]]$ActivityEvents
|
||||||
)
|
)
|
||||||
|
|
||||||
$OpenWindow = $null
|
$OpenWindow = $null
|
||||||
$UseWindows = New-Object System.Collections.Generic.List[object]
|
$UnlockedWindows = New-Object System.Collections.Generic.List[object]
|
||||||
$OpeningActivities = @('logon', 'unlock', 'remote logon', 'session reconnect', 'screensaver dismiss')
|
$OpeningActivities = @('logon', 'unlock', 'screensaver dismiss')
|
||||||
$ImpliedClosureDescriptions = @{
|
$ClosingActivities = @('logoff', 'lock', 'screensaver start', 'session disconnect', 'session reconnect', 'remote logon', 'sleep', 'shutdown', 'restart')
|
||||||
'unlock' = 'lock before unlock'
|
$RepeatedOpeningClosureDescriptions = @{
|
||||||
'session reconnect' = 'disconnect before reconnect'
|
|
||||||
'screensaver dismiss' = 'screensaver before dismiss'
|
|
||||||
}
|
|
||||||
$ImpliedClosureNotes = @{
|
|
||||||
'unlock' = 'lock time unknown'
|
'unlock' = 'lock time unknown'
|
||||||
'session reconnect' = 'disconnect time unknown'
|
|
||||||
'screensaver dismiss' = 'screensaver start unknown'
|
'screensaver dismiss' = 'screensaver start unknown'
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -753,16 +825,26 @@ Function Get-PossibleUseWindow {
|
|||||||
Continue
|
Continue
|
||||||
}
|
}
|
||||||
|
|
||||||
If ($Activity -in @('logoff', 'lock', 'session disconnect', 'sleep', 'shutdown', 'restart')) {
|
If ($Activity -eq 'session reconnect' -and -not (Test-RemoteSessionReconnect -ActivityEvent $ActivityEvent)) {
|
||||||
|
Continue
|
||||||
|
}
|
||||||
|
|
||||||
|
If ($Activity -in $ClosingActivities) {
|
||||||
If ($null -ne $OpenWindow) {
|
If ($null -ne $OpenWindow) {
|
||||||
$UseWindows.Add([PSCustomObject]@{
|
$Note = ''
|
||||||
|
If ($Activity -eq 'session reconnect' -or $Activity -eq 'remote logon') {
|
||||||
|
$Note = 'local console unavailable during remote session'
|
||||||
|
}
|
||||||
|
|
||||||
|
$UnlockedWindows.Add([PSCustomObject]@{
|
||||||
StartTime = $OpenWindow.StartTime
|
StartTime = $OpenWindow.StartTime
|
||||||
Start = $OpenWindow.StartTime.ToString('yyyy-MM-dd HH:mm:ss')
|
Start = $OpenWindow.StartTime.ToString('yyyy-MM-dd HH:mm:ss')
|
||||||
End = $ActivityEvent.TimeCreated.ToString('yyyy-MM-dd HH:mm:ss')
|
End = $ActivityEvent.TimeCreated.ToString('yyyy-MM-dd HH:mm:ss')
|
||||||
|
Duration = Format-LocalUnlockedDuration -StartTime $OpenWindow.StartTime -EndTime $ActivityEvent.TimeCreated
|
||||||
User = $OpenWindow.User
|
User = $OpenWindow.User
|
||||||
Opened = $OpenWindow.Opened
|
Opened = $OpenWindow.Opened
|
||||||
Closed = Get-PossibleUseWindowAction -Activity $Activity
|
Closed = Get-LocalUnlockedWindowAction -Activity $Activity
|
||||||
Note = ''
|
Note = $Note
|
||||||
}) | Out-Null
|
}) | Out-Null
|
||||||
$OpenWindow = $null
|
$OpenWindow = $null
|
||||||
}
|
}
|
||||||
@@ -775,15 +857,16 @@ Function Get-PossibleUseWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
If ($Activity -in $OpeningActivities) {
|
If ($Activity -in $OpeningActivities) {
|
||||||
If ($null -ne $OpenWindow -and $ImpliedClosureDescriptions.ContainsKey($Activity)) {
|
If ($null -ne $OpenWindow -and $RepeatedOpeningClosureDescriptions.ContainsKey($Activity)) {
|
||||||
$UseWindows.Add([PSCustomObject]@{
|
$UnlockedWindows.Add([PSCustomObject]@{
|
||||||
StartTime = $OpenWindow.StartTime
|
StartTime = $OpenWindow.StartTime
|
||||||
Start = $OpenWindow.StartTime.ToString('yyyy-MM-dd HH:mm:ss')
|
Start = $OpenWindow.StartTime.ToString('yyyy-MM-dd HH:mm:ss')
|
||||||
End = "before $($ActivityEvent.TimeCreated.ToString('yyyy-MM-dd HH:mm:ss'))"
|
End = "before $($ActivityEvent.TimeCreated.ToString('yyyy-MM-dd HH:mm:ss'))"
|
||||||
|
Duration = Format-LocalUnlockedDuration -StartTime $OpenWindow.StartTime -EndTime $ActivityEvent.TimeCreated -Maximum
|
||||||
User = $OpenWindow.User
|
User = $OpenWindow.User
|
||||||
Opened = $OpenWindow.Opened
|
Opened = $OpenWindow.Opened
|
||||||
Closed = $ImpliedClosureDescriptions[$Activity]
|
Closed = $RepeatedOpeningClosureDescriptions[$Activity]
|
||||||
Note = $ImpliedClosureNotes[$Activity]
|
Note = 'latest possible duration'
|
||||||
}) | Out-Null
|
}) | Out-Null
|
||||||
$OpenWindow = $null
|
$OpenWindow = $null
|
||||||
}
|
}
|
||||||
@@ -792,17 +875,18 @@ Function Get-PossibleUseWindow {
|
|||||||
$OpenWindow = [PSCustomObject]@{
|
$OpenWindow = [PSCustomObject]@{
|
||||||
StartTime = $ActivityEvent.TimeCreated
|
StartTime = $ActivityEvent.TimeCreated
|
||||||
User = $User
|
User = $User
|
||||||
Opened = Get-PossibleUseWindowAction -Activity $Activity
|
Opened = Get-LocalUnlockedWindowAction -Activity $Activity
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
If ($null -ne $OpenWindow) {
|
If ($null -ne $OpenWindow) {
|
||||||
$UseWindows.Add([PSCustomObject]@{
|
$UnlockedWindows.Add([PSCustomObject]@{
|
||||||
StartTime = $OpenWindow.StartTime
|
StartTime = $OpenWindow.StartTime
|
||||||
Start = $OpenWindow.StartTime.ToString('yyyy-MM-dd HH:mm:ss')
|
Start = $OpenWindow.StartTime.ToString('yyyy-MM-dd HH:mm:ss')
|
||||||
End = 'open through returned events'
|
End = 'open through returned events'
|
||||||
|
Duration = 'open'
|
||||||
User = $OpenWindow.User
|
User = $OpenWindow.User
|
||||||
Opened = $OpenWindow.Opened
|
Opened = $OpenWindow.Opened
|
||||||
Closed = 'not returned'
|
Closed = 'not returned'
|
||||||
@@ -810,25 +894,25 @@ Function Get-PossibleUseWindow {
|
|||||||
}) | Out-Null
|
}) | Out-Null
|
||||||
}
|
}
|
||||||
|
|
||||||
Return $UseWindows
|
Return $UnlockedWindows
|
||||||
}
|
}
|
||||||
|
|
||||||
Function Write-PossibleUseWindowOutput {
|
Function Write-LocalUnlockedWindowOutput {
|
||||||
Param(
|
Param(
|
||||||
[AllowNull()]
|
[AllowNull()]
|
||||||
[object[]]$ActivityEvents
|
[object[]]$ActivityEvents
|
||||||
)
|
)
|
||||||
|
|
||||||
$UseWindows = @(Get-PossibleUseWindow -ActivityEvents $ActivityEvents | Sort-Object -Property StartTime)
|
$UnlockedWindows = @(Get-LocalUnlockedWindow -ActivityEvents $ActivityEvents | Sort-Object -Property StartTime)
|
||||||
|
|
||||||
If ($UseWindows.Count -eq 0) {
|
If ($UnlockedWindows.Count -eq 0) {
|
||||||
Write-Output 'Possible use windows inferred from returned events: none'
|
Write-Output 'Local unlocked windows inferred from returned events: none'
|
||||||
Return
|
Return
|
||||||
}
|
}
|
||||||
|
|
||||||
$Rows = @($UseWindows | Select-Object Start,End,User,Opened,Closed,Note)
|
$Rows = @($UnlockedWindows | Select-Object Start,End,Duration,User,Opened,Closed,Note)
|
||||||
Write-Output 'Possible use windows inferred from returned events:'
|
Write-Output 'Local unlocked windows inferred from returned events:'
|
||||||
Write-PlainTextTable -Rows $Rows -Columns @('Start', 'End', 'User', 'Opened', 'Closed', 'Note')
|
Write-PlainTextTable -Rows $Rows -Columns @('Start', 'End', 'Duration', 'User', 'Opened', 'Closed', 'Note')
|
||||||
}
|
}
|
||||||
|
|
||||||
# Winlogon 7001/7002 tracks user session logon/logoff more reliably than Security 4624/4634.
|
# Winlogon 7001/7002 tracks user session logon/logoff more reliably than Security 4624/4634.
|
||||||
@@ -945,9 +1029,9 @@ ForEach ($PowerFilter in $PowerFilters) {
|
|||||||
$OutputEvents = @(Get-UniqueUserLogonActivity -ActivityEvents $ActivityEvents | Sort-Object -Property TimeCreated)
|
$OutputEvents = @(Get-UniqueUserLogonActivity -ActivityEvents $ActivityEvents | Sort-Object -Property TimeCreated)
|
||||||
Write-UserLogonActivityOutput -ActivityEvents $OutputEvents -StartDateTime $StartDateTime -EndDateTime $EndDateTime
|
Write-UserLogonActivityOutput -ActivityEvents $OutputEvents -StartDateTime $StartDateTime -EndDateTime $EndDateTime
|
||||||
Try {
|
Try {
|
||||||
Write-PossibleUseWindowOutput -ActivityEvents $OutputEvents
|
Write-LocalUnlockedWindowOutput -ActivityEvents $OutputEvents
|
||||||
}
|
}
|
||||||
Catch {
|
Catch {
|
||||||
$PossibleUseWindowError = Get-UserLogonActivityErrorMessage -ErrorRecord $_ -FallbackMessage 'Unable to infer possible use windows.'
|
$LocalUnlockedWindowError = Get-UserLogonActivityErrorMessage -ErrorRecord $_ -FallbackMessage 'Unable to infer local unlocked windows.'
|
||||||
Write-Output "Possible use windows inferred from returned events: unavailable. ${PossibleUseWindowError}"
|
Write-Output "Local unlocked windows inferred from returned events: unavailable. ${LocalUnlockedWindowError}"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user