Presence, AD/SCCM/DNS reasons, monitors, snapshots, new-device priority

Worker: pings every tracked device on a presence sweep (hourly in business
hours plus midnight) and records last online; inventory reports whether a
device was found in AD and SCCM; monitors from WmiMonitorID; snapshots of
the last reachable state replace "Cached"; newly tracked devices are swept
and published first; totals count source devices only; per-type timing in
Worker-State.

Front end: details dialog shows presence, reasons instead of N/A,
"Waiting for worker...", monitors and snapshot times, and refreshes in
place; Custom View gains Days Offline, Last Online, Found In and monitor
columns; manual pair changes show immediately; sync dialog shows timing by
type. Custom View gets a large scrollbar; "Exactly ticked" filter.
This commit is contained in:
Johan Sandoval committed 2026-10-06 19:09:49 +00:00
1 parent 50c2a18a68
commit 7868948bfc
10 files changed
+1230 -356

No files matched your search

+60
View File
@@ -13,6 +13,7 @@
# Initialize-Provider, Open-ProviderCycle, Close-ProviderCycle, pingDevice,
# Resolve-DeviceIP, Get-DiskSpace, Get-LogInfo, Get-DeviceAssociations,
# Get-DeviceInventory, Get-InstalledSoftware
# and optionally Get-DeviceLastSeen.
# =========================================================================================
$script:SccmCfg = $config.SCCM
@@ -254,10 +255,13 @@ function Get-DeviceInventory {
$searcher = $null
try {
# Only letters, digits and - _ . can reach the LDAP filter
if ($computerName -notmatch '^[A-Za-z0-9._-]+$') { throw "invalid name" }
$searcher = [adsisearcher]"(&(objectCategory=computer)(name=$computerName))"
$searcher.PropertiesToLoad.Add("distinguishedname") | Out-Null
$searcher.PropertiesToLoad.Add("memberof") | Out-Null
$adResult = $searcher.FindOne()
$res.InAD = [bool]$adResult # the lookup worked, so "no result" really means "not in AD"
if ($adResult) {
$dn = $adResult.Properties["distinguishedname"][0]
@@ -308,7 +312,9 @@ function Get-DeviceInventory {
$reader = $cmd.ExecuteReader()
$assetExists = $false
$res.InSCCM = $false
if ($reader.Read()) {
$res.InSCCM = $true
if ($reader["MAC_Addresses0"] -isnot [DBNull] -and $reader["MAC_Addresses0"]) { $res.MAC = $reader["MAC_Addresses0"] }
if ($reader["Model0"] -isnot [DBNull] -and $reader["Model0"]) { $res.Model = $reader["Model0"] }
if ($reader["TotalPhysicalMemory0"] -isnot [DBNull] -and $reader["TotalPhysicalMemory0"]) {
@@ -395,9 +401,63 @@ function Get-DeviceInventory {
} catch {}
# ---------------------------
# --- Monitors (WmiMonitorID hardware inventory) ---
$mon = $script:SccmCfg.Monitors
if ($mon -and $mon.Enabled -and (Test-SqlName $mon.View) -and (Test-SqlName $mon.NameColumn) -and (Test-SqlName $mon.ManufacturerColumn)) {
try {
if ($SqlConn -and $SqlConn.State -eq 'Open') {
$monCmd = $SqlConn.CreateCommand()
$monCmd.CommandText = @"
SELECT m.[$($mon.NameColumn)] AS MonName, m.[$($mon.ManufacturerColumn)] AS MonMfr
FROM v_R_System sys
INNER JOIN $($mon.View) m ON sys.ResourceID = m.ResourceID
WHERE sys.Name0 = @MonCompName
"@
$monCmd.Parameters.AddWithValue("@MonCompName", $computerName) | Out-Null
$monReader = $monCmd.ExecuteReader()
$names = @()
while ($monReader.Read()) {
$name = ConvertFrom-WmiCharCodes $monReader["MonName"]
$mfr = ConvertFrom-WmiCharCodes $monReader["MonMfr"]
if ($mon.InternalPattern -and $mfr -match $mon.InternalPattern -and -not $name) { continue } # laptop panel
$names += $(if ($name) { $name } elseif ($mfr) { "$mfr (unnamed)" } else { "Unknown monitor" })
}
$monReader.Dispose(); $monCmd.Dispose()
$res.MonitorCount = "$($names.Count)"
$res.Monitors = if ($names.Count -gt 0) { $names -join "<br>" } else { "None" }
}
} catch {}
}
return $res
}
# WmiMonitorID strings are uint16 arrays; SCCM inventories them as "72,80,32,69,50,52,0,0"
function ConvertFrom-WmiCharCodes($value) {
if ($null -eq $value -or $value -is [DBNull]) { return "" }
$text = "$value".Trim()
if ($text -match '^\d+(\s*,\s*\d+)*$') {
$text = -join ($text -split '\s*,\s*' | Where-Object { [int]$_ -gt 0 } | ForEach-Object { [char][int]$_ })
}
return $text.Trim()
}
# When a device is tracked for the first time and doesn't answer a ping, "last online" is
# backfilled from the client's last activity (heartbeat / policy / status messages).
function Get-DeviceLastSeen {
param([string]$computerName, $Session)
$SqlConn = $Session.Sql
if (-not $SqlConn -or $SqlConn.State -ne 'Open') { return $null }
$cmd = $SqlConn.CreateCommand()
try {
$cmd.CommandText = "SELECT TOP 1 ch.LastActiveTime FROM v_R_System sys INNER JOIN v_CH_ClientSummary ch ON sys.ResourceID = ch.ResourceID WHERE sys.Name0 = @SeenName"
$cmd.Parameters.AddWithValue("@SeenName", $computerName) | Out-Null
$val = $cmd.ExecuteScalar()
if ($val -and $val -isnot [DBNull]) { return ([datetime]$val).ToLocalTime() }
} catch {} finally { $cmd.Dispose() }
return $null
}
# -----------------------------------------------------------------------------------------
# Installed software (used by Get-Software.ps1)
# -----------------------------------------------------------------------------------------