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
First we need to handle pagination with this function
function getallpagination () {
<#
.SYNOPSIS
This function is used to grab all items from Graph API that are paginated
.DESCRIPTION
The function connects to the Graph API Interface and gets all items from the API that are paginated
.EXAMPLE
getallpagination -url "https://graph.microsoft.com/v1.0/groups"
Returns all items
.NOTES
NAME: getallpagination
#>
[cmdletbinding()]
param
(
$url
)
$response = (Invoke-MgGraphRequest -uri $url -Method Get -OutputType PSObject)
$alloutput = $response.value
$alloutputNextLink = $response."@odata.nextLink"
while ($null -ne $alloutputNextLink) {
$alloutputResponse = (Invoke-MGGraphRequest -Uri $alloutputNextLink -Method Get -outputType PSObject)
$alloutputNextLink = $alloutputResponse."@odata.nextLink"
$alloutput += $alloutputResponse.value
}
return $alloutput
}
Then grab the results
##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,upgradeEligibility,azureAdJoinType"
$reportdata = (getallpagination -url $reporturi)
$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) {
$allmembers = get-mggroupmember -All -GroupId $win11groupexist
##It exists, add members
write-host "Windows 11 Group Exists, adding members"
foreach ($compliantdevice in $compliantdevices) {
$compliantdeviceid = ($alldevices | Where-Object displayName -eq $compliantdevice).id
##Check if already in the group
write-host "Checking if $compliantdevice is already in the group"
$groupmember = ($allmembers) | 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
$allmembers = get-mggroupmember -All -GroupId $win11groupid
foreach ($compliantdevice in $compliantdevices) {
$compliantdeviceid = ($alldevices | Where-Object displayName -eq $compliantdevice).id
##Check if already in the group
write-host "Checking if $compliantdevice is already in the group"
$groupmember = ($allmembers) | where-object ID -eq $compliantdeviceid
if ($null -eq $groupmember) {
write-host "Adding $compliantdevice to the group"
new-mggroupmember -GroupId $win11groupid -DirectoryObjectId $compliantdeviceid
}
}
}
##Windows 10
if ($null -ne $win10groupexist) {
$allmembers = get-mggroupmember -All -GroupId $win10groupexist
##It exists, add members
write-host "Windows 10 Group Exists, adding members"
foreach ($noncompliantdevice in $noncompliantdevices) {
$noncompliantdeviceid = ($alldevices | Where-Object displayName -eq $noncompliantdevice).id
##Check if already in the group
write-host "Checking if $noncompliantdevice is already in the group"
$groupmember = ($allmembers) | 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
$allmembers = get-mggroupmember -All -GroupId $win10groupid
foreach ($noncompliantdevice in $noncompliantdevices) {
$noncompliantdeviceid = ($alldevices | Where-Object displayName -eq $noncompliantdevice).id
##Check if already in the group
write-host "Checking if $noncompliantdevice is already in the group"
$groupmember = ($allmembers) | 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.
A****************
Thanks a lot.
Great post.
Glad you found it useful 🙂
(Edited so the site doesn’t get flagged NSFW)
This is awesome, very clever approach. #Respect