Загрузка данных
#requires -version 2.0
<#
.SYNOPSIS
Проверка отключения LLMNR и NetBIOS.
.DESCRIPTION
Скрипт проверяет:
- LLMNR
- NetBIOS over TCP/IP
- TCP/139
- UDP/137-138
Формат summary:
COMPUTER01 - PASS
COMPUTER02 - PASS WITH WARNINGS
COMPUTER03 - FAIL
Для каждого компьютера создается подробный файл:
COMPUTER01.txt
После успешного сохранения результата на сетевую шару
файл переименовывается в:
COMPUTER01_PASS.txt
COMPUTER01_FAIL.txt
COMPUTER01_PASS_WITH_WARNINGS.txt
Дополнительно создается пустой marker-файл:
COMPUTER01.marker
Marker создается ТОЛЬКО после успешного сохранения
и переименования сетевого отчета.
Если marker существует, компьютер вообще не обращается
к сетевой папке и проверка не выполняется повторно.
Если сетевой путь недоступен:
- результат сохраняется локально;
- .marker НЕ создается;
- при следующем запуске будет новая попытка.
#>
# ============================================================
# CONFIGURATION
# ============================================================
# Общая директория для результатов
$ResultDirectory = "\\10.68.16.120\report\netbios_llmnr_check"
# Общий файл со сводкой
$SummaryFile = Join-Path $ResultDirectory "summary.txt"
# Имя компьютера
$ComputerName = $env:COMPUTERNAME
# ============================================================
# MARKER FILE
# ============================================================
# Пустой marker-файл.
#
# Например:
#
# PC-001.marker
#
# Сам факт наличия этого файла означает:
# "этот компьютер уже успешно сохранил результат на сервере"
$MarkerFile = Join-Path `
$ResultDirectory `
($ComputerName + ".marker")
# ============================================================
# INITIALIZATION
# ============================================================
$ErrorActionPreference = "SilentlyContinue"
# ============================================================
# MARKER CHECK
# ============================================================
# Проверяем ТОЛЬКО marker-файл.
#
# Если он существует — компьютер уже обработан.
#
# ВАЖНО:
# Если marker существует, к другим сетевым файлам
# вообще не обращаемся.
if (Test-Path $MarkerFile) {
Write-Host ""
Write-Host "============================================================"
Write-Host "NETBIOS + LLMNR POLICY AUDIT"
Write-Host "============================================================"
Write-Host ""
Write-Host "Computer: $ComputerName"
Write-Host ""
Write-Host "Audit already completed."
Write-Host ""
Write-Host "Marker:"
Write-Host $MarkerFile
Write-Host ""
Write-Host "No action required."
Write-Host "============================================================"
exit 0
}
# ============================================================
# INITIALIZATION
# ============================================================
$Results = New-Object System.Collections.ArrayList
$FailCount = 0
$WarnCount = 0
$PassCount = 0
# ============================================================
# FUNCTIONS
# ============================================================
function Add-Result {
param(
[string]$Status,
[string]$Name,
[string]$Details
)
$Line = "[{0}] {1}: {2}" -f $Status, $Name, $Details
[void]$Results.Add($Line)
switch ($Status) {
"PASS" {
$script:PassCount++
}
"FAIL" {
$script:FailCount++
}
"WARN" {
$script:WarnCount++
}
}
}
function Add-Section {
param(
[string]$Title
)
$Separator = ""
$Separator = $Separator.PadLeft(60, "-")
[void]$Results.Add("")
[void]$Results.Add($Separator)
[void]$Results.Add($Title)
[void]$Results.Add($Separator)
}
function Get-RegistryValueSafe {
param(
[string]$Path,
[string]$Name
)
try {
$Property = Get-ItemProperty `
-Path $Path `
-Name $Name `
-ErrorAction Stop
return $Property.$Name
}
catch {
return $null
}
}
# ============================================================
# SYSTEM INFORMATION
# ============================================================
$OS = Get-WmiObject Win32_OperatingSystem
$ComputerSystem = Get-WmiObject Win32_ComputerSystem
$DateTime = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$OSCaption = $OS.Caption
$OSVersion = $OS.Version
$OSBuild = $OS.BuildNumber
$Domain = $ComputerSystem.Domain
$CurrentUser = `
$env:USERDOMAIN + "\" + $env:USERNAME
# ============================================================
# REPORT HEADER
# ============================================================
[void]$Results.Add(
"============================================================"
)
[void]$Results.Add(
"DOMAIN SECURITY AUDIT"
)
[void]$Results.Add(
"============================================================"
)
[void]$Results.Add("")
[void]$Results.Add("Computer : $ComputerName")
[void]$Results.Add("Domain : $Domain")
[void]$Results.Add("OS : $OSCaption")
[void]$Results.Add("Version : $OSVersion")
[void]$Results.Add("Build : $OSBuild")
[void]$Results.Add("User : $CurrentUser")
[void]$Results.Add("Date : $DateTime")
# ============================================================
# 1. LLMNR
# ============================================================
Add-Section "1. LLMNR"
# просто проверка реестра
$LLMNRPath = `
"HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\DNSClient"
$EnableMulticast = Get-RegistryValueSafe `
-Path $LLMNRPath `
-Name "EnableMulticast"
if ($null -eq $EnableMulticast) {
Add-Result `
-Status "FAIL" `
-Name "LLMNR policy" `
-Details "EnableMulticast отсутствует. LLMNR не считается отключенным."
}
elseif ([int]$EnableMulticast -eq 0) {
Add-Result `
-Status "PASS" `
-Name "LLMNR policy" `
-Details "EnableMulticast = 0. LLMNR отключен."
}
else {
Add-Result `
-Status "FAIL" `
-Name "LLMNR policy" `
-Details "EnableMulticast = $EnableMulticast. LLMNR включен."
}
# ============================================================
# 2. NETBIOS OVER TCP/IP
# ============================================================
Add-Section "2. NETBIOS over TCP/IP"
# получение списка всех сетевых адаптеров
$Adapters = Get-WmiObject `
Win32_NetworkAdapterConfiguration `
-Filter "IPEnabled=True"
if ($null -eq $Adapters) {
Add-Result `
-Status "WARN" `
-Name "NetBIOS adapters" `
-Details "IP-enabled сетевые адаптеры не найдены."
}
else {
$NetBIOSFailure = $false
foreach ($Adapter in $Adapters) {
$Description = $Adapter.Description
$Index = $Adapter.Index
$TcpipNetbiosOptions = `
$Adapter.TcpipNetbiosOptions
# TcpipNetbiosOptions:
#
# 0 = NetBIOS configuration from DHCP
# 1 = NetBIOS enabled
# 2 = NetBIOS disabled
if ($TcpipNetbiosOptions -eq 2) {
Add-Result `
-Status "PASS" `
-Name "NetBIOS adapter $Index" `
-Details "$Description -> TcpipNetbiosOptions = 2. NetBIOS disabled."
}
elseif ($TcpipNetbiosOptions -eq 1) {
Add-Result `
-Status "FAIL" `
-Name "NetBIOS adapter $Index" `
-Details "$Description -> TcpipNetbiosOptions = 1. NetBIOS ENABLED."
$NetBIOSFailure = $true
}
elseif ($TcpipNetbiosOptions -eq 0) {
Add-Result `
-Status "FAIL" `
-Name "NetBIOS adapter $Index" `
-Details "$Description -> TcpipNetbiosOptions = 0. NetBIOS controlled by DHCP."
$NetBIOSFailure = $true
}
else {
Add-Result `
-Status "WARN" `
-Name "NetBIOS adapter $Index" `
-Details "$Description -> неизвестное значение: $TcpipNetbiosOptions."
$NetBIOSFailure = $true
}
}
if ($NetBIOSFailure) {
Add-Result `
-Status "FAIL" `
-Name "NetBIOS overall" `
-Details "Как минимум один IP-enabled адаптер не имеет принудительно отключенного NetBIOS."
}
else {
Add-Result `
-Status "PASS" `
-Name "NetBIOS overall" `
-Details "На всех IP-enabled адаптерах NetBIOS over TCP/IP отключен."
}
}
# ============================================================
# 3. TCP/139
# ============================================================
Add-Section "3. TCP/139"
$TCP139 = netstat -ano -p tcp 2>$null |
Select-String "LISTENING" |
Select-String ":139"
if ($TCP139) {
[void]$Results.Add("TCP/139 listeners:")
[void]$Results.Add(
($TCP139 | Out-String).Trim()
)
Add-Result `
-Status "FAIL" `
-Name "TCP/139" `
-Details "Обнаружен LISTENING TCP/139."
}
else {
Add-Result `
-Status "PASS" `
-Name "TCP/139" `
-Details "LISTENING TCP/139 не обнаружен."
}
# ============================================================
# 4. UDP/137-138
# ============================================================
Add-Section "4. UDP/137-138"
$UDPNetBIOS = netstat -ano -p udp 2>$null |
Select-String ":(137|138)\s"
if ($UDPNetBIOS) {
[void]$Results.Add("UDP NetBIOS listeners:")
[void]$Results.Add(
($UDPNetBIOS | Out-String).Trim()
)
Add-Result `
-Status "FAIL" `
-Name "UDP/137-138" `
-Details "Обнаружен UDP listener на NetBIOS портах."
}
else {
Add-Result `
-Status "PASS" `
-Name "UDP/137-138" `
-Details "UDP/137-138 listeners не обнаружены."
}
# ============================================================
# FINAL RESULT
# ============================================================
Add-Section "FINAL RESULT"
[void]$Results.Add("PASS : $PassCount")
[void]$Results.Add("WARN : $WarnCount")
[void]$Results.Add("FAIL : $FailCount")
[void]$Results.Add("")
# Определяем общий статус компьютера
if ($FailCount -eq 0 -and $WarnCount -eq 0) {
$OverallStatus = "PASS"
[void]$Results.Add(
"RESULT: PASS"
)
[void]$Results.Add(
"LLMNR и NetBIOS выглядят полностью отключенными."
)
}
elseif ($FailCount -eq 0) {
$OverallStatus = "PASS WITH WARNINGS"
[void]$Results.Add(
"RESULT: PASS WITH WARNINGS"
)
[void]$Results.Add(
"Критических нарушений не обнаружено, но присутствуют предупреждения."
)
}
else {
$OverallStatus = "FAIL"
[void]$Results.Add(
"RESULT: FAIL"
)
[void]$Results.Add(
"Обнаружены настройки, требующие исправления."
)
}
# ============================================================
# PREPARE DETAILED RESULT
# ============================================================
$Header = ""
$Header = $Header.PadLeft(70, "=")
$Output = New-Object System.Collections.ArrayList
[void]$Output.Add("")
[void]$Output.Add($Header)
[void]$Output.Add(
"COMPUTER: $ComputerName"
)
[void]$Output.Add(
"DATE: $DateTime"
)
[void]$Output.Add($Header)
foreach ($Line in $Results) {
[void]$Output.Add($Line)
}
[void]$Output.Add($Header)
[void]$Output.Add(
"END OF AUDIT: $ComputerName"
)
[void]$Output.Add($Header)
[void]$Output.Add("")
# ============================================================
# PREPARE COMPUTER RESULT FILE
# ============================================================
$ComputerResultFile = Join-Path `
$ResultDirectory `
($ComputerName + ".txt")
# ============================================================
# WRITE DETAILED COMPUTER FILE
# ============================================================
$ResultSavedToNetwork = $false
try {
# Сначала создаём обычный файл:
#
# PC-001.txt
$Output | Out-File `
-FilePath $ComputerResultFile `
-Encoding UTF8 `
-Force `
-ErrorAction Stop
$ResultSavedToNetwork = $true
}
catch {
# Если сеть недоступна —
# сохраняем локально.
$LocalLogDirectory = `
"C:\netbios_llmnr_check"
if (-not (Test-Path $LocalLogDirectory)) {
New-Item `
-Path $LocalLogDirectory `
-ItemType Directory `
-Force `
-ErrorAction SilentlyContinue | Out-Null
}
$LocalResult = Join-Path `
$LocalLogDirectory `
($ComputerName + ".txt")
$Output | Out-File `
-FilePath $LocalResult `
-Encoding UTF8 `
-Force
}
# ============================================================
# RENAME NETWORK RESULT TO STATUS FILE
# ============================================================
if ($ResultSavedToNetwork) {
# Заменяем пробелы на "_"
$StatusForFileName = `
$OverallStatus.Replace(" ", "_")
# Например:
#
# PC-001.txt
#
# превращается в:
#
# PC-001_PASS.txt
# PC-001_FAIL.txt
# PC-001_PASS_WITH_WARNINGS.txt
$FinalFileName = `
$ComputerName + "_" +
$StatusForFileName +
".txt"
$FinalResultFile = Join-Path `
$ResultDirectory `
$FinalFileName
try {
Write-Host ""
Write-Host "Renaming result file:"
Write-Host $ComputerResultFile
Write-Host "TO:"
Write-Host $FinalResultFile
Rename-Item `
-Path $ComputerResultFile `
-NewName $FinalFileName `
-Force `
-ErrorAction Stop
# ====================================================
# VERIFY RENAME
# ====================================================
if (Test-Path $FinalResultFile) {
Write-Host ""
Write-Host "Rename successful."
Write-Host "Final result:"
Write-Host $FinalResultFile
$MarkerFileCreated = $false
# =================================================
# CREATE EMPTY MARKER
# =================================================
try {
# Создаём пустой marker-файл.
#
# Например:
#
# PC-001.marker
New-Item `
-Path $MarkerFile `
-ItemType File `
-Force `
-ErrorAction Stop | Out-Null
# Проверяем, что marker действительно появился.
if (Test-Path $MarkerFile) {
$MarkerFileCreated = $true
Write-Host ""
Write-Host "Marker created:"
Write-Host $MarkerFile
}
}
catch {
Write-Host ""
Write-Host "WARNING: Failed to create marker file."
Write-Host $_.Exception.Message
}
# =================================================
# IMPORTANT
# =================================================
# Marker является признаком того,
# что сетевой результат полностью сохранен.
#
# Если marker создать не удалось,
# при следующем запуске проверка повторится.
if ($MarkerFileCreated) {
$MarkerFile = $MarkerFile
}
else {
$MarkerFile = $null
}
}
else {
Write-Host ""
Write-Host "ERROR: Rename command completed,"
Write-Host "but final result file was not found."
$MarkerFile = $null
}
}
catch {
Write-Host ""
Write-Host "============================================================"
Write-Host "ERROR: FAILED TO RENAME RESULT FILE"
Write-Host "============================================================"
Write-Host ""
Write-Host "Computer:"
Write-Host $ComputerName
Write-Host ""
Write-Host "Source:"
Write-Host $ComputerResultFile
Write-Host ""
Write-Host "Destination:"
Write-Host $FinalResultFile
Write-Host ""
Write-Host "Error:"
Write-Host $_.Exception.Message
Write-Host ""
Write-Host "============================================================"
$MarkerFile = $null
}
}
# ============================================================
# WRITE SUMMARY
# ============================================================
try {
# В общий файл пишем только:
#
# COMPUTER - STATUS
$SummaryLine = "{0} - {1}" -f `
$ComputerName, `
$OverallStatus
Add-Content `
-Path $SummaryFile `
-Value $SummaryLine `
-Encoding UTF8 `
-ErrorAction Stop
}
catch {
# Summary недоступен.
#
# Подробный результат уже сохранен.
}
# ============================================================
# CONSOLE OUTPUT
# ============================================================
Write-Host ""
Write-Host "============================================================"
Write-Host "DOMAIN SECURITY AUDIT"
Write-Host "============================================================"
Write-Host ""
foreach ($Line in $Results) {
Write-Host $Line
}
Write-Host ""
Write-Host "============================================================"
Write-Host "Computer result:"
Write-Host ""
if ($ResultSavedToNetwork) {
if ($null -ne $FinalResultFile) {
Write-Host $FinalResultFile
}
else {
Write-Host $ComputerResultFile
}
}
else {
Write-Host "Network unavailable."
Write-Host "Local result:"
Write-Host `
"C:\netbios_llmnr_check\$ComputerName.txt"
}
Write-Host ""
Write-Host "Marker:"
if (Test-Path $MarkerFile) {
Write-Host $MarkerFile
}
else {
Write-Host "NOT CREATED"
}
Write-Host ""
Write-Host "Overall status:"
Write-Host $OverallStatus
Write-Host "============================================================"