105 lines
6.3 KiB
PowerShell
105 lines
6.3 KiB
PowerShell
|
|
# VDI Performance, EDR Overhead & Hang Monitor
|
||
|
|
$BackendUrl = "http://127.0.0.1:8081/api/metrics" # 서버 IP로 변경
|
||
|
|
$Hostname = $env:COMPUTERNAME
|
||
|
|
|
||
|
|
$StartTime = Get-Date
|
||
|
|
$EndTime = $StartTime.AddHours(14)
|
||
|
|
Write-Host "Monitoring started for $Hostname. Will auto-terminate at $EndTime."
|
||
|
|
|
||
|
|
$EtwCooldown = $null
|
||
|
|
rm "monitor.ps1"
|
||
|
|
while ((Get-Date) -lt $EndTime) {
|
||
|
|
try {
|
||
|
|
$ShouldSend = $false
|
||
|
|
|
||
|
|
# 2. CPU & 커널 레벨(DPC/Interrupt)
|
||
|
|
$CpuTotal = Get-WmiObject Win32_Processor | Measure-Object -Property LoadPercentage -Average | Select-Object -ExpandProperty Average
|
||
|
|
if ($null -eq $CpuTotal) { $CpuTotal = 0 }
|
||
|
|
if ($CpuTotal -gt 70) { $ShouldSend = $true } # CPU 70% 조건
|
||
|
|
|
||
|
|
$DpcCounter = Get-Counter '\Processor(_Total)\% DPC Time' -ErrorAction SilentlyContinue
|
||
|
|
$IntCounter = Get-Counter '\Processor(_Total)\% Interrupt Time' -ErrorAction SilentlyContinue
|
||
|
|
$DpcInterrupt = 0
|
||
|
|
if ($DpcCounter -and $IntCounter) {
|
||
|
|
$DpcInterrupt = [math]::Round($DpcCounter.CounterSamples.CookedValue + $IntCounter.CounterSamples.CookedValue, 2)
|
||
|
|
}
|
||
|
|
if ($DpcInterrupt -gt 3.0) { $ShouldSend = $true } # 커널 부하 3% 조건
|
||
|
|
|
||
|
|
# 3. 메모리
|
||
|
|
$Mem = Get-WmiObject Win32_OperatingSystem
|
||
|
|
$MemUsage = [math]::Round((($Mem.TotalVisibleMemorySize - $Mem.FreePhysicalMemory) / $Mem.TotalVisibleMemorySize) * 100, 2)
|
||
|
|
if ($MemUsage -gt 80) { $ShouldSend = $true } # 메모리 80% 조건
|
||
|
|
|
||
|
|
# 4. 프로세스 성능 (관측용 시스템 프로세스 제외 - Observer Effect 방지 및 #1, #2 인스턴스 꼬리표 처리)
|
||
|
|
$IgnoreRegex = "^(_total|idle|taskmgr|wmiprvse|powershell|pwsh|dwm)(#\d+)?$"
|
||
|
|
$ProcessPerf = Get-WmiObject Win32_PerfFormattedData_PerfProc_Process -ErrorAction SilentlyContinue | Where-Object { $_.Name -notmatch $IgnoreRegex }
|
||
|
|
|
||
|
|
$TopCpuRaw = $ProcessPerf | Sort-Object PercentProcessorTime -Descending | Select-Object -First 5
|
||
|
|
$TopIoRaw = $ProcessPerf | Sort-Object IODataBytesPersec -Descending | Select-Object -First 5
|
||
|
|
|
||
|
|
# [물증 확보] 3대 보안 솔루션(V3, 소만사, 지니언스)은 순위와 상관없이 자원 사용 시 강제 수집
|
||
|
|
$SecRegex = "^(v3svc|asdsvc|v3main|v3lite|privacyi|piagent|ngm|corebguard|gncsensor|gsagent|gsprotect|gsview|gsflow)"
|
||
|
|
$SecCpuRaw = $ProcessPerf | Where-Object { $_.Name -match $SecRegex -and $_.PercentProcessorTime -gt 0 }
|
||
|
|
$SecIoRaw = $ProcessPerf | Where-Object { $_.Name -match $SecRegex -and $_.IODataBytesPersec -gt 0 }
|
||
|
|
|
||
|
|
$TopCpu = $TopCpuRaw + $SecCpuRaw | Sort-Object IDProcess -Unique | Select-Object @{Name="ProcessName";Expression={$_.Name}}, @{Name="PID";Expression={$_.IDProcess}}, @{Name="CPU_Percent";Expression={$_.PercentProcessorTime}}, @{Name="Kernel_CPU_Percent";Expression={$_.PercentPrivilegedTime}}
|
||
|
|
$TopIo = $TopIoRaw + $SecIoRaw | Sort-Object IDProcess -Unique | Select-Object @{Name="ProcessName";Expression={$_.Name}}, @{Name="PID";Expression={$_.IDProcess}}, IODataBytesPersec
|
||
|
|
|
||
|
|
if ($TopIo[0].IODataBytesPersec -gt 5242880) { $ShouldSend = $true } # I/O 5MB/s 조건
|
||
|
|
|
||
|
|
$TopMem = Get-Process | Sort-Object WorkingSet -Descending | Select-Object -First 5 | Select-Object @{Name="ProcessName";Expression={$_.Name}}, @{Name="PID";Expression={$_.Id}}, @{Name="WorkingSetMB";Expression={[math]::Round($_.WorkingSet / 1MB, 2)}}
|
||
|
|
|
||
|
|
# 5. Hang 프로세스
|
||
|
|
$HungProcs = Get-Process -ErrorAction SilentlyContinue | Where-Object { $_.MainWindowHandle -ne 0 -and $_.Responding -eq $false -and $_.Name -notmatch $IgnoreRegex } | Select-Object @{Name="ProcessName";Expression={$_.Name}}, @{Name="PID";Expression={$_.Id}}
|
||
|
|
if ($null -eq $HungProcs) { $HungProcs = @() }
|
||
|
|
if ($HungProcs.Count -gt 0) { $ShouldSend = $true }
|
||
|
|
|
||
|
|
# 6. ETW 자동 트리거 (커널 병목 5% 초과 발생 시)
|
||
|
|
if ($DpcInterrupt -gt 5.0) {
|
||
|
|
if ($null -eq $EtwCooldown -or (Get-Date) -gt $EtwCooldown) {
|
||
|
|
if (-not (Test-Path "C:\temp")) { New-Item -ItemType Directory -Force -Path "C:\temp" | Out-Null }
|
||
|
|
Start-Process -FilePath "wpr.exe" -ArgumentList "-start GeneralProfile" -WindowStyle Hidden -Wait
|
||
|
|
Start-Sleep -Seconds 10
|
||
|
|
|
||
|
|
$Timestamp = (Get-Date).ToString("yyyyMMdd_HHmmss")
|
||
|
|
$EtlPath = "C:\temp\Trace_$Timestamp.etl"
|
||
|
|
Start-Process -FilePath "wpr.exe" -ArgumentList "-stop $EtlPath" -WindowStyle Hidden -Wait
|
||
|
|
Write-Host "ETW Trace saved to $EtlPath"
|
||
|
|
|
||
|
|
$EtwCooldown = (Get-Date).AddMinutes(15)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# 7. 이상 데이터 전송
|
||
|
|
if ($ShouldSend) {
|
||
|
|
# 프로세스별 I/O (네트워크+디스크) 해시테이블 생성 (빠른 매핑용)
|
||
|
|
$IoDict = @{}
|
||
|
|
foreach ($p in $ProcessPerf) { $IoDict[$p.IDProcess] = $p.IODataBytesPersec }
|
||
|
|
|
||
|
|
# 네트워크 연결 목록에 프로세스별 총 I/O 대역폭 병합 후 부하가 큰 순으로 정렬
|
||
|
|
$NetConnections = Get-NetTCPConnection -State Established -ErrorAction SilentlyContinue |
|
||
|
|
Select-Object LocalAddress, LocalPort, RemoteAddress, RemotePort,
|
||
|
|
@{Name="ProcessName";Expression={(Get-Process -Id $_.OwningProcess -ErrorAction SilentlyContinue).Name}},
|
||
|
|
@{Name="PID";Expression={$_.OwningProcess}},
|
||
|
|
@{Name="IO_BytesPerSec";Expression={ if ($IoDict.ContainsKey($_.OwningProcess)) { $IoDict[$_.OwningProcess] } else { 0 } }} |
|
||
|
|
Where-Object ProcessName -ne $null | Sort-Object IO_BytesPerSec -Descending
|
||
|
|
|
||
|
|
$Payload = @{
|
||
|
|
hostname = $Hostname
|
||
|
|
total_cpu_percent = $CpuTotal
|
||
|
|
total_mem_percent = $MemUsage
|
||
|
|
dpc_interrupt_percent = $DpcInterrupt
|
||
|
|
top_cpu_processes = $TopCpu
|
||
|
|
top_mem_processes = $TopMem
|
||
|
|
top_io_processes = $TopIo
|
||
|
|
network_connections = $NetConnections
|
||
|
|
hung_processes = $HungProcs
|
||
|
|
} | ConvertTo-Json -Depth 4
|
||
|
|
|
||
|
|
Invoke-RestMethod -Uri $BackendUrl -Method Post -Body $Payload -ContentType "application/json" -ErrorAction SilentlyContinue
|
||
|
|
}
|
||
|
|
} catch { }
|
||
|
|
|
||
|
|
Start-Sleep -Seconds 60
|
||
|
|
}
|