diff --git a/CHANGELOG.md b/CHANGELOG.md index 1cb8961d23..328bbddb56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,8 +2,13 @@ # UNRELEASED +* AADRoleEligibilityScheduleRequest + * Fixed overall logic to prevent errors complaining about existing permissions. * FabricAdminTenantSettings * Fix titles that have a zero length whitespace character. +* IntuneAppProtectionPolicyAndroid + * Fixes an error retrieving the group id for assignment which resulted + in a 500 error when creating or updating an instance. * IntuneAccountProtectionLocalUserGroupMembershipPolicy * Fixes an issue where not all details were exported. * IntuneAccountProtectionPolicy @@ -166,6 +171,8 @@ * IntuneTrustedRootCertificateAndroidWork * Initial Release * MISC + * DEFENDER + * Added support for the UseBasicParsing paramter for REST calls. * Added check to `New-M365DSCReportFromConfiguration` to make sure Windows Remoting is enabled, which is required to convert the DSC config. * Defender diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleEligibilityScheduleRequest/MSFT_AADRoleEligibilityScheduleRequest.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleEligibilityScheduleRequest/MSFT_AADRoleEligibilityScheduleRequest.psm1 index 5091971e4f..68a19db077 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleEligibilityScheduleRequest/MSFT_AADRoleEligibilityScheduleRequest.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleEligibilityScheduleRequest/MSFT_AADRoleEligibilityScheduleRequest.psm1 @@ -46,10 +46,6 @@ [Microsoft.Management.Infrastructure.CimInstance] $ScheduleInfo, - [Parameter()] - [Microsoft.Management.Infrastructure.CimInstance] - $TicketInfo, - [Parameter()] [System.String] [ValidateSet('Absent', 'Present')] @@ -83,8 +79,9 @@ [System.String[]] $AccessTokens ) - $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` - -InboundParameters $PSBoundParameters + + New-M365DSCConnection -Workload 'MicrosoftGraph' ` + -InboundParameters $PSBoundParameters | Out-Null #Ensure the proper dependencies are installed in the current environment. Confirm-M365DSCDependencies @@ -112,7 +109,7 @@ else { Write-Verbose -Message "Getting Role Eligibility by Id {$Id}" - $request = Get-MgBetaRoleManagementDirectoryRoleEligibilityScheduleRequest -UnifiedRoleEligibilityScheduleRequestId $Id ` + $request = Get-MgBetaRoleManagementDirectoryRoleEligibilitySchedule -UnifiedRoleEligibilityScheduleId $Id ` -ErrorAction SilentlyContinue } } @@ -145,7 +142,7 @@ if ($null -eq $request) { Write-Verbose -Message "Retrieving the request by PrincipalId {$($PrincipalInstance.Id)}, RoleDefinitionId {$($RoleDefinitionId)} and DirectoryScopeId {$($DirectoryScopeId)}" - [Array] $requests = Get-MgBetaRoleManagementDirectoryRoleEligibilityScheduleRequest -Filter "PrincipalId eq '$($PrincipalInstance.Id)' and RoleDefinitionId eq '$($RoleDefinitionId)' and DirectoryScopeId eq '$($DirectoryScopeId)'" + [Array] $requests = Get-MgBetaRoleManagementDirectoryRoleEligibilitySchedule -Filter "PrincipalId eq '$($PrincipalInstance.Id)' and RoleDefinitionId eq '$($RoleDefinitionId)' and DirectoryScopeId eq '$($DirectoryScopeId)'" if ($requests.Length -eq 0) { return $nullResult @@ -223,15 +220,6 @@ $ScheduleInfoValue.Add('StartDateTime', $schedule.ScheduleInfo.StartDateTime.ToString('yyyy-MM-ddThh:mm:ssZ')) } - $ticketInfoValue = $null - if ($null -ne $request.TicketInfo) - { - $ticketInfoValue = @{ - ticketNumber = $request.TicketInfo.TicketNumber - ticketSystem = $request.TicketInfo.TicketSystem - } - } - $results = @{ Principal = $PrincipalValue PrincipalType = $PrincipalType @@ -243,7 +231,6 @@ Justification = $request.Justification IsValidationOnly = $request.IsValidationOnly ScheduleInfo = $ScheduleInfoValue - TicketInfo = $ticketInfoValue Ensure = 'Present' Credential = $Credential ApplicationId = $ApplicationId @@ -315,10 +302,6 @@ function Set-TargetResource [Microsoft.Management.Infrastructure.CimInstance] $ScheduleInfo, - [Parameter()] - [Microsoft.Management.Infrastructure.CimInstance] - $TicketInfo, - [Parameter()] [System.String] [ValidateSet('Absent', 'Present')] @@ -352,16 +335,6 @@ function Set-TargetResource [System.String[]] $AccessTokens ) - try - { - $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` - -InboundParameters $PSBoundParameters ` - - } - catch - { - Write-Verbose -Message $_ - } #Ensure the proper dependencies are installed in the current environment. Confirm-M365DSCDependencies @@ -377,128 +350,114 @@ function Set-TargetResource $currentInstance = Get-TargetResource @PSBoundParameters - $PSBoundParameters.Remove('Ensure') | Out-Null - $PSBoundParameters.Remove('Credential') | Out-Null - $PSBoundParameters.Remove('ApplicationId') | Out-Null - $PSBoundParameters.Remove('ApplicationSecret') | Out-Null - $PSBoundParameters.Remove('TenantId') | Out-Null - $PSBoundParameters.Remove('CertificateThumbprint') | Out-Null - $PSBoundParameters.Remove('ManagedIdentity') | Out-Null - $PSBoundParameters.Remove('Verbose') | Out-Null - $PSBoundParameters.Remove('AccessTokens') | Out-Null - - $ParametersOps = ([Hashtable]$PSBoundParameters).clone() - + Write-Verbose -Message "Retrieving Principal Id from Set-TargetResource" + $PrincipalId = $null if ($PrincipalType -eq 'User') { - [Array]$PrincipalIdValue = (Get-MgUser -Filter "UserPrincipalName eq '$Principal'").Id + Write-Verbose -Message "Retrieving Principal by UserPrincipalName {$Principal}" + $PrincipalInstance = Get-MgUser -Filter "UserPrincipalName eq '$Principal'" -ErrorAction SilentlyContinue + $PrincipalId = $PrincipalInstance.Id } - elseif ($PrincipalType -eq 'Group') + elseif ($null -eq $PrincipalIdValue -and $PrincipalType -eq 'Group') { - [Array]$PrincipalIdValue = (Get-MgGroup -Filter "DisplayName eq '$Principal'").Id + Write-Verbose -Message "Retrieving Principal by DisplayName {$Principal}" + $PrincipalInstance = Get-MgGroup -Filter "DisplayName eq '$Principal'" -ErrorAction SilentlyContinue + $PrincipalId = $PrincipalInstance.Id } - elseif ($PrincipalType -eq 'ServicePrincipal') + else { - [Array]$PrincipalIdValue = (Get-MgServicePrincipal -Filter "DisplayName eq '$Principal'").Id + Write-Verbose -Message "Retrieving Principal by DisplayName {$Principal}" + $PrincipalInstance = Get-MgServicePrincipal -Filter "DisplayName eq '$Principal'" -ErrorAction SilentlyContinue + $PrincipalId = $PrincipalInstance.Id } - if ($null -eq $PrincipalIdValue) - { - throw "Couldn't find Principal {$PrincipalId} of type {$PrincipalType}" + Write-Verbose -Message "Retrieving ROleDefinitionId from Set-TargetResource" + $RoleDefinitionId = (Get-MgBetaRoleManagementDirectoryRoleDefinition -Filter "DisplayName eq '$RoleDefinition'").Id + + $instanceParams = @{ + directoryScopeId = $DirectoryScopeId + principalId = $PrincipalId + roleDefinitionId = $RoleDefinitionId + scheduleInfo = @{ + expiration = @{ + type = $ScheduleInfo.Expiration.Type + duration = $ScheduleInfo.Expiration.Duration + endDateTime = $ScheduleInfo.Expiration.EndDateTime + } + startDateTime = $ScheduleInfo.StartDateTime + } } - elseif ($PrincipalIdValue.Length -gt 1) + + if (-not [System.String]::IsNullOrEmpty($AppScopeId)) { - throw "Multiple Principal with ID {$PrincipalId} of type {$PrincipalType} were found. Cannot create schedule." + $instanceParams.Add('appScopeId', $AppScopeId) } - $ParametersOps.Add('PrincipalId', $PrincipalIdValue[0]) - $ParametersOps.Remove('Principal') | Out-Null - - $RoleDefinitionIdValue = (Get-MgBetaRoleManagementDirectoryRoleDefinition -Filter "DisplayName eq '$RoleDefinition'").Id - $ParametersOps.Add('RoleDefinitionId', $RoleDefinitionIdValue) - $ParametersOps.Remove('RoleDefinition') | Out-Null - if ($null -ne $ScheduleInfo) + if ($null -eq $instanceParams.ScheduleInfo.Expiration.Duration) { - $ScheduleInfoValue = @{} + $instanceParams.ScheduleInfo.Expiration.Remove('duration') | Out-Null + } - if ($ScheduleInfo.StartDateTime) - { - $ScheduleInfoValue.Add('startDateTime', $ScheduleInfo.StartDateTime) + $RecurrenceInfo = @{} + $foundRecurrenceItem = $false + if ($null -ne $ScheduleInfo.Recurrence.Pattern.Type) + { + $Pattern = @{ + dayOfMonth = $ScheduleInfo.Recurrence.Pattern.DayOfMonth + daysOfWeek = $ScheduleInfo.Recurrence.Pattern.DaysOfWeek + firstDayOfWeek = $ScheduleInfo.Recurrence.Pattern.FirstDayOfWeek + index = $ScheduleInfo.Recurrence.Pattern.Index + month = $ScheduleInfo.Recurrence.Pattern.Month + type = $ScheduleInfo.Recurrence.Pattern.Type } - - if ($ScheduleInfo.Expiration) - { - $expirationValue = @{ - endDateTime = $ScheduleInfo.Expiration.endDateTime - type = $ScheduleInfo.Expiration.type - } - if ($ScheduleInfo.Expiration.duration) - { - $expirationValue.Add('duration', $ScheduleInfo.Expiration.duration) - } - $ScheduleInfoValue.Add('Expiration', $expirationValue) + $RecurrenceInfo.Add('pattern', $Pattern) + $foundRecurrenceItem = $true + } + if ($null -ne $ScheduleInfo.Recurrence.Range.Type) + { + $Range = @{ + endDate = $ScheduleInfo.Recurrence.Range.EndDate + numberOfOccurrences = $ScheduleInfo.Recurrence.Range.NumberOfOccurrences + recurrenceTimeZone = $ScheduleInfo.Recurrence.Range.RecurrenceTimeZone + startDate = $ScheduleInfo.Recurrence.Range.StartDate + type = $ScheduleInfo.Recurrence.Range.Type } + $RecurrenceInfo.Add('range', $Range) + $foundRecurrenceItem = $true + } + if ($foundRecurrenceItem) + { + $instanceParams.Add('recurrence', $RecurrenceInfo) + } - if ($ScheduleInfo.Recurrence) - { - $Found = $false - $recurrenceValue = @{} - - if ($ScheduleInfo.Recurrence.Pattern) - { - $Found = $true - $patternValue = @{ - dayOfMonth = $ScheduleInfo.Recurrence.Pattern.dayOfMonth - daysOfWeek = $ScheduleInfo.Recurrence.Pattern.daysOfWeek - firstDayOfWeek = $ScheduleInfo.Recurrence.Pattern.firstDayOfWeek - index = $ScheduleInfo.Recurrence.Pattern.index - interval = $ScheduleInfo.Recurrence.Pattern.interval - month = $ScheduleInfo.Recurrence.Pattern.month - type = $ScheduleInfo.Recurrence.Pattern.type - } - $recurrenceValue.Add('Pattern', $patternValue) - } - if ($ScheduleInfo.Recurrence.Range) - { - $Found = $true - $rangeValue = @{ - endDate = $ScheduleInfo.Recurrence.Range.endDate - numberOfOccurrences = $ScheduleInfo.Recurrence.Range.numberOfOccurrences - recurrenceTimeZone = $ScheduleInfo.Recurrence.Range.recurrenceTimeZone - startDate = $ScheduleInfo.Recurrence.Range.startDate - type = $ScheduleInfo.Recurrence.Range.type - } - $recurrenceValue.Add('Range', $rangeValue) - } - if ($Found) - { - $ScheduleInfoValue.Add('Recurrence', $recurrenceValue) - } - } - Write-Verbose -Message "ScheduleInfo: $(Convert-M365DscHashtableToString -Hashtable $ScheduleInfoValue)" - $ParametersOps.ScheduleInfo = $ScheduleInfoValue + if ([System.String]::IsNullOrEmpty($instanceParams.scheduleInfo.expiration.endDateTime)) + { + $instanceParams.scheduleInfo.expiration.Remove('endDateTime') | Out-Null } - $ParametersOps.Remove('PrincipalType') | Out-Null + + # CREATE if ($Ensure -eq 'Present' -and $currentInstance.Ensure -eq 'Absent') { - Write-Verbose -Message "Creating a Role Assignment Schedule Request for principal {$Principal} and role {$RoleDefinition}" - $ParametersOps.Remove('Id') | Out-Null - Write-Verbose -Message "Values: $(Convert-M365DscHashtableToString -Hashtable $ParametersOps)" - New-MgBetaRoleManagementDirectoryRoleEligibilityScheduleRequest @ParametersOps + $instanceParams.Add('action', 'AdminAssign') + $instanceParams.Add('justification', 'AdminAssign by Microsoft365DSC') + Write-Verbose -Message "Creating new role eligibility Schedule with parameters:`r`n$(ConvertTo-Json $instanceParams -Depth 10)" + New-MgBetaRoleManagementDirectoryRoleEligibilityScheduleRequest @instanceParams -Verbose } + # UPDATE elseif ($Ensure -eq 'Present' -and $currentInstance.Ensure -eq 'Present') { - Write-Verbose -Message "Updating the Role Assignment Schedule Request for principal {$Principal} and role {$RoleDefinition}" - $ParametersOps.Remove('Id') | Out-Null - $ParametersOps.Action = 'AdminUpdate' - New-MgBetaRoleManagementDirectoryRoleEligibilityScheduleRequest @ParametersOps + $instanceParams.Add('action', 'AdminUpdate') + $instanceParams.Add('justification', 'AdminUpdate by Microsoft365DSC') + Write-Verbose -Message "Updating role eligibility Schedule with parameters:`r`n$(ConvertTo-Json $instanceParams -Depth 10)" + New-MgBetaRoleManagementDirectoryRoleEligibilityScheduleRequest @instanceParams } + # REMOVE elseif ($Ensure -eq 'Absent' -and $currentInstance.Ensure -eq 'Present') { - Write-Verbose -Message "Removing the Role Assignment Schedule Request for principal {$Principal} and role {$RoleDefinition}" - $ParametersOps.Remove('Id') | Out-Null - $ParametersOps.Action = 'AdminRemove' - New-MgBetaRoleManagementDirectoryRoleEligibilityScheduleRequest @ParametersOps + $instanceParams.Add('action', 'AdminRemove') + $instanceParams.Add('justification', 'AdminRemove by Microsoft365DSC') + Write-Verbose -Message "Removing role eligibility Schedule with parameters:`r`n$(ConvertTo-Json $instanceParams -Depth 10)" + New-MgBetaRoleManagementDirectoryRoleEligibilityScheduleRequest @instanceParams } } @@ -550,10 +509,6 @@ function Test-TargetResource [Microsoft.Management.Infrastructure.CimInstance] $ScheduleInfo, - [Parameter()] - [Microsoft.Management.Infrastructure.CimInstance] - $TicketInfo, - [Parameter()] [System.String] [ValidateSet('Absent', 'Present')] @@ -600,11 +555,9 @@ function Test-TargetResource Add-M365DSCTelemetryEvent -Data $data #endregion - Write-Verbose -Message "Testing configuration of the Azure AD Role Eligibility Schedule Request for user {$Principal} and role {$RoleDefinition}" - $CurrentValues = Get-TargetResource @PSBoundParameters - $ValuesToCheck = ([Hashtable]$PSBoundParameters).clone() - $ValuesToCheck.Remove('Action') | Out-Null + $ValuesToCheck = ([Hashtable]$PSBoundParameters).Clone() + if ($null -ne $CurrentValues.ScheduleInfo -and $null -ne $ValuesToCheck.ScheduleInfo) { # Compare ScheduleInfo.Expiration @@ -646,11 +599,11 @@ function Test-TargetResource return $false } } + $ValuesToCheck.Remove('ScheduleInfo') | Out-Null Write-Verbose -Message "Current Values: $(Convert-M365DscHashtableToString -Hashtable $CurrentValues)" Write-Verbose -Message "Target Values: $(Convert-M365DscHashtableToString -Hashtable $ValuesToCheck)" - $ValuesToCheck.Remove('ScheduleInfo') | Out-Null $testResult = Test-M365DSCParameterState -CurrentValues $CurrentValues ` -Source $($MyInvocation.MyCommand.Source) ` -DesiredValues $PSBoundParameters ` @@ -714,16 +667,8 @@ function Export-TargetResource try { $Script:ExportMode = $true - #region resource generator code - $schedules = Get-MgBetaRoleManagementDirectoryRoleEligibilitySchedule -All -ErrorAction Stop - [array] $Script:exportedInstances = @() - [array] $allRequests = Get-MgBetaRoleManagementDirectoryRoleEligibilityScheduleRequest -All ` - -Filter "Status ne 'Revoked'" -ErrorAction Stop - foreach ($schedule in $schedules) - { - [array] $Script:exportedInstances += $allRequests | Where-Object -FilterScript { $_.TargetScheduleId -eq $schedule.Id } - } - #endregion + [array] $Script:exportedInstances = Get-MgBetaRoleManagementDirectoryRoleEligibilitySchedule -All ` + -ErrorAction SilentlyContinue $i = 1 $dscContent = '' @@ -735,28 +680,27 @@ function Export-TargetResource { Write-Host "`r`n" -NoNewline } - foreach ($request in $Script:exportedInstances) + foreach ($config in $Script:exportedInstances) { if ($null -ne $Global:M365DSCExportResourceInstancesCount) { $Global:M365DSCExportResourceInstancesCount++ } - $displayedKey = $request.Id + $displayedKey = $config.Id Write-Host " |---[$i/$($Script:exportedInstances.Count)] $displayedKey" -NoNewline - # Find the Principal Type $principalType = 'User' - $userInfo = Get-MgUser -UserId $request.PrincipalId -ErrorAction SilentlyContinue + $userInfo = Get-MgUser -UserId $config.PrincipalId -ErrorAction SilentlyContinue if ($null -eq $userInfo) { $principalType = 'Group' - $groupInfo = Get-MgGroup -GroupId $request.PrincipalId -ErrorAction SilentlyContinue + $groupInfo = Get-MgGroup -GroupId $config.PrincipalId -ErrorAction SilentlyContinue if ($null -eq $groupInfo) { $principalType = 'ServicePrincipal' - $spnInfo = Get-MgServicePrincipal -ServicePrincipalId $request.PrincipalId -ErrorAction SilentlyContinue + $spnInfo = Get-MgServicePrincipal -ServicePrincipalId $config.PrincipalId -ErrorAction SilentlyContinue if ($null -ne $spnInfo) { $PrincipalValue = $spnInfo.DisplayName @@ -778,12 +722,12 @@ function Export-TargetResource if ($null -ne $PrincipalValue) { - $RoleDefinitionId = Get-MgBetaRoleManagementDirectoryRoleDefinition -UnifiedRoleDefinitionId $request.RoleDefinitionId + $RoleDefinitionId = Get-MgBetaRoleManagementDirectoryRoleDefinition -UnifiedRoleDefinitionId $config.RoleDefinitionId $params = @{ - Id = $request.Id + Id = $config.Id Principal = $PrincipalValue PrincipalType = $principalType - DirectoryScopeId = $request.DirectoryScopeId + DirectoryScopeId = $config.DirectoryScopeId RoleDefinition = $RoleDefinitionId.DisplayName Ensure = 'Present' Credential = $Credential @@ -794,46 +738,66 @@ function Export-TargetResource ManagedIdentity = $ManagedIdentity.IsPresent AccessTokens = $AccessTokens } + } - $Results = Get-TargetResource @Params + $Results = Get-TargetResource @Params + $Results = Update-M365DSCExportAuthenticationResults -ConnectionMode $ConnectionMode ` + -Results $Results - $Results = Update-M365DSCExportAuthenticationResults -ConnectionMode $ConnectionMode ` - -Results $Results - try - { - if ($null -ne $results.ScheduleInfo) - { - $Results.ScheduleInfo = Get-M365DSCAzureADEligibilityRequestScheduleInfoAsString -ScheduleInfo $Results.ScheduleInfo + if ($Results.ScheduleInfo) + { + $complexMapping = @( + @{ + Name = 'expiration' + CimInstanceName = 'AADRoleEligibilityScheduleRequestScheduleExpiration' + IsRequired = $False } - } - catch - { - Write-Verbose -Message "Error converting Schedule: $_" - } - if ($Results.TicketInfo) + @{ + Name = 'Recurrence' + CimInstanceName = 'AADRoleEligibilityScheduleRequestScheduleRecurrence' + IsRequired = $False + } + @{ + Name = "range" + CimInstanceName = 'AADRoleEligibilityScheduleRequestScheduleRecurrenceRange' + IsRequired = $False + } + @{ + Name = "pattern" + CimInstanceName = 'AADRoleEligibilityScheduleRequestScheduleRecurrencePattern' + IsRequired = $False + } + ) + $complexTypeStringResult = Get-M365DSCDRGComplexTypeToString -ComplexObject $Results.ScheduleInfo ` + -CIMInstanceName 'AADRoleEligibilityScheduleRequestSchedule' ` + -ComplexTypeMapping $complexMapping + if ($complexTypeStringResult) { - $Results.TicketInfo = Get-M365DSCAzureADEligibilityRequestTicketInfoAsString -TicketInfo $Results.TicketInfo + $Results.ScheduleInfo = $complexTypeStringResult } - $currentDSCBlock = Get-M365DSCExportContentForResource -ResourceName $ResourceName ` - -ConnectionMode $ConnectionMode ` - -ModulePath $PSScriptRoot ` - -Results $Results ` - -Credential $Credential - if ($null -ne $Results.ScheduleInfo) + else { - $currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock ` - -ParameterName 'ScheduleInfo' + $Results.Remove('ScheduleInfo') | Out-Null } - if ($null -ne $Results.TicketInfo) + } + $currentDSCBlock = Get-M365DSCExportContentForResource -ResourceName $ResourceName ` + -ConnectionMode $ConnectionMode ` + -ModulePath $PSScriptRoot ` + -Results $Results ` + -Credential $Credential + if ($Results.ScheduleInfo) + { + $isCIMArray = $false + if ($Results.ScheduleInfo.getType().Fullname -like '*[[\]]') { - $currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock ` - -ParameterName 'TicketInfo' + $isCIMArray = $true } - - $dscContent += $currentDSCBlock - Save-M365DSCPartialExport -Content $currentDSCBlock ` - -FileName $Global:PartialExportFileName + $currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock ` + -ParameterName 'ScheduleInfo' -IsCIMArray:$isCIMArray } + $dscContent += $currentDSCBlock + Save-M365DSCPartialExport -Content $currentDSCBlock ` + -FileName $Global:PartialExportFileName $i++ Write-Host $Global:M365DSCEmojiGreenCheckMark } @@ -841,157 +805,16 @@ function Export-TargetResource } catch { - if ($_.ErrorDetails.Message -like '*The tenant needs an AAD Premium*' -or ` - $_.ErrorDetails.MEssage -like '*[AadPremiumLicenseRequired]*') - { - Write-Host "`r`n $($Global:M365DSCEmojiYellowCircle) Tenant does not meet license requirement to extract this component." - } - else - { - Write-Verbose -Message "Exception: $($_.Exception.Message)" - Write-Host $Global:M365DSCEmojiRedX - New-M365DSCLogEntry -Message 'Error during Export:' ` - -Exception $_ ` - -Source $($MyInvocation.MyCommand.Source) ` - -TenantId $TenantId ` - -Credential $Credential - } - - return '' - } -} - -function Get-M365DSCAzureADEligibilityRequestTicketInfoAsString -{ - [CmdletBinding()] - [OutputType([System.String])] - param( - [Parameter(Mandatory = $true)] - [System.Collections.Hashtable] - $TicketInfo - ) - - if ($TicketInfo.TicketNumber -or $TicketInfo.TicketSystem) - { - $StringContent = "MSFT_AADRoleEligibilityScheduleRequestTicketInfo {`r`n" - $StringContent += " ticketNumber = '$($TicketInfo.TicketNumber)'`r`n" - $StringContent += " ticketSystem = '$($TicketInfo.TicketSystem)'`r`n" - $StringContent += " }`r`n" - return $StringContent - } - else - { - return $null - } -} - -function Get-M365DSCAzureADEligibilityRequestScheduleInfoAsString -{ - [CmdletBinding()] - [OutputType([System.String])] - param( - [Parameter(Mandatory = $true)] - [System.Collections.Hashtable] - $ScheduleInfo - ) - - $Found = $false - $StringContent = "MSFT_AADRoleEligibilityScheduleRequestSchedule {`r`n" - if ($ScheduleInfo.StartDateTime) - { - $StringContent += " startDateTime = '$($ScheduleInfo.StartDateTime)'`r`n" - } - if ($ScheduleInfo.Expiration.Duration -or $ScheduleInfo.Expiration.EndDateTime -or $ScheduleInfo.Expiration.Type) - { - $Found = $true - $StringContent += " expiration = MSFT_AADRoleEligibilityScheduleRequestScheduleExpiration`r`n" - $StringContent += " {`r`n" - if ($ScheduleInfo.Expiration.Duration) - { - $StringContent += " duration = '$($ScheduleInfo.Expiration.Duration)'`r`n" - } - if ($ScheduleInfo.Expiration.EndDateTime) - { - $StringContent += " endDateTime = '$($ScheduleInfo.Expiration.EndDateTime.ToString())'`r`n" - } - if ($ScheduleInfo.Expiration.Type) - { - $StringContent += " type = '$($ScheduleInfo.Expiration.Type)'`r`n" - } - $StringContent += " }`r`n" - } - if ($ScheduleInfo.Recurrence.Pattern.DayOfMonth -or $ScheduleInfo.Recurrence.Pattern.DaysOfWeek -or ` - $ScheduleInfo.Recurrence.Pattern.firstDayOfWeek -or $ScheduleInfo.Recurrence.Pattern.Index -or ` - $ScheduleInfo.Recurrence.Pattern.Interval -or $ScheduleInfo.Recurrence.Pattern.Month -or ` - $ScheduleInfo.Recurrence.Pattern.Type -or $ScheduleInfo.Recurrence.Range.EndDate -or $ScheduleInfo.Recurrence.Range.numberOfOccurrences -or ` - $ScheduleInfo.Recurrence.Range.recurrenceTimeZone -or $ScheduleInfo.Recurrence.Range.startDate -or ` - $ScheduleInfo.Recurrence.Range.type) - { - $StringContent += " recurrence = MSFT_AADRoleEligibilityScheduleRequestScheduleRecurrence`r`n" - $StringContent += " {`r`n" + Write-Host $Global:M365DSCEmojiRedX - if ($ScheduleInfo.Recurrence.Pattern.DayOfMonth -or $ScheduleInfo.Recurrence.Pattern.DaysOfWeek -or ` - $ScheduleInfo.Recurrence.Pattern.firstDayOfWeek -or $ScheduleInfo.Recurrence.Pattern.Index -or ` - $ScheduleInfo.Recurrence.Pattern.Interval -or $ScheduleInfo.Recurrence.Pattern.Month -or ` - $ScheduleInfo.Recurrence.Pattern.Type) - { - $Found = $true - $StringContent += " pattern = MSFT_AADRoleEligibilityScheduleRequestScheduleRecurrencePattern`r`n" - $StringContent += " {`r`n" - if ($ScheduleInfo.Recurrence.Pattern.DayOfMonth) - { - $StringContent += " dayOfMonth = $($ScheduleInfo.Recurrence.Pattern.DayOfMonth)`r`n" - } - if ($ScheduleInfo.Recurrence.Pattern.DaysOfWeek) - { - $StringContent += " daysOfWeek = @($($ScheduleInfo.Recurrence.Pattern.DaysOfWeek -join ','))`r`n" - } - if ($ScheduleInfo.Recurrence.Pattern.firstDayOfWeek) - { - $StringContent += " firstDayOfWeek = '$($ScheduleInfo.Recurrence.Pattern.firstDayOfWeek)'`r`n" - } - if ($ScheduleInfo.Recurrence.Pattern.Index) - { - $StringContent += " index = '$($ScheduleInfo.Recurrence.Pattern.Index)'`r`n" - } - if ($ScheduleInfo.Recurrence.Pattern.Interval) - { - $StringContent += " interval = $($ScheduleInfo.Recurrence.Pattern.Interval.ToString())`r`n" - } - if ($ScheduleInfo.Recurrence.Pattern.Month) - { - $StringContent += " month = $($ScheduleInfo.Recurrence.Pattern.Month.ToString())`r`n" - } - if ($ScheduleInfo.Recurrence.Pattern.Type) - { - $StringContent += " type = '$($ScheduleInfo.Recurrence.Pattern.Type)'`r`n" - } - $StringContent += " }`r`n" - } - if ($ScheduleInfo.Recurrence.Range.EndDate -or $ScheduleInfo.Recurrence.Range.numberOfOccurrences -or ` - $ScheduleInfo.Recurrence.Range.recurrenceTimeZone -or $ScheduleInfo.Recurrence.Range.startDate -or ` - $ScheduleInfo.Recurrence.Range.type) - { - $Found = $true - $StringContent += " range = MSFT_AADRoleEligibilityScheduleRequestScheduleRange`r`n" - $StringContent += " {`r`n" - $StringContent += " endDate = '$($ScheduleInfo.Recurrence.Range.EndDate)'`r`n" - $StringContent += " numberOfOccurrences = $($ScheduleInfo.Recurrence.Range.numberOfOccurrences)`r`n" - $StringContent += " recurrenceTimeZone = '$($ScheduleInfo.Recurrence.Range.recurrenceTimeZone)'`r`n" - $StringContent += " startDate = '$($ScheduleInfo.Recurrence.Range.startDate)'`r`n" - $StringContent += " type = '$($ScheduleInfo.Recurrence.Range.type)'`r`n" - $StringContent += " }`r`n" - } - - $StringContent += " }`r`n" - } - $StringContent += " }`r`n" + New-M365DSCLogEntry -Message 'Error during Export:' ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential - if ($Found) - { - return $StringContent + return '' } - return $null } Export-ModuleMember -Function *-TargetResource diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleEligibilityScheduleRequest/MSFT_AADRoleEligibilityScheduleRequest.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleEligibilityScheduleRequest/MSFT_AADRoleEligibilityScheduleRequest.schema.mof index 7e81112f40..788c55c594 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleEligibilityScheduleRequest/MSFT_AADRoleEligibilityScheduleRequest.schema.mof +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleEligibilityScheduleRequest/MSFT_AADRoleEligibilityScheduleRequest.schema.mof @@ -43,13 +43,6 @@ class MSFT_AADRoleEligibilityScheduleRequestSchedule [Write, Description("When the eligible or active assignment becomes active.")] String startDateTime; }; -[ClassVersion("1.0.0")] -class MSFT_AADRoleEligibilityScheduleRequestTicketInfo -{ - [Write, Description("The ticket number.")] String ticketNumber; - [Write, Description("The description of the ticket system.")] String ticketSystem; -}; - [ClassVersion("1.0.0.0"), FriendlyName("AADRoleEligibilityScheduleRequest")] class MSFT_AADRoleEligibilityScheduleRequest : OMI_BaseResource { @@ -63,7 +56,6 @@ class MSFT_AADRoleEligibilityScheduleRequest : OMI_BaseResource [Write, Description("Determines whether the call is a validation or an actual call. Only set this property if you want to check whether an activation is subject to additional rules like MFA before actually submitting the request.")] Boolean IsValidationOnly; [Write, Description("A message provided by users and administrators when create they create the unifiedRoleEligibilityScheduleRequest object. Optional when action is adminRemove. Whether this property is required or optional is also dependent on the settings for the Azure AD role.")] String Justification; [Write, Description("The period of the role eligibility. Optional when action is adminRemove. The period of eligibility is dependent on the settings of the Azure AD role."), EmbeddedInstance("MSFT_AADRoleEligibilityScheduleRequestSchedule")] String ScheduleInfo; - [Write, Description("Ticket details linked to the role eligibility request including details of the ticket number and ticket system."), EmbeddedInstance("MSFT_AADRoleEligibilityScheduleRequestTicketInfo")] String TicketInfo; [Write, Description("Present ensures the instance exists, absent ensures it is removed."), ValueMap{"Present","Absent"}, Values{"Present","Absent"}] string Ensure; [Write, Description("Credentials of the Intune Admin"), EmbeddedInstance("MSFT_Credential")] string Credential; [Write, Description("Id of the Azure Active Directory application to authenticate with.")] String ApplicationId; diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAppProtectionPolicyAndroid/MSFT_IntuneAppProtectionPolicyAndroid.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAppProtectionPolicyAndroid/MSFT_IntuneAppProtectionPolicyAndroid.psm1 index 56f6253c5f..6536efe50c 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAppProtectionPolicyAndroid/MSFT_IntuneAppProtectionPolicyAndroid.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAppProtectionPolicyAndroid/MSFT_IntuneAppProtectionPolicyAndroid.psm1 @@ -296,16 +296,24 @@ function Get-TargetResource { foreach ($assignment in $policyInfo.Assignments) { + $groupInfo = Get-MgGroup -GroupId $assignment.Target.AdditionalProperties.groupId -ErrorAction SilentlyContinue + $groupValue = $assignment.Target.AdditionalProperties.groupId + if ($null -ne $groupInfo) + { + $groupValue = $groupInfo.DisplayName + } + switch ($assignment.Target.AdditionalProperties.'@odata.type') { '#microsoft.graph.groupAssignmentTarget' { - $assignmentsArray += $assignment.Target.AdditionalProperties.groupId + + $assignmentsArray += $groupValue } '#microsoft.graph.exclusionGroupAssignmentTarget' { - $exclusionArray += $assignment.Target.AdditionalProperties.groupId + $exclusionArray += $groupValue } } } @@ -361,6 +369,7 @@ function Get-TargetResource } catch { + Write-Verbose -Message $_ if ($_.Exception.Message -eq 'Multiple Policies with same displayname identified - Module currently only functions with unique names') { throw $_ @@ -662,7 +671,13 @@ function Set-TargetResource $PSBoundParameters.Assignments | ForEach-Object { if ($_ -ne $null) { - $assignmentsArray += set-JSONstring -id $_ -type 'Assignments' + $groupInfo = Get-MgGroup -Filter "DisplayName eq '$_'" + $idValue = $_ + if (-not [System.String]::IsNullOrEmpty($groupInfo)) + { + $idValue = $groupInfo.Id + } + $assignmentsArray += set-JSONstring -id $idValue -type 'Assignments' } } $configstring += ( 'Assignments' + ":`r`n" + ($PSBoundParameters.Assignments | Out-String) + "`r`n" ) @@ -721,7 +736,7 @@ function Set-TargetResource $setParams.add('AndroidManagedAppProtectionId', $currentPolicy.id) Update-MgBetaDeviceAppManagementAndroidManagedAppProtection @setParams - Write-Verbose -Message 'Setting Group Assignments...' + Write-Verbose -Message "Setting Group Assignments with values:`r`n$(ConvertTo-Json $assignmentsArray -Depth 10)" Set-MgBetaDeviceAppManagementTargetedManagedAppConfiguration -TargetedManagedAppConfigurationId $setParams.AndroidManagedAppProtectionId -Assignments $assignmentsArray } @@ -1027,7 +1042,20 @@ function Test-TargetResource # handle complex parameters - manually for now if ($PSBoundParameters.keys -contains 'Assignments' ) { - $targetvalues.add('Assignments', $psboundparameters.Assignments) + $assignmentsValue = @() + foreach ($assignment in $Assignments) + { + $groupInfo = Get-MgGroup -GroupId $assignment -ErrorAction SilentlyContinue + if ($null -ne $groupInfo) + { + $assignmentsValue += $groupInfo.DisplayName + } + else + { + $assignmentsValue += $assignment + } + } + $targetvalues.add('Assignments', $assignmentsValue) } Write-Verbose -Message 'Starting Exluded Groups Check' diff --git a/Modules/Microsoft365DSC/Modules/M365DSCUtil.psm1 b/Modules/Microsoft365DSC/Modules/M365DSCUtil.psm1 index f59acc102a..5d201c08be 100644 --- a/Modules/Microsoft365DSC/Modules/M365DSCUtil.psm1 +++ b/Modules/Microsoft365DSC/Modules/M365DSCUtil.psm1 @@ -662,6 +662,19 @@ function Test-M365DSCParameterState if ($null -ne $IncludedDrifts -and $IncludedDrifts.Keys.Count -gt 0) { $DriftedParameters = $IncludedDrifts + foreach ($existingDrift in $IncludedDrifts) + { + $propertyName = $existingDrift.Keys[0] + $value = $existingDrift."$propertyName" + $start = $value.IndexOf('') + $currentValue = $value.Substring(0, $start).Replace('', '') + $desiredValue = $value.Substring($start+15, ($value.Length)-($start+15)).Replace('', '').Replace('', '') + $DriftObject.DriftInfo.Add($propertyName, @{ + PropertyName = $propertyName + CurrentValue = $currentValue + DesiredValue = $desiredValue + }) + } $returnValue = $false } diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADRoleEligibilityScheduleRequest.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADRoleEligibilityScheduleRequest.Tests.ps1 index 6f84a2bcd2..a39b4805ab 100644 --- a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADRoleEligibilityScheduleRequest.Tests.ps1 +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADRoleEligibilityScheduleRequest.Tests.ps1 @@ -48,14 +48,16 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { Mock -CommandName Get-MgBetaRoleManagementDirectoryRoleDefinition -MockWith { return @{ - DisplayName = 'Teams Communications Administrator' - Id = '12345' + DisplayName = 'Teams Communications Administrator' + Id = '12345' + DirectoryScopeId = '/' } } Mock -CommandName Get-MgBetaRoleManagementDirectoryRoleEligibilitySchedule -MockWith { return @{ Id = '12345-12345-12345-12345-12345' RoleDefinitionId = "12345" + DirectoryScopeId = '/' } } @@ -89,6 +91,11 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { Mock -CommandName Get-MgBetaRoleManagementDirectoryRoleEligibilityScheduleRequest -MockWith { return $null } + + + Mock -CommandName Get-MgBetaRoleManagementDirectoryRoleEligibilitySchedule -MockWith { + return $null + } } It 'Should return Values from the Get method' { (Get-TargetResource @testParams).Ensure | Should -Be 'Absent' @@ -263,7 +270,7 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { It 'Should call the Set to Update the instance' { Set-TargetResource @testParams - Should -Invoke -CommandName Get-MgBetaRoleManagementDirectoryRoleEligibilityScheduleRequest -Exactly 1 + Should -Invoke -CommandName New-MgBetaRoleManagementDirectoryRoleEligibilityScheduleRequest -Exactly 1 } } Context -Name 'ReverseDSC Tests' -Fixture {