Learning PowerShell: Removing Unknown Profiles
This is going to be another quick solution to a problem I have. Long story short, we have a lot of shared computers. Each shared computer has a local profile for every user that has EVER logged in to it. Profiles get messy and collect clutter; they almost never get smaller, only bigger. Maybe the user has an application that doesn't clean up temp data very well, maybe they have a recycle bin that never gets emptied, or maybe they saved a bunch of large spreadsheets to their desktop instead of to the network drive where they belong.
This wouldn't be a problem if organizations were static and without turnover, but employees invariably leave, yet their clutter remains on every computer that they ever touched. I don't like this, so I'm going to remove every profile that the system doesn't recognize. You can do this manually from system properties, but that's tedious and annoying. Let's use PowerShell instead.
Ta-da! Look! Script! Well... function, anyway. This is actually adapted from something else that I've written to do some other cleanup stuff, but I won't get into that.
function Kill-UnknownProfiles # Clean up unknown user profiles
{
# Get local user profiles
$UserProfiles = Get-WmiObject -Class Win32_UserProfile
# Loop through profiles
foreach ($Profile in $UserProfiles)
{
# Set user SID as a security principal object
$UserSID = New-Object System.Security.Principal.SecurityIdentifier($Profile.SID)
try # Try to translate SID to a username. Unknown profiles will throw an exception
{
$UserSID.Translate([System.Security.Principal.NTAccount]) | Out-Null
}
catch # Catch exception and remove unknown profile
{
Write-Host -ForegroundColor Red "`nFound unknown user with SID $UserSID"
Write-Host "Removing unknown account profile"
Remove-WmiObject -InputObject $Profile
}
}
}
It isn't a very long script, but you should take the time to understand how it works. The core idea here is that the script is attempting to resolve an account's security identifier (SID) to a name. If it can't do that, the script throws an exception. The exception is then handled by removing the profile.
Here's the long(er) version:
- We collect user profiles into a variable called $UserProfiles. This includes all profiles on the local computer, including some builtins.
- Each profile in $UserProfiles can be parsed for an SID. If you aren't familiar with SIDs, they are an immutable characteristic of an object in a Windows environment. Most importantly for this use case, the SID remains attached to anything associated with the account even after the account is removed from Active Directory.
- We use a loop to run through each profile in $UserProfiles independently. The loop has two parts. The try block attempts to resolve the SID to an account name. This is how we identify unknown accounts in the system. If resolution succeeds, we have a legitimate account for someone who (hopefully) still works here and the catch block is skipped. However, if resolution fails, PowerShell will throw an exception.
- If/when a try block throws an exception, PowerShell will look for a catch block with some instructions on how to handle the exception. Since we know that only unknown profiles will trigger an exception, we know that we can safely remove the profile with which the loop is currently iterating. It should be noted that using exceptions for flow control is not a secure programming practice and should be avoided in more complex applications.
And that's it. It may be short, but this covers some very important and useful concepts. I hope you learned something, and I hope you never have to manually remove user profiles from Windows ever again.
Thanks for reading!
No comments to display
No comments to display