Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #requires -RunAsAdministrator
- #requires -Version 4
- function Get-LogOnOffTimeSpanInfo
- {
- <#
- .SYNOPSIS
- Find all longon/logoff & total active session times.
- .DESCRIPTION
- This script finds all logon, logoff and total active session times of users on the computer specified.
- For this script to function as expected, the advanced AD policies ...
- - Audit Logon
- - Audit Logoff
- - Audit Other Logon/Logoff Events
- ... must be enabled and targeted to the appropriate computers via GPO.
- One thing that it does NOT do on win7ps5.1 is get the current logged in user.
- I don't know why, tho.
- .PARAMETER ComputerName
- The name of the computer to check. Defaults to "$env:COMPUTERNAME".
- .PARAMETER IncludeOrphanLogons
- This will include logon entries that do NOT have matching logoff entries.
- The result will be some VERY long timespans.
- .EXAMPLE
- No examples at this time.
- .NOTES
- Source = Random-PowerShell-Work/Get-UserLogonSessionHistory.ps1 at master
- adbertram/Random-PowerShell-Work
- — https://github.com/adbertram/Random-PowerShell-Work/blob/master/ActiveDirectory/Get-UserLogonSessionHistory.ps1
- Version info ..
- - 2018-10-06 = changes made by Lee_Dailey
- renamed from "Get-EventLogs" to "Get-LogOnOffTimeSpanInfo"
- = the name was far too similar to the builtin "Get-EventLog" cmdlet
- = original source name was "Get-UserLogonSessionHistory"
- modified to make it more readable [to me] & fewer long lines
- moved CBH into the function instead of before it
- renamed .SYNOPSIS to .DESCRIPTION since it is a LONG description
- added a less wordy .SYSNOPSIS
- reformatted to my sometimes odd preferences
- added 4-space indents instead of two
- removed entirely unneeded TRY @ 31 & matching CATCH @ 119
- also removed unneeded TRY @ 50 & matching CATCH @ 111
- removed credentials code
- = use an elevated session
- tried to fix test for orphaned start time [no stop time to go with it]
- = old version left that user out
- = this will give _really_ odd timespans for anyone other than the current user [*grin*]
- replaced Write-Verbose calls with Write-Information
- = avoids unwanted verbose output of the Get-WinEvent cmdlet
- set default $ComputerName = $env:COMPUTERNAME
- removed "Mandatory" for $ComputerName parameter
- added $IncludeOrphanLogons switch, code to use it, & ".PARAMETER" info
- #>
- Param
- (
- [Parameter (
- Position = 0
- )]
- [ValidateNotNullOrEmpty ()]
- [string]
- $ComputerName = $env:COMPUTERNAME,
- [Parameter ()]
- [switch]
- $IncludeOrphanLogons
- )
- begin
- {
- $NewSessionStartMsg = @'
- New session start event found:
- event ID = {0}
- username = {1}
- logonID = {2}
- time = {3}
- '@
- #region >> define events to indicate session start or stop
- $SessionEvents = @(
- ## Advanced Audit Policy --> Audit Logon
- @{
- Label = 'Logon'
- EventType = 'SessionStart'
- LogName = 'Security'
- ID = 4624
- }
- # Advanced Audit Policy --> Audit Logoff
- @{
- Label = 'Logoff'
- EventType = 'SessionStop'
- LogName = 'Security'
- ID = 4647
- }
- @{
- Label = 'Startup'
- EventType = 'SessionStop'
- LogName = 'System'
- ID = 6005
- }
- # Advanced Audit Policy --> Audit Other Logon/Logoff Events
- @{
- Label = 'RdpSessionReconnect'
- EventType = 'SessionStart'
- LogName = 'Security'
- ID = 4778
- }
- # Advanced Audit Policy --> Audit Other Logon/Logoff Events
- @{
- Label = 'RdpSessionDisconnect'
- EventType = 'SessionStop'
- LogName = 'Security'
- ID = 4779
- }
- # Advanced Audit Policy --> Audit Other Logon/Logoff Events
- @{
- Label = 'Locked'
- EventType = 'SessionStop'
- LogName = 'Security'
- ID = 4800
- }
- # Advanced Audit Policy --> Audit Other Logon/Logoff Events
- @{
- Label = 'Unlocked'
- EventType = 'SessionStart'
- LogName = 'Security'
- ID = 4801
- }
- ) # end >> $SessionEvents = @(
- $SessionStartIds = ($SessionEvents.Where({
- $_.EventType -eq 'SessionStart'
- })).ID
- # from LD - i dunno what line the next comment really otta go with
- # it was at the end of the "$SessionStopIDs" line
- # Startup ID will be used for events where the computer was powered off abruptly or crashes
- # not a great measurement
- $SessionStopIds = ($SessionEvents.Where({
- $_.EventType -eq 'SessionStop'
- })).ID
- #endregion >> define events to indicate session start or stop
- $logNames = $SessionEvents.LogName |
- Select-Object -Unique
- $ids = $SessionEvents.Id
- # Build the insane XPath query for the security event log in order to query events as fast as possible
- $logonXPath =
- 'Event[System[EventID=4624]] and ' +
- "Event[EventData[Data[@Name='TargetDomainName'] != 'Window Manager']] and " +
- "Event[EventData[Data[@Name='TargetDomainName'] != 'NT AUTHORITY']] and " +
- "(Event[EventData[Data[@Name='LogonType'] = '2']] or " +
- "Event[EventData[Data[@Name='LogonType'] = '11']])"
- $otherXpath = 'Event[System[({0})]]' -f "EventID=$(($ids.
- where({$_ -ne '4624' })) -join ' or EventID=')"
- $xPath = '({0}) or ({1})' -f $logonXPath, $otherXpath
- } # end >> begin block
- process
- {
- Write-Information ('Starting to gather event log info for {0} ...' -f $ComputerName)
- $events = Get-WinEvent -ComputerName $ComputerName -LogName $logNames -FilterXPath $xPath
- Write-Information (' Found [ {0} ] events to look through.' -f $events.Count)
- $events.foreach({
- if ($_.Id -in $SessionStartIds)
- {
- $logonEvtId = $_.Id
- $xEvt = [xml]$_.ToXml()
- $Username = ($xEvt.Event.EventData.Data |
- Where-Object {
- $_.Name -eq 'TargetUserName'
- }).'#text'
- $LogonId = ($xEvt.Event.EventData.Data |
- Where-Object {
- $_.Name -eq 'TargetLogonId'
- }).'#text'
- if (-not $LogonId)
- {
- $LogonId = ($xEvt.Event.EventData.Data |
- Where-Object {
- $_.Name -eq 'LogonId'
- }).'#text'
- }
- $LogonTime = $_.TimeCreated
- Write-Information ($NewSessionStartMsg -f $logonEvtId, $Username, $LogonId, $LogonTime)
- $SessionEndEvent = $Events.where({
- $_.TimeCreated -gt $LogonTime -and
- $_.ID -in $SessionStopIds -and
- (([xml]$_.ToXml()).Event.EventData.Data |
- Where-Object {
- $_.Name -eq 'TargetLogonId'
- }).'#text' -eq $LogonId
- }) |
- Select-Object -First 1
- # this handles orphaned StartTimes
- # this gives a _large_ number of orphans - currently 91 of 170 on my system
- if (-not $SessionEndEvent)
- {
- Write-Information (' Could not find a session end event for logon ID [ {0} ].' -f $LogonId)
- Write-Information ' Using current date & time.'
- if ($IncludeOrphanLogons)
- {
- $LogoffTime = Get-Date
- }
- else
- {
- $LogoffTime = ''
- }
- }
- else
- {
- $LogoffTime = $SessionEndEvent.TimeCreated
- }
- # if the $LogoffTime is blank, then we want to skip this one
- if (-not [string]::IsNullOrEmpty($LogoffTime))
- {
- Write-Information (' Session stop ID is [ {0} ]' -f $SessionEndEvent.Id)
- $LogoffId = $SessionEndEvent.Id
- $SessionActiveTime = $LogoffTime - $LogonTime
- [PSCustomObject]@{
- ComputerName = $_.MachineName
- Username = $Username
- StartTime = $LogonTime
- StartAction = $SessionEvents.where({ $_.ID -eq $logonEvtId }).Label
- StopTime = $LogoffTime
- StopAction = $SessionEvents.where({ $_.ID -eq $LogoffID }).Label
- SessionActive_Days = '{0:N2}' -f $SessionActiveTime.TotalDays
- SessionActive_Minutes = '{0}' -f ([int]$SessionActiveTime.TotalMinutes)
- }
- }
- } # end >> if ($_.Id -in $SessionStartIds)
- }) # end >> $events.foreach({
- } # end >> process block
- end {}
- } # end >> function Get-LogOnOffTimeSpanInfo
- # grab your list from a text file OR via Get-ADComputer [*grin*]
- $ComputerList = @(
- 'LocalHost'
- '10.0.0.1'
- '127.0.0.1'
- 'BetterNotBeThere'
- $env:COMPUTERNAME
- )
- $IC_Params = @{
- ComputerName = $ComputerList
- ScriptBlock = ${Function:Get-LogOnOffTimeSpanInfo}
- # comment out the next line if you want to see the errors
- ErrorAction = 'SilentlyContinue'
- }
- # run the code on each system and only send back the filtered info
- $RespondingSystems = Invoke-Command @IC_Params
- $NON_RespondingSystems = $ComputerList.Where({
- $_ -notin $RespondingSystems.PSComputerName
- })
- $ReportDir = $env:TEMP
- $GroupedRS = $RespondingSystems |
- # strip out the unwanted properties from Invoke-Command
- Select-Object -Property '*' -ExcludeProperty PSComputerName, RunspaceId, PSShowComputerName |
- Group-Object -Property UserName
- foreach ($GRS_Item in $GroupedRS)
- {
- $FileName = ('{0}.csv' -f $GRS_Item.Name)
- $FullFileName = Join-Path -Path $ReportDir -ChildPath $FileName
- $GRS_Item.Group |
- Export-Csv -LiteralPath $FullFileName -NoTypeInformation -Append
- }
- $NON_RespondingSystems |
- Set-Content -LiteralPath (Join-Path -Path $ReportDir -ChildPath 'NON_RespondingSystems.txt')
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement