Delete user profiles except admin

This topic contains 1 reply, has 2 voices, and was last updated by  Dave Wyatt 3 years, 8 months ago.

  • Author
    Posts
  • #14376

    Hotmail Acct
    Participant

    I work as an IT assistant in higher education and often have to add/remove software, printers, etc... to classroom computers. When doing this, we have to delete all the user profiles from the local machine except out domain administrator, local administrator, and Default user. As you know, this can be tedious to say the least. Unfortunately, we do not have remoting enabled for powershell, and computers only have Version 2 installed. Instead we can write scripts and push via LANDesk, which is useful but often times takes much longer. So here is what I got so far. I am new to Powershell, so I could be way off on this, but I am trying to write it as if I was writing it for the local computer.

    $Users = Get-WmiObject -Class Win32_UserProfile
    $IgnoreList = "DAdmin", "LAdmin", "Default", "NetworkService", "LocalService", "SystemProfile
    ForEach ($User in $Users) {
    If ($User.localpath -notlike "*\$IgnoreList") {
    $User.delete()
    }
    }
    It worked fine using only one name from the $IgnoreList, but once I added more it failed. I am guessing that I need a nested loop for each user to go through each name from the $IgnoreList, but I am not sure how.
    Is the reason it isn't working is because each profile is checking that all those names aren't part of it instead of one at a time?
    Thank you very much for any assistance you can offer.

  • #14381

    Dave Wyatt
    Moderator

    You can do this a couple of different ways, depending on your personal preference. You can set up a nested loop, as you already mentioned, or you can dynamically build a regular expression to test against all of the names at once. Here are examples of both options:

    $Users = Get-WmiObject -Class Win32_UserProfile
    $IgnoreList = "DAdmin", "LAdmin", "Default", "NetworkService", "LocalService", "SystemProfile"
    
    :OuterLoop
    foreach ($User in $Users) {
        foreach ($name in $IgnoreList) {
            if ($User.localpath -like "*\$name") {
                continue OuterLoop
            }
        }
    
        $User.Delete()
    }
    
    $Users = Get-WmiObject -Class Win32_UserProfile
    $IgnoreList = "DAdmin", "LAdmin", "Default", "NetworkService", "LocalService", "SystemProfile"
    
    $pattern = ($IgnoreList | ForEach-Object { [regex]::Escape($_) }) -join '|'
    $pattern = "\\(?:$pattern)$"
    
    foreach ($User in $Users) {
        if ($User.LocalPath -notmatch $pattern)
        {
            $User.Delete()
        }
    }
    

    Couple of notes here. In the first example, I used a label to allow the "continue" statement to jump to the next iteration of the outer loop, instead of the inner loop. You'll find details on this technique in the about_Break help file, though the Continue statement supports them as well.

    In the second example, there's technically nothing in your IgnoreList that needs to be escaped by [regex]::Escape(). I included that step as a general best practice; any time you want to match a literal string as part a regular expression, it's a good idea to make sure any special regex characters in the string are escaped. The final pattern that's being built, in this case, will look like this: "\\(?:DAdmin|LAdmin|Default|NetworkService|LocalService|SystemProfile)$", which means it's looking for a backslash character followed by one of the words on the list, at the very end of the string. (The same result you would expect from checking (if $string -like "*\$testValue"), except it can check the entire list in one -match operation.)

You must be logged in to reply to this topic.