I got a few question related to a module I'm unfamiliar with Thank you all in advance for any help.
First off here is my code:
Import-Module Microsoft.Graph.Identity.Governance
Import-Module Microsoft.Graph.Identity.DirectoryManagement
Import-Module Microsoft.Graph.Authentication
connect-mggraph -Scopes "Group.ReadWrite.All,RoleManagement.ReadWrite.Directory" -Tenant "TenantId"
$GroupList = Import-CSV -path "PathHere"
foreach ($Group in $GroupList) {
#Convert variables for easier handling
$Name = $Group.Name
$NickName = $Group.NickName
$AuName = $Group.AU
#Make a new role enabled group and grab its object id
$Id = New-MgGroup -DisplayName $Name -MailEnabled:$False -MailNickName $NickName -SecurityEnabled -IsAssignableToRole -Visibility "Private" | Select Id
#Get the object id of an Admin unit I made earlier
$AdminUnit = Get-MgDirectoryAdministrativeUnit -Filter "DisplayName eq '$AuName'" | Select Id
#This part is stolen from Microsoft documentation
$params = @{
"@odata.type" = "#microsoft.graph.unifiedRoleAssignment"
#Auth Admin
roleDefinitionId = "c4e39bd9-1100-46d3-8c65-fb160da0071f"
principalId = $Id
directoryScopeId = "/administrativeUnits/{0}" -f $AdminUnit
}
New-MgRoleManagementDirectoryRoleAssignment -BodyParameter $params
}
With my above Code I'm getting the following error.
New-MgRoleManagementDirectoryRoleAssignment : Invalid GUID:@{Id=0c504d37-f6f7-4223-a8f5-ec086a6ba272}
Status: 400 (BadRequest)
I think it's not liking the $Id variable I'm passing to it, however it's clearly providing the correct Object Id so I think it may be a formatting issue. I'm unsure what to do to correct it however so if anyone could provide some insight there I would appreciate it.
Secondly, I do not think
directoryScopeId = "/administrativeUnits/{0}" -f $AdminUnit
Is going to work so this is a preemptive "is there a better way to feed a variable into a string?"
My third and final question, is there a better way to achieve this overall via PowerShell? My end goal is to assign a built in role to a single Group, and then scope that to a single Admin Unit and then work through an entire list of these. Is there a better module I could use for this or a more efficient way to logic this out?
The issue with your code is that in both cases you're missing -ExpandProperty
in the Select-Object
calls, because of that instead of getting a value you end up with an object having a single property (Id
). Then $Id
and $AdminUnit
are passed as stringified objects causing the API response error. You can also clearly see it when looking at the API response:
Invalid GUID:@{Id=0c504d37-f6f7-4223-a8f5-ec086a6ba272}
The @{...}
happens when a custom object is converted to a string.
As for the final question, a more efficient way to do it, this depends. The API to create groups will only allow to create single group per call, however you could create them in parallel using ForEach-Object -Parallel
or by using the $batch
API, in both cases the code will get much more complex, for the former you will need to handle TooManyRequests (429)
API responses and for the latter you will not be able to use the cmdlets, will need to construct the API calls yourself. One improvement, assuming the AUs are repeated, is to add a caching mechanism so you don't query for them more than one time (added in the code).
Aside from that the code looks correct, it might be also worth adding a guard clause in case the AU couldn't be found.
# defines a hashtable (the caching mechanism named before)
$aus = @{}
foreach ($Group in $GroupList) {
#Make a new role enabled group and grab its object id
$newMgGroupSplat = @{
DisplayName = $Group.Name
MailEnabled = $False
MailNickName = $Group.NickName
SecurityEnabled = $true
IsAssignableToRole = $true
Visibility = 'Private'
}
$mgGroup = New-MgGroup @newMgGroupSplat
# if the AU doesnt exist in the hashtable
if (-not $aus.ContainsKey($Group.AU)) {
# query it
$au = Get-MgDirectoryAdministrativeUnit -Filter "DisplayName eq '$($Group.AU)'"
# if its not found
if (-not $au) {
# go to the next loop iteration
Write-Warning "'$($Group.AU)' could not be found."
return
}
# else, add it to the hashtable (Key = DisplayName // Value = AU ID)
$aus[$Group.Id] = $au.Id
}
#This part is stolen from Microsoft documentation
$params = @{
'@odata.type' = '#microsoft.graph.unifiedRoleAssignment'
roleDefinitionId = 'c4e39bd9-1100-46d3-8c65-fb160da0071f'
principalId = $mgGroup.Id
directoryScopeId = '/administrativeUnits/{0}' -f $aus[$Group.Id]
}
New-MgRoleManagementDirectoryRoleAssignment -BodyParameter $params
}