Use PowerShell to remove local profiles

A couple of days ago at work, I was asked a question concerning whether a specific one-liner of code would work remotely. That one-liner was (Get-WMIObject Win32_UserProfile | ? {$_.localpath –like “*username).Delete()} I told him that, yes, in fact it would work.  After this, I began to think of a way to make a script that will allow a help desk person, desktop support admin or a server admin to run the script and have it prompt for a machine, rather local or remote to make a connection to and then present a list of user profiles and the option to remove a specified profile.

Overall, it is a fairly simplistic script with with a couple Do/Until loops for the selection processes and some Try/Catch  error checking (which in opinion, should always be included in any script that runs on PowerShell V2). I also make use of System.Management.Automation.Host.ChoiceDescription  class to present a choice at the end of the script on whether the user wishes to quit the script or re-scan and delete another profile.

OS Compatibility

A big gotcha with this script is that while it can be ran from any machine with PowerShell v2, it can only be ran against a client using Vista and above or a server running Windows 2008 and above.  Any other OS’s lower than this do not have the WMI class require for this to work and will fail.

Example

In this example, I have my profile (boe) on my laptop and another account (testuser) that I logged into to create the local profile folder.

Capture

I now call my script which asks for a computername, in which I type in the name and am then presented with 2 profiles, boe and testuser along with the option to quit the profile removal script. You will notice that it starts at 0, which is the beginning index of the array of user profiles.

Capture

I now select the testprofile to remove it.  Since it is labeled 0, I type in 0 and proceed to remove the profile. After a few seconds (your time will vary depending on the size of the profile), I get a confirmation that the profile has been successfully deleted.  There is then another prompt to either continue removing profiles or exit the script.

Capture

As you can see, the folder is now gone.

Capture

Really, that is all there is to it. This can be ran against a remote machine as well and it uses the Test-Connection cmdlet to verify the network access prior to making the WMI connection.

If you try to run this against a server that has an unsupported OS, then the script will throw an error and close.

Capture

Code

The script is available from the following locations:

Script Repository

PoshCode

<#   
.SYNOPSIS   
    Interactive menu that allows a user to connect to a local or remote computer and remove a local profile. 
.DESCRIPTION 
    Presents an interactive menu for user to first make a connection to a remote or local machine.  After making connection to the machine,  
    the user is presented with all of the local profiles and then is asked to make a selection of which profile to delete. This is only valid 
    on Windows Vista OS and above for clients and Windows 2008 and above for server OS.    
.NOTES   
    Name: Remove-LocalProfile 
    Author: Boe Prox 
    DateCreated: 26JAN2011       
.LINK   
    https://boeprox.wordpress.com
    http://msdn.microsoft.com/en-us/library/ee886409%28v=vs.85%29.aspx 
.EXAMPLE  
Remove-LocalProfile 
 
Description 
----------- 
Presents a text based menu for the user to interactively remove a local profile on local or remote machine.    
#>  
 
#Prompt for a computer to connect to 
$computer = Read-Host "Please enter a computer name" 
#Test network connection before making connection 
If ($computer -ne $Env:Computername) { 
    If (!(Test-Connection -comp $computer -count 1 -quiet)) { 
        Write-Warning "$computer is not accessible, please try a different computer or verify it is powered on." 
        Break 
        } 
    } 
Try {     
    #Verify that the OS Version is 6.0 and above, otherwise the script will fail 
    If ((Get-WmiObject -ComputerName $computer Win32_OperatingSystem -ea stop).Version -lt 6.0) { 
        Write-Warning "The Operating System of the computer is not supported.`nClient: Vista and above`nServer: Windows 2008 and above." 
        Break 
        } 
    } 
Catch { 
    Write-Warning "$($error[0])" 
    Break 
    }     
Do {     
#Gather all of the user profiles on computer 
Try { 
    [array]$users = Get-WmiObject -ComputerName $computer Win32_UserProfile -filter "LocalPath Like 'C:\\Users\\%'" -ea stop 
    } 
Catch { 
    Write-Warning "$($error[0]) " 
    Break 
    }     
#Cache the number of users 
$num_users = $users.count 
 
Write-Host -ForegroundColor Green "User profiles on $($computer):" 
 
    #Begin iterating through all of the accounts to display 
    For ($i=0;$i -lt $num_users; $i++) { 
        Write-Host -ForegroundColor Green "$($i): $(($users[$i].localpath).replace('C:\Users\',''))" 
        } 
    Write-Host -ForegroundColor Green "q: Quit" 
    #Prompt for user to select a profile to remove from computer 
    Do {     
        $account = Read-Host "Select a number to delete local profile or 'q' to quit" 
        #Find out if user selected to quit, otherwise answer is an integer 
        If ($account -NotLike "q*") { 
            $account = $account -as [int] 
            } 
        }         
    #Ensure that the selection is a number and within the valid range 
    Until (($account -lt $num_users -AND $account -match "\d") -OR $account -Like "q*") 
    If ($account -Like "q*") { 
        Break 
        } 
    Write-Host -ForegroundColor Yellow "Deleting profile: $(($users[$account].localpath).replace('C:\Users\',''))" 
    #Remove the local profile 
    ($users[$account]).Delete() 
    Write-Host -ForegroundColor Green "Profile:  $(($users[$account].localpath).replace('C:\Users\','')) has been deleted" 
 
    #Configure yes choice 
    $yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes","Remove another profile." 
 
    #Configure no choice 
    $no = New-Object System.Management.Automation.Host.ChoiceDescription "&No","Quit profile removal" 
 
    #Determine Values for Choice 
    $choice = [System.Management.Automation.Host.ChoiceDescription[]] @($yes,$no) 
 
    #Determine Default Selection 
    [int]$default = 0 
 
    #Present choice option to user 
    $userchoice = $host.ui.PromptforChoice("","Remove Another Profile?",$choice,$default) 
    } 
#If user selects No, then quit the script     
Until ($userchoice -eq 1)
This entry was posted in powershell, scripts and tagged , , . Bookmark the permalink.

26 Responses to Use PowerShell to remove local profiles

  1. Krishna says:

    Exception calling “Delete” with “0” argument(s): “”
    At line:77 char:5
    + ($users[$account]).Delete()
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : DotNetMethodException

  2. junk says:

    Hello, I want to subscribe for this blog to obtain most recent
    updates, so where can i do it please help.

  3. Dan says:

    This a great script and works fine on windows 7, 8 and server 2008, but it does not work on windows 10 and also when I tried on remote system I got the following message ARNING: Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))” I am wondering would need to do to fix it.

    Thanks
    Dan

  4. I know this is fairly old but is there a way to sort the list alphabetically (either before or after the index array number is assigned)?

  5. Pingback: Set only part of output as variable? - How to Code .NET

  6. DutchGlory says:

    would it be possible to create a Windows 10 version..??
    thanks

  7. CLR says:

    I have been looking for a while and I think this script might be an answer if someone could tell me how to alter it. I need a script that deals with the machine I am working on and uses no kind of network involvement. I want to login to a corporate PC and run the script to find user profiles on that device and delete the profiles I select. Does anyone know how I can edit this script or find another that will allow me to do this.

  8. Bob Sunderland says:

    Just learning power shell, so sorry for any stupid questions, but I’m going to try to modify this script to remove “Account Unknown” profiles left befhind on Windows XP boxes when employees move on. The account is originally created as an AD account, so when that account is deleted it leaves the “Account Unknown” profile behind. Am I spinning my wheels here? and will this also delete the files and folders associated with these accounts?

  9. Pingback: PowerShell Profile Removal GUI | Learn Powershell | Achieve More

  10. 廖瀚 Dennis Liao says:

    Great work. Many thanks

  11. Phillip says:

    Peter, I too could greatly use your modified version of this script to delete a range of profiles.

  12. mikec49 says:

    Peter, your editied script to select a range of user profiles sounds very useful to me, would it be possible to get the code please?

    • Peter says:

      Use the following replacing original line 55 to end. Note Exclude array to avoid deleting your special profiles. This works for me on Win7 x64 but please test it to determine if it works for you!
      #Cache the number of users
      $num_users = $users.count

      Write-Host -ForegroundColor Green “*** There are $num_users User profiles on $computer”

      #Iterate through all of the accounts to display All User Names
      For ($i=0;$i -lt $num_users; $i++) {
      Write-Host -ForegroundColor Black “$($i): $(($users[$i].localpath).replace(‘C:\Users\’,”))”
      }

      Write-Host -ForegroundColor Green “`n*** `n*** Begin Delete of User Profiles not on Exclude List `n***”
      $ExcludeList = “ProfileA”, “ProfileB”, “ProfileC”
      Write-Host “*** There are $Num_Users User Profiles”
      [int] $Beg_No = Read-Host “*** Enter Beginning User number”
      [int] $End_No = Read-Host “*** Enter Ending user number”
      Write-Host “*** User Profiles from $Beg_No to $End_No are to be deleted`n ”
      if ($Beg_No -lt 0) { Write-Host “+++ Error – Beginning number less than zero”; Return}
      $Limit = $Num_Users – 1
      if ($End_No -gt $Limit) {Write-Host “+++ Error – Ending number GT number of profiles”; return }
      $End_No = $End_No + 1

      #Loop to Delete users in specified range except those on Exclude List
      For ($i = $Beg_No; $i -lt $End_No; $i++) {
      $test = $(($users[$i].localpath).replace(‘C:\Users\’,”))
      if ($ExcludeList -contains $test) { Write-Host “`n+++ Profile $i $test will not be deleted” }
      else
      { $account = $i
      Write-Host -ForegroundColor BLUE “`n*** Profile $i $test to be Deleted ”
      #Remove the local profile

      ($users[$account]).Delete() ;
      $Curr_Date = get-date -format g
      Write-Host -ForegroundColor BLUE “*** Profile $i $(($users[$account].localpath).replace(‘C:\Users\’,”)) has been deleted $Curr_Date”
      $Tmp = “C:\Users\” + $Test
      if (test-path -path $tmp) {write-host -ForegroundColor BLUE “+++ Clean-up $Tmp”; Remove-Item -Recurse -Force $Tmp}
      }
      }

      Write-Host “`n*** `n*** Completed `n***”
      RETURN

      • Bill Siegler says:

        I’m hoping someone can help. I’m trying to use the modified code and I’m getting the following error:

        Missing ‘)’ in method call.
        At C:\powershell\Mod-Remove-LocalProfile.ps1:75 char:49
        + if ($ExcludeList -contains $test) { Write-Host ” <<<< `n+++ Profile $i $test will not be deleted" }
        + CategoryInfo : ParserError: (CloseParenToken:TokenId) [], ParseException
        + FullyQualifiedErrorId : MissingEndParenthesisInMethodCall

        Here is my line 75:
        if ($ExcludeList -contains $test) { Write-Host “`n+++ Profile $i $test will not be deleted” }

  13. Brecht Monkerhey says:

    what would make it perfect is a datagrid view of the profiles where you can select multiple rows for deletion. Don’t know how doable that would be using powershell though 🙂 Anyway, nice job as it is.

  14. Brecht Monkerhey says:

    Nice, just what I was looking for as the delprof utility is not supported anymore on 2008 and 2008r2. Thanks!

    It would be nice to add an option to delete a range or collection of profiles at once, not profile per profile.

    Also, are you sure this way of deleting a profile is the supported way? Deleting profiles incorrectly can mess up your registry.

    • Boe Prox says:

      While I am not 100% sure that this is a “recommended” way of deleting a user’s profile. I can tell you that we have had this implemented on our networks for a couple of months now and have not seen any issues without messing up the registry. That being said, there is always a possibility that something could go wrong… I did throw around the idea of selecting a range of users, but I decided not to implement that on this version. Perhaps on another version I will include this.

      • Peter says:

        Thanks for making this script available. I adapted this code to select a range of user profiles to delete. I have two observations: (1) I find the performance to be extremely slow, taking about 30 minutes to delete 10-20 profiles. I am Sys Admin for Win7 x64 systems in an engineering study lab, and want to reduce the total number of profiles from almost 400 to a more manageable 200. (2) With some frequency, I get the error Exception calling “Delete” with “0” argument(s): “” This apparently is the result of some sort of permissions problem in the User’s directory. To clean this up, I added a test for existance of the user’s directory, and complete the delete via Remove-Item -Recurse -Force
        Thanks again!

  15. Pingback: Episode 139 – Brian and Ben from DevFarm « PowerScripting Podcast

  16. Lee says:

    Very nice, a useful script to have!

Leave a comment