Controlling/Monitoring Local Admin Rights using PowerShell

Almost a month has gone by since my last post so I am long overdue to place some good content. I feel this script I wrote up should be sufficient 🙂 Enjoy!

SANS Critical Control 12: Controlled Use of Administrative Privileges


Download the SourceCode

MD5 – 2AF4224E79672658DCC05AF90A4D0FC8

Recently joined up as a new developer for a great project in my area called PoshSec ( and it has really opened my eyes on how Security Professionals and System Administrators can mitigate security risks using only native PowerShell commands.

Essentially, the goal of PoshSec is to script solutions, baselines & monitoring tools using PowerShell for all the top 20 SANS Critical Security Controls listed below.

  • Critical Control 1: Inventory of Authorized and Unauthorized Devices
  • Critical Control 2: Inventory of Authorized and Unauthorized Software
  • Critical Control 3: Secure Configurations for Hardware and Software on Mobile Devices, Laptops, Workstations, and Servers
  • Critical Control 4: Continuous Vulnerability Assessment and Remediation
  • Critical Control 5: Malware Defenses
  • Critical Control 6: Application Software Security
  • Critical Control 7: Wireless Device Control
  • Critical Control 8: Data Recovery Capability
  • Critical Control 9: Security Skills Assessment and Appropriate Training to Fill Gaps
  • Critical Control 10: Secure Configurations for Network Devices such as Firewalls, Routers, and Switches
  • Critical Control 11: Limitation and Control of Network Ports, Protocols, and Services
  • Critical Control 12: Controlled Use of Administrative Privileges
  • Critical Control 13: Boundary Defense
  • Critical Control 14: Maintenance, Monitoring, and Analysis of Audit Logs
  • Critical Control 15: Controlled Access Based on the Need to Know
  • Critical Control 16: Account Monitoring and Control
  • Critical Control 17: Data Loss Prevention
  • Critical Control 18: Incident Response and Management
  • Critical Control 19: Secure Network Engineering
  • Critical Control 20: Penetration Tests and Red Team Exercises

My recent focus was in reference to Critical Security Control 12: Controlled Use of Administrative Privileges. You can read all about the need to focus attention to this subject here With a recent Security Audit at my work, there has been a larger focus to control what domain users have local administrative rights to their workstation. I decided to kill two birds with one stone by contributing to PoshSec, as well as a providing a comprehensive solution to managing local admin members in my enterprise organization. After a day of creating the script, a day of optimizing the code, and a day in creating help information and useful comments, I have a completed Script.

This can be used natively in PowerShell for the most part. There is an “optional” functionality that can query every computer object in Active Directory and in order to use that functionality, the Active Directory modules must be imported. You can find information on importing Active Directory modules here. If you run into problems, just drop me a message and I will be glad to help out.

*If you copy/paste the code listed below, it does not contain the help information. Make sure to download the script from the link above and validate the MD5 to make sure nothing was corrupted/missing during download. After the download, you will be able to use the Get-Help CMDLET to find valuable help information about using the script.

[code language=”powershell”]
Function Get-SecLocalGroupMembers {

#Local Group Parameter and Validation
"Access Control Assistance Operators",
"Backup Operators",
"Cryptographic Operators",
"Distributed COM Users",
"Event Log Readers",
"Hyper-V Administrators",
"Network Configuration Operators",
"Performance Log Users",
"Performance Monitor Users",
"Power Users",
"Remote Desktop Users",
"Remote Management Users",
[string]$LocalGroup, #Stores variable if parameter input matches any item from above list

#Parameter set switch for static specified computer

#Name is only manditory if -Computer parameter is specified. This accepts multiple computer names seperated by comma.

#Parameter set switch for importing a CSV list of computers

#Path is only manditory if -ImportCSV parameter is specified
[ValidateScript({Test-Path $_ })] #Validates Path is valid

) #End of Parameters/Validation

#Start of Script
$MainObject = @() #Creates the main object array which will store all the unauthorized users

#Approved List of Local Group Members
) | %{$ApprovedArray+= New-Object PSObject -Property @{UserID=($_)}}

#Conditional Logic for $Computers Array

#Imports the results from an Active Directory Query and stores it as the $Computers array
if (($ImportCSV -eq $False) -and ($Computer -eq $False)) {[array]$Computers = Get-ADComputer -Filter ‘name -like "VWGOAAHL3032*"’}

#Imports the list of computers (.CSV) and stores it as the $Computers array
if (($ImportCSV -eq $True) -and ($Computer -eq $False)) {[array]$Computers = Import-CSv $CSVPath}

#Stores the manually specified computer name(s) as the $Computers array
if (($ImportCSV -eq $False) -and ($Computer -eq $True)) {[array]$Computers = $Name}

#Start of $Computers Array loop
Write-Host -ForegroundColor DarkGray "Analyzing and comparing data on $i`n" #Console Ouput notifying that script is starting
foreach ($i in $Computers) {
if (($ImportCSV -eq $False) -and ($Computer -eq $False)) {$i = $} #needed for AD translation
if (($ImportCSV -eq $True) -and ($Computer -eq $False)) {$i = $i.ComputerName} #needed for CSV translation (ComputerName is the header of the CSV list)

#Validates network connectivy of current computer in loop.
if(!(Test-Connection -Cn $i -BufferSize 16 -Count 1 -ea 0 -quiet)){Write-Host -ForegroundColor DarkRed "$i"} #If Unpingable, it moves onto next computer in list

#If pingable, script continues on to retrieve data
else {
$ErrorActionPreference = "SilentlyContinue" #Suppresses Errors
Write-Host -ForegroundColor Gray "$i" #Console Ouput displaying current computer in loop

#Establishing an Active Directory Services Interface (ADSI) connection to current computer in loop
$members = @($ADSI.psbase.Invoke("Members"))
$group = $members | % {$_.GetType().InvokeMember("Name", ‘GetProperty’, $null, $_, $null)}

$ComputerArray = @() #Creates the Internal array which will store all group members of the current computer in loop

#Retrieves members of Local Group for the current computer in loop
$group | %{$ComputerArray += New-Object PSObject -Property @{UserID=($_)}}

#Compares array of approved members, to the array of currently retrieved members
$Unauthorized = Compare-Object $ApprovedArray $ComputerArray -Property UserID

#Analyzes compared results and adds results to the $Mainobject array used in report
$Unauthorized | %{
if ($_.SideIndicator -eq "<=") {$Status = "Missing"} #Approved member not found on current computer elseif ($_.SideIndicator -eq "=>") {$Status = "Found"} #Unauthorized member found on current computer
$MainObject+= New-Object PSObject -Property @{
} #End of $Unauthorized Loop

} #End of Else Loop

}#End of Computers Loop

$MainObject | Export-Clixml -Path C:UserspublicDocumentsGet-SecLocalGroupMembers-2013728.xml
$MainObject | Export-CSV -Path C:UserspublicDocumentsGet-SecLocalGroupMembers-2013728.CSV -NoTypeInformation

} # End of Process

} # End of Function

Lines 53-58 contain an “Approved” list of Local Group Members. So if you want to make sure that one or more Users/Groups are authorized to be in each local group. It can be edited/adjusted to fit your needs.

How it all works.

  • Script Logic (Psedo Code)

  • Parameter Definition

    • User Types CMDLET Parameters defining what local group to compare
      • Validates specified local group parameter on default windows groups to see if parameter valid
  • User continues to type CMDLET Parameters defining what computers to retrieve information from

    • Validates if script should pull information from a (.CSV) list, manually specification, or pull from Active Directory
      • If -ImportCSVPath is used, user can specifcy a path to CSV containing computername (See Synax/Examples)
      • If -Computer is used, user can specify one ore more computernames seperated by comma (See Syntax/Examples)
      • If neither switch is used, it will automatically query AD for computer objects (See Syntax/Examples)
  • Creates Approved Array object based on hard-coded list of Approved Local Group Members

  • Start of Computer List Loop

    • Verify computer is pingable
      • If pingable, moves on to next step
      • If unpingable, skips computer.
  • Retrieve list of current members in local group

    • Create ADSI Connection
    • Stores retrieved group members into an array
  • Compare the retrieved local group member array, against the approved local group member array

    • Stores results as Variable
    • If unauthorized users are found, then it will add them to MainArray with status of “Found”
    • If Approved local group members are not found, it will add them to MainArray with status of “Missing”
  • End of Computer List Loop, will repeat until no more computers are in loop. Each time appending to MainArray

  • The MainArray of unauthorized users that contains the userID,Hostname, & Status is displayed to the console

    • MainArray is exported to .XML
    • MainArray is exported to .CSV

That’s all for today, be sure to check back as I will be creating a video demonstration of this script and its uses soon.

As always please feel free to subscribe/comment/share



Tags// , ,
More Reading
Older// About