diff --git a/src/Api.ps1 b/src/Api.ps1 index 31289c4..b6f7581 100644 --- a/src/Api.ps1 +++ b/src/Api.ps1 @@ -1710,7 +1710,7 @@ function Get-GroupDevicesExportEndpoint { return @{ ok = $true; groupId = $GroupId; groupName = $groupName; userCount = 0; items = @(); count = 0; resolvedMs = [int]$sw.ElapsedMilliseconds } } - $select = 'id,deviceName,userDisplayName,userPrincipalName,operatingSystem,osVersion,complianceState,serialNumber,model,manufacturer,lastSyncDateTime,enrolledDateTime' + $select = 'id,deviceName,userDisplayName,userPrincipalName,operatingSystem,osVersion,complianceState,serialNumber,model,manufacturer,lastSyncDateTime,enrolledDateTime,managementAgent' $batchSize = 20 $devSeen = @{} $items = [System.Collections.Generic.List[object]]::new() @@ -1757,6 +1757,8 @@ function Get-GroupDevicesExportEndpoint { OS = [string]$d.operatingSystem OSVersion = [string]$d.osVersion ComplianceState = [string]$d.complianceState + ManagementAgent = [string]$d.managementAgent + ManagementType = Get-ManagementType ([string]$d.managementAgent) SerialNumber = [string]$d.serialNumber Model = [string]$d.model Manufacturer = [string]$d.manufacturer @@ -1840,6 +1842,15 @@ function Get-UserMemberOfEndpoint { # Devices # ============================================================ +# Verwaltungsart aus dem Graph-Feld 'managementAgent' ableiten. +# 'configurationManagerClientMdm' / 'configurationManagerClientMdmEas' -> Co-Managed +# (ConfigMgr + Intune), alles andere -> reines Intune (MDM). +function Get-ManagementType { + param([string]$Agent) + if ($Agent -match 'configurationManager') { return 'Co-Managed' } + return 'Intune' +} + function Search-DevicesEndpoint { param($Query) $err = Test-Connected @@ -1852,7 +1863,7 @@ function Search-DevicesEndpoint { # HINWEIS: 'managementState' ist KEIN gueltiges $select-Feld auf managedDevices # -> fuehrt zu 400 BadRequest. Bewusst weggelassen. - $select = 'id,deviceName,userDisplayName,userPrincipalName,operatingSystem,osVersion,complianceState,lastSyncDateTime,serialNumber,model,manufacturer,enrolledDateTime' + $select = 'id,deviceName,userDisplayName,userPrincipalName,operatingSystem,osVersion,complianceState,lastSyncDateTime,serialNumber,model,manufacturer,enrolledDateTime,managementAgent' # Ohne Suchbegriff: alle Geräte (erste Seite) # Mit Suchbegriff: Graph unterstuetzt startswith nur auf deviceName/userDisplayName/userPrincipalName. @@ -1924,6 +1935,8 @@ function Search-DevicesEndpoint { ComplianceState = $d.complianceState LastSync = ConvertTo-IsoDate $d.lastSyncDateTime ManagementState = $d.managementState + ManagementAgent = [string]$d.managementAgent + ManagementType = Get-ManagementType ([string]$d.managementAgent) SerialNumber = $d.serialNumber Model = $d.model Manufacturer = $d.manufacturer @@ -1939,12 +1952,37 @@ function Get-DeviceEndpoint { if ($err) { return $err } # 'managementState' entfernt: kein gueltiges $select-Feld auf managedDevices (400). - $select = 'id,deviceName,userDisplayName,userPrincipalName,operatingSystem,osVersion,complianceState,lastSyncDateTime,serialNumber,model,manufacturer,enrolledDateTime,imei,wiFiMacAddress,azureADDeviceId,joinType,deviceEnrollmentType,managedDeviceOwnerType,totalStorageSpaceInBytes,freeStorageSpaceInBytes' + $select = 'id,deviceName,userDisplayName,userPrincipalName,operatingSystem,osVersion,complianceState,lastSyncDateTime,serialNumber,model,manufacturer,enrolledDateTime,imei,wiFiMacAddress,azureADDeviceId,joinType,deviceEnrollmentType,managedDeviceOwnerType,managementAgent,totalStorageSpaceInBytes,freeStorageSpaceInBytes' $d = Invoke-MgGraphRequestRetry -Uri "https://graph.microsoft.com/beta/deviceManagement/managedDevices/$DeviceId`?`$select=$select" -Method GET $totalGB = if ($d.totalStorageSpaceInBytes) { [math]::Round($d.totalStorageSpaceInBytes / 1GB, 1) } else { $null } $freeGB = if ($d.freeStorageSpaceInBytes) { [math]::Round($d.freeStorageSpaceInBytes / 1GB, 1) } else { $null } + # Autopilot-Identity per Seriennummer nachladen (nur Windows, fehlertolerant). + # HINWEIS: Ein echtes "Import-/Registrierungsdatum" liefert Graph nicht; verfuegbar + # sind nur Profil-Zuweisung (deploymentProfileAssignedDateTime) und letzter Kontakt. + $inAutopilot = $false + $apProfileAssign = $null + $apLastContact = $null + $sn = [string]$d.serialNumber + if ($sn -and ([string]$d.operatingSystem).ToLower() -eq 'windows') { + try { + $snEsc = $sn -replace "'", "''" + $apFilt = [Uri]::EscapeDataString("contains(serialNumber,'$snEsc')") + $apSel = 'id,serialNumber,deploymentProfileAssignedDateTime,lastContactedDateTime,enrollmentState' + $apUri = "https://graph.microsoft.com/beta/deviceManagement/windowsAutopilotDeviceIdentities?`$filter=$apFilt&`$select=$apSel&`$top=1" + $apResp = Invoke-MgGraphRequestRetry -Uri $apUri -Method GET + $autop = @($apResp.value)[0] + if ($autop) { + $inAutopilot = $true + $apProfileAssign = ConvertTo-IsoDate $autop.deploymentProfileAssignedDateTime + $apLastContact = ConvertTo-IsoDate $autop.lastContactedDateTime + } + } catch { + Write-Host " [DEVICE] Autopilot-Lookup (SN=$sn): $($_.Exception.Message)" -ForegroundColor DarkYellow + } + } + return @{ Id = $d.id DeviceName = $d.deviceName @@ -1955,6 +1993,8 @@ function Get-DeviceEndpoint { ComplianceState = $d.complianceState LastSync = ConvertTo-IsoDate $d.lastSyncDateTime ManagementState = $d.managementState + ManagementAgent = [string]$d.managementAgent + ManagementType = Get-ManagementType ([string]$d.managementAgent) SerialNumber = $d.serialNumber Model = $d.model Manufacturer = $d.manufacturer @@ -1967,6 +2007,9 @@ function Get-DeviceEndpoint { OwnerType = $d.managedDeviceOwnerType TotalStorageGB = $totalGB FreeStorageGB = $freeGB + InAutopilot = $inAutopilot + AutopilotProfileAssigned = $apProfileAssign + AutopilotLastContacted = $apLastContact } } diff --git a/www/app.js b/www/app.js index 63946e7..69f7c28 100644 --- a/www/app.js +++ b/www/app.js @@ -5872,12 +5872,20 @@ const DEV_COL_MAP = { deviceName: 'DeviceName', userDisplayName: 'UserDisplayName', operatingSystem: 'OS', + managementType: 'ManagementType', complianceState: 'ComplianceState', lastSyncDateTime: 'LastSync', enrolledDateTime: 'EnrolledDateTime', }; const DEV_DATE_COLS = new Set(['LastSync', 'EnrolledDateTime']); +// Verwaltungsart als Badge: Co-Managed (ConfigMgr + Intune) vs. reines Intune. +function devMgmtBadge(type) { + if (type === 'Co-Managed') return 'Co-Managed'; + if (type === 'Intune') return 'Intune'; + return '—'; +} + function devFmtDate(iso) { if (!iso) return '—'; const d = new Date(iso); @@ -5941,6 +5949,7 @@ function devRender() {