Geräte-Tab: serverseitige Suche via Graph API
Suche ruft bei jeder Eingabe die API auf statt lokal zu filtern. Seriennummer wird per exaktem eq-Filter parallel gesucht und mit Namens-Treffern zusammengeführt (Graph unterstützt kein startswith auf serialNumber). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+44
-13
@@ -1544,23 +1544,54 @@ function Search-DevicesEndpoint {
|
|||||||
$q = [string]$Query.q
|
$q = [string]$Query.q
|
||||||
$os = [string]$Query.os
|
$os = [string]$Query.os
|
||||||
$compliance = [string]$Query.compliance
|
$compliance = [string]$Query.compliance
|
||||||
$top = 100
|
$top = 50
|
||||||
|
|
||||||
$filters = @()
|
|
||||||
if ($q -and $q.Length -ge 2) {
|
|
||||||
$qEnc = [uri]::EscapeDataString($q)
|
|
||||||
$filters += "(startswith(deviceName,'$q') or startswith(userDisplayName,'$q') or startswith(serialNumber,'$q'))"
|
|
||||||
}
|
|
||||||
if ($os) { $filters += "operatingSystem eq '$os'" }
|
|
||||||
if ($compliance) { $filters += "complianceState eq '$compliance'" }
|
|
||||||
|
|
||||||
$filterStr = if ($filters.Count -gt 0) { '$filter=' + [uri]::EscapeDataString(($filters -join ' and ')) + '&' } else { '' }
|
|
||||||
$select = 'id,deviceName,userDisplayName,userPrincipalName,operatingSystem,osVersion,complianceState,lastSyncDateTime,managementState,serialNumber,model,manufacturer,enrolledDateTime'
|
$select = 'id,deviceName,userDisplayName,userPrincipalName,operatingSystem,osVersion,complianceState,lastSyncDateTime,managementState,serialNumber,model,manufacturer,enrolledDateTime'
|
||||||
$uri = "https://graph.microsoft.com/v1.0/deviceManagement/managedDevices?${filterStr}`$select=$select&`$top=$top&`$orderby=deviceName"
|
|
||||||
|
|
||||||
|
# Ohne Suchbegriff: alle Geräte (erste Seite)
|
||||||
|
# Mit Suchbegriff: Graph unterstuetzt startswith nur auf deviceName/userDisplayName/userPrincipalName.
|
||||||
|
# Seriennummer wird separat per exaktem Filter gesucht und mit Name-Ergebnissen zusammengefuehrt.
|
||||||
|
$nameItems = @()
|
||||||
|
$snItems = @()
|
||||||
|
|
||||||
|
if ($q -and $q.Length -ge 2) {
|
||||||
|
$filters = @()
|
||||||
|
$nameFilter = "(startswith(deviceName,'$q') or startswith(userDisplayName,'$q') or startswith(userPrincipalName,'$q'))"
|
||||||
|
$filters += $nameFilter
|
||||||
|
if ($os) { $filters += "operatingSystem eq '$os'" }
|
||||||
|
if ($compliance) { $filters += "complianceState eq '$compliance'" }
|
||||||
|
$filterStr = '$filter=' + [uri]::EscapeDataString(($filters -join ' and ')) + '&'
|
||||||
|
$uri = "https://graph.microsoft.com/v1.0/deviceManagement/managedDevices?${filterStr}`$select=$select&`$top=$top&`$orderby=deviceName"
|
||||||
|
$resp = Invoke-MgGraphRequestRetry -Uri $uri -Method GET
|
||||||
|
$nameItems = @($resp.value)
|
||||||
|
|
||||||
|
# Seriennummer: exakter Vergleich (Graph unterstuetzt kein startswith auf serialNumber)
|
||||||
|
$snFilters = @("serialNumber eq '$q'")
|
||||||
|
if ($os) { $snFilters += "operatingSystem eq '$os'" }
|
||||||
|
if ($compliance) { $snFilters += "complianceState eq '$compliance'" }
|
||||||
|
$snFilter = '$filter=' + [uri]::EscapeDataString(($snFilters -join ' and ')) + '&'
|
||||||
|
$snUri = "https://graph.microsoft.com/v1.0/deviceManagement/managedDevices?${snFilter}`$select=$select&`$top=10"
|
||||||
|
try {
|
||||||
|
$snResp = Invoke-MgGraphRequestRetry -Uri $snUri -Method GET
|
||||||
|
$snItems = @($snResp.value)
|
||||||
|
} catch { $snItems = @() }
|
||||||
|
} else {
|
||||||
|
$filters = @()
|
||||||
|
if ($os) { $filters += "operatingSystem eq '$os'" }
|
||||||
|
if ($compliance) { $filters += "complianceState eq '$compliance'" }
|
||||||
|
$filterStr = if ($filters.Count -gt 0) { '$filter=' + [uri]::EscapeDataString(($filters -join ' and ')) + '&' } else { '' }
|
||||||
|
$uri = "https://graph.microsoft.com/v1.0/deviceManagement/managedDevices?${filterStr}`$select=$select&`$top=$top&`$orderby=deviceName"
|
||||||
|
$resp = Invoke-MgGraphRequestRetry -Uri $uri -Method GET
|
||||||
|
$nameItems = @($resp.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
# Zusammenfuehren, Duplikate entfernen
|
||||||
|
$seen = @{}
|
||||||
|
$all = @($nameItems) + @($snItems)
|
||||||
$items = @()
|
$items = @()
|
||||||
$resp = Invoke-MgGraphRequestRetry -Uri $uri -Method GET
|
foreach ($d in $all) {
|
||||||
foreach ($d in $resp.value) {
|
if (-not $d.id -or $seen[$d.id]) { continue }
|
||||||
|
$seen[$d.id] = $true
|
||||||
$items += [pscustomobject]@{
|
$items += [pscustomobject]@{
|
||||||
Id = $d.id
|
Id = $d.id
|
||||||
DeviceName = $d.deviceName
|
DeviceName = $d.deviceName
|
||||||
|
|||||||
+24
-27
@@ -5239,18 +5239,7 @@ const DevState = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
async function devLoadAll() {
|
async function devLoadAll() {
|
||||||
if (DevState.loaded) return;
|
await devFetch();
|
||||||
devShowLoading(true);
|
|
||||||
try {
|
|
||||||
const data = await api('/api/devices');
|
|
||||||
DevState.items = data.items || [];
|
|
||||||
DevState.loaded = true;
|
|
||||||
devApplyFilters();
|
|
||||||
} catch (e) {
|
|
||||||
toast('Geräte konnten nicht geladen werden: ' + e, 'error');
|
|
||||||
} finally {
|
|
||||||
devShowLoading(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function devShowLoading(on) {
|
function devShowLoading(on) {
|
||||||
@@ -5258,22 +5247,30 @@ function devShowLoading(on) {
|
|||||||
document.getElementById('devEmpty').classList.add('hidden');
|
document.getElementById('devEmpty').classList.add('hidden');
|
||||||
}
|
}
|
||||||
|
|
||||||
function devApplyFilters() {
|
async function devFetch() {
|
||||||
const q = document.getElementById('devSearch').value.toLowerCase();
|
const q = document.getElementById('devSearch').value.trim();
|
||||||
const os = document.getElementById('devOsFilter').value;
|
const os = document.getElementById('devOsFilter').value;
|
||||||
const cmp = document.getElementById('devComplianceFilter').value;
|
const cmp = document.getElementById('devComplianceFilter').value;
|
||||||
|
|
||||||
DevState.filtered = DevState.items.filter(d => {
|
devShowLoading(true);
|
||||||
if (os && d.OS !== os) return false;
|
try {
|
||||||
if (cmp && d.ComplianceState !== cmp) return false;
|
const params = new URLSearchParams();
|
||||||
if (q) {
|
if (q) params.set('q', q);
|
||||||
const hay = `${d.DeviceName} ${d.UserDisplayName} ${d.UserPrincipalName} ${d.SerialNumber}`.toLowerCase();
|
if (os) params.set('os', os);
|
||||||
if (!hay.includes(q)) return false;
|
if (cmp) params.set('compliance', cmp);
|
||||||
}
|
const data = await api('/api/devices?' + params.toString());
|
||||||
return true;
|
DevState.items = data.items || [];
|
||||||
});
|
DevState.filtered = DevState.items;
|
||||||
|
devSort();
|
||||||
|
} catch (e) {
|
||||||
|
toast('Geräte konnten nicht geladen werden: ' + e, 'error');
|
||||||
|
} finally {
|
||||||
|
devShowLoading(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
devSort();
|
function devApplyFilters() {
|
||||||
|
devFetch();
|
||||||
}
|
}
|
||||||
|
|
||||||
function devSort() {
|
function devSort() {
|
||||||
@@ -5495,10 +5492,10 @@ document.getElementById('devActions')?.addEventListener('click', async (e) => {
|
|||||||
let devSearchDebounce = null;
|
let devSearchDebounce = null;
|
||||||
document.getElementById('devSearch').addEventListener('input', () => {
|
document.getElementById('devSearch').addEventListener('input', () => {
|
||||||
clearTimeout(devSearchDebounce);
|
clearTimeout(devSearchDebounce);
|
||||||
devSearchDebounce = setTimeout(devApplyFilters, 250);
|
devSearchDebounce = setTimeout(devFetch, 400);
|
||||||
});
|
});
|
||||||
document.getElementById('devOsFilter').addEventListener('change', devApplyFilters);
|
document.getElementById('devOsFilter').addEventListener('change', devFetch);
|
||||||
document.getElementById('devComplianceFilter').addEventListener('change', devApplyFilters);
|
document.getElementById('devComplianceFilter').addEventListener('change', devFetch);
|
||||||
|
|
||||||
// Sortierung
|
// Sortierung
|
||||||
document.querySelectorAll('#devTable th.sortable').forEach(th => {
|
document.querySelectorAll('#devTable th.sortable').forEach(th => {
|
||||||
|
|||||||
Reference in New Issue
Block a user