Initial commit
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
# 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
|
||||
}
|
||||
Reference in New Issue
Block a user