Skip to content

Commit

Permalink
Merge pull request microsoft#5173 from NikCharlebois/AADApplication--…
Browse files Browse the repository at this point in the history
…-ApplicationTemplate

AADApplication - Added support for ApplicationTemplate
  • Loading branch information
NikCharlebois authored Oct 9, 2024
2 parents 45e913b + 7dc39d9 commit 6c48a5e
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 51 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
* AADApplication
* Fixed an issue trying to retrieve the beta instance.
* Added support for OnPremisesPublishing.
* Added support for ApplicationTemplate.
* AADAuthenticationRequirement
* Initial release.
* AADConnectorGroupApplicationProxy
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ function Get-TargetResource
[Microsoft.Management.Infrastructure.CimInstance]
$OnPremisesPublishing,

[Parameter()]
[System.String]
$ApplicationTemplateId,

[Parameter()]
[ValidateSet('Present', 'Absent')]
[System.String]
Expand Down Expand Up @@ -157,7 +161,7 @@ function Get-TargetResource
}
else
{
$AADApp = Get-MgApplication -Filter "AppId eq '$AppId'"
$AADApp = Get-MgBetaApplication -Filter "AppId eq '$AppId'"
}
}
}
Expand All @@ -176,7 +180,7 @@ function Get-TargetResource
}
else
{
$AADApp = Get-MgApplication -Filter "DisplayName eq '$($DisplayName)'"
$AADApp = [Array](Get-MgBetaApplication -Filter "DisplayName eq '$($DisplayName)'")
}
}
if ($null -ne $AADApp -and $AADApp.Count -gt 1)
Expand All @@ -192,9 +196,8 @@ function Get-TargetResource
{
Write-Verbose -Message 'An instance of Azure AD App was retrieved.'


$AADBetaApp= Get-MgBetaApplication -Property "id,displayName,appId,authenticationBehaviors" -ApplicationId $AADApp.Id -ErrorAction SilentlyContinue
$AADAppKeyCredentials = Get-MgApplication -Property "keyCredentials" -ApplicationId $AADApp.Id -ErrorAction SilentlyContinue
$AADBetaApp= Get-MgBetaApplication -Property "id,displayName,appId,authenticationBehaviors,additionalProperties" -ApplicationId $AADApp.Id -ErrorAction SilentlyContinue
$AADAppKeyCredentials = Get-MgBetaApplication -Property "keyCredentials" -ApplicationId $AADApp.Id -ErrorAction SilentlyContinue

$complexAuthenticationBehaviors = @{}
if ($null -ne $AADBetaApp.authenticationBehaviors.blockAzureADGraphAccess)
Expand Down Expand Up @@ -475,7 +478,8 @@ function Get-TargetResource
PasswordCredentials = $complexPasswordCredentials
AppRoles = $complexAppRoles
Permissions = $permissionsObj
OnPremisesPublishing = $onPremisesPublishingValue
OnPremisesPublishing = $onPremisesPublishingValue
ApplicationTemplateId = $AADApp.AdditionalProperties.applicationTemplateId
Ensure = 'Present'
Credential = $Credential
ApplicationId = $ApplicationId
Expand Down Expand Up @@ -601,6 +605,10 @@ function Set-TargetResource
[Microsoft.Management.Infrastructure.CimInstance]
$OnPremisesPublishing,

[Parameter()]
[System.String]
$ApplicationTemplateId,

[Parameter()]
[ValidateSet('Present', 'Absent')]
[System.String]
Expand Down Expand Up @@ -806,10 +814,44 @@ function Set-TargetResource
Write-Verbose -Message "Multiple instances of a deleted application with name {$DisplayName} wehre found. Creating a new instance since we can't determine what instance to restore."
}
}

# Create from Template
$createdFromTemplate = $false
if ($Ensure -eq 'Present' -and $currentAADApp.Ensure -eq 'Absent' -and -not $skipToUpdate -and `
-not [System.String]::IsNullOrEmpty($ApplicationTemplateId) -and `
$ApplicationTemplateId -ne '8adf8e6e-67b2-4cf2-a259-e3dc5476c621')
{
$skipToUpdate = $true
Write-Verbose -Message "Creating application {$DisplayName} from Application Template {$ApplicationTemplateId}"
$newApp = Invoke-MgBetaInstantiateApplicationTemplate -DisplayName $DisplayName `
-ApplicationTemplateId $ApplicationTemplateId
$currentAADApp = @{
AppId = $newApp.Application.AppId
Id = $newApp.Application.AppId
DisplayName = $newApp.Application.DisplayName
ObjectId = $newApp.Application.AdditionalProperties.objectId
}

$createdFromTemplate = $true

do
{
Write-Verbose -Message 'Waiting for 10 seconds'
Start-Sleep -Seconds 10
$appEntity = Get-MgApplication -ApplicationId $currentAADApp.AppId -ErrorAction SilentlyContinue
$tries++
} until ($null -eq $appEntity -or $tries -le 12)
}
Write-Host "Ensure = $Ensure"
Write-Host "ApplicationTemplateId = $ApplicationTemplateId"
Write-Host "skipToUpdate = $skipToUpdate"
Write-Host "currentAADApp.Ensure = $($currentAADApp.Ensure))"
if ($Ensure -eq 'Present' -and $currentAADApp.Ensure -eq 'Absent' -and -not $skipToUpdate)
{
Write-Verbose -Message "Creating New AzureAD Application {$DisplayName} with values:`r`n$($currentParameters | Out-String)"
$currentParameters.Remove('ObjectId') | Out-Null
$currentParameters.Remove('ApplicationTemplateId') | Out-Null
Write-Verbose -Message "Creating New AzureAD Application {$DisplayName} with values:`r`n$($currentParameters | Out-String)"

$currentAADApp = New-MgApplication @currentParameters
Write-Verbose -Message "Azure AD Application {$DisplayName} was successfully created"
$needToUpdatePermissions = $true
Expand All @@ -831,15 +873,21 @@ function Set-TargetResource
elseif (($Ensure -eq 'Present' -and $currentAADApp.Ensure -eq 'Present') -or $skipToUpdate)
{
$currentParameters.Remove('ObjectId') | Out-Null
$currentParameters.Remove('ApplicationTemplateId') | Out-Null

if (-not $skipToUpdate)
if (-not $skipToUpdate -or $createdFromTemplate)
{
$AppIdValue = $currentAADApp.ObjectId
}

$currentParameters.Add('ApplicationId', $AppIdValue)
Write-Verbose -Message "Updating existing AzureAD Application {$DisplayName} with values:`r`n$($currentParameters | Out-String)"
Update-MgApplication @currentParameters
$currentAADApp.Add('ID', $AppIdValue)

if (-not $currentAADApp.ContainsKey('ID'))
{
$currentAADApp.Add('ID', $AppIdValue)
}
$needToUpdatePermissions = $true
$needToUpdateAuthenticationBehaviors = $true
$needToUpdateKeyCredentials = $true
Expand Down Expand Up @@ -1188,6 +1236,10 @@ function Test-TargetResource
[Microsoft.Management.Infrastructure.CimInstance]
$OnPremisesPublishing,

[Parameter()]
[System.String]
$ApplicationTemplateId,

[Parameter()]
[ValidateSet('Present', 'Absent')]
[System.String]
Expand Down Expand Up @@ -1305,7 +1357,6 @@ function Test-TargetResource
$ValuesToCheck.Remove('AppId') | Out-Null
$ValuesToCheck.Remove('Permissions') | Out-Null


$TestResult = Test-M365DSCParameterState -CurrentValues $CurrentValues `
-Source $($MyInvocation.MyCommand.Source) `
-DesiredValues $PSBoundParameters `
Expand Down Expand Up @@ -1383,7 +1434,7 @@ function Export-TargetResource
try
{
$Script:ExportMode = $true
[array] $Script:exportedInstances = Get-MgApplication -Filter $Filter -All -ErrorAction Stop
[array] $Script:exportedInstances = Get-MgBetaApplication -Filter $Filter -All -ErrorAction Stop
foreach ($AADApp in $Script:exportedInstances)
{
if ($null -ne $Global:M365DSCExportResourceInstancesCount)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ class MSFT_AADApplication : OMI_BaseResource
[Write, Description("Specifies the URLs that user tokens are sent to for sign in, or the redirect URIs that OAuth 2.0 authorization codes and access tokens are sent to.")] String ReplyURLs[];
[Write, Description("UPN or ObjectID values of the app's owners.")] String Owners[];
[Write, Description("Represents the set of properties required for configuring Application Proxy for this application. Configuring these properties allows you to publish your on-premises application for secure remote access."), EmbeddedInstance("MSFT_AADApplicationOnPremisesPublishing")] String OnPremisesPublishing;
[Write, Description("Identifier of the associated Application Template.")] String ApplicationTemplateId;
[Write, Description("Specify if the Azure AD App should exist or not."), ValueMap{"Present","Absent"}, Values{"Present","Absent"}] String Ensure;
[Write, Description("Credentials for the Microsoft Graph delegated permissions."), EmbeddedInstance("MSFT_Credential")] string Credential;
[Write, Description("Id of the Azure Active Directory application to authenticate with.")] String ApplicationId;
Expand Down
63 changes: 23 additions & 40 deletions Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADApplication.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -90,14 +90,14 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture {
Credential = $Credential
}

Mock -CommandName Get-MgApplication -MockWith {
Mock -CommandName Get-MgBetaApplication -MockWith {
return $null
}
}

It 'Should return values from the get method' {
(Get-TargetResource @testParams).Ensure | Should -Be 'Absent'
Should -Invoke -CommandName 'Get-MgApplication' -Exactly 1
Should -Invoke -CommandName 'Get-MgBetaApplication' -Exactly 1
}
It 'Should return false from the test method' {
Test-TargetResource @testParams | Should -Be $false
Expand Down Expand Up @@ -126,7 +126,7 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture {
Credential = $Credential
}

Mock -CommandName Get-MgApplication -MockWith {
Mock -CommandName Get-MgBetaApplication -MockWith {
$AADApp = New-Object PSCustomObject
$AADApp | Add-Member -MemberType NoteProperty -Name DisplayName -Value 'App1'
$AADApp | Add-Member -MemberType NoteProperty -Name Id -Value '5dcb2237-c61b-4258-9c85-eae2aaeba9d6'
Expand All @@ -147,7 +147,7 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture {

It 'Should return values from the get method' {
(Get-TargetResource @testParams).Ensure | Should -Be 'Present'
Should -Invoke -CommandName 'Get-MgApplication' -Exactly 2
Should -Invoke -CommandName 'Get-MgBetaApplication' -Exactly 3
}

It 'Should return false from the test method' {
Expand Down Expand Up @@ -248,25 +248,12 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture {
PermissionIds = @('12345-12345-12345-12345-12345')
} -ClientOnly
)

} -ClientOnly
Ensure = 'Present'
Credential = $Credential
}

Mock -CommandName Get-MgBetaApplication -MockWith {
$AADApp = New-Object PSCustomObject
$AADApp | Add-Member -MemberType NoteProperty -Name DisplayName -Value 'App1'
$AADApp | Add-Member -MemberType NoteProperty -Name Id -Value '5dcb2237-c61b-4258-9c85-eae2aaeba9d6'
$AADApp | Add-Member -MemberType NoteProperty -Name AppId -Value '5dcb2237-c61b-4258-9c85-eae2aaeba9d6'
$AADApp | Add-Member -MemberType NoteProperty -Name AuthenticationBehaviors -Value @{
blockAzureADGraphAccess = $false
removeUnverifiedEmailClaim = $true
requireClientServicePrincipal = $false
}
return $AADApp
}
Mock -CommandName Get-MgApplication -MockWith {
$AADApp = New-Object PSCustomObject
$AADApp | Add-Member -MemberType NoteProperty -Name DisplayName -Value 'App1'
$AADApp | Add-Member -MemberType NoteProperty -Name Id -Value '5dcb2237-c61b-4258-9c85-eae2aaeba9d6'
Expand Down Expand Up @@ -349,13 +336,18 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture {
$AADApp | Add-Member -MemberType NoteProperty -Name IdentifierUris -Value 'https://app.contoso.com'
$AADApp | Add-Member -MemberType NoteProperty -Name Oauth2RequirePostResponse -Value $false
$AADApp | Add-Member -MemberType NoteProperty -Name PublicClient -Value $false
$AADApp | Add-Member -MemberType NoteProperty -Name AuthenticationBehaviors -Value @{
blockAzureADGraphAccess = $false
removeUnverifiedEmailClaim = $true
requireClientServicePrincipal = $false
}
return $AADApp
}
}

It 'Should return Values from the get method' {
Get-TargetResource @testParams
Should -Invoke -CommandName 'Get-MgApplication' -Exactly 2
Should -Invoke -CommandName 'Get-MgBetaApplication' -Exactly 3
}

It 'Should return true from the test method' {
Expand All @@ -380,7 +372,7 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture {
Credential = $Credential
}

Mock -CommandName Get-MgApplication -MockWith {
Mock -CommandName Get-MgBetaApplication -MockWith {
$AADApp = New-Object PSCustomObject
$AADApp | Add-Member -MemberType NoteProperty -Name DisplayName -Value 'App1'
$AADApp | Add-Member -MemberType NoteProperty -Name Id -Value '5dcb2237-c61b-4258-9c85-eae2aaeba9d6'
Expand All @@ -400,7 +392,7 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture {

It 'Should return values from the get method' {
Get-TargetResource @testParams
Should -Invoke -CommandName 'Get-MgApplication' -Exactly 2
Should -Invoke -CommandName 'Get-MgBetaApplication' -Exactly 3
}

It 'Should return false from the test method' {
Expand Down Expand Up @@ -434,28 +426,20 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture {
Credential = $Credential
}

Mock -CommandName Get-MgApplication -MockWith {
return $null
}

Mock -CommandName Get-MgBetaApplication -MockWith {
return @{
id = '12345-12345-12345-12345-12345'
appId = '12345-12345-12345-12345-12345'
DisplayName = 'App1'
AuthenticationBehaviours = @{
blockAzureADGraphAccess = $false
removeUnverifiedEmailClaim = $true
requireClientServicePrincipal = $false
return @(
@{
id = '12345-12345-12345-12345-12345'
appId = '12345-12345-12345-12345-12345'
DisplayName = 'App1'
}

}
)
}
}

It 'Should return values from the get method' {
Get-TargetResource @testParams
Should -Invoke -CommandName 'Get-MgApplication' -Exactly 1
Should -Invoke -CommandName 'Get-MgBetaApplication' -Exactly 3
}

It 'Should return false from the test method' {
Expand All @@ -464,7 +448,6 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture {

It 'Should call the new method' {
Set-TargetResource @testParams
Should -Invoke -CommandName 'New-MgApplication' -Exactly 1
Should -Invoke -CommandName 'Update-MgBetaApplication' -Exactly 1
}

Expand Down Expand Up @@ -505,14 +488,14 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture {
Credential = $Credential
}

Mock -CommandName Get-MgApplication -MockWith {
Mock -CommandName Get-MgBetaApplication -MockWith {
return $null
}
}

It 'Should return values from the get method' {
Get-TargetResource @testParams
Should -Invoke -CommandName 'Get-MgApplication' -Exactly 1
Should -Invoke -CommandName 'Get-MgBetaApplication' -Exactly 1
}

It 'Should return false from the test method' {
Expand All @@ -533,7 +516,7 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture {
Credential = $Credential
}

Mock -CommandName Get-MgApplication -MockWith {
Mock -CommandName Get-MgBetaApplication -MockWith {
$AADApp = New-Object PSCustomObject
$AADApp | Add-Member -MemberType NoteProperty -Name DisplayName -Value 'App1'
$AADApp | Add-Member -MemberType NoteProperty -Name Id -Value '5dcb2237-c61b-4258-9c85-eae2aaeba9d6'
Expand Down

0 comments on commit 6c48a5e

Please sign in to comment.