Skip to content

Instantly share code, notes, and snippets.

@Ax-jguarracino
Created November 1, 2023 13:57
Show Gist options
  • Select an option

  • Save Ax-jguarracino/db472556c3adb0af16121f7d297ccd37 to your computer and use it in GitHub Desktop.

Select an option

Save Ax-jguarracino/db472556c3adb0af16121f7d297ccd37 to your computer and use it in GitHub Desktop.
Windows - Maintenance Tasks - Remove Old User Profiles
<#
.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