Is group policy an option?
Stale Resource Cleanup on Windows 10 Devices
I have been tasked with finding a way to clean up stale AD account logins and their associated user directories from our fleet of Windows 10 devices. But I am having trouble finding a way to do that.
I can find the local accounts on the device, and I can find the local user accounts get-localuser and I can find the AD accounts using get-aduser. But I neither of those pulls a list of non-local users that have logged into the test device. Just local and AD account respectively.
I can pull all accounts on a device using get-wmiobject but the date format used for the LasUseTime attribute does not appear to be compatible with the output of a get-time command and I can't find anywhere that explains what the format is and how to pull a compatible date. As a result, the code below does not trigger any accounts on the test machine. Despite the fact that some of them have not logged in since last year sometime.
$Users = Get-WmiObject -Class Win32_UserProfile
foreach ($User in $Users)
{
If ($User.LastUseTime -lt (Get-Date).AddDays(-90)) {(Remove-WmiObject -Class Win32_UserProfile -WhatIf)}
}
I can also pull the accounts using get-ciminstance, which uses a compatible date/time format. Running the code above with get and remove-wmiobject replaced with get and remove-ciminstance it completes successfully. But the LastUseTime shows the same date and time for all CIM instance which is todays date and the time that the script was last run. So the date condition in the IF statement is not triggered.
Does anyone have any idea how I might go about doing this?
2 additional answers
Sort by: Most helpful
-
Rich Matheisen 45,011 Reputation points
2022-05-24T19:00:39.85+00:00 Like this:
$User.ConvertToDateTime($User.LastUseTime)
-
Rich Matheisen 45,011 Reputation points
2022-05-26T02:39:59.1+00:00 This took a bit of digging, but I think I have the way to get the last time a profile was loaded (as opposed to just being modified):
Get-ChildItem "hklm:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\" | #Get all local profiles ForEach-Object{ $n = $_.name -replace 'hkey_local_machine','hklm:' if ([byte[]]$ba = (Get-ItemProperty $n).sid){ # not every profile has a SID (even though its name may be a SID!) $sid = (New-Object System.Security.Principal.SecurityIdentifier($ba, 0)).toString() if ((Get-ItemProperty $n).LocalProfileLoadTimeHigh){ # not every profile has been loaded # convert the high/low values to a hex string # convert the hex string to an unsigned 64-bit integer # treat the value a filetime and conver that to a DateTime object [uint64]$ftime = "0X{0:X8}{1:X8}" -f (Get-ItemProperty $n).LocalProfileLoadTimeHigh, (Get-ItemProperty $n).LocalProfileLoadTimelow $LastLoaded = [DateTime]::FromFileTime($ftime) [PSCustomObject]@{ SID = $sid LocalProfileLoadTime = $LastLoaded } } } }
That code produces PSCustomObjects that look like this:
SID LocalProfileLoadTime --- -------------------- S-1-5-21-1671195940-3624339693-1328601057-1001 5/25/2022 9:50:43 AM
The time on my profile (above) matches the time I logged on, not the current time.
You can use "Get-CimInstance -Class Win32_UserProfile" and compare their SIDs to the SIDs from the above code. If they match, compare the LocalProfileLoadTime to 90-day window and if the result is what you want, pipe the SimInstance to Remove-CimInstance.
But this still leave open the question of what are you going to do about all the data for that user? Were they using OneDrive? How will you deal with authentication to remove the synchronization before removing the local files (i.e. you don't want to remove the files from OneDrive, just the local copies). What about applications the user may have installed? Etc., etc., etc.