profilecleaner.ps1
🧩 Syntax:
# List of users that should not be deleted for inactivity
$excludedUsers = @(
"hzun74",
"mcsj35",
"wtaub",
"BAY.Cerner724",
"Imprivata_CMI_801",
"Imprivata_MMG_bay",
"Imprivata_MMG_CMI"
)
Function Get-FolderSize {
param (
[Parameter(Mandatory=$true)]
[string]$profilePath
)
$size = (Get-ChildItem -LiteralPath "\\$computerName\$($profilePath.Replace(':', '$'))" -Recurse | Measure-Object -Property Length -Sum).Sum / 1MB
return [math]::Round($size, 2)
}
function Get-ADName($username) {
try {
$adUser = Get-ADUser -Identity $username -ErrorAction SilentlyContinue
if ($adUser) {
return $adUser.GivenName + " " + $adUser.Surname
} else {
return $null
}
} catch {
return $null
}
}
function ConvertTo-ReadableSize ($bytes) {
$unit = "B"
if ($bytes -gt 1GB) {
$bytes /= 1GB
$unit = "GB"
} elseif ($bytes -gt 1MB) {
$bytes /= 1MB
$unit = "MB"
} elseif ($bytes -gt 1KB) {
$bytes /= 1KB
$unit = "KB"
}
return "{0:N2} {1}" -f $bytes, $unit
}
function TimeSinceLastUseInMonths($lastUseTime) {
$timeSpan = [DateTime]::Now - $lastUseTime
return "{0:N2}" -f ($timeSpan.Days / 30.44) # Using average days in a month for calculation
}
function Remove-SelectedProfiles($selectedProfiles) {
Write-Host "`nProfiles to be removed:" -ForegroundColor Red
foreach ($profile in $selectedProfiles) {
$adFullName = Get-ADName -username $profile.LocalPath.Split('\')[-1]
Write-Host ("`t" + $profile.LocalPath.Split('\')[-1] + " ($adFullName)") -ForegroundColor Yellow
}
$confirm = Read-Host "`nAre you sure you want to remove these profiles? (yes/no)"
if ($confirm -eq "yes") {
foreach ($profile in $selectedProfiles) {
$profile | Remove-CimInstance
Write-Host "Removed profile for $($profile.LocalPath)"
}
}
}
$previousComputerName = $null
do {
# Clear screen for fresh view and add horizontal rule
Clear-Host
Write-Host ('-' * 50) -ForegroundColor Cyan
if (-not $previousComputerName) {
$computerName = Read-Host "Enter the computer name"
} else {
$computerName = $previousComputerName
}
$remoteComputer = $computerName
# Test PS Remoting
try {
$result = Invoke-Command -ComputerName $remoteComputer -ScriptBlock { $true } -ErrorAction Stop
}
catch {
$result = $false
}
if ($result) {
Write-Output "PS Remoting is already enabled on $remoteComputer."
} else {
Write-Output "PS Remoting is not enabled on $remoteComputer. Trying to enable it using PSexec..."
# Use PSexec to enable PS Remoting on the remote computer
psexec.exe \\$remoteComputer powershell -Command "Enable-PSRemoting -Force -SkipNetworkProfileCheck"
# Check if PS Remoting is now enabled
try {
$resultAfter = Invoke-Command -ComputerName $remoteComputer -ScriptBlock { $true } -ErrorAction Stop
}
catch {
$resultAfter = $false
}
if ($resultAfter) {
Write-Output "Successfully enabled PS Remoting on $remoteComputer."
} else {
Write-Output "Failed to enable PS Remoting on $remoteComputer."
}
}
$choice = Read-Host "Choose an action: (1) List profiles, (2) Remove profiles not accessed in X months, (3) Manage profiles by folder size"
$profiles = Get-CimInstance -Class Win32_UserProfile -ComputerName $computerName | Where-Object {
$_.Special -eq $false -and $_.LocalPath -notmatch '\\(Public|Administrator|Default)$'
} | Sort-Object {
$shortcutFolder = "\\$computerName\c$\users\" + $_.LocalPath.Split('\')[-1] + "\Desktop\shortcuts"
if (Test-Path $shortcutFolder) {
(Get-Item $shortcutFolder).LastWriteTime
} else {
[datetime]::MinValue
}
} -Descending
if ($choice -eq "1") {
$i = 0
foreach ($profile in $profiles) {
$adFullName = Get-ADName -username $profile.LocalPath.Split('\')[-1]
$size = ConvertTo-ReadableSize -bytes ((Get-ChildItem -Recurse ("\\$computerName\c$\users\" + $profile.LocalPath.Split('\')[-1])).Length | Measure-Object -Sum).Sum
$shortcutFolder = "\\$computerName\c$\users\" + $profile.LocalPath.Split('\')[-1] + "\Desktop\shortcuts"
$lastModified = if (Test-Path $shortcutFolder) { (Get-Item $shortcutFolder).LastWriteTime } else { "shortcuts folder not found within Desktop" }
# Display user details in formatted and colored output
Write-Host "`n[$i]" -ForegroundColor Yellow
Write-Host ("Name: $($profile.LocalPath.Split('\')[-1]) ($adFullName)") -ForegroundColor Green
Write-Host "Size: $size" -ForegroundColor Green
Write-Host "Last Modified: $lastModified" -ForegroundColor Green
$i++
}
$selectedIndices = (Read-Host "`nSelect users to remove by index (space-delimited)").Split()
$selectedProfiles = $profiles | Where-Object { $selectedIndices -contains $profiles.IndexOf($_).ToString() }
Remove-SelectedProfiles -selectedProfiles $selectedProfiles
}
if ($choice -eq "2") {
Write-Host "`nProfiles and their inactivity duration:" -ForegroundColor Cyan
foreach ($profile in $profiles) {
$shortcutFolder = "\\$computerName\c$\users\" + $profile.LocalPath.Split('\')[-1] + "\Desktop\shortcuts"
if (Test-Path $shortcutFolder) {
$lastModified = (Get-Item $shortcutFolder).LastWriteTime
$monthsInactive = TimeSinceLastUseInMonths -lastUseTime $lastModified
Write-Host ("`t" + $profile.LocalPath.Split('\')[-1] + ": " + $monthsInactive + " months") -ForegroundColor Green
} else {
Write-Host ("`t" + $profile.LocalPath.Split('\')[-1] + ": shortcuts folder not found within Desktop") -ForegroundColor Red
}
}
$months = Read-Host "`nEnter the number of months of inactivity for profile removal"
$cutoffDate = (Get-Date).AddMonths(-$months)
$profilesToBeRemoved = $profiles | Where-Object {
$shortcutFolder = "\\$computerName\c$\users\" + $_.LocalPath.Split('\')[-1] + "\Desktop\shortcuts"
if ($excludedUsers -contains $_.LocalPath.Split('\')[-1]) {
return $false
}
if (Test-Path $shortcutFolder) {
(Get-Item $shortcutFolder).LastWriteTime -lt $cutoffDate
} else {
$false
}
}
Remove-SelectedProfiles -selectedProfiles $profilesToBeRemoved
}
if ($choice -eq '3') {
$profiles = Get-CimInstance -ComputerName $computerName -ClassName Win32_UserProfile | Where-Object { !$_.Special }
$profiles | Select-Object LocalPath, @{Name='Size (MB)';Expression={Get-FolderSize $_.LocalPath}}
$sizeCriterion = Read-Host "Enter the folder size criterion (in MB)"
$comparison = Read-Host "Enter 'G' to delete profiles with size greater than the criterion, or 'L' to delete profiles with size lesser than the criterion"
$sizeCriterionBytes = $sizeCriterion/1000000
if ($comparison -eq 'G') {
$profilesToRemove = $profiles | Where-Object {(Get-FolderSize $_.LocalPath) -gt $sizeCriterionBytes}
} elseif ($comparison -eq 'L') {
$profilesToRemove = $profiles | Where-Object {(Get-FolderSize $_.LocalPath) -lt $sizeCriterionBytes}
}
# Confirm and delete profiles
$confirm = Read-Host "Enter 'Y' to confirm removal of the listed profiles or 'N' to cancel"
if ($confirm -eq 'Y') {
$profilesToRemove | ForEach-Object { Remove-CimInstance -CimInstance $_ }
}
}
$action = Read-Host "`nChoose an action: (1) Search again on the same PC, (2) Search another PC, (3) Exit"
if ($action -eq "3") {
break
} elseif ($action -eq "2") {
$previousComputerName = $null
continue
} else {
$previousComputerName = $computerName
}
} while ($true)johnkonkemclaren
Member