Delete user profiles except staff/local accounts

This topic contains 3 replies, has 4 voices, and was last updated by Profile photo of Rob Simmers Rob Simmers 1 year, 5 months ago.

  • Author
  • #24874
    Profile photo of Garrett Chandler
    Garrett Chandler

    Reading through these forums I found a few threads discussing old user profile deletion. I work in a school district and need to delete student profiles off machines pretty regularly. All of our student profiles share a common naming scheme of their ID number which is six digits. For example, a student profile name in C:\Users could be 620145. I was wondering how I can delete specifically just these profiles that are also older than 15 days or so with a scheduled PowerShell script. Can anyone suggest anything? Here is the code I have been playing with. I'm new at this, so I could be way off. I would greatly appreciate any assistance.



    Start-Transcript -Path C:\ProfileCleanup.txt -Append

    Write-Warning "Filtering for user profiles older than $Days days"
    Get-CimInstance win32_userprofile -filter “NOT localpath like '%Default%'” -Verbose |
    Where {($_.LastUseTime -lt $(Get-Date).Date.AddDays(-$days)) -and ({$_.Name -match '^\d+6$'}) } |
    Remove-CimInstance -Verbose


  • #24886
    Profile photo of Richard Siddaway
    Richard Siddaway

    Looking at Win32_UserProfile I got these results

    £> Get-CimInstance Win32_UserProfile | select localpath


    Where do your profiles that would fit the filter come from?

    I'd test this by commenting out the Remove-CimInstance and seeing what comes through

  • #24887

    [url='']delprof2[/url] is a 3rd party replacement for Microsoft's [url='']original delprof[/url] tool that supports modern versions of Windows.

    If you want to write your own PowerShell script for deleting profiles then remember that to properly clean up profiles you shouldn't be deleting just the profile folder but you should also be deleting registry entries associated with that user.

  • #24891
    Profile photo of Rob Simmers
    Rob Simmers

    I wrote this for some Citrix folks I used to work with. It has static exclusions and dynamic exclusions using a AD group that contained admin accounts, so anyone in that group or in the static would not be deleted I used ADSI because there would be no module or snappin dependency. Works great keeping the servers clean, comments welcome. 🙂

    function Add-Log {
            [Parameter()] [ValidateSet(“Error”, “Warn”, “Info”)]
            [string]$Level = "Info",
            [string]$Path=("$env:temp\{0}.log" -f ($MyInvocation.ScriptName).Name)
        $date= Get-Date
        $outContent = "[$date]`t$Level`t`t$Message"
        Write-Verbose $outContent
        Add-Content -Path $Path -Value $outContent
    function Get-ADSearcherGroupMember {
        param (
        #Get a list of domains in the forest and grab the DN of the one matching the above parameter.
        $forest= [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
        $domainSrch= $forest.Domains | Where {$_.Name -like "$Domain*"}
        #Write-Output "Found the remote domain, the full LDAP distinguished name is $DomainDN"
        #Create an LDAP searcher object and pass in the DN of the domain we wish to query
        $Searcher=New-Object System.DirectoryServices.DirectorySearcher([ADSI]"LDAP://$domainDN")
        Write-Verbose ("Search Filter: {0}" -f $Searcher.Filter)
        $Searcher.PageSize = 2500
        $Searcher.SearchScope = "Subtree"
        $colPropList = "Name","Member"
        foreach ($i in $colPropList){$Searcher.PropertiesToLoad.Add($i) | Out-Null}
        $object = @() 
        #Loop through the results
        Foreach($result in $results){
            $ | foreach {
                $user = [ADSI]("LDAP://{0}" -f $_)
                $object += New-Object PSObject -Property @{            
                    Group    = $group.get("samaccountname")    
                    Name     = $user.get("samaccountname")       
                    Class   = $user.get("objectClass")[1]          
                } #object 
    function Delete-Profile {
        $Exclude | Sort-Object | foreach{ Add-Log -Path $logPath -Message ("Excluding:  {0}" -f $_) }
        $profiles = Get-WMIObject -Class Win32_UserProfile
        Add-Log -Path $logPath -Message ("Found {0} profiles..." -f $profiles.Count)
        foreach ( $profile in $profiles ) {
            $Loaded = $false
            $Excluded = $false
            Add-Log -Path $logPath -Message ("Processing profile {0}..." -f $profile.LocalPath)
            if ( $profile.Loaded ) {
                Add-Log -Path $logPath -Message ("{0} profile is loaded. Deletion will be skipped." -f $profile.LocalPath)
                $Loaded = $true
            if ( $Exclude -contains $profile.LocalPath.Substring($profile.LocalPath.lastindexofany("\") + 1, $profile.LocalPath.Length - ($profile.LocalPath.lastindexofany("\") + 1)) ) {
                Add-Log -Path $logPath -Message ("{0} profile has been excluded. Deletion will be skipped." -f $profile.LocalPath)
                $Excluded = $true
            If ($Loaded -eq $false -And $Excluded -eq $false) {
                Add-Log -Path $logPath -Message ("Attempting to delete {0} profile..." -f $profile.LocalPath)
                try {
                    if ($pscmdlet.ShouldProcess($profile.LocalPath, "Delete")) {
                        Add-Log -Path $logPath -Message ("{0} profile has been deleted successfully." -f $profile.LocalPath)
                catch {
                    Add-Log -Path $logPath -Message ("{0} profile could not be deleted. Error: {1}" -f $profile.LocalPath, $_.Exception.Message) -Level Error
    $scriptPath = split-path -parent $MyInvocation.MyCommand.Definition
    $logName = $MyInvocation.MyCommand.Name.ToLower().Replace("ps1","log")
    $logPath = "{0}\{1}" -f $scriptPath, $logName
    Add-Log -Path $logPath -Message ("Initiating {0}..." -f $MyInvocation.MyCommand)
    Write-Verbose ("Logging Path: {0}" -f $logPath)
    Add-Log -Path $logPath -Message ("Loading static exclusions...")
    $exclusions = "administrator","all users","default user","default", "localservice","networkservice","public","myserviceaccount"
    Add-Log -Path $logPath -Message ("Loading dynamic exclusions from group AD group")
    Get-ADSearcherGroupMember -Name "Domain Admins" -Domain $env:UserDomain | Where {$_.Class -eq "person"} | Select Name | foreach{$exclusions += $_.Name}
    Add-Log -Path $logPath -Message ("Beginning profile removal...")
    Delete-Profile -Exclude $exclusions @PSBoundParameters
    Add-Log -Path $logPath -Message ("Completed profile removal.  Script execution complete.")

You must be logged in to reply to this topic.