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 2 years ago.

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

    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.

    (pre)[cmdletbinding(SupportsShouldProcess)]

    Param(
    [Parameter(Position=0)]
    [ValidateNotNullorEmpty()]
    [int]$Days=15
    )

    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

    Stop-Transcript(/pre)

  • #24886
    Profile photo of Richard Siddaway
    Richard Siddaway
    Moderator

    Looking at Win32_UserProfile I got these results

    £> Get-CimInstance Win32_UserProfile | select localpath

    localpath
    ———
    C:\Users\TestUser
    C:\Users\Richard
    C:\Windows\ServiceProfiles\NetworkService
    C:\Windows\ServiceProfiles\LocalService
    C:\windows\system32\config\systemprofile

    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
    Profile photo of Matt Bloomfield
    Matt Bloomfield
    Participant

    [url='https://helgeklein.com/free-tools/delprof2-user-profile-deletion-tool']delprof2[/url] is a 3rd party replacement for Microsoft's [url='http://www.microsoft.com/en-us/download/details.aspx?id=5405']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
    Participant

    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. 🙂

    
    [CmdletBinding(SupportsShouldProcess=$True,ConfirmImpact='Low')]
    param()
    
    function Add-Log {
         
        [CmdletBinding()]	
        param(
    		[string]$Message,
            [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 (
            [string]$Name="*",
            [string]$Domain=$env:UserDomain
        )
         
        #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*"}
        $domainDN=$domainSrch.GetDirectoryEntry().distinguishedName 
        #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")
         
        $Searcher.filter="(&(objectCategory=group)(objectClass=group)(Name=$Name))"
        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}
        $results=$Searcher.Findall()
    
        $object = @() 
        #Loop through the results
        Foreach($result in $results){
            $group=$result.GetDirectoryEntry()
                 
            $group.properties.member | 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 
            }
        }
        $object
    }
    
    function Delete-Profile {
        [CmdletBinding(SupportsShouldProcess=$True,ConfirmImpact='Low')]
        param(
            [string[]]$Exclude
        )
        $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")) {
                        $profile.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.