Delete Old User profiles

# written 7-10-23 [email protected]
# modified 8-10-23 for proper Last used time
# takes into account SentinelOne Canary files and special profiles

write-host "Deleting profiles older than $PurgeOlderThan days"

    $UPs=Get-CimInstance -Class Win32_UserProfile |  Where-Object {!($_.Special) -and $_.LocalPath -like "*\users\*" -and $_.Localpath -notlike '$*'}
    $uparray=@()
    foreach ($up in $ups) {
        # write-host $up.localpath
        $files=gci -path $up.LocalPath -recurse -force -erroraction silentlycontinue -File
        if ($files.count -gt 0) {
            $NewestFile=(($files | where-object {$_.name -notlike "*.dat" -and $_.FullName -notlike '*afterSentDocuments*'} | Sort-Object -Descending -Property LastWriteTime)[0])
            $NewestFileLastWrite=$NewestFile.LastWriteTime
            $NewestPretty=$newestFileLastWrite.ToString("MM-dd-yyyy") + " "+$newestfile.fullname
            $size = [int](($files | measure-object -property length -sum).sum /1gb)
            #$ntuserlastaccesstime=(get-itemproperty -path "$($up.LocalPath)\AppData\Local\Microsoft\Windows\UsrClass.dat" -name LastWriteTime).LastWriteTime
            # $uparray+=[pscustomobject]@{Folder=$up.localpath;Windows_Profile=$up.LastUseTime;UsrClassDAT=$ntuserLastAccessTime;GB=$size;NewestFile=$newest}
            $uparray+=[pscustomobject]@{Folder=$up.localpath;Size=$size;Count=$files.count;Windows_Profile=$up.LastUseTime;GB=$size;Last_Update=$newestPretty}
            }

        $ProfileAge= ((Get-Date) - $NewestFileLastWrite).Days
        if ($PurgeOlderThan -gt 25 -and $ProfileAge -gt $PurgeOlderThan) {
            $x=Get-CimInstance -Class Win32_UserProfile | ? LocalPath -eq $up.localpath   |  Remove-CimInstance
            write-host "Deleted" $up.Localpath "because it was last updated $ProfileAge days ago on" $newestFileLastWrite
            }
        else {
            write-host "Did not delete" $up.localpath "because it's only $profileAge days old"
            }
        }

    $uparray | ConvertTo-HTML
        

Script data

Language - PowerShell

Run as - System / Root User

Script timeout duration - 30 Mins

Script variables

Run time variables - PurgeOlderThan

Read me

OK - It's well known that delprof2 and even the Microsoft GPO to delete old profiles doesn't work. I wrote this to find out the most recent file edited within a user profile and purge based on THAT date. This will delete profiles older than "PurgeOlderThan" in days, with a >25 day sanity check. (if <25, it won't delete!) As a side benefit, it will also show all profiles and their sizes.

1