From e44c2bc096c15549772f7d58b952a606ceac0849 Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Thu, 19 Oct 2023 12:19:17 -0400 Subject: [PATCH 01/31] Adds Auth Context support for conditional access policies --- .../MSFT_AADConditionalAccessPolicy.psm1 | 43 +++++++++++++++++++ ...MSFT_AADConditionalAccessPolicy.schema.mof | 1 + 2 files changed, 44 insertions(+) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 index e6abf5f904..0a0904a285 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 @@ -185,6 +185,10 @@ function Get-TargetResource [System.String] $AuthenticationStrength, + [Parameter()] + [System.String[]] + $AuthenticationContexts, + #generic [Parameter()] [ValidateSet('Present', 'Absent')] @@ -575,6 +579,21 @@ function Get-TargetResource } } + $AuthenticationContextsValues = @() + if ($null -ne $Policy.Conditions.Applications.IncludeAuthenticationContextClassReferences) + { + foreach ($class in $Policy.Conditions.Applications.IncludeAuthenticationContextClassReferences) + { + $classReference = Get-MgBetaIdentityConditionalAccessAuthenticationContextClassReference ` + -AuthenticationContextClassReferenceId $class ` + -ErrorAction SilentlyContinue + if ($null -ne $classReference) + { + $AuthenticationContextsValues += $classReference.DisplayName + } + } + } + $result = @{ DisplayName = $Policy.DisplayName Id = $Policy.Id @@ -640,6 +659,7 @@ function Get-TargetResource PersistentBrowserMode = [System.String]$Policy.SessionControls.PersistentBrowser.Mode #no translation needed AuthenticationStrength = $AuthenticationStrengthValue + AuthenticationContexts = $AuthenticationContextsValues #Standard part TermsOfUse = $termOfUseName Ensure = 'Present' @@ -841,6 +861,10 @@ function Set-TargetResource [System.String] $AuthenticationStrength, + [Parameter()] + [System.String[]] + $AuthenticationContexts, + #generic [Parameter()] [ValidateSet('Present', 'Absent')] @@ -925,6 +949,21 @@ function Set-TargetResource { $conditions.Applications.Add('IncludeUserActions', $IncludeUserActions) } + if ($AuthenticationContexts) + { + # Retrieve the class reference based on display name. + $AuthenticationContextsValues = @() + $classReferences = Get-MgBetaIdentityConditionalAccessAuthenticationContextClassReference -ErrorAction SilentlyContinue + foreach ($authContext in $AuthenticationContexts) + { + $currentClassId = $classReferences | Where-Object -FilterScript {$_.DisplayName -eq $authContext} + if ($null -ne $currentClassId) + { + $AuthenticationContextsValues += $currentClassId.Id + } + } + $conditions.Applications.Add('IncludeAuthenticationContextClassReferences', $AuthenticationContextsValues) + } #create and provision User Condition object Write-Verbose -Message 'Set-Targetresource: process includeusers' @@ -1725,6 +1764,10 @@ function Test-TargetResource [System.String] $AuthenticationStrength, + [Parameter()] + [System.String[]] + $AuthenticationContexts, + #generic [Parameter()] [ValidateSet('Present', 'Absent')] diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.schema.mof index 5e37ff420b..d209e98f00 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.schema.mof +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.schema.mof @@ -42,6 +42,7 @@ class MSFT_AADConditionalAccessPolicy : OMI_BaseResource [Write, Description("Specifies, whether Browser Persistence is controlled by the Policy.")] Boolean PersistentBrowserIsEnabled; [Write, Description("Specifies, what Browser Persistence control is enforced by the Policy."), ValueMap{"Always","Never",""}, Values{"Always","Never",""}] String PersistentBrowserMode; [Write, Description("Name of the associated authentication strength policy.")] String AuthenticationStrength; + [Write, Description("Authentication context class references.")] String AuthenticationContexts[]; [Write, Description("Specify if the Azure AD CA Policy 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; From 41c6ef8f4c2e9c54b386eb2f6e2d6d4bf969833a Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Thu, 19 Oct 2023 12:20:05 -0400 Subject: [PATCH 02/31] Update CHANGELOG.md --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 388563095a..dd73c7121d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Change log for Microsoft365DSC +# UNRELEASED + +* AADConditionalAccessPolicy + * Adds support for Authentication Context. + FIXES [#3813](https://github.com/microsoft/Microsoft365DSC/issues/3813) + # 1.23.1018.1 * AADAuthenticationMethodPolicyAuthenticator From a6d17fd6d12604d5d1be6b7da2af76ea322c2d20 Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Thu, 19 Oct 2023 17:18:42 +0000 Subject: [PATCH 03/31] Updated Resources and Cmdlet documentation pages --- docs/docs/resources/azure-ad/AADConditionalAccessPolicy.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/docs/resources/azure-ad/AADConditionalAccessPolicy.md b/docs/docs/resources/azure-ad/AADConditionalAccessPolicy.md index 605e498521..4cc29f9f1e 100644 --- a/docs/docs/resources/azure-ad/AADConditionalAccessPolicy.md +++ b/docs/docs/resources/azure-ad/AADConditionalAccessPolicy.md @@ -45,6 +45,7 @@ | **PersistentBrowserIsEnabled** | Write | Boolean | Specifies, whether Browser Persistence is controlled by the Policy. | | | **PersistentBrowserMode** | Write | String | Specifies, what Browser Persistence control is enforced by the Policy. | `Always`, `Never`, `` | | **AuthenticationStrength** | Write | String | Name of the associated authentication strength policy. | | +| **AuthenticationContexts** | Write | StringArray[] | Authentication context class references. | | | **Ensure** | Write | String | Specify if the Azure AD CA Policy should exist or not. | `Present`, `Absent` | | **Credential** | Write | PSCredential | Credentials for the Microsoft Graph delegated permissions. | | | **ApplicationId** | Write | String | Id of the Azure Active Directory application to authenticate with. | | From 06b33dbf5032adfa593bc6a351e4b3eff1d10962 Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Thu, 19 Oct 2023 14:55:52 -0400 Subject: [PATCH 04/31] Fixes #3712 --- CHANGELOG.md | 3 +++ .../MSFT_TeamsComplianceRecordingPolicy.psm1 | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd73c7121d..a032116246 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ * AADConditionalAccessPolicy * Adds support for Authentication Context. FIXES [#3813](https://github.com/microsoft/Microsoft365DSC/issues/3813) +* TeamsComplianceRecordingPolicy + * Fixes an issue where the Compliance Application ID wasn't properly retrieved. + FIXES [#3712](https://github.com/microsoft/Microsoft365DSC/issues/3712) # 1.23.1018.1 diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsComplianceRecordingPolicy/MSFT_TeamsComplianceRecordingPolicy.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsComplianceRecordingPolicy/MSFT_TeamsComplianceRecordingPolicy.psm1 index 707422b878..feffced474 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsComplianceRecordingPolicy/MSFT_TeamsComplianceRecordingPolicy.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsComplianceRecordingPolicy/MSFT_TeamsComplianceRecordingPolicy.psm1 @@ -78,7 +78,7 @@ function Get-TargetResource Write-Verbose -Message "Found an instance with Identity {$Identity}" $results = @{ Identity = $instance.Identity - ComplianceRecordingApplications = $instance.ComplianceRecordingApplications + ComplianceRecordingApplications = [Array]$instance.ComplianceRecordingApplications.Id Description = $instance.Description DisableComplianceRecordingAudioNotificationForCalls = $instance.DisableComplianceRecordingAudioNotificationForCalls Enabled = $instance.Enabled From 9be43924a8872095ccfea6e3a808de44316f5516 Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Thu, 19 Oct 2023 15:13:09 -0400 Subject: [PATCH 05/31] Update Microsoft365DSC.TeamsComplianceRecordingPolicy.Tests.ps1 --- ...soft365DSC.TeamsComplianceRecordingPolicy.Tests.ps1 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.TeamsComplianceRecordingPolicy.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.TeamsComplianceRecordingPolicy.Tests.ps1 index 5883bcdf14..a0d97fe0c9 100644 --- a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.TeamsComplianceRecordingPolicy.Tests.ps1 +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.TeamsComplianceRecordingPolicy.Tests.ps1 @@ -107,7 +107,7 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { Description = 'FakeStringValue' Enabled = $True DisableComplianceRecordingAudioNotificationForCalls = $True - ComplianceRecordingApplications = 'FakeStringValue' + ComplianceRecordingApplications = @{Id='FakeStringValue'} Identity = 'FakeStringValue' } @@ -147,7 +147,7 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { Description = 'FakeStringValue' Enabled = $True DisableComplianceRecordingAudioNotificationForCalls = $True - ComplianceRecordingApplications = 'FakeStringValue' + ComplianceRecordingApplications = @{Id='FakeStringValue'} Identity = 'FakeStringValue' } @@ -175,10 +175,10 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { Mock -CommandName Get-CsTeamsComplianceRecordingPolicy -MockWith { return @{ WarnUserOnRemoval = $False - Description = 'FakeStringValueDrift #Drift' + Description = 'FakeStringValueDrift' #Drift Enabled = $False DisableComplianceRecordingAudioNotificationForCalls = $False - ComplianceRecordingApplications = 'FakeStringValueDrift #Drift' + ComplianceRecordingApplications = @{Id='FakeStringValueDrift'} #Drift Identity = 'FakeStringValue' } } @@ -212,7 +212,7 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { Description = 'FakeStringValue' Enabled = $True DisableComplianceRecordingAudioNotificationForCalls = $True - ComplianceRecordingApplications = 'FakeStringValue' + ComplianceRecordingApplications = @{Id='FakeStringValue'} Identity = 'FakeStringValue' } From 56175657d9b498a1a4e0ee87243f7ae18810eea9 Mon Sep 17 00:00:00 2001 From: Philippe Kernevez Date: Mon, 16 Oct 2023 13:55:54 +0200 Subject: [PATCH 06/31] dd SCSecurityFilter resources --- CHANGELOG.md | 3 + .../MSFT_SCSecurityFilter.psm1 | 530 ++++++++++++++++++ .../MSFT_SCSecurityFilter.schema.mof | 17 + .../MSFT_SCSecurityFilter/readme.md | 5 + .../MSFT_SCSecurityFilter/settings.json | 16 + .../1-AddingNewSecurityFilter.ps1 | 29 + .../M365DSCIntegration.Master.Tests.ps1 | 12 + ...Microsoft365DSC.SCSecurityFilter.Tests.ps1 | 272 +++++++++ Tests/Unit/Stubs/Microsoft365.psm1 | 127 +++++ 9 files changed, 1011 insertions(+) create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_SCSecurityFilter/MSFT_SCSecurityFilter.psm1 create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_SCSecurityFilter/MSFT_SCSecurityFilter.schema.mof create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_SCSecurityFilter/readme.md create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_SCSecurityFilter/settings.json create mode 100644 Modules/Microsoft365DSC/Examples/Resources/SCSecurityFilter/1-AddingNewSecurityFilter.ps1 create mode 100644 Tests/Unit/Microsoft365DSC/Microsoft365DSC.SCSecurityFilter.Tests.ps1 diff --git a/CHANGELOG.md b/CHANGELOG.md index a032116246..4de13ea72e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,9 @@ FIXES [#3777](https://github.com/microsoft/Microsoft365DSC/issues/3777) * MISC * Fixes fancy quotes in complex objects for extraction. +* SCSecurityFilter + * Initial release + FIXES: [#3796](https://github.com/microsoft/Microsoft365DSC/issues/3796) # 1.23.1011.1 diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_SCSecurityFilter/MSFT_SCSecurityFilter.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_SCSecurityFilter/MSFT_SCSecurityFilter.psm1 new file mode 100644 index 0000000000..c2ab43fe5e --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_SCSecurityFilter/MSFT_SCSecurityFilter.psm1 @@ -0,0 +1,530 @@ +function Get-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + param + ( + # Resource properties + [Parameter(Mandatory = $true)] + [System.String] + $FilterName, + + [Parameter()] + [ValidateSet('Export', 'Preview', 'Purge', 'Search', 'All')] + [System.String] + $Action = 'All', + + [Parameter()] + [System.String[]] + $Users, + + [Parameter()] + [System.String] + $Description, + + [Parameter()] + [System.String[]] + $Filters, + + [Parameter()] + [ValidateSet( + 'APC', # Asia-Pacific + 'AUS', #Australia + 'CAN', # Canada + 'EUR', #Europe, Middle East, Africa + 'FRA', #France + 'GBR', # United Kingdom + 'IND', # India + 'JPN', # Japan + 'LAM', # Latin America + 'NAM' # North America + )] + [System.String] + $Region, + + # And the DSC ones + + [Parameter()] + [ValidateSet('Present', 'Absent')] + [System.String] + $Ensure = 'Present', + + [Parameter()] + [System.Management.Automation.PSCredential] + $Credential, + + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint, + + [Parameter()] + [System.String] + $CertificatePath, + + [Parameter()] + [System.Management.Automation.PSCredential] + $CertificatePassword + ) + + Write-Verbose -Message "Getting configuration of Security Filter for $FilterName" + + if ($Global:CurrentModeIsExport) + { + $ConnectionMode = New-M365DSCConnection -Workload 'SecurityComplianceCenter' ` + -InboundParameters $PSBoundParameters ` + -SkipModuleReload $true + } + else + { + $ConnectionMode = New-M365DSCConnection -Workload 'SecurityComplianceCenter' ` + -InboundParameters $PSBoundParameters + } + + #Ensure the proper dependencies are installed in the current environment. + Confirm-M365DSCDependencies + + #region Telemetry + $ResourceName = $MyInvocation.MyCommand.ModuleName -replace 'MSFT_', '' + $CommandName = $MyInvocation.MyCommand + $data = Format-M365DSCTelemetryParameters -ResourceName $ResourceName ` + -CommandName $CommandName ` + -Parameters $PSBoundParameters + Add-M365DSCTelemetryEvent -Data $data + #endregion + + $nullReturn = $PSBoundParameters + $nullReturn.Ensure = 'Absent' + try + { + try + { + $secFilter = Get-ComplianceSecurityFilter -FilterName $FilterName -ErrorAction SilentlyContinue -WarningAction Ignore -Confirm:$false + } + catch + { + throw $_ + } + + if ($null -eq $secFilter) + { + Write-Verbose -Message "Security Filter $($FilterName) does not exist." + return $nullReturn + } + else + { + Write-Verbose "Found existing Security Filter $($FilterName)" + $result = @{ + FilterName = $secFilter.FilterName + Action = $secFilter.Action + Users = $secFilter.Users + Description = $secFilter.Description + Filters = $secFilter.Filters + Region = $secFilter.Region + Credential = $Credential + ApplicationId = $ApplicationId + TenantId = $TenantId + CertificateThumbprint = $CertificateThumbprint + CertificatePath = $CertificatePath + CertificatePassword = $CertificatePassword + Ensure = 'Present' + } + + Write-Verbose -Message "Get-TargetResource Result: `n $(Convert-M365DscHashtableToString -Hashtable $result)" + return $result + } + } + catch + { + New-M365DSCLogEntry -Message 'Error retrieving data:' ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + + return $nullReturn + } +} + +function Set-TargetResource +{ + [CmdletBinding()] + param + ( + # Resource properties + [Parameter(Mandatory = $true)] + [System.String] + $FilterName, + + [Parameter()] + [ValidateSet('Export', 'Preview', 'Purge', 'Search', 'All')] + [System.String] + $Action = 'All', + + [Parameter()] + [System.String[]] + $Users, + + [Parameter()] + [System.String] + $Description, + + [Parameter()] + [System.String[]] + $Filters, + + [Parameter()] + [ValidateSet( + 'APC', # Asia-Pacific + 'AUS', #Australia + 'CAN', # Canada + 'EUR', #Europe, Middle East, Africa + 'FRA', #France + 'GBR', # United Kingdom + 'IND', # India + 'JPN', # Japan + 'LAM', # Latin America + 'NAM' # North America + )] + [System.String] + $Region, + + # And the DSC ones + [Parameter()] + [ValidateSet('Present', 'Absent')] + [System.String] + $Ensure = 'Present', + + [Parameter()] + [System.Management.Automation.PSCredential] + $Credential, + + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint, + + [Parameter()] + [System.String] + $CertificatePath, + + [Parameter()] + [System.Management.Automation.PSCredential] + $CertificatePassword + ) + + Write-Verbose -Message "Setting configuration of Security Filter for $FilterName" + + #Ensure the proper dependencies are installed in the current environment. + Confirm-M365DSCDependencies + + #region Telemetry + $ResourceName = $MyInvocation.MyCommand.ModuleName -replace 'MSFT_', '' + $CommandName = $MyInvocation.MyCommand + $data = Format-M365DSCTelemetryParameters -ResourceName $ResourceName ` + -CommandName $CommandName ` + -Parameters $PSBoundParameters + Add-M365DSCTelemetryEvent -Data $data + #endregion + + $ConnectionMode = New-M365DSCConnection -Workload 'SecurityComplianceCenter' ` + -InboundParameters $PSBoundParameters + + $CurrentFilter = Get-TargetResource @PSBoundParameters + + if (('Present' -eq $Ensure) -and ('Absent' -eq $CurrentFilter.Ensure)) + { + Write-Verbose "Creating new Security Filter '$FilterName'." + + $CreationParams = ([Hashtable]$PSBoundParameters).Clone() + + #Remove parameters not used in New-ComplianceSecurityFilter + $CreationParams.Remove('Ensure') | Out-Null + + # Remove authentication parameters + $CreationParams.Remove('Credential') | Out-Null + $CreationParams.Remove('ApplicationId') | Out-Null + $CreationParams.Remove('TenantId') | Out-Null + $CreationParams.Remove('CertificatePath') | Out-Null + $CreationParams.Remove('CertificatePassword') | Out-Null + $CreationParams.Remove('CertificateThumbprint') | Out-Null + $CreationParams.Remove('ManagedIdentity') | Out-Null + $CreationParams.Remove('ApplicationSecret') | Out-Null + + try + { + New-ComplianceSecurityFilter @CreationParams -Confirm:$false + } + catch + { + Write-Warning "New-ComplianceSecurityFilter is not available in tenant $($Credential.UserName.Split('@')[1]): $_" + } + } + elseif (('Present' -eq $Ensure) -and ('Present' -eq $CurrentFilter.Ensure)) + { + Write-Verbose "Updating existing Security Filter '$FilterName'." + + $SetParams = ([Hashtable]$PSBoundParameters).Clone() + + #Remove unused parameters for Set-Label cmdlet + $SetParams.Remove('Ensure') | Out-Null + + # Remove authentication parameters + $SetParams.Remove('Credential') | Out-Null + $SetParams.Remove('ApplicationId') | Out-Null + $SetParams.Remove('TenantId') | Out-Null + $SetParams.Remove('CertificatePath') | Out-Null + $SetParams.Remove('CertificatePassword') | Out-Null + $SetParams.Remove('CertificateThumbprint') | Out-Null + $SetParams.Remove('ManagedIdentity') | Out-Null + $SetParams.Remove('ApplicationSecret') | Out-Null + + try + { + Set-ComplianceSecurityFilter @SetParams -Confirm:$false + } + catch + { + Write-Warning "Set-ComplianceSecurityFilter is not available in tenant $($Credential.UserName.Split('@')[1]): $_" + } + } + elseif (('Absent' -eq $Ensure) -and ('Present' -eq $CurrentFilter.Ensure)) + { + # If the filter exists and it shouldn't, simply remove it;Need to force deletion + Write-Verbose -Message "Deleting Security Filter $FilterName." + + try + { + Remove-ComplianceSecurityFilter -FilterName $FilterName -Confirm:$false + } + catch + { + Write-Warning "emove-ComplianceSecurityFilter is not available in tenant $($Credential.UserName.Split('@')[1]): $_" + } + } +} + +function Test-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Boolean])] + param + ( + # Resource properties + [Parameter(Mandatory = $true)] + [System.String] + $FilterName, + + [Parameter()] + [ValidateSet('Export', 'Preview', 'Purge', 'Search', 'All')] + [System.String] + $Action = 'All', + + [Parameter()] + [System.String[]] + $Users, + + [Parameter()] + [System.String] + $Description, + + [Parameter()] + [System.String[]] + $Filters, + + [Parameter()] + [ValidateSet( + 'APC', # Asia-Pacific + 'AUS', #Australia + 'CAN', # Canada + 'EUR', #Europe, Middle East, Africa + 'FRA', #France + 'GBR', # United Kingdom + 'IND', # India + 'JPN', # Japan + 'LAM', # Latin America + 'NAM' # North America + )] + [System.String] + $Region, + + # And the DSC ones + [Parameter()] + [ValidateSet('Present', 'Absent')] + [System.String] + $Ensure = 'Present', + + [Parameter()] + [System.Management.Automation.PSCredential] + $Credential, + + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint, + + [Parameter()] + [System.String] + $CertificatePath, + + [Parameter()] + [System.Management.Automation.PSCredential] + $CertificatePassword + ) + #Ensure the proper dependencies are installed in the current environment. + Confirm-M365DSCDependencies + + #region Telemetry + $ResourceName = $MyInvocation.MyCommand.ModuleName -replace 'MSFT_', '' + $CommandName = $MyInvocation.MyCommand + $data = Format-M365DSCTelemetryParameters -ResourceName $ResourceName ` + -CommandName $CommandName ` + -Parameters $PSBoundParameters + Add-M365DSCTelemetryEvent -Data $data + #endregion + + Write-Verbose -Message "Testing configuration of Sensitivity label for $FilterName" + $CurrentValues = Get-TargetResource @PSBoundParameters + + $ValuesToCheck = $PSBoundParameters + + # Remove authentication parameters + $ValuesToCheck.Remove('Credential') | Out-Null + $ValuesToCheck.Remove('ApplicationId') | Out-Null + $ValuesToCheck.Remove('TenantId') | Out-Null + $ValuesToCheck.Remove('CertificatePath') | Out-Null + $ValuesToCheck.Remove('CertificatePassword') | Out-Null + $ValuesToCheck.Remove('CertificateThumbprint') | Out-Null + $ValuesToCheck.Remove('ManagedIdentity') | Out-Null + $ValuesToCheck.Remove('ApplicationSecret') | Out-Null + + Write-Verbose -Message "Current Values: $(Convert-M365DscHashtableToString -Hashtable $CurrentValues)" + Write-Verbose -Message "Target Values: $(Convert-M365DscHashtableToString -Hashtable $ValuesToCheck)" + + $TestResult = Test-M365DSCParameterState -CurrentValues $CurrentValues ` + -Source $($MyInvocation.MyCommand.Source) ` + -DesiredValues $ValuesToCheck ` + -ValuesToCheck $ValuesToCheck.Keys + + Write-Verbose -Message "Test-TargetResource returned $TestResult" + return $TestResult +} + +function Export-TargetResource +{ + [CmdletBinding()] + [OutputType([System.String])] + param + ( + [Parameter()] + [System.Management.Automation.PSCredential] + $Credential, + + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint, + + [Parameter()] + [System.String] + $CertificatePath, + + [Parameter()] + [System.Management.Automation.PSCredential] + $CertificatePassword + ) + $ConnectionMode = New-M365DSCConnection -Workload 'SecurityComplianceCenter' ` + -InboundParameters $PSBoundParameters ` + -SkipModuleReload $true + + #Ensure the proper dependencies are installed in the current environment. + Confirm-M365DSCDependencies + + #region Telemetry + $ResourceName = $MyInvocation.MyCommand.ModuleName -replace 'MSFT_', '' + $CommandName = $MyInvocation.MyCommand + $data = Format-M365DSCTelemetryParameters -ResourceName $ResourceName ` + -CommandName $CommandName ` + -Parameters $PSBoundParameters + Add-M365DSCTelemetryEvent -Data $data + #endregion + + try + { + [array]$filters = Get-ComplianceSecurityFilter -ErrorAction Stop -WarningAction Ignore -Confirm:$false + + $dscContent = '' + $i = 1 + if ($filters.Length -eq 0) + { + Write-Host $Global:M365DSCEmojiGreenCheckMark + } + else + { + Write-Host "`r`n" -NoNewline + } + foreach ($filter in $filters) + { + Write-Host " |---[$i/$($filters.Count)] $($filter.FilterName)" -NoNewline + + $Results = Get-TargetResource @PSBoundParameters -FilterName $filter.FilterName + + $Results = Update-M365DSCExportAuthenticationResults -ConnectionMode $ConnectionMode ` + -Results $Results + $currentDSCBlock = Get-M365DSCExportContentForResource -ResourceName $ResourceName ` + -ConnectionMode $ConnectionMode ` + -ModulePath $PSScriptRoot ` + -Results $Results ` + -Credential $Credential + + Write-Host $Global:M365DSCEmojiGreenCheckMark + $dscContent += $currentDSCBlock + Save-M365DSCPartialExport -Content $currentDSCBlock ` + -FileName $Global:PartialExportFileName + $i++ + } + } + catch + { + Write-Host $Global:M365DSCEmojiRedX + + New-M365DSCLogEntry -Message 'Error during Export:' ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + + return '' + } + return $dscContent +} + +Export-ModuleMember -Function *-TargetResource diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_SCSecurityFilter/MSFT_SCSecurityFilter.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_SCSecurityFilter/MSFT_SCSecurityFilter.schema.mof new file mode 100644 index 0000000000..00455b3a46 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_SCSecurityFilter/MSFT_SCSecurityFilter.schema.mof @@ -0,0 +1,17 @@ +[ClassVersion("1.0.0.0"), FriendlyName("SCSecurityFilter")] +class MSFT_SCSecurityFilter : OMI_BaseResource +{ + [Key, Description("The FilterName parameter specifies the name of the compliance security filter that you want to view. If the value contains spaces, enclose the value in quotation marks (\").")] String FilterName; + [Write, Description("The Action parameter filters the results by the type of search action that a filter is applied to. "),ValueMap{"Export", "Preview", "Purge", "Search", "All"}, Values{"Export", "Preview", "Purge", "Search", "All"}] String Action; + [Write, Description("The User parameter filters the results by the user who gets a filter applied to their searches. Acceptable values are : The alias or email address of a user, All or The name of a role group")] String Users[]; + [Write, Description("The Description parameter specifies a description for the compliance security filter. The maximum length is 256 characters. If the value contains spaces, enclose the value in quotation marks (\").")] String Description; + [Write, Description("The Filters parameter specifies the search criteria for the compliance security filter. The filters are applied to the users specified by the Users parameter. You can create three different types of filters: Mailbox filter, Mailbox content filter or Site and site content filter")] String Filters[]; + [Write, Description("The Region parameter specifies the satellite location for multi-geo tenants to conduct eDiscovery searches in."),ValueMap{"APC", "AUS", "CAN", "EUR", "FRA", "GBR", "IND", "JPN", "LAM", "NAM", ""}, Values{"APC", "AUS", "CAN", "EUR", "FRA", "GBR", "IND", "JPN", "LAM", "NAM", ""}] String Region; + [Write, Description("Credentials of the Exchange Global Admin"), EmbeddedInstance("MSFT_Credential")] string Credential; + [Write, Description("Id of the Azure Active Directory application to authenticate with.")] String ApplicationId; + [Write, Description("Id of the Azure Active Directory tenant used for authentication.")] String TenantId; + [Write, Description("Thumbprint of the Azure Active Directory application's authentication certificate to use for authentication.")] String CertificateThumbprint; + [Write, Description("Path to certificate used in service principal usually a PFX file.")] String CertificatePath; + [Write, Description("Username can be made up to anything but password will be used for CertificatePassword"), EmbeddedInstance("MSFT_Credential")] String CertificatePassword; + [Write, Description("Specify if this label policy should exist or not."), ValueMap{"Present","Absent"}, Values{"Present","Absent"}] String Ensure; +}; diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_SCSecurityFilter/readme.md b/Modules/Microsoft365DSC/DSCResources/MSFT_SCSecurityFilter/readme.md new file mode 100644 index 0000000000..2be230efd0 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_SCSecurityFilter/readme.md @@ -0,0 +1,5 @@ +# SCSecurityFilter + +## Description + +This resource configures a Security Filter in Security and Compliance. diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_SCSecurityFilter/settings.json b/Modules/Microsoft365DSC/DSCResources/MSFT_SCSecurityFilter/settings.json new file mode 100644 index 0000000000..ff244b391b --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_SCSecurityFilter/settings.json @@ -0,0 +1,16 @@ +{ + "resourceName": "SCSecurityFilter", + "description": "", + "permissions": { + "graph": { + "delegated": { + "read": [], + "update": [] + }, + "application": { + "read": [], + "update": [] + } + } + } +} diff --git a/Modules/Microsoft365DSC/Examples/Resources/SCSecurityFilter/1-AddingNewSecurityFilter.ps1 b/Modules/Microsoft365DSC/Examples/Resources/SCSecurityFilter/1-AddingNewSecurityFilter.ps1 new file mode 100644 index 0000000000..6134df69fd --- /dev/null +++ b/Modules/Microsoft365DSC/Examples/Resources/SCSecurityFilter/1-AddingNewSecurityFilter.ps1 @@ -0,0 +1,29 @@ +<# +This example is used to test new resources and showcase the usage of new resources being worked on. +It is not meant to use as a production baseline. +#> + +Configuration Example +{ + param( + [Parameter(Mandatory = $true)] + [PSCredential] + $credsGlobalAdmin + ) + Import-DscResource -ModuleName Microsoft365DSC + + node localhost + { + SCSecurityLabel 'ConfigureSecurityLabel' + { + FilterName = "My Filter Name" + Action = "All" + Users = @("jonh.doe@1234.onmicrosoft.com") + Description = "Demo Security Label description" + Filters = @("Mailbox_CountryCode -eq '124'") + Region = "AUS" + Ensure = "Present" + Credential = $credsGlobalAdmin + } + } +} diff --git a/Tests/Integration/M365DSCIntegration.Master.Tests.ps1 b/Tests/Integration/M365DSCIntegration.Master.Tests.ps1 index d72926d762..e0f052fb37 100644 --- a/Tests/Integration/M365DSCIntegration.Master.Tests.ps1 +++ b/Tests/Integration/M365DSCIntegration.Master.Tests.ps1 @@ -684,6 +684,18 @@ Configuration Master Credential = $GlobalAdmin } + + SCSecurityFilter SCSecFilter + { + Action = "All" + Description = "My Desc" + FilterName = "MYFILTER" + Filters = @("Mailbox_CountryCode -eq '124'") + Region = "FRA" + Users = @("John.Smith@$Domain") + Ensure = "Present" + Credential = $GlobalAdmin + } #endregion #region SPO diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.SCSecurityFilter.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.SCSecurityFilter.Tests.ps1 new file mode 100644 index 0000000000..6653e9606c --- /dev/null +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.SCSecurityFilter.Tests.ps1 @@ -0,0 +1,272 @@ +[CmdletBinding()] +param( +) +$M365DSCTestFolder = Join-Path -Path $PSScriptRoot ` + -ChildPath '..\..\Unit' ` + -Resolve +$CmdletModule = (Join-Path -Path $M365DSCTestFolder ` + -ChildPath '\Stubs\Microsoft365.psm1' ` + -Resolve) +$GenericStubPath = (Join-Path -Path $M365DSCTestFolder ` + -ChildPath '\Stubs\Generic.psm1' ` + -Resolve) +Import-Module -Name (Join-Path -Path $M365DSCTestFolder ` + -ChildPath '\UnitTestHelper.psm1' ` + -Resolve) + +$Global:DscHelper = New-M365DscUnitTestHelper -StubModule $CmdletModule ` + -DscResource 'SCSecurityFilter' -GenericStubModule $GenericStubPath +Describe -Name $Global:DscHelper.DescribeHeader -Fixture { + InModuleScope -ModuleName $Global:DscHelper.ModuleName -ScriptBlock { + Invoke-Command -ScriptBlock $Global:DscHelper.InitializeScript -NoNewScope + + BeforeAll { + $secpasswd = ConvertTo-SecureString 'test@password1' -AsPlainText -Force + $Credential = New-Object System.Management.Automation.PSCredential ('tenantadmin@mydomain.com', $secpasswd) + + Mock -CommandName Confirm-M365DSCDependencies -MockWith { + } + + Mock -CommandName New-M365DSCConnection -MockWith { + return 'Credentials' + } + + Mock -CommandName Import-PSSession -MockWith { + } + + Mock -CommandName New-PSSession -MockWith { + } + + + Mock -CommandName Remove-ComplianceSecurityFilter -MockWith { + } + + Mock -CommandName New-ComplianceSecurityFilter -MockWith { + return @{ + + } + } + + Mock -CommandName Set-ComplianceSecurityFilter -MockWith { + return @{ + + } + } + + Mock -CommandName Start-Sleep -MockWith { + } + + # Mock Write-Host to hide output during the tests + Mock -CommandName Write-Host -MockWith { + } + } + + # Test contexts + Context -Name "Security Filter doesn't already exist but should" -Fixture { + BeforeAll { + $testParams = @{ + Action = "All" + Description = "My Desc" + FilterName = "MYFILTER" + Filters = @("Mailbox_CountryCode -eq '124'") + Region = "FRA" + Users = @("John.Smith@$Domain") + Credential = $Credential + Ensure = 'Present' + } + + Mock -CommandName Get-ComplianceSecurityFilter -MockWith { + return $null + } + } + + It 'Should return Absent from the Get method' { + (Get-TargetResource @testParams).Ensure | Should -Be 'Absent' + } + + It 'Should return false from the Test method' { + Test-TargetResource @testParams | Should -Be $false + } + + It 'Should call the New method' { + Set-TargetResource @testParams + Should -Invoke -CommandName New-ComplianceSecurityFilter -Exactly 1 + Should -Invoke -CommandName Set-ComplianceSecurityFilter -Exactly 0 + Should -Invoke -CommandName Remove-ComplianceSecurityFilter -Exactly 0 + } + } + + Context -Name 'Security Filter exists but is not in the Desired State' -Fixture { + BeforeAll { + $testParams = @{ + Action = "All" + Description = "My Desc" + FilterName = "MYFILTER" + Filters = @("Mailbox_CountryCode -eq '124'") + Region = "FRA" + Users = @("John.Smith@$Domain") + Credential = $Credential + Ensure = 'Present' + } + + Mock -CommandName Get-ComplianceSecurityFilter -MockWith { + return @{ + Action = "All" + Description = "My Desc" + FilterName = "MYFILTER" + Filters = @("Mailbox_CountryCode -eq '124'") + Region = "AUS" # This is different + Users = @("John.Smith@$Domain") + Credential = $Credential + Ensure = 'Present' + } + } + } + + It 'Should return Present from the Get method' { + (Get-TargetResource @testParams).Ensure | Should -Be 'Present' + } + + It 'Should return true from the Test method' { + Test-TargetResource @testParams | Should -Be $false + } + + It 'Should update from the Set method' { + Set-TargetResource @testParams + Should -Invoke -CommandName New-ComplianceSecurityFilter -Exactly 0 + Should -Invoke -CommandName Set-ComplianceSecurityFilter -Exactly 1 + Should -Invoke -CommandName Remove-ComplianceSecurityFilter -Exactly 0 + } + + } + + Context -Name 'Security Filter exists and is already in the Desired State' -Fixture { + BeforeAll { + $testParams = @{ + Action = "All" + Description = "My Desc" + FilterName = "MYFILTER" + Filters = @("Mailbox_CountryCode -eq '124'") + Region = "FRA" + Users = @("John.Smith@$Domain") + Ensure = 'Present' + } + + Mock -CommandName Get-ComplianceSecurityFilter -MockWith { + return @{ + Action = "All" + Description = "My Desc" + FilterName = "MYFILTER" + Filters = @("Mailbox_CountryCode -eq '124'") + Region = "FRA" + Users = @("John.Smith@$Domain") + } + } + } + + It 'Should return Present from the Get method' { + $returnValue = Get-TargetResource @testParams + $returnValue.Ensure | Should -Be 'Present' + } + + It 'Should return true from the Test method' { + $returnValue = Test-TargetResource @testParams + $returnValue | Should -Be $true + } + + It 'Should update from the Set method' { + Set-TargetResource @testParams + Should -Invoke -CommandName New-ComplianceSecurityFilter -Exactly 0 + Should -Invoke -CommandName Set-ComplianceSecurityFilter -Exactly 1 + Should -Invoke -CommandName Remove-ComplianceSecurityFilter -Exactly 0 + } + + } + + Context -Name 'Security Filter exists but should not exist' -Fixture { + BeforeAll { + $testParams = @{ + Action = "All" + Description = "My Desc" + FilterName = "MYFILTER" + Filters = @("Mailbox_CountryCode -eq '124'") + Region = "FRA" + Users = @("John.Smith@$Domain") + Credential = $Credential + Ensure = 'Absent' + } + } + + It 'Should return true from the Test method' { + + Mock -CommandName Get-ComplianceSecurityFilter -MockWith { + return @{ + Action = "All" + Description = "My Desc" + FilterName = "MYFILTER" + Filters = @("Mailbox_CountryCode -eq '124'") + Region = "AUS" # This is different + Users = @("John.Smith@$Domain") + } + } + Test-TargetResource @testParams | Should -Be $false + } + It 'Should return Present from the Get method' { + + Mock -CommandName Get-ComplianceSecurityFilter -MockWith { + return @{ + Action = "All" + Description = "My Desc" + FilterName = "MYFILTER" + Filters = @("Mailbox_CountryCode -eq '124'") + Region = "AUS" # This is different + Users = @("John.Smith@$Domain") + } + } + (Get-TargetResource @testParams).Ensure | Should -Be 'Present' + + } + + It 'Should delete from the Set method' { + Mock -CommandName Get-ComplianceSecurityFilter -MockWith { + return @{ + Action = "All" + Description = "My Desc" + FilterName = "MYFILTER" + Filters = @("Mailbox_CountryCode -eq '124'") + Region = "AUS" # This is different + Users = @("John.Smith@$Domain") + } + } + Set-TargetResource @testParams + Should -Invoke -CommandName New-ComplianceSecurityFilter -Exactly 0 + Should -Invoke -CommandName Set-ComplianceSecurityFilter -Exactly 0 + Should -Invoke -CommandName Remove-ComplianceSecurityFilter -Exactly 1 + } + } + + Context -Name 'ReverseDSC Tests' -Fixture { + BeforeAll { + $Global:CurrentModeIsExport = $true + $Global:PartialExportFileName = "$(New-Guid).partial.ps1" + $testParams = @{ + Credential = $Credential + } + Mock -CommandName Get-ComplianceSecurityFilter -MockWith { + return @{ + FilterName = 'TestFilter' + Action = 'All' + } + } + } + + It 'Should Reverse Engineer resource from the Export method' { + $result = Export-TargetResource @testParams + $result | Should -Not -BeNullOrEmpty + Should -Invoke -CommandName Get-ComplianceSecurityFilter -Exactly 2 + } + } + } +} + +Invoke-Command -ScriptBlock $Global:DscHelper.CleanupScript -NoNewScope diff --git a/Tests/Unit/Stubs/Microsoft365.psm1 b/Tests/Unit/Stubs/Microsoft365.psm1 index 8b41f10e85..63cf874524 100644 --- a/Tests/Unit/Stubs/Microsoft365.psm1 +++ b/Tests/Unit/Stubs/Microsoft365.psm1 @@ -60734,6 +60734,28 @@ function Get-ComplianceTag $Identity ) } +function Get-ComplianceSecurityFilter +{ + [CmdletBinding()] + param( + [Parameter()] + [System.String] + $FilterName, + + [Parameter()] + [System.Boolean] + $Confirm, + + [Parameter()] + [ValidateSet('Export', 'Preview', 'Purge', 'Search', 'All')] + [System.String] + $Action = 'All', + + [Parameter()] + [System.String[]] + $Users + ) +} function Get-DeviceConditionalAccessPolicy { [CmdletBinding()] @@ -61924,6 +61946,52 @@ function New-ComplianceTag $MultiStageReviewProperty ) } +function New-ComplianceSecurityFilter +{ + [CmdletBinding()] + param( + [Parameter(Mandatory = $true)] + [System.String] + $FilterName, + + [Parameter(Mandatory = $true)] + [ValidateSet('Export', 'Preview', 'Purge', 'Search', 'All')] + [System.String] + $Action = 'All', + + [Parameter(Mandatory = $true)] + [System.String[]] + $Users, + + [Parameter()] + [System.Boolean] + $Confirm, + + [Parameter()] + [System.String] + $Description, + + [Parameter()] + [System.String[]] + $Filters, + + [Parameter()] + [ValidateSet( + 'APC', # Asia-Pacific + 'AUS', #Australia + 'CAN', # Canada + 'EUR', #Europe, Middle East, Africa + 'FRA', #France + 'GBR', # United Kingdom + 'IND', # India + 'JPN', # Japan + 'LAM', # Latin America + 'NAM' # North America + )] + [System.String] + $Region + ) +} function New-DeviceConditionalAccessPolicy { [CmdletBinding()] @@ -63854,6 +63922,19 @@ function Remove-ComplianceTag $ForceDeletion ) } +function Remove-ComplianceSecurityFilter +{ + [CmdletBinding()] + param( + [Parameter(Mandatory = $true)] + [System.String] + $FilterName, + + [Parameter()] + [System.Boolean] + $Confirm + ) +} function Remove-DeviceConditionalAccessPolicy { [CmdletBinding()] @@ -64873,6 +64954,52 @@ function Set-ComplianceTag $Force ) } +function Set-ComplianceSecurityFilter +{ + [CmdletBinding()] + param( + [Parameter(Mandatory = $true)] + [System.String] + $FilterName, + + [Parameter()] + [ValidateSet('Export', 'Preview', 'Purge', 'Search', 'All')] + [System.String] + $Action = 'All', + + [Parameter()] + [System.String[]] + $Users, + + [Parameter()] + [System.Boolean] + $Confirm, + + [Parameter()] + [System.String] + $Description, + + [Parameter()] + [System.String[]] + $Filters, + + [Parameter()] + [ValidateSet( + 'APC', # Asia-Pacific + 'AUS', #Australia + 'CAN', # Canada + 'EUR', #Europe, Middle East, Africa + 'FRA', #France + 'GBR', # United Kingdom + 'IND', # India + 'JPN', # Japan + 'LAM', # Latin America + 'NAM' # North America + )] + [System.String] + $Region + ) +} function Set-DeviceConditionalAccessPolicy { [CmdletBinding()] From 735366eb6d5b3a53faacb98b09998ef2ba55d62e Mon Sep 17 00:00:00 2001 From: Philippe Kernevez Date: Thu, 19 Oct 2023 21:22:36 +0200 Subject: [PATCH 07/31] Do not use FilterName parameter for export, it requires more non justify permissions --- .../MSFT_SCSecurityFilter.psm1 | 72 ++++++++++++++----- ...Microsoft365DSC.SCSecurityFilter.Tests.ps1 | 2 +- 2 files changed, 57 insertions(+), 17 deletions(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_SCSecurityFilter/MSFT_SCSecurityFilter.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_SCSecurityFilter/MSFT_SCSecurityFilter.psm1 index c2ab43fe5e..595704ada4 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_SCSecurityFilter/MSFT_SCSecurityFilter.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_SCSecurityFilter/MSFT_SCSecurityFilter.psm1 @@ -121,21 +121,7 @@ function Get-TargetResource else { Write-Verbose "Found existing Security Filter $($FilterName)" - $result = @{ - FilterName = $secFilter.FilterName - Action = $secFilter.Action - Users = $secFilter.Users - Description = $secFilter.Description - Filters = $secFilter.Filters - Region = $secFilter.Region - Credential = $Credential - ApplicationId = $ApplicationId - TenantId = $TenantId - CertificateThumbprint = $CertificateThumbprint - CertificatePath = $CertificatePath - CertificatePassword = $CertificatePassword - Ensure = 'Present' - } + $result = MapSecurityFilter $secFilter $Credential $ApplicationId $TenantId $CertificateThumbprint $CertificatePath $CertificatePassword Write-Verbose -Message "Get-TargetResource Result: `n $(Convert-M365DscHashtableToString -Hashtable $result)" return $result @@ -153,6 +139,56 @@ function Get-TargetResource } } +function MapSecurityFilter +{ + param( + [Parameter(Mandatory = $true)] + $Filter, + + [Parameter()] + [System.Management.Automation.PSCredential] + $Credential, + + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint, + + [Parameter()] + [System.String] + $CertificatePath, + + [Parameter()] + [System.Management.Automation.PSCredential] + $CertificatePassword + ) + $result = @{ + FilterName = $Filter.FilterName + Action = $Filter.Action + Users = $Filter.Users + Description = $Filter.Description + Filters = $Filter.Filters + Region = $Filter.Region + Credential = $Credential + ApplicationId = $ApplicationId + TenantId = $TenantId + CertificateThumbprint = $CertificateThumbprint + CertificatePath = $CertificatePath + CertificatePassword = $CertificatePassword + Ensure = 'Present' + } + return $result +} + + + function Set-TargetResource { [CmdletBinding()] @@ -495,7 +531,11 @@ function Export-TargetResource { Write-Host " |---[$i/$($filters.Count)] $($filter.FilterName)" -NoNewline - $Results = Get-TargetResource @PSBoundParameters -FilterName $filter.FilterName + # $GetParams = ([Hashtable]$PSBoundParameters).Clone() + # $GetParams.Add("FilterName", $filter.FilterName) + # $Results = Get-TargetResource @GetParams + $Results = MapSecurityFilter -Filter $filter -Credential $Credential -ApplicationId $ApplicationId ` + -TenantId $TenantId -CertificateThumbprint $CertificateThumbprint -CertificatePath $CertificatePath -CertificatePassword $CertificatePassword $Results = Update-M365DSCExportAuthenticationResults -ConnectionMode $ConnectionMode ` -Results $Results diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.SCSecurityFilter.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.SCSecurityFilter.Tests.ps1 index 6653e9606c..88c08621a1 100644 --- a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.SCSecurityFilter.Tests.ps1 +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.SCSecurityFilter.Tests.ps1 @@ -263,7 +263,7 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { It 'Should Reverse Engineer resource from the Export method' { $result = Export-TargetResource @testParams $result | Should -Not -BeNullOrEmpty - Should -Invoke -CommandName Get-ComplianceSecurityFilter -Exactly 2 + Should -Invoke -CommandName Get-ComplianceSecurityFilter -Exactly 1 } } } From b52c4dcb8663248f2a0b82dc48ab4b34c2b2cda2 Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Fri, 20 Oct 2023 07:36:03 -0400 Subject: [PATCH 08/31] Updated Dependencies --- CHANGELOG.md | 3 ++ .../Dependencies/Manifest.psd1 | 36 +++++++++---------- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a032116246..9042b2aae8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,9 @@ * TeamsComplianceRecordingPolicy * Fixes an issue where the Compliance Application ID wasn't properly retrieved. FIXES [#3712](https://github.com/microsoft/Microsoft365DSC/issues/3712) +* DEPENDENCIES + * Updated Microsoft.Graph dependencies to version 2.8.0. + * Updated MicrosoftTeams dependency to version 5.7.1. # 1.23.1018.1 diff --git a/Modules/Microsoft365DSC/Dependencies/Manifest.psd1 b/Modules/Microsoft365DSC/Dependencies/Manifest.psd1 index c284c7039b..145747cf7c 100644 --- a/Modules/Microsoft365DSC/Dependencies/Manifest.psd1 +++ b/Modules/Microsoft365DSC/Dependencies/Manifest.psd1 @@ -10,71 +10,71 @@ }, @{ ModuleName = 'Microsoft.Graph.Applications' - RequiredVersion = '2.7.0' + RequiredVersion = '2.8.0' }, @{ ModuleName = 'Microsoft.Graph.Authentication' - RequiredVersion = '2.7.0' + RequiredVersion = '2.8.0' }, @{ ModuleName = 'Microsoft.Graph.Beta.DeviceManagement' - RequiredVersion = '2.7.0' + RequiredVersion = '2.8.0' }, @{ ModuleName = 'Microsoft.Graph.Beta.Devices.CorporateManagement' - RequiredVersion = '2.7.0' + RequiredVersion = '2.8.0' }, @{ ModuleName = 'Microsoft.Graph.Beta.DeviceManagement.Administration' - RequiredVersion = '2.7.0' + RequiredVersion = '2.8.0' }, @{ ModuleName = 'Microsoft.Graph.Beta.DeviceManagement.Enrollment' - RequiredVersion = '2.7.0' + RequiredVersion = '2.8.0' }, @{ ModuleName = 'Microsoft.Graph.Beta.Identity.DirectoryManagement' - RequiredVersion = '2.7.0' + RequiredVersion = '2.8.0' }, @{ ModuleName = 'Microsoft.Graph.Beta.Identity.Governance' - RequiredVersion = '2.7.0' + RequiredVersion = '2.8.0' }, @{ ModuleName = 'Microsoft.Graph.Beta.Identity.SignIns' - RequiredVersion = '2.7.0' + RequiredVersion = '2.8.0' }, @{ ModuleName = 'Microsoft.Graph.Beta.Reports' - RequiredVersion = '2.7.0' + RequiredVersion = '2.8.0' }, @{ ModuleName = 'Microsoft.Graph.Beta.Teams' - RequiredVersion = '2.7.0' + RequiredVersion = '2.8.0' }, @{ ModuleName = 'Microsoft.Graph.DeviceManagement.Administration' - RequiredVersion = '2.7.0' + RequiredVersion = '2.8.0' }, @{ ModuleName = 'Microsoft.Graph.Beta.DirectoryObjects' - RequiredVersion = '2.7.0' + RequiredVersion = '2.8.0' }, @{ ModuleName = 'Microsoft.Graph.Groups' - RequiredVersion = '2.7.0' + RequiredVersion = '2.8.0' }, @{ ModuleName = 'Microsoft.Graph.Planner' - RequiredVersion = '2.7.0' + RequiredVersion = '2.8.0' }, @{ ModuleName = 'Microsoft.Graph.Users' - RequiredVersion = '2.7.0' + RequiredVersion = '2.8.0' }, @{ ModuleName = 'Microsoft.Graph.Users.Actions' - RequiredVersion = '2.7.0' + RequiredVersion = '2.8.0' }, @{ ModuleName = 'Microsoft.PowerApps.Administration.PowerShell' @@ -82,7 +82,7 @@ }, @{ ModuleName = 'MicrosoftTeams' - RequiredVersion = '5.6.0' + RequiredVersion = '5.7.1' }, @{ ModuleName = "MSCloudLoginAssistant" From c810cd499fcc3ab9eab0d6657a1c2ec26ca483a1 Mon Sep 17 00:00:00 2001 From: debghs <145260557+debghs@users.noreply.github.com> Date: Fri, 20 Oct 2023 17:52:07 +0530 Subject: [PATCH 09/31] fixed typo in authentication-and-permissions.md --- .../user-guide/get-started/authentication-and-permissions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/user-guide/get-started/authentication-and-permissions.md b/docs/docs/user-guide/get-started/authentication-and-permissions.md index c674b56ac0..fed5f1ce6c 100644 --- a/docs/docs/user-guide/get-started/authentication-and-permissions.md +++ b/docs/docs/user-guide/get-started/authentication-and-permissions.md @@ -50,7 +50,7 @@ It is also important to note that we have added logic inside of the commands tha ## Power Apps Permissions -In order to authenticate to Power Apps using a Service Principal (Certificate Thumbprint or ApplicationSecret), you will first need to define your app as a Power App Management app. For details on how to proceed, please refer to the folloring link: https://learn.microsoft.com/en-us/power-platform/admin/powershell-create-service-principal#registering-an-admin-management-application +In order to authenticate to Power Apps using a Service Principal (Certificate Thumbprint or ApplicationSecret), you will first need to define your app as a Power App Management app. For details on how to proceed, please refer to the following link: https://learn.microsoft.com/en-us/power-platform/admin/powershell-create-service-principal#registering-an-admin-management-application Additionally, to be able to authenticate using a Certificate Thumbprint, the underlying Power Apps PowerShell module used by Microsoft365DSC requires the certificate's private key (.pfx) to be registered under the current user's certificate store at Cert:\CurrentUser\My\. Omitting to register the private key will result in Microsoft365DSC throwing the following error when trying to authenticate to the Power Platform: From ba1bf743850be56714192e37867dccc6bde992a3 Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Fri, 20 Oct 2023 08:33:39 -0400 Subject: [PATCH 10/31] Initial --- CHANGELOG.md | 2 + ...ADAuthenticationContextClassReference.psm1 | 414 +++++++++++++++ ...enticationContextClassReference.schema.mof | 15 + .../readme.md | 6 + .../settings.json | 40 ++ ...nticationContextClassReference-Example.ps1 | 38 ++ ...henticationContextClassReference.Tests.ps1 | 489 ++++++++++++++++++ 7 files changed, 1004 insertions(+) create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationContextClassReference/MSFT_AADAuthenticationContextClassReference.psm1 create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationContextClassReference/MSFT_AADAuthenticationContextClassReference.schema.mof create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationContextClassReference/readme.md create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationContextClassReference/settings.json create mode 100644 Modules/Microsoft365DSC/Examples/Resources/AADAuthenticationContextClassReference/1-AADAuthenticationContextClassReference-Example.ps1 create mode 100644 Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADAuthenticationContextClassReference.Tests.ps1 diff --git a/CHANGELOG.md b/CHANGELOG.md index a032116246..72f6f2b504 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ # UNRELEASED +* AADAuthenticationContext + * Initial Release. * AADConditionalAccessPolicy * Adds support for Authentication Context. FIXES [#3813](https://github.com/microsoft/Microsoft365DSC/issues/3813) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationContextClassReference/MSFT_AADAuthenticationContextClassReference.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationContextClassReference/MSFT_AADAuthenticationContextClassReference.psm1 new file mode 100644 index 0000000000..843b58d9e8 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationContextClassReference/MSFT_AADAuthenticationContextClassReference.psm1 @@ -0,0 +1,414 @@ +function Get-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + param + ( + #region resource generator code + [Parameter(Mandatory = $true)] + [ValidateSet('c1', 'c2', 'c3', 'c4', 'c5', 'c6', 'c7', 'c8', 'c9', 'c10', 'c11', 'c12', 'c13', 'c14', 'c15', 'c16', 'c17', 'c18', 'c19', 'c20', 'c21', 'c22', 'c23', 'c24', 'c25')] + [System.String] + $Id, + + [Parameter(Mandatory = $true)] + [System.String] + $DisplayName, + + [Parameter()] + [System.String] + $Description, + + [Parameter()] + [System.Boolean] + $IsAvailable, + + [Parameter()] + [System.String] + [ValidateSet('Absent', 'Present')] + $Ensure = 'Present', + + [Parameter()] + [System.Management.Automation.PSCredential] + $Credential, + + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ApplicationSecret, + + [Parameter()] + [System.String] + $CertificateThumbprint, + + [Parameter()] + [Switch] + $ManagedIdentity + ) + + try + { + $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` + -InboundParameters $PSBoundParameters + + #Ensure the proper dependencies are installed in the current environment. + Confirm-M365DSCDependencies + + #region Telemetry + $ResourceName = $MyInvocation.MyCommand.ModuleName.Replace('MSFT_', '') + $CommandName = $MyInvocation.MyCommand + $data = Format-M365DSCTelemetryParameters -ResourceName $ResourceName ` + -CommandName $CommandName ` + -Parameters $PSBoundParameters + Add-M365DSCTelemetryEvent -Data $data + #endregion + + $nullResult = $PSBoundParameters + $nullResult.Ensure = 'Absent' + + $getValue = $null + + $getValue = Get-MgBetaIdentityConditionalAccessAuthenticationContextClassReference ` + -AuthenticationContextClassReferenceId $Id ` + -ErrorAction SilentlyContinue + + if ($null -eq $getValue) + { + Write-Verbose -Message "Could not find Authentication Context with Id {$Id}" + return $nullResult + } + Write-Verbose -Message "Authentication Context Policy with Id {$Id} was found." + + $results = @{ + Id = $getValue.Id + DisplayName = $getValue.DisplayName + Description = $getValue.Description + IsAvailable = [Boolean]$getValue.IsAvailable + Ensure = 'Present' + Credential = $Credential + ApplicationId = $ApplicationId + TenantId = $TenantId + ApplicationSecret = $ApplicationSecret + CertificateThumbprint = $CertificateThumbprint + Managedidentity = $ManagedIdentity.IsPresent + } + + return [System.Collections.Hashtable] $results + } + catch + { + New-M365DSCLogEntry -Message 'Error retrieving data:' ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + + return $nullResult + } +} + +function Set-TargetResource +{ + [CmdletBinding()] + param + ( + #region resource generator code + [Parameter(Mandatory = $true)] + [ValidateSet('c1', 'c2', 'c3', 'c4', 'c5', 'c6', 'c7', 'c8', 'c9', 'c10', 'c11', 'c12', 'c13', 'c14', 'c15', 'c16', 'c17', 'c18', 'c19', 'c20', 'c21', 'c22', 'c23', 'c24', 'c25')] + [System.String] + $Id, + + [Parameter(Mandatory = $true)] + [System.String] + $DisplayName, + + [Parameter()] + [System.String] + $Description, + + [Parameter()] + [System.Boolean] + $IsAvailable, + + [Parameter()] + [System.String] + [ValidateSet('Absent', 'Present')] + $Ensure = 'Present', + + [Parameter()] + [System.Management.Automation.PSCredential] + $Credential, + + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ApplicationSecret, + + [Parameter()] + [System.String] + $CertificateThumbprint, + + [Parameter()] + [Switch] + $ManagedIdentity + ) + + #Ensure the proper dependencies are installed in the current environment. + Confirm-M365DSCDependencies + + #region Telemetry + $ResourceName = $MyInvocation.MyCommand.ModuleName.Replace('MSFT_', '') + $CommandName = $MyInvocation.MyCommand + $data = Format-M365DSCTelemetryParameters -ResourceName $ResourceName ` + -CommandName $CommandName ` + -Parameters $PSBoundParameters + Add-M365DSCTelemetryEvent -Data $data + #endregion + + $currentInstance = Get-TargetResource @PSBoundParameters + + $BoundParameters = Remove-M365DSCAuthenticationParameter -BoundParameters $PSBoundParameters + + if ($Ensure -eq 'Present' -and $currentInstance.Ensure -eq 'Absent') + { + Write-Verbose -Message "Authentication Method Policy instance cannot be created" + } + elseif ($Ensure -eq 'Present' -and $currentInstance.Ensure -eq 'Present') + { + Write-Verbose -Message "Updating the Authentication Method Policy with Id {$($currentInstance.Id)}" + + $UpdateParameters = ([Hashtable]$BoundParameters).clone() + $UpdateParameters = Rename-M365DSCCimInstanceParameter -Properties $UpdateParameters + + $UpdateParameters.Remove('Id') | Out-Null + + $keys = (([Hashtable]$UpdateParameters).clone()).Keys + foreach ($key in $keys) + { + if ($null -ne $UpdateParameters.$key -and $UpdateParameters.$key.getType().Name -like '*cimInstance*') + { + $UpdateParameters.$key = Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject $UpdateParameters.$key + } + } + #region resource generator code + $UpdateParameters.Add("@odata.type", "#microsoft.graph.AuthenticationMethodsPolicy") + Update-MgBetaPolicyAuthenticationMethodPolicy -BodyParameter $UpdateParameters + #endregion + } + elseif ($Ensure -eq 'Absent' -and $currentInstance.Ensure -eq 'Present') + { + Write-Verbose -Message "Removing the Azure AD Authentication Method Policy with Id {$($currentInstance.Id)}" + #region resource generator code + Remove-MgBetaPolicyAuthenticationMethodPolicy + #endregion + } +} + +function Test-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Boolean])] + param + ( + #region resource generator code + [Parameter(Mandatory = $true)] + [ValidateSet('c1', 'c2', 'c3', 'c4', 'c5', 'c6', 'c7', 'c8', 'c9', 'c10', 'c11', 'c12', 'c13', 'c14', 'c15', 'c16', 'c17', 'c18', 'c19', 'c20', 'c21', 'c22', 'c23', 'c24', 'c25')] + [System.String] + $Id, + + [Parameter()] + [System.String] + $DisplayName, + + [Parameter()] + [System.String] + $Description, + + [Parameter()] + [System.Boolean] + $IsAvailable, + + [Parameter()] + [System.String] + [ValidateSet('Absent', 'Present')] + $Ensure = 'Present', + + [Parameter()] + [System.Management.Automation.PSCredential] + $Credential, + + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ApplicationSecret, + + [Parameter()] + [System.String] + $CertificateThumbprint, + + [Parameter()] + [Switch] + $ManagedIdentity + ) + + #Ensure the proper dependencies are installed in the current environment. + Confirm-M365DSCDependencies + + #region Telemetry + $ResourceName = $MyInvocation.MyCommand.ModuleName.Replace('MSFT_', '') + $CommandName = $MyInvocation.MyCommand + $data = Format-M365DSCTelemetryParameters -ResourceName $ResourceName ` + -CommandName $CommandName ` + -Parameters $PSBoundParameters + Add-M365DSCTelemetryEvent -Data $data + #endregion + + Write-Verbose -Message "Testing configuration of the Authentication Context Id {$Id}" + + $CurrentValues = Get-TargetResource @PSBoundParameters + $ValuesToCheck = ([Hashtable]$PSBoundParameters).clone() + + Write-Verbose -Message "Current Values: $(Convert-M365DscHashtableToString -Hashtable $CurrentValues)" + Write-Verbose -Message "Target Values: $(Convert-M365DscHashtableToString -Hashtable $ValuesToCheck)" + $testResult = Test-M365DSCParameterState -CurrentValues $CurrentValues ` + -Source $($MyInvocation.MyCommand.Source) ` + -DesiredValues $PSBoundParameters ` + -ValuesToCheck $ValuesToCheck.Keys + + Write-Verbose -Message "Test-TargetResource returned $testResult" + + return $testResult +} + +function Export-TargetResource +{ + [CmdletBinding()] + [OutputType([System.String])] + param + ( + [Parameter()] + [System.Management.Automation.PSCredential] + $Credential, + + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ApplicationSecret, + + [Parameter()] + [System.String] + $CertificateThumbprint, + + [Parameter()] + [Switch] + $ManagedIdentity + ) + + $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` + -InboundParameters $PSBoundParameters + + #Ensure the proper dependencies are installed in the current environment. + Confirm-M365DSCDependencies + + #region Telemetry + $ResourceName = $MyInvocation.MyCommand.ModuleName.Replace('MSFT_', '') + $CommandName = $MyInvocation.MyCommand + $data = Format-M365DSCTelemetryParameters -ResourceName $ResourceName ` + -CommandName $CommandName ` + -Parameters $PSBoundParameters + Add-M365DSCTelemetryEvent -Data $data + #endregion + + try + { + #region resource generator code + [array]$getValue = Get-MgBetaIdentityConditionalAccessAuthenticationContextClassReference ` + -ErrorAction Stop + #endregion + + $i = 1 + $dscContent = '' + if ($getValue.Length -eq 0) + { + Write-Host $Global:M365DSCEmojiGreenCheckMark + } + else + { + Write-Host "`r`n" -NoNewline + } + foreach ($config in $getValue) + { + $displayedKey = $config.Id + " - " + $config.DisplayName + + Write-Host " |---[$i/$($getValue.Count)] $displayedKey" -NoNewline + $params = @{ + Id = $config.Id + Ensure = 'Present' + Credential = $Credential + ApplicationId = $ApplicationId + TenantId = $TenantId + ApplicationSecret = $ApplicationSecret + CertificateThumbprint = $CertificateThumbprint + Managedidentity = $ManagedIdentity.IsPresent + } + + $Results = Get-TargetResource @Params + $Results = Update-M365DSCExportAuthenticationResults -ConnectionMode $ConnectionMode ` + -Results $Results + + $currentDSCBlock = Get-M365DSCExportContentForResource -ResourceName $ResourceName ` + -ConnectionMode $ConnectionMode ` + -ModulePath $PSScriptRoot ` + -Results $Results ` + -Credential $Credential + + $dscContent += $currentDSCBlock + Save-M365DSCPartialExport -Content $currentDSCBlock ` + -FileName $Global:PartialExportFileName + $i++ + Write-Host $Global:M365DSCEmojiGreenCheckMark + } + return $dscContent + } + catch + { + Write-Host $Global:M365DSCEmojiRedX + + New-M365DSCLogEntry -Message 'Error during Export:' ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + + return '' + } +} + +Export-ModuleMember -Function *-TargetResource diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationContextClassReference/MSFT_AADAuthenticationContextClassReference.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationContextClassReference/MSFT_AADAuthenticationContextClassReference.schema.mof new file mode 100644 index 0000000000..ed2055f575 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationContextClassReference/MSFT_AADAuthenticationContextClassReference.schema.mof @@ -0,0 +1,15 @@ +[ClassVersion("1.0.0.0"), FriendlyName("AADAuthenticationContext")] +class MSFT_AADAuthenticationContext : OMI_BaseResource +{ + [Key, Description("Identifier used to reference the authentication context class. The id is used to trigger step-up authentication for the referenced authentication requirements and is the value that will be issued in the acrs claim of an access token. This value in the claim is used to verify that the required authentication context has been satisfied. The allowed values are c1 through c25. ")] String Id; + [Write, Description("A friendly name that identifies the authenticationContextClassReference object when building user-facing admin experiences. For example, a selection UX")] String DisplayName; + [Write, Description("A short explanation of the policies that are enforced by authenticationContextClassReference. This value should be used to provide secondary text to describe the authentication context class reference when building user-facing admin experiences. For example, a selection UX.")] String Description; + [Write, Description("Indicates whether the authenticationContextClassReference has been published by the security admin and is ready for use by apps. When it's set to false, it shouldn't be shown in admin UX experiences because the value isn't currently available for selection.")] Boolean IsAvailable; + [Write, Description("Present ensures the policy exists, absent ensures it is removed."), ValueMap{"Present","Absent"}, Values{"Present","Absent"}] string Ensure; + [Write, Description("Credentials of the Admin"), EmbeddedInstance("MSFT_Credential")] string Credential; + [Write, Description("Id of the Azure Active Directory application to authenticate with.")] String ApplicationId; + [Write, Description("Id of the Azure Active Directory tenant used for authentication.")] String TenantId; + [Write, Description("Secret of the Azure Active Directory tenant used for authentication."), EmbeddedInstance("MSFT_Credential")] String ApplicationSecret; + [Write, Description("Thumbprint of the Azure Active Directory application's authentication certificate to use for authentication.")] String CertificateThumbprint; + [Write, Description("Managed ID being used for authentication.")] Boolean ManagedIdentity; +}; diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationContextClassReference/readme.md b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationContextClassReference/readme.md new file mode 100644 index 0000000000..212cc73c9b --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationContextClassReference/readme.md @@ -0,0 +1,6 @@ + +# AADAuthenticationMethodPolicy + +## Description + +Azure AD Authentication Method Policy diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationContextClassReference/settings.json b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationContextClassReference/settings.json new file mode 100644 index 0000000000..249e208352 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationContextClassReference/settings.json @@ -0,0 +1,40 @@ +{ + "resourceName": "AADAuthenticationMethodPolicy", + "description": "This resource configures an Azure AD Authentication Method Policy.", + "roles": { + "read": [ + "Security Reader" + ], + "update": [ + "Authentication Policy Administrator" + ] + }, + "permissions": { + "graph": { + "delegated": { + "read": [ + { + "name": "Policy.ReadWrite.AuthenticationMethod" + } + ], + "update": [ + { + "name": "Policy.ReadWrite.AuthenticationMethod" + } + ] + }, + "application": { + "read": [ + { + "name": "Policy.ReadWrite.AuthenticationMethod" + } + ], + "update": [ + { + "name": "Policy.ReadWrite.AuthenticationMethod" + } + ] + } + } + } +} diff --git a/Modules/Microsoft365DSC/Examples/Resources/AADAuthenticationContextClassReference/1-AADAuthenticationContextClassReference-Example.ps1 b/Modules/Microsoft365DSC/Examples/Resources/AADAuthenticationContextClassReference/1-AADAuthenticationContextClassReference-Example.ps1 new file mode 100644 index 0000000000..55efb80fe2 --- /dev/null +++ b/Modules/Microsoft365DSC/Examples/Resources/AADAuthenticationContextClassReference/1-AADAuthenticationContextClassReference-Example.ps1 @@ -0,0 +1,38 @@ +<# +This example is used to test new resources and showcase the usage of new resources being worked on. +It is not meant to use as a production baseline. +#> + +Configuration Example +{ + Import-DscResource -ModuleName Microsoft365DSC + + Node localhost + { + AADAuthenticationMethodPolicy "AADAuthenticationMethodPolicy-Authentication Methods Policy" + { + ApplicationId = $ConfigurationData.NonNodeData.ApplicationId; + CertificateThumbprint = $ConfigurationData.NonNodeData.CertificateThumbprint; + Description = "The tenant-wide policy that controls which authentication methods are allowed in the tenant, authentication method registration requirements, and self-service password reset settings"; + DisplayName = "Authentication Methods Policy"; + Ensure = "Present"; + Id = "authenticationMethodsPolicy"; + PolicyMigrationState = "preMigration"; + PolicyVersion = "1.4"; + RegistrationEnforcement = MSFT_MicrosoftGraphregistrationEnforcement{ + AuthenticationMethodsRegistrationCampaign = MSFT_MicrosoftGraphAuthenticationMethodsRegistrationCampaign{ + SnoozeDurationInDays = 1 + IncludeTargets = @( + MSFT_MicrosoftGraphAuthenticationMethodsRegistrationCampaignIncludeTarget{ + TargetedAuthenticationMethod = 'microsoftAuthenticator' + TargetType = 'group' + Id = 'all_users' + } + ) + State = 'default' + } + }; + TenantId = $ConfigurationData.NonNodeData.TenantId; + } + } +} diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADAuthenticationContextClassReference.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADAuthenticationContextClassReference.Tests.ps1 new file mode 100644 index 0000000000..9d4ad3d0d2 --- /dev/null +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADAuthenticationContextClassReference.Tests.ps1 @@ -0,0 +1,489 @@ +[CmdletBinding()] +param( +) +$M365DSCTestFolder = Join-Path -Path $PSScriptRoot ` + -ChildPath '..\..\Unit' ` + -Resolve +$CmdletModule = (Join-Path -Path $M365DSCTestFolder ` + -ChildPath '\Stubs\Microsoft365.psm1' ` + -Resolve) +$GenericStubPath = (Join-Path -Path $M365DSCTestFolder ` + -ChildPath '\Stubs\Generic.psm1' ` + -Resolve) +Import-Module -Name (Join-Path -Path $M365DSCTestFolder ` + -ChildPath '\UnitTestHelper.psm1' ` + -Resolve) + +$Global:DscHelper = New-M365DscUnitTestHelper -StubModule $CmdletModule ` + -DscResource "AADAuthenticationMethodPolicy" -GenericStubModule $GenericStubPath +Describe -Name $Global:DscHelper.DescribeHeader -Fixture { + InModuleScope -ModuleName $Global:DscHelper.ModuleName -ScriptBlock { + Invoke-Command -ScriptBlock $Global:DscHelper.InitializeScript -NoNewScope + BeforeAll { + + $secpasswd = ConvertTo-SecureString "f@kepassword1" -AsPlainText -Force + $Credential = New-Object System.Management.Automation.PSCredential ('tenantadmin@mydomain.com', $secpasswd) + + Mock -CommandName Confirm-M365DSCDependencies -MockWith { + } + + Mock -CommandName Update-MgBetaPolicyAuthenticationMethodPolicy -MockWith { + } + + Mock -CommandName Remove-MgBetaPolicyAuthenticationMethodPolicy -MockWith { + } + + Mock -CommandName New-M365DSCConnection -MockWith { + return "Credentials" + } + + # Mock Write-Host to hide output during the tests + Mock -CommandName Write-Host -MockWith { + } + } + # Test contexts + Context -Name "The AADAuthenticationMethodPolicy should exist but it DOES NOT" -Fixture { + BeforeAll { + $testParams = @{ + Description = "FakeStringValue" + DisplayName = "FakeStringValue" + Id = "FakeStringValue" + PolicyMigrationState = "preMigration" + PolicyVersion = "FakeStringValue" + ReconfirmationInDays = 25 + RegistrationEnforcement = (New-CimInstance -ClassName MSFT_MicrosoftGraphregistrationEnforcement -Property @{ + AuthenticationMethodsRegistrationCampaign = (New-CimInstance -ClassName MSFT_MicrosoftGraphauthenticationMethodsRegistrationCampaign -Property @{ + IncludeTargets = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_MicrosoftGraphauthenticationMethodsRegistrationCampaignIncludeTarget -Property @{ + Id = "FakeStringValue" + TargetType = "user" + TargetedAuthenticationMethod = "FakeStringValue" + } -ClientOnly) + ) + State = "default" + SnoozeDurationInDays = 25 + ExcludeTargets = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_AADAuthenticationMethodPolicyExcludeTarget -Property @{ + TargetType = "user" + Id = "FakeStringValue" + } -ClientOnly) + ) + } -ClientOnly) + } -ClientOnly) + SystemCredentialPreferences = (New-CimInstance -ClassName MSFT_MicrosoftGraphsystemCredentialPreferences -Property @{ + State = "default" + IncludeTargets = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_AADAuthenticationMethodPolicyIncludeTarget -Property @{ + TargetType = "user" + Id = "FakeStringValue" + } -ClientOnly) + ) + ExcludeTargets = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_AADAuthenticationMethodPolicyExcludeTarget -Property @{ + TargetType = "user" + Id = "FakeStringValue" + } -ClientOnly) + ) + } -ClientOnly) + Ensure = "Present" + Credential = $Credential; + } + + Mock -CommandName Get-MgBetaPolicyAuthenticationMethodPolicy -MockWith { + return $null + } + } + It 'Should return Values from the Get method' { + (Get-TargetResource @testParams).Ensure | Should -Be 'Absent' + } + It 'Should return false from the Test method' { + Test-TargetResource @testParams | Should -Be $false + } + } + + Context -Name "The AADAuthenticationMethodPolicy exists but it SHOULD NOT" -Fixture { + BeforeAll { + $testParams = @{ + Description = "FakeStringValue" + DisplayName = "FakeStringValue" + Id = "FakeStringValue" + PolicyMigrationState = "preMigration" + PolicyVersion = "FakeStringValue" + ReconfirmationInDays = 25 + RegistrationEnforcement = (New-CimInstance -ClassName MSFT_MicrosoftGraphregistrationEnforcement -Property @{ + AuthenticationMethodsRegistrationCampaign = (New-CimInstance -ClassName MSFT_MicrosoftGraphauthenticationMethodsRegistrationCampaign -Property @{ + IncludeTargets = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_MicrosoftGraphauthenticationMethodsRegistrationCampaignIncludeTarget -Property @{ + Id = "FakeStringValue" + TargetType = "user" + TargetedAuthenticationMethod = "FakeStringValue" + } -ClientOnly) + ) + State = "default" + SnoozeDurationInDays = 25 + ExcludeTargets = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_AADAuthenticationMethodPolicyExcludeTarget -Property @{ + TargetType = "user" + Id = "FakeStringValue" + } -ClientOnly) + ) + } -ClientOnly) + } -ClientOnly) + SystemCredentialPreferences = (New-CimInstance -ClassName MSFT_MicrosoftGraphsystemCredentialPreferences -Property @{ + State = "default" + IncludeTargets = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_AADAuthenticationMethodPolicyIncludeTarget -Property @{ + TargetType = "user" + Id = "FakeStringValue" + } -ClientOnly) + ) + ExcludeTargets = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_AADAuthenticationMethodPolicyExcludeTarget -Property @{ + TargetType = "user" + Id = "FakeStringValue" + } -ClientOnly) + ) + } -ClientOnly) + Ensure = 'Absent' + Credential = $Credential; + } + + Mock -CommandName Get-MgBetaPolicyAuthenticationMethodPolicy -MockWith { + return @{ + AdditionalProperties = @{ + '@odata.type' = "#microsoft.graph.AuthenticationMethodsPolicy" + } + Description = "FakeStringValue" + DisplayName = "FakeStringValue" + Id = "FakeStringValue" + PolicyMigrationState = "preMigration" + PolicyVersion = "FakeStringValue" + ReconfirmationInDays = 25 + RegistrationEnforcement = @{ + AuthenticationMethodsRegistrationCampaign = @{ + IncludeTargets = @( + @{ + Id = "FakeStringValue" + TargetType = "user" + TargetedAuthenticationMethod = "FakeStringValue" + } + ) + State = "default" + SnoozeDurationInDays = 25 + ExcludeTargets = @( + @{ + TargetType = "user" + Id = "FakeStringValue" + } + ) + } + } + SystemCredentialPreferences = @{ + State = "default" + IncludeTargets = @( + @{ + TargetType = "user" + Id = "FakeStringValue" + } + ) + ExcludeTargets = @( + @{ + TargetType = "user" + Id = "FakeStringValue" + } + ) + } + + } + } + } + + It 'Should return Values from the Get method' { + (Get-TargetResource @testParams).Ensure | Should -Be 'Present' + } + + It 'Should return true from the Test method' { + Test-TargetResource @testParams | Should -Be $false + } + + It 'Should Remove the group from the Set method' { + Set-TargetResource @testParams + Should -Invoke -CommandName Remove-MgBetaPolicyAuthenticationMethodPolicy -Exactly 1 + } + } + Context -Name "The AADAuthenticationMethodPolicy Exists and Values are already in the desired state" -Fixture { + BeforeAll { + $testParams = @{ + Description = "FakeStringValue" + DisplayName = "FakeStringValue" + Id = "FakeStringValue" + PolicyMigrationState = "preMigration" + PolicyVersion = "FakeStringValue" + ReconfirmationInDays = 25 + RegistrationEnforcement = (New-CimInstance -ClassName MSFT_MicrosoftGraphregistrationEnforcement -Property @{ + AuthenticationMethodsRegistrationCampaign = (New-CimInstance -ClassName MSFT_MicrosoftGraphauthenticationMethodsRegistrationCampaign -Property @{ + IncludeTargets = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_MicrosoftGraphauthenticationMethodsRegistrationCampaignIncludeTarget -Property @{ + Id = "FakeStringValue" + TargetType = "user" + TargetedAuthenticationMethod = "FakeStringValue" + } -ClientOnly) + ) + State = "default" + SnoozeDurationInDays = 25 + ExcludeTargets = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_AADAuthenticationMethodPolicyExcludeTarget -Property @{ + TargetType = "user" + Id = "FakeStringValue" + } -ClientOnly) + ) + } -ClientOnly) + } -ClientOnly) + SystemCredentialPreferences = (New-CimInstance -ClassName MSFT_MicrosoftGraphsystemCredentialPreferences -Property @{ + State = "default" + IncludeTargets = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_AADAuthenticationMethodPolicyIncludeTarget -Property @{ + TargetType = "user" + Id = "FakeStringValue" + } -ClientOnly) + ) + ExcludeTargets = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_AADAuthenticationMethodPolicyExcludeTarget -Property @{ + TargetType = "user" + Id = "FakeStringValue" + } -ClientOnly) + ) + } -ClientOnly) + Ensure = 'Present' + Credential = $Credential; + } + + Mock -CommandName Get-MgBetaPolicyAuthenticationMethodPolicy -MockWith { + return @{ + AdditionalProperties = @{ + '@odata.type' = "#microsoft.graph.AuthenticationMethodsPolicy" + } + Description = "FakeStringValue" + DisplayName = "FakeStringValue" + Id = "FakeStringValue" + PolicyMigrationState = "preMigration" + PolicyVersion = "FakeStringValue" + ReconfirmationInDays = 25 + RegistrationEnforcement = @{ + AuthenticationMethodsRegistrationCampaign = @{ + IncludeTargets = @( + @{ + Id = "FakeStringValue" + TargetType = "user" + TargetedAuthenticationMethod = "FakeStringValue" + } + ) + State = "default" + SnoozeDurationInDays = 25 + ExcludeTargets = @( + @{ + TargetType = "user" + Id = "FakeStringValue" + } + ) + } + } + SystemCredentialPreferences = @{ + State = "default" + IncludeTargets = @( + @{ + TargetType = "user" + Id = "FakeStringValue" + } + ) + ExcludeTargets = @( + @{ + TargetType = "user" + Id = "FakeStringValue" + } + ) + } + + } + } + } + + + It 'Should return true from the Test method' { + Test-TargetResource @testParams | Should -Be $true + } + } + + Context -Name "The AADAuthenticationMethodPolicy exists and values are NOT in the desired state" -Fixture { + BeforeAll { + $testParams = @{ + Description = "FakeStringValue" + DisplayName = "FakeStringValue" + Id = "FakeStringValue" + PolicyMigrationState = "preMigration" + PolicyVersion = "FakeStringValue" + ReconfirmationInDays = 25 + RegistrationEnforcement = (New-CimInstance -ClassName MSFT_MicrosoftGraphregistrationEnforcement -Property @{ + AuthenticationMethodsRegistrationCampaign = (New-CimInstance -ClassName MSFT_MicrosoftGraphauthenticationMethodsRegistrationCampaign -Property @{ + IncludeTargets = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_MicrosoftGraphauthenticationMethodsRegistrationCampaignIncludeTarget -Property @{ + Id = "FakeStringValue" + TargetType = "user" + TargetedAuthenticationMethod = "FakeStringValue" + } -ClientOnly) + ) + State = "default" + SnoozeDurationInDays = 25 + ExcludeTargets = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_AADAuthenticationMethodPolicyExcludeTarget -Property @{ + TargetType = "user" + Id = "FakeStringValue" + } -ClientOnly) + ) + } -ClientOnly) + } -ClientOnly) + SystemCredentialPreferences = (New-CimInstance -ClassName MSFT_MicrosoftGraphsystemCredentialPreferences -Property @{ + State = "default" + IncludeTargets = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_AADAuthenticationMethodPolicyIncludeTarget -Property @{ + TargetType = "user" + Id = "FakeStringValue" + } -ClientOnly) + ) + ExcludeTargets = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_AADAuthenticationMethodPolicyExcludeTarget -Property @{ + TargetType = "user" + Id = "FakeStringValue" + } -ClientOnly) + ) + } -ClientOnly) + Ensure = 'Present' + Credential = $Credential; + } + + Mock -CommandName Get-MgBetaPolicyAuthenticationMethodPolicy -MockWith { + return @{ + Description = "FakeStringValue" + DisplayName = "FakeStringValue" + Id = "FakeStringValue" + PolicyMigrationState = "preMigration" + PolicyVersion = "FakeStringValue" + ReconfirmationInDays = 7 + RegistrationEnforcement = @{ + AuthenticationMethodsRegistrationCampaign = @{ + IncludeTargets = @( + @{ + Id = "FakeStringValue" + TargetType = "user" + TargetedAuthenticationMethod = "FakeStringValue" + } + ) + State = "default" + SnoozeDurationInDays = 7 + ExcludeTargets = @( + @{ + TargetType = "user" + Id = "FakeStringValue" + } + ) + } + } + SystemCredentialPreferences = @{ + State = "default" + IncludeTargets = @( + @{ + TargetType = "user" + Id = "FakeStringValue" + } + ) + ExcludeTargets = @( + @{ + TargetType = "user" + Id = "FakeStringValue" + } + ) + } + } + } + } + + It 'Should return Values from the Get method' { + (Get-TargetResource @testParams).Ensure | Should -Be 'Present' + } + + It 'Should return false from the Test method' { + Test-TargetResource @testParams | Should -Be $false + } + + It 'Should call the Set method' { + Set-TargetResource @testParams + Should -Invoke -CommandName Update-MgBetaPolicyAuthenticationMethodPolicy -Exactly 1 + } + } + + Context -Name 'ReverseDSC Tests' -Fixture { + BeforeAll { + $Global:CurrentModeIsExport = $true + $Global:PartialExportFileName = "$(New-Guid).partial.ps1" + $testParams = @{ + Credential = $Credential + } + + Mock -CommandName Get-MgBetaPolicyAuthenticationMethodPolicy -MockWith { + return @{ + AdditionalProperties = @{ + '@odata.type' = "#microsoft.graph.AuthenticationMethodsPolicy" + } + Description = "FakeStringValue" + DisplayName = "FakeStringValue" + Id = "FakeStringValue" + PolicyMigrationState = "preMigration" + PolicyVersion = "FakeStringValue" + ReconfirmationInDays = 25 + RegistrationEnforcement = @{ + AuthenticationMethodsRegistrationCampaign = @{ + IncludeTargets = @( + @{ + Id = "FakeStringValue" + TargetType = "user" + TargetedAuthenticationMethod = "FakeStringValue" + } + ) + State = "default" + SnoozeDurationInDays = 25 + ExcludeTargets = @( + @{ + TargetType = "user" + Id = "FakeStringValue" + } + ) + } + } + SystemCredentialPreferences = @{ + State = "default" + IncludeTargets = @( + @{ + TargetType = "user" + Id = "FakeStringValue" + } + ) + ExcludeTargets = @( + @{ + TargetType = "user" + Id = "FakeStringValue" + } + ) + } + + } + } + } + It 'Should Reverse Engineer resource from the Export method' { + $result = Export-TargetResource @testParams + $result | Should -Not -BeNullOrEmpty + } + } + } +} + +Invoke-Command -ScriptBlock $Global:DscHelper.CleanupScript -NoNewScope From 237db1fcd012c678f1fbf044005e1e408cf349c8 Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Fri, 20 Oct 2023 09:18:28 -0400 Subject: [PATCH 11/31] Fixes --- ...ADAuthenticationContextClassReference.psm1 | 37 +- ...enticationContextClassReference.schema.mof | 8 +- ...nticationContextClassReference-Example.ps1 | 39 +- ...henticationContextClassReference.Tests.ps1 | 407 +++--------------- 4 files changed, 82 insertions(+), 409 deletions(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationContextClassReference/MSFT_AADAuthenticationContextClassReference.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationContextClassReference/MSFT_AADAuthenticationContextClassReference.psm1 index 843b58d9e8..0869dca002 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationContextClassReference/MSFT_AADAuthenticationContextClassReference.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationContextClassReference/MSFT_AADAuthenticationContextClassReference.psm1 @@ -10,7 +10,7 @@ function Get-TargetResource [System.String] $Id, - [Parameter(Mandatory = $true)] + [Parameter()] [System.String] $DisplayName, @@ -124,7 +124,7 @@ function Set-TargetResource [System.String] $Id, - [Parameter(Mandatory = $true)] + [Parameter()] [System.String] $DisplayName, @@ -179,41 +179,24 @@ function Set-TargetResource #endregion $currentInstance = Get-TargetResource @PSBoundParameters - $BoundParameters = Remove-M365DSCAuthenticationParameter -BoundParameters $PSBoundParameters if ($Ensure -eq 'Present' -and $currentInstance.Ensure -eq 'Absent') { - Write-Verbose -Message "Authentication Method Policy instance cannot be created" + Write-Verbose -Message "Creating new Authentication Context with Id {$Id}" + New-MgBetaIdentityConditionalAccessAuthenticationContextClassReference @BoundParameters | Out-Null } elseif ($Ensure -eq 'Present' -and $currentInstance.Ensure -eq 'Present') { - Write-Verbose -Message "Updating the Authentication Method Policy with Id {$($currentInstance.Id)}" - - $UpdateParameters = ([Hashtable]$BoundParameters).clone() - $UpdateParameters = Rename-M365DSCCimInstanceParameter -Properties $UpdateParameters - - $UpdateParameters.Remove('Id') | Out-Null - - $keys = (([Hashtable]$UpdateParameters).clone()).Keys - foreach ($key in $keys) - { - if ($null -ne $UpdateParameters.$key -and $UpdateParameters.$key.getType().Name -like '*cimInstance*') - { - $UpdateParameters.$key = Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject $UpdateParameters.$key - } - } - #region resource generator code - $UpdateParameters.Add("@odata.type", "#microsoft.graph.AuthenticationMethodsPolicy") - Update-MgBetaPolicyAuthenticationMethodPolicy -BodyParameter $UpdateParameters - #endregion + Write-Verbose -Message "Updating the Authentication Context with Id {$($currentInstance.Id)}" + $BoundParameters.Add('AuthenticationContextClassReferenceId', $Id) + $BoundParameters.Remove('Id') | Out-Null + Update-MgBetaIdentityConditionalAccessAuthenticationContextClassReference @BoundParameters | Out-Null } elseif ($Ensure -eq 'Absent' -and $currentInstance.Ensure -eq 'Present') { - Write-Verbose -Message "Removing the Azure AD Authentication Method Policy with Id {$($currentInstance.Id)}" - #region resource generator code - Remove-MgBetaPolicyAuthenticationMethodPolicy - #endregion + Write-Verbose -Message "Removing the Authentication Context with Id {$($currentInstance.Id)}" + Remove-MgBetaIdentityConditionalAccessAuthenticationContextClassReference -AuthenticationContextClassReferenceId $Id | Out-Null } } diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationContextClassReference/MSFT_AADAuthenticationContextClassReference.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationContextClassReference/MSFT_AADAuthenticationContextClassReference.schema.mof index ed2055f575..b7f86d5f21 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationContextClassReference/MSFT_AADAuthenticationContextClassReference.schema.mof +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationContextClassReference/MSFT_AADAuthenticationContextClassReference.schema.mof @@ -1,7 +1,7 @@ -[ClassVersion("1.0.0.0"), FriendlyName("AADAuthenticationContext")] -class MSFT_AADAuthenticationContext : OMI_BaseResource +[ClassVersion("1.0.0.0"), FriendlyName("AADAuthenticationContextClassReference")] +class MSFT_AADAuthenticationContextClassReference : OMI_BaseResource { - [Key, Description("Identifier used to reference the authentication context class. The id is used to trigger step-up authentication for the referenced authentication requirements and is the value that will be issued in the acrs claim of an access token. This value in the claim is used to verify that the required authentication context has been satisfied. The allowed values are c1 through c25. ")] String Id; + [Key, Description("Identifier used to reference the authentication context class. The id is used to trigger step-up authentication for the referenced authentication requirements and is the value that will be issued in the acrs claim of an access token. This value in the claim is used to verify that the required authentication context has been satisfied. The allowed values are c1 through c25."), ValueMap{"c1","c2","c3","c4","c5","c6","c7","c8","c9","c10","c11","c12","c13","c14","c15","c16","c17","c18","c19","c20","c21","c22","c23","c24","c25"}, Values{"c1","c2","c3","c4","c5","c6","c7","c8","c9","c10","c11","c12","c13","c14","c15","c16","c17","c18","c19","c20","c21","c22","c23","c24","c25"}] String Id; [Write, Description("A friendly name that identifies the authenticationContextClassReference object when building user-facing admin experiences. For example, a selection UX")] String DisplayName; [Write, Description("A short explanation of the policies that are enforced by authenticationContextClassReference. This value should be used to provide secondary text to describe the authentication context class reference when building user-facing admin experiences. For example, a selection UX.")] String Description; [Write, Description("Indicates whether the authenticationContextClassReference has been published by the security admin and is ready for use by apps. When it's set to false, it shouldn't be shown in admin UX experiences because the value isn't currently available for selection.")] Boolean IsAvailable; @@ -11,5 +11,5 @@ class MSFT_AADAuthenticationContext : OMI_BaseResource [Write, Description("Id of the Azure Active Directory tenant used for authentication.")] String TenantId; [Write, Description("Secret of the Azure Active Directory tenant used for authentication."), EmbeddedInstance("MSFT_Credential")] String ApplicationSecret; [Write, Description("Thumbprint of the Azure Active Directory application's authentication certificate to use for authentication.")] String CertificateThumbprint; - [Write, Description("Managed ID being used for authentication.")] Boolean ManagedIdentity; + [Write, Description("Managed ID being used for authentication.")] Boolean ManagedIdentity; }; diff --git a/Modules/Microsoft365DSC/Examples/Resources/AADAuthenticationContextClassReference/1-AADAuthenticationContextClassReference-Example.ps1 b/Modules/Microsoft365DSC/Examples/Resources/AADAuthenticationContextClassReference/1-AADAuthenticationContextClassReference-Example.ps1 index 55efb80fe2..33c0004a94 100644 --- a/Modules/Microsoft365DSC/Examples/Resources/AADAuthenticationContextClassReference/1-AADAuthenticationContextClassReference-Example.ps1 +++ b/Modules/Microsoft365DSC/Examples/Resources/AADAuthenticationContextClassReference/1-AADAuthenticationContextClassReference-Example.ps1 @@ -5,34 +5,25 @@ It is not meant to use as a production baseline. Configuration Example { + param + ( + [Parameter(Mandatory = $true)] + [PSCredential] + $credsCredential + ) + Import-DscResource -ModuleName Microsoft365DSC - Node localhost + node localhost { - AADAuthenticationMethodPolicy "AADAuthenticationMethodPolicy-Authentication Methods Policy" + AADAuthenticationContextClassReference "AADAuthenticationContextClassReference-Test" { - ApplicationId = $ConfigurationData.NonNodeData.ApplicationId; - CertificateThumbprint = $ConfigurationData.NonNodeData.CertificateThumbprint; - Description = "The tenant-wide policy that controls which authentication methods are allowed in the tenant, authentication method registration requirements, and self-service password reset settings"; - DisplayName = "Authentication Methods Policy"; - Ensure = "Present"; - Id = "authenticationMethodsPolicy"; - PolicyMigrationState = "preMigration"; - PolicyVersion = "1.4"; - RegistrationEnforcement = MSFT_MicrosoftGraphregistrationEnforcement{ - AuthenticationMethodsRegistrationCampaign = MSFT_MicrosoftGraphAuthenticationMethodsRegistrationCampaign{ - SnoozeDurationInDays = 1 - IncludeTargets = @( - MSFT_MicrosoftGraphAuthenticationMethodsRegistrationCampaignIncludeTarget{ - TargetedAuthenticationMethod = 'microsoftAuthenticator' - TargetType = 'group' - Id = 'all_users' - } - ) - State = 'default' - } - }; - TenantId = $ConfigurationData.NonNodeData.TenantId; + Credential = $credsCredential; + Description = "Context test"; + DisplayName = "My Context"; + Ensure = "Present"; + Id = "c3"; + IsAvailable = $True; } } } diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADAuthenticationContextClassReference.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADAuthenticationContextClassReference.Tests.ps1 index 9d4ad3d0d2..a41d9b3ac9 100644 --- a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADAuthenticationContextClassReference.Tests.ps1 +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADAuthenticationContextClassReference.Tests.ps1 @@ -15,7 +15,7 @@ Import-Module -Name (Join-Path -Path $M365DSCTestFolder ` -Resolve) $Global:DscHelper = New-M365DscUnitTestHelper -StubModule $CmdletModule ` - -DscResource "AADAuthenticationMethodPolicy" -GenericStubModule $GenericStubPath + -DscResource "AADAuthenticationContextClassReference" -GenericStubModule $GenericStubPath Describe -Name $Global:DscHelper.DescribeHeader -Fixture { InModuleScope -ModuleName $Global:DscHelper.ModuleName -ScriptBlock { Invoke-Command -ScriptBlock $Global:DscHelper.InitializeScript -NoNewScope @@ -27,10 +27,10 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { Mock -CommandName Confirm-M365DSCDependencies -MockWith { } - Mock -CommandName Update-MgBetaPolicyAuthenticationMethodPolicy -MockWith { + Mock -CommandName Update-MgBetaIdentityConditionalAccessAuthenticationContextClassReference -MockWith { } - Mock -CommandName Remove-MgBetaPolicyAuthenticationMethodPolicy -MockWith { + Mock -CommandName Remove-MgBetaIdentityConditionalAccessAuthenticationContextClassReference -MockWith { } Mock -CommandName New-M365DSCConnection -MockWith { @@ -42,54 +42,18 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { } } # Test contexts - Context -Name "The AADAuthenticationMethodPolicy should exist but it DOES NOT" -Fixture { + Context -Name "The instance should exist but it DOES NOT" -Fixture { BeforeAll { $testParams = @{ - Description = "FakeStringValue" - DisplayName = "FakeStringValue" - Id = "FakeStringValue" - PolicyMigrationState = "preMigration" - PolicyVersion = "FakeStringValue" - ReconfirmationInDays = 25 - RegistrationEnforcement = (New-CimInstance -ClassName MSFT_MicrosoftGraphregistrationEnforcement -Property @{ - AuthenticationMethodsRegistrationCampaign = (New-CimInstance -ClassName MSFT_MicrosoftGraphauthenticationMethodsRegistrationCampaign -Property @{ - IncludeTargets = [CimInstance[]]@( - (New-CimInstance -ClassName MSFT_MicrosoftGraphauthenticationMethodsRegistrationCampaignIncludeTarget -Property @{ - Id = "FakeStringValue" - TargetType = "user" - TargetedAuthenticationMethod = "FakeStringValue" - } -ClientOnly) - ) - State = "default" - SnoozeDurationInDays = 25 - ExcludeTargets = [CimInstance[]]@( - (New-CimInstance -ClassName MSFT_AADAuthenticationMethodPolicyExcludeTarget -Property @{ - TargetType = "user" - Id = "FakeStringValue" - } -ClientOnly) - ) - } -ClientOnly) - } -ClientOnly) - SystemCredentialPreferences = (New-CimInstance -ClassName MSFT_MicrosoftGraphsystemCredentialPreferences -Property @{ - State = "default" - IncludeTargets = [CimInstance[]]@( - (New-CimInstance -ClassName MSFT_AADAuthenticationMethodPolicyIncludeTarget -Property @{ - TargetType = "user" - Id = "FakeStringValue" - } -ClientOnly) - ) - ExcludeTargets = [CimInstance[]]@( - (New-CimInstance -ClassName MSFT_AADAuthenticationMethodPolicyExcludeTarget -Property @{ - TargetType = "user" - Id = "FakeStringValue" - } -ClientOnly) - ) - } -ClientOnly) - Ensure = "Present" + Description = "This is my super context test"; + DisplayName = "My Super Context"; + Ensure = "Present"; + Id = "c3"; + IsAvailable = $True; Credential = $Credential; } - Mock -CommandName Get-MgBetaPolicyAuthenticationMethodPolicy -MockWith { + Mock -CommandName Get-MgBetaIdentityConditionalAccessAuthenticationContextClassReference -MockWith { return $null } } @@ -101,99 +65,23 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { } } - Context -Name "The AADAuthenticationMethodPolicy exists but it SHOULD NOT" -Fixture { + Context -Name "The instance exists but it SHOULD NOT" -Fixture { BeforeAll { $testParams = @{ - Description = "FakeStringValue" - DisplayName = "FakeStringValue" - Id = "FakeStringValue" - PolicyMigrationState = "preMigration" - PolicyVersion = "FakeStringValue" - ReconfirmationInDays = 25 - RegistrationEnforcement = (New-CimInstance -ClassName MSFT_MicrosoftGraphregistrationEnforcement -Property @{ - AuthenticationMethodsRegistrationCampaign = (New-CimInstance -ClassName MSFT_MicrosoftGraphauthenticationMethodsRegistrationCampaign -Property @{ - IncludeTargets = [CimInstance[]]@( - (New-CimInstance -ClassName MSFT_MicrosoftGraphauthenticationMethodsRegistrationCampaignIncludeTarget -Property @{ - Id = "FakeStringValue" - TargetType = "user" - TargetedAuthenticationMethod = "FakeStringValue" - } -ClientOnly) - ) - State = "default" - SnoozeDurationInDays = 25 - ExcludeTargets = [CimInstance[]]@( - (New-CimInstance -ClassName MSFT_AADAuthenticationMethodPolicyExcludeTarget -Property @{ - TargetType = "user" - Id = "FakeStringValue" - } -ClientOnly) - ) - } -ClientOnly) - } -ClientOnly) - SystemCredentialPreferences = (New-CimInstance -ClassName MSFT_MicrosoftGraphsystemCredentialPreferences -Property @{ - State = "default" - IncludeTargets = [CimInstance[]]@( - (New-CimInstance -ClassName MSFT_AADAuthenticationMethodPolicyIncludeTarget -Property @{ - TargetType = "user" - Id = "FakeStringValue" - } -ClientOnly) - ) - ExcludeTargets = [CimInstance[]]@( - (New-CimInstance -ClassName MSFT_AADAuthenticationMethodPolicyExcludeTarget -Property @{ - TargetType = "user" - Id = "FakeStringValue" - } -ClientOnly) - ) - } -ClientOnly) - Ensure = 'Absent' + Description = "This is my super context test"; + DisplayName = "My Super Context"; + Ensure = "Absent"; + Id = "c3"; + IsAvailable = $True; Credential = $Credential; } - Mock -CommandName Get-MgBetaPolicyAuthenticationMethodPolicy -MockWith { + Mock -CommandName Get-MgBetaIdentityConditionalAccessAuthenticationContextClassReference -MockWith { return @{ - AdditionalProperties = @{ - '@odata.type' = "#microsoft.graph.AuthenticationMethodsPolicy" - } - Description = "FakeStringValue" - DisplayName = "FakeStringValue" - Id = "FakeStringValue" - PolicyMigrationState = "preMigration" - PolicyVersion = "FakeStringValue" - ReconfirmationInDays = 25 - RegistrationEnforcement = @{ - AuthenticationMethodsRegistrationCampaign = @{ - IncludeTargets = @( - @{ - Id = "FakeStringValue" - TargetType = "user" - TargetedAuthenticationMethod = "FakeStringValue" - } - ) - State = "default" - SnoozeDurationInDays = 25 - ExcludeTargets = @( - @{ - TargetType = "user" - Id = "FakeStringValue" - } - ) - } - } - SystemCredentialPreferences = @{ - State = "default" - IncludeTargets = @( - @{ - TargetType = "user" - Id = "FakeStringValue" - } - ) - ExcludeTargets = @( - @{ - TargetType = "user" - Id = "FakeStringValue" - } - ) - } - + Description = "This is my super context test"; + DisplayName = "My Super Context"; + Id = "c3"; + IsAvailable = $True; } } } @@ -208,201 +96,52 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { It 'Should Remove the group from the Set method' { Set-TargetResource @testParams - Should -Invoke -CommandName Remove-MgBetaPolicyAuthenticationMethodPolicy -Exactly 1 + Should -Invoke -CommandName Remove-MgBetaIdentityConditionalAccessAuthenticationContextClassReference -Exactly 1 } } - Context -Name "The AADAuthenticationMethodPolicy Exists and Values are already in the desired state" -Fixture { + Context -Name "The instance exists and values are already in the desired state" -Fixture { BeforeAll { $testParams = @{ - Description = "FakeStringValue" - DisplayName = "FakeStringValue" - Id = "FakeStringValue" - PolicyMigrationState = "preMigration" - PolicyVersion = "FakeStringValue" - ReconfirmationInDays = 25 - RegistrationEnforcement = (New-CimInstance -ClassName MSFT_MicrosoftGraphregistrationEnforcement -Property @{ - AuthenticationMethodsRegistrationCampaign = (New-CimInstance -ClassName MSFT_MicrosoftGraphauthenticationMethodsRegistrationCampaign -Property @{ - IncludeTargets = [CimInstance[]]@( - (New-CimInstance -ClassName MSFT_MicrosoftGraphauthenticationMethodsRegistrationCampaignIncludeTarget -Property @{ - Id = "FakeStringValue" - TargetType = "user" - TargetedAuthenticationMethod = "FakeStringValue" - } -ClientOnly) - ) - State = "default" - SnoozeDurationInDays = 25 - ExcludeTargets = [CimInstance[]]@( - (New-CimInstance -ClassName MSFT_AADAuthenticationMethodPolicyExcludeTarget -Property @{ - TargetType = "user" - Id = "FakeStringValue" - } -ClientOnly) - ) - } -ClientOnly) - } -ClientOnly) - SystemCredentialPreferences = (New-CimInstance -ClassName MSFT_MicrosoftGraphsystemCredentialPreferences -Property @{ - State = "default" - IncludeTargets = [CimInstance[]]@( - (New-CimInstance -ClassName MSFT_AADAuthenticationMethodPolicyIncludeTarget -Property @{ - TargetType = "user" - Id = "FakeStringValue" - } -ClientOnly) - ) - ExcludeTargets = [CimInstance[]]@( - (New-CimInstance -ClassName MSFT_AADAuthenticationMethodPolicyExcludeTarget -Property @{ - TargetType = "user" - Id = "FakeStringValue" - } -ClientOnly) - ) - } -ClientOnly) - Ensure = 'Present' - Credential = $Credential; + Description = "This is my super context test"; + DisplayName = "My Super Context"; + Ensure = "Present"; + Id = "c3"; + IsAvailable = $True; + Credential = $Credential; } - Mock -CommandName Get-MgBetaPolicyAuthenticationMethodPolicy -MockWith { + Mock -CommandName Get-MgBetaIdentityConditionalAccessAuthenticationContextClassReference -MockWith { return @{ - AdditionalProperties = @{ - '@odata.type' = "#microsoft.graph.AuthenticationMethodsPolicy" - } - Description = "FakeStringValue" - DisplayName = "FakeStringValue" - Id = "FakeStringValue" - PolicyMigrationState = "preMigration" - PolicyVersion = "FakeStringValue" - ReconfirmationInDays = 25 - RegistrationEnforcement = @{ - AuthenticationMethodsRegistrationCampaign = @{ - IncludeTargets = @( - @{ - Id = "FakeStringValue" - TargetType = "user" - TargetedAuthenticationMethod = "FakeStringValue" - } - ) - State = "default" - SnoozeDurationInDays = 25 - ExcludeTargets = @( - @{ - TargetType = "user" - Id = "FakeStringValue" - } - ) - } - } - SystemCredentialPreferences = @{ - State = "default" - IncludeTargets = @( - @{ - TargetType = "user" - Id = "FakeStringValue" - } - ) - ExcludeTargets = @( - @{ - TargetType = "user" - Id = "FakeStringValue" - } - ) - } - + Description = "This is my super context test"; + DisplayName = "My Super Context"; + Id = "c3"; + IsAvailable = $True; } } } - It 'Should return true from the Test method' { Test-TargetResource @testParams | Should -Be $true } } - Context -Name "The AADAuthenticationMethodPolicy exists and values are NOT in the desired state" -Fixture { + Context -Name "The instance exists and values are NOT in the desired state" -Fixture { BeforeAll { $testParams = @{ - Description = "FakeStringValue" - DisplayName = "FakeStringValue" - Id = "FakeStringValue" - PolicyMigrationState = "preMigration" - PolicyVersion = "FakeStringValue" - ReconfirmationInDays = 25 - RegistrationEnforcement = (New-CimInstance -ClassName MSFT_MicrosoftGraphregistrationEnforcement -Property @{ - AuthenticationMethodsRegistrationCampaign = (New-CimInstance -ClassName MSFT_MicrosoftGraphauthenticationMethodsRegistrationCampaign -Property @{ - IncludeTargets = [CimInstance[]]@( - (New-CimInstance -ClassName MSFT_MicrosoftGraphauthenticationMethodsRegistrationCampaignIncludeTarget -Property @{ - Id = "FakeStringValue" - TargetType = "user" - TargetedAuthenticationMethod = "FakeStringValue" - } -ClientOnly) - ) - State = "default" - SnoozeDurationInDays = 25 - ExcludeTargets = [CimInstance[]]@( - (New-CimInstance -ClassName MSFT_AADAuthenticationMethodPolicyExcludeTarget -Property @{ - TargetType = "user" - Id = "FakeStringValue" - } -ClientOnly) - ) - } -ClientOnly) - } -ClientOnly) - SystemCredentialPreferences = (New-CimInstance -ClassName MSFT_MicrosoftGraphsystemCredentialPreferences -Property @{ - State = "default" - IncludeTargets = [CimInstance[]]@( - (New-CimInstance -ClassName MSFT_AADAuthenticationMethodPolicyIncludeTarget -Property @{ - TargetType = "user" - Id = "FakeStringValue" - } -ClientOnly) - ) - ExcludeTargets = [CimInstance[]]@( - (New-CimInstance -ClassName MSFT_AADAuthenticationMethodPolicyExcludeTarget -Property @{ - TargetType = "user" - Id = "FakeStringValue" - } -ClientOnly) - ) - } -ClientOnly) - Ensure = 'Present' - Credential = $Credential; + Description = "This is my super context test"; + DisplayName = "My Super Context"; + Ensure = "Present"; + Id = "c3"; + IsAvailable = $True; + Credential = $Credential; } - Mock -CommandName Get-MgBetaPolicyAuthenticationMethodPolicy -MockWith { + Mock -CommandName Get-MgBetaIdentityConditionalAccessAuthenticationContextClassReference -MockWith { return @{ - Description = "FakeStringValue" - DisplayName = "FakeStringValue" - Id = "FakeStringValue" - PolicyMigrationState = "preMigration" - PolicyVersion = "FakeStringValue" - ReconfirmationInDays = 7 - RegistrationEnforcement = @{ - AuthenticationMethodsRegistrationCampaign = @{ - IncludeTargets = @( - @{ - Id = "FakeStringValue" - TargetType = "user" - TargetedAuthenticationMethod = "FakeStringValue" - } - ) - State = "default" - SnoozeDurationInDays = 7 - ExcludeTargets = @( - @{ - TargetType = "user" - Id = "FakeStringValue" - } - ) - } - } - SystemCredentialPreferences = @{ - State = "default" - IncludeTargets = @( - @{ - TargetType = "user" - Id = "FakeStringValue" - } - ) - ExcludeTargets = @( - @{ - TargetType = "user" - Id = "FakeStringValue" - } - ) - } + Description = "This is my super context test"; + DisplayName = "My Super Drifted Context"; # Drift + Id = "c3"; + IsAvailable = $True; } } } @@ -417,7 +156,7 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { It 'Should call the Set method' { Set-TargetResource @testParams - Should -Invoke -CommandName Update-MgBetaPolicyAuthenticationMethodPolicy -Exactly 1 + Should -Invoke -CommandName Update-MgBetaIdentityConditionalAccessAuthenticationContextClassReference -Exactly 1 } } @@ -426,55 +165,15 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { $Global:CurrentModeIsExport = $true $Global:PartialExportFileName = "$(New-Guid).partial.ps1" $testParams = @{ - Credential = $Credential + Credential = $Credential; } - Mock -CommandName Get-MgBetaPolicyAuthenticationMethodPolicy -MockWith { + Mock -CommandName Get-MgBetaIdentityConditionalAccessAuthenticationContextClassReference -MockWith { return @{ - AdditionalProperties = @{ - '@odata.type' = "#microsoft.graph.AuthenticationMethodsPolicy" - } - Description = "FakeStringValue" - DisplayName = "FakeStringValue" - Id = "FakeStringValue" - PolicyMigrationState = "preMigration" - PolicyVersion = "FakeStringValue" - ReconfirmationInDays = 25 - RegistrationEnforcement = @{ - AuthenticationMethodsRegistrationCampaign = @{ - IncludeTargets = @( - @{ - Id = "FakeStringValue" - TargetType = "user" - TargetedAuthenticationMethod = "FakeStringValue" - } - ) - State = "default" - SnoozeDurationInDays = 25 - ExcludeTargets = @( - @{ - TargetType = "user" - Id = "FakeStringValue" - } - ) - } - } - SystemCredentialPreferences = @{ - State = "default" - IncludeTargets = @( - @{ - TargetType = "user" - Id = "FakeStringValue" - } - ) - ExcludeTargets = @( - @{ - TargetType = "user" - Id = "FakeStringValue" - } - ) - } - + Description = "This is my super context test"; + DisplayName = "My Super Context"; + Id = "c3"; + IsAvailable = $True; } } } From bf076fac077d7749a152f3a793cdbff18a6fa164 Mon Sep 17 00:00:00 2001 From: Philippe Kernevez Date: Fri, 20 Oct 2023 15:28:14 +0200 Subject: [PATCH 12/31] Fix build --- .../Resources/SCSecurityFilter/1-AddingNewSecurityFilter.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/Microsoft365DSC/Examples/Resources/SCSecurityFilter/1-AddingNewSecurityFilter.ps1 b/Modules/Microsoft365DSC/Examples/Resources/SCSecurityFilter/1-AddingNewSecurityFilter.ps1 index 6134df69fd..ca990fa406 100644 --- a/Modules/Microsoft365DSC/Examples/Resources/SCSecurityFilter/1-AddingNewSecurityFilter.ps1 +++ b/Modules/Microsoft365DSC/Examples/Resources/SCSecurityFilter/1-AddingNewSecurityFilter.ps1 @@ -14,7 +14,7 @@ Configuration Example node localhost { - SCSecurityLabel 'ConfigureSecurityLabel' + SCSecurityFilter 'ConfigureSecurityLabel' { FilterName = "My Filter Name" Action = "All" From c61409116ac736870001053a4d992f6dc56ea043 Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Fri, 20 Oct 2023 09:50:35 -0400 Subject: [PATCH 13/31] Update Microsoft365.psm1 --- Tests/Unit/Stubs/Microsoft365.psm1 | 309 +++++++++++++++++++++++++++-- 1 file changed, 289 insertions(+), 20 deletions(-) diff --git a/Tests/Unit/Stubs/Microsoft365.psm1 b/Tests/Unit/Stubs/Microsoft365.psm1 index 8b41f10e85..abed4acd5c 100644 --- a/Tests/Unit/Stubs/Microsoft365.psm1 +++ b/Tests/Unit/Stubs/Microsoft365.psm1 @@ -30128,6 +30128,83 @@ function Get-MgBetaIdentityConditionalAccess $Break ) } +function Get-MgBetaIdentityConditionalAccessAuthenticationContextClassReference +{ + [CmdletBinding()] + param( + [Parameter()] + [System.String[]] + $Property, + + [Parameter()] + [PSObject] + $InputObject, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $ProxyUseDefaultCredentials, + + [Parameter()] + [System.Int32] + $PageSize, + + [Parameter()] + [PSObject] + $HttpPipelinePrepend, + + [Parameter()] + [System.Int32] + $Skip, + + [Parameter()] + [System.Int32] + $Top, + + [Parameter()] + [System.String] + $CountVariable, + + [Parameter()] + [System.Uri] + $Proxy, + + [Parameter()] + [System.String[]] + $Sort, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $All, + + [Parameter()] + [System.String] + $Filter, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ProxyCredential, + + [Parameter()] + [System.String] + $Search, + + [Parameter()] + [System.String] + $AuthenticationContextClassReferenceId, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Break, + + [Parameter()] + [System.String[]] + $ExpandProperty, + + [Parameter()] + [PSObject] + $HttpPipelineAppend + ) +} function Get-MgBetaIdentityConditionalAccessNamedLocation { [CmdletBinding()] @@ -31127,6 +31204,63 @@ function Get-MgBetaPolicyTokenLifetimePolicy $HttpPipelineAppend ) } +function New-MgBetaIdentityConditionalAccessAuthenticationContextClassReference +{ + [CmdletBinding()] + param( + [Parameter()] + [System.String] + $Id, + + [Parameter()] + [PSObject] + $HttpPipelinePrepend, + + [Parameter()] + [PSObject] + $BodyParameter, + + [Parameter()] + [System.Uri] + $Proxy, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $IsAvailable, + + [Parameter()] + [System.String] + $DisplayName, + + [Parameter()] + [System.String] + $Description, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Confirm, + + [Parameter()] + [PSObject] + $HttpPipelineAppend, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $ProxyUseDefaultCredentials, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ProxyCredential, + + [Parameter()] + [System.Collections.Hashtable] + $AdditionalProperties, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Break + ) +} function New-MgBetaIdentityConditionalAccessPolicy { [CmdletBinding()] @@ -31356,11 +31490,11 @@ function New-MgBetaPolicyCrossTenantAccessPolicyPartner [Parameter()] [PSObject] - $AutomaticUserConsentSettings, + $InboundTrust, [Parameter()] [PSObject] - $InboundTrust, + $AutomaticUserConsentSettings, [Parameter()] [PSObject] @@ -31370,6 +31504,10 @@ function New-MgBetaPolicyCrossTenantAccessPolicyPartner [PSObject] $B2BDirectConnectOutbound, + [Parameter()] + [System.Management.Automation.SwitchParameter] + $IsInMultiTenantOrganization, + [Parameter()] [PSObject] $B2BDirectConnectInbound, @@ -31525,6 +31663,55 @@ function Remove-MgBetaIdentityConditionalAccess $HttpPipelineAppend ) } +function Remove-MgBetaIdentityConditionalAccessAuthenticationContextClassReference +{ + [CmdletBinding()] + param( + [Parameter()] + [PSObject] + $HttpPipelinePrepend, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ProxyCredential, + + [Parameter()] + [System.Uri] + $Proxy, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $PassThru, + + [Parameter()] + [System.String] + $IfMatch, + + [Parameter()] + [PSObject] + $InputObject, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Confirm, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $ProxyUseDefaultCredentials, + + [Parameter()] + [System.String] + $AuthenticationContextClassReferenceId, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Break, + + [Parameter()] + [PSObject] + $HttpPipelineAppend + ) +} function Remove-MgBetaIdentityConditionalAccessNamedLocation { [CmdletBinding()] @@ -31693,16 +31880,16 @@ function Remove-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfig $InputObject, [Parameter()] - [System.String] - $AuthenticationMethodConfigurationId, + [System.Management.Automation.SwitchParameter] + $Confirm, [Parameter()] [System.Management.Automation.SwitchParameter] $ProxyUseDefaultCredentials, [Parameter()] - [System.Management.Automation.SwitchParameter] - $Confirm, + [System.String] + $AuthenticationMethodConfigurationId, [Parameter()] [System.Management.Automation.SwitchParameter] @@ -31717,10 +31904,6 @@ function Remove-MgBetaPolicyAuthenticationStrengthPolicy { [CmdletBinding()] param( - [Parameter()] - [System.String] - $AuthenticationStrengthPolicyId, - [Parameter()] [PSObject] $HttpPipelinePrepend, @@ -31757,6 +31940,10 @@ function Remove-MgBetaPolicyAuthenticationStrengthPolicy [System.Management.Automation.SwitchParameter] $ProxyUseDefaultCredentials, + [Parameter()] + [System.String] + $AuthenticationStrengthPolicyId, + [Parameter()] [System.Management.Automation.SwitchParameter] $Break @@ -31970,6 +32157,71 @@ function Update-MgBetaIdentityConditionalAccess $HttpPipelineAppend ) } +function Update-MgBetaIdentityConditionalAccessAuthenticationContextClassReference +{ + [CmdletBinding()] + param( + [Parameter()] + [System.String] + $Description, + + [Parameter()] + [System.String] + $DisplayName, + + [Parameter()] + [System.Collections.Hashtable] + $AdditionalProperties, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $ProxyUseDefaultCredentials, + + [Parameter()] + [PSObject] + $HttpPipelinePrepend, + + [Parameter()] + [PSObject] + $InputObject, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $IsAvailable, + + [Parameter()] + [System.Uri] + $Proxy, + + [Parameter()] + [PSObject] + $BodyParameter, + + [Parameter()] + [System.String] + $Id, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Confirm, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ProxyCredential, + + [Parameter()] + [System.String] + $AuthenticationContextClassReferenceId, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Break, + + [Parameter()] + [PSObject] + $HttpPipelineAppend + ) +} function Update-MgBetaIdentityConditionalAccessPolicy { [CmdletBinding()] @@ -32119,6 +32371,10 @@ function Update-MgBetaPolicyAuthenticationMethodPolicy [System.Management.Automation.SwitchParameter] $Confirm, + [Parameter()] + [PSObject] + $ReportSuspiciousActivitySettings, + [Parameter()] [System.Management.Automation.PSCredential] $ProxyCredential, @@ -32165,8 +32421,8 @@ function Update-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfig $InputObject, [Parameter()] - [System.String] - $AuthenticationMethodConfigurationId, + [System.Management.Automation.SwitchParameter] + $Confirm, [Parameter()] [PSObject] @@ -32177,8 +32433,8 @@ function Update-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfig $ProxyUseDefaultCredentials, [Parameter()] - [System.Management.Automation.SwitchParameter] - $Confirm, + [System.String] + $AuthenticationMethodConfigurationId, [Parameter()] [System.String] @@ -32456,6 +32712,10 @@ function Update-MgBetaPolicyCrossTenantAccessPolicy [System.String] $Description, + [Parameter()] + [PSObject] + $Templates, + [Parameter()] [System.String] $DisplayName, @@ -32472,10 +32732,6 @@ function Update-MgBetaPolicyCrossTenantAccessPolicy [PSObject] $HttpPipelinePrepend, - [Parameter()] - [System.Management.Automation.PSCredential] - $ProxyCredential, - [Parameter()] [PSObject] $Partners, @@ -32496,6 +32752,10 @@ function Update-MgBetaPolicyCrossTenantAccessPolicy [System.Management.Automation.SwitchParameter] $Confirm, + [Parameter()] + [System.Management.Automation.PSCredential] + $ProxyCredential, + [Parameter()] [System.DateTime] $DeletedDateTime, @@ -32525,6 +32785,10 @@ function Update-MgBetaPolicyCrossTenantAccessPolicyDefault [System.Management.Automation.SwitchParameter] $IsServiceDefault, + [Parameter()] + [System.Collections.Hashtable] + $InvitationRedemptionIdentityProviderConfiguration, + [Parameter()] [PSObject] $TenantRestrictions, @@ -32539,11 +32803,11 @@ function Update-MgBetaPolicyCrossTenantAccessPolicyDefault [Parameter()] [PSObject] - $AutomaticUserConsentSettings, + $InboundTrust, [Parameter()] [PSObject] - $InboundTrust, + $AutomaticUserConsentSettings, [Parameter()] [PSObject] @@ -32634,6 +32898,10 @@ function Update-MgBetaPolicyCrossTenantAccessPolicyPartner [PSObject] $B2BDirectConnectOutbound, + [Parameter()] + [System.Management.Automation.SwitchParameter] + $IsInMultiTenantOrganization, + [Parameter()] [System.String] $CrossTenantAccessPolicyConfigurationPartnerTenantId, @@ -32972,6 +33240,7 @@ function Update-MgBetaPolicyTokenLifetimePolicy ) } #endregion + #region Microsoft.Graph.Beta.Teams function Get-MgBetaTeam { From 74735a9d21a8a39a14e106cd2fb69abc0384cd9e Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Fri, 20 Oct 2023 14:11:18 +0000 Subject: [PATCH 14/31] Updated Resources and Cmdlet documentation pages --- .../AADAuthenticationContextClassReference.md | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 docs/docs/resources/azure-ad/AADAuthenticationContextClassReference.md diff --git a/docs/docs/resources/azure-ad/AADAuthenticationContextClassReference.md b/docs/docs/resources/azure-ad/AADAuthenticationContextClassReference.md new file mode 100644 index 0000000000..a7ede04795 --- /dev/null +++ b/docs/docs/resources/azure-ad/AADAuthenticationContextClassReference.md @@ -0,0 +1,85 @@ +# AADAuthenticationContextClassReference + +## Parameters + +| Parameter | Attribute | DataType | Description | Allowed Values | +| --- | --- | --- | --- | --- | +| **Id** | Key | String | Identifier used to reference the authentication context class. The id is used to trigger step-up authentication for the referenced authentication requirements and is the value that will be issued in the acrs claim of an access token. This value in the claim is used to verify that the required authentication context has been satisfied. The allowed values are c1 through c25. | `c1`, `c2`, `c3`, `c4`, `c5`, `c6`, `c7`, `c8`, `c9`, `c10`, `c11`, `c12`, `c13`, `c14`, `c15`, `c16`, `c17`, `c18`, `c19`, `c20`, `c21`, `c22`, `c23`, `c24`, `c25` | +| **DisplayName** | Write | String | A friendly name that identifies the authenticationContextClassReference object when building user-facing admin experiences. For example, a selection UX | | +| **Description** | Write | String | A short explanation of the policies that are enforced by authenticationContextClassReference. This value should be used to provide secondary text to describe the authentication context class reference when building user-facing admin experiences. For example, a selection UX. | | +| **IsAvailable** | Write | Boolean | Indicates whether the authenticationContextClassReference has been published by the security admin and is ready for use by apps. When it's set to false, it shouldn't be shown in admin UX experiences because the value isn't currently available for selection. | | +| **Ensure** | Write | String | Present ensures the policy exists, absent ensures it is removed. | `Present`, `Absent` | +| **Credential** | Write | PSCredential | Credentials of the Admin | | +| **ApplicationId** | Write | String | Id of the Azure Active Directory application to authenticate with. | | +| **TenantId** | Write | String | Id of the Azure Active Directory tenant used for authentication. | | +| **ApplicationSecret** | Write | PSCredential | Secret of the Azure Active Directory tenant used for authentication. | | +| **CertificateThumbprint** | Write | String | Thumbprint of the Azure Active Directory application's authentication certificate to use for authentication. | | +| **ManagedIdentity** | Write | Boolean | Managed ID being used for authentication. | | + + +# AADAuthenticationMethodPolicy + +## Description + +Azure AD Authentication Method Policy + +## Permissions + +### Microsoft Graph + +To authenticate with the Microsoft Graph API, this resource required the following permissions: + +#### Delegated permissions + +- **Read** + + - Policy.ReadWrite.AuthenticationMethod + +- **Update** + + - Policy.ReadWrite.AuthenticationMethod + +#### Application permissions + +- **Read** + + - Policy.ReadWrite.AuthenticationMethod + +- **Update** + + - Policy.ReadWrite.AuthenticationMethod + +## Examples + +### Example 1 + +This example is used to test new resources and showcase the usage of new resources being worked on. +It is not meant to use as a production baseline. + +```powershell +Configuration Example +{ + param + ( + [Parameter(Mandatory = $true)] + [PSCredential] + $credsCredential + ) + + Import-DscResource -ModuleName Microsoft365DSC + + node localhost + { + AADAuthenticationContextClassReference "AADAuthenticationContextClassReference-Test" + { + Credential = $credsCredential; + Description = "Context test"; + DisplayName = "My Context"; + Ensure = "Present"; + Id = "c3"; + IsAvailable = $True; + } + } +} +``` + From 5abc6dcf87dbd81a2114189dda2d16b97ac3da12 Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Fri, 20 Oct 2023 11:07:47 -0400 Subject: [PATCH 15/31] Initial Release --- CHANGELOG.md | 2 + .../MSFT_AADAttributeSet.psm1 | 378 ++++++++++++++++++ .../MSFT_AADAttributeSet.schema.mof | 14 + .../MSFT_AADAttributeSet/readme.md | 6 + .../MSFT_AADAttributeSet/settings.json | 34 ++ .../readme.md | 4 +- .../settings.json | 14 +- .../1-AADAttributeSet-Example.ps1 | 28 ++ .../Microsoft365DSC.AADAttributeSet.Tests.ps1 | 182 +++++++++ Tests/Unit/Stubs/Microsoft365.psm1 | 241 +++++++++++ 10 files changed, 891 insertions(+), 12 deletions(-) create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_AADAttributeSet/MSFT_AADAttributeSet.psm1 create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_AADAttributeSet/MSFT_AADAttributeSet.schema.mof create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_AADAttributeSet/readme.md create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_AADAttributeSet/settings.json create mode 100644 Modules/Microsoft365DSC/Examples/Resources/AADAttributeSet/1-AADAttributeSet-Example.ps1 create mode 100644 Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADAttributeSet.Tests.ps1 diff --git a/CHANGELOG.md b/CHANGELOG.md index 5883411a56..3e3a3f78f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ # UNRELEASED +* AADAttributeSet + * Initial Release. * AADAuthenticationContext * Initial Release. * AADConditionalAccessPolicy diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAttributeSet/MSFT_AADAttributeSet.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAttributeSet/MSFT_AADAttributeSet.psm1 new file mode 100644 index 0000000000..3b8692d9e5 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAttributeSet/MSFT_AADAttributeSet.psm1 @@ -0,0 +1,378 @@ +function Get-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + param + ( + [Parameter(Mandatory = $true)] + [System.String] + $Id, + + [Parameter()] + [System.String] + $Description, + + [Parameter()] + [ValidateRange(1,500)] + [System.Int32] + $MaxAttributesPerSet = $null, + + [Parameter()] + [System.String] + [ValidateSet('Absent', 'Present')] + $Ensure = 'Present', + + [Parameter()] + [System.Management.Automation.PSCredential] + $Credential, + + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ApplicationSecret, + + [Parameter()] + [System.String] + $CertificateThumbprint, + + [Parameter()] + [Switch] + $ManagedIdentity + ) + + try + { + $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` + -InboundParameters $PSBoundParameters + + #Ensure the proper dependencies are installed in the current environment. + Confirm-M365DSCDependencies + + #region Telemetry + $ResourceName = $MyInvocation.MyCommand.ModuleName.Replace('MSFT_', '') + $CommandName = $MyInvocation.MyCommand + $data = Format-M365DSCTelemetryParameters -ResourceName $ResourceName ` + -CommandName $CommandName ` + -Parameters $PSBoundParameters + Add-M365DSCTelemetryEvent -Data $data + #endregion + + $nullResult = $PSBoundParameters + $nullResult.Ensure = 'Absent' + + $getValue = $null + + $getValue = Get-MgBetaDirectoryAttributeSet ` + -AttributeSetId $Id ` + -ErrorAction SilentlyContinue + + if ($null -eq $getValue) + { + Write-Verbose -Message "Could not find Attribute Set with Id {$Id}" + return $nullResult + } + Write-Verbose -Message "Attribute Set with Id {$Id} was found." + + $results = @{ + Id = $getValue.Id + Description = $getValue.Description + MaxAttributesPerSet = $getValue.MaxAttributesPerSet + Ensure = 'Present' + Credential = $Credential + ApplicationId = $ApplicationId + TenantId = $TenantId + ApplicationSecret = $ApplicationSecret + CertificateThumbprint = $CertificateThumbprint + Managedidentity = $ManagedIdentity.IsPresent + } + + return [System.Collections.Hashtable] $results + } + catch + { + New-M365DSCLogEntry -Message 'Error retrieving data:' ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + + return $nullResult + } +} + +function Set-TargetResource +{ + [CmdletBinding()] + param + ( + [Parameter(Mandatory = $true)] + [System.String] + $Id, + + [Parameter()] + [System.String] + $Description, + + [Parameter()] + [ValidateRange(1,500)] + [System.Int32] + $MaxAttributesPerSet = $null, + + [Parameter()] + [System.String] + [ValidateSet('Absent', 'Present')] + $Ensure = 'Present', + + [Parameter()] + [System.Management.Automation.PSCredential] + $Credential, + + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ApplicationSecret, + + [Parameter()] + [System.String] + $CertificateThumbprint, + + [Parameter()] + [Switch] + $ManagedIdentity + ) + + #Ensure the proper dependencies are installed in the current environment. + Confirm-M365DSCDependencies + + #region Telemetry + $ResourceName = $MyInvocation.MyCommand.ModuleName.Replace('MSFT_', '') + $CommandName = $MyInvocation.MyCommand + $data = Format-M365DSCTelemetryParameters -ResourceName $ResourceName ` + -CommandName $CommandName ` + -Parameters $PSBoundParameters + Add-M365DSCTelemetryEvent -Data $data + #endregion + + $currentInstance = Get-TargetResource @PSBoundParameters + $BoundParameters = Remove-M365DSCAuthenticationParameter -BoundParameters $PSBoundParameters + + if ($Ensure -eq 'Present' -and $currentInstance.Ensure -eq 'Absent') + { + Write-Verbose -Message "Creating new Attribute Set with Id {$Id}" + New-MgBetaDirectoryAttributeSet @BoundParameters | Out-Null + } + elseif ($Ensure -eq 'Present' -and $currentInstance.Ensure -eq 'Present') + { + Write-Verbose -Message "Updating the Attribute Set with Id {$($currentInstance.Id)}" + $BoundParameters.Add('AttributeSetId', $Id) + $BoundParameters.Remove('Id') | Out-Null + Update-MgBetaDirectoryAttributeSet @BoundParameters | Out-Null + } + elseif ($Ensure -eq 'Absent' -and $currentInstance.Ensure -eq 'Present') + { + Write-Verbose -Message "Removing the Attribute Set with Id {$($currentInstance.Id)}" + Remove-MgBetaDirectoryAttributeSet -AuthenticationContextClassReferenceId $Id | Out-Null + } +} + +function Test-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Boolean])] + param + ( + [Parameter(Mandatory = $true)] + [System.String] + $Id, + + [Parameter()] + [System.String] + $Description, + + [Parameter()] + [ValidateRange(1,500)] + [System.Int32] + $MaxAttributesPerSet = $null, + + [Parameter()] + [System.String] + [ValidateSet('Absent', 'Present')] + $Ensure = 'Present', + + [Parameter()] + [System.Management.Automation.PSCredential] + $Credential, + + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ApplicationSecret, + + [Parameter()] + [System.String] + $CertificateThumbprint, + + [Parameter()] + [Switch] + $ManagedIdentity + ) + + #Ensure the proper dependencies are installed in the current environment. + Confirm-M365DSCDependencies + + #region Telemetry + $ResourceName = $MyInvocation.MyCommand.ModuleName.Replace('MSFT_', '') + $CommandName = $MyInvocation.MyCommand + $data = Format-M365DSCTelemetryParameters -ResourceName $ResourceName ` + -CommandName $CommandName ` + -Parameters $PSBoundParameters + Add-M365DSCTelemetryEvent -Data $data + #endregion + + Write-Verbose -Message "Testing configuration of the Attribute Set with Id {$Id}" + + $CurrentValues = Get-TargetResource @PSBoundParameters + $ValuesToCheck = ([Hashtable]$PSBoundParameters).clone() + + Write-Verbose -Message "Current Values: $(Convert-M365DscHashtableToString -Hashtable $CurrentValues)" + Write-Verbose -Message "Target Values: $(Convert-M365DscHashtableToString -Hashtable $ValuesToCheck)" + $testResult = Test-M365DSCParameterState -CurrentValues $CurrentValues ` + -Source $($MyInvocation.MyCommand.Source) ` + -DesiredValues $PSBoundParameters ` + -ValuesToCheck $ValuesToCheck.Keys + + Write-Verbose -Message "Test-TargetResource returned $testResult" + + return $testResult +} + +function Export-TargetResource +{ + [CmdletBinding()] + [OutputType([System.String])] + param + ( + [Parameter()] + [System.Management.Automation.PSCredential] + $Credential, + + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ApplicationSecret, + + [Parameter()] + [System.String] + $CertificateThumbprint, + + [Parameter()] + [Switch] + $ManagedIdentity + ) + + $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` + -InboundParameters $PSBoundParameters + + #Ensure the proper dependencies are installed in the current environment. + Confirm-M365DSCDependencies + + #region Telemetry + $ResourceName = $MyInvocation.MyCommand.ModuleName.Replace('MSFT_', '') + $CommandName = $MyInvocation.MyCommand + $data = Format-M365DSCTelemetryParameters -ResourceName $ResourceName ` + -CommandName $CommandName ` + -Parameters $PSBoundParameters + Add-M365DSCTelemetryEvent -Data $data + #endregion + + try + { + [array]$getValue = Get-MgBetaDirectoryAttributeSet -All -ErrorAction Stop + + $i = 1 + $dscContent = '' + if ($getValue.Length -eq 0) + { + Write-Host $Global:M365DSCEmojiGreenCheckMark + } + else + { + Write-Host "`r`n" -NoNewline + } + foreach ($config in $getValue) + { + $displayedKey = $config.Id + + Write-Host " |---[$i/$($getValue.Count)] $displayedKey" -NoNewline + $params = @{ + Id = $config.Id + Ensure = 'Present' + Credential = $Credential + ApplicationId = $ApplicationId + TenantId = $TenantId + ApplicationSecret = $ApplicationSecret + CertificateThumbprint = $CertificateThumbprint + Managedidentity = $ManagedIdentity.IsPresent + } + + $Results = Get-TargetResource @Params + $Results = Update-M365DSCExportAuthenticationResults -ConnectionMode $ConnectionMode ` + -Results $Results + + $currentDSCBlock = Get-M365DSCExportContentForResource -ResourceName $ResourceName ` + -ConnectionMode $ConnectionMode ` + -ModulePath $PSScriptRoot ` + -Results $Results ` + -Credential $Credential + + $dscContent += $currentDSCBlock + Save-M365DSCPartialExport -Content $currentDSCBlock ` + -FileName $Global:PartialExportFileName + $i++ + Write-Host $Global:M365DSCEmojiGreenCheckMark + } + return $dscContent + } + catch + { + Write-Host $Global:M365DSCEmojiRedX + + New-M365DSCLogEntry -Message 'Error during Export:' ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + + return '' + } +} + +Export-ModuleMember -Function *-TargetResource diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAttributeSet/MSFT_AADAttributeSet.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAttributeSet/MSFT_AADAttributeSet.schema.mof new file mode 100644 index 0000000000..9011a94914 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAttributeSet/MSFT_AADAttributeSet.schema.mof @@ -0,0 +1,14 @@ +[ClassVersion("1.0.0.0"), FriendlyName("AADAttributeSet")] +class MSFT_AADAttributeSet : OMI_BaseResource +{ + [Key, Description("Identifier for the attribute set that is unique within a tenant. Can be up to 32 characters long and include Unicode characters. Cannot contain spaces or special characters. Cannot be changed later. Case insensitive")] String Id; + [Write, Description("Identifier for the attribute set that is unique within a tenant. Can be up to 32 characters long and include Unicode characters. Cannot contain spaces or special characters. Cannot be changed later. Case insensitive")] String Description; + [Write, Description("Maximum number of custom security attributes that can be defined in this attribute set. Default value is null. If not specified, the administrator can add up to the maximum of 500 active attributes per tenant. Can be changed later.")] UInt32 MaxAttributesPerSet; + [Write, Description("Present ensures the policy exists, absent ensures it is removed."), ValueMap{"Present","Absent"}, Values{"Present","Absent"}] string Ensure; + [Write, Description("Credentials of the Admin"), EmbeddedInstance("MSFT_Credential")] string Credential; + [Write, Description("Id of the Azure Active Directory application to authenticate with.")] String ApplicationId; + [Write, Description("Id of the Azure Active Directory tenant used for authentication.")] String TenantId; + [Write, Description("Secret of the Azure Active Directory tenant used for authentication."), EmbeddedInstance("MSFT_Credential")] String ApplicationSecret; + [Write, Description("Thumbprint of the Azure Active Directory application's authentication certificate to use for authentication.")] String CertificateThumbprint; + [Write, Description("Managed ID being used for authentication.")] Boolean ManagedIdentity; +}; diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAttributeSet/readme.md b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAttributeSet/readme.md new file mode 100644 index 0000000000..9637edfab0 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAttributeSet/readme.md @@ -0,0 +1,6 @@ + +# AADAttributeSet + +## Description + +Represents a group of related custom security attribute definitions. diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAttributeSet/settings.json b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAttributeSet/settings.json new file mode 100644 index 0000000000..008f1d53c5 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAttributeSet/settings.json @@ -0,0 +1,34 @@ +{ + "resourceName": "AADAttributeSet", + "description": "Represents a group of related custom security attribute definitions.", + "roles": { + "read": [ + "Security Reader" + ], + "update": [ + "Authentication Policy Administrator" + ] + }, + "permissions": { + "graph": { + "delegated": { + "read": [ + ], + "update": [ + ] + }, + "application": { + "read": [ + { + "name": "CustomSecAttributeDefinition.ReadWrite.All" + } + ], + "update": [ + { + "name": "CustomSecAttributeDefinition.ReadWrite.All" + } + ] + } + } + } +} diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationContextClassReference/readme.md b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationContextClassReference/readme.md index 212cc73c9b..75f2c972fe 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationContextClassReference/readme.md +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationContextClassReference/readme.md @@ -1,6 +1,6 @@ -# AADAuthenticationMethodPolicy +# AADAuthenticationContextClassReference ## Description -Azure AD Authentication Method Policy +Represents a Microsoft Entra authentication context class reference. Authentication context class references are custom values that define a Conditional Access authentication requirement diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationContextClassReference/settings.json b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationContextClassReference/settings.json index 249e208352..60045eb8e5 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationContextClassReference/settings.json +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationContextClassReference/settings.json @@ -1,6 +1,6 @@ { - "resourceName": "AADAuthenticationMethodPolicy", - "description": "This resource configures an Azure AD Authentication Method Policy.", + "resourceName": "AADAuthenticationContextClassReference", + "description": "Represents a Microsoft Entra authentication context class reference. Authentication context class references are custom values that define a Conditional Access authentication requirement.", "roles": { "read": [ "Security Reader" @@ -13,25 +13,19 @@ "graph": { "delegated": { "read": [ - { - "name": "Policy.ReadWrite.AuthenticationMethod" - } ], "update": [ - { - "name": "Policy.ReadWrite.AuthenticationMethod" - } ] }, "application": { "read": [ { - "name": "Policy.ReadWrite.AuthenticationMethod" + "name": "Policy.Read.ConditionalAccess" } ], "update": [ { - "name": "Policy.ReadWrite.AuthenticationMethod" + "name": "Policy.ReadWrite.ConditionalAccess" } ] } diff --git a/Modules/Microsoft365DSC/Examples/Resources/AADAttributeSet/1-AADAttributeSet-Example.ps1 b/Modules/Microsoft365DSC/Examples/Resources/AADAttributeSet/1-AADAttributeSet-Example.ps1 new file mode 100644 index 0000000000..e2eddf1bfa --- /dev/null +++ b/Modules/Microsoft365DSC/Examples/Resources/AADAttributeSet/1-AADAttributeSet-Example.ps1 @@ -0,0 +1,28 @@ +<# +This example is used to test new resources and showcase the usage of new resources being worked on. +It is not meant to use as a production baseline. +#> + +Configuration Example +{ + param + ( + [Parameter(Mandatory = $true)] + [PSCredential] + $credsCredential + ) + + Import-DscResource -ModuleName Microsoft365DSC + + node localhost + { + AADAttributeSet "AADAttributeSetTest" + { + Credential = $credsCredential; + Description = "Attribute set with 420 attributes"; + Ensure = "Present"; + Id = "TestAttributeSet"; + MaxAttributesPerSet = 420; + } + } +} diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADAttributeSet.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADAttributeSet.Tests.ps1 new file mode 100644 index 0000000000..3750d5d3ad --- /dev/null +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADAttributeSet.Tests.ps1 @@ -0,0 +1,182 @@ +[CmdletBinding()] +param( +) +$M365DSCTestFolder = Join-Path -Path $PSScriptRoot ` + -ChildPath '..\..\Unit' ` + -Resolve +$CmdletModule = (Join-Path -Path $M365DSCTestFolder ` + -ChildPath '\Stubs\Microsoft365.psm1' ` + -Resolve) +$GenericStubPath = (Join-Path -Path $M365DSCTestFolder ` + -ChildPath '\Stubs\Generic.psm1' ` + -Resolve) +Import-Module -Name (Join-Path -Path $M365DSCTestFolder ` + -ChildPath '\UnitTestHelper.psm1' ` + -Resolve) + +$Global:DscHelper = New-M365DscUnitTestHelper -StubModule $CmdletModule ` + -DscResource "AADAttributeSet" -GenericStubModule $GenericStubPath +Describe -Name $Global:DscHelper.DescribeHeader -Fixture { + InModuleScope -ModuleName $Global:DscHelper.ModuleName -ScriptBlock { + Invoke-Command -ScriptBlock $Global:DscHelper.InitializeScript -NoNewScope + BeforeAll { + + $secpasswd = ConvertTo-SecureString "f@kepassword1" -AsPlainText -Force + $Credential = New-Object System.Management.Automation.PSCredential ('tenantadmin@mydomain.com', $secpasswd) + + Mock -CommandName Confirm-M365DSCDependencies -MockWith { + } + + Mock -CommandName Update-MgBetaDirectoryAttributeSet -MockWith { + } + + Mock -CommandName Remove-MgBetaDirectoryAttributeSet -MockWith { + } + + Mock -CommandName New-M365DSCConnection -MockWith { + return "Credentials" + } + + # Mock Write-Host to hide output during the tests + Mock -CommandName Write-Host -MockWith { + } + } + # Test contexts + Context -Name "The instance should exist but it DOES NOT" -Fixture { + BeforeAll { + $testParams = @{ + Description = "This is my super context test"; + MaxAttributesPerSet = 420; + Ensure = "Present"; + Id = "c3"; + Credential = $Credential; + } + + Mock -CommandName Get-MgBetaDirectoryAttributeSet -MockWith { + return $null + } + } + It 'Should return Values from the Get method' { + (Get-TargetResource @testParams).Ensure | Should -Be 'Absent' + } + It 'Should return false from the Test method' { + Test-TargetResource @testParams | Should -Be $false + } + } + + Context -Name "The instance exists but it SHOULD NOT" -Fixture { + BeforeAll { + $testParams = @{ + Description = "This is my super context test"; + MaxAttributesPerSet = 420; + Ensure = "Absent"; + Id = "c3"; + Credential = $Credential; + } + + Mock -CommandName Get-MgBetaDirectoryAttributeSet -MockWith { + return @{ + Description = "This is my super context test"; + MaxAttributesPerSet = 420; + Id = "c3"; + } + } + } + + It 'Should return Values from the Get method' { + (Get-TargetResource @testParams).Ensure | Should -Be 'Present' + } + + It 'Should return true from the Test method' { + Test-TargetResource @testParams | Should -Be $false + } + + It 'Should Remove the group from the Set method' { + Set-TargetResource @testParams + Should -Invoke -CommandName Remove-MgBetaDirectoryAttributeSet -Exactly 1 + } + } + Context -Name "The instance exists and values are already in the desired state" -Fixture { + BeforeAll { + $testParams = @{ + Description = "This is my super context test"; + MaxAttributesPerSet = 420; + Ensure = "Present"; + Id = "c3"; + Credential = $Credential; + } + + Mock -CommandName Get-MgBetaDirectoryAttributeSet -MockWith { + return @{ + Description = "This is my super context test"; + MaxAttributesPerSet = 420; + Id = "c3"; + } + } + } + + It 'Should return true from the Test method' { + Test-TargetResource @testParams | Should -Be $true + } + } + + Context -Name "The instance exists and values are NOT in the desired state" -Fixture { + BeforeAll { + $testParams = @{ + Description = "This is my super context test"; + MaxAttributesPerSet = 420; + Ensure = "Present"; + Id = "c3"; + Credential = $Credential; + } + + Mock -CommandName Get-MgBetaDirectoryAttributeSet -MockWith { + return @{ + Description = "This is my super context test"; + MaxAttributesPerSet = 431; #drift + Ensure = "Present"; + Id = "c3"; + Credential = $Credential; + } + } + } + + It 'Should return Values from the Get method' { + (Get-TargetResource @testParams).Ensure | Should -Be 'Present' + } + + It 'Should return false from the Test method' { + Test-TargetResource @testParams | Should -Be $false + } + + It 'Should call the Set method' { + Set-TargetResource @testParams + Should -Invoke -CommandName Update-MgBetaDirectoryAttributeSet -Exactly 1 + } + } + + Context -Name 'ReverseDSC Tests' -Fixture { + BeforeAll { + $Global:CurrentModeIsExport = $true + $Global:PartialExportFileName = "$(New-Guid).partial.ps1" + $testParams = @{ + Credential = $Credential; + } + + Mock -CommandName Get-MgBetaDirectoryAttributeSet -MockWith { + return @{ + Description = "This is my super context test"; + MaxAttributesPerSet = 420; + Id = "c3"; + } + } + } + It 'Should Reverse Engineer resource from the Export method' { + $result = Export-TargetResource @testParams + $result | Should -Not -BeNullOrEmpty + } + } + } +} + +Invoke-Command -ScriptBlock $Global:DscHelper.CleanupScript -NoNewScope diff --git a/Tests/Unit/Stubs/Microsoft365.psm1 b/Tests/Unit/Stubs/Microsoft365.psm1 index abed4acd5c..66ab3db329 100644 --- a/Tests/Unit/Stubs/Microsoft365.psm1 +++ b/Tests/Unit/Stubs/Microsoft365.psm1 @@ -49717,6 +49717,83 @@ function Get-MgBetaDirectoryAdministrativeUnitScopedRoleMember $HttpPipelineAppend ) } +function Get-MgBetaDirectoryAttributeSet +{ + [CmdletBinding()] + param( + [Parameter()] + [System.String[]] + $Property, + + [Parameter()] + [PSObject] + $InputObject, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $ProxyUseDefaultCredentials, + + [Parameter()] + [System.Int32] + $PageSize, + + [Parameter()] + [PSObject] + $HttpPipelinePrepend, + + [Parameter()] + [System.Int32] + $Skip, + + [Parameter()] + [System.Int32] + $Top, + + [Parameter()] + [System.String] + $CountVariable, + + [Parameter()] + [System.Uri] + $Proxy, + + [Parameter()] + [System.String[]] + $Sort, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $All, + + [Parameter()] + [System.String] + $Filter, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ProxyCredential, + + [Parameter()] + [System.String] + $Search, + + [Parameter()] + [System.String] + $AttributeSetId, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Break, + + [Parameter()] + [System.String[]] + $ExpandProperty, + + [Parameter()] + [PSObject] + $HttpPipelineAppend + ) +} function Get-MgBetaDirectoryDeletedItem { [CmdletBinding()] @@ -50812,6 +50889,59 @@ function New-MgBetaDirectoryAdministrativeUnitScopedRoleMember $HttpPipelineAppend ) } +function New-MgBetaDirectoryAttributeSet +{ + [CmdletBinding()] + param( + [Parameter()] + [System.String] + $Description, + + [Parameter()] + [PSObject] + $HttpPipelinePrepend, + + [Parameter()] + [PSObject] + $BodyParameter, + + [Parameter()] + [System.Uri] + $Proxy, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ProxyCredential, + + [Parameter()] + [System.Int32] + $MaxAttributesPerSet, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Confirm, + + [Parameter()] + [PSObject] + $HttpPipelineAppend, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $ProxyUseDefaultCredentials, + + [Parameter()] + [System.String] + $Id, + + [Parameter()] + [System.Collections.Hashtable] + $AdditionalProperties, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Break + ) +} function New-MgBetaDirectoryRole { [CmdletBinding()] @@ -51203,6 +51333,55 @@ function Remove-MgBetaDirectoryAdministrativeUnitScopedRoleMember $Break ) } +function Remove-MgBetaDirectoryAttributeSet +{ + [CmdletBinding()] + param( + [Parameter()] + [System.String] + $AttributeSetId, + + [Parameter()] + [PSObject] + $HttpPipelinePrepend, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ProxyCredential, + + [Parameter()] + [System.Uri] + $Proxy, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $PassThru, + + [Parameter()] + [System.String] + $IfMatch, + + [Parameter()] + [PSObject] + $InputObject, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Confirm, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $ProxyUseDefaultCredentials, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Break, + + [Parameter()] + [PSObject] + $HttpPipelineAppend + ) +} function Remove-MgBetaDirectoryRole { [CmdletBinding()] @@ -51818,6 +51997,67 @@ function Update-MgBetaDirectoryAdministrativeUnit $HttpPipelineAppend ) } +function Update-MgBetaDirectoryAttributeSet +{ + [CmdletBinding()] + param( + [Parameter()] + [System.String] + $AttributeSetId, + + [Parameter()] + [PSObject] + $HttpPipelinePrepend, + + [Parameter()] + [PSObject] + $BodyParameter, + + [Parameter()] + [System.Uri] + $Proxy, + + [Parameter()] + [System.Int32] + $MaxAttributesPerSet, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ProxyCredential, + + [Parameter()] + [PSObject] + $InputObject, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Confirm, + + [Parameter()] + [System.String] + $Id, + + [Parameter()] + [PSObject] + $HttpPipelineAppend, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $ProxyUseDefaultCredentials, + + [Parameter()] + [System.String] + $Description, + + [Parameter()] + [System.Collections.Hashtable] + $AdditionalProperties, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Break + ) +} function Update-MgBetaDirectorySetting { [CmdletBinding()] @@ -52260,6 +52500,7 @@ function Update-MgBetaOrganizationSettingPersonInsight ) } #endregion + #region Microsoft.Graph.Beta.Identity.Governance function Get-MgBetaAgreement { From 579f62ac4090c01f90e4ecc0fb1532006f7e3b7e Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Fri, 20 Oct 2023 11:43:04 -0400 Subject: [PATCH 16/31] Update MSFT_AADAttributeSet.psm1 --- .../DSCResources/MSFT_AADAttributeSet/MSFT_AADAttributeSet.psm1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAttributeSet/MSFT_AADAttributeSet.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAttributeSet/MSFT_AADAttributeSet.psm1 index 3b8692d9e5..47173e12ac 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAttributeSet/MSFT_AADAttributeSet.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAttributeSet/MSFT_AADAttributeSet.psm1 @@ -185,7 +185,7 @@ function Set-TargetResource elseif ($Ensure -eq 'Absent' -and $currentInstance.Ensure -eq 'Present') { Write-Verbose -Message "Removing the Attribute Set with Id {$($currentInstance.Id)}" - Remove-MgBetaDirectoryAttributeSet -AuthenticationContextClassReferenceId $Id | Out-Null + Remove-MgBetaDirectoryAttributeSet -AttributeSetId $Id | Out-Null } } From 7d7ed6216be7a6f174e7acf6fbeb94347105ed09 Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Fri, 20 Oct 2023 18:50:56 +0000 Subject: [PATCH 17/31] Updated Resources and Cmdlet documentation pages --- .../resources/azure-ad/AADAttributeSet.md | 81 +++++++++++++++++++ .../AADAuthenticationContextClassReference.md | 12 ++- 2 files changed, 86 insertions(+), 7 deletions(-) create mode 100644 docs/docs/resources/azure-ad/AADAttributeSet.md diff --git a/docs/docs/resources/azure-ad/AADAttributeSet.md b/docs/docs/resources/azure-ad/AADAttributeSet.md new file mode 100644 index 0000000000..2e0e5f5ff4 --- /dev/null +++ b/docs/docs/resources/azure-ad/AADAttributeSet.md @@ -0,0 +1,81 @@ +# AADAttributeSet + +## Parameters + +| Parameter | Attribute | DataType | Description | Allowed Values | +| --- | --- | --- | --- | --- | +| **Id** | Key | String | Identifier for the attribute set that is unique within a tenant. Can be up to 32 characters long and include Unicode characters. Cannot contain spaces or special characters. Cannot be changed later. Case insensitive | | +| **Description** | Write | String | Identifier for the attribute set that is unique within a tenant. Can be up to 32 characters long and include Unicode characters. Cannot contain spaces or special characters. Cannot be changed later. Case insensitive | | +| **MaxAttributesPerSet** | Write | UInt32 | Maximum number of custom security attributes that can be defined in this attribute set. Default value is null. If not specified, the administrator can add up to the maximum of 500 active attributes per tenant. Can be changed later. | | +| **Ensure** | Write | String | Present ensures the policy exists, absent ensures it is removed. | `Present`, `Absent` | +| **Credential** | Write | PSCredential | Credentials of the Admin | | +| **ApplicationId** | Write | String | Id of the Azure Active Directory application to authenticate with. | | +| **TenantId** | Write | String | Id of the Azure Active Directory tenant used for authentication. | | +| **ApplicationSecret** | Write | PSCredential | Secret of the Azure Active Directory tenant used for authentication. | | +| **CertificateThumbprint** | Write | String | Thumbprint of the Azure Active Directory application's authentication certificate to use for authentication. | | +| **ManagedIdentity** | Write | Boolean | Managed ID being used for authentication. | | + + +## Description + +Represents a group of related custom security attribute definitions. + +## Permissions + +### Microsoft Graph + +To authenticate with the Microsoft Graph API, this resource required the following permissions: + +#### Delegated permissions + +- **Read** + + - None + +- **Update** + + - None + +#### Application permissions + +- **Read** + + - CustomSecAttributeDefinition.ReadWrite.All + +- **Update** + + - CustomSecAttributeDefinition.ReadWrite.All + +## Examples + +### Example 1 + +This example is used to test new resources and showcase the usage of new resources being worked on. +It is not meant to use as a production baseline. + +```powershell +Configuration Example +{ + param + ( + [Parameter(Mandatory = $true)] + [PSCredential] + $credsCredential + ) + + Import-DscResource -ModuleName Microsoft365DSC + + node localhost + { + AADAttributeSet "AADAttributeSetTest" + { + Credential = $credsCredential; + Description = "Attribute set with 420 attributes"; + Ensure = "Present"; + Id = "TestAttributeSet"; + MaxAttributesPerSet = 420; + } + } +} +``` + diff --git a/docs/docs/resources/azure-ad/AADAuthenticationContextClassReference.md b/docs/docs/resources/azure-ad/AADAuthenticationContextClassReference.md index a7ede04795..b9d41753c8 100644 --- a/docs/docs/resources/azure-ad/AADAuthenticationContextClassReference.md +++ b/docs/docs/resources/azure-ad/AADAuthenticationContextClassReference.md @@ -17,11 +17,9 @@ | **ManagedIdentity** | Write | Boolean | Managed ID being used for authentication. | | -# AADAuthenticationMethodPolicy - ## Description -Azure AD Authentication Method Policy +Represents a Microsoft Entra authentication context class reference. Authentication context class references are custom values that define a Conditional Access authentication requirement ## Permissions @@ -33,21 +31,21 @@ To authenticate with the Microsoft Graph API, this resource required the followi - **Read** - - Policy.ReadWrite.AuthenticationMethod + - None - **Update** - - Policy.ReadWrite.AuthenticationMethod + - None #### Application permissions - **Read** - - Policy.ReadWrite.AuthenticationMethod + - Policy.Read.ConditionalAccess - **Update** - - Policy.ReadWrite.AuthenticationMethod + - Policy.ReadWrite.ConditionalAccess ## Examples From 80e20136249c6742c2690a519645132526628e60 Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Tue, 24 Oct 2023 14:26:18 +0000 Subject: [PATCH 18/31] Updated Resources and Cmdlet documentation pages --- .../security-compliance/SCSecurityFilter.md | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 docs/docs/resources/security-compliance/SCSecurityFilter.md diff --git a/docs/docs/resources/security-compliance/SCSecurityFilter.md b/docs/docs/resources/security-compliance/SCSecurityFilter.md new file mode 100644 index 0000000000..88520a3751 --- /dev/null +++ b/docs/docs/resources/security-compliance/SCSecurityFilter.md @@ -0,0 +1,84 @@ +# SCSecurityFilter + +## Parameters + +| Parameter | Attribute | DataType | Description | Allowed Values | +| --- | --- | --- | --- | --- | +| **FilterName** | Key | String | The FilterName parameter specifies the name of the compliance security filter that you want to view. If the value contains spaces, enclose the value in quotation marks ("). | | +| **Action** | Write | String | The Action parameter filters the results by the type of search action that a filter is applied to. | `Export`, `Preview`, `Purge`, `Search`, `All` | +| **Users** | Write | StringArray[] | The User parameter filters the results by the user who gets a filter applied to their searches. Acceptable values are : The alias or email address of a user, All or The name of a role group | | +| **Description** | Write | String | The Description parameter specifies a description for the compliance security filter. The maximum length is 256 characters. If the value contains spaces, enclose the value in quotation marks ("). | | +| **Filters** | Write | StringArray[] | The Filters parameter specifies the search criteria for the compliance security filter. The filters are applied to the users specified by the Users parameter. You can create three different types of filters: Mailbox filter, Mailbox content filter or Site and site content filter | | +| **Region** | Write | String | The Region parameter specifies the satellite location for multi-geo tenants to conduct eDiscovery searches in. | `APC`, `AUS`, `CAN`, `EUR`, `FRA`, `GBR`, `IND`, `JPN`, `LAM`, `NAM`, `` | +| **Credential** | Write | PSCredential | Credentials of the Exchange Global Admin | | +| **ApplicationId** | Write | String | Id of the Azure Active Directory application to authenticate with. | | +| **TenantId** | Write | String | Id of the Azure Active Directory tenant used for authentication. | | +| **CertificateThumbprint** | Write | String | Thumbprint of the Azure Active Directory application's authentication certificate to use for authentication. | | +| **CertificatePath** | Write | String | Path to certificate used in service principal usually a PFX file. | | +| **CertificatePassword** | Write | PSCredential | Username can be made up to anything but password will be used for CertificatePassword | | +| **Ensure** | Write | String | Specify if this label policy should exist or not. | `Present`, `Absent` | + +## Description + +This resource configures a Security Filter in Security and Compliance. + +## Permissions + +### Microsoft Graph + +To authenticate with the Microsoft Graph API, this resource required the following permissions: + +#### Delegated permissions + +- **Read** + + - None + +- **Update** + + - None + +#### Application permissions + +- **Read** + + - None + +- **Update** + + - None + +## Examples + +### Example 1 + +This example is used to test new resources and showcase the usage of new resources being worked on. +It is not meant to use as a production baseline. + +```powershell +Configuration Example +{ + param( + [Parameter(Mandatory = $true)] + [PSCredential] + $credsGlobalAdmin + ) + Import-DscResource -ModuleName Microsoft365DSC + + node localhost + { + SCSecurityFilter 'ConfigureSecurityLabel' + { + FilterName = "My Filter Name" + Action = "All" + Users = @("jonh.doe@1234.onmicrosoft.com") + Description = "Demo Security Label description" + Filters = @("Mailbox_CountryCode -eq '124'") + Region = "AUS" + Ensure = "Present" + Credential = $credsGlobalAdmin + } + } +} +``` + From b913ec64e773201712d380d2c93dcb824c6275cd Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Tue, 24 Oct 2023 10:47:33 -0700 Subject: [PATCH 19/31] AADSocialIdentityProvider New Resource --- .../MSFT_AADAttributeSet/settings.json | 2 +- .../MSFT_AADSocialIdentityProvider.psm1 | 409 +++++++++++++ .../MSFT_AADSocialIdentityProvider.schema.mof | 15 + .../MSFT_AADSocialIdentityProvider/readme.md | 6 + .../settings.json | 34 ++ .../MSFT_EXOAvailabilityAddressSpace.psm1 | 2 +- ...1-CreateSocialIdentityProvider-Example.ps1 | 29 + ...365DSC.AADSocialIdentityProvider.Tests.ps1 | 204 +++++++ Tests/Unit/Stubs/Microsoft365.psm1 | 569 ++++++++++++++++-- 9 files changed, 1234 insertions(+), 36 deletions(-) create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_AADSocialIdentityProvider/MSFT_AADSocialIdentityProvider.psm1 create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_AADSocialIdentityProvider/MSFT_AADSocialIdentityProvider.schema.mof create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_AADSocialIdentityProvider/readme.md create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_AADSocialIdentityProvider/settings.json create mode 100644 Modules/Microsoft365DSC/Examples/Resources/AADSocialIdentityProvider/1-CreateSocialIdentityProvider-Example.ps1 create mode 100644 Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADSocialIdentityProvider.Tests.ps1 diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAttributeSet/settings.json b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAttributeSet/settings.json index 008f1d53c5..9d211172e0 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAttributeSet/settings.json +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAttributeSet/settings.json @@ -20,7 +20,7 @@ "application": { "read": [ { - "name": "CustomSecAttributeDefinition.ReadWrite.All" + "name": "CustomSecAttributeDefinition.Read.All" } ], "update": [ diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADSocialIdentityProvider/MSFT_AADSocialIdentityProvider.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADSocialIdentityProvider/MSFT_AADSocialIdentityProvider.psm1 new file mode 100644 index 0000000000..d1aaa21d53 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADSocialIdentityProvider/MSFT_AADSocialIdentityProvider.psm1 @@ -0,0 +1,409 @@ +function Get-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + param + ( + [Parameter(Mandatory = $true)] + [System.String] + $ClientId, + + [Parameter()] + [System.String] + $ClientSecret, + + [Parameter()] + [System.String] + $DisplayName, + + [Parameter()] + [ValidateSet("AADSignup", "EmailOTP", "Microsoft", "MicrosoftAccount", "Google", "Amazon", "LinkedIn", "Facebook", "GitHub", "Twitter", "Weibo", "QQ", "WeChat")] + [System.String] + $IdentityProviderType, + + [Parameter()] + [System.String] + [ValidateSet('Absent', 'Present')] + $Ensure = 'Present', + + [Parameter()] + [System.Management.Automation.PSCredential] + $Credential, + + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ApplicationSecret, + + [Parameter()] + [System.String] + $CertificateThumbprint, + + [Parameter()] + [Switch] + $ManagedIdentity + ) + + try + { + $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` + -InboundParameters $PSBoundParameters + + #Ensure the proper dependencies are installed in the current environment. + Confirm-M365DSCDependencies + + #region Telemetry + $ResourceName = $MyInvocation.MyCommand.ModuleName.Replace('MSFT_', '') + $CommandName = $MyInvocation.MyCommand + $data = Format-M365DSCTelemetryParameters -ResourceName $ResourceName ` + -CommandName $CommandName ` + -Parameters $PSBoundParameters + Add-M365DSCTelemetryEvent -Data $data + #endregion + + $nullResult = $PSBoundParameters + $nullResult.Ensure = 'Absent' + + $getValue = Get-MgBetaIdentityProvider -Filter "Id eq '$ClientId'" ` + -ErrorAction SilentlyContinue | Where-Object -FilterScript {$_.AdditionalProperties.'@odata.type' -eq '#microsoft.graph.socialIdentityProvider'} + + if ($null -eq $getValue) + { + Write-Verbose -Message "Could not find Social Identity Provider Client Id {$ClientId}" + return $nullResult + } + Write-Verbose -Message "Social Identity Provider with ClientId {$ClientId} was found." + + $ClientSecretValue = $null + if ($getValue.AdditionalProperties.clientSecret) + { + $ClientSecretValue = $getValue.AdditionalProperties.clientSecret + } + $results = @{ + ClientId = $getValue.Id + ClientSecret = $ClientSecretValue + DisplayName = $getValue.DisplayName + IdentityProviderType = $getValue.AdditionalProperties.identityProviderType + Ensure = 'Present' + Credential = $Credential + ApplicationId = $ApplicationId + TenantId = $TenantId + ApplicationSecret = $ApplicationSecret + CertificateThumbprint = $CertificateThumbprint + Managedidentity = $ManagedIdentity.IsPresent + } + + return [System.Collections.Hashtable] $results + } + catch + { + New-M365DSCLogEntry -Message 'Error retrieving data:' ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + + return $nullResult + } +} + +function Set-TargetResource +{ + [CmdletBinding()] + param + ( + [Parameter(Mandatory = $true)] + [System.String] + $ClientId, + + [Parameter()] + [System.String] + $ClientSecret, + + [Parameter()] + [System.String] + $DisplayName, + + [Parameter()] + [ValidateSet("AADSignup", "EmailOTP", "Microsoft", "MicrosoftAccount", "Google", "Amazon", "LinkedIn", "Facebook", "GitHub", "Twitter", "Weibo", "QQ", "WeChat")] + [System.String] + $IdentityProviderType, + + [Parameter()] + [System.String] + [ValidateSet('Absent', 'Present')] + $Ensure = 'Present', + + [Parameter()] + [System.Management.Automation.PSCredential] + $Credential, + + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ApplicationSecret, + + [Parameter()] + [System.String] + $CertificateThumbprint, + + [Parameter()] + [Switch] + $ManagedIdentity + ) + + #Ensure the proper dependencies are installed in the current environment. + Confirm-M365DSCDependencies + + #region Telemetry + $ResourceName = $MyInvocation.MyCommand.ModuleName.Replace('MSFT_', '') + $CommandName = $MyInvocation.MyCommand + $data = Format-M365DSCTelemetryParameters -ResourceName $ResourceName ` + -CommandName $CommandName ` + -Parameters $PSBoundParameters + Add-M365DSCTelemetryEvent -Data $data + #endregion + + $currentInstance = Get-TargetResource @PSBoundParameters + $BoundParameters = Remove-M365DSCAuthenticationParameter -BoundParameters $PSBoundParameters + + $AdditionalProperties = @{ + '@odata.type' = "microsoft.graph.socialIdentityProvider" + identityProviderType = $IdentityProviderType + } + $BoundParameters.Add("AdditionalProperties", $AdditionalProperties) + $BoundParameters.Remove("IdentityProviderType") | Out-Null + if ($ClientId) + { + $BoundParameters.AdditionalProperties.Add('ClientId', $ClientId) + $BoundParameters.Remove("ClientId") | Out-Null + } + if ($ClientSecret) + { + $BoundParameters.AdditionalProperties.Add('ClientSecret', $ClientSecret) + $BoundParameters.Remove("ClientSecret") | Out-Null + } + if ($Ensure -eq 'Present' -and $currentInstance.Ensure -eq 'Absent') + { + Write-Verbose -Message "Creating new Social Identity Provider with Client Id {$ClientId}" + New-MgBetaIdentityProvider @BoundParameters | Out-Null + } + elseif ($Ensure -eq 'Present' -and $currentInstance.Ensure -eq 'Present') + { + $BoundParameters.Add('IdentityProviderBaseId', $ClientId) + $BoundParameters.AdditionalProperties.Remove('IdentityProviderType') | Out-Null + Write-Verbose -Message "Updating the Social Identity Provider with Client Id {$ClientId}" + Update-MgBetaIdentityProvider @BoundParameters | Out-Null + } + elseif ($Ensure -eq 'Absent' -and $currentInstance.Ensure -eq 'Present') + { + Write-Verbose -Message "Removing the Social Identity Provider with Client Id {$ClientId}" + Remove-MgBetaIdentityProvider -IdentityProviderBaseId $ClientId | Out-Null + } +} + +function Test-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Boolean])] + param + ( + [Parameter(Mandatory = $true)] + [System.String] + $ClientId, + + [Parameter()] + [System.String] + $ClientSecret, + + [Parameter()] + [System.String] + $DisplayName, + + [Parameter()] + [ValidateSet("AADSignup", "EmailOTP", "Microsoft", "MicrosoftAccount", "Google", "Amazon", "LinkedIn", "Facebook", "GitHub", "Twitter", "Weibo", "QQ", "WeChat")] + [System.String] + $IdentityProviderType, + + [Parameter()] + [System.String] + [ValidateSet('Absent', 'Present')] + $Ensure = 'Present', + + [Parameter()] + [System.Management.Automation.PSCredential] + $Credential, + + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ApplicationSecret, + + [Parameter()] + [System.String] + $CertificateThumbprint, + + [Parameter()] + [Switch] + $ManagedIdentity + ) + + #Ensure the proper dependencies are installed in the current environment. + Confirm-M365DSCDependencies + + #region Telemetry + $ResourceName = $MyInvocation.MyCommand.ModuleName.Replace('MSFT_', '') + $CommandName = $MyInvocation.MyCommand + $data = Format-M365DSCTelemetryParameters -ResourceName $ResourceName ` + -CommandName $CommandName ` + -Parameters $PSBoundParameters + Add-M365DSCTelemetryEvent -Data $data + #endregion + + Write-Verbose -Message "Testing configuration of the Social Identity Provider with Client Id {$ClientId}" + + $CurrentValues = Get-TargetResource @PSBoundParameters + $ValuesToCheck = ([Hashtable]$PSBoundParameters).clone() + + Write-Verbose -Message "Current Values: $(Convert-M365DscHashtableToString -Hashtable $CurrentValues)" + Write-Verbose -Message "Target Values: $(Convert-M365DscHashtableToString -Hashtable $ValuesToCheck)" + $testResult = Test-M365DSCParameterState -CurrentValues $CurrentValues ` + -Source $($MyInvocation.MyCommand.Source) ` + -DesiredValues $PSBoundParameters ` + -ValuesToCheck $ValuesToCheck.Keys + + Write-Verbose -Message "Test-TargetResource returned $testResult" + + return $testResult +} + +function Export-TargetResource +{ + [CmdletBinding()] + [OutputType([System.String])] + param + ( + [Parameter()] + [System.Management.Automation.PSCredential] + $Credential, + + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ApplicationSecret, + + [Parameter()] + [System.String] + $CertificateThumbprint, + + [Parameter()] + [Switch] + $ManagedIdentity + ) + + $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` + -InboundParameters $PSBoundParameters + + #Ensure the proper dependencies are installed in the current environment. + Confirm-M365DSCDependencies + + #region Telemetry + $ResourceName = $MyInvocation.MyCommand.ModuleName.Replace('MSFT_', '') + $CommandName = $MyInvocation.MyCommand + $data = Format-M365DSCTelemetryParameters -ResourceName $ResourceName ` + -CommandName $CommandName ` + -Parameters $PSBoundParameters + Add-M365DSCTelemetryEvent -Data $data + #endregion + + try + { + [array]$getValue = Get-MgBetaIdentityProvider -All -ErrorAction Stop | Where-Object -FilterScript {$_.AdditionalProperties.'@odata.type' -eq '#microsoft.graph.socialIdentityProvider'} + + $i = 1 + $dscContent = '' + if ($getValue.Length -eq 0) + { + Write-Host $Global:M365DSCEmojiGreenCheckMark + } + else + { + Write-Host "`r`n" -NoNewline + } + foreach ($config in $getValue) + { + $displayedKey = $config.DisplayName + + Write-Host " |---[$i/$($getValue.Count)] $displayedKey" -NoNewline + $params = @{ + ClientId = $config.Id + Ensure = 'Present' + Credential = $Credential + ApplicationId = $ApplicationId + TenantId = $TenantId + ApplicationSecret = $ApplicationSecret + CertificateThumbprint = $CertificateThumbprint + Managedidentity = $ManagedIdentity.IsPresent + } + + $Results = Get-TargetResource @Params + $Results = Update-M365DSCExportAuthenticationResults -ConnectionMode $ConnectionMode ` + -Results $Results + + $currentDSCBlock = Get-M365DSCExportContentForResource -ResourceName $ResourceName ` + -ConnectionMode $ConnectionMode ` + -ModulePath $PSScriptRoot ` + -Results $Results ` + -Credential $Credential + + $dscContent += $currentDSCBlock + Save-M365DSCPartialExport -Content $currentDSCBlock ` + -FileName $Global:PartialExportFileName + $i++ + Write-Host $Global:M365DSCEmojiGreenCheckMark + } + return $dscContent + } + catch + { + Write-Host $Global:M365DSCEmojiRedX + + New-M365DSCLogEntry -Message 'Error during Export:' ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + + return '' + } +} + +Export-ModuleMember -Function *-TargetResource diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADSocialIdentityProvider/MSFT_AADSocialIdentityProvider.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_AADSocialIdentityProvider/MSFT_AADSocialIdentityProvider.schema.mof new file mode 100644 index 0000000000..83ed3abb1e --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADSocialIdentityProvider/MSFT_AADSocialIdentityProvider.schema.mof @@ -0,0 +1,15 @@ +[ClassVersion("1.0.0.0"), FriendlyName("AADSocialIdentityProvider")] +class MSFT_AADSocialIdentityProvider : OMI_BaseResource +{ + [Key, Description("The client identifier for the application obtained when registering the application with the identity provider.")] String ClientId; + [Write, Description("The client secret for the application that is obtained when the application is registered with the identity provider. This is write-only. A read operation returns ****.")] String ClientSecret; + [Write, Description("The display name of the identity provider.")] String DisplayName; + [Write, Description("For a B2B scenario, possible values: Google, Facebook. For a B2C scenario, possible values: Microsoft, Google, Amazon, LinkedIn, Facebook, GitHub, Twitter, Weibo, QQ, WeChat."), ValueMap{"AADSignup", "EmailOTP", "Microsoft", "MicrosoftAccount", "Google", "Amazon", "LinkedIn", "Facebook", "GitHub", "Twitter", "Weibo", "QQ", "WeChat"}, Values{"AADSignup", "EmailOTP", "Microsoft", "MicrosoftAccount", "Google", "Amazon", "LinkedIn", "Facebook", "GitHub", "Twitter", "Weibo", "QQ", "WeChat"}] String IdentityProviderType; + [Write, Description("Present ensures the policy exists, absent ensures it is removed."), ValueMap{"Present","Absent"}, Values{"Present","Absent"}] string Ensure; + [Write, Description("Credentials of the Admin"), EmbeddedInstance("MSFT_Credential")] string Credential; + [Write, Description("Id of the Azure Active Directory application to authenticate with.")] String ApplicationId; + [Write, Description("Id of the Azure Active Directory tenant used for authentication.")] String TenantId; + [Write, Description("Secret of the Azure Active Directory tenant used for authentication."), EmbeddedInstance("MSFT_Credential")] String ApplicationSecret; + [Write, Description("Thumbprint of the Azure Active Directory application's authentication certificate to use for authentication.")] String CertificateThumbprint; + [Write, Description("Managed ID being used for authentication.")] Boolean ManagedIdentity; +}; diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADSocialIdentityProvider/readme.md b/Modules/Microsoft365DSC/DSCResources/MSFT_AADSocialIdentityProvider/readme.md new file mode 100644 index 0000000000..d3d323d1a2 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADSocialIdentityProvider/readme.md @@ -0,0 +1,6 @@ + +# AADIdentityProvider + +## Description + +Represents identity providers with External Identities for both Microsoft Entra ID and Azure AD B2C tenants. For Microsoft Entra B2B scenarios in a Microsoft Entra tenant, the identity provider type can be Google or Facebook. diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADSocialIdentityProvider/settings.json b/Modules/Microsoft365DSC/DSCResources/MSFT_AADSocialIdentityProvider/settings.json new file mode 100644 index 0000000000..92e00500a2 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADSocialIdentityProvider/settings.json @@ -0,0 +1,34 @@ +{ + "resourceName": "AADAttributeSet", + "description": "Represents a group of related custom security attribute definitions.", + "roles": { + "read": [ + "Security Reader" + ], + "update": [ + "Authentication Policy Administrator" + ] + }, + "permissions": { + "graph": { + "delegated": { + "read": [ + ], + "update": [ + ] + }, + "application": { + "read": [ + { + "name": "IdentityProvider.Read.All" + } + ], + "update": [ + { + "name": "IdentityProvider.ReadWrite.All" + } + ] + } + } + } +} diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_EXOAvailabilityAddressSpace/MSFT_EXOAvailabilityAddressSpace.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_EXOAvailabilityAddressSpace/MSFT_EXOAvailabilityAddressSpace.psm1 index 317a80fa88..5897eda34b 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_EXOAvailabilityAddressSpace/MSFT_EXOAvailabilityAddressSpace.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_EXOAvailabilityAddressSpace/MSFT_EXOAvailabilityAddressSpace.psm1 @@ -259,7 +259,7 @@ function Set-TargetResource { $AvailabilityAddressSpaceParams.Remove('Identity') | Out-Null $AvailabilityAddressSpaceParams.Remove('Credentials') | Out-Null - add-AvailabilityAddressSpace @AvailabilityAddressSpaceParams -ea stop + Add-AvailabilityAddressSpace @AvailabilityAddressSpaceParams -ea stop } catch { diff --git a/Modules/Microsoft365DSC/Examples/Resources/AADSocialIdentityProvider/1-CreateSocialIdentityProvider-Example.ps1 b/Modules/Microsoft365DSC/Examples/Resources/AADSocialIdentityProvider/1-CreateSocialIdentityProvider-Example.ps1 new file mode 100644 index 0000000000..3c4f482979 --- /dev/null +++ b/Modules/Microsoft365DSC/Examples/Resources/AADSocialIdentityProvider/1-CreateSocialIdentityProvider-Example.ps1 @@ -0,0 +1,29 @@ +<# +This example is used to test new resources and showcase the usage of new resources being worked on. +It is not meant to use as a production baseline. +#> + +Configuration Example +{ + param + ( + [Parameter(Mandatory = $true)] + [PSCredential] + $credsCredential + ) + + Import-DscResource -ModuleName Microsoft365DSC + + node localhost + { + AADSocialIdentityProvider "AADSocialIdentityProvider-Google" + { + ClientId = "Google-OAUTH"; + ClientSecret = "FakeSecret"; + Credential = $credsCredential; + DisplayName = "My Google Provider"; + Ensure = "Present"; + IdentityProviderType = "Google"; + } + } +} diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADSocialIdentityProvider.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADSocialIdentityProvider.Tests.ps1 new file mode 100644 index 0000000000..a521e2ec34 --- /dev/null +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADSocialIdentityProvider.Tests.ps1 @@ -0,0 +1,204 @@ +[CmdletBinding()] +param( +) +$M365DSCTestFolder = Join-Path -Path $PSScriptRoot ` + -ChildPath '..\..\Unit' ` + -Resolve +$CmdletModule = (Join-Path -Path $M365DSCTestFolder ` + -ChildPath '\Stubs\Microsoft365.psm1' ` + -Resolve) +$GenericStubPath = (Join-Path -Path $M365DSCTestFolder ` + -ChildPath '\Stubs\Generic.psm1' ` + -Resolve) +Import-Module -Name (Join-Path -Path $M365DSCTestFolder ` + -ChildPath '\UnitTestHelper.psm1' ` + -Resolve) + +$Global:DscHelper = New-M365DscUnitTestHelper -StubModule $CmdletModule ` + -DscResource "AADSocialIdentityProvider" -GenericStubModule $GenericStubPath +Describe -Name $Global:DscHelper.DescribeHeader -Fixture { + InModuleScope -ModuleName $Global:DscHelper.ModuleName -ScriptBlock { + Invoke-Command -ScriptBlock $Global:DscHelper.InitializeScript -NoNewScope + BeforeAll { + + $secpasswd = ConvertTo-SecureString "f@kepassword1" -AsPlainText -Force + $Credential = New-Object System.Management.Automation.PSCredential ('tenantadmin@mydomain.com', $secpasswd) + + Mock -CommandName Confirm-M365DSCDependencies -MockWith { + } + + Mock -CommandName Update-MgBetaIdentityProvider -MockWith { + } + + Mock -CommandName Remove-MgBetaIdentityProvider -MockWith { + } + + Mock -CommandName New-M365DSCConnection -MockWith { + return "Credentials" + } + + # Mock Write-Host to hide output during the tests + Mock -CommandName Write-Host -MockWith { + } + } + # Test contexts + Context -Name "The instance should exist but it DOES NOT" -Fixture { + BeforeAll { + $testParams = @{ + ClientId = "Google-OAUTH"; + ClientSecret = "FakeSecret"; + DisplayName = "My Google Provider"; + Ensure = "Present"; + IdentityProviderType = "Google"; + Credential = $Credential; + } + + Mock -CommandName Get-MgBetaIdentityProvider -MockWith { + return $null + } + } + It 'Should return Values from the Get method' { + (Get-TargetResource @testParams).Ensure | Should -Be 'Absent' + } + It 'Should return false from the Test method' { + Test-TargetResource @testParams | Should -Be $false + } + } + + Context -Name "The instance exists but it SHOULD NOT" -Fixture { + BeforeAll { + $testParams = @{ + ClientId = "Google-OAUTH"; + ClientSecret = "FakeSecret"; + DisplayName = "My Google Provider"; + Ensure = "Absent"; + IdentityProviderType = "Google"; + Credential = $Credential; + } + + Mock -CommandName Get-MgBetaIdentityProvider -MockWith { + return @{ + Id = "Google-OAUTH"; + AdditionalProperties = @{ + ClientId = "Google-OAUTH"; + ClientSecret = "FakeSecret"; + IdentityProviderType = "Google"; + '@odata.type' = "#microsoft.graph.socialIdentityProvider" + } + DisplayName = "My Google Provider"; + } + } + } + + It 'Should return Values from the Get method' { + (Get-TargetResource @testParams).Ensure | Should -Be 'Present' + } + + It 'Should return true from the Test method' { + Test-TargetResource @testParams | Should -Be $false + } + + It 'Should Remove the group from the Set method' { + Set-TargetResource @testParams + Should -Invoke -CommandName Remove-MgBetaIdentityProvider -Exactly 1 + } + } + Context -Name "The instance exists and values are already in the desired state" -Fixture { + BeforeAll { + $testParams = @{ + ClientId = "Google-OAUTH"; + ClientSecret = "FakeSecret"; + DisplayName = "My Google Provider"; + Ensure = "Present"; + IdentityProviderType = "Google"; + Credential = $Credential; + } + + Mock -CommandName Get-MgBetaIdentityProvider -MockWith { + return @{ + Id = "Google-OAUTH"; + AdditionalProperties = @{ + ClientId = "Google-OAUTH"; + ClientSecret = "FakeSecret"; + IdentityProviderType = "Google"; + '@odata.type' = "#microsoft.graph.socialIdentityProvider" + } + DisplayName = "My Google Provider"; + } + } + } + + It 'Should return true from the Test method' { + Test-TargetResource @testParams | Should -Be $true + } + } + + Context -Name "The instance exists and values are NOT in the desired state" -Fixture { + BeforeAll { + $testParams = @{ + ClientId = "Google-OAUTH"; + ClientSecret = "FakeSecret"; + DisplayName = "My Google Provider"; + Ensure = "Present"; + IdentityProviderType = "Google"; + Credential = $Credential; + } + + Mock -CommandName Get-MgBetaIdentityProvider -MockWith { + return @{ + Id = "Google-OAUTH"; + AdditionalProperties = @{ + ClientId = "Google-OAUTH"; + ClientSecret = "FakeSecret"; + IdentityProviderType = "Google"; + '@odata.type' = "#microsoft.graph.socialIdentityProvider" + } + DisplayName = "My Drift Provider"; # Drift + } + } + } + + It 'Should return Values from the Get method' { + (Get-TargetResource @testParams).Ensure | Should -Be 'Present' + } + + It 'Should return false from the Test method' { + Test-TargetResource @testParams | Should -Be $false + } + + It 'Should call the Set method' { + Set-TargetResource @testParams + Should -Invoke -CommandName Update-MgBetaIdentityPRovider -Exactly 1 + } + } + + Context -Name 'ReverseDSC Tests' -Fixture { + BeforeAll { + $Global:CurrentModeIsExport = $true + $Global:PartialExportFileName = "$(New-Guid).partial.ps1" + $testParams = @{ + Credential = $Credential; + } + + Mock -CommandName Get-MgBetaIdentityProvider -MockWith { + return @{ + Id = "Google-OAUTH"; + AdditionalProperties = @{ + ClientId = "Google-OAUTH"; + ClientSecret = "FakeSecret"; + IdentityProviderType = "Google"; + '@odata.type' = "#microsoft.graph.socialIdentityProvider" + } + DisplayName = "My Google Provider"; + } + } + } + It 'Should Reverse Engineer resource from the Export method' { + $result = Export-TargetResource @testParams + $result | Should -Not -BeNullOrEmpty + } + } + } +} + +Invoke-Command -ScriptBlock $Global:DscHelper.CleanupScript -NoNewScope diff --git a/Tests/Unit/Stubs/Microsoft365.psm1 b/Tests/Unit/Stubs/Microsoft365.psm1 index 66ab3db329..de5eb5834a 100644 --- a/Tests/Unit/Stubs/Microsoft365.psm1 +++ b/Tests/Unit/Stubs/Microsoft365.psm1 @@ -56077,6 +56077,83 @@ function Get-MgBetaIdentityConditionalAccess $Break ) } +function Get-MgBetaIdentityConditionalAccessAuthenticationContextClassReference +{ + [CmdletBinding()] + param( + [Parameter()] + [System.String[]] + $Property, + + [Parameter()] + [PSObject] + $InputObject, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $ProxyUseDefaultCredentials, + + [Parameter()] + [System.Int32] + $PageSize, + + [Parameter()] + [PSObject] + $HttpPipelinePrepend, + + [Parameter()] + [System.Int32] + $Skip, + + [Parameter()] + [System.Int32] + $Top, + + [Parameter()] + [System.String] + $CountVariable, + + [Parameter()] + [System.Uri] + $Proxy, + + [Parameter()] + [System.String[]] + $Sort, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $All, + + [Parameter()] + [System.String] + $Filter, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ProxyCredential, + + [Parameter()] + [System.String] + $Search, + + [Parameter()] + [System.String] + $AuthenticationContextClassReferenceId, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Break, + + [Parameter()] + [System.String[]] + $ExpandProperty, + + [Parameter()] + [PSObject] + $HttpPipelineAppend + ) +} function Get-MgBetaIdentityConditionalAccessNamedLocation { [CmdletBinding()] @@ -56231,6 +56308,83 @@ function Get-MgBetaIdentityConditionalAccessPolicy $HttpPipelineAppend ) } +function Get-MgBetaIdentityProvider +{ + [CmdletBinding()] + param( + [Parameter()] + [System.String] + $IdentityProviderBaseId, + + [Parameter()] + [System.String[]] + $Property, + + [Parameter()] + [PSObject] + $InputObject, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $ProxyUseDefaultCredentials, + + [Parameter()] + [System.Int32] + $PageSize, + + [Parameter()] + [PSObject] + $HttpPipelinePrepend, + + [Parameter()] + [System.Int32] + $Skip, + + [Parameter()] + [System.Int32] + $Top, + + [Parameter()] + [System.String] + $CountVariable, + + [Parameter()] + [System.Uri] + $Proxy, + + [Parameter()] + [System.String[]] + $Sort, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $All, + + [Parameter()] + [System.String] + $Filter, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ProxyCredential, + + [Parameter()] + [System.String] + $Search, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Break, + + [Parameter()] + [System.String[]] + $ExpandProperty, + + [Parameter()] + [PSObject] + $HttpPipelineAppend + ) +} function Get-MgBetaOauth2PermissionGrant { [CmdletBinding()] @@ -57076,6 +57230,63 @@ function Get-MgBetaPolicyTokenLifetimePolicy $HttpPipelineAppend ) } +function New-MgBetaIdentityConditionalAccessAuthenticationContextClassReference +{ + [CmdletBinding()] + param( + [Parameter()] + [System.String] + $Id, + + [Parameter()] + [PSObject] + $HttpPipelinePrepend, + + [Parameter()] + [PSObject] + $BodyParameter, + + [Parameter()] + [System.Uri] + $Proxy, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $IsAvailable, + + [Parameter()] + [System.String] + $DisplayName, + + [Parameter()] + [System.String] + $Description, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Confirm, + + [Parameter()] + [PSObject] + $HttpPipelineAppend, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $ProxyUseDefaultCredentials, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ProxyCredential, + + [Parameter()] + [System.Collections.Hashtable] + $AdditionalProperties, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Break + ) +} function New-MgBetaIdentityConditionalAccessPolicy { [CmdletBinding()] @@ -57153,6 +57364,55 @@ function New-MgBetaIdentityConditionalAccessPolicy $HttpPipelineAppend ) } +function New-MgBetaIdentityProvider +{ + [CmdletBinding()] + param( + [Parameter()] + [System.String] + $Id, + + [Parameter()] + [PSObject] + $HttpPipelinePrepend, + + [Parameter()] + [System.String] + $DisplayName, + + [Parameter()] + [System.Uri] + $Proxy, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ProxyCredential, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Confirm, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $ProxyUseDefaultCredentials, + + [Parameter()] + [PSObject] + $BodyParameter, + + [Parameter()] + [System.Collections.Hashtable] + $AdditionalProperties, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Break, + + [Parameter()] + [PSObject] + $HttpPipelineAppend + ) +} function New-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration { [CmdletBinding()] @@ -57305,11 +57565,11 @@ function New-MgBetaPolicyCrossTenantAccessPolicyPartner [Parameter()] [PSObject] - $AutomaticUserConsentSettings, + $InboundTrust, [Parameter()] [PSObject] - $InboundTrust, + $AutomaticUserConsentSettings, [Parameter()] [PSObject] @@ -57319,6 +57579,10 @@ function New-MgBetaPolicyCrossTenantAccessPolicyPartner [PSObject] $B2BDirectConnectOutbound, + [Parameter()] + [System.Management.Automation.SwitchParameter] + $IsInMultiTenantOrganization, + [Parameter()] [PSObject] $B2BDirectConnectInbound, @@ -57396,33 +57660,74 @@ function New-MgBetaPolicyTokenLifetimePolicy [System.Management.Automation.PSCredential] $ProxyCredential, - [Parameter()] - [System.Management.Automation.SwitchParameter] - $IsOrganizationDefault, - + [Parameter()] + [System.Management.Automation.SwitchParameter] + $IsOrganizationDefault, + + [Parameter()] + [System.Uri] + $Proxy, + + [Parameter()] + [System.Collections.Hashtable] + $BodyParameter, + + [Parameter()] + [System.String] + $Id, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Confirm, + + [Parameter()] + [System.DateTime] + $DeletedDateTime, + + [Parameter()] + [PSObject] + $AppliesTo, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Break, + + [Parameter()] + [PSObject] + $HttpPipelineAppend + ) +} +function Remove-MgBetaIdentityConditionalAccess +{ + [CmdletBinding()] + param( + [Parameter()] + [PSObject] + $HttpPipelinePrepend, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ProxyCredential, + [Parameter()] [System.Uri] $Proxy, [Parameter()] - [System.Collections.Hashtable] - $BodyParameter, + [System.Management.Automation.SwitchParameter] + $PassThru, [Parameter()] [System.String] - $Id, + $IfMatch, [Parameter()] [System.Management.Automation.SwitchParameter] $Confirm, [Parameter()] - [System.DateTime] - $DeletedDateTime, - - [Parameter()] - [PSObject] - $AppliesTo, + [System.Management.Automation.SwitchParameter] + $ProxyUseDefaultCredentials, [Parameter()] [System.Management.Automation.SwitchParameter] @@ -57433,7 +57738,7 @@ function New-MgBetaPolicyTokenLifetimePolicy $HttpPipelineAppend ) } -function Remove-MgBetaIdentityConditionalAccess +function Remove-MgBetaIdentityConditionalAccessAuthenticationContextClassReference { [CmdletBinding()] param( @@ -57457,6 +57762,10 @@ function Remove-MgBetaIdentityConditionalAccess [System.String] $IfMatch, + [Parameter()] + [PSObject] + $InputObject, + [Parameter()] [System.Management.Automation.SwitchParameter] $Confirm, @@ -57465,6 +57774,10 @@ function Remove-MgBetaIdentityConditionalAccess [System.Management.Automation.SwitchParameter] $ProxyUseDefaultCredentials, + [Parameter()] + [System.String] + $AuthenticationContextClassReferenceId, + [Parameter()] [System.Management.Automation.SwitchParameter] $Break, @@ -57572,6 +57885,55 @@ function Remove-MgBetaIdentityConditionalAccessPolicy $HttpPipelineAppend ) } +function Remove-MgBetaIdentityProvider +{ + [CmdletBinding()] + param( + [Parameter()] + [System.Management.Automation.PSCredential] + $ProxyCredential, + + [Parameter()] + [PSObject] + $HttpPipelinePrepend, + + [Parameter()] + [System.Uri] + $Proxy, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $PassThru, + + [Parameter()] + [System.String] + $IfMatch, + + [Parameter()] + [PSObject] + $InputObject, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Confirm, + + [Parameter()] + [PSObject] + $HttpPipelineAppend, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $ProxyUseDefaultCredentials, + + [Parameter()] + [System.String] + $IdentityProviderBaseId, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Break + ) +} function Remove-MgBetaPolicyAuthenticationMethodPolicy { [CmdletBinding()] @@ -57642,16 +58004,16 @@ function Remove-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfig $InputObject, [Parameter()] - [System.String] - $AuthenticationMethodConfigurationId, + [System.Management.Automation.SwitchParameter] + $Confirm, [Parameter()] [System.Management.Automation.SwitchParameter] $ProxyUseDefaultCredentials, [Parameter()] - [System.Management.Automation.SwitchParameter] - $Confirm, + [System.String] + $AuthenticationMethodConfigurationId, [Parameter()] [System.Management.Automation.SwitchParameter] @@ -57666,10 +58028,6 @@ function Remove-MgBetaPolicyAuthenticationStrengthPolicy { [CmdletBinding()] param( - [Parameter()] - [System.String] - $AuthenticationStrengthPolicyId, - [Parameter()] [PSObject] $HttpPipelinePrepend, @@ -57706,6 +58064,10 @@ function Remove-MgBetaPolicyAuthenticationStrengthPolicy [System.Management.Automation.SwitchParameter] $ProxyUseDefaultCredentials, + [Parameter()] + [System.String] + $AuthenticationStrengthPolicyId, + [Parameter()] [System.Management.Automation.SwitchParameter] $Break @@ -57919,6 +58281,71 @@ function Update-MgBetaIdentityConditionalAccess $HttpPipelineAppend ) } +function Update-MgBetaIdentityConditionalAccessAuthenticationContextClassReference +{ + [CmdletBinding()] + param( + [Parameter()] + [System.String] + $Description, + + [Parameter()] + [System.String] + $DisplayName, + + [Parameter()] + [System.Collections.Hashtable] + $AdditionalProperties, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $ProxyUseDefaultCredentials, + + [Parameter()] + [PSObject] + $HttpPipelinePrepend, + + [Parameter()] + [PSObject] + $InputObject, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $IsAvailable, + + [Parameter()] + [System.Uri] + $Proxy, + + [Parameter()] + [PSObject] + $BodyParameter, + + [Parameter()] + [System.String] + $Id, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Confirm, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ProxyCredential, + + [Parameter()] + [System.String] + $AuthenticationContextClassReferenceId, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Break, + + [Parameter()] + [PSObject] + $HttpPipelineAppend + ) +} function Update-MgBetaIdentityConditionalAccessPolicy { [CmdletBinding()] @@ -58004,6 +58431,63 @@ function Update-MgBetaIdentityConditionalAccessPolicy $HttpPipelineAppend ) } +function Update-MgBetaIdentityProvider +{ + [CmdletBinding()] + param( + [Parameter()] + [System.String] + $Id, + + [Parameter()] + [PSObject] + $HttpPipelinePrepend, + + [Parameter()] + [PSObject] + $BodyParameter, + + [Parameter()] + [System.Uri] + $Proxy, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ProxyCredential, + + [Parameter()] + [System.String] + $IdentityProviderBaseId, + + [Parameter()] + [System.String] + $DisplayName, + + [Parameter()] + [PSObject] + $InputObject, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Confirm, + + [Parameter()] + [PSObject] + $HttpPipelineAppend, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $ProxyUseDefaultCredentials, + + [Parameter()] + [System.Collections.Hashtable] + $AdditionalProperties, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Break + ) +} function Update-MgBetaPolicyAuthenticationMethodPolicy { [CmdletBinding()] @@ -58068,6 +58552,10 @@ function Update-MgBetaPolicyAuthenticationMethodPolicy [System.Management.Automation.SwitchParameter] $Confirm, + [Parameter()] + [PSObject] + $ReportSuspiciousActivitySettings, + [Parameter()] [System.Management.Automation.PSCredential] $ProxyCredential, @@ -58114,8 +58602,8 @@ function Update-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfig $InputObject, [Parameter()] - [System.String] - $AuthenticationMethodConfigurationId, + [System.Management.Automation.SwitchParameter] + $Confirm, [Parameter()] [PSObject] @@ -58126,8 +58614,8 @@ function Update-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfig $ProxyUseDefaultCredentials, [Parameter()] - [System.Management.Automation.SwitchParameter] - $Confirm, + [System.String] + $AuthenticationMethodConfigurationId, [Parameter()] [System.String] @@ -58405,6 +58893,10 @@ function Update-MgBetaPolicyCrossTenantAccessPolicy [System.String] $Description, + [Parameter()] + [PSObject] + $Templates, + [Parameter()] [System.String] $DisplayName, @@ -58421,10 +58913,6 @@ function Update-MgBetaPolicyCrossTenantAccessPolicy [PSObject] $HttpPipelinePrepend, - [Parameter()] - [System.Management.Automation.PSCredential] - $ProxyCredential, - [Parameter()] [PSObject] $Partners, @@ -58445,6 +58933,10 @@ function Update-MgBetaPolicyCrossTenantAccessPolicy [System.Management.Automation.SwitchParameter] $Confirm, + [Parameter()] + [System.Management.Automation.PSCredential] + $ProxyCredential, + [Parameter()] [System.DateTime] $DeletedDateTime, @@ -58474,6 +58966,10 @@ function Update-MgBetaPolicyCrossTenantAccessPolicyDefault [System.Management.Automation.SwitchParameter] $IsServiceDefault, + [Parameter()] + [System.Collections.Hashtable] + $InvitationRedemptionIdentityProviderConfiguration, + [Parameter()] [PSObject] $TenantRestrictions, @@ -58488,11 +58984,11 @@ function Update-MgBetaPolicyCrossTenantAccessPolicyDefault [Parameter()] [PSObject] - $AutomaticUserConsentSettings, + $InboundTrust, [Parameter()] [PSObject] - $InboundTrust, + $AutomaticUserConsentSettings, [Parameter()] [PSObject] @@ -58583,6 +59079,10 @@ function Update-MgBetaPolicyCrossTenantAccessPolicyPartner [PSObject] $B2BDirectConnectOutbound, + [Parameter()] + [System.Management.Automation.SwitchParameter] + $IsInMultiTenantOrganization, + [Parameter()] [System.String] $CrossTenantAccessPolicyConfigurationPartnerTenantId, @@ -58921,6 +59421,7 @@ function Update-MgBetaPolicyTokenLifetimePolicy ) } #endregion + #region Microsoft.Graph.Beta.Teams function Get-MgBetaTeam { From f26c65414b5422ecfc6f7ce0ddd4bd25f5ef99d9 Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Tue, 24 Oct 2023 10:48:41 -0700 Subject: [PATCH 20/31] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e3a3f78f8..21b1154c8f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ * AADConditionalAccessPolicy * Adds support for Authentication Context. FIXES [#3813](https://github.com/microsoft/Microsoft365DSC/issues/3813) +* AADSocialIdentityProvider + * Initial release. * TeamsComplianceRecordingPolicy * Fixes an issue where the Compliance Application ID wasn't properly retrieved. FIXES [#3712](https://github.com/microsoft/Microsoft365DSC/issues/3712) From a58b818f97aefddd7b3d4683aede6499d55bdea3 Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Tue, 24 Oct 2023 18:07:07 +0000 Subject: [PATCH 21/31] Updated Resources and Cmdlet documentation pages --- .../resources/azure-ad/AADAttributeSet.md | 2 +- .../azure-ad/AADSocialIdentityProvider.md | 85 +++++++++++++++++++ 2 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 docs/docs/resources/azure-ad/AADSocialIdentityProvider.md diff --git a/docs/docs/resources/azure-ad/AADAttributeSet.md b/docs/docs/resources/azure-ad/AADAttributeSet.md index 2e0e5f5ff4..5cd6f05fb3 100644 --- a/docs/docs/resources/azure-ad/AADAttributeSet.md +++ b/docs/docs/resources/azure-ad/AADAttributeSet.md @@ -40,7 +40,7 @@ To authenticate with the Microsoft Graph API, this resource required the followi - **Read** - - CustomSecAttributeDefinition.ReadWrite.All + - CustomSecAttributeDefinition.Read.All - **Update** diff --git a/docs/docs/resources/azure-ad/AADSocialIdentityProvider.md b/docs/docs/resources/azure-ad/AADSocialIdentityProvider.md new file mode 100644 index 0000000000..3cc81eddbd --- /dev/null +++ b/docs/docs/resources/azure-ad/AADSocialIdentityProvider.md @@ -0,0 +1,85 @@ +# AADSocialIdentityProvider + +## Parameters + +| Parameter | Attribute | DataType | Description | Allowed Values | +| --- | --- | --- | --- | --- | +| **ClientId** | Key | String | The client identifier for the application obtained when registering the application with the identity provider. | | +| **ClientSecret** | Write | String | The client secret for the application that is obtained when the application is registered with the identity provider. This is write-only. A read operation returns ****. | | +| **DisplayName** | Write | String | The display name of the identity provider. | | +| **IdentityProviderType** | Write | String | For a B2B scenario, possible values: Google, Facebook. For a B2C scenario, possible values: Microsoft, Google, Amazon, LinkedIn, Facebook, GitHub, Twitter, Weibo, QQ, WeChat. | `AADSignup`, `EmailOTP`, `Microsoft`, `MicrosoftAccount`, `Google`, `Amazon`, `LinkedIn`, `Facebook`, `GitHub`, `Twitter`, `Weibo`, `QQ`, `WeChat` | +| **Ensure** | Write | String | Present ensures the policy exists, absent ensures it is removed. | `Present`, `Absent` | +| **Credential** | Write | PSCredential | Credentials of the Admin | | +| **ApplicationId** | Write | String | Id of the Azure Active Directory application to authenticate with. | | +| **TenantId** | Write | String | Id of the Azure Active Directory tenant used for authentication. | | +| **ApplicationSecret** | Write | PSCredential | Secret of the Azure Active Directory tenant used for authentication. | | +| **CertificateThumbprint** | Write | String | Thumbprint of the Azure Active Directory application's authentication certificate to use for authentication. | | +| **ManagedIdentity** | Write | Boolean | Managed ID being used for authentication. | | + + +# AADIdentityProvider + +## Description + +Represents identity providers with External Identities for both Microsoft Entra ID and Azure AD B2C tenants. For Microsoft Entra B2B scenarios in a Microsoft Entra tenant, the identity provider type can be Google or Facebook. + +## Permissions + +### Microsoft Graph + +To authenticate with the Microsoft Graph API, this resource required the following permissions: + +#### Delegated permissions + +- **Read** + + - None + +- **Update** + + - None + +#### Application permissions + +- **Read** + + - IdentityProvider.Read.All + +- **Update** + + - IdentityProvider.ReadWrite.All + +## Examples + +### Example 1 + +This example is used to test new resources and showcase the usage of new resources being worked on. +It is not meant to use as a production baseline. + +```powershell +Configuration Example +{ + param + ( + [Parameter(Mandatory = $true)] + [PSCredential] + $credsCredential + ) + + Import-DscResource -ModuleName Microsoft365DSC + + node localhost + { + AADSocialIdentityProvider "AADSocialIdentityProvider-Google" + { + ClientId = "Google-OAUTH"; + ClientSecret = "FakeSecret"; + Credential = $credsCredential; + DisplayName = "My Google Provider"; + Ensure = "Present"; + IdentityProviderType = "Google"; + } + } +} +``` + From f0a96256513f325a8f188a09e206aa5f7ab1fbf8 Mon Sep 17 00:00:00 2001 From: deb Date: Wed, 25 Oct 2023 16:35:21 +0530 Subject: [PATCH 22/31] fix: typo --- docs/docs/home/what-is-M365DSC.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/home/what-is-M365DSC.md b/docs/docs/home/what-is-M365DSC.md index 1ccb351243..4045754118 100644 --- a/docs/docs/home/what-is-M365DSC.md +++ b/docs/docs/home/what-is-M365DSC.md @@ -49,7 +49,7 @@ Microsoft365DSC is the very first PowerShell project that natively supports Reve Upon providing credentials with correct permissions, the tool will begin the extraction of the configuration. Once it completes the extraction, it will prompt you to specify a destination directory to store the extracted artifacts. -The tool will extract several artifacts, including all SharePoint Add-ins and Frameworks packages, the configuration itself, and a metadata file that contains all variables that are specific to your environment. That metadata file (.psd1) abstracts components of you configuration, such as the tenant name, in order to make it as easy as possible for you to replicate those configurations across tenants. As an example, you can extract the configuration from any given tenant using the ReverseDSC functionality, open the extracted .psd1 metadata file, change the tenant's name to a new destination, and apply that new configuration. This allows organizations to keep the configuration of multiple tenants in synchronization with one another. +The tool will extract several artifacts, including all SharePoint Add-ins and Frameworks packages, the configuration itself, and a metadata file that contains all variables that are specific to your environment. That metadata file (.psd1) abstracts components of your configuration, such as the tenant name, in order to make it as easy as possible for you to replicate those configurations across tenants. As an example, you can extract the configuration from any given tenant using the ReverseDSC functionality, open the extracted .psd1 metadata file, change the tenant's name to a new destination, and apply that new configuration. This allows organizations to keep the configuration of multiple tenants in synchronization with one another. See the [Exporting](../../user-guide/get-started/snapshot-of-existing-tenant/) page for more information about possible options. From d3f51fa81b7b4a168f151c94dc14d6baf54e1658 Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Wed, 25 Oct 2023 11:03:45 -0700 Subject: [PATCH 23/31] Fixes #3830 --- CHANGELOG.md | 3 +++ .../MSFT_AADApplication.psm1 | 21 +++++++++---------- .../Microsoft365DSC/Modules/M365DSCUtil.psm1 | 19 ++++++++++++----- 3 files changed, 27 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0943e19ce1..a39e1d42f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ # UNRELEASED +* AADApplication + * Changes to how permissions drifts are logged. + FIXES [#3830](https://github.com/microsoft/Microsoft365DSC/issues/3830) * AADAttributeSet * Initial Release. * AADAuthenticationContext diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADApplication/MSFT_AADApplication.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADApplication/MSFT_AADApplication.psm1 index f91d1f061f..0141201b15 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADApplication/MSFT_AADApplication.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADApplication/MSFT_AADApplication.psm1 @@ -752,15 +752,14 @@ function Test-TargetResource if ($CurrentValues.Permissions.Length -gt 0 -and $null -ne $CurrentValues.Permissions.Name) { $permissionsDiff = Compare-Object -ReferenceObject ($CurrentValues.Permissions.Name) -DifferenceObject ($Permissions.Name) + $driftedParams = @{} if ($null -ne $permissionsDiff) { Write-Verbose -Message "Permissions differ: $($permissionsDiff | Out-String)" Write-Verbose -Message "Test-TargetResource returned $false" - $EventMessage = "Permissions for Azure AD Application {$DisplayName} were not in the desired state.`r`n" + ` - "They should contain {$($Permissions.Name)} but instead contained {$($CurrentValues.Permissions.Name)}" - Add-M365DSCEvent -Message $EventMessage -EntryType 'Warning' ` - -EventID 1 -Source $($MyInvocation.MyCommand.Source) - return $false + $EventValue = "$($CurrentValues.Permissions.Name)" + $EventValue += "$($Permissions.Name)" + $driftedParams.Add('Permissions', $EventValue) } else { @@ -773,11 +772,10 @@ function Test-TargetResource { Write-Verbose -Message 'No Permissions exist for the current Azure AD App, but permissions were specified for desired state' Write-Verbose -Message "Test-TargetResource returned $false" - $EventMessage = "Permissions for Azure AD Application {$DisplayName} were not in the desired state.`r`n" + ` - "They should contain {$($Permissions.Name)} but instead contained {`$null}" - Add-M365DSCEvent -Message $EventMessage -EntryType 'Warning' ` - -EventID 1 -Source $($MyInvocation.MyCommand.Source) - return $false + + $EventValue = "`$null" + $EventValue += "$($Permissions.Name)" + $driftedParams.Add('Permissions', $EventValue) } else { @@ -800,7 +798,8 @@ function Test-TargetResource $TestResult = Test-M365DSCParameterState -CurrentValues $CurrentValues ` -Source $($MyInvocation.MyCommand.Source) ` -DesiredValues $PSBoundParameters ` - -ValuesToCheck $ValuesToCheck.Keys + -ValuesToCheck $ValuesToCheck.Keys ` + -IncludedDrifts $driftedParams Write-Verbose -Message "Test-TargetResource returned $TestResult" diff --git a/Modules/Microsoft365DSC/Modules/M365DSCUtil.psm1 b/Modules/Microsoft365DSC/Modules/M365DSCUtil.psm1 index 33bdafaeba..5e58dd9842 100644 --- a/Modules/Microsoft365DSC/Modules/M365DSCUtil.psm1 +++ b/Modules/Microsoft365DSC/Modules/M365DSCUtil.psm1 @@ -472,7 +472,7 @@ $VerbosePreference = 'Continue' $DesiredEntry.$PropertyName -ne $EquivalentEntryInCurrent.$PropertyName) { $drift = $true - if ($DesiredEntry.$PropertyName.Contains('$OrganizationName')) + if ($DesiredEntry.$PropertyName.GetType().Name -eq 'String' -and $DesiredEntry.$PropertyName.Contains('$OrganizationName')) { if ($DesiredEntry.$PropertyName.Split('@')[0] -eq $EquivalentEntryInCurrent.$PropertyName.Split('@')[0]) { @@ -565,9 +565,13 @@ function Test-M365DSCParameterState [Parameter(Position = 5)] [System.String] - $Tenant + $Tenant, + + [Parameter(Position = 6)] + [System.Collections.Hashtable] + $IncludedDrifts ) - $verbosePreference = 'SilentlyContinue' + $VerbosePreference = 'SilentlyContinue' #region Telemetry $data = [System.Collections.Generic.Dictionary[[String], [String]]]::new() $data.Add('Resource', "$Source") @@ -576,6 +580,12 @@ function Test-M365DSCParameterState $returnValue = $true $DriftedParameters = @{ } + if ($null -ne $IncludedDrifts -and $IncludedDrifts.Keys.Count -gt 0) + { + $DriftedParameters = $IncludedDrifts + Write-Verbose -Message "@@@@@@@@@@`r`n$($IncludedDrifts | Out-String)" + $returnValue = $false + } if (($DesiredValues.GetType().Name -ne 'HashTable') ` -and ($DesiredValues.GetType().Name -ne 'CimInstance') ` @@ -659,7 +669,6 @@ function Test-M365DSCParameterState } $AllDesiredValuesAsArray += [PSCustomObject]$currentEntry } - $arrayCompare = Compare-PSCustomObjectArrays -CurrentValues $CurrentValues.$fieldName ` -DesiredValues $AllDesiredValuesAsArray @@ -885,7 +894,7 @@ function Test-M365DSCParameterState { Write-Verbose -Message $_ } - if ($returnValue -eq $false) + if ($returnValue -eq $false -or $DriftedParameters.Keys.Length -gt 0) { $EventMessage = [System.Text.StringBuilder]::New() $EventMessage.Append("`r`n") | Out-Null From 264eaea2948542134819547650e89dc219dceee3 Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Wed, 25 Oct 2023 11:25:19 -0700 Subject: [PATCH 24/31] Release 1.23.1025.1 --- CHANGELOG.md | 2 +- Modules/Microsoft365DSC/Microsoft365DSC.psd1 | 37 ++++++++++---------- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a39e1d42f9..02ce28caaf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Change log for Microsoft365DSC -# UNRELEASED +# 1.23.1025.1 * AADApplication * Changes to how permissions drifts are logged. diff --git a/Modules/Microsoft365DSC/Microsoft365DSC.psd1 b/Modules/Microsoft365DSC/Microsoft365DSC.psd1 index 46358c8525..e9001ef1e7 100644 --- a/Modules/Microsoft365DSC/Microsoft365DSC.psd1 +++ b/Modules/Microsoft365DSC/Microsoft365DSC.psd1 @@ -3,7 +3,7 @@ # # Generated by: Microsoft Corporation # -# Generated on: 2023-10-18 +# Generated on: 2023-10-25 @{ @@ -11,7 +11,7 @@ # RootModule = '' # Version number of this module. - ModuleVersion = '1.23.1018.1' + ModuleVersion = '1.23.1025.1' # Supported PSEditions # CompatiblePSEditions = @() @@ -140,25 +140,24 @@ IconUri = 'https://github.com/microsoft/Microsoft365DSC/blob/Dev/Modules/Microsoft365DSC/Dependencies/Images/Logo.png?raw=true' # ReleaseNotes of this module - ReleaseNotes = '* AADAuthenticationMethodPolicyAuthenticator - * Fixes an issue with the Get method when an assigned group - was deleted. + ReleaseNotes = '* AADApplication + * Changes to how permissions drifts are logged. + FIXES [#3830](https://github.com/microsoft/Microsoft365DSC/issues/3830) + * AADAttributeSet + * Initial Release. + * AADAuthenticationContext + * Initial Release. * AADConditionalAccessPolicy - * Added support for the SigninFrequencyInterval parameter. - * EXODistributionGroup - * Changes the export logic to use PrimarySMTPAddress if provided. - * IntuneAntivirusPolicyWindows10SettingCatalog - * Added "-All" parameter to retrieve all settings from a template. - FIXES [#3722](https://github.com/microsoft/Microsoft365DSC/issues/3722) - * TeamsGroupPolicyAssignment - * Fixes the export of CsGroup, when the display name of a group is included in - another display name. - FIXES [#3736](https://github.com/microsoft/Microsoft365DSC/issues/3736) - * TeamsUserPolicyAssignment + * Adds support for Authentication Context. + FIXES [#3813](https://github.com/microsoft/Microsoft365DSC/issues/3813) + * AADSocialIdentityProvider * Initial release. - FIXES [#3777](https://github.com/microsoft/Microsoft365DSC/issues/3777) - * MISC - * Fixes fancy quotes in complex objects for extraction.' + * TeamsComplianceRecordingPolicy + * Fixes an issue where the Compliance Application ID was not properly retrieved. + FIXES [#3712](https://github.com/microsoft/Microsoft365DSC/issues/3712) + * DEPENDENCIES + * Updated Microsoft.Graph dependencies to version 2.8.0. + * Updated MicrosoftTeams dependency to version 5.7.1.' # Flag to indicate whether the module requires explicit user acceptance for install/update # RequireLicenseAcceptance = $false From ce1c9082796fb6ef8c8553fa1d38f7d8709663e8 Mon Sep 17 00:00:00 2001 From: deb Date: Thu, 26 Oct 2023 01:33:03 +0530 Subject: [PATCH 25/31] fix: typo --- docs/docs/contributing/getting-started.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/contributing/getting-started.md b/docs/docs/contributing/getting-started.md index f89ab37973..78127933e3 100644 --- a/docs/docs/contributing/getting-started.md +++ b/docs/docs/contributing/getting-started.md @@ -10,7 +10,7 @@ The Microsoft365DSC project is open to contribution from the community. In order ![Infographic](../Images/CreateFork.jpg){ align=center width=500 } -- A dialog box asking you to select the account to fork the repository will appear. Select you account from the list. +- A dialog box asking you to select the account to fork the repository will appear. Select your account from the list. ![Select Account to fork under](../Images/ForkLocation.jpg){ width=500 } From 017fefc98226bace3459cee715d6d76f9548c4a5 Mon Sep 17 00:00:00 2001 From: William-francillette Date: Wed, 25 Oct 2023 21:43:26 +0100 Subject: [PATCH 26/31] fix approvers and reviewers + M365DSCDRGUtil:convertComplextoHashtable --- ...nagementAccessPackageAssignmentPolicy.psm1 | 91 +++++++++++++++++-- .../Modules/M365DSCDRGUtil.psm1 | 8 +- 2 files changed, 89 insertions(+), 10 deletions(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADEntitlementManagementAccessPackageAssignmentPolicy/MSFT_AADEntitlementManagementAccessPackageAssignmentPolicy.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADEntitlementManagementAccessPackageAssignmentPolicy/MSFT_AADEntitlementManagementAccessPackageAssignmentPolicy.psm1 index 099402bc79..030d514a65 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADEntitlementManagementAccessPackageAssignmentPolicy/MSFT_AADEntitlementManagementAccessPackageAssignmentPolicy.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADEntitlementManagementAccessPackageAssignmentPolicy/MSFT_AADEntitlementManagementAccessPackageAssignmentPolicy.psm1 @@ -126,7 +126,7 @@ function Get-TargetResource Write-Verbose -Message "Found access package assignment policy with id {$($getValue.Id)} and DisplayName {$DisplayName}" #region Format AccessReviewSettings - $formattedAccessReviewSettings = Get-M365DSCDRGComplexTypeToHashtable -ComplexObject $getValue.AccessReviewSettings + $formattedAccessReviewSettings = Get-M365DSCDRGComplexTypeToHashtable -ComplexObject $getValue.AccessReviewSettings -Verbose if($null -ne $formattedAccessReviewSettings) { $formattedAccessReviewSettings.remove('additionalProperties') | Out-Null @@ -139,6 +139,7 @@ function Get-TargetResource if (-not [String]::isNullOrEmpty($setting.AdditionalProperties.id)) { $user = Get-MgUser -UserId $setting.AdditionalProperties.id -ErrorAction SilentlyContinue + if ($null -ne $user) { $setting.add('Id', $user.UserPrincipalName) @@ -148,7 +149,7 @@ function Get-TargetResource { $setting.add('ManagerLevel', $setting.AdditionalProperties.managerLevel) } - $setting.remove('additionalProperties') | Out-Null + $setting.remove('AdditionalProperties') | Out-Null } } #endregion @@ -170,7 +171,11 @@ function Get-TargetResource $setting.add('odataType', $setting.AdditionalProperties.'@odata.type') if (-not [String]::isNullOrEmpty($setting.AdditionalProperties.id)) { - $setting.add('Id', $setting.AdditionalProperties.id) + $user = Get-MgUser -UserId $setting.AdditionalProperties.id -ErrorAction SilentlyContinue + if ($null -ne $user) + { + $setting.add('Id', $user.UserPrincipalName) + } } if (-not [String]::isNullOrEmpty($setting.AdditionalProperties.managerLevel)) { @@ -187,7 +192,11 @@ function Get-TargetResource $setting.add('odataType', $setting.AdditionalProperties.'@odata.type') if (-not [String]::isNullOrEmpty($setting.AdditionalProperties.id)) { - $setting.add('Id', $setting.AdditionalProperties.id) + $user = Get-MgUser -UserId $setting.AdditionalProperties.id -ErrorAction SilentlyContinue + if ($null -ne $user) + { + $setting.add('Id', $user.UserPrincipalName) + } } if (-not [String]::isNullOrEmpty($setting.AdditionalProperties.managerLevel)) { @@ -462,6 +471,36 @@ function Set-TargetResource } } } + if ( $null -ne $CreateParameters.RequestApprovalSettings.ApprovalStages.PrimaryApprovers) + { + for ($i = 0; $i -lt $CreateParameters.RequestApprovalSettings.ApprovalStages.PrimaryApprovers.Length; $i++) + { + $primaryApprover = $CreateParameters.RequestApprovalSettings.ApprovalStages.PrimaryApprovers[$i] + if ($null -ne $primaryApprover.id) + { + $user = Get-MgUser -Filter "startswith(UserPrincipalName, '$($primaryApprover.Id.Split('@')[0])')" -ErrorAction SilentlyContinue + if ($null -ne $user) + { + $CreateParameters.RequestApprovalSettings.ApprovalStages.PrimaryApprovers[$i].Id = $user.Id + } + } + } + } + if ( $null -ne $CreateParameters.RequestApprovalSettings.ApprovalStages.EscalationApprovers) + { + for ($i = 0; $i -lt $CreateParameters.RequestApprovalSettings.ApprovalStages.EscalationApprovers.Length; $i++) + { + $escalationApprover = $CreateParameters.RequestApprovalSettings.ApprovalStages.EscalationApprovers[$i] + if ($null -ne $escalationApprover.id) + { + $user = Get-MgUser -Filter "startswith(UserPrincipalName, '$($escalationApprover.Id.Split('@')[0])')" -ErrorAction SilentlyContinue + if ($null -ne $user) + { + $CreateParameters.RequestApprovalSettings.ApprovalStages.EscalationApprovers[$i].Id = $user.Id + } + } + } + } if ($null -ne $CreateParameters.RequestorSettings -and $null -ne $CreateParameters.RequestorSettings.AllowedRequestors) { for ($i = 0; $i -lt $CreateParameters.RequestorSettings.AllowedRequestors.Length; $i++) @@ -527,6 +566,36 @@ function Set-TargetResource } } } + if ($null -ne $UpdateParameters.RequestApprovalSettings.ApprovalStages.PrimaryApprovers) + { + for ($i = 0; $i -lt $UpdateParameters.RequestApprovalSettings.ApprovalStages.PrimaryApprovers.Length; $i++) + { + $primaryApprover = $UpdateParameters.RequestApprovalSettings.ApprovalStages.PrimaryApprovers[$i] + if ($null -ne $primaryApprover.id) + { + $user = Get-MgUser -Filter "startswith(UserPrincipalName, '$($primaryApprover.Id.Split('@')[0])')" -ErrorAction SilentlyContinue + if ($null -ne $user) + { + $UpdateParameters.RequestApprovalSettings.ApprovalStages.PrimaryApprovers[$i].Id = $user.Id + } + } + } + } + if ($null -ne $UpdateParameters.RequestApprovalSettings.ApprovalStages.EscalationApprovers) + { + for ($i = 0; $i -lt $UpdateParameters.RequestApprovalSettings.ApprovalStages.EscalationApprovers.Length; $i++) + { + $escalationApprover = $UpdateParameters.RequestApprovalSettings.ApprovalStages.EscalationApprovers[$i] + if ($null -ne $escalationApprover.id) + { + $user = Get-MgUser -Filter "startswith(UserPrincipalName, '$($escalationApprover.Id.Split('@')[0])')" -ErrorAction SilentlyContinue + if ($null -ne $user) + { + $UpdateParameters.RequestApprovalSettings.ApprovalStages.EscalationApprovers[$i].Id = $user.Id + } + } + } + } if ($null -ne $UpdateParameters.RequestorSettings -and $null -ne $UpdateParameters.RequestorSettings.AllowedRequestors) { #Write-Verbose -Message "Updating Requestors' Id" @@ -810,7 +879,17 @@ function Export-TargetResource if ($null -ne $Results.AccessReviewSettings) { - $complexTypeStringResult = Get-M365DSCDRGComplexTypeToString -ComplexObject $Results.AccessReviewSettings -CIMInstanceName MicrosoftGraphassignmentreviewsettings + $complexMapping = @( + @{ + Name = 'Reviewers' + CimInstanceName = 'MicrosoftGraphuserset' + IsRequired = $false + } + ) + $complexTypeStringResult = Get-M365DSCDRGComplexTypeToString ` + -ComplexObject $Results.AccessReviewSettings ` + -CIMInstanceName MicrosoftGraphassignmentreviewsettings ` + -ComplexTypeMapping $complexMapping if ($complexTypeStringResult) { $Results.AccessReviewSettings = $complexTypeStringResult @@ -939,7 +1018,7 @@ function Export-TargetResource if ($null -ne $Results.AccessReviewSettings) { $currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock -ParameterName 'AccessReviewSettings' - $currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock -ParameterName 'Reviewers' + #$currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock -ParameterName 'Reviewers' } if ($null -ne $Results.Questions ) { diff --git a/Modules/Microsoft365DSC/Modules/M365DSCDRGUtil.psm1 b/Modules/Microsoft365DSC/Modules/M365DSCDRGUtil.psm1 index 53c6531a34..318f1becae 100644 --- a/Modules/Microsoft365DSC/Modules/M365DSCDRGUtil.psm1 +++ b/Modules/Microsoft365DSC/Modules/M365DSCDRGUtil.psm1 @@ -134,21 +134,21 @@ function Get-M365DSCDRGComplexTypeToHashtable return , [hashtable[]]$results } + if ($ComplexObject.getType().fullname -like '*Dictionary*') { $results = @{} $ComplexObject = [hashtable]::new($ComplexObject) $keys = $ComplexObject.Keys + foreach ($key in $keys) { if ($null -ne $ComplexObject.$key) { $keyName = $key - $keyType = $ComplexObject.$key.gettype().fullname - - if ($keyType -like '*CimInstance*' -or $keyType -like '*Dictionary*' -or $keyType -like 'Microsoft.Graph.PowerShell.Models.*' -or $keyType -like '*[[\]]') + if ($keyType -like '*CimInstance*' -or $keyType -like '*Dictionary*' -or $keyType -like 'Microsoft.Graph.PowerShell.Models.*' -or $keyType -like 'Microsoft.Graph.Beta.PowerShell.Models.*' -or $keyType -like '*[[\]]') { $hash = Get-M365DSCDRGComplexTypeToHashtable -ComplexObject $ComplexObject.$key @@ -185,7 +185,7 @@ function Get-M365DSCDRGComplexTypeToHashtable if ($null -ne $ComplexObject.$keyName) { $keyType = $ComplexObject.$keyName.gettype().fullname - if ($keyType -like '*CimInstance*' -or $keyType -like '*Dictionary*' -or $keyType -like 'Microsoft.Graph.PowerShell.Models.*') + if ($keyType -like '*CimInstance*' -or $keyType -like '*Dictionary*' -or $keyType -like 'Microsoft.Graph.*PowerShell.Models.*') { $hash = Get-M365DSCDRGComplexTypeToHashtable -ComplexObject $ComplexObject.$keyName From c9d1f4cbdafcac992c4668b49cc0fa4bfb679b14 Mon Sep 17 00:00:00 2001 From: William-francillette Date: Wed, 25 Oct 2023 21:48:30 +0100 Subject: [PATCH 27/31] add changelog --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0943e19ce1..9d374d6822 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ # UNRELEASED +* AADEntitlementManagementAccessPackageAssignmentPolicy + * Fixes an issue where reviewers were not properly exported +* M365DSCDRGUTIL + * Fixes an issue with Get-M365DSCDRGComplexTypeToHashtable where Beta cmdlet were not recognized for recursive calls + FIXES [#3448](https://github.com/microsoft/Microsoft365DSC/issues/3448) * AADAttributeSet * Initial Release. * AADAuthenticationContext From cde3fb2ba93524c5f22fef14fda5ed37b51f920c Mon Sep 17 00:00:00 2001 From: deb Date: Fri, 27 Oct 2023 22:44:16 +0530 Subject: [PATCH 28/31] fixed typos --- docs/docs/concepts/personas.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/docs/concepts/personas.md b/docs/docs/concepts/personas.md index f5da2b61f4..7efaac432e 100644 --- a/docs/docs/concepts/personas.md +++ b/docs/docs/concepts/personas.md @@ -69,7 +69,7 @@ This article describes the personas we've identified for Microsoft365DSC and pro Description: -

The Security Administrators are responsible for defining new Entra Identity policies, make updates to exsting ones and monitor them for configuration drifts at scale and across one or multiple tenants. Their goal is to ensure the overal security of the tenant by ensuring only authorized users can perform certain tasks. They are dealing with components such as:

+

The Security Administrators are responsible for defining new Entra Identity policies, make updates to existing ones and monitor them for configuration drifts at scale and across one or multiple tenants. Their goal is to ensure the overal security of the tenant by ensuring only authorized users can perform certain tasks. They are dealing with components such as:

  • AADAuthenticationMethodPolicy
  • AADAuthorizationPolicy
  • @@ -149,7 +149,7 @@ This article describes the personas we've identified for Microsoft365DSC and pro Description: -

    The Teams Collaboration Administrators are responsible for ensuring the proper functioning of the Teams collaboration features, such as managing channel, managing teams, etc. and for their associated policies (e.g., Teams Channel Policies, Teams Messaging Policies, etc.). They are dealing with components such as:

    +

    The Teams Collaboration Administrators are responsible for ensuring the proper functioning of the Teams collaboration features, such as managing channels, managing teams, etc. and for their associated policies (e.g., Teams Channel Policies, Teams Messaging Policies, etc.). They are dealing with components such as:

    • TeamsAppPermissionPolicy
    • TeamsChannel
    • From 1da75aac4a7573fa2730a49da80103bb2ae9252e Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Fri, 27 Oct 2023 15:05:38 -0700 Subject: [PATCH 29/31] Fixes #3787 --- CHANGELOG.md | 6 +++ ...SFT_AADRoleEligibilityScheduleRequest.psm1 | 49 ++++++++++--------- 2 files changed, 31 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 93a773633d..4ba3b82a9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Change log for Microsoft365DSC +# UNRELEASED + +* AADRoleEligibilityScheduleRequest + * Fixes how the Get method retrieves existing instances for Groups. + FIXES [#3787](https://github.com/microsoft/Microsoft365DSC/issues/3787) + # 1.23.1025.1 * AADEntitlementManagementAccessPackageAssignmentPolicy diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleEligibilityScheduleRequest/MSFT_AADRoleEligibilityScheduleRequest.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleEligibilityScheduleRequest/MSFT_AADRoleEligibilityScheduleRequest.psm1 index 873eddbbce..f7a9a96153 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleEligibilityScheduleRequest/MSFT_AADRoleEligibilityScheduleRequest.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleEligibilityScheduleRequest/MSFT_AADRoleEligibilityScheduleRequest.psm1 @@ -177,10 +177,11 @@ $RoleDefinitionId = (Get-MgBetaRoleManagementDirectoryRoleDefinition -Filter "DisplayName eq '$RoleDefinition'").Id Write-Verbose -Message "Found Role {$RoleDefinitionId}" + $schedule = Get-MgBetaRoleManagementDirectoryRoleEligibilitySchedule -Filter "PrincipalId eq '$PrincipalId' and RoleDefinitionId eq '$RoleDefinitionId'" $request = Get-MgBetaRoleManagementDirectoryRoleEligibilityScheduleRequest -Filter "PrincipalId eq '$PrincipalId' and RoleDefinitionId eq '$RoleDefinitionId'" } } - if ($null -eq $request) + if ($null -eq $schedule) { return $nullResult } @@ -188,12 +189,12 @@ Write-Verbose -Message "Found existing AADRolelLigibilityScheduleRequest" if ($PrincipalType -eq 'User') { - $PrincipalInstance = Get-MgUser -UserId $request.PrincipalId -ErrorAction SilentlyContinue + $PrincipalInstance = Get-MgUser -UserId $schedule.PrincipalId -ErrorAction SilentlyContinue $PrincipalTypeValue = 'User' } if ($null -eq $PrincipalInstance -or $PrincipalType -eq 'Group') { - $PrincipalInstance = Get-MGGroup -GroupId $request.PrincipalId -ErrorAction SilentlyContinue + $PrincipalInstance = Get-MGGroup -GroupId $schedule.PrincipalId -ErrorAction SilentlyContinue $PrincipalTypeValue = 'Group' } @@ -201,47 +202,47 @@ { return $nullResult } - $RoleDefinitionValue = Get-MgBetaRoleManagementDirectoryRoleDefinition -UnifiedRoleDefinitionId $request.RoleDefinitionId + $RoleDefinitionValue = Get-MgBetaRoleManagementDirectoryRoleDefinition -UnifiedRoleDefinitionId $schedule.RoleDefinitionId $ScheduleInfoValue = @{} - if ($null -ne $request.ScheduleInfo.Expiration) + if ($null -ne $schedule.ScheduleInfo.Expiration) { $expirationValue = @{ - duration = $request.ScheduleInfo.Expiration.Duration - type = $request.ScheduleInfo.Expiration.Type + duration = $schedule.ScheduleInfo.Expiration.Duration + type = $schedule.ScheduleInfo.Expiration.Type } - if ($null -ne $request.ScheduleInfo.Expiration.EndDateTime) + if ($null -ne $schedule.ScheduleInfo.Expiration.EndDateTime) { - $expirationValue.Add('endDateTime', $request.ScheduleInfo.Expiration.EndDateTime.ToString("yyyy-MM-ddThh:mm:ssZ")) + $expirationValue.Add('endDateTime', $schedule.ScheduleInfo.Expiration.EndDateTime.ToString("yyyy-MM-ddThh:mm:ssZ")) } $ScheduleInfoValue.Add('expiration', $expirationValue) } - if ($null -ne $request.ScheduleInfo.Recurrence) + if ($null -ne $schedule.ScheduleInfo.Recurrence) { $recurrenceValue = @{ pattern = @{ - dayOfMonth = $request.ScheduleInfo.Recurrence.Pattern.dayOfMonth - daysOfWeek = $request.ScheduleInfo.Recurrence.Pattern.daysOfWeek - firstDayOfWeek = $request.ScheduleInfo.Recurrence.Pattern.firstDayOfWeek - index = $request.ScheduleInfo.Recurrence.Pattern.index - interval = $request.ScheduleInfo.Recurrence.Pattern.interval - month = $request.ScheduleInfo.Recurrence.Pattern.month - type = $request.ScheduleInfo.Recurrence.Pattern.type + dayOfMonth = $schedule.ScheduleInfo.Recurrence.Pattern.dayOfMonth + daysOfWeek = $schedule.ScheduleInfo.Recurrence.Pattern.daysOfWeek + firstDayOfWeek = $schedule.ScheduleInfo.Recurrence.Pattern.firstDayOfWeek + index = $schedule.ScheduleInfo.Recurrence.Pattern.index + interval = $schedule.ScheduleInfo.Recurrence.Pattern.interval + month = $schedule.ScheduleInfo.Recurrence.Pattern.month + type = $schedule.ScheduleInfo.Recurrence.Pattern.type } range = @{ - endDate = $request.ScheduleInfo.Recurrence.Range.endDate - numberOfOccurrences = $request.ScheduleInfo.Recurrence.Range.numberOfOccurrences - recurrenceTimeZone = $request.ScheduleInfo.Recurrence.Range.recurrenceTimeZone - startDate = $request.ScheduleInfo.Recurrence.Range.startDate - type = $request.ScheduleInfo.Recurrence.Range.type + endDate = $schedule.ScheduleInfo.Recurrence.Range.endDate + numberOfOccurrences = $schedule.ScheduleInfo.Recurrence.Range.numberOfOccurrences + recurrenceTimeZone = $schedule.ScheduleInfo.Recurrence.Range.recurrenceTimeZone + startDate = $schedule.ScheduleInfo.Recurrence.Range.startDate + type = $schedule.ScheduleInfo.Recurrence.Range.type } } $ScheduleInfoValue.Add('Recurrence', $recurrenceValue) } - if ($null -ne $request.ScheduleInfo.StartDateTime) + if ($null -ne $schedule.ScheduleInfo.StartDateTime) { - $ScheduleInfoValue.Add('StartDateTime', $request.ScheduleInfo.StartDateTime.ToString("yyyy-MM-ddThh:mm:ssZ")) + $ScheduleInfoValue.Add('StartDateTime', $schedule.ScheduleInfo.StartDateTime.ToString("yyyy-MM-ddThh:mm:ssZ")) } $ticketInfoValue = $null From f927989ae877d783ac5344c433b9921122077567 Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Mon, 30 Oct 2023 10:48:59 -0400 Subject: [PATCH 30/31] Update MSFT_AADRoleEligibilityScheduleRequest.psm1 --- ...SFT_AADRoleEligibilityScheduleRequest.psm1 | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleEligibilityScheduleRequest/MSFT_AADRoleEligibilityScheduleRequest.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleEligibilityScheduleRequest/MSFT_AADRoleEligibilityScheduleRequest.psm1 index f7a9a96153..f662a15551 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleEligibilityScheduleRequest/MSFT_AADRoleEligibilityScheduleRequest.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleEligibilityScheduleRequest/MSFT_AADRoleEligibilityScheduleRequest.psm1 @@ -181,6 +181,11 @@ $request = Get-MgBetaRoleManagementDirectoryRoleEligibilityScheduleRequest -Filter "PrincipalId eq '$PrincipalId' and RoleDefinitionId eq '$RoleDefinitionId'" } } + else + { + $RoleDefinitionId = (Get-MgBetaRoleManagementDirectoryRoleDefinition -Filter "DisplayName eq '$RoleDefinition'").Id + $schedule = Get-MgBetaRoleManagementDirectoryRoleEligibilitySchedule -Filter "PrincipalId eq '$($request.PrincipalId)' and RoleDefinitionId eq '$RoleDefinitionId'" + } if ($null -eq $schedule) { return $nullResult @@ -189,12 +194,12 @@ Write-Verbose -Message "Found existing AADRolelLigibilityScheduleRequest" if ($PrincipalType -eq 'User') { - $PrincipalInstance = Get-MgUser -UserId $schedule.PrincipalId -ErrorAction SilentlyContinue + $PrincipalInstance = Get-MgUser -UserId $request.PrincipalId -ErrorAction SilentlyContinue $PrincipalTypeValue = 'User' } if ($null -eq $PrincipalInstance -or $PrincipalType -eq 'Group') { - $PrincipalInstance = Get-MGGroup -GroupId $schedule.PrincipalId -ErrorAction SilentlyContinue + $PrincipalInstance = Get-MGGroup -GroupId $request.PrincipalId -ErrorAction SilentlyContinue $PrincipalTypeValue = 'Group' } @@ -202,7 +207,6 @@ { return $nullResult } - $RoleDefinitionValue = Get-MgBetaRoleManagementDirectoryRoleDefinition -UnifiedRoleDefinitionId $schedule.RoleDefinitionId $ScheduleInfoValue = @{} @@ -255,11 +259,11 @@ } $PrincipalValue = $null - if ($PrincipalTypeValue -eq 'User') + if ($PrincipalType -eq 'User') { $PrincipalValue = $PrincipalInstance.UserPrincipalName } - elseif ($PrincipalTypeValue -eq 'Group') + if ($null -eq $PrincipalValue -or $PrincipalTypeValue -eq 'Group') { $PrincipalValue = $PrincipalInstance.DisplayName } @@ -267,7 +271,7 @@ $results = @{ Principal = $PrincipalValue PrincipalType = $PrincipalTypeValue - RoleDefinition = $RoleDefinitionValue.DisplayName + RoleDefinition = $RoleDefinition DirectoryScopeId = $request.DirectoryScopeId AppScopeId = $request.AppScopeId Action = $request.Action @@ -730,10 +734,10 @@ function Export-TargetResource #region resource generator code $schedules = Get-MgBetaRoleManagementDirectoryRoleEligibilitySchedule -All -ErrorAction Stop [array] $Script:exportedInstances = @() - foreach ($schedule in $schedules) - { - [array] $allRequests = Get-MgBetaRoleManagementDirectoryRoleEligibilityScheduleRequest -All ` + [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 @@ -752,10 +756,12 @@ function Export-TargetResource { $displayedKey = $request.Id Write-Host " |---[$i/$($Script:exportedInstances.Count)] $displayedKey" -NoNewline + + $RoleDefinitionId = Get-MgBetaRoleManagementDirectoryRoleDefinition -UnifiedRoleDefinitionId $request.RoleDefinitionId $params = @{ Id = $request.Id Principal = $request.PrincipalId - RoleDefinition = 'TempDefinition' + RoleDefinition = $RoleDefinitionId.DisplayName ScheduleInfo = 'TempSchedule' Ensure = 'Present' Credential = $Credential From c6359a09dcdeee20b5a108405e0f05dacb61611f Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Mon, 30 Oct 2023 11:20:54 -0400 Subject: [PATCH 31/31] Fixes Unit Tests --- ...SFT_AADRoleEligibilityScheduleRequest.psm1 | 2 +- ...ADRoleEligibilityScheduleRequest.Tests.ps1 | 19 +++++++++++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleEligibilityScheduleRequest/MSFT_AADRoleEligibilityScheduleRequest.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleEligibilityScheduleRequest/MSFT_AADRoleEligibilityScheduleRequest.psm1 index f662a15551..2e4b3c31ac 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleEligibilityScheduleRequest/MSFT_AADRoleEligibilityScheduleRequest.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleEligibilityScheduleRequest/MSFT_AADRoleEligibilityScheduleRequest.psm1 @@ -186,7 +186,7 @@ $RoleDefinitionId = (Get-MgBetaRoleManagementDirectoryRoleDefinition -Filter "DisplayName eq '$RoleDefinition'").Id $schedule = Get-MgBetaRoleManagementDirectoryRoleEligibilitySchedule -Filter "PrincipalId eq '$($request.PrincipalId)' and RoleDefinitionId eq '$RoleDefinitionId'" } - if ($null -eq $schedule) + if ($null -eq $schedule -or $null -eq $request) { return $nullResult } diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADRoleEligibilityScheduleRequest.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADRoleEligibilityScheduleRequest.Tests.ps1 index a3330e6392..6f7082cd94 100644 --- a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADRoleEligibilityScheduleRequest.Tests.ps1 +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADRoleEligibilityScheduleRequest.Tests.ps1 @@ -25,6 +25,7 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { $secpasswd = ConvertTo-SecureString 'test@password1' -AsPlainText -Force $Credential = New-Object System.Management.Automation.PSCredential ('tenantadmin@mydomain.com', $secpasswd) $Script:exportedInstances = $null + $Script:ExportMode = $null Mock -CommandName Add-M365DSCTelemetryEvent -MockWith { } @@ -159,8 +160,7 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { RoleDefinition = "Teams Communications Administrator"; ScheduleInfo = New-CimInstance -ClassName MSFT_AADRoleEligibilityScheduleRequestSchedule -Property @{ - expiration = New-CimInstance -ClassName MSFT_AADRoleEligibilityScheduleRequestScheduleExpiration -Property @{ - + expiration = New-CimInstance -ClassName MSFT_AADRoleEligibilityScheduleRequestScheduleExpiration -Property @{ type = 'afterDateTime' } -ClientOnly } -ClientOnly @@ -182,6 +182,21 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { }; } } + Mock -CommandName Get-MgBetaRoleManagementDirectoryRoleEligibilitySchedule -MockWith { + return @{ + Action = "AdminAssign"; + Id = '12345-12345-12345-12345-12345' + DirectoryScopeId = "/"; + IsValidationOnly = $False; + PrincipalId = "123456"; + RoleDefinitionId = "12345"; + ScheduleInfo = @{ + expiration = @{ + type = 'afterDateTime' + } + }; + } + } } It 'Should return Values from the Get method' {