Загрузка данных
$Server = "RUKLGDC01.pcmarus.loc"
$Stamp = Get-Date -Format "yyyyMMdd_HHmmss"
$RemoteScriptLocal = "C:\Windows\Temp\DHCP_Analysis_$Stamp.ps1"
$RemoteOutLocal = "C:\Windows\Temp\DHCP_Analysis_$Stamp.txt"
$RemoteDoneLocal = "C:\Windows\Temp\DHCP_Analysis_$Stamp.done"
$RemoteScriptUNC = "\\$Server\C$\Windows\Temp\DHCP_Analysis_$Stamp.ps1"
$RemoteOutUNC = "\\$Server\C$\Windows\Temp\DHCP_Analysis_$Stamp.txt"
$RemoteDoneUNC = "\\$Server\C$\Windows\Temp\DHCP_Analysis_$Stamp.done"
$LocalReportDir = "C:\DHCP_Reports"
$LocalReport = Join-Path $LocalReportDir "DHCP_Analysis_$Stamp.txt"
$ScriptBody = @'
$ErrorActionPreference = "Continue"
Import-Module DhcpServer -ErrorAction Stop
$TargetScopes = @(
"10.182.150.0",
"10.182.151.0",
"10.182.152.0",
"10.182.153.0",
"10.182.154.0",
"10.182.155.0"
)
& {
Write-Output "============================================================"
Write-Output " DHCP DIAGNOSTIC ANALYSIS"
Write-Output "============================================================"
Write-Output "Server: $env:COMPUTERNAME"
Write-Output "Date: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"
Write-Output "Mode: READ ONLY"
Write-Output "`n=== DHCP SERVICE ==="
Get-Service DHCPServer |
Select-Object Name,Status,StartType |
Format-List
Write-Output "`n=== TARGET SCOPE CONFIGURATION ==="
foreach ($ScopeId in $TargetScopes) {
Get-DhcpServerv4Scope -ScopeId $ScopeId -ErrorAction SilentlyContinue |
Select-Object ScopeId,Name,State,StartRange,EndRange,
SubnetMask,LeaseDuration |
Format-List
}
Write-Output "`n=== TARGET SCOPE STATISTICS ==="
foreach ($ScopeId in $TargetScopes) {
Get-DhcpServerv4ScopeStatistics `
-ScopeId $ScopeId `
-ErrorAction SilentlyContinue |
Select-Object ScopeId,PercentageInUse,InUse,Free,Reserved,Pending |
Format-List
}
Write-Output "`n=== COLLECTING ACTIVE LEASES ==="
$AllLeases = foreach ($ScopeId in $TargetScopes) {
Get-DhcpServerv4Lease `
-ScopeId $ScopeId `
-AllLeases `
-ErrorAction SilentlyContinue |
Select-Object @{
Name = "ScopeId"
Expression = {$ScopeId}
},
IPAddress,
HostName,
ClientId,
AddressState,
LeaseExpiryTime
}
Write-Output "Total leases collected: $($AllLeases.Count)"
$ActiveLeases = $AllLeases |
Where-Object {
$_.AddressState -eq "Active"
}
Write-Output "Active leases collected: $($ActiveLeases.Count)"
Write-Output "`n=== DUPLICATE CLIENT ID INSIDE THE SAME SCOPE ==="
$DuplicatesSameScope = $ActiveLeases |
Where-Object {$_.ClientId} |
Group-Object ScopeId,ClientId |
Where-Object {$_.Count -gt 1}
if ($DuplicatesSameScope) {
foreach ($Group in $DuplicatesSameScope) {
Write-Output "`nDuplicate group: $($Group.Name)"
Write-Output "Lease count: $($Group.Count)"
$Group.Group |
Sort-Object IPAddress |
Format-Table ScopeId,IPAddress,HostName,ClientId,
AddressState,LeaseExpiryTime -AutoSize
}
}
else {
Write-Output "No active duplicate ClientId values inside one scope were found."
}
Write-Output "`n=== CLIENT ID PRESENT IN MULTIPLE SCOPES ==="
$DuplicatesAcrossScopes = $ActiveLeases |
Where-Object {$_.ClientId} |
Group-Object ClientId |
Where-Object {
($_.Group.ScopeId | Sort-Object -Unique).Count -gt 1
}
if ($DuplicatesAcrossScopes) {
foreach ($Group in $DuplicatesAcrossScopes) {
Write-Output "`nClientId: $($Group.Name)"
Write-Output "Scopes: $(
($Group.Group.ScopeId | Sort-Object -Unique) -join ', '
)"
$Group.Group |
Sort-Object ScopeId,IPAddress |
Format-Table ScopeId,IPAddress,HostName,ClientId,
AddressState,LeaseExpiryTime -AutoSize
}
}
else {
Write-Output "No ClientId values occurring in multiple scopes were found."
}
Write-Output "`n=== SAME HOSTNAME WITH DIFFERENT CLIENT ID VALUES ==="
$HostNameDuplicates = $ActiveLeases |
Where-Object {
$_.HostName -and
$_.HostName.Trim() -ne ""
} |
Group-Object HostName |
Where-Object {
($_.Group.ClientId | Sort-Object -Unique).Count -gt 1
}
if ($HostNameDuplicates) {
foreach ($Group in $HostNameDuplicates) {
Write-Output "`nHostName: $($Group.Name)"
Write-Output "ClientId count: $(
($Group.Group.ClientId | Sort-Object -Unique).Count
)"
$Group.Group |
Sort-Object ScopeId,IPAddress |
Format-Table ScopeId,IPAddress,HostName,ClientId,
AddressState,LeaseExpiryTime -AutoSize
}
}
else {
Write-Output "No hostnames with multiple ClientId values were found."
}
Write-Output "`n=== SAME HOSTNAME PRESENT IN MULTIPLE SCOPES ==="
$HostNamesAcrossScopes = $ActiveLeases |
Where-Object {
$_.HostName -and
$_.HostName.Trim() -ne ""
} |
Group-Object HostName |
Where-Object {
($_.Group.ScopeId | Sort-Object -Unique).Count -gt 1
}
if ($HostNamesAcrossScopes) {
foreach ($Group in $HostNamesAcrossScopes) {
Write-Output "`nHostName: $($Group.Name)"
Write-Output "Scopes: $(
($Group.Group.ScopeId | Sort-Object -Unique) -join ', '
)"
$Group.Group |
Sort-Object ScopeId,IPAddress |
Format-Table ScopeId,IPAddress,ClientId,
AddressState,LeaseExpiryTime -AutoSize
}
}
else {
Write-Output "No hostnames occurring in multiple scopes were found."
}
Write-Output "`n=== LEASES WITHOUT HOSTNAME ==="
$NoHostName = $ActiveLeases |
Where-Object {
-not $_.HostName -or
$_.HostName.Trim() -eq ""
}
$NoHostName |
Group-Object ScopeId |
Select-Object Name,Count |
Format-Table -AutoSize
Write-Output "`n=== DHCP OPTIONS FOR TARGET SCOPES ==="
foreach ($ScopeId in $TargetScopes) {
Write-Output "`nScope: $ScopeId"
Get-DhcpServerv4OptionValue `
-ScopeId $ScopeId `
-ErrorAction SilentlyContinue |
Format-Table OptionId,Name,Value -AutoSize
}
Write-Output "`n=== EXCLUSION RANGES ==="
foreach ($ScopeId in $TargetScopes) {
Write-Output "`nScope: $ScopeId"
$Exclusions = Get-DhcpServerv4ExclusionRange `
-ScopeId $ScopeId `
-ErrorAction SilentlyContinue
if ($Exclusions) {
$Exclusions |
Format-Table ScopeId,StartRange,EndRange -AutoSize
}
else {
Write-Output "No exclusions configured."
}
}
Write-Output "`n=== RESERVATIONS ==="
foreach ($ScopeId in $TargetScopes) {
Write-Output "`nScope: $ScopeId"
$Reservations = Get-DhcpServerv4Reservation `
-ScopeId $ScopeId `
-ErrorAction SilentlyContinue
if ($Reservations) {
$Reservations |
Format-Table ScopeId,IPAddress,ClientId,Name,Description -AutoSize
}
else {
Write-Output "No reservations configured."
}
}
Write-Output "`n=== DHCP ADMIN EVENTS FOR LAST 7 DAYS ==="
$StartTime = (Get-Date).AddDays(-7)
$Events = Get-WinEvent -FilterHashtable @{
LogName = "DhcpAdminEvents"
StartTime = $StartTime
} -ErrorAction SilentlyContinue |
Where-Object {
$_.Level -in 1,2,3
} |
Select-Object -First 300 TimeCreated,Id,LevelDisplayName,Message
if ($Events) {
Write-Output "`nEvent summary:"
$Events |
Group-Object Id |
Sort-Object Count -Descending |
Select-Object Name,Count |
Format-Table -AutoSize
Write-Output "`nLatest events:"
$Events |
Select-Object -First 100 |
Format-List
}
else {
Write-Output "No errors or warnings were found."
}
Write-Output "`n=== EVENT 20287 SUMMARY BY SCOPE ==="
$PoolErrors = Get-WinEvent -FilterHashtable @{
LogName = "DhcpAdminEvents"
Id = 20287
StartTime = $StartTime
} -ErrorAction SilentlyContinue
if ($PoolErrors) {
$ScopeNames = foreach ($Event in $PoolErrors) {
if ($Event.Message -match "scope/superscope\s+([^\s]+)") {
$Matches[1]
}
else {
"Unknown"
}
}
$ScopeNames |
Group-Object |
Sort-Object Count -Descending |
Select-Object Name,Count |
Format-Table -AutoSize
}
else {
Write-Output "Event 20287 was not found during the selected period."
}
Write-Output "`n=== CONCLUSION MARKERS ==="
Write-Output "Duplicate ClientId in same scope: $($DuplicatesSameScope.Count)"
Write-Output "ClientId in multiple scopes: $($DuplicatesAcrossScopes.Count)"
Write-Output "Hostname with different ClientId: $($HostNameDuplicates.Count)"
Write-Output "Hostname in multiple scopes: $($HostNamesAcrossScopes.Count)"
Write-Output "Active leases without hostname: $($NoHostName.Count)"
Write-Output "`nDIAGNOSTIC COLLECTION COMPLETED"
} 2>&1 |
Out-String -Width 400 |
Set-Content -LiteralPath "__OUT__" -Encoding UTF8
New-Item -ItemType File -Path "__DONE__" -Force | Out-Null
'@
$ScriptBody = $ScriptBody.Replace("__OUT__", $RemoteOutLocal)
$ScriptBody = $ScriptBody.Replace("__DONE__", $RemoteDoneLocal)
try {
New-Item -ItemType Directory -Path $LocalReportDir -Force |
Out-Null
Write-Host "Проверка доступа к DHCP-серверу..." -ForegroundColor Cyan
if (-not (Test-Path "\\$Server\C$")) {
throw "Нет доступа к административной шаре \\$Server\C$"
}
Write-Host "Копирование диагностического скрипта..." -ForegroundColor Cyan
Set-Content `
-LiteralPath $RemoteScriptUNC `
-Value $ScriptBody `
-Encoding UTF8 `
-Force
$CommandLine = "powershell.exe -NoProfile -NonInteractive " +
"-ExecutionPolicy Bypass -File `"$RemoteScriptLocal`""
Write-Host "Запуск диагностики на $Server..." -ForegroundColor Cyan
$ProcessClass = [wmiclass]"\\$Server\root\cimv2:Win32_Process"
$Result = $ProcessClass.Create($CommandLine)
if ($Result.ReturnValue -ne 0) {
throw "Не удалось запустить процесс. WMI ReturnValue: $($Result.ReturnValue)"
}
Write-Host "Процесс запущен. PID: $($Result.ProcessId)" -ForegroundColor Green
$Deadline = (Get-Date).AddMinutes(5)
while (
-not (Test-Path $RemoteDoneUNC) -and
(Get-Date) -lt $Deadline
) {
Start-Sleep -Seconds 2
}
if (-not (Test-Path $RemoteDoneUNC)) {
throw "Диагностика не завершилась за 5 минут."
}
Copy-Item `
-LiteralPath $RemoteOutUNC `
-Destination $LocalReport `
-Force
Write-Host "`nДиагностика завершена." -ForegroundColor Green
Write-Host "Отчёт сохранён: $LocalReport" -ForegroundColor Green
Write-Host "`n=== КРАТКИЙ ВЫВОД ИЗ ОТЧЁТА ===`n" -ForegroundColor Cyan
Get-Content $LocalReport |
Select-String -Pattern `
"Duplicate ClientId in same scope",
"ClientId in multiple scopes",
"Hostname with different ClientId",
"Hostname in multiple scopes",
"Active leases without hostname",
"DIAGNOSTIC COLLECTION COMPLETED"
}
catch {
Write-Host "Ошибка: $($_.Exception.Message)" -ForegroundColor Red
if (Test-Path $RemoteOutUNC) {
Copy-Item `
-LiteralPath $RemoteOutUNC `
-Destination $LocalReport `
-Force `
-ErrorAction SilentlyContinue
Write-Host "Частичный отчёт сохранён: $LocalReport" -ForegroundColor Yellow
}
}
finally {
Remove-Item $RemoteScriptUNC -Force -ErrorAction SilentlyContinue
Remove-Item $RemoteOutUNC -Force -ErrorAction SilentlyContinue
Remove-Item $RemoteDoneUNC -Force -ErrorAction SilentlyContinue
}