Windows-11-Upgrades mit Intune verfolgen
Erfahre, wie du mit einem Azure Automation Runbook und Microsoft Intune einen Bericht zur Verfolgung von Windows-11-Upgrades erstellst.

Im heutigen Blog gehe ich auf eine Frage eines unserer Community-Mitglieder ein, das einen Bericht zur Verfolgung von Windows-11-Upgrades über ein Azure Automation Runbook und Microsoft Intune erstellen möchte. Er hat versucht, die Details der registrierten Geräte mit einem Runbook zu erfassen, aber bisher keine Lösung gefunden. In diesem Beitrag zeigen wir, wie du mit Intune und Azure Automation einen Bericht zur Verfolgung von Windows-11-Upgrades erstellst.

Inhalt
Warum das Verfolgen von Windows-11-Upgrades wichtig ist
Das Verfolgen von Windows-11-Upgrades liefert Administratoren echte, verwertbare Daten statt bloßer Vermutungen. Da Windows 10 das Ende des Supports erreicht, braucht jede Organisation eine verlässliche Möglichkeit, die Compliance nachzuweisen und die verbleibenden Geräte zu priorisieren. Microsoft dokumentiert den offiziellen Zeitplan zum Support-Ende auf Microsoft Learn, was eine gute Referenz ist, wenn du deine Reporting-Strategie rund um das Verfolgen von Windows-11-Upgrades aufbaust.
Der nachfolgende Ansatz versendet eine geplante E-Mail mit einem Tortendiagramm und einer vollständigen Geräteliste und macht das Verfolgen von Windows-11-Upgrades so zu einem freihändigen Prozess, der von selbst läuft und direkt in deinem Posteingang landet. So musst du den Bericht nicht manuell zusammenstellen und kannst dich darauf verlassen, dass die Zahlen jede Woche aktuell sind.
Wie du ein Azure Automation Account erstellst
Ich habe bereits einen sehr ausführlichen Blog darüber geschrieben, wie du mit Azure Automation und Runbooks startest. Am besten liest du diesen Blog zuerst. Du musst sicherstellen, dass das Modul Graph.Authentication installiert ist, und du benötigst die folgenden Graph-API-Berechtigungen:
- Mail.Send
- DeviceManagementManagedDevices.Read.All
Wie du den Bericht erhältst
Du findest das Skript in meinem GitHub-Repository oder hier. Du musst das Skript in dein Runbook kopieren:
# Variables
$MailTo = ""
$MailSender = ""
# Authenticate and connect to Microsoft Graph
Connect-AzAccount -Identity
$token = Get-AzAccessToken -ResourceUrl "https://graph.microsoft.com"
#Connect to Microsoft Graph API
Connect-MgGraph -AccessToken $token.Token
# Get Windows devices from Intune
$devices = Get-MgDeviceManagementManagedDevice -all -Filter "contains(operatingSystem,'Windows')"
# Filter Windows 11 devices
$windows11Devices = $devices | Where-Object { $_.OsVersion -ge "10.0.22000" }
# Calculate device counts
$totalDevices = $devices.Count
$windows11DevicesCount = $windows11Devices.Count
# Calculate pie chart percentages
$windows11Percentage = ($windows11DevicesCount / $totalDevices) * 100
$otherWindowsPercentage = 100 - $windows11Percentage
# Create HTML report
$html = @"
<style>
body {
font-family: Arial, sans-serif;
}
h1 {
font-size: 28px;
color: #0078d4;
margin-top: 0;
text-align: center;
}
.chart-container {
display: flex;
flex-wrap: wrap;
justify-content: center;
}
.pie-chart {
width: 300px;
height: 300px;
margin: 20px;
}
.device-list {
margin-top: 40px;
}
table {
border-collapse: collapse;
width: 100%;
}
th {
background-color: #0078d4;
color: #fff;
font-weight: bold;
padding: 8px;
text-align: left;
}
td {
border: 1px solid #ddd;
padding: 8px;
}
tr:nth-child(even) {
background-color: #f2f2f2;
}
</style>
<h1>Windows 11 Adoption Report</h1>
<div class="chart-container">
<div class="pie-chart">
<canvas id="chart"></canvas>
</div>
</div>
<div class="device-list">
<table>
<thead>
<tr>
<th>Device Name</th>
<th>User</th>
<th>Last Sync DateTime</th>
<th>OSVersion</th>
</tr>
</thead>
<tbody>
"@
foreach ($device in $devices) {
$html += "<tr><td>$($device.DeviceName)</td><td>$($device.EmailAddress)</td><td>$($device.LastSyncDateTime)</td><td>$($device.OSVersion)</td></tr>"
}
$html += @"
</tbody>
</table>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
var ctx = document.getElementById('chart').getContext('2d');
var chart = new Chart(ctx, {
type: 'pie',
data: {
labels: ['Windows 11', 'Other Windows'],
datasets: [{
backgroundColor: ['#0078d4', '#f2f2f2'],
data: [$windows11Percentage, $otherWindowsPercentage]
}]
},
options: {
legend: {
display: true,
position: 'bottom',
labels: {
fontColor: '#333',
fontSize: 14,
padding: 16
}
}
}
});
</script>
"@
$html | Out-File -FilePath "Windows11AdoptionReport.html"
$base64 = [Convert]::ToBase64String([IO.File]::ReadAllBytes(".\Windows11AdoptionReport.html"))
#Send Mail
$URLsend = "https://graph.microsoft.com/v1.0/users/$MailSender/sendMail"
$BodyJsonsend = @"
{
"message": {
"subject": "Intune error report",
"body": {
"contentType": "Text",
"content": "Dear Admin, this Mail contains the Windows 11 Adoption report"
},
"toRecipients": [
{
"emailAddress": {
"address": "$MailTo"
}
}
],
"attachments": [
{
"@odata.type": "#microsoft.graph.fileAttachment",
"name": "Windows11AdoptionReport.html",
"contentType": "text/plain",
"contentBytes": "$base64"
}
]
}
}
"@
$response = Invoke-MgRestMethod -Method POST -Uri $URLsend -Body $BodyJsonsend
Ein kurzer Hinweis dazu, wie das Skript entscheidet, was als Windows 11 zählt: Es vergleicht die Eigenschaft OsVersion mit der Buildnummer 10.0.22000, also dem ersten Windows-11-Release. Alles ab diesem Build wird als Windows 11 gewertet, alles darunter weiterhin als Windows 10. Wenn du nur ein bestimmtes Feature-Update wie 23H2 verfolgen möchtest, erhöhst du einfach den Schwellenwert auf die passende Buildnummer, und der Bericht berechnet die Prozentwerte automatisch neu.
Du musst die E-Mail-Adressen von Absender und Empfänger in diese Variablen eintragen:
$MailTo = ""
$MailSender = ""
Das war es schon. Wenn du dieses Runbook so planst, dass es täglich oder wöchentlich läuft, wird das Verfolgen von Windows-11-Upgrades zu einer vollständig automatisierten Routine, die einen klaren, visuellen Bericht direkt in deinen Posteingang liefert. Möchtest du die Lösung erweitern, kannst du nach Gruppen filtern oder die Daten in ein Dashboard schreiben.
Ein praktischer Tipp für den Betrieb: Lege im Runbook einen Zeitplan an, der zum Rhythmus deiner Deployment-Ringe passt – wöchentlich am Montagmorgen ist für die meisten Teams ein guter Startpunkt, weil der Bericht dann pünktlich zum Wochenstart bereitliegt. So kannst du in der Statusrunde direkt über den aktuellen Fortschritt der Migration sprechen, ohne vorher Daten manuell aufbereiten zu müssen, und erkennst sofort, welche Geräte noch auf Windows 10 hängen.
Häufige Stolpersteine: Das häufigste Problem ist eine verwaltete Identität, der eine der beiden Graph-Berechtigungen fehlt, sodass die Geräteabfrage leer bleibt oder der Mailversand stillschweigend fehlschlägt. Stelle daher sicher, dass sowohl DeviceManagementManagedDevices.Read.All als auch Mail.Send erteilt und administrativ zugestimmt sind. Ein zweiter Stolperstein ist eine Division durch null, wenn der Tenant noch keine Windows-Geräte enthält, weshalb es sich beim ersten Test lohnt, die Prozentberechnung abzusichern. Denke außerdem daran, dass das Runbook den HTML-Bericht in das temporäre Arbeitsverzeichnis schreibt, das nach jedem Job geleert wird – die Datei muss also nur lange genug existieren, um an die E-Mail angehängt zu werden.
Kommentare
Nice work Jannikreinhard.
Hey Jannik, I have been following the steps outlined in this however I seem to be running into an issue with the access token explaining you must specify access token, any ideas please?
There was something missing in the script. I have fixed this
Hey Jannik, I managed to work around it via a similar way but appreciate this. I also come into the following issue which I didn’t manage to bug System.Management.Automation.MethodInvocationException: Exception calling “ReadAllBytes” with “1” argument(s): “Could not find file ‘C:\Windows\System32\Windows11AdoptionReport.html’.” —> System.IO.FileNotFoundException: Could not find file ‘C:\Windows\System32\Windows11AdoptionReport.html’. It doesn’t seem to Output the file so can’t find it.
The script works fine at outputting the file to the windows\system32 folder when ran locally however seems to be having issue in the runbook
Hey Jannik, I’ve got the same problem as Jack with the file not writing out. I also have an issue that my registered application can’t send mail as the user. How did you manage the credentials/permissions for this in your environment?
Do you have an error code
I get a 401 Unauthorised
Hi Kristen, I managed the credentials for the application by following Janniks guide using the below
Install-Module Microsoft.Graph -Scope CurrentUser
Connect-MgGraph -Scopes Application.Read.All, AppRoleAssignment.ReadWrite.All, RoleManagement.ReadWrite.Directory
$managedIdentityId = “Managed Identity Object ID”
$roleName = “DeviceManagementApps.Read.All”
$msgraph = Get-MgServicePrincipal -Filter “AppId eq ‘00000003-0000-0000-c000-000000000000′”
$role = $Msgraph.AppRoles| Where-Object {$_.Value -eq $roleName}
New-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $managedIdentityId -PrincipalId $managedIdentityId -ResourceId $msgraph.Id -AppRoleId $role.Id
Disconnect-MgGraph
My error that I am getting for the output-file is System.Management.Automation.MethodInvocationException: Exception calling “ReadAllBytes” with “1” argument(s): “Could not find file ‘C:\Windows\System32\Windows11AdoptionReport.html’.” —> System.IO.FileNotFoundException: Could not find file ‘C:\Windows\System32\Windows11AdoptionReport.html’. It doesn’t seem to Output the file so can’t find it.
Hey Jannik, did you manage to find out what may be the cause of the runbook not outputting the html file?
Many Thanks