To be able to do this in your domain will require some setup work. First off, you need to configure a Group Policy to ensure that the proper events are being audited on your clients. As with all Group Policy, you must make sure that the policy is scoped to reach your clients, and that you have allowed ample time for the policy to be replicated in your domain, downloaded to the clients, and applied.
Note: This will only work for client that are Windows Vista or later.
The audit policy to set is: Logon/Logoff Events with the sub category of Other Logon/Logoff Events set to capture Successful events. In your Group Policy, follow these instructions.
- Expand Computer Configuration \ Policies \ Windows Settings \ Security Settings \ Advanced Audit Policy Configuration \ Audit Policies \ Logon/Logoff
- Double click Audit Other Logon/Logoff Events
- Check Configure the following audit events.
- Check Success
Once this policy is applied to your clients, you will now be able to look for the following events in the security log of your clients:
ID | Event |
4649 | A replay attack was detected. |
4778 | A session was reconnected to a Window Station. |
4779 | A session was disconnected from a Window Station. |
4800 | The workstation was locked. |
4801 | The workstation was unlocked. |
4802 | The screen saver was invoked. |
4803 | The screen saver was dismissed. |
5378 | The requested credentials delegation was disallowed by policy. |
5632 | A request was made to authenticate to a wireless network. |
5633 | A request was made to authenticate to a wired network. |
We also need to enable auditing for interactive logons on your clients.
- Expand Computer Configuration \ Policies \ Windows Settings \ Security Settings \ Advanced Audit Policy Configuration \ Audit Policies \ Logon/Logoff
- Double click Audit Logon.
- Check Configure the following audit events.
- Check Success
Finally, we need to determine if the user has logged off.
- Expand Computer Configuration \ Policies \ Windows Settings \ Security Settings \ Advanced Audit Policy Configuration \ Audit Policies \ Logon/Logoff
- Double click Audit Logoff.
- Check Configure the following audit events.
- Check Success
We are interested in 3 events. If Event 4800 is the first of the three that we come across, then the client is locked. If event 4801 is the first, then the client has been unlocked, but the code below will detect event 4648 which will be logged right after event 4801. Event 4801 will not be generated if the client is powered off without first unlocking and then doing a proper shutdown. In other words there was a loss of power or the user just held the power button in until the machine forced itself to power down. For this reason, we also need to look for event 4648 which is an interactive logon. If the client is on, but the user logged off, we need to look for event 4647.
A list of these audit event can be obtained at: http://support.microsoft.com/default.aspx?scid=kb;EN-US;947226
The code below is designed to me dot sourced into your current PowerShell session. Look for the Status property to see if the machine is locked, logged on, or logged off.
<#
.SYNOPSIS
Determines if a client is locked.
.DESCRIPTION
Examines a client to determine if it is locked, logged on, of logged off.
.PARAMETER ComputerName
The Name or IP address of the client to test.
.PARAMETER DaysToSearch
The number of days in history you want to examin in the clients log files. The default is 14 days.
.EXAMPLE
PS C:\Users\Administrator> Test-LockedClient lon-cli1
Status : Unlocked
TimeCreated : 8/17/2012 10:48:31 AM
TimeDiff : 00:16:58.7258484
UserName : administrator
Domain : CONTOSO
Checks the status of a client.
.EXAMPLE
PS C:\Users\Administrator> Test-LockedClient lon-cli1 -DaysToSearch 10
Status : Unlocked
TimeCreated : 8/17/2012 10:48:31 AM
TimeDiff : 00:18:02.8665857
UserName : administrator
Domain : CONTOSO
Checks the status of a client, Examining the log files back 10 days instead of the default of 14.
#>
Function Test-LockedClient
{
Param (
[cmdletbinding()]
[Parameter(Mandatory=$True)]$ComputerName,
[int]$DaysToSearch = 14
)
$StartTime = (Get-Date).AddDays(-($DaysToSearch))
$LogHash = @{LogName = 'Security';StartTime = $StartTime; ID=4647,4648,4800,4801}
Try
{
$Event = Get-WinEvent -FilterHashtable $LogHash -ComputerName $ComputerName -ea Stop |
Sort-Object -Property TimeCreated -Descending |
Select -First 1
}
Catch
{
Write-Host "Host offline" -ForegroundColor Red -BackgroundColor DarkRed
}
Switch ($Event.ID)
{
# User logged off'
'4647'
{
$Status = "Logged_Off"
$TimeWritten = $Event.TimeCreated
$TimeDiff = (Get-Date) - $Event.TimeCreated
$UserName = ($Event.Properties)[1].value
$Domain = ($Event.Properties)[2].value
}
# Workstation is unlocked.
'4648'
{
$Status = "Unlocked"
$TimeWritten = $Event.TimeCreated
$TimeDiff = (Get-Date) - $Event.TimeCreated
$UserName = ($Event.Properties)[5].value
$Domain = ($Event.Properties)[6].value
}
# Workstation is locked.
'4800'
{
$Status = "Locked"
$TimeWritten = $Event.TimeCreated
$TimeDiff = (Get-Date) - $Event.TimeCreated
$UserName = ($Event.Properties)[1].value
$Domain = ($Event.Properties)[2].value
}
# If no Event Returned
Default
{
$Status = "No_Data__Client my be offline."
$TimeWritten = $Null
$TimeDiff = $NULL
}
}
# Create Object to hold the output.
$Obj = New-Object PSObject
# Add member data to the object.
$Obj | Add-Member -MemberType NoteProperty -Name "Status" -Value $Status
$Obj | Add-Member -MemberType NoteProperty -Name "TimeCreated"
-Value $TimeWritten
$Obj | Add-Member -MemberType NoteProperty -Name "TimeDiff" -Value $TimeDiff
$Obj | Add-Member -MemberType NoteProperty -Name "UserName" -Value $UserName
$Obj | Add-Member -MemberType NoteProperty -Name "Domain" -Value $Domain
# Write the object to the pipeline.
Write-Output $Obj
}
Comments