This
PowerShell script was written to facilitate an audit of the local admin groups on all systems in our domain. It will remove invalid accounts, or add new ones, or simply report what it finds.
******* Updated version *******
#Region Header
#======================================================================================
#
File Name : Audit-And-Purge-LocalAdmins.ps1
#
Original Author : Kenneth C. Mazie (kcmjr AT kcmjr.com)
#
:
#
Description : Used to audit and manage the local administrators group on domain
computers.
#
:
#
Notes : Original version rewritten for more reliable operation and better
reporting.
#
: Make sure to update all variables before running. Output is only to the
console.
#
:
#
Arguments : 4 pipeline command argument options exist:
#
: -Report <mode> Mode must be "brief"
"verbose", or "none". Defaults to "brief"
#
: -Debug If included enables test
mode. Defaults to $false if left off.
#
: -Add If included will
add any user ID in the "ValidAdmins"
#
:
array to local admin group on domain systems.
#
: -Remove If included will remove any user
ID in the "BadUserNames"
#
:
hash table from the local admins group on domain systems.
#
: Any combination of options can be included at once.
#
:
#
Warnings : Be carefull not to delete important accounts (like your own)!!
#
:
#
Legal : Public Domain. Modify and redistribute freely. No rights reserved.
#
: SCRIPT PROVIDED "AS IS" WITHOUT WARRANTIES OR GUARANTEES OF
#
: ANY KIND. USE AT YOUR OWN RISK. NO TECHNICAL SUPPORT PROVIDED.
#
:
#
Credits : Code snippets and/or ideas came from many sources including but
#
: not limited to the following:
#
:
#
Last Update by : Kenneth C. Mazie
#
Version History : v1.0 - 02-19-14 - Original
#
Change History : v1.1 - 04-03-14 - Misc edits
#
: v2.0 - 05-15-14 - MAJOR rewrite. Altered all process flows.
Altered
#
: input file format.
#
:
#=======================================================================================
#EndRegion
Param (
[switch]$Debug,
[switch]$Add,
[switch]$Remove,
$Report = "brief"
)
Clear-Host
$ErrorActionPreference = "silentlycontinue"
$Domain = "mydomain"
$TestPC = "test-machine"
Try{if (!(Get-Module -Name ActiveDirectory)){Import-Module ActiveDirectory}}
Catch{[void][System.Windows.Forms.MessageBox]::Show("The Active Directory
PowerShell module was not found and is required. Exiting" , "Error");Break}
function ListAdministrators
{$members = $Group.psbase.invoke("Members") | %{$_.GetType().InvokeMember("Name",'GetProperty',$null,$_,$null)}
#$members
return $members}
$ValidAdmins = @{ #--[ Hash table of valid
local admins ]--
1="enterprise
admins";
2="domain admins";
3="administrator";
4="user1"
}
$NewAdmins = @() #--[ Array of new admins to
add ]--
$NewAdmins += "testuser"
$BadUserNames = @{ #--[ Hash table of users to
remove from local admins group ]--
1="testuser";
2="bob";
3="jim";
4="dan"
}
Write-Host "Processing domain
membership..." -ForegroundColor Yellow
If ($Debug){$Computers = @($TestPC)}Else{$Computers = Get-ADComputer -Filter {OperatingSystem -Like "*Windows*"} -Property * | select name}
$Count = $Computers.count
foreach ($Computer in $Computers){
$List = "";$Target = "";$Group = ""
If ($Debug){$Computer = $Computer}Else{$Computer = $Computer.name}
Write-Host "`nTarget =
$Computer ("($Count-1)" remaining )" -ForegroundColor Cyan
if ($Computer -like "*ESX*"){ #--[ One off bypass ]--
Write-Host "BYPASSING "$Computer -ForegroundColor Magenta
}Else{
#--[
Check if computer is accessible, if not go to next computer in list ]--
if (Test-Connection -ComputerName $Computer -Count 1 -ErrorAction SilentlyContinue){
$Target = [ADSI]("WinNT://" + $Computer + ",computer")
$Group = $Target.psbase.children.find("administrators") #--[ Select the local
admins group ]--
$List = ListAdministrators #--[ Get the members of the
administrators group via ADSI ]--
#--[ Alternately get list of users in local admin group with WMI
]--
# $List =
Get-WmiObject -computername $computer -Class win32_GROUPUSER -ErrorAction
SilentlyContinue | WHERE {$_.groupcomponent -match 'administrators' } | foreach
{[wmi]$_.partcomponent }
ForEach ($User in $List){
$User = $User.TrimStart().ToLower()
If ($Report -ne ""){
If ($Report -eq "brief"){} #Write-Host " "$User -ForegroundColor Gray
} #--[ Just report changes, or
optionally all entries ]--
If ($Report -eq "verbose"){
#--[
Report results against valid user list ]--
If ($ValidAdmins.ContainsValue($User)){
Write-Host "
AUTHORIZED admin ""$User"" detected..." -ForegroundColor Green
}Else{
If ($User.substring(0,8) -eq "S-1-5-21"){ #--[ Name is an orphaned
SID ]--
Write-Host "
ORPHANED SID Please Remove Manually... $User" -ForegroundColor Yellow
}Else{
If ($Remove){
Write-Host "
UNAUTHORIZED admin ""$User"" detected..." -ForegroundColor Red
}Else{
Write-Host " UNEXPECTED admin
""$User"" detected..." -ForegroundColor White
}
}
}
}
}
#--[
Remove the user ]----------------------------------------------
If ($Remove){
If ($BadUserNames.ContainsValue($User)){
Write-Host "
--- Attempting to remove ""$User""..." -ForegroundColor Red
$Group.Remove("WinNT://" + $Target + "/" + $User)
$VerifyList = ListAdministrators
If ($VerifyList -contains $User){
Write-Host "
--- Verification failed. Retrying as
""$Domain\$User""..." -ForegroundColor Red
$Group.Remove("WinNT://" + $Target + "/" + $Domain + "/" + $User)
}
$VerifyList = ListAdministrators
If ($VerifyList -contains $User){
Write-Host "
--- Re-Verification failed. Please remove ""$User""
manually ---" -ForegroundColor Red
}Else{
Write-Host " --- Verified removal of
""$User"" ---" -ForegroundColor Green
}
$Change = $true
}
}
}
#--[ Add
the user
]-------------------------------------------------
If ($Add){
ForEach ($Admin in $NewAdmins){
#
$Exists = 0
$AddList = ListAdministrators
If ($AddList -contains $Admin.ToLower()){#$Exist = 1}
#
If ($Exists -eq 0){
Write-Host " NEW
ADMIN ""$Admin"" " -ForegroundColor Gray -NoNewline
Write-Host "EXISTS... Not
Adding" -ForegroundColor Red
}Else{
Write-Host " ADDING
----> $Admin" -ForegroundColor Green
$Group.Add("WinNT://" + $Target.name + "/" + $Admin)
$Change = $true
}
}
}
}Else{
#-------------------------------------------------------------------
Write-Host " System is not reachable online..." -ForegroundColor Red
}
If ($Change){Write-Host " Redetecting admins..." -ForegroundColor Magenta; ListAdministrators; $Change=$false}
}
$Count --
}
Write-host "`nCompleted...
" -ForegroundColor Yellow
-----------------------------------------------------------------------------------
---------------------
Below is the original version -------------------------
-----------------------------------------------------------------------------------
#Region Header
<#======================================================================================
File Name : AuditLocalAdmins.ps1
Original Author : Kenneth C. Mazie (kcmjr AT kcmjr.com)
:
Description : Will examine all systems in specified domain to determine
membership
: in the local admins group.
:
Notes : Add users to ignore to the local admins filter array, otherwise
: all members will be listed. Requires Get-QADComputer from the
: Quest (now Dell) Active Directory commandlets available free at
:
http://www.quest.com/powershell/activeroles-server.aspx
:
Warnings : None
:
Legal : Public Domain. Modify and redistribute freely. No rights reserved.
: SCRIPT PROVIDED "AS IS" WITHOUT WARRANTIES OR GUARANTEES OF
: ANY KIND. USE AT YOUR OWN RISK. NO TECHNICAL SUPPORT PROVIDED.
:
Credits : None
:
Last Update by : Kenneth C. Mazie
Version History : v1.0 - 07-14-14 - Original
Change History : v1.1 - 00-00-00 -
:
=======================================================================================#>
#EndRegion
Clear-Host
$ErrorActionPreference = "silentlycontinue"
$domain = "mydomain.com"
#--[
Local admins to filter out ]--
$Administrators = @{
1="admin1";
2="admin2"
}
$Computers = Get-QADComputer | select name
$Count = $Computers.count
foreach ($Computer in $Computers){
$Computer = $Computer.name
Write-Host "`nTarget = $Computer
($Count)" -ForegroundColor Cyan
if ($Computer -eq "computer1"){ # --[ A one-off bypass
]--
Write-Host "BYPASSING "$Computer -ForegroundColor Magenta
}Else{
#--[
Check if computer is accessible, if not go to next computer in list ]--
if (Test-Connection -ComputerName $Computer -Count 1 -ErrorAction SilentlyContinue){
#--[ Get
list of users in local admin group with WMI ]--
$list = Get-WmiObject -computername $computer -Class win32_GROUPUSER -ErrorAction SilentlyContinue | WHERE {$_.groupcomponent -match 'administrators' } | foreach {[wmi]$_.partcomponent }
#--[ For
each user filter out domain admins and administrator ]--
foreach ($user in $list){
If ($Administrators.ContainsValue($user.name.tolower())){}Else{
Write-Host "
"$user.name
}
}
}Else{
Write-Host "
System is not reachable online..." -ForegroundColor Red
}
$Count --
}
}
Write-host Completed...