-
-
Save Ax-jguarracino/db472556c3adb0af16121f7d297ccd37 to your computer and use it in GitHub Desktop.
Windows - Maintenance Tasks - Remove Old User Profiles
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <# | |
| .SYNOPSIS | |
| Removes user profiles older than the provided age threshold. | |
| .PARAMETER ageLimit | |
| [ System.Int32 ] : Mandatory : EVALUATION & REMEDIATION | |
| The amount of time, in days, that should elapse before a user profile is considered "inactive" and removed. | |
| .PARAMETER whitelistedUsers | |
| [ System.String[] ] : Optional : EVALUATION & REMEDIATION | |
| Usernames that should be excluded from profile removal, even if they're older than our defined ageLimit. | |
| .HISTORY | |
| Name : Anthony Maxwell | |
| Date : 08/14/2023 | |
| Version: 1.0.0 | |
| - Initial Release. | |
| Name: John Guarracino | |
| Date: 10/03/2023 | |
| Version: 1.0.2 | |
| - Rewrote worklet to use LocalProfileUnloadTime registry values as profile detection method | |
| Name: John Guarracino | |
| Date: 11/01/2023 | |
| Version: 1.0.3 | |
| - Updated script to incorporate new evaluation logic. | |
| #> | |
| ######################################### | |
| # PARAMETERS | |
| # Define the time delta to prune profiles older than | |
| $ageLimit = 30 # For example, profiles older than 30 days | |
| # Define whitelisted usernames | |
| # Users entered here will be ignored during processing | |
| $whitelistedUsers = @('Administrator', 'defaultuser0', 'NetworkService', 'LocalService', 'systemprofile') | |
| ######################################### | |
| # Calculate the oldest allowable profile date | |
| $oldestDate = [System.DateTime]::Now.AddDays(-$ageLimit) | |
| # Get the profile list from the registry | |
| $regKeyPath = "SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList" | |
| $regKey = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey($regKeyPath) | |
| $profileList = $regKey.GetSubKeyNames() | |
| # Empty array for storing user names needing remediation | |
| $remediationList = @() | |
| Foreach ($sid in $profileList) | |
| { | |
| Try | |
| { | |
| # Attempt to get user profile info from Win32_UserProfile | |
| $userProfile = Get-CimInstance -ClassName Win32_UserProfile | Where-Object { $_.SID -eq $sid } | |
| If ($null -ne $userProfile) | |
| { | |
| # Extract username from the local path | |
| $userName = Split-Path -Path $userProfile.LocalPath -Leaf | |
| } | |
| Else | |
| { | |
| Write-Output "SID: $($sid) not found in local user profiles" | |
| } | |
| } | |
| Catch | |
| { | |
| Write-Output "Error querying Win32_UserProfile for SID $($sid): $_.Exception.Message" | |
| Continue | |
| } | |
| # Skip the whitelisted users | |
| If ($whitelistedUsers -contains $userName) | |
| { | |
| Continue | |
| } | |
| # Unload Time registry values to check | |
| $profileKey = $regKey.OpenSubKey($sid) | |
| # Retrieve decimal value and format to 8-digit hexadecimal | |
| $localProfileUnloadTimeHigh = '{0:X8}' -f $profileKey.GetValue("LocalProfileUnloadTimeHigh", $null) | |
| $localProfileUnloadTimeLow = '{0:X8}' -f $profileKey.GetValue("LocalProfileUnloadTimeLow", $null) | |
| # Check for High and Low load Unload Time values | |
| $unloadTime = If ($localProfileUnloadTimeHigh -and $localProfileUnloadTimeLow) | |
| { | |
| # Concatenate and convert Unload times to a DateTime object | |
| [datetime]::FromFileTime("0x$localProfileUnloadTimeHigh$localProfileUnloadTimeLow") | |
| } | |
| # Unload Time is null or undefined $null safety net. | |
| Else | |
| { | |
| $null | |
| } | |
| # Resolve the time delta | |
| $lastUsed = $null | |
| If ($unloadTime) | |
| { | |
| $delta = [System.DateTime]::Now - $unloadTime | |
| If ($delta -is [TimeSpan]) | |
| { | |
| $lastUsed = $delta.Days | |
| } | |
| } | |
| # Evaluate if the profile is older than our allowed range | |
| If ($unloadTime -and $unloadTime -lt $oldestDate) | |
| { | |
| Write-Output "The profile for user $userName has not been logged into for $lastUsed days. `nSID: $sid `nProfile Path: $($userProfile.LocalPath) `nProfile was last unloaded on $unloadTime" | |
| Write-Output "" | |
| $remediationList += $userName | |
| } | |
| } | |
| # Close registry | |
| $regKey.Close() | |
| # --! Evaluate Compliance !-- | |
| If ($remediationList.Count -gt 0) | |
| { | |
| Write-Output "Profiles flagged for remediation: $($remediationList -join ', ')" | |
| Exit 2 | |
| } | |
| Else | |
| { | |
| Write-Output "All user profiles on this device are compliant. Now exiting." | |
| Exit 0 | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment