Dynamic security groups in Azure AD are great, but wouldn’t it be great if a dynamic query existed to add to groups based on Windows 11 compatibility.
Until such a query exists, I have put together a script using the metrics from Endpoint Analytics Work from Anywhere report.
As usual, the script can be found on GitHub here
To make it as dynamic as possible, I would recommend using Azure Automation Runbook to run regularly (obviously with an app registration)
After connecting to Graph, it creates two lists of machines, compliant and non-compliant
##Get Devices compliant/not compliant with windows 11
write-host "Inspecting devices for Windows 11 compliance"
$reporturi = "https://graph.microsoft.com/beta/deviceManagement/userExperienceAnalyticsWorkFromAnywhereMetrics('allDevices')/metricDevices?`$select=id,deviceName,managedBy,manufacturer,model,osDescription,osVersion,upgradeEligibility,azureAdJoinType,upgradeEligibility,ramCheckFailed,storageCheckFailed,processorCoreCountCheckFailed,processorSpeedCheckFailed,tpmCheckFailed,secureBootCheckFailed,processorFamilyCheckFailed,processor64BitCheckFailed,osCheckFailed&dtFilter=all&`$orderBy=osVersion asc"
$reportdata = (invoke-mggraphrequest -uri $reporturi -method GET).value
$compliantdevices = @()
$noncompliantdevices = @()
write-host "Checking Machines for Compatibility"
$counter = 0
foreach ($machine in $reportdata) {
$counter++
$deviceid = $machine.id
Write-Progress -Activity 'Processing Devices' -CurrentOperation $deviceid -PercentComplete (($counter / $reportdata.count) * 100)
$w11compliance = $machine.upgradeEligibility
if ($w11compliance -eq "Capable") {
$compliantdevices += $machine.deviceName
}
else {
$noncompliantdevices += $machine.deviceName
}
}
Next, it checks if the groups exist already and if not creates the two groups.
After creating, it checks if the machine is in the group and if not, adds it in
write-host "Creating AAD Groups"
##Create AAD Groups
write-host "Creating Windows 11 Group"
$win11groupexist = (get-mggroup -filter "displayName eq '$w11groupname'").id
write-host "Creating Windows 10 Group"
$win10groupexist = (get-mggroup -filter "displayName eq '$w10groupname'").id
##Windows 11
##Check if group exists
write-host "Checking if Windows 11 Group Exists"
if ($null -ne $win11groupexist) {
##It exists, add members
write-host "Windows 11 Group Exists, adding members"
foreach ($compliantdevice in $compliantdevices) {
$compliantdeviceid = (Get-MgDevice -Filter "displayName eq '$compliantdevice'").id
##Check if already in the group
write-host "Checking if $compliantdevice is already in the group"
$groupmember = (get-mggroupmember -GroupId $win11groupexist) | where-object ID -eq $compliantdeviceid
if ($null -eq $groupmember) {
write-host "Adding $compliantdevice to the group"
new-mggroupmember -GroupId $win11groupexist -DirectoryObjectId $compliantdeviceid
}
}
}
else {
##Does not, create it first
write-host "Windows 11 Group does not exist, creating it"
$win11group = new-mggroup -DisplayName $w11groupname -Description "Devices Compliant with Windows 11" -SecurityEnabled -mailEnabled:$false -MailNickname $w11groupname
$win11groupid = $win11group.id
foreach ($compliantdevice in $compliantdevices) {
$compliantdeviceid = (Get-MgDevice -Filter "displayName eq '$compliantdevice'").id
##Check if already in the group
write-host "Checking if $compliantdevice is already in the group"
$groupmember = (get-mggroupmember -GroupId $win11groupid) | where-object ID -eq $compliantdeviceid
if ($null -eq $groupmember) {
write-host "Adding $compliantdevice to the group"
new-mggroupmember -GroupId $win11groupid -DirectoryObjectId $compliantdeviceid
}
}
}
##Windows 10
##Check if group exists
write-host "Checking if Windows 10 Group Exists"
if ($null -ne $win10groupexist) {
##It exists, add members
write-host "Windows 10 Group Exists, adding members"
foreach ($noncompliantdevice in $noncompliantdevices) {
$noncompliantdeviceid = (Get-MgDevice -Filter "displayName eq '$noncompliantdevice'").id
##Check if already in the group
write-host "Checking if $noncompliantdevice is already in the group"
$groupmember = (get-mggroupmember -GroupId $win10groupexist) | where-object ID -eq $noncompliantdeviceid
if ($null -eq $groupmember) {
write-host "Adding $noncompliantdevice to the group"
new-mggroupmember -GroupId $win10groupexist -DirectoryObjectId $noncompliantdeviceid
}
}
}
else {
##Does not, create it first
write-host "Windows 10 Group does not exist, creating it"
$win10group = new-mggroup -DisplayName $w10groupname -Description "Devices Not Compliant with Windows 10" -SecurityEnabled -MailEnabled:$false -MailNickname $w10groupname
$win10groupid = $win10group.id
foreach ($noncompliantdevice in $noncompliantdevices) {
$noncompliantdeviceid = (Get-MgDevice -Filter "displayName eq '$noncompliantdevice'").id
##Check if already in the group
$groupmember = (get-mggroupmember -GroupId $win10groupid) | where-object ID -eq $noncompliantdeviceid
if ($null -eq $groupmember) {
write-host "Adding $noncompliantdevice to the group"
new-mggroupmember -GroupId $win10groupid -DirectoryObjectId $noncompliantdeviceid
}
}
}
I then use these groups to assign and exclude against Feature Update policies, but whatever works for you.
This is awesome, very clever approach. #Respect