Microsoft Entra ID의 그룹 기반 라이선스에 대한 PowerShell 및 Microsoft Graph 예제
Microsoft Entra ID의 그룹 기반 라이선스에 대한 전체 기능은 Azure Portal을 통해 사용할 수 있으며, 현재 기존 Microsoft Graph 및 Microsoft Graph PowerShell을 사용하여 수행할 수 있는 몇 가지 유용한 작업이 있습니다. 이 문서는 가능한 작업에 대한 예제를 제공합니다.
참고 항목
cmdlet 실행을 시작하기 전에 먼저 Connect-MgGraph cmdlet을 실행하여 조직에 연결해야 합니다.
Warning
이 코드는 데모 용도의 예로 제공됩니다. 사용자 환경에서 사용하려는 경우, 먼저 작은 규모로 테스트하거나 별도의 테스트 조직에서 테스트하는 것이 좋습니다. 환경의 특정 요구에 맞게 코드를 조정해야 할 수도 있습니다.
그룹에 라이선스 할당
다음 샘플을 사용하여 Microsoft Graph를 통해 그룹에 라이선스를 할당합니다.
POST https://graph.microsoft.com/v1.0/groups/1ad75eeb-7e5a-4367-a493-9214d90d54d0/assignLicense
Content-type: application/json
{
"addLicenses": [
{
"disabledPlans": [ "11b0131d-43c8-4bbb-b2c8-e80f9a50834a" ],
"skuId": "c7df2760-2c81-4ef7-b578-5b5392b571df"
},
{
"disabledPlans": [ "a571ebcc-fqe0-4ca2-8c8c-7a284fd6c235" ],
"skuId": "sb05e124f-c7cc-45a0-a6aa-8cf78c946968"
}
],
"removeLicenses": []
}
출력:
HTTP/1.1 202 Accepted
Content-type: application/json
location: https://graph.microsoft.com/v2/d056d009-17b3-4106-8173-cd3978ada898/directoryObjects/1ad75eeb-7e5a-4367-a493-9214d90d54d0/Microsoft.DirectoryServices.Group
{
"id": "1ad75eeb-7e5a-4367-a493-9214d90d54d0",
"deletedDateTime": null,
"classification": null,
"createdDateTime": "2018-04-18T22:05:03Z",
"securityEnabled": true,
}
그룹에 할당된 제품 라이선스 보기
Get-MgGroup cmdlet을 사용하여 그룹 개체를 검색하고 AssignedLicenses 속성을 확인할 수 있습니다. 현재 그룹에 할당된 모든 제품 라이선스가 나열됩니다.
# Define the group ID
$groupId = "99c4216a-56de-42c4-a4ac-e411cd8c7c41"
# Get the group with the specified ID and its assigned licenses
$group = Get-MgGroup -GroupId $groupId -Property "AssignedLicenses"
# Extract the assigned licenses
$assignedLicenses = $group | Select-Object -ExpandProperty AssignedLicenses
# Extract the SKU IDs from the assigned licenses
$skuIds = $assignedLicenses | Select-Object -ExpandProperty SkuId
# For each SKU ID, get the corresponding SKU part number
$skuPartNumbers = $skuIds | ForEach-Object {
$skuId = $_
$subscribedSku = Get-MgSubscribedSku | Where-Object { $_.SkuId -eq $skuId }
$skuPartNumber = $subscribedSku | Select-Object -ExpandProperty SkuPartNumber
$skuPartNumber
}
# Output the SKU part numbers
$skuPartNumbers
다음은 결과입니다.
SkuPartNumber
-------------
ENTERPRISEPREMIUM
EMSPREMIUM
참고 항목
여기서 다시 조정된 데이터는 제품(SKU) 정보로 제한됩니다. 라이선스에서 비활성화된 서비스 계획 목록을 생성하려면 그룹 라이선스에 대한 Microsoft Graph PowerShell 예제를 참조하세요.
다음 샘플을 사용하여 Microsoft Graph에서 동일한 데이터를 가져옵니다.
GET https://graph.microsoft.com/v1.0/groups/99c4216a-56de-42c4-a4ac-e411cd8c7c41?$select=assignedLicenses
출력:
HTTP/1.1 200 OK
{
"value": [
{
"assignedLicenses": [
{
"accountId":"aaaaaaaa-0000-1111-2222-bbbbbbbbbbbb",
"skuId":"c7df2760-2c81-4ef7-b578-5b5392b571df",
"disabledPlans":[]
},
{
"accountId":"aaaaaaaa-0000-1111-2222-bbbbbbbbbbbb",
"skuId":" b05e124f-c7cc-45a0-a6aa-8cf78c946968",
"disabledPlans":[]
},
],
}
]
}
라이선스가 있는 모든 그룹 가져오기
다음 명령을 실행하면 라이선스가 할당되어 있는 모든 그룹을 찾을 수 있습니다.
Get-MgGroup -All -Property Id, MailNickname, DisplayName, GroupTypes, Description, AssignedLicenses | Where-Object {$_.AssignedLicenses -ne $null }
어떤 제품이 할당되어 있는지에 대해 자세한 정보를 표시할 수 있습니다.
# Get all groups with assigned licenses
$groups = Get-MgGroup -All -Property Id, MailNickname, DisplayName, GroupTypes, Description, AssignedLicenses | Where-Object {$_.AssignedLicenses -ne $null }
# Process each group
$groupInfo = foreach ($group in $groups) {
# For each group, get the SKU part numbers of the assigned licenses
$skuPartNumbers = foreach ($skuId in $group.AssignedLicenses.SkuId) {
$subscribedSku = Get-MgSubscribedSku | Where-Object { $_.SkuId -eq $skuId }
$subscribedSku.SkuPartNumber
}
# Create a custom object with the group's object ID, display name, and license SKU part numbers
[PSCustomObject]@{
ObjectId = $group.Id
DisplayName = $group.DisplayName
Licenses = $skuPartNumbers -join ', '
}
}
$groupInfo
다음은 결과입니다.
Id DisplayName AssignedLicenses
-- ----------- ----------------
7023a314-6148-4d7b-b33f-6c775572879a EMS E5 – Licensed users EMSPREMIUM
cf41f428-3b45-490b-b69f-a349c8a4c38e PowerBi - Licensed users POWER_BI_STANDARD
962f7189-59d9-4a29-983f-556ae56f19a5 O365 E3 - Licensed users ENTERPRISEPACK
c2652d63-9161-439b-b74e-fcd8228a7074 EMSandOffice {ENTERPRISEPREMIUM,EMSPREMIUM}
라이선스가 있는 그룹에 대한 통계 가져오기
라이선스가 있는 그룹에 대해 기본적인 통계를 보고할 수 있습니다. 아래 예제에서 스크립트는 총 사용자 수, 그룹에서 이미 할당한 라이선스가 있는 사용자 수 및 그룹에서 라이선스를 할당할 수 없는 사용자 수를 나열합니다.
# Import User Graph Module
Import-Module Microsoft.Graph.Users
# Authenticate to MS Graph
Connect-MgGraph -Scopes "User.Read.All", "Directory.Read.All", "Group.ReadWrite.All"
#get all groups with licenses
$groups = Get-MgGroup -All -Property LicenseProcessingState, DisplayName, Id, AssignedLicenses | Select-Object displayname, Id, LicenseProcessingState, AssignedLicenses | Select-Object DisplayName, Id, AssignedLicenses -ExpandProperty LicenseProcessingState | Select-Object DisplayName, State, Id, AssignedLicenses | Where-Object {$_.State -eq "ProcessingComplete"}
$groupInfoArray = @()
# Filter the groups to only include those that have licenses assigned
$groups = $groups | Where-Object {$_.AssignedLicenses -ne $null}
# For each group, get the group name, license types, total user count, licensed user count, and license error count
foreach ($group in $groups) {
$groupInfo = New-Object PSObject
$groupInfo | Add-Member -MemberType NoteProperty -Name "Group Name" -Value $group.DisplayName
$groupInfo | Add-Member -MemberType NoteProperty -Name "Group ID" -Value $group.Id
$groupInfo | Add-Member -MemberType NoteProperty -Name "License Types" -Value ($group.AssignedLicenses | Select-Object -ExpandProperty SkuId)
$groupInfo | Add-Member -MemberType NoteProperty -Name "Total User Count" -Value (Get-MgGroupMember -GroupId $group.Id -All | Measure-Object).Count
$groupInfo | Add-Member -MemberType NoteProperty -Name "Licensed User Count" -Value (Get-MgGroupMember -GroupId $group.Id -All | Where-Object {$_. LicenseProcessingState -eq "ProcessingComplete"} | Measure-Object).Count
$groupInfo | Add-Member -MemberType NoteProperty -Name "License Error Count" -Value (Get-MgGroupMember -GroupId $group.Id -All | Where-Object {$_.LicenseProcessingState -eq "ProcessingFailed"} | Measure-Object).Count
$groupInfoArray += $groupInfo
}
# Format the output and print it to the console
$groupInfoArray | Format-Table -AutoSize
결과는 다음 표입니다.
GroupName GroupId GroupLicenses TotalUserCount LicensedUserCount LicenseErrorCount
--------- ------- ------------- -------------- ----------------- -----------------
Dynamics Licen... 9160c903-9f91-4597-8f79-22b6c47eafbf AAD_PREMIUM_P2 0 0 0
O365 E5 - base... 055dcca3-fb75-4398-a1b8-f8c6f4c24e65 ENTERPRISEPREMIUM 2 2 0
O365 E5 - extr... 6b14a1fe-c3a9-4786-9ee4-3a2bb54dcb8e ENTERPRISEPREMIUM 3 3 0
EMS E5 - all s... 7023a314-6148-4d7b-b33f-6c775572879a EMSPREMIUM 2 2 0
PowerBi - Lice... cf41f428-3b45-490b-b69f-a349c8a4c38e POWER_BI_STANDARD 2 2 0
O365 E3 - all ... 962f7189-59d9-4a29-983f-556ae56f19a5 ENTERPRISEPACK 2 2 0
O365 E5 - EXO 102fb8f4-bbe7-462b-83ff-2145e7cdd6ed ENTERPRISEPREMIUM 1 1 0
Access to Offi... 11151866-5419-4d93-9141-0603bbf78b42 STANDARDPACK 4 3 1
라이선스 오류가 있는 모든 그룹 가져오기
라이선스를 할당할 수 없는 일부 사용자가 포함된 그룹을 찾으려면 다음을 수행합니다.
# Get all groups that have assigned licenses
$groups = Get-MgGroup -All -Property DisplayName, Id, AssignedLicenses |
Where-Object { $_.AssignedLicenses -ne $null } |
Select-Object DisplayName, Id, AssignedLicenses
# Initialize an array to store group information
$groupInfo = @()
# Iterate over each group
foreach ($group in $groups) {
$groupId = $group.Id
$groupName = $group.DisplayName
# Initialize counters for total members and members with license errors
$totalCount = 0
$licenseErrorCount = 0
# Get all members of the group that have license errors
$members = Get-MgGroupMemberWithLicenseError -GroupId $groupId
# Process each member
foreach ($member in $members) {
$totalCount++
# If the member has a license error (indicated by a non-empty Id), increment the error count
if (![string]::IsNullOrEmpty($member.Id)) {
$licenseErrorCount++
}
}
# Create a custom object with the group's information and counts
$groupInfo += [PSCustomObject]@{
GroupName = $groupName
GroupId = $groupId
TotalUserCount = $totalCount
LicenseErrorCount = $licenseErrorCount
}
}
# Display the groups with licensing errors
$groupInfo | Where-Object { $_.LicenseErrorCount -gt 0 } | Format-Table -Property GroupName, GroupId, TotalUserCount, LicenseErrorCount
결과는 다음 예제와 같습니다.
GroupId GroupName TotalUserCount LicenseErrorCount
-- ----------- --------- -----------
11151866-5419-4d93-9141-0603bbf78b42 Access to Office 365 2 2
다음을 사용하여 Microsoft Graph에서 동일한 데이터 가져오기
GET https://graph.microsoft.com/v1.0/groups?$filter=hasMembersWithLicenseErrors+eq+true
출력:
HTTP/1.1 200 OK
{
"value":[
{
"odata.type": "Microsoft.DirectoryServices.Group",
"objectType": "Group",
"id": "11151866-5419-4d93-9141-0603bbf78b42",
... # other group properties.
},
{
"odata.type": "Microsoft.DirectoryServices.Group",
"objectType": "Group",
"id": "c57cdc98-0dcd-4f90-a82f-c911b288bab9",
...
},
... # other groups with license errors.
]
"odata.nextLink":"https://graph.microsoft.com/v1.0/ groups?$filter=hasMembersWithLicenseErrors+eq+true&$skipToken=<encodedPageToken>"
}
그룹에서 라이선스 오류가 있는 모든 사용자 가져오기
라이선스 관련 오류가 포함된 그룹이 있는 경우 오류의 영향을 받는 모든 사용자를 나열할 수 있습니다. 사용자는 다른 그룹의 오류도 가져올 수 있습니다. 하지만 이 예제에서는 사용자에 대한 IndirectLicenseError 항목의 ReferencedObjectId 속성을 확인하여 요청된 그룹과 관련된 오류만으로 결과를 제한합니다.
#a sample group with errors
$groupId = '11151866-5419-4d93-9141-0603bbf78b42'
#get all user members of the group
$Members = Get-MgGroupMember -All -GroupId $groupId
#get full information about user objects
Foreach ($Member in $Members) {
Get-MgUser -UserId $Member.Id |
#filter out users without license errors and users with license errors from other groups
Where {$Member.AdditionalProperties.IndirectLicenseErrors -and $Member.AdditionalProperties.IndirectLicenseErrors.ReferencedObjectId -eq $groupId} |
#display id, name and error detail. Note: we are filtering out license errors from other groups
Select Id, `
DisplayName, `
@{Name="LicenseError";Expression={$Member.AdditionalProperties.IndirectLicenseErrors |
Where {$Member.AdditionalProperties.IndirectLicenseErrors.ReferencedObjectId -eq $groupId} |
Select -ExpandProperty Error}}
}
결과는 다음 예제와 같습니다.
Id DisplayName License Error
-- ----------- ------------
11bb11bb-cc22-dd33-ee44-55ff55ff55ff Catherine Gibson MutuallyExclusiveViolation
다음을 사용하여 Microsoft Graph에서 동일한 데이터를 가져옵니다.
GET https://graph.microsoft.com/v1.0/groups/11151866-5419-4d93-9141-0603bbf78b42/membersWithLicenseErrors
출력:
HTTP/1.1 200 OK
{
"value":[
{
"odata.type": "Microsoft.DirectoryServices.User",
"objectType": "User",
"id": "11bb11bb-cc22-dd33-ee44-55ff55ff55ff",
... # other user properties.
},
... # other users.
],
"odata.nextLink":"https://graph.microsoft.com/v1.0/groups/11151866-5419-4d93-9141-0603bbf78b42/membersWithLicenseErrors?$skipToken=<encodedPageToken>"
}
전체 조직에서 라이선스 오류가 있는 모든 사용자 가져오기
다음 스크립트는 하나 이상의 그룹에서 라이선스 오류가 있는 모든 사용자를 가져오는 데 사용할 수 있습니다. 이 스크립트는 사용자당, 라이선스 오류당 한 행을 출력하기 때문에 각 오류의 소스를 명확하게 식별할 수 있습니다.
참고 항목
이 스크립트는 조직의 모든 사용자를 열거하기 때문에 대규모 조직에는 적합하지 않을 수 있습니다.
Get-MgUser -All | Where {$_.AdditionalProperties.IndirectLicenseErrors } | % {
$user = $_;
$user.AdditionalProperties.IndirectLicenseErrors | % {
New-Object Object |
Add-Member -NotePropertyName UserName -NotePropertyValue $user.DisplayName -PassThru |
Add-Member -NotePropertyName UserId -NotePropertyValue $user.Id -PassThru |
Add-Member -NotePropertyName GroupId -NotePropertyValue $_.AdditionalProperties.IndirectLicenseErrors.ReferencedObjectId -PassThru |
Add-Member -NotePropertyName LicenseError -NotePropertyValue $_.AdditionalProperties.IndirectLicenseErrors -PassThru
}
}
결과는 다음 예제와 같습니다.
UserName UserId GroupId LicenseError
-------- ------ ------- ------------
Anna Bergman 00aa00aa-bb11-cc22-dd33-44ee44ee44ee 7946137d-b00d-4336-975e-b1b81b0666d0 MutuallyExclusiveViolation
Catherine Gibson 11bb11bb-cc22-dd33-ee44-55ff55ff55ff f2503e79-0edc-4253-8bed-3e158366466b CountViolation
Catherine Gibson 22cc22cc-dd33-ee44-ff55-66aa66aa66aa 11151866-5419-4d93-9141-0603bbf78b42 MutuallyExclusiveViolation
Drew Fogarty 33dd33dd-ee44-ff55-aa66-77bb77bb77bb 1ebd5028-6092-41d0-9668-129a3c471332 MutuallyExclusiveViolation
다음은 라이선스 오류가 포함된 그룹만 검색하는 스크립트의 다른 버전입니다. 문제가 있는 그룹이 많지 않을 것으로 예상되는 시나리오에 더 적합할 수 있습니다.
$groupIds = Get-MgGroup -All -Filter "HasMembersWithLicenseErrors eq true"
foreach ($groupId in $groupIds) {
$Members = Get-MgGroupMember -All -GroupId $groupId
foreach ($Member in $Members) { Get-MgUser -UserId $Member.Id |
Where {$Member.AdditionalProperties.IndirectLicenseErrors -and $Member.AdditionalProperties.IndirectLicenseErrors.ReferencedObjectId -eq $groupId.ObjectID} |
Select DisplayName, `
ObjectId, `
@{Name="LicenseError";Expression={$Member.AdditionalProperties.IndirectLicenseErrors | Where {$Member.AdditionalProperties.IndirectLicenseErrors.ReferencedObjectId -eq $groupId.Id} | Select -ExpandProperty Error}}
}
}
사용자 라이선스가 직접 할당되었는지 또는 그룹에서 상속되었는지 확인
사용자 개체의 경우 특정 제품 라이선스가 그룹에서 할당되었는지 또는 직접 할당되었는지 확인할 수 있습니다.
아래 두 가지 샘플 함수를 사용하여 개별 사용자에 대한 할당 유형을 분석할 수 있습니다.
#Returns TRUE if the user has the license assigned directly
function UserHasLicenseAssignedDirectly
{
Param([Microsoft.Graph.PowerShell.Models.IMicrosoftGraphUser]$user, [string]$skuId)
foreach($license in $user.Licenses)
{
#we look for the specific license SKU in all licenses assigned to the user
if ($license.AccountSkuId -ieq $skuId)
{
#GroupsAssigningLicense contains a collection of IDs of objects assigning the license
#This could be a group object or a user object (contrary to what the name suggests)
#If the collection is empty, this means the license is assigned directly - this is the case for users who have never been licensed via groups in the past
if ($license.GroupsAssigningLicense.Count -eq 0)
{
return $true
}
#If the collection contains the ID of the user object, this means the license is assigned directly
#Note: the license may also be assigned through one or more groups in addition to being assigned directly
foreach ($assignmentSource in $license.GroupsAssigningLicense)
{
if ($assignmentSource -ieq $user.ObjectId)
{
return $true
}
}
return $false
}
}
return $false
}
#Returns TRUE if the user is inheriting the license from a group
function UserHasLicenseAssignedFromGroup
{
Param([Microsoft.Graph.PowerShell.Models.IMicrosoftGraphUser]$user, [string]$skuId)
foreach($license in $user.Licenses)
{
#we look for the specific license SKU in all licenses assigned to the user
if ($license.AccountSkuId -ieq $skuId)
{
#GroupsAssigningLicense contains a collection of IDs of objects assigning the license
#This could be a group object or a user object (contrary to what the name suggests)
foreach ($assignmentSource in $license.GroupsAssigningLicense)
{
#If the collection contains at least one ID not matching the user ID this means that the license is inherited from a group.
#Note: the license may also be assigned directly in addition to being inherited
if ($assignmentSource -ine $user.ObjectId)
{
return $true
}
}
return $false
}
}
return $false
}
이 스크립트는 SKU ID를 입력으로 사용하여 조직의 각 사용자에 대해 해당 함수를 실행합니다. 이 예제에서는 Enterprise Mobility + Security에 대한 라이선스가 필요합니다. 이 라이선스는 조직에서 ID contoso:EMS로 표시됩니다.
#the license SKU we are interested in. use Get-MgSubscribedSku to see a list of all identifiers in your organization
$skuId = "contoso:EMS"
#find all users that have the SKU license assigned
Get-MgUser -All | where {$_.isLicensed -eq $true -and $_.Licenses.AccountSKUID -eq $skuId} | select `
Id, `
@{Name="SkuId";Expression={$skuId}}, `
@{Name="AssignedDirectly";Expression={(UserHasLicenseAssignedDirectly $_ $skuId)}}, `
@{Name="AssignedFromGroup";Expression={(UserHasLicenseAssignedFromGroup $_ $skuId)}}
결과는 다음 예제와 같습니다.
Id SkuId AssignedDirectly AssignedFromGroup
-- ----- ---------------- -----------------
157870f6-e050-4b3c-ad5e-0f0a377c8f4d contoso:EMS True False
1f3174e2-ee9d-49e9-b917-e8d84650f895 contoso:EMS False True
240622ac-b9b8-4d50-94e2-dad19a3bf4b5 contoso:EMS True True
Graph는 결과를 표시하는 간단한 방법이 없지만 이 API에서 확인할 수 있습니다.
GET https://graph.microsoft.com/v1.0/users/e61ff361-5baf-41f0-b2fd-380a6a5e406a?$select=licenseAssignmentStates
출력:
HTTP/1.1 200 OK
{
"value":[
{
"odata.type": "Microsoft.DirectoryServices.User",
"objectType": "User",
"id": "e61ff361-5baf-41f0-b2fd-380a6a5e406a",
"licenseAssignmentState":[
{
"skuId": "157870f6-e050-4b3c-ad5e-0f0a377c8f4d",
"disabledPlans":[],
"assignedByGroup": null, # assigned directly.
"state": "Active",
"error": "None"
},
{
"skuId": "1f3174e2-ee9d-49e9-b917-e8d84650f895",
"disabledPlans":[],
"assignedByGroup": "e61ff361-5baf-41f0-b2fd-380a6a5e406a", # assigned by this group.
"state": "Active",
"error": "None"
},
{
"skuId": "240622ac-b9b8-4d50-94e2-dad19a3bf4b5",
"disabledPlans":[
"e61ff361-5baf-41f0-b2fd-380a6a5e406a"
],
"assignedByGroup": "e61ff361-5baf-41f0-b2fd-380a6a5e406a",
"state": "Active",
"error": "None"
},
{
"skuId": "240622ac-b9b8-4d50-94e2-dad19a3bf4b5",
"disabledPlans":[],
"assignedByGroup": null, # It is the same license as the previous one. It means the license is assigned directly once and inherited from group as well.
"state": " Active ",
"error": " None"
}
],
...
}
],
}
그룹 라이선스가 있는 사용자에 대한 직접 라이선스 제거
이 스크립트의 용도는 동일한 라이선스를 그룹에서 이미 상속한(예: 그룹 기반 라이선스로 전환의 일환으로) 사용자로부터 불필요한 직접 라이선스를 제거하는 것입니다.
참고 항목
우선 제거할 직접 라이선스가 상속된 라이선스보다 더 많은 서비스 기능을 사용하지 않는지 검사하는 것이 중요합니다. 그렇지 않을 경우 직접 라이선스를 제거하면 사용자가 서비스 및 데이터를 액세스할 수 없게 될 수 있습니다. 현재는 어떤 서비스가 상속된 라이선스를 통해 사용되고 어떤 서비스가 직접 라이선스를 통해 사용되는지 PowerShell을 통해 확인할 수 없습니다. 스크립트에서는 우리가 아는 최소 수준의 서비스가 그룹에서 상속되는 것으로 지정하고 사용자가 예기치 않게 서비스 액세스 권한을 상실하지 않는지 확인합니다.
#BEGIN: Helper functions used by the script
#Returns TRUE if the user has the license assigned directly
function UserHasLicenseAssignedDirectly
{
Param([Microsoft.Graph.PowerShell.Models.IMicrosoftGraphUser]$user, [string]$skuId)
$license = GetUserLicense $user $skuId
if ($license -ne $null)
{
#GroupsAssigningLicense contains a collection of IDs of objects assigning the license
#This could be a group object or a user object (contrary to what the name suggests)
#If the collection is empty, this means the license is assigned directly - this is the case for users who have never been licensed via groups in the past
if ($license.GroupsAssigningLicense.Count -eq 0)
{
return $true
}
#If the collection contains the ID of the user object, this means the license is assigned directly
#Note: the license may also be assigned through one or more groups in addition to being assigned directly
foreach ($assignmentSource in $license.GroupsAssigningLicense)
{
if ($assignmentSource -ieq $user.ObjectId)
{
return $true
}
}
return $false
}
return $false
}
#Returns TRUE if the user is inheriting the license from a specific group
function UserHasLicenseAssignedFromThisGroup
{
Param([Microsoft.Graph.PowerShell.Models.IMicrosoftGraphUser]$user, [string]$skuId, [Guid]$groupId)
$license = GetUserLicense $user $skuId
if ($license -ne $null)
{
#GroupsAssigningLicense contains a collection of IDs of objects assigning the license
#This could be a group object or a user object (contrary to what the name suggests)
foreach ($assignmentSource in $license.GroupsAssigningLicense)
{
#If the collection contains at least one ID not matching the user ID this means that the license is inherited from a group.
#Note: the license may also be assigned directly in addition to being inherited
if ($assignmentSource -ieq $groupId)
{
return $true
}
}
return $false
}
return $false
}
#Returns the license object corresponding to the skuId. Returns NULL if not found
function GetUserLicense
{
Param([Microsoft.Graph.PowerShell.Models.IMicrosoftGraphUser]$user, [string]$skuId, [Guid]$groupId)
#we look for the specific license SKU in all licenses assigned to the user
foreach($license in $user.Licenses)
{
if ($license.AccountSkuId -ieq $skuId)
{
return $license
}
}
return $null
}
#produces a list of disabled service plan names for a set of plans we want to leave enabled
function GetDisabledPlansForSKU
{
Param([string]$skuId, [string[]]$enabledPlans)
$allPlans = Get-MgSubscribedSku | where {$_.SkuId -ieq $skuId} | Select -ExpandProperty ServiceStatus | Where {$_.ProvisioningStatus -ine "PendingActivation" -and $_.ServicePlan.TargetClass -ieq "User"} | Select -ExpandProperty ServicePlans | Select -ExpandProperty ServiceName
$disabledPlans = $allPlans | Where {$enabledPlans -inotcontains $_}
return $disabledPlans
}
function GetUnexpectedEnabledPlansForUser
{
Param([Microsoft.Graph.PowerShell.Models.IMicrosoftGraphUser]$user, [string]$skuId, [string[]]$expectedDisabledPlans)
$license = GetUserLicense $user $skuId
$extraPlans = @();
if($license -ne $null)
{
$userDisabledPlans = $license.ServiceStatus | where {$_.ProvisioningStatus -ieq "Disabled"} | Select -ExpandProperty ServicePlan | Select -ExpandProperty ServiceName
$extraPlans = $expectedDisabledPlans | where {$userDisabledPlans -notcontains $_}
}
return $extraPlans
}
#END: helper functions
#BEGIN: executing the script
#the group to be processed
$groupId = "48ca647b-7e4d-41e5-aa66-40cab1e19101"
#license to be removed - Office 365 E3
$skuId = "contoso:ENTERPRISEPACK"
#minimum set of service plans we know are inherited from groups - we want to make sure that there aren't any users who have more services enabled
#which could mean that they may lose access after we remove direct licenses
$servicePlansFromGroups = ("EXCHANGE_S_ENTERPRISE", "SHAREPOINTENTERPRISE", "OFFICESUBSCRIPTION")
$expectedDisabledPlans = GetDisabledPlansForSKU $skuId $servicePlansFromGroups
#process all members in the group and get full info about each user in the group looping through group members.
$Members = Get-MgGroupMember -All -GroupId $groupId
Foreach ($member in $Members) {
Get-MgUser -UserId $Member.Id | Foreach {
$user = $_;
$operationResult = "";
#check if Direct license exists on the user
if (UserHasLicenseAssignedDirectly $user $skuId)
{
#check if the license is assigned from this group, as expected
if (UserHasLicenseAssignedFromThisGroup $user $skuId $groupId)
{
#check if there are any extra plans we didn't expect - we are being extra careful not to remove unexpected services
$extraPlans = GetUnexpectedEnabledPlansForUser $user $skuId $expectedDisabledPlans
if ($extraPlans.Count -gt 0)
{
$operationResult = "User has extra plans that may be lost - license removal was skipped. Extra plans: $extraPlans"
}
else
{
#remove the direct license from user
Set-MgUserLicense -UserId $user.Id -RemoveLicenses $skuId
$operationResult = "Removed direct license from user."
}
}
else
{
$operationResult = "User does not inherit this license from this group. License removal was skipped."
}
}
else
{
$operationResult = "User has no direct license to remove. Skipping."
}
#format output
New-Object Object |
Add-Member -NotePropertyName UserId -NotePropertyValue $user.Id -PassThru |
Add-Member -NotePropertyName OperationResult -NotePropertyValue $operationResult -PassThru
} | Format-Table
}
#END: executing the script
결과는 다음 예제와 같습니다.
UserId OperationResult
------ ---------------
7c7f860f-700a-462a-826c-f50633931362 Removed direct license from user.
0ddacdd5-0364-477d-9e4b-07eb6cdbc8ea User has extra plans that may be lost - license removal was skipped. Extra plans: SHAREPOINTWAC
aadbe4da-c4b5-4d84-800a-9400f31d7371 User has no direct license to remove. Skipping.
참고 항목
위의 스크립트를 실행하기 전에 테스트 환경에 따라 직접 라이선스를 제거할 $skuId
및 $groupId
변수의 값을 업데이트합니다.
다음 단계
그룹의 라이선스를 관리할 수 있는 기능 집합에 대한 자세한 내용은 다음 문서를 참조하세요.
- Microsoft Entra ID의 그룹 기반 라이선스란?
- Microsoft Entra ID의 그룹에 라이선스 할당
- Microsoft Entra ID의 그룹에 대한 라이선스 문제 식별 및 해결
- Microsoft Entra ID에서 라이선스가 부여된 개별 사용자를 그룹 기반 라이선스로 마이그레이션하는 방법
- Microsoft Entra ID에서 그룹 기반 라이선스를 사용하여 제품 라이선스 간에 사용자를 마이그레이션하는 방법
- Microsoft Entra 그룹 기반 라이선스 추가 시나리오
- Microsoft Entra ID의 그룹 기반 라이선스에 대한 PowerShell 예