As clients modernise, migrating from on-premises to cloud, or legacy UEM tools to more modern ones, there’s often a need to perform some tidy up.
Commonly, I see clients who have added Local Administrator accounts to devices. Often for testing, or “to get a job done”, but then often, they’re forgotten to clean up the accounts afterwards – sometimes it’s even just down to bad practice.
With the likes of Windows LAPS and just-in-time access being available via Endpoint Privilege Management for example, there’s really not much need any more to have multiple Local Administrator accounts present on devices.
For this exact reason, I’ve created a remediation script for use with Microsoft Intune which will, during detection, pull back the users who have “Local Administrator” rights, and display them in the Post-Detection Output column within Intune, which can then be exported for reviewing and cleansing.
The remediation part of the script can remove the identified accounts automatically, if desired.
Detect-LocalAdmins.ps1
<#
.SYNOPSIS
Detection Script for unauthorised Local Administrator accounts
Companion to "Remediate-LocalAdmins.ps1"
.AUTHOR
James Vincent - October 2025
.DESCRIPTION
- Identifies all local accounts in the Administrators group
- Excludes known/approved accounts (e.g. LAPSAdmin)
- If any unauthorised accounts exist, outputs them for Intune detection
#>
# Translate localised Administrators group name using its SID
$sid = New-Object System.Security.Principal.SecurityIdentifier("S-1-5-32-544")
$account = $sid.Translate([System.Security.Principal.NTAccount])
$accountName = $account.Value
$parts = $accountName -split '\\'
$groupName = $parts[1]
# Get members of the local Administrators group
$adminlist = (net localgroup $groupName) | Where-Object { $_ -match '\S' } | Select-Object -Skip 4 | Select-Object -SkipLast 1
# Filter to only local accounts (exclude domain users)
$Regexes = '^[^\\]+$'
$localAdmins = ($adminlist | Select-String -Pattern $Regexes).Line
# Approved local admin accounts
$allowedAdmins = @(
"LAPSAdmin",
"LAPSadm",
"James",
"Vini"
)
# Filter out approved accounts
$unauthorisedAdmins = $localAdmins | Where-Object { $allowedAdmins -notcontains $_ }
# Define Log file and location
$LogDir = "$env:ProgramData\Microsoft\IntuneManagementExtension\Logs"
$LogFile = Join-Path $LogDir "Remediate-LocalAdmins.log"
# Ensure log directory exists
if (!(Test-Path $LogDir)) {
New-Item -Path $LogDir -ItemType Directory -Force | Out-Null
}
# Write logging function
function Write-Log {
param (
[string]$Message,
[string]$Level = "INFO"
)
$timestamp = (Get-Date).ToString("dd-MM-yyyy HH:mm:ss")
$entry = "[$timestamp] [$Level] $Message"
Add-Content -Path $LogFile -Value $entry
Write-Output $entry
}
Write-Log "Starting Local Admin Detection Script"
if ($unauthorisedAdmins) {
Write-Log "Unauthorised Local Admins found: $($unauthorisedAdmins -join ', ')"
Write-Output "Unauthorised Local Admins found:"
Write-Output "$($unauthorisedAdmins -join ', ')"
exit 1 # Non-compliant, triggers remediation
} else {
Write-Log "No unauthorised Local Admin accounts found."
Write-Output "Compliant - No unauthorised Local Admin accounts found."
exit 0 # Compliant
}
Write-Log "Local Admin Detection Complete"
Remediate-LocalAdmins.ps1
<#
.SYNOPSIS
Remediation Script to REMOVE unauthorised Local Administrator accounts
Logs all actions to $env:ProgramData\Microsoft\Logs\Remediate-LocalAdmins.log
.AUTHOR
James Vincent - October 2025
.DESCRIPTION
- Identifies all local accounts in the Administrators group
- Excludes approved accounts (e.g. LAPSAdmin)
- Removes any remaining local admin accounts
- Logs all actions and results to a central log file
#>
# Define Log file and location
$LogDir = "$env:ProgramData\Microsoft\IntuneManagementExtension\Logs"
$LogFile = Join-Path $LogDir "Remediate-LocalAdmins.log"
# Ensure log directory exists
if (!(Test-Path $LogDir)) {
New-Item -Path $LogDir -ItemType Directory -Force | Out-Null
}
# Create or append to the log file
function Write-Log {
param (
[Parameter(Mandatory=$true)][string]$Message,
[ValidateSet("INFO", "WARN", "ERROR")][string]$Level = "INFO"
)
$timestamp = (Get-Date).ToString("dd-MM-yyyy HH:mm:ss")
$entry = "[$timestamp] [$Level] $Message"
Add-Content -Path $LogFile -Value $entry
Write-Output $entry
}
Write-Log "Starting Local Admin Remediation Script"
try {
# Resolve localised Administrators group name
$sid = New-Object System.Security.Principal.SecurityIdentifier("S-1-5-32-544")
$account = $sid.Translate([System.Security.Principal.NTAccount])
$accountName = $account.Value
$parts = $accountName -split '\\'
$groupName = $parts[1]
Write-Log "Resolved Administrators group name as '$groupName'."
# Get members of the local Administrators group
$adminlist = (net localgroup $groupName) | Where-Object { $_ -match '\S' } | Select-Object -Skip 4 | Select-Object -SkipLast 1
# Filter to only local accounts (exclude domain)
$Regexes = '^[^\\]+$'
$localAdmins = ($adminlist | Select-String -Pattern $Regexes).Line
# Approved local admin accounts
$allowedAdmins = @(
"LAPSAdmin",
"LAPSadm",
"James",
"Vini"
)
if ($localAdmins) {
Write-Log "Found the following local admin accounts: $($localAdmins -join ', ')"
foreach ($admin in $localAdmins) {
if ($allowedAdmins -notcontains $admin) {
try {
Write-Log "Attempting to remove unauthorised admin account '$admin'."
#net localgroup $groupName $admin /delete | Out-Null
Write-Log "Successfully removed '$admin'."
} catch {
Write-Log "Failed to remove '$admin': $_" -Level "ERROR"
}
} else {
Write-Log "Skipping approved account '$admin'."
}
}
} else {
Write-Log "No local administrator accounts found to remediate."
}
}
catch {
Write-Log "Unexpected error occurred: $_" -Level "ERROR"
}
Write-Log "Local Admin Remediation Complete"
Upload these as you normally would. Not in the user context, not signed, and in 64bit.
You can choose to just run the detection script also, if you’re not interested in tidying the Local Administrators group just yet. This can be useful for gathering insights.
Leave a Reply