How to get an report with all new enrolled devices

Bericht über alle neu registrierten Geräte

Den Überblick über neu registrierte Geräte in deiner Organisation zu behalten, kann eine herausfordernde Aufgabe sein, wenn du dich ausschließlich auf die Intune-Konsole verlässt. Wäre es nicht großartig, automatisch einen umfassenden Bericht per E-Mail zu erhalten? Wie du weißt, liebe ich es, Dinge zu automatisieren. In diesem Blogbeitrag schauen wir uns eine einfache und effiziente Möglichkeit an, mit PowerShell, Azure Automation Runbooks und der Microsoft Graph API einen wöchentlichen Bericht über alle neu registrierten Geräte zu erstellen. Diese automatisierte Lösung spart dir Zeit und Aufwand, sodass du dich auf wichtigere Aufgaben bei der Verwaltung der Geräte deiner Organisation konzentrieren kannst. Also, lass uns loslegen und lernen, wie du diesen wertvollen Bericht erstellst!

So erstellst du einen Bericht über alle neu registrierten Geräte

Wie kommst du an das Skript?

Du findest das Skript in meinem GitHub-Repository. Bevor du das Skript ausführst, musst du die Absender- und Empfänger-E-Mail-Adresse anpassen:

So erstellst du einen Bericht über alle neu registrierten Geräte

Was ist der Zweck des Skripts?

Dieses PowerShell-Skript ruft alle in den letzten 7 Tagen registrierten Geräte ab, erstellt daraus eine CSV-Datei und hängt die CSV an eine E-Mail an.

Wie kann ich den Bericht planen?

Um den Bericht zu planen, kannst du ein Azure Automation Runbook erstellen und dich über eine App-Registrierung authentifizieren. Das Einzige, was du tun musst, ist, den Inhalt des Skripts in das Runbook einzufügen.

Wie erstellst du die Automatisierung?

Eine App-Registrierung erstellen

  • Suche nach Microsoft Entra ID
So erstellst du einen Bericht über alle neu registrierten Geräte
  • Wähle App registration
So erstellst du einen Bericht über alle neu registrierten Geräte
  • Wähle +New registration
So erstellst du einen Bericht über alle neu registrierten Geräte
  • Gib einen Namen ein und klicke auf Register
So erstellst du einen Bericht über alle neu registrierten Geräte
  • Klicke auf API permissions und +Add a permission
So erstellst du einen Bericht über alle neu registrierten Geräte
  • Wähle Microsoft Graph
So erstellst du einen Bericht über alle neu registrierten Geräte
  • Wähle Application permissions
So erstellst du einen Bericht über alle neu registrierten Geräte
  • Suche nach DeviceManagementApps.Read.All & Mail.Send
So erstellst du einen Bericht über alle neu registrierten Geräte
  • Klicke auf Grant admin consent for *** und bestätige mit Yes
So erstellst du einen Bericht über alle neu registrierten Geräte
  • Wähle Certificates & secrets und klicke auf +New client secret
So erstellst du einen Bericht über alle neu registrierten Geräte
  • Gib eine Description ein und wähle eine Expires time
  • Klicke auf Add
So erstellst du einen Bericht über alle neu registrierten Geräte
  • Kopiere und speichere den Value und die Secret ID
So erstellst du einen Bericht über alle neu registrierten Geräte

Automation Account erstellen

  • Suche nach Automation Accounts
So erstellst du einen Bericht über alle neu registrierten Geräte
  • Klicke auf + Create
So erstellst du einen Bericht über alle neu registrierten Geräte
  • Wähle ein Subscription und eine Resource group
  • Gib einen account name ein und wähle eine Region
  • Klicke auf Next
So erstellst du einen Bericht über alle neu registrierten Geräte
  • Klicke auf Next
So erstellst du einen Bericht über alle neu registrierten Geräte
  • Klicke auf Next -> Next -> Create
So erstellst du einen Bericht über alle neu registrierten Geräte

Das Runbook erstellen

  • Öffne das Automation Account
  • Navigiere zu Variables und klicke auf + Add a variable
  • Füge den Secret ValueTenantId und die App ID als Variable hinzu
  • So erstellst du einen Bericht über alle neu registrierten Geräte
  • So erstellst du einen Bericht über alle neu registrierten Geräte
  • So erstellst du einen Bericht über alle neu registrierten Geräte
  • So erstellst du einen Bericht über alle neu registrierten Geräte
  • So erstellst du einen Bericht über alle neu registrierten Geräte
  • So erstellst du einen Bericht über alle neu registrierten Geräte
  • Wähle Runbooks
  • Klicke auf + Create a runbook
So erstellst du einen Bericht über alle neu registrierten Geräte
  • Gib einen Name ein
  • Wähle PowerShell als Runbook-Typ
  • Wähle 5.1 als Runtime-Version
  • Klicke auf Create
So erstellst du einen Bericht über alle neu registrierten Geräte
  • Füge das Skript aus meinem Github-Repository ein
  • Trage im Skript die Absender- und Empfänger-E-Mail ein
So erstellst du einen Bericht über alle neu registrierten Geräte
  • Speichere und teste das Skript
So erstellst du einen Bericht über alle neu registrierten Geräte
So erstellst du einen Bericht über alle neu registrierten Geräte
  • Klicke auf Publish
So erstellst du einen Bericht über alle neu registrierten Geräte
  • Navigiere zu Schedules und klicke auf + Add a schedule
So erstellst du einen Bericht über alle neu registrierten Geräte
So erstellst du einen Bericht über alle neu registrierten Geräte
  • Klicke auf Link to schedule und füge den erstellten schedule hinzu
So erstellst du einen Bericht über alle neu registrierten Geräte
So erstellst du einen Bericht über alle neu registrierten Geräte

Skript

<#
Version: 1.0
Author: Jannik Reinhard (jannikreinhard.com)
Script: Get-NewEnrolledDevicesReport
Description:
Get Email with new enrolled devices
Release notes:
Version 1.0: Init
#>


function Get-AuthHeader{
    param (
        [parameter(Mandatory=$true)]$tenantId,
        [parameter(Mandatory=$true)]$clientId,
        [parameter(Mandatory=$true)]$clientSecret
       )

    $authBody=@{
        client_id=$clientId
        client_secret=$clientSecret
        scope="https://graph.microsoft.com/.default"
        grant_type="client_credentials"
    }

    $uri="https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token"
    $accessToken=Invoke-WebRequest -Uri $uri -ContentType "application/x-www-form-urlencoded" -Body $authBody -Method Post -ErrorAction Stop -UseBasicParsing
    $accessToken=$accessToken.content | ConvertFrom-Json

    $authHeader = @{
        'Content-Type'='application/json'
        'Authorization'="Bearer " + $accessToken.access_token
        'ExpiresOn'=$accessToken.expires_in
    }

    return $authHeader
}

#################################################################################################
########################################### Start ###############################################
#################################################################################################
# Variables
$MailSender = "mail@abc.onmicrosoft.com"
$MailTo = "mail@abc.onmicrosoft.com"

# Automation Secrets
$tenantId = Get-AutomationVariable -Name 'TenantId'
$clientId = Get-AutomationVariable -Name 'AppId'
$clientSecret = Get-AutomationVariable -Name 'AppSecret'


$global:authToken = Get-AuthHeader -tenantId $tenantId -clientId $clientId -clientSecret $clientSecret

# Define the time range
$endDate = Get-Date
$startDate = $endDate.AddDays(-7)
$filter = "enrolledDateTime gt $($startDate.ToString("yyyy-MM-ddTHH:mm:ssZ"))&enrolledDateTime le $($endDate.ToString("yyyy-MM-ddTHH:mm:ssZ"))"

# Query Intune devices enrolled in the past week
$graphApiUrl = "https://graph.microsoft.com/v1.0/deviceManagement/managedDevices"
$graphApiQuery = "?`$filter=$filter&`$select=id,deviceName,operatingSystem,enrolledDateTime,userPrincipalName,model"
$uri = $graphApiUrl + $graphApiQuery
$response = Invoke-RestMethod -Method Get -Uri $uri -Headers $global:authToken

# Generate CSV report
$reportPath = "NewEnrolledDevicesReport.csv"
$response.value | Select-Object id,deviceName,operatingSystem,enrolledDateTime,userPrincipalName,model | Export-Csv -Path $reportPath -NoTypeInformation
$csv = [Convert]::ToBase64String([IO.File]::ReadAllBytes(".\$reportPath"))

#Send Mail
$URLsend = "https://graph.microsoft.com/v1.0/users/$MailSender/sendMail"
$BodyJsonsend = @"
{
    "message": {
      "subject": "New enrolled devices",
      "body": {
        "contentType": "Text",
        "content": "Dear Admin, this Mail contains the enrolled devices from the previous 7 days"
      },
      "toRecipients": [
        {
          "emailAddress": {
            "address": "$MailTo"
          }
        }
      ],
      "attachments": [
        {
          "@odata.type": "#microsoft.graph.fileAttachment",
          "name": "newEnrolledDevicesReport.csv",
          "contentType": "text/plain",
          "contentBytes": "$csv"
        }
      ]
    }
  }
"@


Invoke-RestMethod -Method POST -Uri $URLsend -Headers $global:authToken -Body $BodyJsonsend

Häufige Fehler und Tipps

Wenn du den Bericht über alle neu registrierten Geräte zum ersten Mal einrichtest, sorgen meist ein paar Kleinigkeiten für die größten Probleme. Der erste Punkt sind die API-Berechtigungen. Das Skript liest verwaltete Geräte aus, daher braucht die App-Registrierung zusätzlich zu Mail.Send auch DeviceManagementManagedDevices.Read.All, und du musst anschließend auf Grant admin consent klicken. Vergisst du die Zustimmung, wird zwar ein Token ausgestellt, aber jeder Graph-Aufruf endet mit einem 403, was verwirrend sein kann, weil die Authentifizierung selbst erfolgreich aussieht.

Der zweite Stolperstein ist das Client Secret. Secrets laufen ab, wähle also eine realistische Gültigkeitsdauer und setze dir eine Erinnerung, das Secret rechtzeitig vor dem Ablauf zu erneuern. Wenn dein wöchentlicher Bericht plötzlich ausbleibt, ist ein abgelaufenes Secret der wahrscheinlichste Grund. Es hat sich bewährt, das Secret als verschlüsselte Automation-Variable zu speichern, statt es fest in das Runbook zu schreiben, genau wie oben gezeigt, damit du es an einer Stelle aktualisieren kannst, ohne das Skript anzufassen.

Teste das Runbook außerdem einmal manuell, bevor du es mit einem Zeitplan verknüpfst. Nutze dazu den Test-Bereich im Automation Account, um zu prüfen, ob die E-Mail zugestellt wird und sich der CSV-Anhang korrekt öffnen lässt. Sobald das funktioniert, läuft der wöchentliche Zeitplan völlig automatisch. Verwaltest du mehrere Tenants, klonst du das Runbook einfach pro Automation Account und passt die drei Variablen an, und schon hast du einen sauberen, wiederholbaren Bericht über alle neu registrierten Geräte für deine gesamte Umgebung.

Fazit

Zusammenfassend lässt sich sagen, dass die Automatisierung des Prozesses zur Erstellung und zum Versand von Berichten über neu registrierte Geräte Zeit und Aufwand spart und sicherstellt, dass du beim Geräte-Management stets auf dem neuesten Stand bleibst. Indem du die in diesem Beitrag beschriebenen Schritte befolgst, kannst du ganz einfach einen automatisierten Bericht einrichten, der dich über die Geräteregistrierung in deiner Organisation informiert. Probiere es aus und erlebe die Vorteile der Automatisierung aus erster Hand.

Passe das Fazit gerne nach Belieben an oder lass es mich wissen, wenn du weitere Unterstützung benötigst.

5 thoughts on “Bericht über alle neu registrierten Geräte

  1. Hi Jannik, thank you for this!
    I am experiencing this error after testing the Runbook,.
    The csv file does exist but it is empty.

    Completed

    The remote server returned an error: (401) Unauthorized.
    Cannot bind argument to parameter ‘InputObject’ because it is null.
    Object reference not set to an instance of an object.
    System.Management.Automation.MethodInvocationException: Exception calling “ReadAllBytes” with “1” argument(s): “Could not find file ‘C:\Windows\System32\NewEnrolledDevicesReport.csv’.” —> System.IO.FileNotFoundException: Could not find file ‘C:\Windows\System32\NewEnrolledDevicesReport.csv’.
    at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
    at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
    at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
    at System.IO.File.InternalReadAllBytes(String path, Boolean checkHost)
    at CallSite.Target(Closure , CallSite , Type , String )
    — End of inner exception stack trace —
    at System.Management.Automation.ExceptionHandlingOps.ConvertToMethodInvocationException(Exception exception, Type typeToThrow, String methodName, Int32 numArgs, MemberInfo memberInfo)
    at CallSite.Target(Closure , CallSite , Type , String )
    at System.Dynamic.UpdateDelegates.UpdateAndExecute2[T0,T1,TRet](CallSite site, T0 arg0, T1 arg1)
    at System.Management.Automation.Interpreter.DynamicInstruction`3.Run(InterpretedFrame frame)
    at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
    Object reference not set to an instance of an object.

    • Same here: The remote server returned an error: (403) Forbidden.
      System.Management.Automation.MethodInvocationException: Exception calling “ReadAllBytes” with “1” argument(s): “Could not find file ‘C:\Windows\System32\NewEnrolledDevicesReport.csv’.” —> System.IO.FileNotFoundException: Could not find file ‘C:\Windows\System32\NewEnrolledDevicesReport.csv’.
      at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
      at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
      at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
      at System.IO.File.InternalReadAllBytes(String path, Boolean checkHost)
      at CallSite.Target(Closure , CallSite , Type , String )
      — End of inner exception stack trace —
      at System.Management.Automation.ExceptionHandlingOps.ConvertToMethodInvocationException(Exception exception, Type typeToThrow, String methodName, Int32 numArgs, MemberInfo memberInfo)
      at CallSite.Target(Closure , CallSite , Type , String )
      at System.Dynamic.UpdateDelegates.UpdateAndExecute2[T0,T1,TRet](CallSite site, T0 arg0, T1 arg1)
      at System.Management.Automation.Interpreter.DynamicInstruction`3.Run(InterpretedFrame frame)
      at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
      The remote server returned an error: (400) Bad Request.

Comments are closed.