Загрузка данных
#requires -version 2.0
<#
.SYNOPSIS
Аудит отключения SMBv1 (клиент + сервер), фактическое состояние.
.NOTES
Запуск: startup-скрипт GPO (SYSTEM) или logon-скрипт с правами админа.
Принудительный повтор без учёта маркера: задать переменную среды SMB1_AUDIT_FORCE=1
Пропуск задержки: SMB1_AUDIT_NODELAY=1
#>
# ============ CONFIG ============
$ResultDirectory = "\\192.168.6.7\report\smbv1\"
$SummaryCsv = Join-Path $ResultDirectory "_summary.csv"
$LocalLogDirectory = "C:\smb_v1_check"
$MinDelaySeconds = 60
$MaxDelaySeconds = 300 # НЕ выше 540: startup-скрипт GPO живёт 600 сек
$MarkerExpireDays = 30 # через столько дней аудит повторяется
# ================================
$ComputerName = $env:COMPUTERNAME
$Results = New-Object System.Collections.ArrayList
$FailCount = 0; $WarnCount = 0; $PassCount = 0
function Add-Result([string]$Status, [string]$Name, [string]$Details) {
[void]$Results.Add(("[{0}] {1}: {2}" -f $Status, $Name, $Details))
switch ($Status) {
"PASS" { $script:PassCount++ }
"FAIL" { $script:FailCount++ }
"WARN" { $script:WarnCount++ }
}
}
function Add-Section([string]$Title) {
[void]$Results.Add("")
[void]$Results.Add(("-" * 60))
[void]$Results.Add($Title)
[void]$Results.Add(("-" * 60))
}
function Get-RegistryValueSafe([string]$Path, [string]$Name) {
try {
$p = Get-ItemProperty -Path $Path -Name $Name -ErrorAction Stop
return $p.$Name
} catch { return $null }
}
function Test-IsAdmin {
$id = [System.Security.Principal.WindowsIdentity]::GetCurrent()
$pr = New-Object System.Security.Principal.WindowsPrincipal($id)
return $pr.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator)
}
function Test-PendingReboot {
if (Test-Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending") { return $true }
if (Test-Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired") { return $true }
$v = Get-RegistryValueSafe "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager" "PendingFileRenameOperations"
return ($null -ne $v)
}
# Состояние компонента SMB1Protocol через DISM (Win8+). Возврат: строка State или $null
function Get-DismFeatureState {
try {
$out = & dism.exe /online /get-featureinfo /featurename:SMB1Protocol /format:list 2>$null
foreach ($line in $out) {
if ($line -match "^\s*State\s*:\s*(.+)$") { return $Matches[1].Trim() }
}
} catch {}
return $null
}
# ============ OS INFO ============
$OS = Get-WmiObject Win32_OperatingSystem
$CS = Get-WmiObject Win32_ComputerSystem
$DateTime = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$OSCaption = $OS.Caption
$OSBuild = [int]$OS.BuildNumber
$IsWin7 = ($OS.Version -like "6.1*")
$IsWin8Plus = ([version]$OS.Version -ge [version]"6.2")
$Arch = $OS.OSArchitecture
if ([string]::IsNullOrEmpty($Arch)) { $Arch = $(if ([IntPtr]::Size -eq 8) {"64-bit"} else {"32-bit"}) }
# ============ SHARE AVAILABILITY ============
$ShareAvailable = Test-Path $ResultDirectory
# Догрузка локальных отчётов прошлых запусков
if ($ShareAvailable -and (Test-Path $LocalLogDirectory)) {
Get-ChildItem $LocalLogDirectory -Filter "*.txt" -ErrorAction SilentlyContinue | ForEach-Object {
try { Copy-Item $_.FullName (Join-Path $ResultDirectory $_.Name) -Force; Remove-Item $_.FullName -Force } catch {}
}
}
# ============ MARKER ============
if ($ShareAvailable -and $env:SMB1_AUDIT_FORCE -ne "1") {
$marker = Get-ChildItem $ResultDirectory -Filter ($ComputerName + "_*.txt") -ErrorAction SilentlyContinue |
Sort-Object LastWriteTime -Descending | Select-Object -First 1
if ($null -ne $marker) {
$age = (New-TimeSpan -Start $marker.LastWriteTime -End (Get-Date)).Days
if ($age -lt $MarkerExpireDays) {
Write-Host "Audit already completed $($age)d ago: $($marker.FullName). Exit."
exit 0
}
Remove-Item $marker.FullName -Force -ErrorAction SilentlyContinue
}
}
# ============ DELAY ============
if ($env:SMB1_AUDIT_NODELAY -ne "1") {
$Delay = (New-Object System.Random).Next($MinDelaySeconds, $MaxDelaySeconds)
Write-Host "Waiting $Delay seconds..."
Start-Sleep -Seconds $Delay
}
# ============ HEADER ============
[void]$Results.Add("=" * 60)
[void]$Results.Add("SMB v1 DISABLE AUDIT v2")
[void]$Results.Add("=" * 60)
[void]$Results.Add("Computer : $ComputerName")
[void]$Results.Add("Domain : $($CS.Domain)")
[void]$Results.Add("OS : $OSCaption (build $OSBuild, $Arch)")
[void]$Results.Add("Date : $DateTime")
[void]$Results.Add("Elevated : $(Test-IsAdmin)")
# ============ SERVER SIDE ============
Add-Section "1. SERVER SIDE (входящие SMBv1)"
$ServerStatus = "UNKNOWN"
if ($IsWin8Plus) {
# Авторитетный источник: Get-SmbServerConfiguration
$usedCmdlet = $false
try {
$cfg = Get-SmbServerConfiguration -ErrorAction Stop
$usedCmdlet = $true
if ($cfg.EnableSMB1Protocol) {
$ServerStatus = "FAIL"
Add-Result FAIL "Server effective" "Get-SmbServerConfiguration: EnableSMB1Protocol = True. SMBv1-сервер АКТИВЕН."
} else {
$ServerStatus = "PASS"
Add-Result PASS "Server effective" "Get-SmbServerConfiguration: EnableSMB1Protocol = False."
}
} catch {}
if (-not $usedCmdlet) {
$v = Get-RegistryValueSafe "HKLM:\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters" "SMB1"
if ($null -ne $v) {
if ([int]$v -eq 0) { $ServerStatus = "PASS"; Add-Result PASS "Server registry" "LanmanServer\SMB1 = 0." }
else { $ServerStatus = "FAIL"; Add-Result FAIL "Server registry" "LanmanServer\SMB1 = $v. SMBv1 включён." }
} else {
# Параметр отсутствует: на <1709 это ВКЛЮЧЕНО, на >=1709 — смотрим компонент
if ($OSBuild -lt 16299) {
$ServerStatus = "FAIL"
Add-Result FAIL "Server registry" "Параметр SMB1 отсутствует, билд $OSBuild (< 1709): SMBv1-сервер включён по умолчанию. Задать SMB1 = 0."
} else {
$ServerStatus = "WARN"
Add-Result WARN "Server registry" "Параметр SMB1 отсутствует. Состояние определяется компонентом (см. ниже)."
}
}
}
# Состояние компонента (установлен/вычищен)
$dism = Get-DismFeatureState
if ($null -ne $dism) {
Add-Result PASS "Server feature" "Компонент SMB1Protocol: $dism" | Out-Null
# переоформляем как инфо-строку
$Results[$Results.Count - 1] = "[INFO] Server feature: компонент SMB1Protocol = $dism"
$script:PassCount--
if ($dism -match "^Enabled" -and $ServerStatus -eq "PASS") {
$ServerStatus = "WARN"
Add-Result WARN "Server feature" "Компонент SMB1Protocol = $dism: протокол выключен, но бинарники установлены. Рекомендуется Disable-WindowsOptionalFeature -FeatureName SMB1Protocol."
}
}
}
elseif ($IsWin7) {
$v = Get-RegistryValueSafe "HKLM:\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters" "SMB1"
if ($null -eq $v) {
$ServerStatus = "FAIL"
Add-Result FAIL "Server registry" "Параметр SMB1 отсутствует: на Windows 7 это ВКЛЮЧЕНО. Задать SMB1 = 0 (DWORD)."
} elseif ([int]$v -eq 0) {
$ServerStatus = "PASS"
Add-Result PASS "Server registry" "LanmanServer\SMB1 = 0. Серверная часть отключена."
} else {
$ServerStatus = "FAIL"
Add-Result FAIL "Server registry" "LanmanServer\SMB1 = $v. SMBv1-сервер включён."
}
}
else {
$ServerStatus = "WARN"
Add-Result WARN "Server" "ОС не поддерживается скриптом (ниже Win7): $($OS.Version). Проверьте вручную."
}
# ============ CLIENT SIDE ============
Add-Section "2. CLIENT SIDE (исходящие SMBv1)"
$ClientStatus = "UNKNOWN"
$drvPath = "HKLM:\SYSTEM\CurrentControlSet\Services\mrxsmb10"
$drvStart = Get-RegistryValueSafe $drvPath "Start"
$drvKeyExists = Test-Path $drvPath
# Фактическое состояние драйвера
$drvRunning = $null
try {
$svc = Get-Service -Name "mrxsmb10" -ErrorAction Stop
$drvRunning = ($svc.Status -eq "Running")
} catch { $drvRunning = $false }
if (-not $drvKeyExists) {
$ClientStatus = "PASS"
Add-Result PASS "Client driver" "Ключ mrxsmb10 отсутствует: компонент удалён, исходящие SMBv1 невозможны."
}
elseif ([int]$drvStart -eq 4) {
if ($drvRunning) {
$ClientStatus = "FAIL"
Add-Result FAIL "Client driver" "Start = 4, но драйвер ЗАГРУЖЕН: отключение применится только после перезагрузки. SMBv1-клиент активен прямо сейчас."
} else {
$ClientStatus = "PASS"
Add-Result PASS "Client driver" "Start = 4 (Disabled), драйвер не загружен."
}
}
else {
$desc = switch ([int]$drvStart) { 2 {"Automatic"} 3 {"Manual"} default {"Start=$drvStart"} }
if ($drvRunning) {
$ClientStatus = "FAIL"
Add-Result FAIL "Client driver" "mrxsmb10: $desc и драйвер ЗАГРУЖЕН. Исходящие SMBv1 активны."
} else {
$ClientStatus = "WARN"
Add-Result WARN "Client driver" "mrxsmb10: $desc (не Disabled), сейчас не загружен, но может стартовать. Требуется Start = 4."
}
}
# DependOnService у LanmanWorkstation: MRxSmb10 там быть не должно
$dep = Get-RegistryValueSafe "HKLM:\SYSTEM\CurrentControlSet\Services\LanmanWorkstation" "DependOnService"
if ($null -ne $dep) {
$depStr = ($dep -join ";")
if (($dep | ForEach-Object { $_.ToString() }) -contains "MRxSmb10") {
if ($ClientStatus -eq "PASS") { $ClientStatus = "WARN" }
Add-Result WARN "Client dependency" "LanmanWorkstation DependOnService содержит MRxSmb10 ($depStr). При отключённом драйвере это ломает сетевой клиент. Убрать: sc.exe config lanmanworkstation depend= bowser/mrxsmb20/nsi"
} else {
Add-Result PASS "Client dependency" "DependOnService без MRxSmb10 ($depStr)."
}
} else {
Add-Result WARN "Client dependency" "Не удалось прочитать DependOnService у LanmanWorkstation."
}
# ============ PENDING REBOOT ============
if (Test-PendingReboot) {
if ($ServerStatus -eq "PASS") { $ServerStatus = "WARN" }
if ($ClientStatus -eq "PASS") { $ClientStatus = "WARN" }
Add-Result WARN "Pending reboot" "Обнаружен ожидающий перезагрузки конфиг. Состояние SMBv1 может не соответствовать реестру до ребута."
}
# ============ PATCHES (только информационно, на итог не влияет) ============
Add-Section "3. INFO: PATCHES (не влияет на итог)"
if ($IsWin7) {
try {
$hf = Get-HotFix -ErrorAction Stop | Where-Object { $_.InstalledOn -ne $null } |
Sort-Object InstalledOn -Descending | Select-Object -First 1
if ($null -ne $hf) {
$d = [datetime]$hf.InstalledOn
if ($d -ge [datetime]"2020-01-14") {
Add-Result WARN "Patches" "Win7 после конца поддержки: последний апдейт $($hf.HotFixID) от $d (ESU?)."
} else {
Add-Result WARN "Patches" "Последний апдейт $($hf.HotFixID) от $d. Для отключения SMBv1 патчи НЕ нужны (SMB1=0 работает и так), но см. MS17-010."
}
} else {
Add-Result WARN "Patches" "Даты установки обновлений не читаются (часто бывает под неполными правами)."
}
} catch {
Add-Result WARN "Patches" "Не удалось получить список обновлений."
}
} else {
[void]$Results.Add("[INFO] $OSCaption — проверка патчей вне области аудита SMBv1.")
}
# ============ FINAL ============
Add-Section "FINAL RESULT"
[void]$Results.Add("Server : $ServerStatus")
[void]$Results.Add("Client : $ClientStatus")
if ($ServerStatus -eq "FAIL" -or $ClientStatus -eq "FAIL" -or $FailCount -gt 0) {
$OverallStatus = "FAIL"
[void]$Results.Add("RESULT: FAIL — SMBv1 активен на клиенте и/или сервере.")
} elseif ($ServerStatus -eq "WARN" -or $ClientStatus -eq "WARN" -or $WarnCount -gt 0) {
$OverallStatus = "PASS_WITH_WARNINGS"
[void]$Results.Add("RESULT: PASS WITH WARNINGS — SMBv1 выключен, есть замечания (ребут/остатки конфигурации).")
} else {
$OverallStatus = "PASS"
[void]$Results.Add("RESULT: PASS — SMBv1 полностью отключён, фактическое состояние подтверждено.")
}
# ============ OUTPUT ============
$statusFile = $ComputerName + "_" + $OverallStatus + ".txt"
$saved = $false
if ($ShareAvailable) {
try {
$Results | Out-File (Join-Path $ResultDirectory $statusFile) -Encoding UTF8 -Force
$saved = $true
# строка в сводный CSV
$csvLine = '"{0}";"{1}";"{2}";"{3}";"{4}";"{5}";"{6}"' -f `
$ComputerName, $DateTime, $OSCaption, $OSBuild, $ServerStatus, $ClientStatus, $OverallStatus
Add-Content -Path $SummaryCsv -Value $csvLine -Encoding UTF8
} catch { $saved = $false }
}
if (-not $saved) {
if (-not (Test-Path $LocalLogDirectory)) { New-Item $LocalLogDirectory -ItemType Directory -Force | Out-Null }
$Results | Out-File (Join-Path $LocalLogDirectory $statusFile) -Encoding UTF8 -Force
}
Write-Host ""
$Results | ForEach-Object { Write-Host $_ }
Write-Host ""
Write-Host "Overall: $OverallStatus"