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ón | Estado | Para qué sirve |
|---|---|---|
Microsoft.Graph.Intune (Connect-MSGraph) | Retirado. Su última versión, la 6.1907.1.0, es de julio de 2019 | Para nada: desde 2024 falla al conectarse |
Microsoft.Graph.DeviceManagement y sus hermanos | Vigente, versión 2.41.2 | Equipos, acciones remotas, cumplimiento, configuración y aplicaciones detectadas |
Microsoft.Graph.Beta.DeviceManagement | Vigente, pero llama a la versión beta de Graph | Lo que aún no está en v1.0: scripts, remediaciones y el catálogo de configuración |
Invoke-MgGraphRequest | Vigente, dentro de Microsoft.Graph.Authentication | Cualquier 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ódulo | Comandos | Tamaño | Carga en PowerShell 7 | Carga en 5.1 |
|---|---|---|---|---|
Microsoft.Graph.Authentication | 18 | 38,8 MB | 0,4 a 4,1 s | 0,6 a 0,9 s |
Microsoft.Graph.DeviceManagement | 229 | 24,3 MB | 1,3 a 4,5 s | 1,3 a 3,7 s |
Microsoft.Graph.DeviceManagement.Enrollment | 30 | 2,5 MB | 0,4 a 1,3 s | 0,3 a 1,1 s |
Microsoft.Graph.Devices.CorporateManagement | 1.164 | 40,9 MB | 6,3 a 6,9 s | 9,3 a 12,8 s |
Microsoft.Graph.Beta.DeviceManagement | 940 | 116,1 MB | 16,6 a 24,5 s | 27,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:
- 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.
- 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.
- 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:
| Permiso | Qué permite |
|---|---|
DeviceManagementManagedDevices.Read.All | Leer equipos, aplicaciones detectadas e información de malware |
DeviceManagementManagedDevices.ReadWrite.All | Además, cambiar y borrar equipos y sus categorías |
DeviceManagementManagedDevices.PrivilegedOperations.All | Las acciones que afectan al usuario: sincronizar, reiniciar, bloquear, retirar y restablecer |
DeviceManagementConfiguration.Read.All | Leer directivas de configuración y de cumplimiento |
DeviceManagementApps.Read.All | Leer las aplicaciones de Intune y sus directivas |
DeviceManagementServiceConfig.Read.All | Leer la inscripción, incluida la de Autopilot |
DeviceManagementScripts.Read.All | Leer 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:
-UseDeviceCodeda 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 Processdeja 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 ejecutaDisconnect-MgGraph.-TenantIdelige 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:
| Cmdlet | Qué hace | Permiso mínimo |
|---|---|---|
Get-MgDeviceManagementManagedDevice | Lista los equipos inscritos o lee uno | DeviceManagementManagedDevices.Read.All |
Sync-MgDeviceManagementManagedDevice | Pide al equipo que se conecte a Intune ya | DeviceManagementManagedDevices.PrivilegedOperations.All |
Restart-MgDeviceManagementManagedDeviceNow | Reinicia el equipo | DeviceManagementManagedDevices.PrivilegedOperations.All |
Invoke-MgRetireDeviceManagementManagedDevice | Retira el equipo: quita los datos y la gestión de la empresa | DeviceManagementManagedDevices.PrivilegedOperations.All |
Clear-MgDeviceManagementManagedDevice | Restablece el equipo de fábrica (borrado remoto) | DeviceManagementManagedDevices.PrivilegedOperations.All |
Remove-MgDeviceManagementManagedDevice | Borra el equipo de Intune, y además lo retira | DeviceManagementManagedDevices.ReadWrite.All |
Get-MgDeviceManagementDeviceCompliancePolicy | Lista las directivas de cumplimiento | DeviceManagementConfiguration.Read.All |
Get-MgDeviceManagementDeviceConfiguration | Lista los perfiles de configuración clásicos | DeviceManagementConfiguration.Read.All |
Get-MgDeviceManagementDetectedApp | Lista el software que Intune encontró en los equipos | DeviceManagementManagedDevices.Read.All |
Get-MgDeviceAppManagementMobileApp | Lista las aplicaciones que Intune distribuye | DeviceManagementApps.Read.All |
Get-MgDeviceManagementWindowsAutopilotDeviceIdentity | Lista los equipos registrados en Autopilot | DeviceManagementServiceConfig.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ón | Cmdlet | Qué le pasa al equipo |
|---|---|---|
| Retirar | Invoke-MgRetireDeviceManagementManagedDevice | Pierde los datos y la configuración de la empresa; los datos personales se quedan |
| Eliminar | Remove-MgDeviceManagementManagedDevice | Desaparece de la consola en el acto y, además, se retira |
| Borrar (restablecer) | Clear-MgDeviceManagementManagedDevice | Vuelve 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 plataforma | Remediaciones | |
|---|---|---|
| Para qué | Configurar algo una vez | Detectar un problema y corregirlo, de forma periódica |
| Cuándo corre | Una vez; solo se repite si cambia el script o la asignación | Con horario: una vez, cada pocas horas o a diario |
| Si falla | Tres reintentos, uno por cada conexión del equipo, y no vuelve a intentarlo | Vuelve a correr según su horario |
| Tamaño y tiempo | Menos de 200 KB; se corta a los 30 minutos | Hasta 200 paquetes; la salida se corta a los 2.048 caracteres |
| Licencia | La de Intune | Además, Windows Enterprise E3 o E5, Education A3 o A5, o Windows VDA por usuario |
| Equipos | Unidos a Microsoft Entra ID; los solo registrados, según la página que se lea | Unidos a Microsoft Entra ID o híbridos, con Windows Enterprise, Professional o Education |
| En Graph | Solo 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ímite | Valor | Fuente |
|---|---|---|
| Escrituras sobre equipos (sincronizar, reiniciar, retirar) | 200 cada 20 s por aplicación; 400 por organización | Límites de Microsoft Graph |
| Lecturas sobre equipos | 2.000 cada 20 s por aplicación; 4.000 por organización | Límites de Microsoft Graph |
| Borrados de fábrica | 500 al día por organización | Acciones de dispositivo de Intune |
| Retiros y eliminaciones | 1.000 al día cada uno | Acciones de dispositivo de Intune |
| Acciones en bloque desde la consola | 100 equipos por acción | Acciones de dispositivo de Intune |
| Salida de una remediación | 2.048 caracteres | Remediaciones |
| Script de plataforma | Menos de 200 KB y 30 minutos | Scripts 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:
| Tema | Lo que dice un sitio | Lo que dice otro |
|---|---|---|
| Versión de la API | La guía de instalación recomienda usar siempre v1.0 en los scripts | Scripts, remediaciones y el catálogo de configuración solo existen en beta |
| Equipos solo registrados | La página de la extensión de Intune los admite | La de scripts de plataforma dice que no reciben scripts, y en otra línea explica cómo asignárselos |
| Frecuencia de las remediaciones | La misma página dice que se repiten cada 24 horas | También ofrece horarios de una vez y cada pocas horas |
| Permiso para leer scripts | La guía de la API dice que la lectura pasó a DeviceManagementScripts.ReadWrite.All | Existe DeviceManagementScripts.Read.All, y Find-MgGraphCommand lo da para las remediaciones |
| Permiso para borrar de fábrica | La página de la llamada wipe pide PrivilegedOperations.All | Find-MgGraphCommand acepta además ManagedDevices.ReadWrite.All |
| Ejemplo en C# de la guía de la API | Instala la biblioteca MSAL | El código usa AuthenticationContext, de la biblioteca anterior, ADAL |
| Conexión por código | La documentación escribe -UseDeviceAuthentication | El parámetro se llama -UseDeviceCode; el otro es un alias |
Errores frecuentes con Intune PowerShell
| Mensaje o síntoma | Causa | Qué 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 reconoce | El 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-9d5bdfd93547 | Script con el módulo antiguo, Connect-MSGraph | Reescríbalo con los módulos de Graph |
403 Forbidden | Falta el permiso, el rol de Intune o la licencia | Revise Get-MgContext, el rol de la cuenta y la licencia |
Get-MgDeviceManagementConfigurationPolicy no se reconoce | El catálogo de configuración no está en v1.0 | Use Get-MgBetaDeviceManagementConfigurationPolicy o Invoke-MgGraphRequest |
429 Too Many Requests | Se pasó el límite de la API | Agregue una pausa en el bucle, como en el escenario 3 |
| La lista trae menos equipos de los que hay | Falta -All: solo llegó la primera página | Agregue -All |
| La corrección de una remediación nunca corre | La detección no termina con exit 1 | Revise 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
- Deje el módulo antiguo. Cualquier script con
Connect-MSGraphoSelect-MgProfilehay que reescribirlo. - Instale solo los submódulos que usa, todos en la misma versión, y cargue el de beta solo donde haga falta.
- Pida el permiso mínimo. Un informe no necesita
PrivilegedOperations; sepárelo de los scripts que actúan. - Para tareas automáticas, use una aplicación con certificado, no un usuario ni un secreto en un archivo.
- Ensaye con
-WhatIftoda acción que borra o retira, y escriba el nombre de cada equipo en pantalla, porque el ensayo no lo muestra. - No use eliminar para limpiar la lista: eliminar también retira el equipo.
- Revise cada mes los equipos que no sincronizan, con el escenario 2.
- Compruebe la licencia antes de diseñar remediaciones de Intune.
- 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.




