Solved User profile issue (modified date incorrect)


SVQxHC

Member
Local time
7:05 AM
Posts
4
OS
Windows 11
Hello everyone,

I have a bunch of computers with W11 v. 23h2 and I have encountered the same problem on all of them.

When I go to System - Advanced settings - User profile, I can see all the user profiles with the last modification date of today or yesterday, this is happening even with users who are no longer working here (disabled accounts).

They are all AD users, I don't know if this could be the problem, to be honest.

My problem is that I would love to create a PowerShell Script to delete all user profiles on all computers if the user has not logged in to that computer in the last 2 or 3 months... because we have shared computers running out of SSD space because of the user profiles (some computers are shared between 20 or more workers, since they only use the computers for reading documents, printing or sending a quick email), and deleting old profiles one by one is just tedious when you have to do it on 400+ computers... Since the user's profile are getting modified daily, the scripts won't work correctly.

Does anyone know what I can do to solve this problem? I've tried to find some solutions on Google but couldn't figure it out.

Sorry if this is the wrong place in the forums to ask.

Thanks in advance.
 
Windows Build/Version
W11 pro 23H2 22631.4169

My Computer My Computer

At a glance

Windows 11Intel Core i5-10500 CPU @ 3.10GHz8GB DDR4Intel(R) UHD Graphics 630
OS
Windows 11
Computer type
PC/Desktop
Manufacturer/Model
HP
CPU
Intel Core i5-10500 CPU @ 3.10GHz
Motherboard
HP 8717
Memory
8GB DDR4
Graphics Card(s)
Intel(R) UHD Graphics 630
Monitor(s) Displays
HP P24h G4 x 2
Hard Drives
WDC SN530 S256G
This has been going on for the last few versions of Windows. For accurate results, you need to read the profile load and unload times from the registry key for each profile. Something like this will get you started.

Powershell:
Set-StrictMode -Version 'latest'

@(Get-CimInstance -Namespace 'root\cimv2' -ClassName 'Win32_UserProfile' -Filter '(Special = ''False'') AND (Loaded = ''False'')' |
ForEach-Object {
    [string]$profileSID = $_.SID

    $profile = [PSCustomObject]@{
        SID = $profileSID
        LastUseTime = [DateTime]::MaxValue
    }

    if ($null -eq (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\$($_.SID)" -Name @('LocalProfileLoadTimeHigh', 'LocalProfileLoadTimeLow', 'LocalProfileUnloadTimeHigh', 'LocalProfileUnloadTimeLow') -ErrorAction SilentlyContinue))
    {
        $profile.LastUseTime = [DateTime]::new(1970,1,1,0,0,0)
    }
    else
    {
        Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\$($_.SID)" -Name @('LocalProfileLoadTimeHigh', 'LocalProfileLoadTimeLow', 'LocalProfileUnloadTimeHigh', 'LocalProfileUnloadTimeLow') -ErrorAction SilentlyContinue |
        ForEach-Object {
            [DateTime]$loadTime = [DateTime]::new(1980,1,1,0,0,0)
            if (([bool]$_.PSObject.Properties['LocalProfileLoadTimeLow']) -and ([bool]$_.PSObject.Properties['LocalProfileLoadTimeHigh']))
            {
                [System.UInt64]$highTime = $_.LocalProfileLoadTimeHigh
                [System.UInt64]$lowTime = $_.LocalProfileLoadTimeLow
                $highTime = $highTime -shl 32
                [DateTime]$loadTime = [DateTime]::FromFileTime($highTime -bor $lowTime)
            }

            [DateTime]$unloadTime = [DateTime]::new(1980,1,1,0,0,0)
            if (([bool]$_.PSObject.Properties['LocalProfileUnloadTimeLow']) -and ([bool]$_.PSObject.Properties['LocalProfileUnloadTimeHigh']))
            {
                [System.UInt64]$highTime = $_.LocalProfileUnloadTimeHigh
                [System.UInt64]$lowTime = $_.LocalProfileUnloadTimeLow
                $highTime = $highTime -shl 32
                $unloadTime = [DateTime]::FromFileTime($highTime -bor $lowTime)
            }

            $profile.LastUseTime = [DateTime]::FromFileTime(([Math]::Max($loadTime.ToFileTime(), $unloadTime.ToFileTime())))
        }
    }
    Write-Output $profile
})
 

My Computer My Computer

At a glance

Windows 11 Enterprise 25H2 [rev. 8893]
OS
Windows 11 Enterprise 25H2 [rev. 8893]
This has been going on for the last few versions of Windows. For accurate results, you need to read the profile load and unload times from the registry key for each profile. Something like this will get you started.

Powershell:
Set-StrictMode -Version 'latest'

@(Get-CimInstance -Namespace 'root\cimv2' -ClassName 'Win32_UserProfile' -Filter '(Special = ''False'') AND (Loaded = ''False'')' |
ForEach-Object {
    [string]$profileSID = $_.SID

    $profile = [PSCustomObject]@{
        SID = $profileSID
        LastUseTime = [DateTime]::MaxValue
    }

    if ($null -eq (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\$($_.SID)" -Name @('LocalProfileLoadTimeHigh', 'LocalProfileLoadTimeLow', 'LocalProfileUnloadTimeHigh', 'LocalProfileUnloadTimeLow') -ErrorAction SilentlyContinue))
    {
        $profile.LastUseTime = [DateTime]::new(1970,1,1,0,0,0)
    }
    else
    {
        Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\$($_.SID)" -Name @('LocalProfileLoadTimeHigh', 'LocalProfileLoadTimeLow', 'LocalProfileUnloadTimeHigh', 'LocalProfileUnloadTimeLow') -ErrorAction SilentlyContinue |
        ForEach-Object {
            [DateTime]$loadTime = [DateTime]::new(1980,1,1,0,0,0)
            if (([bool]$_.PSObject.Properties['LocalProfileLoadTimeLow']) -and ([bool]$_.PSObject.Properties['LocalProfileLoadTimeHigh']))
            {
                [System.UInt64]$highTime = $_.LocalProfileLoadTimeHigh
                [System.UInt64]$lowTime = $_.LocalProfileLoadTimeLow
                $highTime = $highTime -shl 32
                [DateTime]$loadTime = [DateTime]::FromFileTime($highTime -bor $lowTime)
            }

            [DateTime]$unloadTime = [DateTime]::new(1980,1,1,0,0,0)
            if (([bool]$_.PSObject.Properties['LocalProfileUnloadTimeLow']) -and ([bool]$_.PSObject.Properties['LocalProfileUnloadTimeHigh']))
            {
                [System.UInt64]$highTime = $_.LocalProfileUnloadTimeHigh
                [System.UInt64]$lowTime = $_.LocalProfileUnloadTimeLow
                $highTime = $highTime -shl 32
                $unloadTime = [DateTime]::FromFileTime($highTime -bor $lowTime)
            }

            $profile.LastUseTime = [DateTime]::FromFileTime(([Math]::Max($loadTime.ToFileTime(), $unloadTime.ToFileTime())))
        }
    }
    Write-Output $profile
})

Hey Pseymour, I'll try your code. Thanks!

I tested and modified it and was able to achieve my main goal, thanks again Pseymour!
 
Last edited:

My Computer My Computer

At a glance

Windows 11Intel Core i5-10500 CPU @ 3.10GHz8GB DDR4Intel(R) UHD Graphics 630
OS
Windows 11
Computer type
PC/Desktop
Manufacturer/Model
HP
CPU
Intel Core i5-10500 CPU @ 3.10GHz
Motherboard
HP 8717
Memory
8GB DDR4
Graphics Card(s)
Intel(R) UHD Graphics 630
Monitor(s) Displays
HP P24h G4 x 2
Hard Drives
WDC SN530 S256G
Quite welcome. I should mention there is also a group policy setting for this, but if I remember correctly, it only cleans profiles on restart. So if you let your machines sleep instead of restart or shut down, nothing gets deleted.
 

My Computer My Computer

At a glance

Windows 11 Enterprise 25H2 [rev. 8893]
OS
Windows 11 Enterprise 25H2 [rev. 8893]
Back
Top Bottom