CH-J Server Managerspráva serverů přes SSH
Menu
Vydané zdroje

CH-J Server Manager

Procházejte adresáře a soubory konkrétního vydání aplikace.

Stáhnout zdroje ZIP
CH-J / Server Manager 368 souborů
core-20261017T201717Z-057348c4a70f Přidáno: Datum není evidováno · Sestaveno:
windowsMetrics.js Přidáno: Datum není evidováno 13.0 KB · 179 řádků
Kód Stáhnout soubor
1"use strict";
3// Windows system metrics for chj.system-monitor (Windows 11, Windows Server incl. Server Core).
4// Runs one fixed PowerShell script per refresh through the existing SSH session. .NET and the registry
5// are the primary sources (they also work for standard accounts, which are often denied WMI/CIM over SSH);
6// CIM performance classes add details when permitted. Values Windows does not provide are null, never 0.
7const METRICS_SCRIPT = String.raw`param([string]$ArgsJson)
8$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue'
9$A = $ArgsJson | ConvertFrom-Json
10$out = [ordered]@{ errors = @() }
11function Try-Cim([string]$Class, [string]$Filter) {
12 try { if ($Filter) { return @(Get-CimInstance -ClassName $Class -Filter $Filter -ErrorAction Stop) } else { return @(Get-CimInstance -ClassName $Class -ErrorAction Stop) } }
13 catch { $script:out.errors += "$($Class): $($_.Exception.Message)"; return $null }
15if ($A.static) {
16 $nt = Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' -ErrorAction SilentlyContinue
17 $cpuKey = Get-ItemProperty 'HKLM:\HARDWARE\DESCRIPTION\System\CentralProcessor\0' -ErrorAction SilentlyContinue
18 $static = [ordered]@{ caption = [string]$nt.ProductName; build = [string]$nt.CurrentBuildNumber; ubr = [string]$nt.UBR; displayVersion = [string]$nt.DisplayVersion
19 installationType = [string]$nt.InstallationType; hostname = [Environment]::MachineName; architecture = [string]$env:PROCESSOR_ARCHITECTURE
20 cpuModel = ([string]$cpuKey.ProcessorNameString).Trim(); logical = [Environment]::ProcessorCount; physical = $null; sockets = $null; memoryTotal = $null }
21 $os = Try-Cim 'Win32_OperatingSystem'
22 if ($os) { $static.caption = [string]$os[0].Caption; $static.memoryTotal = [double]$os[0].TotalVisibleMemorySize * 1024 }
23 $cpu = Try-Cim 'Win32_Processor'
24 if ($cpu) { $static.sockets = $cpu.Count; $static.physical = [int](($cpu | Measure-Object -Property NumberOfCores -Sum).Sum); $static.logical = [int](($cpu | Measure-Object -Property NumberOfLogicalProcessors -Sum).Sum) }
25 if (-not $static.memoryTotal) { try { Add-Type -AssemblyName Microsoft.VisualBasic; $static.memoryTotal = [double](New-Object Microsoft.VisualBasic.Devices.ComputerInfo).TotalPhysicalMemory } catch { $out.errors += "ComputerInfo: $($_.Exception.Message)" } }
26 $out.static = $static
28# Uptime: CIM boot time, otherwise the monotonic performance counter since boot.
29$out.uptimeSeconds = $null
30$os = Try-Cim 'Win32_OperatingSystem'
31if ($os) {
32 $out.uptimeSeconds = [math]::Floor(((Get-Date) - $os[0].LastBootUpTime).TotalSeconds)
33 $out.memoryTotal = [double]$os[0].TotalVisibleMemorySize * 1024; $out.memoryAvailable = [double]$os[0].FreePhysicalMemory * 1024
34} else {
35 $out.uptimeSeconds = [math]::Floor([Diagnostics.Stopwatch]::GetTimestamp() / [Diagnostics.Stopwatch]::Frequency)
36 try { Add-Type -AssemblyName Microsoft.VisualBasic; $ci = New-Object Microsoft.VisualBasic.Devices.ComputerInfo; $out.memoryTotal = [double]$ci.TotalPhysicalMemory; $out.memoryAvailable = [double]$ci.AvailablePhysicalMemory } catch { $out.errors += "ComputerInfo: $($_.Exception.Message)" }
38# Raw CPU counter; Core computes the usage from the difference between two refreshes.
39$cpu = Try-Cim 'Win32_PerfRawData_PerfOS_Processor' "Name='_Total'"
40if ($cpu) { $out.cpuRaw = [ordered]@{ busyInverse = [string]$cpu[0].PercentProcessorTime; time = [string]$cpu[0].Timestamp_Sys100NS } }
41$system = Try-Cim 'Win32_PerfRawData_PerfOS_System'
42if ($system) { $out.processorQueueLength = [int]$system[0].ProcessorQueueLength; $out.processes = [int]$system[0].Processes }
43# Physical memory lists (gauges, no second sample needed).
44$memory = Try-Cim 'Win32_PerfRawData_PerfOS_Memory'
45if ($memory) {
46 $m = $memory[0]
47 $out.memoryCounters = [ordered]@{ available = [double]$m.AvailableBytes; cache = [double]$m.CacheBytes; systemCacheResident = [double]$m.SystemCacheResidentBytes
48 standbyCore = [double]$m.StandbyCacheCoreBytes; standbyNormal = [double]$m.StandbyCacheNormalPriorityBytes; standbyReserve = [double]$m.StandbyCacheReserveBytes
49 modified = [double]$m.ModifiedPageListBytes; freeZero = [double]$m.FreeAndZeroPageListBytes; committed = [double]$m.CommittedBytes; commitLimit = [double]$m.CommitLimit
50 poolPaged = [double]$m.PoolPagedResidentBytes; poolNonpaged = [double]$m.PoolNonpagedBytes; systemCode = [double]$m.SystemCodeResidentBytes; systemDriver = [double]$m.SystemDriverResidentBytes
51 pagesInput = [string]$m.PagesInputPersec; pagesOutput = [string]$m.PagesOutputPersec; time = [string]$m.Timestamp_Sys100NS; frequency = [string]$m.Frequency_Sys100NS }
53# Pagefiles: allocated size, current and peak usage (MB as reported by Windows).
54$usage = Try-Cim 'Win32_PageFileUsage'
55if ($null -ne $usage) { $out.pagefiles = @($usage | ForEach-Object { [ordered]@{ name = [string]$_.Name; allocatedMb = [double]$_.AllocatedBaseSize; currentMb = [double]$_.CurrentUsage; peakMb = [double]$_.PeakUsage; temporary = [bool]$_.TempPageFile } }) }
56# Fixed disks through .NET (no WMI rights required).
57$out.disks = @([IO.DriveInfo]::GetDrives() | Where-Object { $_.DriveType -eq 'Fixed' -and $_.IsReady } | ForEach-Object { [ordered]@{ name = $_.Name.TrimEnd('\'); total = [double]$_.TotalSize; available = [double]$_.AvailableFreeSpace; free = [double]$_.TotalFreeSpace; format = [string]$_.DriveFormat; label = [string]$_.VolumeLabel } })
58$out.systemDrive = [string]$env:SystemDrive
59# Network adapters through .NET: status, MAC, unicast addresses and cumulative byte counters.
60$adapters = @()
61foreach ($nic in [Net.NetworkInformation.NetworkInterface]::GetAllNetworkInterfaces()) {
62 if ($nic.NetworkInterfaceType -in @('Loopback', 'Tunnel')) { continue }
63 $props = $nic.GetIPProperties()
64 $stats = $null; try { $stats = $nic.GetIPStatistics() } catch {}
65 $addresses = @($props.UnicastAddresses | Where-Object { -not $_.Address.IsIPv6LinkLocal } | ForEach-Object { "$($_.Address.IPAddressToString)/$($_.PrefixLength)" })
66 $mac = ($nic.GetPhysicalAddress().GetAddressBytes() | ForEach-Object { $_.ToString('x2') }) -join ':'
67 $adapters += [ordered]@{ name = $nic.Name; description = $nic.Description; state = [string]$nic.OperationalStatus; mac = $mac; speed = [double]$nic.Speed
68 rx = $(if ($stats) { [double]$stats.BytesReceived } else { $null }); tx = $(if ($stats) { [double]$stats.BytesSent } else { $null })
69 rxPackets = $(if ($stats) { [double]$stats.UnicastPacketsReceived + [double]$stats.NonUnicastPacketsReceived } else { $null })
70 txPackets = $(if ($stats) { [double]$stats.UnicastPacketsSent + [double]$stats.NonUnicastPacketsSent } else { $null })
71 addresses = $addresses; gateway = [bool](@($props.GatewayAddresses | Where-Object { $_.Address.ToString() -notin @('0.0.0.0', '::') }).Count) }
73$out.adapters = $adapters
74[Console]::Out.WriteLine('CHJ_RESULT:' + [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes((ConvertTo-Json -InputObject $out -Depth 6 -Compress))))
75`;
77const finite = (value) => {
78 if (value === null || value === undefined || value === "") return null;
79 const number = Number(value);
80 return Number.isFinite(number) ? number : null;
81};
82const text = (value, limit = 240) => String(value ?? "").replace(/[\x00-\x1f\x7f]/g, " ").trim().slice(0, limit);
84function cpuUsage(previous, current) {
85 if (!previous || !current) return null;
86 const busy = Number(BigInt(current.busyInverse) - BigInt(previous.busyInverse));
87 const time = Number(BigInt(current.time) - BigInt(previous.time));
88 if (!(time > 0)) return null;
89 // PERF_100NSEC_TIMER_INV: the counter measures idle time; usage = 1 - delta(idle) / delta(time).
90 return Math.max(0, Math.min(100, (1 - busy / time) * 100));
93function rate(previous, current, key) {
94 if (!previous || !current || !current.frequency) return null;
95 const count = Number(BigInt(current[key]) - BigInt(previous[key]));
96 const seconds = Number(BigInt(current.time) - BigInt(previous.time)) / Number(current.frequency);
97 return seconds > 0 && count >= 0 ? count / seconds : null;
100// Normalizes the script output into the shared metrics structure. state keeps the previous raw samples.
101function normalizeWindowsMetrics(raw, staticInfo, state = {}, fallbackHostname = "unknown") {
102 const s = staticInfo || {};
103 const total = finite(raw.memoryTotal) ?? finite(s.memoryTotal);
104 const available = finite(raw.memoryAvailable);
105 const counters = raw.memoryCounters || null;
106 const usage = cpuUsage(state.cpuRaw, raw.cpuRaw);
107 const pagefiles = Array.isArray(raw.pagefiles) ? raw.pagefiles.map((file) => ({
108 name: text(file.name, 260), allocated: finite(file.allocatedMb) === null ? null : file.allocatedMb * 1048576,
109 used: finite(file.currentMb) === null ? null : file.currentMb * 1048576, peak: finite(file.peakMb) === null ? null : file.peakMb * 1048576, temporary: file.temporary === true
110 })) : null;
111 const pageTotal = pagefiles ? pagefiles.reduce((sum, file) => sum + (file.allocated || 0), 0) : null;
112 const pageUsed = pagefiles ? pagefiles.reduce((sum, file) => sum + (file.used || 0), 0) : null;
113 const disks = (raw.disks || []).map((disk) => ({ name: text(disk.name, 16), total: finite(disk.total), available: finite(disk.available), used: finite(disk.total) !== null && finite(disk.free) !== null ? disk.total - disk.free : null, format: text(disk.format, 16), label: text(disk.label, 64) }));
114 const systemDrive = disks.find((disk) => disk.name.toLowerCase() === String(raw.systemDrive || "C:").toLowerCase()) || disks[0] || null;
115 const adapters = (raw.adapters || []).slice(0, 64);
116 const defaultAdapter = adapters.find((adapter) => adapter.gateway && adapter.state === "Up");
117 let memoryDetail = null;
118 if (counters && total) {
119 const standby = (counters.standbyCore || 0) + (counters.standbyNormal || 0) + (counters.standbyReserve || 0);
120 const inUse = Math.max(0, total - counters.available - counters.modified);
121 memoryDetail = {
122 source: "Win32_PerfRawData_PerfOS_Memory",
123 // Non-overlapping physical pages: in use + modified + standby + free/zero ~= total.
124 slices: { inUse, modified: counters.modified, standby, free: counters.freeZero },
125 available: counters.available,
126 systemCache: counters.systemCacheResident,
127 cacheBytes: counters.cache,
128 kernel: { pagedPool: counters.poolPaged, nonpagedPool: counters.poolNonpaged, systemCode: counters.systemCode, systemDriver: counters.systemDriver },
129 commit: { committed: counters.committed, limit: counters.commitLimit },
130 paging: { pagesInPerSecond: rate(state.memoryCounters, counters, "pagesInput"), pagesOutPerSecond: rate(state.memoryCounters, counters, "pagesOutput") }
131 };
132 }
133 return {
134 os: "windows",
135 platform: "Windows",
136 kernel: [s.build ? `build ${s.build}${s.ubr ? `.${s.ubr}` : ""}` : "", text(s.displayVersion, 20)].filter(Boolean).join(" ") || null,
137 osName: text(s.caption, 120) || null,
138 installationType: text(s.installationType, 40) || null,
139 hostname: text(s.hostname, 120) || fallbackHostname,
140 uptimeSeconds: finite(raw.uptimeSeconds),
141 load1: null,
142 loadAverageSupported: false,
143 processorQueueLength: finite(raw.processorQueueLength),
144 processes: finite(raw.processes),
145 memory: { total, available },
146 memoryDetail,
147 swap: { kind: "pagefile", total: pageTotal, used: pageUsed, free: pageTotal !== null && pageUsed !== null ? Math.max(0, pageTotal - pageUsed) : null },
148 pagefiles,
149 disk: systemDrive ? { mount: systemDrive.name, total: systemDrive.total, used: systemDrive.used, available: systemDrive.available } : { mount: null, total: null, used: null, available: null },
150 disks,
151 cpu: {
152 usagePercent: usage,
153 usagePending: usage === null && Boolean(raw.cpuRaw),
154 architecture: text(s.architecture, 32) || null,
155 model: text(s.cpuModel, 160) || null,
156 logicalCores: finite(s.logical),
157 physicalCores: finite(s.physical),
158 sockets: finite(s.sockets),
159 coreTypes: []
160 },
161 network: {
162 defaultInterface: defaultAdapter ? text(defaultAdapter.name, 64) : "",
163 interfaces: adapters.map((adapter) => {
164 // Some virtual NIC drivers (e.g. emulated Intel PRO/1000) report 0 octets while packets flow.
165 const bytesReported = !(finite(adapter.rx) === 0 && finite(adapter.tx) === 0 && (finite(adapter.rxPackets) > 0 || finite(adapter.txPackets) > 0));
166 return {
167 name: text(adapter.name, 64), description: text(adapter.description, 120), state: adapter.state === "Up" ? "up" : text(adapter.state, 24).toLowerCase(),
168 mac: text(adapter.mac, 64), rxBytes: bytesReported ? finite(adapter.rx) : null, txBytes: bytesReported ? finite(adapter.tx) : null,
169 rxPackets: finite(adapter.rxPackets), txPackets: finite(adapter.txPackets), bytesUnavailableReason: bytesReported ? null : "The network driver does not report transferred bytes (packets are counted).",
170 speedBitsPerSecond: finite(adapter.speed) > 0 ? adapter.speed : null,
171 addresses: (adapter.addresses || []).slice(0, 16).map((address) => text(address, 64)), isDefault: adapter === defaultAdapter
172 };
173 })
174 },
175 unavailable: (raw.errors || []).slice(0, 10).map((entry) => text(entry, 200))
176 };
179module.exports = { METRICS_SCRIPT, cpuUsage, normalizeWindowsMetrics };
SHA-256eee1e394b81111803210edebadebd62ebaf5d152348489b3d0b83ad5d1b19eab

CH-J Proprietary Software License 1.14 · Zdroje jsou zveřejněny pod CH-J Proprietary Software License 1.14. Jejich dostupnost nemění licenční podmínky ani neposkytuje další oprávnění.

SHA-256 archivucf4455b698f0f28e456a37b1834976a0194d8486acb7101052d59a838745cca3
Soubory