faitza.com
faitza.com
> blog_tech

Gestion Intune via Microsoft Graph avec PowerShell

Calcul... powershell intune microsoft-graph microsoft-365 endpoint-management
Intune + PowerShell + Microsoft Graph

Introduction

Faitza_Intune.ps1 regroupe les fonctions PowerShell dédiées à la gestion et à l'audit du parc géré par Microsoft Intune : inventaire des appareils, conformité, politiques de configuration et applications déployées. Toutes les requêtes passent par Microsoft Graph API via Invoke-RestMethod — sans module PowerShell tiers.

Prérequis

Toutes les fonctions utilisent Get-Faitza_Modul_Headers -resource "graph" pour obtenir un Bearer token valide. Voir l'article dédié : Token Bearer pour les APIs Microsoft en PowerShell.

Device — Appareils d'un utilisateur

Récupère les appareils gérés par Intune pour un utilisateur donné, filtrés par système d'exploitation. Retourne les objets bruts de l'API Graph (deviceName, id, operatingSystem, complianceState, lastSyncDateTime, etc.).

Droits requis

DeviceManagementManagedDevices.Read.All

function Get-Faitza_Intune_Device {
    param (
        [string]$UserUPN,
        [string[]]$osdevice = @("Windows"),
        $Headers = $null
    )

    try {
        Write-Host "$($PSStyle.Background.Red)>>> Get-Faitza_Intune_Device <<<$($PSStyle.Reset)"
        if ([string]::IsNullOrWhiteSpace($UserUPN)) { throw "Parametre -UserUPN manquant." }
        if (-not $Headers) { $Headers = Get-Faitza_Modul_Headers -resource "graph" }
        $GraphApiUrl = "https://graph.microsoft.com/v1.0/deviceManagement/managedDevices?`$filter=userPrincipalName eq '$UserUPN'"

        $Response = Invoke-RestMethod -Uri $GraphApiUrl -Headers $Headers -Method Get

        if ($null -ne $Response.value) {
            $filteredDevices = $Response.value | Where-Object { $_.operatingSystem -in $osdevice }
        } else {
            $filteredDevices = $null
        }
        return $filteredDevices
    } catch {
        throw "Erreur Get-Faitza_Intune_Device : $_"
    } finally {
        Write-Host "$($PSStyle.Background.Red)<<< Get-Faitza_Intune_Device >>>$($PSStyle.Reset)"
    }
}
# Appareils Windows de l'utilisateur
$devices = Get-Faitza_Intune_Device -UserUPN "[email protected]"
$devices | Select-Object deviceName, complianceState, lastSyncDateTime | Format-Table -AutoSize

# Appareils iOS
$iosDevices = Get-Faitza_Intune_Device -UserUPN "[email protected]" -osdevice @("iOS")
Write-Host "$($iosDevices.Count) appareil(s) iOS"

# Réutiliser un token déjà obtenu
$headers = Get-Faitza_Modul_Headers -resource "graph"
$devices  = Get-Faitza_Intune_Device -UserUPN "[email protected]" -Headers $headers

UserByDevice — Propriétaire d'un appareil

Retourne l'UPN (UserPrincipalName) de l'utilisateur principal associé à un appareil à partir de son nom. Utile pour retrouver le propriétaire d'une machine sans passer par Active Directory.

Droits requis

DeviceManagementManagedDevices.Read.All

function Get-Faitza_Intune_UserByDevice {
    param ([string]$DeviceName)

    try {
        Write-Host "$($PSStyle.Background.Red)>>> Get-Faitza_Intune_UserByDevice <<<$($PSStyle.Reset)"
        if ([string]::IsNullOrWhiteSpace($DeviceName)) { throw "Parametre -DeviceName manquant." }

        $Headers = Get-Faitza_Modul_Headers -resource "graph"
        $GraphApiUrl = "https://graph.microsoft.com/v1.0/deviceManagement/managedDevices?`$filter=deviceName eq '$DeviceName'"
        $Response = Invoke-RestMethod -Uri $GraphApiUrl -Headers $Headers -Method Get

        if ($null -ne $Response.value -and $Response.value.Count -gt 0) {
            $Device = $Response.value[0]
            return $Device.userPrincipalName
        } else {
            Write-Warning "Aucun appareil trouve avec le nom '$DeviceName'."
            return $null
        }
    } catch {
        throw "Erreur Get-Faitza_Intune_UserByDevice : $_"
    } finally {
        Write-Host "$($PSStyle.Background.Red)<<< Get-Faitza_Intune_UserByDevice >>>$($PSStyle.Reset)"
    }
}
# Trouver le propriétaire d'un poste
$upn = Get-Faitza_Intune_UserByDevice -DeviceName "LAPTOP-FAITZA01"
Write-Host "Utilisateur : $upn"

# Utilisation en pipeline pour enrichir un inventaire
$deviceNames = @("LAPTOP-01", "DESKTOP-02", "SURFACE-03")
$deviceNames | ForEach-Object {
    [PSCustomObject]@{
        DeviceName = $_
        UPN        = Get-Faitza_Intune_UserByDevice -DeviceName $_
    }
} | Format-Table -AutoSize

DevicePolicy — Politiques d'un appareil

Retourne l'ensemble des politiques de configuration et de conformité appliquées sur un appareil donné (par nom ou par ID). Interroge les deux endpoints deviceConfigurationStates et deviceCompliancePolicyStates avec pagination, et retourne un objet unifié par politique avec son état.

Droits requis

DeviceManagementManagedDevices.Read.All · DeviceManagementConfiguration.Read.All

function Get-Faitza_Intune_DevicePolicy {
    [CmdletBinding()]
    param ([string]$DeviceName, [string]$DeviceId)
    try {
        Write-Host "$($PSStyle.Background.Red)>>> Get-Faitza_Intune_DevicePolicy <<<$($PSStyle.Reset)"
        if ([string]::IsNullOrWhiteSpace($DeviceName) -and [string]::IsNullOrWhiteSpace($DeviceId)) { throw "Veuillez fournir au moins un -DeviceName ou un -DeviceId." }

        $Headers = Get-Faitza_Modul_Headers -resource "graph"
        $Results = @()
        $DevicePlatform = "Inconnu"

        if ([string]::IsNullOrWhiteSpace($DeviceId)) {
            $SearchUrl = "https://graph.microsoft.com/v1.0/deviceManagement/managedDevices?`$filter=deviceName eq '$DeviceName'"
            $DeviceLookup = (Invoke-RestMethod -Uri $SearchUrl -Headers $Headers -Method Get).value
            if ($DeviceLookup.Count -eq 0) { return "L'appareil '$DeviceName' est introuvable." }
            $DeviceId = $DeviceLookup[0].id
            $DeviceName = $DeviceLookup[0].deviceName
            $DevicePlatform = $DeviceLookup[0].operatingSystem
        } else {
            $DeviceLookup = Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/deviceManagement/managedDevices/$DeviceId" -Headers $Headers -Method Get
            $DevicePlatform = $DeviceLookup.operatingSystem
            if ([string]::IsNullOrWhiteSpace($DeviceName)) { $DeviceName = $DeviceLookup.deviceName }
        }

        $ConfigUrl = "https://graph.microsoft.com/v1.0/deviceManagement/managedDevices/$DeviceId/deviceConfigurationStates"
        $ConfigStates = @()
        do {
            $Response = Invoke-RestMethod -Uri $ConfigUrl -Headers $Headers -Method Get
            if ($null -ne $Response.value) { $ConfigStates += $Response.value }
            $ConfigUrl = $Response.'@odata.nextLink'
        } while ($null -ne $ConfigUrl)

        $CompUrl = "https://graph.microsoft.com/v1.0/deviceManagement/managedDevices/$DeviceId/deviceCompliancePolicyStates"
        $CompStates = @()
        do {
            $Response = Invoke-RestMethod -Uri $CompUrl -Headers $Headers -Method Get
            if ($null -ne $Response.value) { $CompStates += $Response.value }
            $CompUrl = $Response.'@odata.nextLink'
        } while ($null -ne $CompUrl)

        foreach ($State in $ConfigStates) {
            $Results += [PSCustomObject]@{
                DeviceName        = $DeviceName
                Plateforme        = $DevicePlatform
                UserPrincipalName = $State.userPrincipalName
                PolicyName        = $State.displayName
                PolicyId          = $State.id
                PolicyType        = "Configuration"
                State             = $State.state
            }
        }

        foreach ($State in $CompStates) {
            $Results += [PSCustomObject]@{
                DeviceName        = $DeviceName
                Plateforme        = $DevicePlatform
                UserPrincipalName = $State.userPrincipalName
                PolicyName        = $State.displayName
                PolicyId          = $State.id
                PolicyType        = "Compliance"
                State             = $State.state
            }
        }

        return $Results
    } catch {
        throw "Erreur Get-Faitza_Intune_DevicePolicy : $_"
    } finally {
        Write-Host "$($PSStyle.Background.Red)<<< Get-Faitza_Intune_DevicePolicy >>>$($PSStyle.Reset)"
    }
}
# Par nom d'appareil
$policies = Get-Faitza_Intune_DevicePolicy -DeviceName "LAPTOP-FAITZA01"
$policies | Format-Table PolicyName, PolicyType, State -AutoSize

# Par ID
$policies = Get-Faitza_Intune_DevicePolicy -DeviceId "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

# Filtrer les politiques non conformes
$policies | Where-Object State -ne 'compliant' | Select-Object PolicyName, PolicyType, State

UserPolicy — Politiques d'un utilisateur

Retourne toutes les politiques appliquées sur l'ensemble des appareils d'un utilisateur. Appelle Get-Faitza_Intune_DevicePolicy pour chaque appareil trouvé via l'endpoint /users/{UPN}/managedDevices.

Droits requis

DeviceManagementManagedDevices.Read.All · DeviceManagementConfiguration.Read.All

function Get-Faitza_Intune_UserPolicy {
    [CmdletBinding()]
    param ([string]$UserUPN)
    try {
        Write-Host "$($PSStyle.Background.Red)>>> Get-Faitza_Intune_UserPolicy <<<$($PSStyle.Reset)"
        if ([string]::IsNullOrWhiteSpace($UserUPN)) { throw "Veuillez fournir un -UserUPN." }

        $Headers = Get-Faitza_Modul_Headers -resource "graph"
        $UserResults = @()

        Write-Host "Recherche des appareils geres pour l'utilisateur : $UserUPN"
        $DevicesUrl = "https://graph.microsoft.com/v1.0/users/$UserUPN/managedDevices"
        $Devices = (Invoke-RestMethod -Uri $DevicesUrl -Headers $Headers -Method Get).value

        if ($Devices.Count -eq 0) { return "Aucun appareil gere (Intune) trouve pour l'utilisateur '$UserUPN'." }

        foreach ($Device in $Devices) {
            Write-Host "-> Analyse de l'appareil $($Device.deviceName)"
            $DevicePolicies = Get-Faitza_Intune_DevicePolicy -DeviceId $Device.id -DeviceName $Device.deviceName
            foreach ($Pol in $DevicePolicies) {
                $Pol.TargetType = "User's Device"
                $UserResults += $Pol
            }
        }
        return $UserResults
    } catch {
        throw "Erreur Get-Faitza_Intune_UserPolicy : $_"
    } finally {
        Write-Host "$($PSStyle.Background.Red)<<< Get-Faitza_Intune_UserPolicy >>>$($PSStyle.Reset)"
    }
}
# Toutes les politiques sur tous les appareils d'un utilisateur
$userPolicies = Get-Faitza_Intune_UserPolicy -UserUPN "[email protected]"
$userPolicies | Format-Table DeviceName, PolicyName, PolicyType, State -AutoSize

# Politiques non conformes uniquement
$userPolicies | Where-Object State -ne 'compliant' |
    Select-Object DeviceName, PolicyName, State |
    Export-Csv ".\non_conformes_jdupont.csv" -NoTypeInformation -Delimiter ";" -Encoding UTF8

PolicyDetails — Détails d'une politique

Retourne les détails complets d'une politique Intune par son ID. Compatible avec tous les types de politiques : profils de configuration classiques, politiques de conformité, Settings Catalog, Endpoint Security, scripts PowerShell. Teste chaque endpoint successivement et retourne le premier résultat disponible au format JSON compact.

Droits requis

DeviceManagementConfiguration.Read.All · DeviceManagementManagedDevices.Read.All

function Get-Faitza_Intune_PolicyDetails {
    [CmdletBinding()]
    param ([string]$PolicyId)
    try {
        Write-Host "$($PSStyle.Background.Red)>>> Get-Faitza_Intune_PolicyDetails <<<$($PSStyle.Reset)"
        if ([string]::IsNullOrWhiteSpace($PolicyId)) { throw "Parametre -PolicyId manquant." }

        $Headers = Get-Faitza_Modul_Headers -resource "graph"

        try {
            $ConfigUrl = "https://graph.microsoft.com/v1.0/deviceManagement/deviceConfigurations/$PolicyId"
            $Clean = Invoke-RestMethod -Uri $ConfigUrl -Headers $Headers -Method Get -ErrorAction Stop | Select-Object * -ExcludeProperty id, lastModifiedDateTime, createdDateTime, version
            return ($Clean | ConvertTo-Json -Depth 5 -Compress)
        } catch { }

        try {
            $CompUrl = "https://graph.microsoft.com/v1.0/deviceManagement/deviceCompliancePolicies/$PolicyId"
            $Clean = Invoke-RestMethod -Uri $CompUrl -Headers $Headers -Method Get -ErrorAction Stop | Select-Object * -ExcludeProperty id, lastModifiedDateTime, createdDateTime, version
            return ($Clean | ConvertTo-Json -Depth 5 -Compress)
        } catch { }

        try {
            $SettingsUrl = "https://graph.microsoft.com/beta/deviceManagement/configurationPolicies/$PolicyId"
            $Clean = Invoke-RestMethod -Uri $SettingsUrl -Headers $Headers -Method Get -ErrorAction Stop | Select-Object * -ExcludeProperty id, lastModifiedDateTime
            return "Settings Catalog : " + ($Clean | ConvertTo-Json -Depth 5 -Compress)
        } catch { }

        try {
            $IntentUrl = "https://graph.microsoft.com/beta/deviceManagement/intents/$PolicyId"
            $Clean = Invoke-RestMethod -Uri $IntentUrl -Headers $Headers -Method Get -ErrorAction Stop | Select-Object * -ExcludeProperty id, lastModifiedDateTime
            return "Endpoint Security : " + ($Clean | ConvertTo-Json -Depth 5 -Compress)
        } catch { }

        try {
            $ScriptUrl = "https://graph.microsoft.com/beta/deviceManagement/deviceManagementScripts/$PolicyId"
            $Clean = Invoke-RestMethod -Uri $ScriptUrl -Headers $Headers -Method Get -ErrorAction Stop
            return "Script PowerShell : $($Clean.fileName)"
        } catch { }

        return "Details introuvables via l'API pour l'ID $PolicyId"
    } catch {
        throw "Erreur Get-Faitza_Intune_PolicyDetails : $_"
    } finally {
        Write-Host "$($PSStyle.Background.Red)<<< Get-Faitza_Intune_PolicyDetails >>>$($PSStyle.Reset)"
    }
}
# Détails d'une politique (type détecté automatiquement)
$details = Get-Faitza_Intune_PolicyDetails -PolicyId "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
Write-Host $details

# Archiver les détails dans un fichier JSON
$details | Out-File ".\politique_$PolicyId.json" -Encoding UTF8

# Obtenir l'ID depuis Get-Faitza_Intune_AllPolicies, puis inspecter
$policies = Get-Faitza_Intune_AllPolicies
$id = ($policies.data | Where-Object PolicyName -eq "BitLocker - Windows 10").PolicyId
Get-Faitza_Intune_PolicyDetails -PolicyId $id

AllPolicies — Inventaire des politiques

Inventaire exhaustif de toutes les politiques du tenant, couvrant six types distincts : profils de configuration, politiques de conformité, Settings Catalog, Endpoint Security, scripts PowerShell et modèles d'administration (GPO). Pour chaque politique, résout les groupes Entra ID assignés via un cache interne. Retourne un hashtable @{ data = ...; erreur = ... }.

Droits requis

DeviceManagementConfiguration.Read.All · DeviceManagementManagedDevices.Read.All · GroupMember.Read.All (résolution des groupes)

function Get-Faitza_Intune_AllPolicies {
    [CmdletBinding()]
    param ()
    try {
        Write-Host "$($PSStyle.Background.Red)>>> Get-Faitza_Intune_AllPolicies <<<$($PSStyle.Reset)"
        $Headers = Get-Faitza_Modul_Headers -resource "graph"
        $AllPolicies = @()
        $GroupCache = @{}
        $ApiErrors = @()

        $Endpoints = @(
            @{ Type = "Configuration Profile"; Url = "https://graph.microsoft.com/beta/deviceManagement/deviceConfigurations" },
            @{ Type = "Compliance Policy"; Url = "https://graph.microsoft.com/beta/deviceManagement/deviceCompliancePolicies" },
            @{ Type = "Settings Catalog"; Url = "https://graph.microsoft.com/beta/deviceManagement/configurationPolicies" },
            @{ Type = "Endpoint Security"; Url = "https://graph.microsoft.com/beta/deviceManagement/intents" },
            @{ Type = "PowerShell Script"; Url = "https://graph.microsoft.com/beta/deviceManagement/deviceManagementScripts" },
            @{ Type = "Administrative Template"; Url = "https://graph.microsoft.com/beta/deviceManagement/groupPolicyConfigurations" }
        )

        foreach ($Endpoint in $Endpoints) {
            Write-Host "Collecte des politiques : $($Endpoint.Type)"
            $NextLink = $Endpoint.Url
            $TempData = @()

            do {
                try {
                    $Response = Invoke-RestMethod -Uri $NextLink -Headers $Headers -Method Get
                    if ($null -ne $Response.value) { $TempData += $Response.value }
                    $NextLink = $Response.'@odata.nextLink'
                } catch {
                    $errMsg = $_.Exception.Message
                    if ($errMsg -match "Resource not found for the segment") {
                        $FriendlyError = "Le module n'est pas initialise sur votre tenant Intune (0 politique existante)."
                        Write-Host "Info : $FriendlyError" -ForegroundColor DarkGray
                        $ApiErrors += "[$($Endpoint.Type)] $FriendlyError"
                    } else {
                        Write-Host "Erreur sur $($Endpoint.Type) : $errMsg" -ForegroundColor Yellow
                        $ApiErrors += "[$($Endpoint.Type)] Erreur inattendue : $errMsg"
                    }
                    $NextLink = $null
                }
            } while ($null -ne $NextLink)

            foreach ($Item in $TempData) {
                $CleanForExcel = {
                    param([string]$text)
                    if ([string]::IsNullOrWhiteSpace($text)) { return "" }
                    $str = $text -replace '[\x00-\x1F\x7F]', ''
                    if ($str -match "^[=\-\+@]") { $str = "'" + $str }
                    if ($str.Length -gt 30000) { return $str.Substring(0, 30000) + "... [TRONQUE]" }
                    return $str.Trim()
                }

                $PolicyId = $Item.id
                $RawName  = if ($Item.displayName) { $Item.displayName } else { $Item.name }
                $SafeDate = ""
                if ($null -ne $Item.lastModifiedDateTime) { try { $SafeDate = (Get-Date $Item.lastModifiedDateTime).ToString("dd/MM/yyyy HH:mm") } catch { } }
                $PolicyDescription = if (-not [string]::IsNullOrWhiteSpace($Item.description)) { $Item.description } else { "" }
                $AssignationCible = "Non assigne"
                $GroupesEntraID = ""

                try {
                    $AssignUrl = "$($Endpoint.Url)/$PolicyId/assignments"
                    $Assignments = (Invoke-RestMethod -Uri $AssignUrl -Headers $Headers -Method Get).value
                    $ListAssign = @()
                    $ListGroups = @()

                    foreach ($Assign in $Assignments) {
                        $TargetType = $Assign.target.'@odata.type'
                        if ($TargetType -match "allLicensedUsers") { $ListAssign += "Tous les Utilisateurs" }
                        elseif ($TargetType -match "allDevices") { $ListAssign += "Tous les Appareils" }
                        elseif ($TargetType -match "groupAssignmentTarget") {
                            $ListAssign += "Groupe"
                            $GroupId = $Assign.target.groupId
                            if (-not $GroupCache.ContainsKey($GroupId)) {
                                try {
                                    $Faitza_Result = Get-Faitza_Entra_Groupe_Name -GroupId $GroupId
                                    if ($null -ne $Faitza_Result -and $Faitza_Result -ne "") { $GroupCache[$GroupId] = $Faitza_Result } else { $GroupCache[$GroupId] = "ID sans nom ($GroupId)" }
                                } catch { $GroupCache[$GroupId] = "Erreur resolution ($GroupId)" }
                            }
                            $ListGroups += $GroupCache[$GroupId]
                        }
                    }

                    if ($ListAssign.Count -gt 0) { $AssignationCible = ($ListAssign | Select-Object -Unique) -join " + " }
                    if ($ListGroups.Count -gt 0) { $GroupesEntraID = ($ListGroups | Select-Object -Unique) -join ", " }
                } catch { $AssignationCible = "Erreur lecture assignation" }

                $AllPolicies += [PSCustomObject]@{
                    PolicyId          = &$CleanForExcel $PolicyId
                    PolicyName        = &$CleanForExcel $RawName
                    PolicyType        = &$CleanForExcel $Endpoint.Type
                    Description       = &$CleanForExcel $PolicyDescription
                    LastModified      = $SafeDate
                    Cible_Assignation = &$CleanForExcel $AssignationCible
                    Groupes_Entra_ID  = &$CleanForExcel $GroupesEntraID
                    ErrorCount        = 0
                    ConflictCount     = 0
                    SuccessCount      = 0
                }
            }
        }

        return @{ data = $AllPolicies; erreur = $ApiErrors }
    } catch {
        throw "Erreur Get-Faitza_Intune_AllPolicies : $_"
    } finally {
        Write-Host "$($PSStyle.Background.Red)<<< Get-Faitza_Intune_AllPolicies >>>$($PSStyle.Reset)"
    }
}
$result = Get-Faitza_Intune_AllPolicies
$policies = $result.data
$errors   = $result.erreur

# Afficher toutes les politiques
$policies | Format-Table PolicyName, PolicyType, Cible_Assignation -AutoSize

# Synthèse par type
$policies | Group-Object PolicyType | Select-Object Name, Count | Sort-Object Count -Descending

# Export Excel (module ImportExcel requis)
$policies | Export-Excel -Path ".\intune_policies.xlsx" -WorksheetName "Politiques" -AutoSize -FreezeTopRow -TableName "TPolicies"

# Afficher les erreurs d'API éventuelles
if ($errors.Count -gt 0) { $errors | ForEach-Object { Write-Warning $_ } }

AllApps — Inventaire des applications

Liste toutes les applications déployées via Intune en interrogeant l'endpoint /deviceAppManagement/mobileApps avec pagination. Couvre tous les types : Win32, MSI, Microsoft Store, iOS/Android, apps métier (LOB), web apps. Retourne un hashtable @{ data = ...; erreur = ... }.

Droits requis

DeviceManagementApps.Read.All

function Get-Faitza_Intune_AllApps {
    [CmdletBinding()]
    param ()
    try {
        Write-Host "$($PSStyle.Background.Red)>>> Get-Faitza_Intune_AllApps <<<$($PSStyle.Reset)"
        $Headers = Get-Faitza_Modul_Headers -resource "graph"
        $AllApps = @()
        $GroupCache = @{}
        $ApiErrors = @()

        Write-Host "Collecte des Applications..."
        $NextLink = "https://graph.microsoft.com/beta/deviceAppManagement/mobileApps"
        $TempData = @()

        do {
            try {
                $Response = Invoke-RestMethod -Uri $NextLink -Headers $Headers -Method Get
                if ($null -ne $Response.value) { $TempData += $Response.value }
                $NextLink = $Response.'@odata.nextLink'
            } catch {
                $errMsg = $_.Exception.Message
                Write-Host "Erreur sur les applications : $errMsg" -ForegroundColor Yellow
                $ApiErrors += "[Applications] Erreur inattendue : $errMsg"
                $NextLink = $null
            }
        } while ($null -ne $NextLink)

        foreach ($Item in $TempData) {
            $CleanForExcel = {
                param([string]$text)
                if ([string]::IsNullOrWhiteSpace($text)) { return "" }
                $str = $text -replace '[\x00-\x1F\x7F]', ''
                if ($str -match "^[=\-\+@]") { $str = "'" + $str }
                if ($str.Length -gt 30000) { return $str.Substring(0, 30000) + "... [TRONQUE]" }
                return $str.Trim()
            }

            $AppId = $Item.id
            $RawName = $Item.displayName
            $RawType = if ($Item.'@odata.type') { $Item.'@odata.type'.Replace('#microsoft.graph.', '') } else { "Unknown" }
            $AppDescription = if (-not [string]::IsNullOrWhiteSpace($Item.description)) { $Item.description } else { "" }
            $SafeDate = ""
            if ($null -ne $Item.lastModifiedDateTime) { try { $SafeDate = (Get-Date $Item.lastModifiedDateTime).ToString("dd/MM/yyyy HH:mm") } catch { } }

            $AllApps += [PSCustomObject]@{
                AppId             = &$CleanForExcel $AppId
                AppName           = &$CleanForExcel $RawName
                AppType           = &$CleanForExcel $RawType
                Description       = &$CleanForExcel $AppDescription
                LastModified      = $SafeDate
                Cible_Assignation = "Non assigne"
                Groupes_Entra_ID  = ""
                ErrorCount        = 0
                ConflictCount     = 0
                SuccessCount      = 0
                NotInstalledCount = 0
            }
        }

        return @{ data = $AllApps; erreur = $ApiErrors }
    } catch {
        throw "Erreur Get-Faitza_Intune_AllApps : $_"
    } finally {
        Write-Host "$($PSStyle.Background.Red)<<< Get-Faitza_Intune_AllApps >>>$($PSStyle.Reset)"
    }
}
$result = Get-Faitza_Intune_AllApps
$apps   = $result.data

Write-Host "$($apps.Count) applications dans le tenant"

# Synthèse par type
$apps | Group-Object AppType | Select-Object Name, Count | Sort-Object Count -Descending | Format-Table

# Export Excel
$apps | Export-Excel -Path ".\intune_apps.xlsx" -WorksheetName "Applications" -AutoSize -FreezeTopRow -TableName "TApps"

DeviceCompliance — Conformité détaillée

Retourne l'état de conformité détaillé d'un appareil : complianceState, OS et version, dernière synchronisation, date d'expiration de la période de grâce. Accepte un nom d'appareil ou un ID Intune.

Droits requis

DeviceManagementManagedDevices.Read.All

function Get-Faitza_Intune_DeviceCompliance {
    [CmdletBinding()]
    param ([string]$DeviceName, [string]$DeviceId)
    try {
        Write-Host "$($PSStyle.Background.Red)>>> Get-Faitza_Intune_DeviceCompliance <<<$($PSStyle.Reset)"
        $Anomalies = @()
        $Headers = Get-Faitza_Modul_Headers -resource "graph"
        $BaseUrl = "https://graph.microsoft.com/beta/deviceManagement/managedDevices"
        $DeviceData = $null

        if ($DeviceId) {
            $DeviceData = Invoke-RestMethod -Uri "$BaseUrl/$DeviceId" -Headers $Headers -Method Get -ErrorAction SilentlyContinue
        } else {
            $Url = "$BaseUrl`?$filter=deviceName eq '$DeviceName'"
            $Response = Invoke-RestMethod -Uri $Url -Headers $Headers -Method Get -ErrorAction Stop
            if ($Response.value.Count -gt 0) { $DeviceData = $Response.value[0]; $DeviceId = $DeviceData.id }
        }

        if ($null -eq $DeviceData) {
            $Anomalies += "Appareil introuvable dans Intune."
            return [PSCustomObject]@{ DeviceName = $DeviceName; ComplianceState = "Unknown"; Anomalies = $Anomalies }
        }

        return [PSCustomObject]@{
            DeviceId        = $DeviceData.id
            DeviceName      = $DeviceData.deviceName
            UserPrincipal   = $DeviceData.userPrincipalName
            OperatingSystem = "$($DeviceData.operatingSystem) ($($DeviceData.osVersion))"
            ComplianceState = $DeviceData.complianceState
            LastSync        = $DeviceData.lastSyncDateTime
            GraceExpiration = $DeviceData.complianceGracePeriodExpirationDateTime
            RaisonEchec     = "Voir details Intune"
            Anomalies       = $Anomalies
        }
    } catch {
        throw "Erreur Get-Faitza_Intune_DeviceCompliance : $_"
    } finally {
        Write-Host "$($PSStyle.Background.Red)<<< Get-Faitza_Intune_DeviceCompliance >>>$($PSStyle.Reset)"
    }
}
# Par nom d'appareil
$compliance = Get-Faitza_Intune_DeviceCompliance -DeviceName "LAPTOP-FAITZA01"
$compliance | Format-List

# Par ID
$compliance = Get-Faitza_Intune_DeviceCompliance -DeviceId "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

Write-Host "État : $($compliance.ComplianceState)"
Write-Host "OS   : $($compliance.OperatingSystem)"
Write-Host "Sync : $($compliance.LastSync)"

DeviceComplianceState — État rapide

Vérifie rapidement si un appareil est conforme. Retourne un objet compact avec ComplianceState, le booléen IsCompliant et un indicateur visuel (OK / KO / WARN / UNKNOWN). Accepte un nom d'appareil ou un ID Intune.

Droits requis

DeviceManagementManagedDevices.Read.All

function Get-Faitza_Intune_DeviceComplianceState {
    [CmdletBinding()]
    param ([string]$DeviceName, [string]$IntuneDeviceId)

    try {
        Write-Host "$($PSStyle.Background.Red)>>> Get-Faitza_Intune_DeviceComplianceState <<<$($PSStyle.Reset)"
        if ([string]::IsNullOrWhiteSpace($DeviceName) -and [string]::IsNullOrWhiteSpace($IntuneDeviceId)) { throw "Veuillez fournir -DeviceName ou -IntuneDeviceId." }

        $Headers = Get-Faitza_Modul_Headers -resource "graph"

        if (-not [string]::IsNullOrWhiteSpace($IntuneDeviceId)) {
            $device = Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/deviceManagement/managedDevices/$IntuneDeviceId`?`$select=id,deviceName,complianceState" -Headers $Headers -Method Get -ErrorAction Stop
        } else {
            $safeName = $DeviceName -replace "'", "''"
            $resp = Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/deviceManagement/managedDevices?`$filter=deviceName eq '$safeName'&`$select=id,deviceName,complianceState" -Headers $Headers -Method Get -ErrorAction Stop
            if (-not $resp.value -or $resp.value.Count -eq 0) { throw "Device '$DeviceName' introuvable dans Intune." }
            $device = $resp.value[0]
        }

        $emoji = switch ($device.complianceState) {
            'compliant'     { 'OK' }
            'noncompliant'  { 'KO' }
            'inGracePeriod' { 'WARN' }
            default         { 'UNKNOWN' }
        }

        return [PSCustomObject]@{
            DeviceName      = $device.deviceName
            ComplianceState = $device.complianceState
            IsCompliant     = ($device.complianceState -eq 'compliant')
            Emoji           = $emoji
        }
    } catch {
        throw "Erreur Get-Faitza_Intune_DeviceComplianceState : $_"
    } finally {
        Write-Host "$($PSStyle.Background.Red)<<< Get-Faitza_Intune_DeviceComplianceState >>>$($PSStyle.Reset)"
    }
}
# Vérification rapide par nom
$state = Get-Faitza_Intune_DeviceComplianceState -DeviceName "LAPTOP-FAITZA01"
Write-Host "[$($state.Emoji)] $($state.DeviceName) — $($state.ComplianceState)"

# Par ID Intune
$state = Get-Faitza_Intune_DeviceComplianceState -IntuneDeviceId "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

# Vérification en masse sur une liste de postes
$postes = @("LAPTOP-01", "DESKTOP-02", "SURFACE-03")
$postes | ForEach-Object {
    Get-Faitza_Intune_DeviceComplianceState -DeviceName $_
} | Format-Table DeviceName, ComplianceState, IsCompliant, Emoji -AutoSize

// Commentaires

Aucun commentaire pour l'instant.