Skip to content

Commit

Permalink
Merge pull request #5585 from microsoft/Dev
Browse files Browse the repository at this point in the history
Release 1.24.1218.1
  • Loading branch information
NikCharlebois authored Dec 18, 2024
2 parents 2130ad3 + 312f02a commit 7e9e26d
Show file tree
Hide file tree
Showing 74 changed files with 7,642 additions and 95 deletions.
29 changes: 28 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,46 @@
# Change log for Microsoft365DSC

# UNRELEASED
# 1.24.1218.1

* AADApplication
* Added support for Oauth2PermissionScopes.
* Fixes comparison issue for permissions.
* EXOTransportRule
* Fixes issue extracting arrays in Get-TargetResource.
* FIXES [#5575](https://github.com/microsoft/Microsoft365DSC/issues/5575)
* TeamsMeetingPolicy
* Adds support for additional Copilot setting value.
* FIXES [#5573](https://github.com/microsoft/Microsoft365DSC/issues/5573)
* FIXES [#5550](https://github.com/microsoft/Microsoft365DSC/issues/5550)
* MISC
* Fixed the Fabric web request to use basic parsing.
* Reset only necessary authentication context.
* M365DSCUtil
* Update `Get-M365DSCWorkloadsListFromResourceNames` function for more input types.
FIXES [#5525](https://github.com/microsoft/Microsoft365DSC/issues/5525)
* DEPENDENCIES
* Updated Microsoft.PowerApps.Administration.PowerShell to version 2.0.202.
* Updated MSCloudLoginAssistant to version 1.1.31.

# 1.24.1211.1

* AADApplication
* Changed logic to remove all permissions when an empty array is specified.
FIXES [#5534](https://github.com/microsoft/Microsoft365DSC/issues/5534)
* Changed logic to update AppRoles by first disabling the entry.
FIXES [#5524](https://github.com/microsoft/Microsoft365DSC/issues/5524)
* AADFeatureRolloutPolicy
* Fixed policy retrieval
FIXES [#5521](https://github.com/microsoft/Microsoft365DSC/issues/5521)
* AADRoleEligibilityScheduleRequest
* Changed logic to retrieve instance by Service Principal with custom role.
FIXES [#5532](https://github.com/microsoft/Microsoft365DSC/issues/5532)
* IntuneDeviceManagementAndroidDeviceOwnerEnrollmentProfile
* Fixing issue with the way the QrCodeImage property was exported and handled.
* IntuneFirewallPolicyWindows10
* Fix export of properties that appear multiple times in subsections.
* IntuneSecurityBaselineWindows10
* Initial release.
* M365DSCDRGUtil
* Improve settings catalog handling for nested objects.
* M365DSCResourceGenerator
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -792,6 +792,11 @@ function Export-TargetResource
}
foreach ($config in $getValue)
{
if ($null -ne $Global:M365DSCExportResourceInstancesCount)
{
$Global:M365DSCExportResourceInstancesCount++
}

$displayedKey = $config.Id
if (-not [String]::IsNullOrEmpty($config.displayName))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1149,9 +1149,8 @@ function Export-TargetResource
$currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock -ParameterName 'Members' -IsCIMArray $true
$currentDSCBlock = $currentDSCBlock.Replace("`",`"`r`n", '')
$currentDSCBlock = $currentDSCBlock.Replace(",`r`n", '').Replace("`");`r`n", ");`r`n")
$currentDSCBlock = $currentDSCBlock.Replace("Members = @(`"", 'Members = @(')
$currentDSCBlock = $currentDSCBlock.Replace("`$OrganizationName'", "' + `$OrganizationName")
}

$dscContent += $currentDSCBlock
Save-M365DSCPartialExport -Content $currentDSCBlock `
-FileName $Global:PartialExportFileName
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,24 @@ function Get-TargetResource
$complexPreAuthorizedApplications += $myPreAuthorizedApplications
}
}

$complexOAuth2Scopes = @()
foreach ($currentOAuth2Scope in $AADApp.api.Oauth2PermissionScopes)
{
$complexOAuth2Scopes += @{
adminConsentDescription = $currentOAuth2Scope.adminConsentDescription
adminConsentDisplayName = $currentOAuth2Scope.adminConsentDisplayName
id = $currentOAuth2Scope.id
isEnabled = $currentOAuth2Scope.isEnabled
type = $currentOAuth2Scope.type
userConsentDescription = $currentOAuth2Scope.userConsentDescription
userConsentDisplayName = $currentOAuth2Scope.userConsentDisplayName
value = $currentOAuth2Scope.value
}
}

$complexApi.Add('PreAuthorizedApplications', $complexPreAuthorizedApplications)
$complexApi.Add('Oauth2PermissionScopes', $complexOAuth2Scopes)
if ($complexApi.values.Where({ $null -ne $_ }).Count -eq 0)
{
$complexApi = $null
Expand Down Expand Up @@ -736,18 +753,56 @@ function Set-TargetResource
}
$currentParameters.Remove('AvailableToOtherTenants') | Out-Null
$currentParameters.Remove('PublicClient') | Out-Null
$currentParameters.Remove('Verbose') | Out-Null

if ($currentParameters.KnownClientApplications)
#region API
$apiValue = @{}
if ($currentParameters.Api.KnownClientApplications)
{
$apiValue.Add('KnownClientApplications', $currentParameters.Api.KnownClientApplications)
}
if ($currentParameters.Api.Oauth2PermissionScopes)
{
$apiValue = @{
KnownClientApplications = $currentParameters.KnownClientApplications
Write-Verbose -Message "Oauth2PermissionScopes specified and is not empty"
$scopeValue = @()
foreach ($scope in $currentParameters.Api.Oauth2PermissionScopes)
{
$scopeEntry = @{
adminConsentDescription = $scope.adminConsentDescription
adminConsentDisplayName = $scope.adminConsentDisplayName
isEnabled = $scope.isEnabled
type = $scope.type
userConsentDescription = $scope.userConsentDescription
userConsentDisplayName = $scope.userConsentDisplayName
value = $scope.value
}
if (-not [System.String]::IsNullOrEmpty($scope.id))
{
Write-Verbose -Message "Adding existing scope id {$($scope.id)}"
$scopeEntry.Add('id', $scope.id)
}
else
{
Write-Verbose -Message "Generating new scope id"
$scopeEntry.Add('id', (New-Guid).ToString())
}

$scopeValue += $scopeEntry
}
$currentParameters.Add('Api', $apiValue)
$currentParameters.Remove('KnownClientApplications') | Out-Null
$apiValue.Add('Oauth2PermissionScopes', $scopeValue)
}
$currentParameters.Remove('KnownClientApplications') | Out-Null
#endregion

if ($currentParameters.ContainsKey('Api'))
{
Write-Verbose "Found existing API parameter. Updating with $(Convert-M365DscHashtableToString -Hashtable $apiValue)"
$currentParameters.Api = $apiValue
}
else
{
$currentParameters.Remove('KnownClientApplications') | Out-Null
Write-Verbose "Adding API parameter with $(Convert-M365DscHashtableToString -Hashtable $apiValue)"
$currentParameters.Add('Api', $apiValue)
}

if ($ReplyUrls -or $LogoutURL -or $Homepage)
Expand All @@ -774,7 +829,6 @@ function Set-TargetResource
$currentParameters.Remove('Homepage') | Out-Null
$currentParameters.Remove('OnPremisesPublishing') | Out-Null


$keys = (([Hashtable]$currentParameters).clone()).Keys
foreach ($key in $keys)
{
Expand Down Expand Up @@ -859,6 +913,7 @@ function Set-TargetResource
$currentParameters.Remove('ApplicationTemplateId') | Out-Null
Write-Verbose -Message "Creating New AzureAD Application {$DisplayName} with values:`r`n$($currentParameters | Out-String)"

Write-Verbose -Message "Parameters with API: $(ConvertTo-Json $currentParameters -Depth 10)"
$currentAADApp = New-MgApplication @currentParameters
Write-Verbose -Message "Azure AD Application {$DisplayName} was successfully created"
$needToUpdatePermissions = $true
Expand Down Expand Up @@ -888,6 +943,8 @@ function Set-TargetResource
}

$currentParameters.Add('ApplicationId', $AppIdValue)
$currentParameters.Remove('AppRoles') | Out-Null

Write-Verbose -Message "Updating existing AzureAD Application {$DisplayName} with values:`r`n$($currentParameters | Out-String)"
Update-MgApplication @currentParameters

Expand All @@ -898,6 +955,62 @@ function Set-TargetResource
$needToUpdatePermissions = $true
$needToUpdateAuthenticationBehaviors = $true
$needToUpdateKeyCredentials = $true

# Update AppRoles
if ($null -ne $AppRoles)
{
Write-Verbose -Message "AppRoles were specified."

# Find roles to Remove
$fixedRoles = @()
$rolesToRemove = @()
foreach ($currentRole in $currentAADApp.AppRoles)
{
$associatedDesiredRoleEntry = $AppRoles | Where-Object -FilterScript {$_.DisplayName -eq $currentRole.DisplayName}
if ($null -eq $associatedDesiredRoleEntry)
{
Write-Verbose -Message "Could not find matching AppRole entry in Desired values for {$($currentRole.DisplayName)}. Will remove role."
$fixedRole = $currentRole
$fixedRole.IsEnabled = $false
$fixedRoles += $fixedRole
$rolesToRemove += $currentRole.DisplayName
}
else
{
Write-Verbose -Message "Found matching AppRole entry in Desired values for {$($currentRole.DisplayName)}. Keeping same value as current, but setting to disable."
$entry = @{
AllowedMemberTypes = $currentRole.AllowedMemberTypes
Id = $currentRole.Id
IsEnabled = $false
Origin = $currentRole.Origin
Value = $currentRole.Value
DisplayName = $currentRole.DisplayName
Description = $currentRole.Description
}
$fixedRoles += $entry
}
}

Write-Verbose -Message "Updating AppRoles with the disabled roles to remove: {$($rolesToRemove -join ',')}"
Update-MgApplication -ApplicationId $currentAADApp.ObjectId -AppRoles $fixedRoles

Write-Verbose -Message "Updating the app a second time, this time removing the app roles {$($rolesToRemove -join ',')} and updating the others."
$resultingAppRoles = @()
foreach ($currentAppRole in $AppRoles)
{
$entry = @{
AllowedMemberTypes = $currentAppRole.AllowedMemberTypes
Id = $currentAppRole.Id
IsEnabled = $currentAppRole.IsEnabled
Origin = $currentAppRole.Origin
Value = $currentAppRole.Value
DisplayName = $currentAppRole.DisplayName
Description = $currentAppRole.Description
}
$resultingAppRoles += $entry
}
Update-MgApplication -ApplicationId $currentAADApp.ObjectId -AppRoles $resultingAppRoles
}
}
# App exists but should not
elseif ($Ensure -eq 'Absent' -and $currentAADApp.Ensure -eq 'Present')
Expand Down Expand Up @@ -985,7 +1098,7 @@ function Set-TargetResource
$allRequiredAccess = @()
}
else
{
{
$allSourceAPIs = $Permissions.SourceAPI | Select-Object -Unique
$allRequiredAccess = @()

Expand Down Expand Up @@ -1039,6 +1152,10 @@ function Set-TargetResource
{
$roleId = $role.Id
}
if ([System.String]::IsNullOrEmpty($roleId))
{
throw "Could not find associated role {$($permission.Name)} for API {$($sourceAPI)}"
}
$appPermission = @{
Id = $roleId
Type = 'Role'
Expand All @@ -1054,6 +1171,7 @@ function Set-TargetResource
}

Write-Verbose -Message "Updating permissions for Azure AD Application {$($currentAADApp.DisplayName)} with RequiredResourceAccess:`r`n$($allRequiredAccess | Out-String)"
Write-Verbose -Message "ResourceAccess:`r`n$($allRequiredAccess.ResourceAccess | Out-String)"
Write-Verbose -Message "Current App Id: $($currentAADApp.AppId)"

# Even if the property is named ApplicationId, we need to pass in the ObjectId
Expand All @@ -1072,7 +1190,8 @@ function Set-TargetResource
requireClientServicePrincipal = $AuthenticationBehaviors.requireClientServicePrincipal
}

Update-MgBetaApplication -ApplicationId $currentAADApp.Id -AuthenticationBehaviors $IAuthenticationBehaviors | Out-Null
Update-MgBetaApplication -ApplicationId $currentAADApp.Id `
-AuthenticationBehaviors $IAuthenticationBehaviors | Out-Null
}

if ($needToUpdateKeyCredentials -and $KeyCredentials)
Expand Down Expand Up @@ -1307,8 +1426,8 @@ function Test-TargetResource

$CurrentValues = Get-TargetResource @PSBoundParameters

if ($CurrentValues.Permissions.Length -gt 0 -and `
$null -ne $CurrentValues.Permissions.Name)
if ($CurrentValues.Permissions.Length -gt 0 -and $null -ne $CurrentValues.Permissions.Name -and `
$null -ne $Permissions)
{
$differenceObject = $Permissions.Name
if ($null -eq $differenceObject)
Expand Down Expand Up @@ -1506,6 +1625,11 @@ function Export-TargetResource
CimInstanceName = 'MicrosoftGraphPreAuthorizedApplication'
IsRequired = $False
}
@{
Name = 'Oauth2PermissionScopes'
CimInstanceName = 'MSFT_MicrosoftGraphApiOauth2PermissionScopes'
IsRequired = $False
}
)
$complexTypeStringResult = Get-M365DSCDRGComplexTypeToString `
-ComplexObject $Results.Api `
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,26 @@ class MSFT_MicrosoftGraphPreAuthorizedApplication
[Write, Description("The unique identifier for the scopes the client application is granted.")] String PermissionIds[];
};

[ClassVersion("1.0.0")]
class MSFT_MicrosoftGraphApiOauth2PermissionScopes
{
[Write, Description("A description of the delegated permissions, intended to be read by an administrator granting the permission on behalf of all users. This text appears in tenant-wide admin consent experiences.")] String adminConsentDescription;
[Write, Description("The permission's title, intended to be read by an administrator granting the permission on behalf of all users.")] String adminConsentDisplayName;
[Write, Description("A description of the delegated permissions, intended to be read by a user granting the permission on their own behalf. This text appears in consent experiences where the user is consenting only on behalf of themselves.")] String userConsentDescription;
[Write, Description("A title for the permission, intended to be read by a user granting the permission on their own behalf. This text appears in consent experiences where the user is consenting only on behalf of themselves.")] String userConsentDisplayName;
[Write, Description("Specifies the value to include in the scp (scope) claim in access tokens. Must not exceed 120 characters in length.")] String value;
[Write, Description("When you create or update a permission, this property must be set to true (which is the default). To delete a permission, this property must first be set to false. At that point, in a subsequent call, the permission may be removed.")] Boolean isEnabled;
[Write, Description("The possible values are: User and Admin. Specifies whether this delegated permission should be considered safe for non-admin users to consent to on behalf of themselves, or whether an administrator consent should always be required.")] String type;
[Write, Description("Unique delegated permission identifier inside the collection of delegated permissions defined for a resource application.")] String id;

};

[ClassVersion("1.0.0")]
class MSFT_MicrosoftGraphApiApplication
{
[Write, Description("Lists the client applications that are preauthorized with the specified delegated permissions to access this application's APIs. Users aren't required to consent to any preauthorized application (for the permissions specified). However, any other permissions not listed in preAuthorizedApplications (requested through incremental consent for example) will require user consent."), EmbeddedInstance("MSFT_MicrosoftGraphPreAuthorizedApplication")] String PreAuthorizedApplications[];
[Write, Description("List of associated API scopes."), EmbeddedInstance("MSFT_MicrosoftGraphAPIOauth2PermissionScopes")] String Oauth2PermissionScopes[];

};

[ClassVersion("1.0.0")]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,10 +148,24 @@ function Get-TargetResource
[Array] $requests = Get-MgBetaRoleManagementDirectoryRoleAssignmentScheduleRequest -Filter "PrincipalId eq '$($PrincipalInstance.Id)' and RoleDefinitionId eq '$($RoleDefinitionId)' and DirectoryScopeId eq '$($DirectoryScopeId)'"
if ($requests.Length -eq 0)
{
return $nullResult
Write-Verbose -Message "Trying to retrieve by reverse RoleId retrieval"
$partialRequests = Get-MgBetaRoleManagementDirectoryRoleAssignmentScheduleRequest -Filter "PrincipalId eq '$($PrincipalInstance.Id)' and DirectoryScopeId eq '$($DirectoryScopeId)'"
$reverseRoleId = $null
foreach ($partialRequest in $partialRequests)
{
$roleEntry = Get-MgBetaRoleManagementDirectoryRoleDefinition -UnifiedRoleDefinitionId $partialRequest.RoleDefinitionId | Where-Object -FilterScript {$_.DisplayName -eq $RoleDefinition}
if ($null -ne $roleEntry)
{
$request = $partialRequest
$RoleDefinitionId = $partialRequest.RoleDefinitionId
break
}
}
}
else
{
$request = $requests[0]
}

$request = $requests[0]
}

$schedules = Get-MgBetaRoleManagementDirectoryRoleAssignmentSchedule -Filter "PrincipalId eq '$($request.PrincipalId)'"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@
$PrincipalValue = $PrincipalInstance.DisplayName
}

Write-Verbose -Message 'Found Principal'
Write-Verbose -Message "Found Principal {$PrincipalValue}"
$RoleDefinitionId = (Get-MgBetaRoleManagementDirectoryRoleDefinition -Filter "DisplayName eq '$RoleDefinition'").Id
Write-Verbose -Message "Retrieved role definition {$RoleDefinition} with ID {$RoleDefinitionId}"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ function Set-TargetResource
Write-Verbose -Message 'Waiting for 20 seconds for new permissions to be effective.'
Start-Sleep 20
Write-Verbose -Message 'Disconnecting from Exchange Online'
Reset-MSCloudLoginConnectionProfileContext
Reset-MSCloudLoginConnectionProfileContext -Workload ExchangeOnline
}
}

Expand Down
Loading

0 comments on commit 7e9e26d

Please sign in to comment.