ps/Modules/.build/Clear-BadPesterUserAccounts.ps1
2023-05-30 22:51:22 -07:00

183 lines
6.1 KiB
PowerShell

Function Clear-BadPesterUserAccounts {
<#
.SYNOPSIS
Cleans up all incorrectly created user accounts on the system from Pester.
.EXAMPLE
Clear-BadPesterUserAccounts
.OUTPUTS
Returns the list of folder names (from C:\Users) that are "invalid".
If the return list is empty then there were none to remove.
This is useful for post-facto additional resource cleanup. In the case of a non-WhatIf, this will be an ephemeral response, so catch it while you can.
.PARAMETER AllPossibleDomainsToSearch
What domains do we want to search? Defaults to [fh, corp]
.PARAMETER WhatIf
Used to test before removing for validation
#>
param(
$AllPossibleDomainsToSearch = @("fh","corp"),
[switch]$WhatIf
)
$logLead = (Get-LogLeadName)
# This means we are on Windows
# At the very least, we can't get the CIM Instances to remove users if they exist
if ($null -eq (Get-Command Get-CimInstance -ErrorAction SilentlyContinue)) {
Write-Host "$logLead : Can't CimInstance on this host, nothing to do"
return
}
Write-Host "$logLead : Cleaning bad pester user accounts [Dry run? $WhatIf]"
# Get local user accounts
# Get IIS user accounts or IIS app pool names (it defaults the identity to the name if no identity specified)
# Get all domain GMSA accounts
# Get all domain user accounts
#
# Get all c:\users folders
# Diff the names
# Remove the users
# Annoying bug...
if ($null -ne (Get-Module Carbon)) {
# Carbon stomps all over our Get-ADDomainController amongst other things
Remove-Module Carbon -Force
}
$userAccountsToExclude = @()
$foldersToKeep = @()
$foldersToRemove = @()
# The system can't determine about some of these, they are special folders
# This is where any such folders go
# Try to make them dynamic before adding them here.
# Public is a very special child unrelated to anything else.
$userAccountsToExclude += "Public"
if ($null -ne (Get-Module -ListAvailable -Name WebAdministration)) {
Get-Module WebAdministration | Remove-Module -Force
Import-Module WebAdministration
$appPools = @(Get-ChildItem IIS:\AppPools)
foreach($appPool in $appPools) {
if (![string]::IsNullOrWhiteSpace($appPool.processModel.userName)) {
$userAccountsToExclude += $appPool.processModel.userName
} else {
$userAccountsToExclude += $appPool.Name
}
}
}
$localUsers = @(Get-LocalUser)
foreach($localUser in $localUsers) {
$userAccountsToExclude += $localUser.Name
}
if ($null -eq (Get-Module -ListAvailable -Name ActiveDirectory)) {
# This is truly an impossible condition to hit. So if we hit it, hit it hard.
throw 'how in the name of sanity is this server not setup to query the domain???'
}
Import-Module ActiveDirectory
foreach($domainName in $AllPossibleDomainsToSearch) {
$dc = Get-ADDomainController -DomainName $domainName -Discover -NextClosestSite
$dcHostname = $dc.Hostname[0]
if ([string]::IsNullOrWhiteSpace($dcHostname)) {
Write-Warning "$logLead : Could not find a hostname for $domainName - Can you access that domain from here?"
continue
}
$domainServiceAccounts = @(Get-ADServiceAccount -Filter "*" -Server $dcHostname)
foreach($domainServiceAccount in $domainServiceAccounts) {
$userAccountsToExclude += $domainServiceAccount.SamAccountName
}
$domainUserAccounts = @(Get-ADUser -Filter "*" -Server $dcHostname)
foreach($domainUserAccount in $domainUserAccounts) {
$userAccountsToExclude += $domainUserAccount.SamAccountName
}
}
$userFolders = @(Get-ChildItem -Directory -Path C:\Users)
foreach($folder in $userFolders) {
if ($userAccountsToExclude -contains $folder.Name) {
$foldersToKeep += $folder.Name
} else {
$foldersToRemove += $folder.Name
}
}
$allCimAccounts = @(Get-CimInstance -ClassName Win32_UserProfile)
$teamCity = (Test-IsTeamCityProcess)
if ($teamCity) {
Write-Host "##teamcity[blockOpened name='Display accounts for followup']"
} else {
Write-Host "================================="
}
if (!(Test-IsCollectionNullOrEmpty $foldersToKeep)) {
$tcBlurb = "Keep these accounts"
if ($teamCity) {
Write-Host "##teamcity[blockOpened name='$tcBlurb']"
} else {
Write-Host "$logLead : Found these folders to KEEP"
}
foreach($folder in $foldersToKeep) {
if ($teamCity) {
Write-Host "$logLead : KEEP C:\Users\$folder"
} else {
Write-Verbose "$logLead : KEEP C:\Users\$folder"
}
}
if ($teamCity) {
Write-Host "##teamcity[blockClosed name='$tcBlurb']"
} else {
Write-Host "================================="
}
}
if (!(Test-IsCollectionNullOrEmpty $foldersToRemove)) {
$tcBlurb = "Remove these accounts"
if ($teamCity) {
Write-Host "##teamcity[blockOpened name='$tcBlurb']"
} else {
Write-Host "$logLead : Found these folders to REMOVE"
}
foreach($folder in $foldersToRemove) {
Write-Host "$logLead : REMOVE C:\Users\$folder"
$matchingCimInstances = @($allCimAccounts.Where({$_.LocalPath -eq "C:\Users\$folder"}))
foreach($instance in $matchingCimInstances) {
if ($instance.Sid.StartsWith("S-1-5-82")) {
Write-Host "$logLead : $folder is an IIS-AppPool SID"
}
}
$matchingCimInstances | Remove-CimInstance -WhatIf:$WhatIf
}
if ($teamCity) {
Write-Host "##teamcity[blockClosed name='$tcBlurb']"
} else {
Write-Host ""
}
}
if ($teamCity) {
Write-Host "##teamcity[blockClosed name='Display accounts for followup']"
} else {
Write-Host "================================="
}
return $foldersToRemove
}