Скрипт аудиту локальних адміністраторів

Показує, хто на комп’ютері має повні права, чи увімкнений вбудований запис адміністратора, у якому стані контроль облікових записів і шифрування системного диска. Дописує рядок у спільний CSV із переліком ризиків. Нічого не змінює. Перевірений на Windows 11 Pro 26200.

Скрипт

Без прав адміністратора теж працює — тоді стан шифрування диска буде недоступний.

Get-LocalAdmins.ps1
# Аудит локальних адміністраторів: хто на цьому комп’ютері має повні права,
# у якому стані UAC, чи зашифрований диск і чи увімкнений вбудований Administrator.
# Нічого не змінює — тільки читає. Дописує рядок у спільний CSV.
#
#   .\Get-LocalAdmins.ps1
#   .\Get-LocalAdmins.ps1 -CsvPath "\\SERVER\inv\local-admins.csv"

param(
    [string] $CsvPath
)

$ErrorActionPreference = 'SilentlyContinue'

# --- Хто в групі адміністраторів ---------------------------------------
# Групу шукаємо за SID, а не за назвою: в українській Windows вона
# зветься «Адміністратори», в англійській — Administrators.
$admins = Get-LocalGroupMember -SID 'S-1-5-32-544'
$adminNames = @()
foreach ($a in $admins) {
    $short = ($a.Name -split '\\')[-1]
    # Вбудовані записи системи не рахуємо як «зайвих людей»
    $builtin = $short -in 'Administrator', 'Адміністратор', 'Domain Admins', 'Адміни домену'
    $adminNames += [pscustomobject]@{
        Name     = $a.Name
        Class    = $a.ObjectClass
        Source   = $a.PrincipalSource
        Builtin  = $builtin
    }
}
$people = @($adminNames | Where-Object { -not $_.Builtin })

# --- Вбудований Administrator ------------------------------------------
$builtinAdmin = Get-LocalUser | Where-Object { $_.SID.Value -like 'S-1-5-*-500' } | Select-Object -First 1

# --- UAC ----------------------------------------------------------------
$sys = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System'
$enableLua = (Get-ItemProperty $sys -Name EnableLUA).EnableLUA
$promptAdmin = (Get-ItemProperty $sys -Name ConsentPromptBehaviorAdmin).ConsentPromptBehaviorAdmin
$promptUser = (Get-ItemProperty $sys -Name ConsentPromptBehaviorUser).ConsentPromptBehaviorUser

# ConsentPromptBehaviorUser = 3 означає, що звичайному користувачеві
# Windows сама пропонує ввести дані адміністратора — саме те, що потрібно
# для схеми «працюємо без прав, підвищуємо за потреби».
$promptUserText = switch ($promptUser) {
    0 { 'відмовляти без запиту' }
    1 { 'запит облікових даних на захищеному робочому столі' }
    3 { 'запит облікових даних' }
    default { "значення $promptUser" }
}

# --- Шифрування системного диска ---------------------------------------
# Без прав адміністратора модуль BitLocker друкує власні помилки повз
# $ErrorActionPreference, тому глушимо потік помилок явно.
$bl = $null
try { $bl = Get-BitLockerVolume -MountPoint $env:SystemDrive -ErrorAction Stop 2>$null } catch { }
$blState = if ($bl) { "$($bl.VolumeStatus) / $($bl.ProtectionStatus)" } else { 'потрібні права адміністратора' }

# --- Ризики -------------------------------------------------------------
$risks = @()
if ($people.Count -gt 0)        { $risks += "зайвих адміністраторів: $($people.Count)" }
if ($enableLua -ne 1)           { $risks += 'UAC вимкнений' }
if ($builtinAdmin.Enabled)      { $risks += 'вбудований Administrator увімкнений' }
if ($bl -and $bl.ProtectionStatus -ne 'On') { $risks += 'системний диск не зашифрований' }

$row = [pscustomobject]@{
    Компютер        = $env:COMPUTERNAME
    Адміністратори  = (($adminNames | ForEach-Object { $_.Name }) -join '; ')
    ЗайвіЛюди       = (($people | ForEach-Object { $_.Name }) -join '; ')
    КількістьЗайвих = $people.Count
    ВбудованийAdmin = if ($builtinAdmin) { "$($builtinAdmin.Name): $(if ($builtinAdmin.Enabled) { 'увімкнений' } else { 'вимкнений' })" } else { 'не знайдено' }
    UAC             = if ($enableLua -eq 1) { 'увімкнений' } else { 'ВИМКНЕНИЙ' }
    ЗапитДляЮзера   = $promptUserText
    BitLocker       = $blState
    Ризики          = ($risks -join '; ')
    Дата            = (Get-Date -Format 'yyyy-MM-dd HH:mm')
}

$row | Format-List

if ($CsvPath) {
    $dir = Split-Path $CsvPath -Parent
    if ($dir -and -not (Test-Path $dir)) { New-Item -ItemType Directory -Path $dir -Force | Out-Null }
    $exists = Test-Path $CsvPath
    # UTF8 з BOM — інакше Excel покаже кирилицю абракадаброю
    $row | Export-Csv -Path $CsvPath -NoTypeInformation -Encoding UTF8 -Append:$exists
    Write-Host "Записано у $CsvPath" -ForegroundColor Green
}
Зібрати парк в один файл:
.\Get-LocalAdmins.ps1 -CsvPath "\SERVER\inv\local-admins.csv"
Або віддалено, якщо є домен і WinRM: Invoke-Command -ComputerName PC1,PC2 -FilePath .\Get-LocalAdmins.ps1

Як читати результат

Колонка «ЗайвіЛюди» — це ваш список роботи. Туди потрапляють усі, крім вбудованих записів системи. Порожньо — комп’ютер у порядку.
«UAC: ВИМКНЕНИЙ» важливіше за кількість адміністраторів. З вимкненим контролем облікових записів будь-яка запущена програма одразу отримує повні права, без жодного запиту.
Групу шукайте за ідентифікатором, а не за назвою. В українській Windows вона зветься «Адміністратори», в англійській — Administrators. Тому в скрипті -SID 'S-1-5-32-544', і він працює на будь-якій локалізації.
Файл .ps1 зберігайте у UTF-8 з BOM. Windows PowerShell 5.1 читає файл без BOM як ANSI, і скрипт з українськими коментарями не запуститься.