Here we provide an example of how we can use PowerShell to find the user profile last use time.
The reason we were doing this was to purge any local profiles that hadn’t been used for, say, 4 weeks or more. This could potentially free up valuable disk space on some of the smaller solid state drives that we maintain.
There were several methods we explored to find the most accurate time a profile was last used.
Use WMI to Find Last Use Time
One attempt included getting the LastUseTime of a user profile using WMI, but unfortunately the date just wasn’t accurate.
$computerName = "name"
Get-WmiObject -ComputerName $computerName -Class Win32_UserProfile | where-object {!($_.Special) -and !($_.Loaded) } | Sort-Object -Property LastUseTime -Descending | foreach {
$lastusetime = [Management.ManagementDateTimeConverter]::ToDateTime($_.LastUseTime).tostring('dd/MM/yyyy HH:mm:ss')
$objSID = New-Object System.Security.Principal.SecurityIdentifier ($_.SID)
$objUser = $objSID.Translate( [System.Security.Principal.NTAccount])
$username = $objUser.Value
write-host $username $lastusetime
}
Use NTUser.dat to Find Last Write Time
Another attempt was to use NTUser.dat to find the last use time, but the last write time wasn’t accurate either!
"c:\Users" | get-childitem -Directory | foreach {
$username = $_.Name
$path = $_.FullName
If (Test-Path "$path\ntuser.dat")
{
$ntuserdat = Get-Item "$path\ntuser.dat" -force
$ntuserdatLastWrite = $ntuserdat.LastWriteTime
Write-Host $username $ntuserdatLastWrite
}
}
Find Last Logon Using Event Viewer
Finally we decided it’s most accurate to consult the event viewer logs. Below we filter the Security auditing event log on interactive users logins, where the date of the log entry is within the last 2 weeks.
#logged in in last 14 days $threshold = -14 $startDate = (get-date).AddDays($threshold) #last login date (including screen unlock etc), interactive logins only, no virtual logins $userLogins = Get-WinEvent -ProviderName 'Microsoft-Windows-Security-Auditing' -FilterXPath "*[System[EventID=4624] and EventData[Data[@Name='LogonType']='2'] and EventData[Data[@Name='VirtualAccount']='%%1843']]" | where-object TimeCreated -ge $startDate | Select-Object @{Name = 'LoginDate'; Expression = {$_.TimeCreated}}, @{Name = 'Username'; Expression = { $_.Properties.Value[5] }}, @{Name = 'SID'; Expression = { $_.Properties.Value[4]}} | Group-Object Username | Foreach-Object {$_.Group | Sort-Object LoginDate -Descending | Select-Object -First 1} | Foreach-Object { $username = $_.Username $logindate = $_.LoginDate $sid = $_.SID #get user profile by sid write-host "Processing username $username with last login date of $logindate and sid $sid" $wmiUserProfile = Get-WmiObject Win32_UserProfile -Filter "sid = '$sid'" if ($wmiUserProfile -ne $null) { if (!$wmiUserProfile.Special -and !$wmiUserProfile.Loaded) { write-host "Attempting to remove profile for $username" $wmiUserProfile | Remove-WMIObject $result = Get-WmiObject -Class Win32_UserProfile -Filter "sid = '$sid'" if ($result -eq $null) { write-host "$username profile deleted successfully." } else { write-host "Could not deleted $username profile." } } else { write-host "Profile for $username is either special or currently loaded and will not be deleted." } } else { write-host "Could not find profile for username $username and sid $sid." } }