Intune PowerShell: comandos de Microsoft Graph, scripts y escenarios para administrar los equipos

Intune PowerShell: tres pilas de portátiles plateados vistos de canto, con sus puertos a la vista, como un parque de equipos que se administra a la vez

Intune PowerShell es la forma de administrar Microsoft Intune desde la consola: listar todos los equipos de la empresa con una orden, sincronizar Intune en cien portátiles sin abrir cien fichas, saber qué equipo tiene instalada una aplicación o revisar en todo el parque el resultado de los scripts y las remediaciones de Intune. Hoy se hace con los módulos de Microsoft Graph, porque el módulo antiguo de Intune dejó de funcionar en 2024, y esta guía explica cuál instalar, qué permisos pedir, los comandos que más se usan y cinco escenarios listos para copiar.

Sirve a dos lectores. Si dirige la empresa o el área y no es de sistemas, el primer apartado y el de recomendaciones le dicen qué se puede automatizar y qué riesgos tiene darle a un script permiso para borrar equipos. Si es técnico, el resto le da las órdenes con sus permisos mínimos, los límites de la API y las trampas que encontramos, entre ellas dos acciones destructivas que no piden confirmación. Para lo general de la consola está la guía de PowerShell, y para el resto de Microsoft 365 con Graph, la de Microsoft 365 PowerShell.

Las órdenes se validaron con los módulos de Microsoft Graph 2.41.2, la versión vigente el 9 de noviembre de 2026, descargados sin instalar, en Windows PowerShell 5.1 y en PowerShell 7.6.9, y los bloques de los escenarios se ejecutaron con datos simulados. No nos conectamos a ninguna organización de Intune: lo que responde el servicio sale de la documentación de Microsoft, y el artículo lo dice en cada caso.

Qué es Intune PowerShell y qué módulo usar hoy

En realidad, Intune no tiene un módulo de PowerShell propio que esté vigente. Lo que se llama Intune PowerShell son los cmdlets de Microsoft Graph que hablan con la parte de Intune, cuyos nombres empiezan casi todos por Get-MgDeviceManagement o Get-MgDeviceAppManagement. Debajo está la API de Graph de Intune, la misma que usa el centro de administración, así que lo que se hace con un clic se puede hacer con una orden.

OpciónEstadoPara qué sirve
Microsoft.Graph.Intune (Connect-MSGraph)Retirado. Su última versión, la 6.1907.1.0, es de julio de 2019Para nada: desde 2024 falla al conectarse
Microsoft.Graph.DeviceManagement y sus hermanosVigente, versión 2.41.2Equipos, acciones remotas, cumplimiento, configuración y aplicaciones detectadas
Microsoft.Graph.Beta.DeviceManagementVigente, pero llama a la versión beta de GraphLo que aún no está en v1.0: scripts, remediaciones y el catálogo de configuración
Invoke-MgGraphRequestVigente, dentro de Microsoft.Graph.AuthenticationCualquier llamada a la API cuando no hay cmdlet o se quiere controlar la respuesta

Además, el módulo antiguo se conectaba con una aplicación de Microsoft que se retiró. En los foros de Microsoft Q&A, el personal de Microsoft explicó en 2024 que, desde el 1 de abril de ese año, la aplicación «Microsoft Intune PowerShell» dejaba de existir y que había que cambiar los scripts antes del 1 de mayo; desde entonces, Connect-MSGraph responde AADSTS700016: Application with identifier 'd1ddf0e4-d672-4dae-b554-9d5bdfd93547' was not found in the directory. Si encuentra ese error en un script heredado, no tiene arreglo: hay que reescribirlo con los módulos de Graph.

Los módulos de Graph para Intune, medidos

Microsoft recomienda instalar solo los submódulos que se usan, no el paquete entero. Estos son los que cubren Intune, con lo que medimos al cargarlos en un portátil con Windows 11:

MóduloComandosTamañoCarga en PowerShell 7Carga en 5.1
Microsoft.Graph.Authentication1838,8 MB0,4 a 4,1 s0,6 a 0,9 s
Microsoft.Graph.DeviceManagement22924,3 MB1,3 a 4,5 s1,3 a 3,7 s
Microsoft.Graph.DeviceManagement.Enrollment302,5 MB0,4 a 1,3 s0,3 a 1,1 s
Microsoft.Graph.Devices.CorporateManagement1.16440,9 MB6,3 a 6,9 s9,3 a 12,8 s
Microsoft.Graph.Beta.DeviceManagement940116,1 MB16,6 a 24,5 s27,4 a 35,3 s

Los tiempos son de dos pasadas en cada versión, y la segunda fue más rápida porque los archivos ya estaban en la caché del disco. Microsoft.Graph.DeviceManagement es el que más se usa: trae los equipos, las acciones remotas, el cumplimiento y la configuración clásica. Devices.CorporateManagement trae las aplicaciones de Intune, y Enrollment, Autopilot. El de beta pesa casi cinco veces más y tarda en cargar; conviene importarlo solo en los scripts que lo necesitan.

Sin embargo, hay un detalle que confunde al leer guías viejas: hasta 2024 existía Microsoft.Graph.DeviceManagement.Actions, con la sincronización y el borrado remoto. Su última versión en la Galería de PowerShell es la 2.25.0, de noviembre de 2024, y hoy esas acciones viven dentro de Microsoft.Graph.DeviceManagement. Lo comprobamos con Get-Command: Sync-MgDeviceManagementManagedDevice sale de ese módulo.

Para qué sirve Intune PowerShell en la empresa

La consola de Intune está bien para un equipo. Intune PowerShell sirve cuando la pregunta es sobre todos:

  • Inventario. Una hoja con cada equipo, su usuario, el sistema, el número de serie, el cifrado y el espacio libre, sin exportar a mano.
  • Equipos olvidados. Los que no hablan con Intune desde hace semanas, que suelen ser portátiles perdidos, guardados o reinstalados sin avisar.
  • Acciones en bloque. Sincronizar Intune en todos los equipos de una sede después de cambiar una directiva, o reiniciar los de un grupo.
  • Software. Qué equipos tienen instalada una aplicación concreta, por ejemplo una herramienta de acceso remoto que no debería estar.
  • Resultados de scripts. Qué devolvió un script de detección en cada equipo, sin abrir el informe de cada paquete.
  • Tareas programadas. Un informe semanal que se genera solo, con una aplicación y un certificado en lugar de un usuario.

Antes de empezar: licencia, roles y permisos

Hacen falta tres cosas, y fallar en cualquiera da el mismo error 403:

  1. Licencia de Intune en la organización. Cada página de la API lo advierte: la API de Graph de Intune requiere una licencia activa de Intune para el inquilino.
  2. Un rol que permita la acción. Con acceso delegado, el usuario que se conecta tiene que poder hacer lo mismo en el centro de administración. Para sincronizar, por ejemplo, Microsoft pide como mínimo el rol de Intune de Operador del departamento de soporte técnico o uno personalizado con el permiso de sincronizar.
  3. El permiso de Graph adecuado, llamado ámbito, que un administrador tiene que aprobar. La guía de acceso a la API de Intune lo dice sin matices: hoy todos los permisos de Intune requieren acceso de administrador.

Estos son los permisos de Intune que más se usan y lo que permiten, según esa guía y la referencia de cada llamada:

PermisoQué permite
DeviceManagementManagedDevices.Read.AllLeer equipos, aplicaciones detectadas e información de malware
DeviceManagementManagedDevices.ReadWrite.AllAdemás, cambiar y borrar equipos y sus categorías
DeviceManagementManagedDevices.PrivilegedOperations.AllLas acciones que afectan al usuario: sincronizar, reiniciar, bloquear, retirar y restablecer
DeviceManagementConfiguration.Read.AllLeer directivas de configuración y de cumplimiento
DeviceManagementApps.Read.AllLeer las aplicaciones de Intune y sus directivas
DeviceManagementServiceConfig.Read.AllLeer la inscripción, incluida la de Autopilot
DeviceManagementScripts.Read.AllLeer scripts y remediaciones

Por eso, la regla práctica es pedir solo lo que el script usa. Un informe no necesita PrivilegedOperations, y un script que solo sincroniza no necesita ReadWrite. Si duda, Find-MgGraphCommand lo responde sin conectarse:

Find-MgGraphCommand -Command Sync-MgDeviceManagementManagedDevice | Select-Object -First 1 -ExpandProperty Permissions

Instalar Intune PowerShell

Para empezar con Intune PowerShell basta con los submódulos, en el ámbito del usuario, que no pide permisos de administrador. Microsoft recomienda PowerShell 7, aunque los módulos funcionan en Windows PowerShell 5.1 con .NET Framework 4.7.2 o posterior:

Install-Module Microsoft.Graph.Authentication, Microsoft.Graph.DeviceManagement -Scope CurrentUser -Repository PSGallery
Install-Module Microsoft.Graph.Beta.DeviceManagement -Scope CurrentUser -Repository PSGallery
Get-Module Microsoft.Graph.* -ListAvailable | Select-Object Name, Version

Por otro lado, instale todos en la misma versión: mezclar una Authentication nueva con un DeviceManagement viejo es una fuente frecuente de errores al cargar. La guía de módulos de PowerShell explica cómo actualizarlos y por qué Update-Module deja la versión anterior instalada al lado.

Conectarse a Intune con Microsoft Graph

Para trabajar a mano, la conexión delegada pide los permisos y abre el inicio de sesión de la cuenta de trabajo:

Connect-MgGraph -Scopes 'DeviceManagementManagedDevices.Read.All' -NoWelcome
Get-MgContext | Select-Object Account, TenantId, Scopes

Get-MgContext confirma con qué cuenta, en qué organización y con qué permisos quedó la sesión. Tres opciones que conviene conocer:

  • -UseDeviceCode da un código para iniciar sesión desde otro equipo, útil en un servidor sin navegador. La documentación lo escribe -UseDeviceAuthentication, que es uno de sus alias.
  • -ContextScope Process deja la sesión solo en esa ventana. Sin él, el inicio de sesión se guarda y la siguiente consola entra sin preguntar, hasta que se ejecuta Disconnect-MgGraph.
  • -TenantId elige la organización. Es obligatorio en la práctica si su cuenta es invitada en varias, como la de un proveedor.

Sin conexión, cualquier cmdlet de Intune responde Authentication needed. Please call Connect-MgGraph., y lo mismo Invoke-MgGraphRequest. Ese mensaje es de las búsquedas más repetidas sobre el tema y no indica una avería: falta Connect-MgGraph, o la sesión se cerró.

Conexión sin usuario, para tareas automáticas

Por el contrario, un informe que corre cada lunes no debe depender de la contraseña de nadie. Para eso se registra una aplicación en Microsoft Entra ID con permisos de aplicación, se aprueban y se conecta con un certificado:

Connect-MgGraph -ClientId '00000000-0000-0000-0000-000000000000' -TenantId 'empresa.onmicrosoft.com' -CertificateThumbprint 'A1B2C3D4E5F6A1B2C3D4E5F6A1B2C3D4E5F6A1B2' -NoWelcome

Eso sí, el certificado tiene que estar en el almacén del usuario o del equipo que ejecuta el script. Microsoft documenta también un secreto de cliente, pero un secreto es una contraseña en un archivo; el certificado es la opción más segura de las dos. Si el script corre en Azure, la identidad administrada (Connect-MgGraph -Identity) evita las dos cosas. Con permisos de aplicación no hay usuario ni rol de Intune que limite: lo que se apruebe vale para toda la organización. La guía de tareas programadas con PowerShell explica cómo dejar el script programado en Windows.

Los comandos de Intune PowerShell más comunes

Estos son los cmdlets que resuelven la mayoría del trabajo diario. El permiso es el mínimo que da Find-MgGraphCommand para cada llamada:

CmdletQué hacePermiso mínimo
Get-MgDeviceManagementManagedDeviceLista los equipos inscritos o lee unoDeviceManagementManagedDevices.Read.All
Sync-MgDeviceManagementManagedDevicePide al equipo que se conecte a Intune yaDeviceManagementManagedDevices.PrivilegedOperations.All
Restart-MgDeviceManagementManagedDeviceNowReinicia el equipoDeviceManagementManagedDevices.PrivilegedOperations.All
Invoke-MgRetireDeviceManagementManagedDeviceRetira el equipo: quita los datos y la gestión de la empresaDeviceManagementManagedDevices.PrivilegedOperations.All
Clear-MgDeviceManagementManagedDeviceRestablece el equipo de fábrica (borrado remoto)DeviceManagementManagedDevices.PrivilegedOperations.All
Remove-MgDeviceManagementManagedDeviceBorra el equipo de Intune, y además lo retiraDeviceManagementManagedDevices.ReadWrite.All
Get-MgDeviceManagementDeviceCompliancePolicyLista las directivas de cumplimientoDeviceManagementConfiguration.Read.All
Get-MgDeviceManagementDeviceConfigurationLista los perfiles de configuración clásicosDeviceManagementConfiguration.Read.All
Get-MgDeviceManagementDetectedAppLista el software que Intune encontró en los equiposDeviceManagementManagedDevices.Read.All
Get-MgDeviceAppManagementMobileAppLista las aplicaciones que Intune distribuyeDeviceManagementApps.Read.All
Get-MgDeviceManagementWindowsAutopilotDeviceIdentityLista los equipos registrados en AutopilotDeviceManagementServiceConfig.Read.All

Get-MgDeviceManagementManagedDevice: listar los equipos

Get-MgDeviceManagementManagedDevice es la orden con la que empieza casi todo. Sin -All, solo trae la primera página de resultados; con -All, sigue pidiendo páginas hasta el final. Con -Property, que también se escribe -Select, trae solo los campos que se usan y la respuesta es más pequeña:

$equipos = Get-MgDeviceManagementManagedDevice -All -Property 'id','deviceName','userPrincipalName','operatingSystem','osVersion','complianceState','lastSyncDateTime'
$equipos.Count
$equipos | Group-Object OperatingSystem | Select-Object Name, Count

Para que el servicio haga el filtro, -Filter admite la sintaxis OData de Graph. Pero la referencia del recurso managedDevice solo declara el filtro en unos pocos campos: complianceState, managementAgent, deviceCategoryDisplayName y jailBroken con eq y or, y lastSyncDateTime y enrolledDateTime con lt y gt. Para todo lo demás, el nombre del equipo incluido, lo seguro es traer la lista y filtrar con Where-Object:

Get-MgDeviceManagementManagedDevice -All -Filter "complianceState eq 'noncompliant'" |
    Select-Object DeviceName, UserPrincipalName, LastSyncDateTime
Get-MgDeviceManagementManagedDevice -All | Where-Object DeviceName -like 'PC-CONT*'

Por último, un aviso para quien filtra por nombre: Intune puede tener dos registros con el mismo nombre, por ejemplo cuando un portátil se reinstaló y se volvió a inscribir. Antes de actuar sobre un equipo buscado por nombre, compruebe que salió uno solo.

Sincronizar Intune desde PowerShell

La acción de sincronizar pide al equipo que se conecte a Intune en ese momento y reciba lo pendiente, sin esperar a su próximo ciclo. Según la página de la acción de sincronizar, en Windows también procesa scripts, remediaciones y el estado de las aplicaciones. Desde la consola, para un equipo:

$equipo = @(Get-MgDeviceManagementManagedDevice -All | Where-Object DeviceName -eq 'PC-CONTABILIDAD')
if ($equipo.Count -ne 1) { throw "Se esperaba un equipo y hay $($equipo.Count)" }
Sync-MgDeviceManagementManagedDevice -ManagedDeviceId $equipo[0].Id

Si responde sin mostrar nada, funcionó, porque la API contesta con un 204 sin contenido. Que el equipo reciba la orden depende de que esté encendido y conectado. Para sincronizar Intune desde el propio equipo, sin la API, Microsoft documenta dos caminos: Configuración > Sincronizar en el Portal de empresa, o reiniciar el servicio IntuneManagementExtension, que con permisos de administrador es una orden:

Restart-Service -Name IntuneManagementExtension

Retirar, borrar y restablecer: tres acciones distintas

Aquí está la trampa más cara de Intune PowerShell. La página de acciones de dispositivo define tres cosas que en la conversación diaria se confunden:

AcciónCmdletQué le pasa al equipo
RetirarInvoke-MgRetireDeviceManagementManagedDevicePierde los datos y la configuración de la empresa; los datos personales se quedan
EliminarRemove-MgDeviceManagementManagedDeviceDesaparece de la consola en el acto y, además, se retira
Borrar (restablecer)Clear-MgDeviceManagementManagedDeviceVuelve a los valores de fábrica y pierde todo

En cambio, lo que más sorprende es la segunda fila: borrar un equipo de Intune no es solo quitarlo de la lista. Microsoft lo dice así: eliminar un equipo lo oculta del centro de administración e inicia un retiro. Por lo tanto, si su intención era limpiar registros duplicados, use antes Get-MgDeviceManagementManagedDevice para estar seguro de que borra el registro viejo y no el del equipo que alguien usa.

Por qué estas acciones no piden confirmación

La segunda sorpresa la medimos en el módulo: las tres acciones tienen el impacto de confirmación en Medium, y PowerShell solo pide confirmación cuando es High. Es decir, Clear-MgDeviceManagementManagedDevice restablece un equipo de fábrica sin preguntar. Use -WhatIf para ensayar y -Confirm para que pregunte:

Clear-MgDeviceManagementManagedDevice -ManagedDeviceId $equipo[0].Id -WhatIf

Además, el mensaje de -WhatIf no dice qué equipo. Muestra Call remote 'POST /deviceManagement/managedDevices/{managedDevice-id}/microsoft.graph.wipe' operation, con el identificador sin rellenar. En un bucle, escriba usted el nombre de cada equipo antes de la acción, o el ensayo no le servirá para revisar la lista.

Por otra parte, Intune pone un tope diario por organización, que cuenta igual la consola, las acciones en bloque y la API: 500 borrados de fábrica, 1.000 retiros y 1.000 eliminaciones al día. Un script con un error en el filtro puede gastar el cupo del día, y lo que alcanzó a hacer no tiene vuelta atrás. Algunas organizaciones activan la aprobación de varios administradores, que exige que un segundo administrador apruebe la acción antes de ejecutarla.

Directivas, cumplimiento, aplicaciones y Autopilot

Para revisar la configuración, los cmdlets de lectura siguen también el mismo patrón:

Get-MgDeviceManagementDeviceCompliancePolicy -All | Select-Object DisplayName, LastModifiedDateTime
Get-MgDeviceManagementDeviceConfiguration -All | Select-Object DisplayName, LastModifiedDateTime
Get-MgDeviceAppManagementMobileApp -All | Select-Object DisplayName, Publisher
Get-MgDeviceManagementWindowsAutopilotDeviceIdentity -All | Select-Object SerialNumber, Model, GroupTag, EnrollmentState

Sin embargo, falta una pieza que hoy es la principal: las directivas del catálogo de configuración, el método que Intune usa para casi todo lo nuevo. No tienen cmdlet en la versión v1.0: Get-MgDeviceManagementConfigurationPolicy no existe, y sí Get-MgBetaDeviceManagementConfigurationPolicy, en el módulo de beta. Lo mismo pasa con los scripts de plataforma y las remediaciones, como se ve en el apartado siguiente. Si prefiere no cargar el módulo de beta, Invoke-MgGraphRequest hace la misma llamada y recorre las páginas con @odata.nextLink:

$uri = 'beta/deviceManagement/configurationPolicies?$select=id,name,platforms,lastModifiedDateTime'
$politicas = do {
    $r = Invoke-MgGraphRequest -Method GET -Uri $uri
    $r.value
    $uri = $r.'@odata.nextLink'
} while ($uri)
$politicas | ForEach-Object { [pscustomobject]$_ } | Select-Object name, platforms, lastModifiedDateTime

La ruta va entre comillas simples a propósito: con comillas dobles, PowerShell tomaría $select por una variable vacía y la consulta perdería el filtro de campos.

Scripts de Intune y remediaciones de Intune

Intune también ejecuta PowerShell dentro de los equipos, con los scripts de Intune, y aquí conviene no mezclar dos cosas. Con los módulos de Graph se administra Intune desde fuera; con los scripts de Intune y las remediaciones de Intune, el propio Intune lleva un script a cada equipo y lo ejecuta allí, a través de su agente, la extensión de administración de Intune. Esta es la diferencia entre las dos opciones, según la página de scripts de plataforma y la guía para detectar y corregir problemas:

Scripts de plataformaRemediaciones
Para quéConfigurar algo una vezDetectar un problema y corregirlo, de forma periódica
Cuándo correUna vez; solo se repite si cambia el script o la asignaciónCon horario: una vez, cada pocas horas o a diario
Si fallaTres reintentos, uno por cada conexión del equipo, y no vuelve a intentarloVuelve a correr según su horario
Tamaño y tiempoMenos de 200 KB; se corta a los 30 minutosHasta 200 paquetes; la salida se corta a los 2.048 caracteres
LicenciaLa de IntuneAdemás, Windows Enterprise E3 o E5, Education A3 o A5, o Windows VDA por usuario
EquiposUnidos a Microsoft Entra ID; los solo registrados, según la página que se leaUnidos a Microsoft Entra ID o híbridos, con Windows Enterprise, Professional o Education
En GraphSolo en beta (Get-MgBetaDeviceManagementScript)Solo en beta (Get-MgBetaDeviceManagementDeviceHealthScript)

De todas ellas, la fila de la licencia es la que más preguntas genera: Microsoft 365 Empresa Premium no aparece en la lista de licencias de las remediaciones, que solo nombra las ediciones Enterprise, Education y VDA. Antes de diseñar una solución con remediaciones de Intune, compruebe qué licencia tienen los usuarios.

Lo que traen de fábrica los scripts de Intune

Hay tres detalles de los scripts de Intune que conviene saber antes de subir el primero. De fábrica corren con las credenciales del usuario que inició sesión, en PowerShell de 32 bits y con la comprobación de firma activada; un script sin firmar no correrá hasta cambiar esa opción. Por otra parte, la extensión revisa si hay scripts nuevos cada 8 horas, así que un cambio puede tardar en llegar; sincronizar Intune lo adelanta.

Una remediación de Intune paso a paso

En pocas palabras, una remediación es un paquete con un script de detección y, si se quiere, uno de corrección. La regla es simple: si la detección termina con exit 1, Intune considera que hay un problema y ejecuta la corrección; con cualquier otro código, no. Este script de detección avisa si a la unidad del sistema le queda menos del 15 % libre:

# Deteccion: avisa si a la unidad del sistema le queda menos del 15 % libre
$umbral = 15
$disco = Get-CimInstance -ClassName Win32_LogicalDisk -Filter "DeviceID='$env:SystemDrive'"
$libre = [math]::Round(100 * $disco.FreeSpace / $disco.Size, 1)
$gb = [math]::Round($disco.FreeSpace / 1GB, 1)
if ($libre -lt $umbral) {
    Write-Output "Poco espacio: $gb GB libres ($libre %) en $env:SystemDrive"
    exit 1
}
Write-Output "Espacio correcto: $gb GB libres ($libre %) en $env:SystemDrive"
exit 0

Lo ejecutamos tal cual en un portátil con Windows 11, en Windows PowerShell 5.1 y en PowerShell 7, y en los dos devolvió lo mismo: Poco espacio: 136.9 GB libres (14.4 %) en C: y el código 1. Fíjese, además, en el punto decimal: PowerShell escribe los números dentro de una cadena con el formato invariable, no con la coma de Colombia. En el informe de Intune ese texto aparece como la salida de la detección.

Por otro lado, este paquete no lleva script de corrección a propósito: liberar espacio sin mirar qué se borra no es algo que deba hacerse a ciegas en todos los equipos. Así, una remediación de solo detección es un informe que se mantiene solo, y eso ya sirve. Guarde el script en UTF-8 y sin tildes en el texto que escribe, súbalo como archivo y no lo pegue en el navegador; Microsoft lo recomienda así para evitar problemas de codificación. Para el espacio libre en sí, la guía de liberar espacio en OneDrive explica la causa más común en los portátiles de empresa.

Escenarios de Intune PowerShell listos para usar

Los cinco escenarios usan el mismo caso, una empresa de unos 120 equipos administrados con Intune. Todos son de lectura salvo el 3, que sincroniza.

Escenario 1: inventario de equipos en una hoja de cálculo

Es el primer informe que suele pedirse a Intune PowerShell: una fila por equipo, con lo que pregunta la gerencia: de quién es, qué sistema tiene, si cumple las directivas, cuándo habló con Intune por última vez, el número de serie, si el disco está cifrado y cuánto espacio libre le queda.

Connect-MgGraph -Scopes 'DeviceManagementManagedDevices.Read.All' -NoWelcome
$campos = 'deviceName','userPrincipalName','operatingSystem','osVersion','complianceState','lastSyncDateTime','serialNumber','model','isEncrypted','freeStorageSpaceInBytes','totalStorageSpaceInBytes'
$informe = Get-MgDeviceManagementManagedDevice -All -Property $campos | ForEach-Object {
    [pscustomobject]@{
        Equipo       = $_.DeviceName
        Usuario      = $_.UserPrincipalName
        Sistema      = "$($_.OperatingSystem) $($_.OSVersion)"
        Cumplimiento = $_.ComplianceState
        UltimaSync   = $_.LastSyncDateTime
        DiasSinSync  = if ($_.LastSyncDateTime) { ((Get-Date) - $_.LastSyncDateTime).Days } else { $null }
        Serie        = $_.SerialNumber
        Modelo       = $_.Model
        Cifrado      = $_.IsEncrypted
        LibreGB      = [math]::Round($_.FreeStorageSpaceInBytes / 1GB, 1)
        LibrePct     = if ($_.TotalStorageSpaceInBytes) { [math]::Round(100 * $_.FreeStorageSpaceInBytes / $_.TotalStorageSpaceInBytes) } else { $null }
    }
}
$cod = if ($PSVersionTable.PSVersion.Major -ge 7) { 'utf8BOM' } else { 'UTF8' }
$ruta = Join-Path ([Environment]::GetFolderPath('Desktop')) 'equipos-intune.csv'
$informe | Sort-Object DiasSinSync -Descending | Export-Csv $ruta -NoTypeInformation -Delimiter ';' -Encoding $cod

Además, dos decisiones del bloque tienen motivo. El separador es punto y coma porque es el que espera Excel con la configuración regional de Colombia; con coma, abre todo en una sola columna. Y la codificación cambia según la versión porque -Encoding UTF8 en PowerShell 7 escribe sin la marca que Excel necesita para leer bien las tildes, y en 5.1 sí la escribe. Lo medimos con un archivo de prueba en las dos versiones.

Escenario 2: equipos que no hablan con Intune desde hace un mes

lastSyncDateTime es uno de los pocos campos que el servicio filtra con lt, así que la búsqueda la hace Intune y no su consola:

$limite = (Get-Date).ToUniversalTime().AddDays(-30).ToString('yyyy-MM-ddTHH:mm:ssZ')
Get-MgDeviceManagementManagedDevice -All -Filter "lastSyncDateTime lt $limite" -Property 'deviceName','userPrincipalName','operatingSystem','lastSyncDateTime' |
    Sort-Object LastSyncDateTime |
    Select-Object DeviceName, UserPrincipalName, OperatingSystem, LastSyncDateTime

Primero, la fecha va en hora universal y sin comillas, como pide la sintaxis de Graph. En la práctica, cada equipo de esa lista tiene una explicación: un portátil guardado en un cajón, uno reinstalado que quedó duplicado, uno perdido. Mientras siga así, ninguno recibe directivas ni actualizaciones; por eso conviene revisarla cada mes.

Escenario 3: sincronizar Intune en todos los equipos Windows

Por ejemplo, después de cambiar una directiva importante, este bloque pide la sincronización a cada equipo Windows, con una pausa entre uno y otro para no rozar los límites de la API:

Connect-MgGraph -Scopes 'DeviceManagementManagedDevices.Read.All','DeviceManagementManagedDevices.PrivilegedOperations.All' -NoWelcome
$windows = @(Get-MgDeviceManagementManagedDevice -All -Property 'id','deviceName','operatingSystem' | Where-Object OperatingSystem -eq 'Windows')
$n = 0
foreach ($e in $windows) {
    Write-Output "Sincronizando $($e.DeviceName)"
    Sync-MgDeviceManagementManagedDevice -ManagedDeviceId $e.Id
    $n++
    Start-Sleep -Milliseconds 200
}
"$n equipos Windows sincronizados"

La cuenta de la pausa sale de los límites de Microsoft Graph: para los equipos de Intune, una aplicación puede hacer 200 escrituras cada 20 segundos en una organización. Con 200 milisegundos de pausa, el script hace como mucho 100 cada 20 segundos, la mitad del límite. En la empresa del caso, 120 equipos suman 24 segundos de pausas; en una de 1.000 equipos, 200 segundos, y aun sin pausa no podría bajar de 100. Si se pasa, Graph responde 429; el módulo trae reintentos automáticos, de fábrica tres con 3 segundos de espera, según Get-MgRequestContext.

Escenario 4: qué equipos tienen instalada una aplicación

Del mismo modo, el inventario de software que hace Intune en cada equipo se consulta así. El ejemplo busca AnyDesk, una herramienta de acceso remoto cuya licencia gratuita es solo para uso personal, como explicamos en la guía de soporte remoto:

$apps = @(Get-MgDeviceManagementDetectedApp -All | Where-Object DisplayName -like '*AnyDesk*')
$apps | Select-Object DisplayName, Version, DeviceCount
foreach ($a in $apps) {
    Get-MgDeviceManagementDetectedAppManagedDevice -DetectedAppId $a.Id -All |
        Select-Object @{n='Aplicacion';e={$a.DisplayName}}, @{n='Version';e={$a.Version}}, DeviceName
}

Cada aplicación detectada lleva su versión, por eso el bloque recorre todas las que coinciden. Una limitación que dice la referencia del recurso: las aplicaciones que Intune no distribuye solo aparecen en los equipos marcados como corporativos, así que un portátil personal inscrito no saldrá en esta búsqueda.

Escenario 5: el resultado de una remediación en cada equipo

Igualmente, el informe de una remediación se puede leer con la API, con el módulo de beta. Este bloque lista, para el paquete de espacio en disco, qué devolvió la detección en cada equipo:

Connect-MgGraph -Scopes 'DeviceManagementScripts.Read.All','DeviceManagementManagedDevices.Read.All' -NoWelcome
$paquete = @(Get-MgBetaDeviceManagementDeviceHealthScript -All | Where-Object DisplayName -eq 'Espacio en disco')
if ($paquete.Count -ne 1) { throw 'No hay un paquete con ese nombre, o hay varios' }
Get-MgBetaDeviceManagementDeviceHealthScriptDeviceRunState -DeviceHealthScriptId $paquete[0].Id -All -ExpandProperty 'managedDevice' |
    Select-Object @{n='Equipo';e={$_.ManagedDevice.DeviceName}}, DetectionState, LastStateUpdateDateTime, PreRemediationDetectionScriptOutput |
    Sort-Object DetectionState

Por ejemplo, la columna PreRemediationDetectionScriptOutput trae el texto que escribió el script, el de los gigas libres. De esta manera, cien informes de equipo se convierten en una sola lista.

Comprobar un equipo antes de culpar a Intune

Por ejemplo, cuando un equipo no recibe nada, antes de revisar el script de Intune PowerShell conviene mirar si de verdad está inscrito. Estas órdenes funcionan sin permisos de administrador:

dsregcmd /status | Select-String 'AzureAdJoined', 'DomainJoined', 'WorkplaceJoined'
Get-Service -Name IntuneManagementExtension -ErrorAction SilentlyContinue
Get-ScheduledTask -TaskPath '\Microsoft\Windows\EnterpriseMgmt\*' -ErrorAction SilentlyContinue | Select-Object -First 5 TaskPath, TaskName

En el portátil de nuestras pruebas, la primera dijo AzureAdJoined : NO y WorkplaceJoined : YES, el servicio de la extensión no existía y no había ninguna tarea de inscripción: el equipo tiene la cuenta de trabajo agregada, pero no está administrado por Intune. Por cierto, es el mismo caso que describimos en la guía de BitLocker con Intune, y explica muchos «Intune no me aplica la directiva».

Límites de la API de Intune que conviene conocer

Estos son los límites que más afectan a un script de Intune PowerShell que actúa sobre muchos equipos:

LímiteValorFuente
Escrituras sobre equipos (sincronizar, reiniciar, retirar)200 cada 20 s por aplicación; 400 por organizaciónLímites de Microsoft Graph
Lecturas sobre equipos2.000 cada 20 s por aplicación; 4.000 por organizaciónLímites de Microsoft Graph
Borrados de fábrica500 al día por organizaciónAcciones de dispositivo de Intune
Retiros y eliminaciones1.000 al día cada unoAcciones de dispositivo de Intune
Acciones en bloque desde la consola100 equipos por acciónAcciones de dispositivo de Intune
Salida de una remediación2.048 caracteresRemediaciones
Script de plataformaMenos de 200 KB y 30 minutosScripts de plataforma

Lo que la documentación de Microsoft no dice igual en todas partes

Al contrastar las páginas con el módulo, además, encontramos estas diferencias. Ninguna impide trabajar, pero cualquiera puede costar una tarde:

TemaLo que dice un sitioLo que dice otro
Versión de la APILa guía de instalación recomienda usar siempre v1.0 en los scriptsScripts, remediaciones y el catálogo de configuración solo existen en beta
Equipos solo registradosLa página de la extensión de Intune los admiteLa de scripts de plataforma dice que no reciben scripts, y en otra línea explica cómo asignárselos
Frecuencia de las remediacionesLa misma página dice que se repiten cada 24 horasTambién ofrece horarios de una vez y cada pocas horas
Permiso para leer scriptsLa guía de la API dice que la lectura pasó a DeviceManagementScripts.ReadWrite.AllExiste DeviceManagementScripts.Read.All, y Find-MgGraphCommand lo da para las remediaciones
Permiso para borrar de fábricaLa página de la llamada wipe pide PrivilegedOperations.AllFind-MgGraphCommand acepta además ManagedDevices.ReadWrite.All
Ejemplo en C# de la guía de la APIInstala la biblioteca MSALEl código usa AuthenticationContext, de la biblioteca anterior, ADAL
Conexión por códigoLa documentación escribe -UseDeviceAuthenticationEl parámetro se llama -UseDeviceCode; el otro es un alias

Errores frecuentes con Intune PowerShell

Mensaje o síntomaCausaQué hacer
Authentication needed. Please call Connect-MgGraph.No hay sesión, o se cerróEjecute Connect-MgGraph con los permisos que necesita el script
Select-MgProfile no se reconoceEl script es de la versión 1 de los módulos; la 2 lo quitóUse los cmdlets Get-MgBeta… del módulo de beta
AADSTS700016 con d1ddf0e4-d672-4dae-b554-9d5bdfd93547Script con el módulo antiguo, Connect-MSGraphReescríbalo con los módulos de Graph
403 ForbiddenFalta el permiso, el rol de Intune o la licenciaRevise Get-MgContext, el rol de la cuenta y la licencia
Get-MgDeviceManagementConfigurationPolicy no se reconoceEl catálogo de configuración no está en v1.0Use Get-MgBetaDeviceManagementConfigurationPolicy o Invoke-MgGraphRequest
429 Too Many RequestsSe pasó el límite de la APIAgregue una pausa en el bucle, como en el escenario 3
La lista trae menos equipos de los que hayFalta -All: solo llegó la primera páginaAgregue -All
La corrección de una remediación nunca correLa detección no termina con exit 1Revise el código de salida del script de detección

Lo que no probamos

No nos conectamos a ninguna organización de Intune ni ejecutamos ninguna acción sobre equipos reales. Sí se midió en un portátil con Windows 11, sin permisos de administrador: los cinco módulos, sus comandos y sus tiempos de carga en las dos versiones de PowerShell; los permisos con Find-MgGraphCommand; los mensajes sin conexión; el comportamiento de -WhatIf y el nivel de confirmación de las acciones; el script de detección, y el estado de inscripción del equipo. Los bloques de los escenarios se ejecutaron en las dos versiones con cmdlets simulados que devuelven equipos de ejemplo, y sus propiedades se comprobaron contra los tipos reales del módulo 2.41.2. Lo que hace el servicio de Intune con cada llamada se cuenta según la documentación de Microsoft.

Recomendaciones

  1. Deje el módulo antiguo. Cualquier script con Connect-MSGraph o Select-MgProfile hay que reescribirlo.
  2. Instale solo los submódulos que usa, todos en la misma versión, y cargue el de beta solo donde haga falta.
  3. Pida el permiso mínimo. Un informe no necesita PrivilegedOperations; sepárelo de los scripts que actúan.
  4. Para tareas automáticas, use una aplicación con certificado, no un usuario ni un secreto en un archivo.
  5. Ensaye con -WhatIf toda acción que borra o retira, y escriba el nombre de cada equipo en pantalla, porque el ensayo no lo muestra.
  6. No use eliminar para limpiar la lista: eliminar también retira el equipo.
  7. Revise cada mes los equipos que no sincronizan, con el escenario 2.
  8. Compruebe la licencia antes de diseñar remediaciones de Intune.
  9. Ponga una pausa en los bucles que actúan sobre muchos equipos.

Cuando Intune es parte de la administración diaria

Intune PowerShell ahorra horas, pero un script con permiso para retirar equipos es tan delicado como la consola misma: alguien tiene que decidir quién lo ejecuta, con qué permisos y qué se revisa cada mes. Es trabajo de rutina, no de una vez.

En KHARONTE, la administración de Microsoft 365 y de las consolas de los equipos está en nuestra gestión de plataformas, y el día a día de los puestos de trabajo, en el soporte técnico para empresas, con una mesa de ayuda TI que atiende a los usuarios. Si busca servicios administrados de TI para que el parque de equipos se mantenga al día, revise nuestros servicios de TI para empresas.

Hablemos de la TI de su empresa

Cuéntenos qué necesita su operación y le enviamos una propuesta por escrito. Cada línea del portafolio se contrata por separado.

Compartir este artículo

Últimas entradas

Escríbanos ahora