Skip to content

Commit

Permalink
Merge pull request #3905 from NikCharlebois/FIXES-#3902
Browse files Browse the repository at this point in the history
Fixes #3902
  • Loading branch information
NikCharlebois authored Nov 15, 2023
2 parents c6c8831 + 9bafbb5 commit c7ce163
Show file tree
Hide file tree
Showing 3 changed files with 176 additions and 4 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

# UNRELEASED

* AADServicePrincipal
* Added support to define members.
FIXES [#3902](https://github.com/microsoft/Microsoft365DSC/issues/3902)
* EXOCASMailboxPlan
* Fixes an issue where we are not able to set the settings of a CAS
Mailbox Plan by specifying the Identity without the GUID in the name.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ function Get-TargetResource
[System.String]
$AppId,

[Parameter()]
[Microsoft.Management.Infrastructure.CimInstance[]]
$AppRoleAssignedTo,

[Parameter()]
[System.String]
$ObjectId,
Expand Down Expand Up @@ -125,6 +129,7 @@ function Get-TargetResource
else
{
$AADServicePrincipal = Get-MgServicePrincipal -ServicePrincipalId $ObjectId `
-Expand 'AppRoleAssignedTo' `
-ErrorAction Stop
}
}
Expand All @@ -142,7 +147,8 @@ function Get-TargetResource
}
else
{
$AADServicePrincipal = Get-MgServicePrincipal -Filter "AppID eq '$($AppId)'"
$AADServicePrincipal = Get-MgServicePrincipal -Filter "AppID eq '$($AppId)'" `
-Expand 'AppRoleAssignedTo'
}
}
if ($null -eq $AADServicePrincipal)
Expand All @@ -151,8 +157,32 @@ function Get-TargetResource
}
else
{
$AppRoleAssignedToValues = @()
foreach ($principal in $AADServicePrincipal.AppRoleAssignedTo)
{
$currentAssignment = @{
PrincipalType = $null
Identity = $null
}
if ($principal.PrincipalType -eq 'User')
{
$user = Get-MgUser -UserId $principal.PrincipalId
$currentAssignment.PrincipalType = 'User'
$currentAssignment.Identity = $user.UserPrincipalName.Split('@')[0]
$AppRoleAssignedToValues += $currentAssignment
}
elseif ($principal.PrincipalType -eq 'Group')
{
$group = Get-MgGroup -GroupId $principal.PrincipalId
$currentAssignment.PrincipalType = 'Group'
$currentAssignment.Identity = $group.DisplayName
$AppRoleAssignedToValues += $currentAssignment
}
}

$result = @{
AppId = $AADServicePrincipal.AppId
AppRoleAssignedTo = $AppRoleAssignedToValues
ObjectID = $AADServicePrincipal.Id
DisplayName = $AADServicePrincipal.DisplayName
AlternativeNames = $AADServicePrincipal.AlternativeNames
Expand Down Expand Up @@ -181,6 +211,7 @@ function Get-TargetResource
}
catch
{
Write-Verbose -Message $_
New-M365DSCLogEntry -Message 'Error retrieving data:' `
-Exception $_ `
-Source $($MyInvocation.MyCommand.Source) `
Expand All @@ -200,6 +231,10 @@ function Set-TargetResource
[System.String]
$AppId,

[Parameter()]
[Microsoft.Management.Infrastructure.CimInstance[]]
$AppRoleAssignedTo,

[Parameter()]
[System.String]
$ObjectId,
Expand Down Expand Up @@ -286,11 +321,9 @@ function Set-TargetResource
$ManagedIdentity
)

Write-Verbose -Message "1 - There are now {$((Get-ChildItem function: | Measure-Object).Count) functions}"
$ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' `
-InboundParameters $PSBoundParameters

Write-Verbose -Message "2 - There are now {$((Get-ChildItem function: | Measure-Object).Count) functions}"
Write-Verbose -Message 'Setting configuration of Azure AD ServicePrincipal'
#Ensure the proper dependencies are installed in the current environment.
Confirm-M365DSCDependencies
Expand Down Expand Up @@ -319,6 +352,10 @@ function Set-TargetResource
# ServicePrincipal should exist but it doesn't
if ($Ensure -eq 'Present' -and $currentAADServicePrincipal.Ensure -eq 'Absent')
{
if ($null -ne $AppRoleAssignedTo)
{
$currentParameters.AppRoleAssignedTo = $AppRoleAssignedToValue
}
Write-Verbose -Message 'Creating new Service Principal'
New-MgServicePrincipal @currentParameters
}
Expand All @@ -328,7 +365,93 @@ function Set-TargetResource
Write-Verbose -Message 'Updating existing Service Principal'
Write-Verbose -Message "CurrentParameters: $($currentParameters | Out-String)"
Write-Verbose -Message "ServicePrincipalID: $($currentAADServicePrincipal.ObjectID)"
$currentParameters.Remove('AppRoleAssignedTo') | Out-Null
Update-MgServicePrincipal -ServicePrincipalId $currentAADServicePrincipal.ObjectID @currentParameters

if ($AppRoleAssignedTo)
{
[Array]$currentPrincipals = $currentAADServicePrincipal.AppRoleAssignedTo.Identity
[Array]$desiredPrincipals = $AppRoleAssignedTo.Identity

[Array]$differences = Compare-Object -ReferenceObject $currentPrincipals -DifferenceObject $desiredPrincipals
[Array]$membersToAdd = $differences | Where-Object -FilterScript {$_.SideIndicator -eq '=>'}
[Array]$membersToRemove = $differences | Where-Object -FilterScript {$_.SideIndicator -eq '<='}

if ($differences.Count -gt 0)
{
if ($membersToAdd.Count -gt 0)
{
$AppRoleAssignedToValues = @()
foreach ($assignment in $AppRoleAssignedTo)
{
$AppRoleAssignedToValues += @{
PrincipalType = $assignment.PrincipalType
Identity = $assignment.Identity
}
}
foreach ($member in $membersToAdd)
{
$assignment = $AppRoleAssignedToValues | Where-Object -FilterScript {$_.Identity -eq $member.InputObject}
if ($assignment.PrincipalType -eq 'User')
{
Write-Verbose -Message "Retrieving user {$($assignment.Identity)}"
$user = Get-MgUser -Filter "startswith(UserPrincipalName, '$($assignment.Identity)')"
$PrincipalIdValue = $user.Id
}
else
{
Write-Verbose -Message "Retrieving group {$($assignment.Identity)}"
$group = Get-MgGroup -Filter "DisplayName eq '$($assignment.Identity)'"
$PrincipalIdValue = $group.Id
}

$bodyParam = @{
principalId = $PrincipalIdValue
resourceId = $currentAADServicePrincipal.ObjectID
appRoleId = "00000000-0000-0000-0000-000000000000"
}
Write-Verbose -Message "Adding member {$($member.InputObject.ToString())}"
New-MgServicePrincipalAppRoleAssignedTo -ServicePrincipalId $currentAADServicePrincipal.ObjectID `
-BodyParameter $bodyParam | Out-Null
}
}

if ($membersToRemove.Count -gt 0)
{
$AppRoleAssignedToValues = @()
foreach ($assignment in $currentAADServicePrincipal.AppRoleAssignedTo)
{
$AppRoleAssignedToValues += @{
PrincipalType = $assignment.PrincipalType
Identity = $assignment.Identity
}
}
foreach ($member in $membersToRemove)
{
$assignment = $AppRoleAssignedToValues | Where-Object -FilterScript {$_.Identity -eq $member.InputObject}
if ($assignment.PrincipalType -eq 'User')
{
Write-Verbose -Message "Retrieving user {$($assignment.Identity)}"
$user = Get-MgUser -Filter "startswith(UserPrincipalName, '$($assignment.Identity)')"
$PrincipalIdValue = $user.Id
}
else
{
Write-Verbose -Message "Retrieving group {$($assignment.Identity)}"
$group = Get-MgGroup -Filter "DisplayName eq '$($assignment.Identity)'"
$PrincipalIdValue = $group.Id
}
Write-Verbose -Message "PrincipalID Value = '$PrincipalIdValue'"
Write-Verbose -Message "ServicePrincipalId = '$($currentAADServicePrincipal.ObjectID)'"
$allAssignments = Get-MgServicePrincipalAppRoleAssignedTo -ServicePrincipalId $currentAADServicePrincipal.ObjectID
$assignmentToRemove = $allAssignments | Where-Object -FilterScript {$_.PrincipalId -eq $PrincipalIdValue}
Write-Verbose -Message "Removing member {$($member.InputObject.ToString())}"
Remove-MgServicePrincipalAppRoleAssignedTo -ServicePrincipalId $currentAADServicePrincipal.ObjectID `
-AppRoleAssignmentId $assignmentToRemove.Id | Out-Null
}
}
}
}
}
# ServicePrincipal exists but should not
elseif ($Ensure -eq 'Absent' -and $currentAADServicePrincipal.Ensure -eq 'Present')
Expand All @@ -348,6 +471,10 @@ function Test-TargetResource
[System.String]
$AppId,

[Parameter()]
[Microsoft.Management.Infrastructure.CimInstance[]]
$AppRoleAssignedTo,

[Parameter()]
[System.String]
$ObjectId,
Expand Down Expand Up @@ -525,7 +652,10 @@ function Export-TargetResource
$i = 1
Write-Host "`r`n" -NoNewline
$Script:ExportMode = $true
[array] $Script:exportedInstances = Get-MgServicePrincipal -All:$true -Filter $Filter -ErrorAction Stop
[array] $Script:exportedInstances = Get-MgServicePrincipal -All:$true `
-Filter $Filter `
-Expand 'AppRoleAssignedTo' `
-ErrorAction Stop
foreach ($AADServicePrincipal in $Script:exportedInstances)
{
Write-Host " |---[$i/$($Script:exportedInstances.Count)] $($AADServicePrincipal.DisplayName)" -NoNewline
Expand All @@ -544,11 +674,20 @@ function Export-TargetResource
{
$Results = Update-M365DSCExportAuthenticationResults -ConnectionMode $ConnectionMode `
-Results $Results
if ($Results.AppRoleAssignedTo.Count -gt 0)
{
$Results.AppRoleAssignedTo = Get-M365DSCAzureADServicePrincipalAssignmentAsString -Assignments $Results.AppRoleAssignedTo
}
$currentDSCBlock = Get-M365DSCExportContentForResource -ResourceName $ResourceName `
-ConnectionMode $ConnectionMode `
-ModulePath $PSScriptRoot `
-Results $Results `
-Credential $Credential
if ($null -ne $Results.AppRoleAssignedTo)
{
$currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock `
-ParameterName 'AppRoleAssignedTo'
}
$dscContent += $currentDSCBlock
Save-M365DSCPartialExport -Content $currentDSCBlock `
-FileName $Global:PartialExportFileName
Expand All @@ -573,4 +712,26 @@ function Export-TargetResource
}
}

function Get-M365DSCAzureADServicePrincipalAssignmentAsString
{
[CmdletBinding()]
[OutputType([System.String])]
param(
[Parameter(Mandatory = $true)]
[System.Collections.ArrayList]
$Assignments
)

$StringContent = '@('
foreach ($assignment in $Assignments)
{
$StringContent += "MSFT_AADServicePrincipalRoleAssignment {`r`n"
$StringContent += " PrincipalType = '" + $assignment.PrincipalType + "'`r`n"
$StringContent += " Identity = '" + $assignment.Identity + "'`r`n"
$StringContent += " }`r`n"
}
$StringContent += ' )'
return $StringContent
}

Export-ModuleMember -Function *-TargetResource
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
[ClassVersion("1.0.0")]
class MSFT_AADServicePrincipalRoleAssignment
{
[Write, Description("Type of principal. Accepted values are User or Group"), ValueMap{"Group","User"}, Values{"Group","User"}] String PrincipalType;
[Write, Description("Unique identity representing the principal.")] String Identity;
};

[ClassVersion("1.0.0.0"), FriendlyName("AADServicePrincipal")]
class MSFT_AADServicePrincipal : OMI_BaseResource
{
[Key, Description("The unique identifier for the associated application.")] String AppId;
[Write, Description("App role assignments for this app or service, granted to users, groups, and other service principals."), EmbeddedInstance("MSFT_AADServicePrincipalRoleAssignment")] String AppRoleAssignedTo[];
[Write, Description("The ObjectID of the ServicePrincipal")] String ObjectID;
[Write, Description("Displayname of the ServicePrincipal.")] String DisplayName;
[Write, Description("The alternative names for this service principal")] String AlternativeNames[];
Expand Down

0 comments on commit c7ce163

Please sign in to comment.