#Get user names that have logged onto workstation
$Users = gwmi win32_networkloginprofile | where {$_.name -match "EXP\\"} | where {$_.name -notmatch "srvtasksched"}

$Users | foreach{

    $Name = $_.Name
    $LastLogon = $_.LastLogon

    $LogonTime = [System.datetime]::ParseExact($LastLogon.Substring(0, $LastLogon.IndexOf(".")), "yyyyMMddHHmmss", [System.Globalization.DateTimeFormatInfo]::InvariantInfo)

    if($(Get-Date).Subtract($LogonTime).TotalDays -ge 14)
        #User hasn't logged into workstation in over 2 weeks
        #Get profile path
        $UserSID = $(New-Object System.Security.Principal.NTAccount($Name)).Translate([System.Security.Principal.SecurityIdentifier]).Value
        $UserRegKey = GCI 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList' | where {$_.Name -match $UserSID}

        $ProfilePath = $(Get-ItemProperty $UserRegKey.PSPath -Name ProfileImagePath).ProfileImagePath

        Write-Host "Deleting User $Name"
        gwmi win32_userprofile | where {$_.SID -eq $UserSID} | foreach {$_.Delete()}



That's the script. It detects and deletes domain profiles (Domain is EXP) on systems that haven't logged into the system in over 14 days, and it works.

However, I started receiving complaints that the script is deleting local accounts, one local account in particular. Assuming that was impossible (I have perfect script skills, right?), I took a look, ran the script, and saw that the profile folders for all the local accounts were still present under C:\Users (Win 7 workstations). False claim.

Fast forward, more complaints. I ran the script again, same results. However, this time I noticed that the registry entry for one particular local account was gone (the one the complaints are stemming from). I ran the script pretty much line by line after that, breaking down the $Users | foreach{ loop, making sure it grabs the correct sids and runs Win32_UserProfile.delete() on the right SIDs, it does.

However, when running the script (it's a sched task so I ran it 'manually' from there), that same local SIDs is deleted, and all the rest remain, which adds to the confusion; because when watching the action, I see the domain user folders under C:\Users delete immediately, but the local ones remain, adding to the confusion.

At first I thought this was limited to a single local profile, however after opening the registry I noticed HKEY_USERS only had a couple entries:

  1. My domain account from connecting remotely, and

  2. The problem account I logged into to verify the account still existed, even though the profile didn't.

All the other SIDs, local or domain, were gone. It is limited to a single local user account.

The effects of this of course is that when someone logs into a local account, everything in their profile folder is overwritten, however watching the script run and delete all profile folders of domain accounts but not local accounts is a bit misleading.


I removed and updated info above. Also, pictures are worth a thousand words, so here goes:

  1. Shot of Profile List Reg Key and C:\Users before running script. The partially blank SIDs are tied to domain accounts, and the highlighted profile folders are to domain users:

enter image description here

enter image description here

  1. Shot of same, after script runs. One domain SID left, which is mine:

enter image description here enter image description here

For clarification, I want to know why a local account is being deleted when this script runs. It seems like either

  1. No local accounts would be deleted (script runs as intended)

  2. All local profiles would be deleted (script doesn't discriminate against one local account, even if that means it also doesn't run as intended).

  • 1
    HKEY_USERS only has subkeys for users who currently have their profile loaded (i.e. logged-on). It's perfectly normal to only see a couple of SID-named subkeys there (unless you're talking about a Terminal Server computer). It would be disturbing if you saw more on a Windows 7 PC, actually. – Evan Anderson Apr 11 '14 at 20:55
  • Oh-- and what is your question? I'm not seeing it in there. You say something about data being "overwritten", which doesn't make sense to me (and makes me thing you're talking about deletion-- not overwriting). I dunno. I'm having trouble parsing it. – Evan Anderson Apr 11 '14 at 20:56
  • Sorry, my question is "Why are local accounts being deleted?" They are the collateral damage, and I'm on mobile right now so I can update the question. This came after a very long Friday. – MDMoore313 Apr 11 '14 at 21:04
  • @EvanAnderson hopefully these updates clarify things. – MDMoore313 Apr 11 '14 at 23:41
  • 1
    In these situations I always add some form of output to demonstrate whats happening. I would add 3 lines to dump $userSID, $UserRegKey & $ProfilePath to a log file ($UserSID >>Log.log), or use Start-Transcript [...] Stop-Transcript at each end of your script. The out put for those should show your script grabbing the wrong data and may give hints as to why its inconsistent with your by hand tests. – Patrick Apr 16 '14 at 10:52

Not quite sure how this would be getting locals... unless the -match "EXP\\" is somehow not behaving as expected. Do the workstations contain "EXP" in the name? Is it possible these local accounts are used to make local logons and remain logged on for more than 14 days? Your 14 day window may be a little too aggressive.

Your code is leveraging 2 different WMI providers that contain mostly the same info. Suggest a simpler loop (single WMI query) where you also (#1) match only those accounts whose SID matches the domain SID, and also write some logs to more easily diagnose issues if there continue to be problems. Change value of $sidPrefix to match that of your domain.

$sidPrefix = "S-1-5-99-999999999-"
gwmi Win32_UserProfile | WHERE {$_.sid -match $sidPrefix -AND $_.localpath -match "\\users\\" -AND $_.localpath -notmatch "srvtasksched" } | foreach {
    $name = split-path $_.localpath -leaf
    $lastUse = $_.lastusetime
    $LogonTime = [System.datetime]::ParseExact($lastUse.Substring(0, $lastUse.IndexOf(".")), "yyyyMMddHHmmss", [System.Globalization.DateTimeFormatInfo]::InvariantInfo)
    $now = get-date
    [int]$daysOld = $now.Subtract($LogonTime).TotalDays

    if($daysOld -ge 30)     {
        $info = "$name,$daysOld,$lastUse,$now"
        $info | out-file -append -enc ascii "C:\temp\profClean.csv"
  • ...Do the workstations contain "EXP" in the name? No, not these. I'll give the sid prefix thing a try, since that won't necessarily change. – MDMoore313 Apr 15 '14 at 17:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.