From a721e4badcf614354f3a0b4c050012ec6fb47be9 Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Mon, 11 Nov 2024 11:03:51 -0500 Subject: [PATCH 01/65] AzureBillingAccountPolicy - Initial Release --- CHANGELOG.md | 5 + .../MSFT_AzureBillingAccountPolicy.psm1 | 475 ++++++++++++++++++ .../MSFT_AzureBillingAccountPolicy.schema.mof | 25 + .../MSFT_AzureBillingAccountPolicy/readme.md | 6 + .../settings.json | 20 + ...FT_AzureBillingAccountScheduledAction.psm1 | 2 +- .../AzureBillingAccountPolicy/2-Update.ps1 | 39 ++ ...365DSC.AzureBillingAccountPolicy.Tests.ps1 | 186 +++++++ 8 files changed, 757 insertions(+), 1 deletion(-) create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_AzureBillingAccountPolicy/MSFT_AzureBillingAccountPolicy.psm1 create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_AzureBillingAccountPolicy/MSFT_AzureBillingAccountPolicy.schema.mof create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_AzureBillingAccountPolicy/readme.md create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_AzureBillingAccountPolicy/settings.json create mode 100644 Modules/Microsoft365DSC/Examples/Resources/AzureBillingAccountPolicy/2-Update.ps1 create mode 100644 Tests/Unit/Microsoft365DSC/Microsoft365DSC.AzureBillingAccountPolicy.Tests.ps1 diff --git a/CHANGELOG.md b/CHANGELOG.md index 6845ab5c9e..147673142d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Change log for Microsoft365DSC +# UNRELEASED + +* AzureBillingAccountPolicy + * Initial release. + # 1.24.1106.3 * AzureBillingAccountScheduledAction diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AzureBillingAccountPolicy/MSFT_AzureBillingAccountPolicy.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AzureBillingAccountPolicy/MSFT_AzureBillingAccountPolicy.psm1 new file mode 100644 index 0000000000..2066157785 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AzureBillingAccountPolicy/MSFT_AzureBillingAccountPolicy.psm1 @@ -0,0 +1,475 @@ +function Get-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + param + ( + [Parameter(Mandatory = $true)] + [System.String] + $BillingAccount, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance] + $EnterpriseAgreementPolicies, + + [Parameter()] + [System.String] + $MarketplacePurchases, + + [Parameter()] + [System.String] + $ReservationPurchases, + + [Parameter()] + [System.String] + $SavingsPlanPurchases, + + [Parameter()] + [System.String] + $Name, + + [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()] + [Switch] + $ManagedIdentity, + + [Parameter()] + [System.String[]] + $AccessTokens + ) + + New-M365DSCConnection -Workload 'Azure' ` + -InboundParameters $PSBoundParameters | Out-Null + + #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' + try + { + $uri = "https://management.azure.com/providers/Microsoft.Billing/billingAccounts/$($BillingAccount)/policies/default?api-version=2024-04-01" + $response = Invoke-AzRest -Uri $uri -Method GET + $instance = (ConvertFrom-Json ($response.Content)).value + + if ($null -eq $instance) + { + return $nullResult + } + + $EnterpriseAgreementPoliciesValue = $null + if ($null -ne $EnterpriseAgreementPolicies) + { + $EnterpriseAgreementPoliciesValue = @{ + accountOwnerViewCharges = $instance.properties.enterpriseAgreementPolicies.accountOwnerViewCharges + authenticationType = $instance.properties.enterpriseAgreementPolicies.authenticationType + departmentAdminViewCharges = $instance.properties.enterpriseAgreementPolicies.departmentAdminViewCharges + } + } + + $results = @{ + BillingAccount = $BillingAccount + Name = $instance.name + EnterpriseAgreementPolicies = $EnterpriseAgreementPoliciesValue + MarketplacePurchases = $instance.properties.marketplacePurchases + ReservationPurchases = $instance.properties.reservationPurchases + SavingsPlanPurchases = $instance.properties.savingsPlanPurchases + Ensure = 'Present' + Credential = $Credential + ApplicationId = $ApplicationId + TenantId = $TenantId + CertificateThumbprint = $CertificateThumbprint + ManagedIdentity = $ManagedIdentity.IsPresent + AccessTokens = $AccessTokens + } + return [System.Collections.Hashtable] $results + } + catch + { + Write-Verbose -Message $_ + 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] + $BillingAccount, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance] + $EnterpriseAgreementPolicies, + + [Parameter()] + [System.String] + $MarketplacePurchases, + + [Parameter()] + [System.String] + $ReservationPurchases, + + [Parameter()] + [System.String] + $SavingsPlanPurchases, + + [Parameter()] + [System.String] + $Name, + + [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()] + [Switch] + $ManagedIdentity, + + [Parameter()] + [System.String[]] + $AccessTokens + ) + + New-M365DSCConnection -Workload 'Azure' ` + -InboundParameters $PSBoundParameters | Out-Null + + #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 + + $instanceParams = @{ + properties = @{ + enterpriseAgreementPolicies = @{ + accountOwnerViewCharges = $EnterpriseAgreementPolicies.accountOwnerViewCharges + authenticationType = $EnterpriseAgreementPolicies.authenticationType + departmentAdminViewCharges = $EnterpriseAgreementPolicies.departmentAdminViewCharges + } + marketplacePurchases = $MarketplacePurchases + reservationPurchases = $ReservationPurchases + savingsPlanPurchases = $SavingsPlanPurchases + } + } + $payload = ConvertTo-Json $instanceParams -Depth 5 -Compress + Write-Verbose -Message "Updating billing account policy for {$BillingAccount} with payload:`r`n$($payload)" + $uri = "https://management.azure.com/providers/Microsoft.Billing/billingAccounts/$($BillingAccount)/policies/default?api-version=2024-04-01" + $response = Invoke-AzRest -Uri $uri -Method "PUT" -Payload $payload + Write-Verbose -Message "Response:`r`n$($response.Content)" +} + +function Test-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Boolean])] + param + ( + [Parameter(Mandatory = $true)] + [System.String] + $BillingAccount, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance] + $EnterpriseAgreementPolicies, + + [Parameter()] + [System.String] + $MarketplacePurchases, + + [Parameter()] + [System.String] + $ReservationPurchases, + + [Parameter()] + [System.String] + $SavingsPlanPurchases, + + [Parameter()] + [System.String] + $Name, + + [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()] + [Switch] + $ManagedIdentity, + + [Parameter()] + [System.String[]] + $AccessTokens + ) + + #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 + + $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 = $true + + #Compare Cim instances + foreach ($key in $PSBoundParameters.Keys) + { + $source = $PSBoundParameters.$key + $target = $CurrentValues.$key + if ($source.getType().Name -like '*CimInstance*') + { + $testResult = Compare-M365DSCComplexObject ` + -Source ($source) ` + -Target ($target) + + if (-Not $testResult) + { + $testResult = $false + break + } + + $ValuesToCheck.Remove($key) | Out-Null + } + } + + if ($testResult) + { + $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, + + [Parameter()] + [System.String[]] + $AccessTokens + ) + + $ConnectionMode = New-M365DSCConnection -Workload 'Azure' ` + -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 + { + $Script:ExportMode = $true + + #Get all billing account + $accounts = Get-M365DSCAzureBillingAccount + + $i = 1 + $dscContent = '' + if ($accounts.Length -eq 0) + { + Write-Host $Global:M365DSCEmojiGreenCheckMark + } + else + { + Write-Host "`r`n" -NoNewline + } + foreach ($account in $accounts.value) + { + $displayedKey = $account.properties.displayName + Write-Host " |---[$i/$($accounts.value.Length)] $displayedKey" -NoNewline + + if ($null -ne $Global:M365DSCExportResourceInstancesCount) + { + $Global:M365DSCExportResourceInstancesCount++ + } + $params = @{ + BillingAccount = $account.name + Credential = $Credential + ApplicationId = $ApplicationId + TenantId = $TenantId + CertificateThumbprint = $CertificateThumbprint + ManagedIdentity = $ManagedIdentity.IsPresent + AccessTokens = $AccessTokens + } + + $Results = Get-TargetResource @Params + $Results = Update-M365DSCExportAuthenticationResults -ConnectionMode $ConnectionMode ` + -Results $Results + + + if ($Results.EnterpriseAgreementPolicies) + { + $complexTypeStringResult = Get-M365DSCDRGComplexTypeToString -ComplexObject $Results.EnterpriseAgreementPolicies -CIMInstanceName AzureBillingAccountPolicyEnterpriseAgreementPolicy + if ($complexTypeStringResult) + { + $Results.EnterpriseAgreementPolicies = $complexTypeStringResult + } + else + { + $Results.Remove('EnterpriseAgreementPolicies') | Out-Null + } + } + $currentDSCBlock = Get-M365DSCExportContentForResource -ResourceName $ResourceName ` + -ConnectionMode $ConnectionMode ` + -ModulePath $PSScriptRoot ` + -Results $Results ` + -Credential $Credential + + if ($Results.EnterpriseAgreementPolicies) + { + $isCIMArray = $false + if ($Results.EnterpriseAgreementPolicies.getType().Fullname -like '*[[\]]') + { + $isCIMArray = $true + } + $currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock -ParameterName 'EnterpriseAgreementPolicies' -IsCIMArray:$isCIMArray + } + $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_AzureBillingAccountPolicy/MSFT_AzureBillingAccountPolicy.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_AzureBillingAccountPolicy/MSFT_AzureBillingAccountPolicy.schema.mof new file mode 100644 index 0000000000..5b68ca919e --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AzureBillingAccountPolicy/MSFT_AzureBillingAccountPolicy.schema.mof @@ -0,0 +1,25 @@ +[ClassVersion("1.0.0.0")] +class MSFT_AzureBillingAccountPolicyEnterpriseAgreementPolicy +{ + [Write, Description("The policy that controls whether account owner can view charges.")] String accountOwnerViewCharges; + [Write, Description("The state showing the enrollment auth level.")] String authenticationType; + [Write, Description("The policy that controls whether department admin can view charges.")] String departmentAdminViewCharges; +}; +[ClassVersion("1.0.0.0"), FriendlyName("AzureBillingAccountPolicy")] +class MSFT_AzureBillingAccountPolicy : OMI_BaseResource +{ + [Key, Description("Unique identifier of the associated billing account.")] String BillingAccount; + [Write, Description("Name of the policy.")] String Name; + [Write, Description("The policies for Enterprise Agreement enrollments."), EmbeddedInstance("MSFT_AzureBillingAccountPolicyEnterpriseAgreementPolicy")] String EnterpriseAgreementPolicies; + [Write, Description("The policy that controls whether Azure marketplace purchases are allowed.")] String MarketplacePurchases; + [Write, Description("The policy that controls whether Azure reservation purchases are allowed.")] String ReservationPurchases; + [Write, Description("The policy that controls whether users with Azure savings plan purchase are allowed.")] String SavingsPlanPurchases; + + [Write, Description("Present ensures the instance exists, absent ensures it is removed."), ValueMap{"Absent","Present"}, Values{"Absent","Present"}] string Ensure; + [Write, Description("Credentials of the workload's 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("Managed ID being used for authentication.")] Boolean ManagedIdentity; + [Write, Description("Access token used for authentication.")] String AccessTokens[]; +}; diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AzureBillingAccountPolicy/readme.md b/Modules/Microsoft365DSC/DSCResources/MSFT_AzureBillingAccountPolicy/readme.md new file mode 100644 index 0000000000..8432d3040a --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AzureBillingAccountPolicy/readme.md @@ -0,0 +1,6 @@ + +# AzureBillingAccountPolicy + +## Description + +Configures policies settings for an Azure billing account. diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AzureBillingAccountPolicy/settings.json b/Modules/Microsoft365DSC/DSCResources/MSFT_AzureBillingAccountPolicy/settings.json new file mode 100644 index 0000000000..2be977460b --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AzureBillingAccountPolicy/settings.json @@ -0,0 +1,20 @@ +{ + "resourceName": "AzureBillingAccountPolicy", + "description": "Configures policies settings for an Azure billing account.", + "roles": { + "read": [], + "update": [] + }, + "permissions": { + "graph": { + "delegated": { + "read": [], + "update": [] + }, + "application": { + "read": [], + "update": [] + } + } + } +} diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AzureBillingAccountScheduledAction/MSFT_AzureBillingAccountScheduledAction.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AzureBillingAccountScheduledAction/MSFT_AzureBillingAccountScheduledAction.psm1 index e6b49c0e6f..5eff8056b5 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AzureBillingAccountScheduledAction/MSFT_AzureBillingAccountScheduledAction.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AzureBillingAccountScheduledAction/MSFT_AzureBillingAccountScheduledAction.psm1 @@ -81,7 +81,7 @@ function Get-TargetResource $nullResult.Ensure = 'Absent' try { - $uri = "https://management.azure.com/providers/Microsoft.Billing/billingAccounts/$($account.name)/providers/Microsoft.CostManagement/scheduledActions?api-version=2023-11-01" + $uri = "https://management.azure.com/providers/Microsoft.Billing/billingAccounts/$($BillingAccount)/providers/Microsoft.CostManagement/scheduledActions?api-version=2023-11-01" $response = Invoke-AzRest -Uri $uri -Method GET $actions = (ConvertFrom-Json ($response.Content)).value diff --git a/Modules/Microsoft365DSC/Examples/Resources/AzureBillingAccountPolicy/2-Update.ps1 b/Modules/Microsoft365DSC/Examples/Resources/AzureBillingAccountPolicy/2-Update.ps1 new file mode 100644 index 0000000000..4bedeb545c --- /dev/null +++ b/Modules/Microsoft365DSC/Examples/Resources/AzureBillingAccountPolicy/2-Update.ps1 @@ -0,0 +1,39 @@ +<# +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()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint + ) + Import-DscResource -ModuleName Microsoft365DSC + node localhost + { + AzureBillingAccountPolicy "MyBillingAccountPolicy" + { + BillingAccount = "1e5b9e50-a1ea-581e-fb3a-xxxxxxxxx:6487d5cf-0a7b-42e6-9549-xxxxxxx_2019-05-31"; + Name = "default" + ApplicationId = $ApplicationId + TenantId = $TenantId + CertificateThumbprint = $CertificateThumbprint + EnterpriseAgreementPolicies = MSFT_AzureBillingAccountPolicyEnterpriseAgreementPolicy { + authenticationType = "OrganizationalAccountOnly" + } + MarketplacePurchases = "AllAllowed" + ReservationPurchases = "Allowed" + SavingsPlanPurchases = "NotAllowed" + } + } +} diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AzureBillingAccountPolicy.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AzureBillingAccountPolicy.Tests.ps1 new file mode 100644 index 0000000000..1aaf278223 --- /dev/null +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AzureBillingAccountPolicy.Tests.ps1 @@ -0,0 +1,186 @@ +[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) + +$CurrentScriptPath = $PSCommandPath.Split('\') +$CurrentScriptName = $CurrentScriptPath[$CurrentScriptPath.Length -1] +$ResourceName = $CurrentScriptName.Split('.')[1] +$Global:DscHelper = New-M365DscUnitTestHelper -StubModule $CmdletModule ` + -DscResource $ResourceName -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 (New-Guid | Out-String) -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 Get-M365DSCAzureBillingAccount -MockWith { + return @{ + value = @{ + name = "1e5b9e50-a1ea-581e-fb3a-xxxxxxxxx:6487d5cf-0a7b-42e6-9549-xxxxxxx_2019-05-31" + properties = @{ + displayName = "MyBillingAccount" + } + } + } + } + + # Mock Write-Host to hide output during the tests + Mock -CommandName Write-Host -MockWith { + } + $Script:exportedInstances =$null + $Script:ExportMode = $false + } + # Test contexts + Context -Name "The instance exists and values are already in the desired state" -Fixture { + BeforeAll { + $testParams = @{ + BillingAccount = "1e5b9e50-a1ea-581e-fb3a-xxxxxxxxx:6487d5cf-0a7b-42e6-9549-xxxxxxx_2019-05-31"; + Name = "default" + EnterpriseAgreementPolicies = (New-CimInstance -ClassName MSFT_AzureBillingAccountPolicyEnterpriseAgreementPolicy -Property @{ + authenticationType = "OrganizationalAccountOnly" + } -ClientOnly) + MarketplacePurchases = "AllAllowed" + ReservationPurchases = "Allowed" + SavingsPlanPurchases = "NotAllowed" + Ensure = 'Present' + Credential = $Credential; + } + + Mock -CommandName Invoke-AzRest -MockWith { + return @{ + Content = ConvertTo-Json @{ + value = @( + @{ + name = "default" + id = "12345-12345-12345-12345-12345" + properties = @{ + enterpriseAgreementPolicies = @{ + authenticationType = "OrganizationalAccountOnly" + } + marketplacePurchases = "AllAllowed" + reservationPurchases = "Allowed" + savingsPlanPurchases = "NotAllowed" + } + } + ) + } -Dept 10 -Compress + } + } + } + + 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 = @{ + BillingAccount = "1e5b9e50-a1ea-581e-fb3a-xxxxxxxxx:6487d5cf-0a7b-42e6-9549-xxxxxxx_2019-05-31"; + Name = "default" + EnterpriseAgreementPolicies = (New-CimInstance -ClassName MSFT_AzureBillingAccountPolicyEnterpriseAgreementPolicy -Property @{ + authenticationType = "OrganizationalAccountOnly" + } -ClientOnly) + MarketplacePurchases = "AllAllowed" + ReservationPurchases = "Allowed" + SavingsPlanPurchases = "Allowed" #Drift + Ensure = 'Present' + Credential = $Credential; + } + + Mock -CommandName Invoke-AzRest -MockWith { + return @{ + Content = ConvertTo-Json @{ + value = @( + @{ + name = "default" + id = "12345-12345-12345-12345-12345" + properties = @{ + enterpriseAgreementPolicies = @{ + authenticationType = "OrganizationalAccountOnly" + } + marketplacePurchases = "AllAllowed" + reservationPurchases = "Allowed" + savingsPlanPurchases = "NotAllowed" + } + } + ) + } -Dept 10 -Compress + } + } + } + + 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 Invoke-AzRest -Exactly 1 + } + } + + Context -Name 'ReverseDSC Tests' -Fixture { + BeforeAll { + $Global:CurrentModeIsExport = $true + $Global:PartialExportFileName = "$(New-Guid).partial.ps1" + $testParams = @{ + Credential = $Credential; + } + + Mock -CommandName Invoke-AzRest -MockWith { + return @{ + Content = ConvertTo-Json @{ + value = @( + @{ + name = "default" + id = "12345-12345-12345-12345-12345" + properties = @{ + enterpriseAgreementPolicies = @{ + authenticationType = "OrganizationalAccountOnly" + } + marketplacePurchases = "AllAllowed" + reservationPurchases = "Allowed" + savingsPlanPurchases = "NotAllowed" + } + } + ) + } -Dept 10 -Compress + } + } + } + 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 bcf30cda83dd40d88bb0bc6ce652b24fdd7a93c2 Mon Sep 17 00:00:00 2001 From: dannyKBjj Date: Tue, 12 Nov 2024 17:02:38 +0000 Subject: [PATCH 02/65] First draft of module Untested --- ...IntuneMobileAppConfigurationPolicyIOS.psm1 | 775 ++++++++++++++++++ ...MobileAppConfigurationPolicyIOS.schema.mof | Bin 0 -> 8196 bytes .../readme.md | 6 + .../settings.json | 32 + 4 files changed, 813 insertions(+) create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/MSFT_IntuneMobileAppConfigurationPolicyIOS.psm1 create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/MSFT_IntuneMobileAppConfigurationPolicyIOS.schema.mof create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/readme.md create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/settings.json diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/MSFT_IntuneMobileAppConfigurationPolicyIOS.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/MSFT_IntuneMobileAppConfigurationPolicyIOS.psm1 new file mode 100644 index 0000000000..039b5b9077 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/MSFT_IntuneMobileAppConfigurationPolicyIOS.psm1 @@ -0,0 +1,775 @@ +function Get-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + param + ( + #region resource generator code + [Parameter()] + [System.String] + $Id, + + [Parameter(Mandatory = $true)] + [System.String] + $DisplayName, + + [Parameter()] + [System.String] + $Description, + + [Parameter()] + [System.String[]] + $targetedMobileApps, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $settings, + + + #====================== + #standard params + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $Assignments, + #endregion + + [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, + + [Parameter()] + [System.String[]] + $AccessTokens + + ) + + try + { + $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` + -InboundParameters $PSBoundParameters + } + catch + { + Write-Verbose -Message 'Connection to the workload failed.' + } + + #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' + try + { + #$getValue = Get-MgBetaDeviceManagementDeviceConfiguration -DeviceConfigurationId $id -ErrorAction SilentlyContinue + if (-not [string]::IsNullOrWhiteSpace($id)){ $getValue = Get-MgBetaDeviceAppManagementMobileAppConfiguration -DeviceConfigurationId $id -ErrorAction SilentlyContinue } + + #region resource generator code + if ($null -eq $getValue) + { + $getValue = Get-MgBetaDeviceAppManagementMobileAppConfiguration -Filter "DisplayName eq '$Displayname'" -ErrorAction SilentlyContinue | Where-Object ` + -FilterScript { ` + $_.AdditionalProperties.'@odata.type' -eq '#microsoft.graph.iosMobileAppConfiguration' ` + } + } + #endregion + + if ($null -eq $getValue) + { + Write-Verbose -Message "Nothing with id {$id} was found" + return $nullResult + } + + Write-Verbose -Message "Found something with id {$id}" + +<# + $complexSettings = @() + foreach ($setting in $getValue.AdditionalProperties.settings) + { + $mySettings = @{} + $mySettings.Add($setting.keys, $setting.values) + + if ($mySettings.values.Where({$null -ne $_}).count -gt 0) + { + $complexSettings += $mySettings + } + } + +#> + + + + + + + + + $results = @{ + #region resource generator code + Id = $getValue.Id + Description = $getValue.Description + DisplayName = $getValue.DisplayName + + targetedMobileApps = $getValue.TargetedMobileApps + settings = $getValue.AdditionalProperties.settings + encodedSettingXml = $getValue.AdditionalProperties.encodedSettingXml + + Ensure = 'Present' + Credential = $Credential + ApplicationId = $ApplicationId + TenantId = $TenantId + ApplicationSecret = $ApplicationSecret + CertificateThumbprint = $CertificateThumbprint + Managedidentity = $ManagedIdentity.IsPresent + AccessTokens = $AccessTokens + version = $getValue.AdditionalProperties.version + + } + + + + $assignmentsValues = Get-MgBetaDeviceAppManagementMobileAppConfigurationAssignment -ManagedDeviceMobileAppConfigurationId $Results.Id + $assignmentResult = @() + if ($assignmentsValues.Count -gt 0) + { + $assignmentResult += ConvertFrom-IntunePolicyAssignment ` + -IncludeDeviceFilter:$true ` + -Assignments ($assignmentsValues) + } + $results.Add('Assignments', $assignmentResult) + + 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()] + [System.String] + $Id, + + [Parameter(Mandatory = $true)] + [System.String] + $DisplayName, + + [Parameter()] + [System.String] + $Description, + + [Parameter()] + [System.String[]] + $targetedMobileApps, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $settings, + + + #====================== + #standard params + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $Assignments, + #endregion + + [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, + + [Parameter()] + [System.String[]] + $AccessTokens + ) + + try + { + $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` + -InboundParameters $PSBoundParameters + } + catch + { + Write-Verbose -Message $_ + } + + #Ensure the proper dependencies are installed in the current environment. + Confirm-M365DSCDependencies + + #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 + + $PSBoundParameters.Remove('Ensure') | Out-Null + $PSBoundParameters.Remove('Credential') | Out-Null + $PSBoundParameters.Remove('ApplicationId') | Out-Null + $PSBoundParameters.Remove('ApplicationSecret') | Out-Null + $PSBoundParameters.Remove('TenantId') | Out-Null + $PSBoundParameters.Remove('CertificateThumbprint') | Out-Null + $PSBoundParameters.Remove('ManagedIdentity') | Out-Null + $PSBoundParameters.Remove('AccessTokens') | Out-Null + + + + + if ($Ensure -eq 'Present' -and $currentInstance.Ensure -eq 'Absent') + { + Write-Verbose -Message "Creating {$DisplayName}" + $PSBoundParameters.Remove('Assignments') | Out-Null + + $CreateParameters = ([Hashtable]$PSBoundParameters).clone() + $CreateParameters = Rename-M365DSCCimInstanceParameter -Properties $CreateParameters + + $AdditionalProperties = Get-M365DSCAdditionalProperties -Properties ($CreateParameters) + + foreach ($key in $AdditionalProperties.keys) + { + if ($key -ne '@odata.type') + { + $keyName = $key.substring(0, 1).ToUpper() + $key.substring(1, $key.length - 1) + $CreateParameters.remove($keyName) + } + } + + $CreateParameters.Remove('Id') | Out-Null + $CreateParameters.Remove('Verbose') | Out-Null + + foreach ($key in ($CreateParameters.clone()).Keys) + { + if ($CreateParameters[$key].getType().Fullname -like '*CimInstance*') + { + $CreateParameters[$key] = Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject $CreateParameters[$key] + } + } + + + + $CreateParameters.add('AdditionalProperties', $AdditionalProperties) + + #region resource generator code + $policy = New-MgBetaDeviceManagementDeviceConfiguration @CreateParameters + $assignmentsHash = ConvertTo-IntunePolicyAssignment -IncludeDeviceFilter:$true -Assignments $Assignments + + if ($policy.id) + { + Update-DeviceConfigurationPolicyAssignment -DeviceConfigurationPolicyId $policy.id ` + -Targets $assignmentsHash ` + -Repository 'deviceAppManagement/mobileAppConfigurations' + } + #endregion + } + elseif ($Ensure -eq 'Present' -and $currentInstance.Ensure -eq 'Present') + { + Write-Verbose -Message "Updating {$DisplayName}" + $PSBoundParameters.Remove('Assignments') | Out-Null + + $UpdateParameters = ([Hashtable]$PSBoundParameters).clone() + $UpdateParameters = Rename-M365DSCCimInstanceParameter -Properties $UpdateParameters + + $AdditionalProperties = Get-M365DSCAdditionalProperties -Properties ($UpdateParameters) + foreach ($key in $AdditionalProperties.keys) + { + if ($key -ne '@odata.type') + { + $keyName = $key.substring(0, 1).ToUpper() + $key.substring(1, $key.length - 1) + $UpdateParameters.remove($keyName) + } + } + + $UpdateParameters.Remove('Id') | Out-Null + $UpdateParameters.Remove('Verbose') | Out-Null + + foreach ($key in ($UpdateParameters.clone()).Keys) + { + if ($UpdateParameters[$key].getType().Fullname -like '*CimInstance*') + { + $UpdateParameters[$key] = Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject $UpdateParameters[$key] + } + } + + + + #region resource generator code + Update-MgBetaDeviceManagementDeviceConfiguration @UpdateParameters ` + -DeviceConfigurationId $currentInstance.Id + $assignmentsHash = ConvertTo-IntunePolicyAssignment -IncludeDeviceFilter:$true -Assignments $Assignments + Update-DeviceConfigurationPolicyAssignment -DeviceConfigurationPolicyId $currentInstance.id ` + -Targets $assignmentsHash ` + -Repository 'deviceAppManagement/mobileAppConfigurations' + #endregion + } + elseif ($Ensure -eq 'Absent' -and $currentInstance.Ensure -eq 'Present') + { + Write-Verbose -Message "Removing {$DisplayName}" + #region resource generator code + Remove-MgBetaDeviceManagementDeviceConfiguration -DeviceConfigurationId $currentInstance.Id + #endregion + } +} + +function Test-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Boolean])] + param + ( + #region resource generator code + [Parameter()] + [System.String] + $Id, + + [Parameter(Mandatory = $true)] + [System.String] + $DisplayName, + + [Parameter()] + [System.String] + $Description, + + [Parameter()] + [System.String[]] + $targetedMobileApps, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $settings, + + + #====================== + #standard params + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $Assignments, + #endregion + + [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, + + [Parameter()] + [System.String[]] + $AccessTokens + ) + + #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 {$id}" + + $CurrentValues = Get-TargetResource @PSBoundParameters + $ValuesToCheck = ([Hashtable]$PSBoundParameters).clone() + + if ($CurrentValues.Ensure -ne $Ensure) + { + Write-Verbose -Message "Test-TargetResource returned $false" + return $false + } + $testResult = $true + + foreach ($key in $PSBoundParameters.Keys) + { + if ($PSBoundParameters[$key].getType().Name -like '*CimInstance*') + { + $CIMArraySource = @() + $CIMArrayTarget = @() + $CIMArraySource += $PSBoundParameters[$key] + $CIMArrayTarget += $CurrentValues.$key + if ($CIMArraySource.count -ne $CIMArrayTarget.count) + { + Write-Verbose -Message "Configuration drift:Number of items does not match: Source=$($CIMArraySource.count) Target=$($CIMArrayTarget.count)" + $testResult = $false + break + } + $i = 0 + foreach ($item in $CIMArraySource ) + { + $testResult = Compare-M365DSCComplexObject ` + -Source (Get-M365DSCDRGComplexTypeToHashtable -ComplexObject $CIMArraySource[$i]) ` + -Target ($CIMArrayTarget[$i]) + + $i++ + if (-Not $testResult) + { + $testResult = $false + break + } + } + if (-Not $testResult) + { + $testResult = $false + break + } + + $ValuesToCheck.Remove($key) | Out-Null + } + } + $ValuesToCheck.Remove('Id') | Out-Null + + Write-Verbose -Message "Current Values: $(Convert-M365DscHashtableToString -Hashtable $CurrentValues)" + Write-Verbose -Message "Target Values: $(Convert-M365DscHashtableToString -Hashtable $ValuesToCheck)" + + #Convert any DateTime to String + foreach ($key in $ValuesToCheck.Keys) + { + if (($null -ne $CurrentValues[$key]) ` + -and ($CurrentValues[$key].getType().Name -eq 'DateTime')) + { + $CurrentValues[$key] = $CurrentValues[$key].toString() + } + } + + if ($testResult) + { + $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.String] + $Filter, + + [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, + + [Parameter()] + [System.String[]] + $AccessTokens + ) + + $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-MgBetaDeviceManagementDeviceConfiguration -Filter $Filter -All ` + -ErrorAction Stop | Where-Object ` + -FilterScript { ` + $_.AdditionalProperties.'@odata.type' -eq '#microsoft.graph.iosMobileAppConfiguration' ` + } + #endregion + + $i = 1 + $dscContent = '' + if ($getValue.Length -eq 0) + { + Write-Host $Global:M365DSCEmojiGreenCheckMark + } + else + { + Write-Host "`r`n" -NoNewline + } + foreach ($config in $getValue) + { + if ($null -ne $Global:M365DSCExportResourceInstancesCount) + { + $Global:M365DSCExportResourceInstancesCount++ + } + + Write-Host " |---[$i/$($getValue.Count)] $($config.DisplayName)" -NoNewline + $params = @{ + Id = $config.id + DisplayName = $config.DisplayName + Ensure = 'Present' + Credential = $Credential + ApplicationId = $ApplicationId + TenantId = $TenantId + ApplicationSecret = $ApplicationSecret + CertificateThumbprint = $CertificateThumbprint + Managedidentity = $ManagedIdentity.IsPresent + AccessTokens = $AccessTokens + } + + $Results = Get-TargetResource @Params + $Results = Update-M365DSCExportAuthenticationResults -ConnectionMode $ConnectionMode ` + -Results $Results + + if ($Results.Assignments) + { + $complexTypeStringResult = Get-M365DSCDRGComplexTypeToString -ComplexObject $Results.Assignments -CIMInstanceName DeviceManagementConfigurationPolicyAssignments + if ($complexTypeStringResult) + { + $Results.Assignments = $complexTypeStringResult + } + else + { + $Results.Remove('Assignments') | Out-Null + } + } + + + + + + + + + + + + $currentDSCBlock = Get-M365DSCExportContentForResource -ResourceName $ResourceName ` + -ConnectionMode $ConnectionMode ` + -ModulePath $PSScriptRoot ` + -Results $Results ` + -Credential $Credential + + + + + if ($Results.Assignments) + { + $isCIMArray = $false + if ($Results.Assignments.getType().Fullname -like '*[[\]]') + { + $isCIMArray = $true + } + $currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock -ParameterName 'Assignments' -IsCIMArray:$isCIMArray + } + + $dscContent += $currentDSCBlock + Save-M365DSCPartialExport -Content $currentDSCBlock ` + -FileName $Global:PartialExportFileName + $i++ + Write-Host $Global:M365DSCEmojiGreenCheckMark + } + return $dscContent + } + catch + { + if ($_.Exception -like '*401*' -or $_.ErrorDetails.Message -like "*`"ErrorCode`":`"Forbidden`"*" -or ` + $_.Exception -like "*Request not applicable to target tenant*") + { + Write-Host "`r`n $($Global:M365DSCEmojiYellowCircle) The current tenant is not registered for Intune." + } + else + { + Write-Host $Global:M365DSCEmojiRedX + + New-M365DSCLogEntry -Message 'Error during Export:' ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + } + + return '' + } +} + + + +function Get-M365DSCAdditionalProperties +{ + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + param + ( + [Parameter(Mandatory = 'true')] + [System.Collections.Hashtable] + $Properties + ) + + $additionalProperties = @( + 'encodedSettingXml' + 'settings' + ) + + $results = @{'@odata.type' = '#microsoft.graph.iosMobileAppConfiguration' } + $cloneProperties = $Properties.clone() + foreach ($property in $cloneProperties.Keys) + { + if ($property -in ($additionalProperties) ) + { + $propertyName = $property[0].ToString().ToLower() + $property.Substring(1, $property.Length - 1) + if ($properties.$property -and $properties.$property.getType().FullName -like '*CIMInstance*') + { + if ($properties.$property.getType().FullName -like '*[[\]]') + { + $array = @() + foreach ($item in $properties.$property) + { + $array += Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject $item + } + $propertyValue = $array + } + else + { + $propertyValue = Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject $properties.$property + } + + } + else + { + $propertyValue = $properties.$property + } + + $results.Add($propertyName, $propertyValue) + } + } + if ($results.Count -eq 1) + { + return $null + } + return $results +} + +Export-ModuleMember -Function *-TargetResource diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/MSFT_IntuneMobileAppConfigurationPolicyIOS.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/MSFT_IntuneMobileAppConfigurationPolicyIOS.schema.mof new file mode 100644 index 0000000000000000000000000000000000000000..1d1beae36f3a81365f7acf7e64c3939bea299147 GIT binary patch literal 8196 zcmeHMTW=ai6h6o*rlJA?t zFf+?6u)DaGstB#YdpUEi-}&b3*Dq&sAOq=0hR-|c$pqhh8Oczd$gcb-`|@mY?8=^; z%Oly5tHm=$T5>AK(v}N3#Pc8V^cB8akU7M0gWtC}hBC!UlzWXkZe)g)Iyk3mo#4vA zK6xh%s|)WLE}qQns`vJ<5&fLWpODdqjGjEjIj){zZJrx1B-4tve84q>b9cDHUn6M2 z|K0fxo}#8xoK;`M>+eI#o?Yb~t`DHSS~!+_T=@Zd(&`E1W>)qTKD)vH9jy0Z{(FR{ z#!2hixX-P>i&Zv}NG%5P+OA9QX3(fBZ|yf@nDS!vb;8JQPj*lKwwW}8zM2QWSs!lG zPgjUXI_JU+o!H!@M|;r7W#xJwe$M4Y_B|iqLDqVeT>C%d!#NP-6!sH^hQI)WswB>J z;1NZi7h6U#;^_b@5WCAGo59ojcy=Gp9xdvzi!+o(iA~r+yr01my^mA6_iuB0ooikwtLeV=Q+m42X&tU6{lGcs*+ z%mRx0{;~)Bird!z&}uwJU3GvLMt;XPbLro-Db~ShP&Z2K#Q6@p{dhfzSZ2$zuszG( zmZO-`$j9^ZJTJ>L z4{*|TyZ3t14fvkHIxT2yS)!5uMij#B}8rs^(UJA2%-L!Aw<)lU(MqUrJ7 zBdVerz0ZAadWI19M1vT(zFb$MSaRKN+W`OJG-3#A#_;;cPGrci$&2{CY+s%?(hF{m zV^-uC(U}q86va(qxXQI%_ZGiyEr#k8sGFM)jj(&*&ZReJ&&9c%?oR1gRb?sh>?`jP z`ptW!xTCK3NGPe;VxPUUdH4EReu6(gT2H%aiQ3AV^0~a}Ow2K2WxXR*XCJX*PhtcW zm)BeKkn!c7*-gc$RSUTsXG|t%m`7HP_$K^_80HxnnS^q(Y|fd88Ar(SOY1krwreYb zeU|Kjm`CLHGt%Xbw+RPy6%h7s@|{q-dfsTEI$Mj#uV#%7-Ji=Zc!Dt@8ctR)NpdDu zje02Nx$oh>!90r9a`^;n6W4U|#K{8Zq4X=y`rTjHA9Vh}-Qg4m!y6I5v)|i)HZpJd@9a}qrmd2b-|v^&fz^8`Y^RiriVv?pVxKe@>O#P zZ5;llrYyxs8uFk9yhZGc-z>P=I)xQ}YL~vZ4&EGCpRxkD8zI^bpiREh#J=<0oLZLm zTWU>bZ=5-)JF8|;im5f^pLs?LcN7 z>xk5RucdFsVy0UzqV=uZZuW1I7oqi4YoU#7oLPoIOl7BJl5_bE!58rFECf(kJ pRpgMH)2XWZ6Z;qkb|S?yohVh;JD4ckDd; Date: Tue, 12 Nov 2024 17:19:21 +0000 Subject: [PATCH 03/65] Update MSFT_IntuneMobileAppConfigurationPolicyIOS.psm1 --- .../MSFT_IntuneMobileAppConfigurationPolicyIOS.psm1 | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/MSFT_IntuneMobileAppConfigurationPolicyIOS.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/MSFT_IntuneMobileAppConfigurationPolicyIOS.psm1 index 039b5b9077..e978d3d975 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/MSFT_IntuneMobileAppConfigurationPolicyIOS.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/MSFT_IntuneMobileAppConfigurationPolicyIOS.psm1 @@ -95,8 +95,7 @@ function Get-TargetResource $nullResult.Ensure = 'Absent' try { - #$getValue = Get-MgBetaDeviceManagementDeviceConfiguration -DeviceConfigurationId $id -ErrorAction SilentlyContinue - if (-not [string]::IsNullOrWhiteSpace($id)){ $getValue = Get-MgBetaDeviceAppManagementMobileAppConfiguration -DeviceConfigurationId $id -ErrorAction SilentlyContinue } + if (-not [string]::IsNullOrWhiteSpace($id)){ $getValue = Get-MgBetaDeviceAppManagementMobileAppConfiguration -ManagedDeviceMobileAppConfigurationId $id -ErrorAction SilentlyContinue } #region resource generator code if ($null -eq $getValue) @@ -325,7 +324,7 @@ function Set-TargetResource $CreateParameters.add('AdditionalProperties', $AdditionalProperties) #region resource generator code - $policy = New-MgBetaDeviceManagementDeviceConfiguration @CreateParameters + $policy = New-MgBetaDeviceAppManagementMobileAppConfiguration @CreateParameters $assignmentsHash = ConvertTo-IntunePolicyAssignment -IncludeDeviceFilter:$true -Assignments $Assignments if ($policy.id) @@ -368,8 +367,8 @@ function Set-TargetResource #region resource generator code - Update-MgBetaDeviceManagementDeviceConfiguration @UpdateParameters ` - -DeviceConfigurationId $currentInstance.Id + Update-MgBetaDeviceAppManagementMobileAppConfiguration @UpdateParameters ` + -ManagedDeviceMobileAppConfigurationId $currentInstance.Id $assignmentsHash = ConvertTo-IntunePolicyAssignment -IncludeDeviceFilter:$true -Assignments $Assignments Update-DeviceConfigurationPolicyAssignment -DeviceConfigurationPolicyId $currentInstance.id ` -Targets $assignmentsHash ` @@ -380,7 +379,7 @@ function Set-TargetResource { Write-Verbose -Message "Removing {$DisplayName}" #region resource generator code - Remove-MgBetaDeviceManagementDeviceConfiguration -DeviceConfigurationId $currentInstance.Id + Remove-MgBetaDeviceAppManagementMobileAppConfiguration -ManagedDeviceMobileAppConfigurationId $currentInstance.Id #endregion } } @@ -601,7 +600,7 @@ function Export-TargetResource { #region resource generator code - [array]$getValue = Get-MgBetaDeviceManagementDeviceConfiguration -Filter $Filter -All ` + [array]$getValue = Get-MgBetaDeviceAppManagementMobileAppConfiguration -Filter $Filter -All ` -ErrorAction Stop | Where-Object ` -FilterScript { ` $_.AdditionalProperties.'@odata.type' -eq '#microsoft.graph.iosMobileAppConfiguration' ` From 003d3a024bef882f62e1c2b595dcf7b1cf9b6d7f Mon Sep 17 00:00:00 2001 From: dannyKBjj Date: Tue, 12 Nov 2024 17:27:31 +0000 Subject: [PATCH 04/65] Updated .md and .json --- .../readme.md | 4 ++-- .../settings.json | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/readme.md b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/readme.md index a82c357af2..d18bcd36ae 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/readme.md +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/readme.md @@ -1,6 +1,6 @@ -# IntuneVPNConfigurationPolicyIOS +# IntuneMobileAppConfigurationPolicyIOS ## Description -This resource configures an Intune VPN Configuration Policy for iOS Device. +This resource configures an Intune Managed Device Mobile App Configuration Policy for iOS Device. diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/settings.json b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/settings.json index 994cfaa911..ebd0a5e8d5 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/settings.json +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/settings.json @@ -1,29 +1,29 @@ { - "resourceName": "IntuneVPNConfigurationPolicyIOS", - "description": "This resource configures an Intune VPN Configuration Policy for iOS Device.", + "resourceName": "IntuneMobileAppConfigurationPolicyIOS", + "description": "This resource configures an Intune Managed Device Mobile App Configuration Policy for iOS Device.", "permissions": { "graph": { "delegated": { "read": [ { - "name": "DeviceManagementConfiguration.Read.All" + "name": "DeviceManagementApps.Read.All" } ], "update": [ { - "name": "DeviceManagementConfiguration.ReadWrite.All" + "name": "DeviceManagementApps.ReadWrite.All" } ] }, "application": { "read": [ { - "name": "DeviceManagementConfiguration.Read.All" + "name": "DeviceManagementApps.Read.All" } ], "update": [ { - "name": "DeviceManagementConfiguration.ReadWrite.All" + "name": "DeviceManagementApps.ReadWrite.All" } ] } From cbb52db5db9e8d523fa78afcdab5a0adcece7c78 Mon Sep 17 00:00:00 2001 From: dannyKBjj Date: Tue, 12 Nov 2024 17:48:04 +0000 Subject: [PATCH 05/65] Update MSFT_IntuneMobileAppConfigurationPolicyIOS.psm1 --- .../MSFT_IntuneMobileAppConfigurationPolicyIOS.psm1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/MSFT_IntuneMobileAppConfigurationPolicyIOS.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/MSFT_IntuneMobileAppConfigurationPolicyIOS.psm1 index e978d3d975..4885274866 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/MSFT_IntuneMobileAppConfigurationPolicyIOS.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/MSFT_IntuneMobileAppConfigurationPolicyIOS.psm1 @@ -115,7 +115,7 @@ function Get-TargetResource Write-Verbose -Message "Found something with id {$id}" -<# + $complexSettings = @() foreach ($setting in $getValue.AdditionalProperties.settings) { @@ -128,7 +128,7 @@ function Get-TargetResource } } -#> + @@ -144,7 +144,7 @@ function Get-TargetResource DisplayName = $getValue.DisplayName targetedMobileApps = $getValue.TargetedMobileApps - settings = $getValue.AdditionalProperties.settings + settings = $complexSettings #$getValue.AdditionalProperties.settings encodedSettingXml = $getValue.AdditionalProperties.encodedSettingXml Ensure = 'Present' From 152d3335cdadf565616465f96342bbc931811d2e Mon Sep 17 00:00:00 2001 From: dannyKBjj Date: Wed, 13 Nov 2024 11:14:26 +0000 Subject: [PATCH 06/65] Export Done Export appears to be working for "settings" --- ...IntuneMobileAppConfigurationPolicyIOS.psm1 | 40 ++++++++++++++----- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/MSFT_IntuneMobileAppConfigurationPolicyIOS.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/MSFT_IntuneMobileAppConfigurationPolicyIOS.psm1 index 4885274866..06616b468c 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/MSFT_IntuneMobileAppConfigurationPolicyIOS.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/MSFT_IntuneMobileAppConfigurationPolicyIOS.psm1 @@ -115,25 +115,21 @@ function Get-TargetResource Write-Verbose -Message "Found something with id {$id}" - + #need to convert dictionary object into a hashtable array so we can work with it $complexSettings = @() foreach ($setting in $getValue.AdditionalProperties.settings) { $mySettings = @{} - $mySettings.Add($setting.keys, $setting.values) - + $mySettings.Add('appConfigKey', $setting['appConfigKey']) + $mySettings.Add('appConfigKeyType', $setting['appConfigKeyType']) + $mySettings.Add('appConfigKeyValue', $setting['appConfigKeyValue']) + if ($mySettings.values.Where({$null -ne $_}).count -gt 0) { $complexSettings += $mySettings } } - - - - - - @@ -657,6 +653,20 @@ function Export-TargetResource + if ($null -ne $Results.settings) + { + $complexTypeStringResult = Get-M365DSCDRGComplexTypeToString ` + -ComplexObject $Results.settings ` + -CIMInstanceName 'MSFT_appConfigurationSettingItem' + if (-Not [String]::IsNullOrWhiteSpace($complexTypeStringResult)) + { + $Results.settings = $complexTypeStringResult + } + else + { + $Results.Remove('settings') | Out-Null + } + } @@ -684,6 +694,18 @@ function Export-TargetResource $currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock -ParameterName 'Assignments' -IsCIMArray:$isCIMArray } + + if ($Results.settings) + { + $isCIMArray = $false + if ($Results.settings.getType().Fullname -like '*[[\]]') + { + $isCIMArray = $true + } + $currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock -ParameterName 'settings' -IsCIMArray:$isCIMArray + } + + $dscContent += $currentDSCBlock Save-M365DSCPartialExport -Content $currentDSCBlock ` -FileName $Global:PartialExportFileName From 3f43bad769a10f43c08e077c68f790e80f3b00c0 Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Wed, 13 Nov 2024 07:32:34 -0500 Subject: [PATCH 07/65] Update MSFT_AzureBillingAccountPolicy.psm1 --- .../MSFT_AzureBillingAccountPolicy.psm1 | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AzureBillingAccountPolicy/MSFT_AzureBillingAccountPolicy.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AzureBillingAccountPolicy/MSFT_AzureBillingAccountPolicy.psm1 index 2066157785..8b9275b11f 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AzureBillingAccountPolicy/MSFT_AzureBillingAccountPolicy.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AzureBillingAccountPolicy/MSFT_AzureBillingAccountPolicy.psm1 @@ -216,6 +216,10 @@ function Set-TargetResource Write-Verbose -Message "Updating billing account policy for {$BillingAccount} with payload:`r`n$($payload)" $uri = "https://management.azure.com/providers/Microsoft.Billing/billingAccounts/$($BillingAccount)/policies/default?api-version=2024-04-01" $response = Invoke-AzRest -Uri $uri -Method "PUT" -Payload $payload + if (-not [System.String]::IsNullOrEmpty($response.Error)) + { + throw "Error: $($response.Error)" + } Write-Verbose -Message "Response:`r`n$($response.Content)" } @@ -422,7 +426,6 @@ function Export-TargetResource $Results = Update-M365DSCExportAuthenticationResults -ConnectionMode $ConnectionMode ` -Results $Results - if ($Results.EnterpriseAgreementPolicies) { $complexTypeStringResult = Get-M365DSCDRGComplexTypeToString -ComplexObject $Results.EnterpriseAgreementPolicies -CIMInstanceName AzureBillingAccountPolicyEnterpriseAgreementPolicy From 2abf667ab20df888de3a3fb90af16daaae9b7d37 Mon Sep 17 00:00:00 2001 From: dannyKBjj Date: Wed, 13 Nov 2024 17:11:31 +0000 Subject: [PATCH 08/65] Tested OK Module is affected by issue #5396. Replace ` with " in M365TenantConfig.ps1 is your configuration key values contain double quotes. Otherwise, it should work as expected. --- ...IntuneMobileAppConfigurationPolicyIOS.psm1 | 14 ++++++++++++-- ...MobileAppConfigurationPolicyIOS.schema.mof | Bin 8196 -> 7984 bytes 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/MSFT_IntuneMobileAppConfigurationPolicyIOS.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/MSFT_IntuneMobileAppConfigurationPolicyIOS.psm1 index 06616b468c..7349c643b8 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/MSFT_IntuneMobileAppConfigurationPolicyIOS.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/MSFT_IntuneMobileAppConfigurationPolicyIOS.psm1 @@ -25,6 +25,9 @@ function Get-TargetResource [Microsoft.Management.Infrastructure.CimInstance[]] $settings, + [Parameter()] + [System.String] + $encodedSettingXml, #====================== #standard params @@ -207,6 +210,9 @@ function Set-TargetResource [Microsoft.Management.Infrastructure.CimInstance[]] $settings, + [Parameter()] + [System.String] + $encodedSettingXml, #====================== #standard params @@ -282,7 +288,7 @@ function Set-TargetResource $PSBoundParameters.Remove('ManagedIdentity') | Out-Null $PSBoundParameters.Remove('AccessTokens') | Out-Null - + if ($Ensure -eq 'Present' -and $currentInstance.Ensure -eq 'Absent') @@ -359,7 +365,7 @@ function Set-TargetResource $UpdateParameters[$key] = Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject $UpdateParameters[$key] } } - + $UpdateParameters.add('AdditionalProperties', $AdditionalProperties) #region resource generator code @@ -407,6 +413,9 @@ function Test-TargetResource [Microsoft.Management.Infrastructure.CimInstance[]] $settings, + [Parameter()] + [System.String] + $encodedSettingXml, #====================== #standard params @@ -712,6 +721,7 @@ function Export-TargetResource $i++ Write-Host $Global:M365DSCEmojiGreenCheckMark } + return $dscContent } catch diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/MSFT_IntuneMobileAppConfigurationPolicyIOS.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/MSFT_IntuneMobileAppConfigurationPolicyIOS.schema.mof index 1d1beae36f3a81365f7acf7e64c3939bea299147..d09774961eca88ea67455f618794f1c369cb29e0 100644 GIT binary patch delta 33 jcmZp1*kHF|7yslcA)U#$`0b#y&}J`zKBmn_gdKPQppj-6Ln=cNLoq`p zLq0rdl)bGH^})C~Ur2O_+-Z0P`d!C;$Ke From 102604e86df9adf576a2e06488d7950ed9ae86ba Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Wed, 13 Nov 2024 15:58:28 -0500 Subject: [PATCH 09/65] AADRoleEligibilityScheduleRequest - Fix Custom Role assignment at app scope. --- .../MSFT_AADRoleEligibilityScheduleRequest.psm1 | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleEligibilityScheduleRequest/MSFT_AADRoleEligibilityScheduleRequest.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleEligibilityScheduleRequest/MSFT_AADRoleEligibilityScheduleRequest.psm1 index c6b343d7b6..51c06e3cf2 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleEligibilityScheduleRequest/MSFT_AADRoleEligibilityScheduleRequest.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleEligibilityScheduleRequest/MSFT_AADRoleEligibilityScheduleRequest.psm1 @@ -240,7 +240,20 @@ return $nullResult } $RoleDefinitionId = (Get-MgBetaRoleManagementDirectoryRoleDefinition -Filter "DisplayName eq '$RoleDefinition'").Id - $schedule = Get-MgBetaRoleManagementDirectoryRoleEligibilitySchedule -Filter "PrincipalId eq '$($request.PrincipalId)' and RoleDefinitionId eq '$RoleDefinitionId'" + $schedules = Get-MgBetaRoleManagementDirectoryRoleEligibilitySchedule -Filter "PrincipalId eq '$($request.PrincipalId)'" + $schedule = $schedules | Where-Object -FilterScript {$_.RoleDefinitionId -eq $RoleDefinitionId} + if ($null -eq $schedule) + { + foreach ($instance in $schedules) + { + $roleDefinitionInfo = Get-MgBetaRoleManagementDirectoryRoleDefinition -UnifiedRoleDefinitionId $instance.RoleDefinitionId + if ($null -ne $roleDefinitionInfo -and $RoleDefinitionInfo.DisplayName -eq $RoleDefinition) + { + $schedule = $instance + break + } + } + } } if ($null -eq $schedule -or $null -eq $request) { From 16e2fcef83781f945be7ce51ec81e44196c46ead Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Wed, 13 Nov 2024 16:00:20 -0500 Subject: [PATCH 10/65] Update CHANGELOG.md --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5576768136..b2602b09c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ # UNRELEASED +* AADRoleEligibilityScheduleRequest + * Adds support for custom role assignments at app scope. + +# 1.24.1113.1 + * AADConditionalAccessPolicy * Fixed bug where an empty value was passed in the request for the insiderRiskLevels parameter, which throws an error. From c6653c92de418c8db7415dbac6c7243eb0f0b40a Mon Sep 17 00:00:00 2001 From: Alfred Schreuder Date: Thu, 14 Nov 2024 09:01:28 +0100 Subject: [PATCH 11/65] Prevent null objects, allow IncludePlatforms without Exclusions --- .../MSFT_AADConditionalAccessPolicy.psm1 | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 index efa3b783bb..af09ab623d 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 @@ -1485,13 +1485,11 @@ function Set-TargetResource if (-not $conditions.Contains('platforms')) { $conditions.Add('platforms', @{ - excludePlatforms = @() includePlatforms = @() }) } else { - $conditions.platforms.Add('excludePlatforms', @()) $conditions.platforms.Add('includePlatforms', @()) } Write-Verbose -Message "Set-Targetresource: IncludePlatforms: $IncludePlatforms" @@ -1504,8 +1502,11 @@ function Set-TargetResource $conditions.platforms.includePlatforms = @() + $IncludePlatforms } #no translation or conversion needed - Write-Verbose -Message "Set-Targetresource: ExcludePlatforms: $ExcludePlatforms" - $conditions.platforms.excludePlatforms = @() + $ExcludePlatforms + if (([Array]$ExcludePlatforms).Length -ne 0) + { + $conditions.platforms.Add('excludePlatforms', @()) + $conditions.platforms.excludePlatforms = @() + $ExcludePlatforms + } #no translation or conversion needed } else @@ -1729,18 +1730,16 @@ function Set-TargetResource $NewParameters.Add('grantControls', $GrantControls) } - Write-Verbose -Message 'Set-Targetresource: process session controls' - - $sessioncontrols = $null if ($ApplicationEnforcedRestrictionsIsEnabled -or $CloudAppSecurityIsEnabled -or $SignInFrequencyIsEnabled -or $PersistentBrowserIsEnabled) { + Write-Verbose -Message 'Set-Targetresource: process session controls' + $sessioncontrols = $null Write-Verbose -Message 'Set-Targetresource: create provision Session Control object' - $sessioncontrols = @{ - applicationEnforcedRestrictions = @{} - } + $sessioncontrols = @{} if ($ApplicationEnforcedRestrictionsIsEnabled -eq $true) { + $sessioncontrols.Add('applicationEnforcedRestrictions', @{}) #create and provision ApplicationEnforcedRestrictions object if used $sessioncontrols.applicationEnforcedRestrictions.Add('IsEnabled', $true) } @@ -1798,9 +1797,9 @@ function Set-TargetResource $sessioncontrols.persistentBrowser.isEnabled = $true $sessioncontrols.persistentBrowser.mode = $PersistentBrowserMode } + $NewParameters.Add('sessionControls', $sessioncontrols) + #add SessionControls to the parameter list } - $NewParameters.Add('sessionControls', $sessioncontrols) - #add SessionControls to the parameter list } Write-Host "newparameters: $($NewParameters | ConvertTo-Json -Depth 5)" From 60797e049a480fbed94193c3230bab33594dbbbd Mon Sep 17 00:00:00 2001 From: Fabien Tschanz Date: Thu, 14 Nov 2024 12:29:49 +0100 Subject: [PATCH 12/65] Add Intune Firewall rules Hyper-V policy for Windows10 --- CHANGELOG.md | 4 + ...uneFirewallRulesHyperVPolicyWindows10.psm1 | 640 ++++++++++++++++++ ...ewallRulesHyperVPolicyWindows10.schema.mof | 46 ++ .../readme.md | 6 + .../settings.json | 44 ++ .../1-Create.ps1 | 53 ++ .../2-Update.ps1 | 53 ++ .../3-Remove.ps1 | 34 + .../Modules/M365DSCDRGUtil.psm1 | 12 +- ...rewallRulesHyperVPolicyWindows10.Tests.ps1 | 493 ++++++++++++++ ...tuneFirewallRulesPolicyWindows10.Tests.ps1 | 8 +- 11 files changed, 1384 insertions(+), 9 deletions(-) create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_IntuneFirewallRulesHyperVPolicyWindows10/MSFT_IntuneFirewallRulesHyperVPolicyWindows10.psm1 create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_IntuneFirewallRulesHyperVPolicyWindows10/MSFT_IntuneFirewallRulesHyperVPolicyWindows10.schema.mof create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_IntuneFirewallRulesHyperVPolicyWindows10/readme.md create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_IntuneFirewallRulesHyperVPolicyWindows10/settings.json create mode 100644 Modules/Microsoft365DSC/Examples/Resources/IntuneFirewallRulesHyperVPolicyWindows10/1-Create.ps1 create mode 100644 Modules/Microsoft365DSC/Examples/Resources/IntuneFirewallRulesHyperVPolicyWindows10/2-Update.ps1 create mode 100644 Modules/Microsoft365DSC/Examples/Resources/IntuneFirewallRulesHyperVPolicyWindows10/3-Remove.ps1 create mode 100644 Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneFirewallRulesHyperVPolicyWindows10.Tests.ps1 diff --git a/CHANGELOG.md b/CHANGELOG.md index b2602b09c6..3380151965 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ * AADRoleEligibilityScheduleRequest * Adds support for custom role assignments at app scope. +* IntuneFirewallRulesHyperVPolicyWindows10 + * Initial release. +* M365DSCDRGUtil + * Improve CIM instance detection for specific Intune resources. # 1.24.1113.1 diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneFirewallRulesHyperVPolicyWindows10/MSFT_IntuneFirewallRulesHyperVPolicyWindows10.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneFirewallRulesHyperVPolicyWindows10/MSFT_IntuneFirewallRulesHyperVPolicyWindows10.psm1 new file mode 100644 index 0000000000..3388ab2c05 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneFirewallRulesHyperVPolicyWindows10/MSFT_IntuneFirewallRulesHyperVPolicyWindows10.psm1 @@ -0,0 +1,640 @@ +function Get-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + param + ( + #region resource generator code + [Parameter()] + [System.String] + $Description, + + [Parameter(Mandatory = $true)] + [System.String] + $DisplayName, + + [Parameter()] + [System.String[]] + $RoleScopeTagIds, + + [Parameter()] + [System.String] + $Id, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $FirewallRuleName, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $Assignments, + #endregion + + [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, + + [Parameter()] + [System.String[]] + $AccessTokens + ) + + 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 + #region resource generator code + $getValue = Get-MgBetaDeviceManagementConfigurationPolicy -DeviceManagementConfigurationPolicyId $Id -ErrorAction SilentlyContinue + + if ($null -eq $getValue) + { + Write-Verbose -Message "Could not find an Intune Firewall Rules Hyper-V Policy for Windows10 with Id {$Id}" + + if (-not [System.String]::IsNullOrEmpty($DisplayName)) + { + $getValue = Get-MgBetaDeviceManagementConfigurationPolicy ` + -Filter "Name eq '$DisplayName'" ` + -ErrorAction SilentlyContinue + } + } + #endregion + if ($null -eq $getValue) + { + Write-Verbose -Message "Could not find an Intune Firewall Rules Hyper-V Policy for Windows10 with Name {$DisplayName}." + return $nullResult + } + $Id = $getValue.Id + Write-Verbose -Message "An Intune Firewall Rules Hyper-V Policy for Windows10 with Id {$Id} and Name {$DisplayName} was found" + + # Retrieve policy specific settings + [array]$settings = Get-MgBetaDeviceManagementConfigurationPolicySetting ` + -DeviceManagementConfigurationPolicyId $Id ` + -ExpandProperty 'settingDefinitions' ` + -All ` + -ErrorAction Stop + + $policySettings = @{} + $policySettings = Export-IntuneSettingCatalogPolicySettings -Settings $settings -ReturnHashtable $policySettings + + #region resource generator code + $complexFirewallRuleName = @() + foreach ($currentFirewallRuleName in $policySettings.FirewallRuleName) + { + $myFirewallRuleName = @{} + foreach ($key in $currentFirewallRuleName.Keys) + { + $myFirewallRuleName.Add($key, $currentFirewallRuleName[$key]) + } + if ($myFirewallRuleName.values.Where({$null -ne $_}).Count -gt 0) + { + $complexFirewallRuleName += $myFirewallRuleName + } + } + $policySettings.Remove('FirewallRuleName') | Out-Null + #endregion + + $results = @{ + #region resource generator code + Description = $getValue.Description + DisplayName = $getValue.Name + RoleScopeTagIds = $getValue.RoleScopeTagIds + Id = $getValue.Id + FirewallRuleName = $complexFirewallRuleName + Ensure = 'Present' + Credential = $Credential + ApplicationId = $ApplicationId + TenantId = $TenantId + ApplicationSecret = $ApplicationSecret + CertificateThumbprint = $CertificateThumbprint + ManagedIdentity = $ManagedIdentity.IsPresent + #endregion + } + $results += $policySettings + + $assignmentsValues = Get-MgBetaDeviceManagementConfigurationPolicyAssignment -DeviceManagementConfigurationPolicyId $Id + $assignmentResult = @() + if ($assignmentsValues.Count -gt 0) + { + $assignmentResult += ConvertFrom-IntunePolicyAssignment -Assignments $assignmentsValues -IncludeDeviceFilter $true + } + $results.Add('Assignments', $assignmentResult) + + 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()] + [System.String] + $Description, + + [Parameter(Mandatory = $true)] + [System.String] + $DisplayName, + + [Parameter()] + [System.String[]] + $RoleScopeTagIds, + + [Parameter()] + [System.String] + $Id, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $FirewallRuleName, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $Assignments, + #endregion + [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, + + [Parameter()] + [System.String[]] + $AccessTokens + ) + + #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 + + $templateReferenceId = 'a5481c22-7a2a-4f59-a33e-6eee30d02f94_1' + $platforms = 'windows10' + $technologies = 'mdm,microsoftSense' + + if ($Ensure -eq 'Present' -and $currentInstance.Ensure -eq 'Absent') + { + Write-Verbose -Message "Creating an Intune Firewall Rules Hyper-V Policy for Windows10 with Name {$DisplayName}" + $BoundParameters.Remove("Assignments") | Out-Null + + $settings = Get-IntuneSettingCatalogPolicySetting ` + -DSCParams ([System.Collections.Hashtable]$BoundParameters) ` + -TemplateId $templateReferenceId + + $createParameters = @{ + Name = $DisplayName + Description = $Description + TemplateReference = @{ templateId = $templateReferenceId } + Platforms = $platforms + Technologies = $technologies + Settings = $settings + } + + #region resource generator code + $policy = New-MgBetaDeviceManagementConfigurationPolicy -BodyParameter $createParameters + + if ($policy.Id) + { + $assignmentsHash = ConvertTo-IntunePolicyAssignment -IncludeDeviceFilter:$true -Assignments $Assignments + Update-DeviceConfigurationPolicyAssignment ` + -DeviceConfigurationPolicyId $policy.Id ` + -Targets $assignmentsHash ` + -Repository 'deviceManagement/configurationPolicies' + } + #endregion + } + elseif ($Ensure -eq 'Present' -and $currentInstance.Ensure -eq 'Present') + { + Write-Verbose -Message "Updating the Intune Firewall Rules Hyper-V Policy for Windows10 with Id {$($currentInstance.Id)}" + $BoundParameters.Remove("Assignments") | Out-Null + + $settings = Get-IntuneSettingCatalogPolicySetting ` + -DSCParams ([System.Collections.Hashtable]$BoundParameters) ` + -TemplateId $templateReferenceId + + Update-IntuneDeviceConfigurationPolicy ` + -DeviceConfigurationPolicyId $currentInstance.Id ` + -Name $DisplayName ` + -Description $Description ` + -TemplateReferenceId $templateReferenceId ` + -Platforms $platforms ` + -Technologies $technologies ` + -Settings $settings + + #region resource generator code + $assignmentsHash = ConvertTo-IntunePolicyAssignment -IncludeDeviceFilter:$true -Assignments $Assignments + Update-DeviceConfigurationPolicyAssignment ` + -DeviceConfigurationPolicyId $currentInstance.Id ` + -Targets $assignmentsHash ` + -Repository 'deviceManagement/configurationPolicies' + #endregion + } + elseif ($Ensure -eq 'Absent' -and $currentInstance.Ensure -eq 'Present') + { + Write-Verbose -Message "Removing the Intune Firewall Rules Hyper-V Policy for Windows10 with Id {$($currentInstance.Id)}" + #region resource generator code + Remove-MgBetaDeviceManagementConfigurationPolicy -DeviceManagementConfigurationPolicyId $currentInstance.Id + #endregion + } +} + +function Test-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Boolean])] + param + ( + #region resource generator code + [Parameter()] + [System.String] + $Description, + + [Parameter(Mandatory = $true)] + [System.String] + $DisplayName, + + [Parameter()] + [System.String[]] + $RoleScopeTagIds, + + [Parameter()] + [System.String] + $Id, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $FirewallRuleName, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $Assignments, + #endregion + + [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, + + [Parameter()] + [System.String[]] + $AccessTokens + ) + + #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 Intune Firewall Rules Hyper-V Policy for Windows10 with Id {$Id} and Name {$DisplayName}" + + $CurrentValues = Get-TargetResource @PSBoundParameters + [Hashtable]$ValuesToCheck = @{} + $MyInvocation.MyCommand.Parameters.GetEnumerator() | ForEach-Object { + if ($_.Key -notlike '*Variable' -or $_.Key -notin @('Verbose', 'Debug', 'ErrorAction', 'WarningAction', 'InformationAction')) + { + if ($null -ne $CurrentValues[$_.Key] -or $null -ne $PSBoundParameters[$_.Key]) + { + $ValuesToCheck.Add($_.Key, $null) + if (-not $PSBoundParameters.ContainsKey($_.Key)) + { + $PSBoundParameters.Add($_.Key, $null) + } + } + } + } + + if ($CurrentValues.Ensure -ne $Ensure) + { + Write-Verbose -Message "Test-TargetResource returned $false" + return $false + } + $testResult = $true + + #Compare Cim instances + foreach ($key in $PSBoundParameters.Keys) + { + $source = $PSBoundParameters.$key + $target = $CurrentValues.$key + if ($null -ne $source -and $source.GetType().Name -like '*CimInstance*') + { + $testResult = Compare-M365DSCComplexObject ` + -Source ($source) ` + -Target ($target) + + if (-not $testResult) + { + break + } + + $ValuesToCheck.Remove($key) | Out-Null + } + } + + $ValuesToCheck.Remove('Id') | Out-Null + $ValuesToCheck = Remove-M365DSCAuthenticationParameter -BoundParameters $ValuesToCheck + + Write-Verbose -Message "Current Values: $(Convert-M365DscHashtableToString -Hashtable $CurrentValues)" + Write-Verbose -Message "Target Values: $(Convert-M365DscHashtableToString -Hashtable $PSBoundParameters)" + + if ($testResult) + { + $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.String] + $Filter, + + [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, + + [Parameter()] + [System.String[]] + $AccessTokens + ) + + $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 + $policyTemplateID = "a5481c22-7a2a-4f59-a33e-6eee30d02f94_1" + [array]$getValue = Get-MgBetaDeviceManagementConfigurationPolicy ` + -Filter $Filter ` + -All ` + -ErrorAction Stop | Where-Object ` + -FilterScript { + $_.TemplateReference.TemplateId -eq $policyTemplateID + } + #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 + if (-not [String]::IsNullOrEmpty($config.displayName)) + { + $displayedKey = $config.displayName + } + elseif (-not [string]::IsNullOrEmpty($config.name)) + { + $displayedKey = $config.name + } + Write-Host " |---[$i/$($getValue.Count)] $displayedKey" -NoNewline + $params = @{ + Id = $config.Id + DisplayName = $config.Name + Ensure = 'Present' + Credential = $Credential + ApplicationId = $ApplicationId + TenantId = $TenantId + ApplicationSecret = $ApplicationSecret + CertificateThumbprint = $CertificateThumbprint + ManagedIdentity = $ManagedIdentity.IsPresent + AccessTokens = $AccessTokens + } + + $Results = Get-TargetResource @Params + $Results = Update-M365DSCExportAuthenticationResults -ConnectionMode $ConnectionMode ` + -Results $Results + if ($null -ne $Results.FirewallRuleName) + { + $complexTypeStringResult = Get-M365DSCDRGComplexTypeToString ` + -ComplexObject $Results.FirewallRuleName ` + -CIMInstanceName 'MicrosoftGraphIntuneSettingsCatalogFirewallRuleName_IntuneFirewallRulesHyperVPolicyWindows10' + if (-not [String]::IsNullOrWhiteSpace($complexTypeStringResult)) + { + $Results.FirewallRuleName = $complexTypeStringResult + } + else + { + $Results.Remove('FirewallRuleName') | Out-Null + } + } + + if ($Results.Assignments) + { + $complexTypeStringResult = Get-M365DSCDRGComplexTypeToString -ComplexObject $Results.Assignments -CIMInstanceName DeviceManagementConfigurationPolicyAssignments + if ($complexTypeStringResult) + { + $Results.Assignments = $complexTypeStringResult + } + else + { + $Results.Remove('Assignments') | Out-Null + } + } + + $currentDSCBlock = Get-M365DSCExportContentForResource -ResourceName $ResourceName ` + -ConnectionMode $ConnectionMode ` + -ModulePath $PSScriptRoot ` + -Results $Results ` + -Credential $Credential + if ($Results.FirewallRuleName) + { + $currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock -ParameterName "FirewallRuleName" -IsCIMArray:$True + } + + if ($Results.Assignments) + { + $currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock -ParameterName "Assignments" -IsCIMArray:$true + } + + $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_IntuneFirewallRulesHyperVPolicyWindows10/MSFT_IntuneFirewallRulesHyperVPolicyWindows10.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneFirewallRulesHyperVPolicyWindows10/MSFT_IntuneFirewallRulesHyperVPolicyWindows10.schema.mof new file mode 100644 index 0000000000..850499481b --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneFirewallRulesHyperVPolicyWindows10/MSFT_IntuneFirewallRulesHyperVPolicyWindows10.schema.mof @@ -0,0 +1,46 @@ +[ClassVersion("1.0.0.0")] +class MSFT_DeviceManagementConfigurationPolicyAssignments +{ + [Write, Description("The type of the target assignment."), ValueMap{"#microsoft.graph.groupAssignmentTarget","#microsoft.graph.allLicensedUsersAssignmentTarget","#microsoft.graph.allDevicesAssignmentTarget","#microsoft.graph.exclusionGroupAssignmentTarget","#microsoft.graph.configurationManagerCollectionAssignmentTarget"}, Values{"#microsoft.graph.groupAssignmentTarget","#microsoft.graph.allLicensedUsersAssignmentTarget","#microsoft.graph.allDevicesAssignmentTarget","#microsoft.graph.exclusionGroupAssignmentTarget","#microsoft.graph.configurationManagerCollectionAssignmentTarget"}] String dataType; + [Write, Description("The type of filter of the target assignment i.e. Exclude or Include. Possible values are:none, include, exclude."), ValueMap{"none","include","exclude"}, Values{"none","include","exclude"}] String deviceAndAppManagementAssignmentFilterType; + [Write, Description("The Id of the filter for the target assignment.")] String deviceAndAppManagementAssignmentFilterId; + [Write, Description("The group Id that is the target of the assignment.")] String groupId; + [Write, Description("The group Display Name that is the target of the assignment.")] String groupDisplayName; + [Write, Description("The collection Id that is the target of the assignment.(ConfigMgr)")] String collectionId; +}; + +[ClassVersion("1.0.0.0")] +class MSFT_MicrosoftGraphIntuneSettingsCatalogFirewallRuleName_IntuneFirewallRulesHyperVPolicyWindows10 +{ + [Write, Description("Enabled - Depends on FirewallRuleName (0: Disabled, 1: Enabled)"), ValueMap{"0", "1"}, Values{"0", "1"}] String Enabled; + [Write, Description("Name - Depends on FirewallRuleName")] String Name; + [Write, Description("Direction - Depends on FirewallRuleName (in: The rule applies to inbound traffic., out: The rule applies to outbound traffic.)"), ValueMap{"in", "out"}, Values{"in", "out"}] String Direction; + [Write, Description("Priority - Depends on FirewallRuleName")] SInt32 Priority; + [Write, Description("Profiles - Depends on FirewallRuleName (1: FW_PROFILE_TYPE_DOMAIN: This value represents the profile for networks that are connected to domains., 2: FW_PROFILE_TYPE_STANDARD: This value represents the standard profile for networks. These networks are classified as private by the administrators in the server host. The classification happens the first time the host connects to the network. Usually these networks are behind Network Address Translation (NAT) devices, routers, and other edge devices, and they are in a private location, such as a home or an office. AND FW_PROFILE_TYPE_PRIVATE: This value represents the profile for private networks, which is represented by the same value as that used for FW_PROFILE_TYPE_STANDARD., 4: FW_PROFILE_TYPE_PUBLIC: This value represents the profile for public networks. These networks are classified as public by the administrators in the server host. The classification happens the first time the host connects to the network. Usually these networks are those at airports, coffee shops, and other public places where the peers in the network or the network administrator are not trusted., 2147483647: FW_PROFILE_TYPE_ALL: This value represents all these network sets and any future network sets.)"), ValueMap{"1", "2", "4", "2147483647"}, Values{"1", "2", "4", "2147483647"}] SInt32 Profiles[]; + [Write, Description("Target - Depends on FirewallRuleName (wsl: WSL)"), ValueMap{"wsl"}, Values{"wsl"}] String VMCreatorId; + [Write, Description("Action - Depends on FirewallRuleName (0: Block, 1: Allow)"), ValueMap{"0", "1"}, Values{"0", "1"}] String Action; + [Write, Description("Local Address Ranges - Depends on FirewallRuleName")] String LocalAddressRanges[]; + [Write, Description("Remote Address Ranges - Depends on FirewallRuleName")] String RemoteAddressRanges[]; + [Write, Description("Remote Port Ranges - Depends on FirewallRuleName")] String RemotePortRanges[]; + [Write, Description("Protocol - Depends on FirewallRuleName")] SInt32 Protocol; + [Write, Description("Local Port Ranges - Depends on FirewallRuleName")] String LocalPortRanges[]; +}; + +[ClassVersion("1.0.0.0"), FriendlyName("IntuneFirewallRulesHyperVPolicyWindows10")] +class MSFT_IntuneFirewallRulesHyperVPolicyWindows10 : OMI_BaseResource +{ + [Write, Description("Policy description")] String Description; + [Key, Description("Policy name")] String DisplayName; + [Write, Description("List of Scope Tags for this Entity instance.")] String RoleScopeTagIds[]; + [Write, Description("The unique identifier for an entity. Read-only.")] String Id; + [Write, Description("Firewall Rules"), EmbeddedInstance("MSFT_MicrosoftGraphIntuneSettingsCatalogFirewallRuleName_IntuneFirewallRulesHyperVPolicyWindows10")] String FirewallRuleName[]; + [Write, Description("Represents the assignment to the Intune policy."), EmbeddedInstance("MSFT_DeviceManagementConfigurationPolicyAssignments")] String Assignments[]; + [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; + [Write, Description("Access token used for authentication.")] String AccessTokens[]; +}; diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneFirewallRulesHyperVPolicyWindows10/readme.md b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneFirewallRulesHyperVPolicyWindows10/readme.md new file mode 100644 index 0000000000..fd833924e4 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneFirewallRulesHyperVPolicyWindows10/readme.md @@ -0,0 +1,6 @@ + +# IntuneFirewallRulesHyperVPolicyWindows10 + +## Description + +Intune Firewall Rules Hyper-V Policy for Windows10 diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneFirewallRulesHyperVPolicyWindows10/settings.json b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneFirewallRulesHyperVPolicyWindows10/settings.json new file mode 100644 index 0000000000..f2f3cc8cdf --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneFirewallRulesHyperVPolicyWindows10/settings.json @@ -0,0 +1,44 @@ +{ + "resourceName":"IntuneFirewallRulesHyperVPolicyWindows10", + "description":"This resource configures an Intune Firewall Rules Hyper-V Policy for Windows10.", + "permissions":{ + "graph":{ + "delegated":{ + "read":[ + { + "name":"DeviceManagementConfiguration.Read.All" + }, + { + "name":"Group.Read.All" + } + ], + "update":[ + { + "name":"DeviceManagementConfiguration.ReadWrite.All" + }, + { + "name":"Group.Read.All" + } + ] + }, + "application":{ + "read":[ + { + "name":"DeviceManagementConfiguration.Read.All" + }, + { + "name":"Group.Read.All" + } + ], + "update":[ + { + "name":"DeviceManagementConfiguration.ReadWrite.All" + }, + { + "name":"Group.Read.All" + } + ] + } + } + } +} \ No newline at end of file diff --git a/Modules/Microsoft365DSC/Examples/Resources/IntuneFirewallRulesHyperVPolicyWindows10/1-Create.ps1 b/Modules/Microsoft365DSC/Examples/Resources/IntuneFirewallRulesHyperVPolicyWindows10/1-Create.ps1 new file mode 100644 index 0000000000..7fed44c711 --- /dev/null +++ b/Modules/Microsoft365DSC/Examples/Resources/IntuneFirewallRulesHyperVPolicyWindows10/1-Create.ps1 @@ -0,0 +1,53 @@ +<# +This example creates a new Intune Firewall Policy for Windows10. +#> + +Configuration Example +{ + param( + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint + ) + Import-DscResource -ModuleName Microsoft365DSC + + node localhost + { + IntuneFirewallRulesHyperVPolicyWindows10 'myIntuneFirewallRulesHyperVPolicyWindows10' + { + Assignments = @( + MSFT_DeviceManagementConfigurationPolicyAssignments{ + deviceAndAppManagementAssignmentFilterType = 'none' + dataType = '#microsoft.graph.groupAssignmentTarget' + groupId = '11111111-1111-1111-1111-111111111111' + } + ); + FirewallRuleName = @( + MSFT_MicrosoftGraphIntuneSettingsCatalogFirewallRuleName_IntuneFirewallRulesHyperVPolicyWindows10{ + Direction = 'out' + RemotePortRanges = @('0-100') + Name = 'Rule1' + Protocol = 80 + Enabled = '1' + Action = '1' + } + ) + Description = 'Description' + DisplayName = "Intune Firewall Rules Hyper-V Policy Windows10"; + Ensure = "Present"; + Id = '00000000-0000-0000-0000-000000000000' + RoleScopeTagIds = @("0"); + ApplicationId = $ApplicationId; + TenantId = $TenantId; + CertificateThumbprint = $CertificateThumbprint; + } + } +} diff --git a/Modules/Microsoft365DSC/Examples/Resources/IntuneFirewallRulesHyperVPolicyWindows10/2-Update.ps1 b/Modules/Microsoft365DSC/Examples/Resources/IntuneFirewallRulesHyperVPolicyWindows10/2-Update.ps1 new file mode 100644 index 0000000000..ed6b26c33e --- /dev/null +++ b/Modules/Microsoft365DSC/Examples/Resources/IntuneFirewallRulesHyperVPolicyWindows10/2-Update.ps1 @@ -0,0 +1,53 @@ +<# +This example updates a Intune Firewall Policy for Windows10. +#> + +Configuration Example +{ + param( + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint + ) + Import-DscResource -ModuleName Microsoft365DSC + + node localhost + { + IntuneFirewallRulesHyperVPolicyWindows10 'myIntuneFirewallRulesHyperVPolicyWindows10' + { + Assignments = @( + MSFT_DeviceManagementConfigurationPolicyAssignments{ + deviceAndAppManagementAssignmentFilterType = 'none' + dataType = '#microsoft.graph.groupAssignmentTarget' + groupId = '11111111-1111-1111-1111-111111111111' + } + ); + FirewallRuleName = @( + MSFT_MicrosoftGraphIntuneSettingsCatalogFirewallRuleName_IntuneFirewallRulesHyperVPolicyWindows10{ + Direction = 'in' # Updated property + RemotePortRanges = @('0-100') + Name = 'Rule1' + Protocol = 80 + Enabled = '1' + Action = '1' + } + ) + Description = 'Description' + DisplayName = "Intune Firewall Rules Hyper-V Policy Windows10"; + Ensure = "Present"; + Id = '00000000-0000-0000-0000-000000000000' + RoleScopeTagIds = @("0"); + ApplicationId = $ApplicationId; + TenantId = $TenantId; + CertificateThumbprint = $CertificateThumbprint; + } + } +} diff --git a/Modules/Microsoft365DSC/Examples/Resources/IntuneFirewallRulesHyperVPolicyWindows10/3-Remove.ps1 b/Modules/Microsoft365DSC/Examples/Resources/IntuneFirewallRulesHyperVPolicyWindows10/3-Remove.ps1 new file mode 100644 index 0000000000..3994f31b44 --- /dev/null +++ b/Modules/Microsoft365DSC/Examples/Resources/IntuneFirewallRulesHyperVPolicyWindows10/3-Remove.ps1 @@ -0,0 +1,34 @@ +<# +This example removes a Device Control Policy. +#> + +Configuration Example +{ + param( + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint + ) + Import-DscResource -ModuleName Microsoft365DSC + + node localhost + { + IntuneFirewallRulesHyperVPolicyWindows10 'myIntuneFirewallRulesHyperVPolicyWindows10' + { + Id = '00000000-0000-0000-0000-000000000000' + DisplayName = 'Intune Firewall Rules Hyper-V Policy Windows10' + Ensure = 'Absent' + ApplicationId = $ApplicationId; + TenantId = $TenantId; + CertificateThumbprint = $CertificateThumbprint; + } + } +} diff --git a/Modules/Microsoft365DSC/Modules/M365DSCDRGUtil.psm1 b/Modules/Microsoft365DSC/Modules/M365DSCDRGUtil.psm1 index 9e9392dc88..2ba46fb602 100644 --- a/Modules/Microsoft365DSC/Modules/M365DSCDRGUtil.psm1 +++ b/Modules/Microsoft365DSC/Modules/M365DSCDRGUtil.psm1 @@ -1778,13 +1778,15 @@ function Get-IntuneSettingCatalogPolicySettingInstanceValue ($Level -eq 1 -and $SettingDefinition.AdditionalProperties.maximumCount -gt 1 -and $groupSettingCollectionDefinitionChildren.Count -ge 1 -and $groupSettingCollectionDefinitionChildren.AdditionalProperties.'@odata.type' -notcontains "#microsoft.graph.deviceManagementConfigurationSettingGroupCollectionDefinition")) { $SettingInstanceName += Get-SettingsCatalogSettingName -SettingDefinition $SettingDefinition -AllSettingDefinitions $AllSettingDefinitions + $settingInstanceNameAlternate = $SettingInstanceName + "_Intune" $cimDSCParams = @() $cimDSCParamsName = "" - $DSCParams.GetEnumerator() | Where-Object -FilterScript { - $_.Value.CimClass.CimClassName -contains $SettingInstanceName - } | Foreach-Object -Process { - $cimDSCParams += $_.Value - $cimDSCParamsName = $_.Key + $DSCParams.GetEnumerator() | ForEach-Object { + if ($_.Value.CimClass.CimClassName -eq $SettingInstanceName -or $_.Value.CimClass.CimClassName -like "$settingInstanceNameAlternate*") + { + $cimDSCParams += $_.Value + $cimDSCParamsName = $_.Key + } } $newDSCParams = @{ $cimDSCParamsName = @() diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneFirewallRulesHyperVPolicyWindows10.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneFirewallRulesHyperVPolicyWindows10.Tests.ps1 new file mode 100644 index 0000000000..42368fc025 --- /dev/null +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneFirewallRulesHyperVPolicyWindows10.Tests.ps1 @@ -0,0 +1,493 @@ +[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 "IntuneFirewallRulesHyperVPolicyWindows10" -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 (New-Guid | Out-String) -AsPlainText -Force + $Credential = New-Object System.Management.Automation.PSCredential ('tenantadmin@mydomain.com', $secpasswd) + + Mock -CommandName Confirm-M365DSCDependencies -MockWith { + } + + Mock -CommandName Get-PSSession -MockWith { + } + + Mock -CommandName Remove-PSSession -MockWith { + } + + Mock -CommandName Update-MgBetaDeviceManagementConfigurationPolicy -MockWith { + } + + Mock -CommandName New-MgBetaDeviceManagementConfigurationPolicy -MockWith { + return @{ + Id = '619bd4a4-3b3b-4441-bd6f-3f4c0c444870' + } + } + + Mock -CommandName Get-MgBetaDeviceManagementConfigurationPolicy -MockWith { + return @{ + Id = '12345-12345-12345-12345-12345' + Description = 'My Test' + Name = 'My Test' + RoleScopeTagIds = @("FakeStringValue") + TemplateReference = @{ + TemplateId = 'a5481c22-7a2a-4f59-a33e-6eee30d02f94_1' + } + } + } + + Mock -CommandName Remove-MgBetaDeviceManagementConfigurationPolicy -MockWith { + } + + Mock -CommandName Update-IntuneDeviceConfigurationPolicy -MockWith { + } + + Mock -CommandName Get-IntuneSettingCatalogPolicySetting -MockWith { + } + + Mock -CommandName Get-MgBetaDeviceManagementConfigurationPolicySetting -MockWith { + return @( + @{ + Id = '0' + SettingDefinitions = @( + @{ + Id = 'vendor_msft_firewall_mdmstore_hypervfirewallrules_{firewallrulename}' + Name = '{FirewallRuleName}' + OffsetUri = '/MdmStore/HyperVFirewallRules/{0}' + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSettingGroupCollectionDefinition' + minimumCount = 0 + maximumCount = 100 + childIds = @( + 'vendor_msft_firewall_mdmstore_hypervfirewallrules_{firewallrulename}_firewallrulename' + 'vendor_msft_firewall_mdmstore_hypervfirewallrules_{firewallrulename}_direction' + 'vendor_msft_firewall_mdmstore_hypervfirewallrules_{firewallrulename}_remoteportranges' + 'vendor_msft_firewall_mdmstore_hypervfirewallrules_{firewallrulename}_name' + 'vendor_msft_firewall_mdmstore_hypervfirewallrules_{firewallrulename}_protocol' + 'vendor_msft_firewall_mdmstore_hypervfirewallrules_{firewallrulename}_enabled' + 'vendor_msft_firewall_mdmstore_hypervfirewallrules_{firewallrulename}_action' + ) + } + }, + @{ + Id = 'vendor_msft_firewall_mdmstore_hypervfirewallrules_{firewallrulename}_firewallrulename' + Name = 'FirewallRuleName' + OffsetUri = '/MdmStore/HyperVFirewallRules/{0}/FirewallRuleName' + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSimpleSettingDefinition' + dependentOn = @( + @{ + dependentOn = 'vendor_msft_firewall_mdmstore_hypervfirewallrules_{firewallrulename}' + parentSettingId = 'vendor_msft_firewall_mdmstore_hypervfirewallrules_{firewallrulename}' + } + ) + } + }, + @{ + Id = 'vendor_msft_firewall_mdmstore_hypervfirewallrules_{firewallrulename}_direction' + Name = 'Direction' + OffsetUri = '/MdmStore/HyperVFirewallRules/{0}/Direction' + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingDefinition' + options = @( + @{ + itemId = 'vendor_msft_firewall_mdmstore_hypervfirewallrules_{firewallrulename}_direction_out' + name = 'The rule applies to outbound traffic.' + dependentOn = @( + @{ + dependentOn = 'vendor_msft_firewall_mdmstore_hypervfirewallrules_{firewallrulename}' + parentSettingId = 'vendor_msft_firewall_mdmstore_hypervfirewallrules_{firewallrulename}' + } + ) + } + ) + } + }, + @{ + Id = 'vendor_msft_firewall_mdmstore_hypervfirewallrules_{firewallrulename}_remoteportranges' + Name = 'RemotePortRanges' + OffsetUri = '/MdmStore/HyperVFirewallRules/{0}/RemotePortRanges' + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSimpleSettingCollectionDefinition' + minimumCount = 0 + maximumCount = 600 + dependentOn = @( + @{ + dependentOn = 'vendor_msft_firewall_mdmstore_hypervfirewallrules_{firewallrulename}' + parentSettingId = 'vendor_msft_firewall_mdmstore_hypervfirewallrules_{firewallrulename}' + } + ) + } + }, + @{ + Id = 'vendor_msft_firewall_mdmstore_hypervfirewallrules_{firewallrulename}_name' + Name = 'Name' + OffsetUri = '/MdmStore/HyperVFirewallRules/{0}/Name' + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSimpleSettingDefinition' + dependentOn = @( + @{ + dependentOn = 'vendor_msft_firewall_mdmstore_hypervfirewallrules_{firewallrulename}' + parentSettingId = 'vendor_msft_firewall_mdmstore_hypervfirewallrules_{firewallrulename}' + } + ) + } + }, + @{ + Id = 'vendor_msft_firewall_mdmstore_hypervfirewallrules_{firewallrulename}_protocol' + Name = 'Protocol' + OffsetUri = '/MdmStore/HyperVFirewallRules/{0}/Protocol' + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSimpleSettingDefinition' + dependentOn = @( + @{ + dependentOn = 'vendor_msft_firewall_mdmstore_hypervfirewallrules_{firewallrulename}' + parentSettingId = 'vendor_msft_firewall_mdmstore_hypervfirewallrules_{firewallrulename}' + } + ) + } + }, + @{ + Id = 'vendor_msft_firewall_mdmstore_hypervfirewallrules_{firewallrulename}_enabled' + Name = 'Enabled' + OffsetUri = '/MdmStore/HyperVFirewallRules/{0}/Enabled' + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingDefinition' + options = @( + @{ + itemId = 'vendor_msft_firewall_mdmstore_hypervfirewallrules_{firewallrulename}_enabled_0' + name = 'Enabled' + dependentOn = @( + @{ + dependentOn = 'vendor_msft_firewall_mdmstore_hypervfirewallrules_{firewallrulename}' + parentSettingId = 'vendor_msft_firewall_mdmstore_hypervfirewallrules_{firewallrulename}' + } + ) + } + ) + } + }, + @{ + Id = 'vendor_msft_firewall_mdmstore_hypervfirewallrules_{firewallrulename}_action' + Name = 'Action' + OffsetUri = '/MdmStore/HyperVFirewallRules/{0}/Action/Type' + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingDefinition' + options = @( + @{ + itemId = 'vendor_msft_firewall_mdmstore_hypervfirewallrules_{firewallrulename}_action_1' + name = 'Allow' + dependentOn = @( + @{ + dependentOn = 'vendor_msft_firewall_mdmstore_hypervfirewallrules_{firewallrulename}' + parentSettingId = 'vendor_msft_firewall_mdmstore_hypervfirewallrules_{firewallrulename}' + } + ) + } + ) + } + } + ) + SettingInstance = @{ + SettingDefinitionId = 'vendor_msft_firewall_mdmstore_hypervfirewallrules_{firewallrulename}' + SettingInstanceTemplateReference = @{ + SettingInstanceTemplateId = '76c7a8be-67d2-44bf-81a5-38c94926b1a1' + } + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationGroupSettingCollectionInstance' + settingDefinitionId = 'vendor_msft_firewall_mdmstore_hypervfirewallrules_{firewallrulename}' + groupSettingCollectionValue = @( + @{ + children = @( + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' + settingDefinitionId = 'vendor_msft_firewall_mdmstore_hypervfirewallrules_{firewallrulename}_enabled' + choiceSettingValue = @{ + children = @() + value = 'vendor_msft_firewall_mdmstore_hypervfirewallrules_{firewallrulename}_enabled_1' + } + }, + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSimpleSettingInstance' + settingDefinitionId = 'vendor_msft_firewall_mdmstore_hypervfirewallrules_{firewallrulename}_name' + simpleSettingValue = @{ + value = '__Test' + } + }, + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSimpleSettingCollectionInstance' + settingDefinitionId = 'vendor_msft_firewall_mdmstore_hypervfirewallrules_{firewallrulename}_remoteportranges' + simpleSettingCollectionValue = @( + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationStringSettingValue' + value = '0-100' + } + ) + }, + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' + settingDefinitionId = 'vendor_msft_firewall_mdmstore_hypervfirewallrules_{firewallrulename}_direction' + choiceSettingValue = @{ + children = @() + value = 'vendor_msft_firewall_mdmstore_hypervfirewallrules_{firewallrulename}_direction_out' + } + }, + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' + settingDefinitionId = 'vendor_msft_firewall_mdmstore_hypervfirewallrules_{firewallrulename}_action' + choiceSettingValue = @{ + children = @() + value = 'vendor_msft_firewall_mdmstore_hypervfirewallrules_{firewallrulename}_action_1' + } + }, + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSimpleSettingInstance' + settingDefinitionId = 'vendor_msft_firewall_mdmstore_hypervfirewallrules_{firewallrulename}_protocol' + simpleSettingValue = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationIntegerSettingValue' + value = 80 + } + } + ) + } + ) + } + } + } + ) + } + + Mock -CommandName Update-DeviceConfigurationPolicyAssignment -MockWith { + } + + Mock -CommandName New-M365DSCConnection -MockWith { + return "Credentials" + } + + # Mock Write-Host to hide output during the tests + Mock -CommandName Write-Host -MockWith { + } + $Script:exportedInstances =$null + $Script:ExportMode = $false + + Mock -CommandName Get-MgBetaDeviceManagementConfigurationPolicyAssignment -MockWith { + return @(@{ + Id = '12345-12345-12345-12345-12345' + Source = 'direct' + SourceId = '12345-12345-12345-12345-12345' + Target = @{ + DeviceAndAppManagementAssignmentFilterId = '12345-12345-12345-12345-12345' + DeviceAndAppManagementAssignmentFilterType = 'none' + AdditionalProperties = @( + @{ + '@odata.type' = '#microsoft.graph.exclusionGroupAssignmentTarget' + groupId = '26d60dd1-fab6-47bf-8656-358194c1a49d' + } + ) + } + }) + } + + } + + # Test contexts + Context -Name "The IntuneFirewallRulesHyperVPolicyWindows10 should exist but it DOES NOT" -Fixture { + BeforeAll { + $testParams = @{ + Assignments = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_DeviceManagementConfigurationPolicyAssignments -Property @{ + DataType = '#microsoft.graph.exclusionGroupAssignmentTarget' + groupId = '26d60dd1-fab6-47bf-8656-358194c1a49d' + deviceAndAppManagementAssignmentFilterType = 'none' + } -ClientOnly) + ) + Description = "My Test" + FirewallRuleName = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_MicrosoftGraphIntuneSettingsCatalogFirewallRuleName_IntuneFirewallRulesHyperVPolicyWindows10 -Property @{ + Direction = 'out' + RemotePortRanges = @('0-100') + Name = '__Test' + Protocol = 80 + Enabled = '1' + Action = '1' + } -ClientOnly) + ) + Id = "619bd4a4-3b3b-4441-bd6f-3f4c0c444870" + DisplayName = "My Test" + RoleScopeTagIds = @("FakeStringValue") + Ensure = "Present" + Credential = $Credential; + } + + Mock -CommandName Get-MgBetaDeviceManagementConfigurationPolicy -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 + } + It 'Should Create the group from the Set method' { + Set-TargetResource @testParams + Should -Invoke -CommandName New-MgBetaDeviceManagementConfigurationPolicy -Exactly 1 + } + } + + Context -Name "The IntuneFirewallRulesHyperVPolicyWindows10 exists but it SHOULD NOT" -Fixture { + BeforeAll { + $testParams = @{ + Assignments = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_DeviceManagementConfigurationPolicyAssignments -Property @{ + DataType = '#microsoft.graph.exclusionGroupAssignmentTarget' + groupId = '26d60dd1-fab6-47bf-8656-358194c1a49d' + deviceAndAppManagementAssignmentFilterType = 'none' + } -ClientOnly) + ) + Description = "My Test" + FirewallRuleName = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_MicrosoftGraphIntuneSettingsCatalogFirewallRuleName_IntuneFirewallRulesHyperVPolicyWindows10 -Property @{ + Direction = 'out' + RemotePortRanges = @('0-100') + Name = '__Test' + Protocol = 80 + Enabled = '1' + Action = '1' + } -ClientOnly) + ) + Id = "619bd4a4-3b3b-4441-bd6f-3f4c0c444870" + DisplayName = "My Test" + RoleScopeTagIds = @("FakeStringValue") + Ensure = "Absent" + Credential = $Credential; + } + } + + 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-MgBetaDeviceManagementConfigurationPolicy -Exactly 1 + } + } + + Context -Name "The IntuneFirewallRulesHyperVPolicyWindows10 Exists and Values are already in the desired state" -Fixture { + BeforeAll { + $testParams = @{ + Assignments = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_DeviceManagementConfigurationPolicyAssignments -Property @{ + DataType = '#microsoft.graph.exclusionGroupAssignmentTarget' + groupId = '26d60dd1-fab6-47bf-8656-358194c1a49d' + deviceAndAppManagementAssignmentFilterType = 'none' + } -ClientOnly) + ) + Description = "My Test" + FirewallRuleName = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_MicrosoftGraphIntuneSettingsCatalogFirewallRuleName_IntuneFirewallRulesHyperVPolicyWindows10 -Property @{ + Direction = 'out' + RemotePortRanges = @('0-100') + Name = '__Test' + Protocol = 80 + Enabled = '1' + Action = '1' + } -ClientOnly) + ) + Id = "619bd4a4-3b3b-4441-bd6f-3f4c0c444870" + DisplayName = "My Test" + RoleScopeTagIds = @("FakeStringValue") + Ensure = "Present" + Credential = $Credential; + } + } + + It 'Should return true from the Test method' { + Test-TargetResource @testParams | Should -Be $true + } + } + + Context -Name "The IntuneFirewallRulesHyperVPolicyWindows10 exists and values are NOT in the desired state" -Fixture { + BeforeAll { + $testParams = @{ + Assignments = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_DeviceManagementConfigurationPolicyAssignments -Property @{ + DataType = '#microsoft.graph.exclusionGroupAssignmentTarget' + groupId = '26d60dd1-fab6-47bf-8656-358194c1a49d' + deviceAndAppManagementAssignmentFilterType = 'none' + } -ClientOnly) + ) + Description = "My Test" + FirewallRuleName = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_MicrosoftGraphIntuneSettingsCatalogFirewallRuleName_IntuneFirewallRulesHyperVPolicyWindows10 -Property @{ + Direction = 'in' # Drift + RemotePortRanges = @('0-100') + Name = '__Test' + Protocol = 80 + Enabled = '1' + Action = '1' + } -ClientOnly) + ) + Id = "619bd4a4-3b3b-4441-bd6f-3f4c0c444870" + DisplayName = "My Test" + RoleScopeTagIds = @("FakeStringValue") + Ensure = "Present" + 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-IntuneDeviceConfigurationPolicy -Exactly 1 + } + } + + Context -Name 'ReverseDSC Tests' -Fixture { + BeforeAll { + $Global:CurrentModeIsExport = $true + $Global:PartialExportFileName = "$(New-Guid).partial.ps1" + $testParams = @{ + Credential = $Credential + } + } + + 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/Microsoft365DSC/Microsoft365DSC.IntuneFirewallRulesPolicyWindows10.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneFirewallRulesPolicyWindows10.Tests.ps1 index 33a599f448..03224a580e 100644 --- a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneFirewallRulesPolicyWindows10.Tests.ps1 +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneFirewallRulesPolicyWindows10.Tests.ps1 @@ -399,7 +399,7 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { ) Description = "My Test" FirewallRuleName = [CimInstance[]]@( - (New-CimInstance -ClassName MicrosoftGraphIntuneSettingsCatalogFirewallRuleName -Property @{ + (New-CimInstance -ClassName MSFT_MicrosoftGraphIntuneSettingsCatalogFirewallRuleName -Property @{ Direction = 'out' InterfaceTypes = @('lan') RemotePortRanges = @('0-100') @@ -447,7 +447,7 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { ) Description = "My Test" FirewallRuleName = [CimInstance[]]@( - (New-CimInstance -ClassName MicrosoftGraphIntuneSettingsCatalogFirewallRuleName -Property @{ + (New-CimInstance -ClassName MSFT_MicrosoftGraphIntuneSettingsCatalogFirewallRuleName -Property @{ Direction = 'out' InterfaceTypes = @('lan') RemotePortRanges = @('0-100') @@ -493,7 +493,7 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { ) Description = "My Test" FirewallRuleName = [CimInstance[]]@( - (New-CimInstance -ClassName MicrosoftGraphIntuneSettingsCatalogFirewallRuleName -Property @{ + (New-CimInstance -ClassName MSFT_MicrosoftGraphIntuneSettingsCatalogFirewallRuleName -Property @{ Direction = 'out' InterfaceTypes = @('lan') RemotePortRanges = @('0-100') @@ -530,7 +530,7 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { ) Description = "My Test" FirewallRuleName = [CimInstance[]]@( - (New-CimInstance -ClassName MicrosoftGraphIntuneSettingsCatalogFirewallRuleName -Property @{ + (New-CimInstance -ClassName MSFT_MicrosoftGraphIntuneSettingsCatalogFirewallRuleName -Property @{ Direction = 'in' # Drift InterfaceTypes = @('lan') RemotePortRanges = @('0-100') From 2313343565eb094e8d00169223d6f3a0deda6274 Mon Sep 17 00:00:00 2001 From: NikCharlebois Date: Thu, 14 Nov 2024 11:53:24 +0000 Subject: [PATCH 13/65] Updated Resources and Cmdlet documentation pages --- ...ntuneFirewallRulesHyperVPolicyWindows10.md | 235 ++++++++++++++++++ 1 file changed, 235 insertions(+) create mode 100644 docs/docs/resources/intune/IntuneFirewallRulesHyperVPolicyWindows10.md diff --git a/docs/docs/resources/intune/IntuneFirewallRulesHyperVPolicyWindows10.md b/docs/docs/resources/intune/IntuneFirewallRulesHyperVPolicyWindows10.md new file mode 100644 index 0000000000..c44d4ee454 --- /dev/null +++ b/docs/docs/resources/intune/IntuneFirewallRulesHyperVPolicyWindows10.md @@ -0,0 +1,235 @@ +# IntuneFirewallRulesHyperVPolicyWindows10 + +## Parameters + +| Parameter | Attribute | DataType | Description | Allowed Values | +| --- | --- | --- | --- | --- | +| **Description** | Write | String | Policy description | | +| **DisplayName** | Key | String | Policy name | | +| **RoleScopeTagIds** | Write | StringArray[] | List of Scope Tags for this Entity instance. | | +| **Id** | Write | String | The unique identifier for an entity. Read-only. | | +| **FirewallRuleName** | Write | MSFT_MicrosoftGraphIntuneSettingsCatalogFirewallRuleName_IntuneFirewallRulesHyperVPolicyWindows10[] | Firewall Rules | | +| **Assignments** | Write | MSFT_DeviceManagementConfigurationPolicyAssignments[] | Represents the assignment to the Intune policy. | | +| **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. | | +| **AccessTokens** | Write | StringArray[] | Access token used for authentication. | | + +### MSFT_DeviceManagementConfigurationPolicyAssignments + +#### Parameters + +| Parameter | Attribute | DataType | Description | Allowed Values | +| --- | --- | --- | --- | --- | +| **dataType** | Write | String | The type of the target assignment. | `#microsoft.graph.groupAssignmentTarget`, `#microsoft.graph.allLicensedUsersAssignmentTarget`, `#microsoft.graph.allDevicesAssignmentTarget`, `#microsoft.graph.exclusionGroupAssignmentTarget`, `#microsoft.graph.configurationManagerCollectionAssignmentTarget` | +| **deviceAndAppManagementAssignmentFilterType** | Write | String | The type of filter of the target assignment i.e. Exclude or Include. Possible values are:none, include, exclude. | `none`, `include`, `exclude` | +| **deviceAndAppManagementAssignmentFilterId** | Write | String | The Id of the filter for the target assignment. | | +| **groupId** | Write | String | The group Id that is the target of the assignment. | | +| **groupDisplayName** | Write | String | The group Display Name that is the target of the assignment. | | +| **collectionId** | Write | String | The collection Id that is the target of the assignment.(ConfigMgr) | | + +### MSFT_MicrosoftGraphIntuneSettingsCatalogFirewallRuleName_IntuneFirewallRulesHyperVPolicyWindows10 + +#### Parameters + +| Parameter | Attribute | DataType | Description | Allowed Values | +| --- | --- | --- | --- | --- | +| **Enabled** | Write | String | Enabled - Depends on FirewallRuleName (0: Disabled, 1: Enabled) | `0`, `1` | +| **Name** | Write | String | Name - Depends on FirewallRuleName | | +| **Direction** | Write | String | Direction - Depends on FirewallRuleName (in: The rule applies to inbound traffic., out: The rule applies to outbound traffic.) | `in`, `out` | +| **Priority** | Write | SInt32 | Priority - Depends on FirewallRuleName | | +| **Profiles** | Write | SInt32Array[] | Profiles - Depends on FirewallRuleName (1: FW_PROFILE_TYPE_DOMAIN: This value represents the profile for networks that are connected to domains., 2: FW_PROFILE_TYPE_STANDARD: This value represents the standard profile for networks. These networks are classified as private by the administrators in the server host. The classification happens the first time the host connects to the network. Usually these networks are behind Network Address Translation (NAT) devices, routers, and other edge devices, and they are in a private location, such as a home or an office. AND FW_PROFILE_TYPE_PRIVATE: This value represents the profile for private networks, which is represented by the same value as that used for FW_PROFILE_TYPE_STANDARD., 4: FW_PROFILE_TYPE_PUBLIC: This value represents the profile for public networks. These networks are classified as public by the administrators in the server host. The classification happens the first time the host connects to the network. Usually these networks are those at airports, coffee shops, and other public places where the peers in the network or the network administrator are not trusted., 2147483647: FW_PROFILE_TYPE_ALL: This value represents all these network sets and any future network sets.) | `1`, `2`, `4`, `2147483647` | +| **VMCreatorId** | Write | String | Target - Depends on FirewallRuleName (wsl: WSL) | `wsl` | +| **Action** | Write | String | Action - Depends on FirewallRuleName (0: Block, 1: Allow) | `0`, `1` | +| **LocalAddressRanges** | Write | StringArray[] | Local Address Ranges - Depends on FirewallRuleName | | +| **RemoteAddressRanges** | Write | StringArray[] | Remote Address Ranges - Depends on FirewallRuleName | | +| **RemotePortRanges** | Write | StringArray[] | Remote Port Ranges - Depends on FirewallRuleName | | +| **Protocol** | Write | SInt32 | Protocol - Depends on FirewallRuleName | | +| **LocalPortRanges** | Write | StringArray[] | Local Port Ranges - Depends on FirewallRuleName | | + + +## Description + +Intune Firewall Rules Hyper-V Policy for Windows10 + +## Permissions + +### Microsoft Graph + +To authenticate with the Microsoft Graph API, this resource required the following permissions: + +#### Delegated permissions + +- **Read** + + - DeviceManagementConfiguration.Read.All, Group.Read.All + +- **Update** + + - DeviceManagementConfiguration.ReadWrite.All, Group.Read.All + +#### Application permissions + +- **Read** + + - DeviceManagementConfiguration.Read.All, Group.Read.All + +- **Update** + + - DeviceManagementConfiguration.ReadWrite.All, Group.Read.All + +## Examples + +### Example 1 + +This example creates a new Intune Firewall Policy for Windows10. + +```powershell +Configuration Example +{ + param( + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint + ) + Import-DscResource -ModuleName Microsoft365DSC + + node localhost + { + IntuneFirewallRulesHyperVPolicyWindows10 'myIntuneFirewallRulesHyperVPolicyWindows10' + { + Assignments = @( + MSFT_DeviceManagementConfigurationPolicyAssignments{ + deviceAndAppManagementAssignmentFilterType = 'none' + dataType = '#microsoft.graph.groupAssignmentTarget' + groupId = '11111111-1111-1111-1111-111111111111' + } + ); + FirewallRuleName = @( + MSFT_MicrosoftGraphIntuneSettingsCatalogFirewallRuleName_IntuneFirewallRulesHyperVPolicyWindows10{ + Direction = 'out' + RemotePortRanges = @('0-100') + Name = 'Rule1' + Protocol = 80 + Enabled = '1' + Action = '1' + } + ) + Description = 'Description' + DisplayName = "Intune Firewall Rules Hyper-V Policy Windows10"; + Ensure = "Present"; + Id = '00000000-0000-0000-0000-000000000000' + RoleScopeTagIds = @("0"); + ApplicationId = $ApplicationId; + TenantId = $TenantId; + CertificateThumbprint = $CertificateThumbprint; + } + } +} +``` + +### Example 2 + +This example updates a Intune Firewall Policy for Windows10. + +```powershell +Configuration Example +{ + param( + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint + ) + Import-DscResource -ModuleName Microsoft365DSC + + node localhost + { + IntuneFirewallRulesHyperVPolicyWindows10 'myIntuneFirewallRulesHyperVPolicyWindows10' + { + Assignments = @( + MSFT_DeviceManagementConfigurationPolicyAssignments{ + deviceAndAppManagementAssignmentFilterType = 'none' + dataType = '#microsoft.graph.groupAssignmentTarget' + groupId = '11111111-1111-1111-1111-111111111111' + } + ); + FirewallRuleName = @( + MSFT_MicrosoftGraphIntuneSettingsCatalogFirewallRuleName_IntuneFirewallRulesHyperVPolicyWindows10{ + Direction = 'in' # Updated property + RemotePortRanges = @('0-100') + Name = 'Rule1' + Protocol = 80 + Enabled = '1' + Action = '1' + } + ) + Description = 'Description' + DisplayName = "Intune Firewall Rules Hyper-V Policy Windows10"; + Ensure = "Present"; + Id = '00000000-0000-0000-0000-000000000000' + RoleScopeTagIds = @("0"); + ApplicationId = $ApplicationId; + TenantId = $TenantId; + CertificateThumbprint = $CertificateThumbprint; + } + } +} +``` + +### Example 3 + +This example removes a Device Control Policy. + +```powershell +Configuration Example +{ + param( + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint + ) + Import-DscResource -ModuleName Microsoft365DSC + + node localhost + { + IntuneFirewallRulesHyperVPolicyWindows10 'myIntuneFirewallRulesHyperVPolicyWindows10' + { + Id = '00000000-0000-0000-0000-000000000000' + DisplayName = 'Intune Firewall Rules Hyper-V Policy Windows10' + Ensure = 'Absent' + ApplicationId = $ApplicationId; + TenantId = $TenantId; + CertificateThumbprint = $CertificateThumbprint; + } + } +} +``` + From 75852cd33af3836faafc6f57f199a3d4aa96d625 Mon Sep 17 00:00:00 2001 From: NikCharlebois Date: Thu, 14 Nov 2024 11:55:32 +0000 Subject: [PATCH 14/65] Updated Schema Definition --- Modules/Microsoft365DSC/SchemaDefinition.json | 140 ++++++++++++++++++ 1 file changed, 140 insertions(+) diff --git a/Modules/Microsoft365DSC/SchemaDefinition.json b/Modules/Microsoft365DSC/SchemaDefinition.json index 3e7a22c247..2ebfcaead9 100644 --- a/Modules/Microsoft365DSC/SchemaDefinition.json +++ b/Modules/Microsoft365DSC/SchemaDefinition.json @@ -41330,6 +41330,146 @@ } ] }, + { + "ClassName": "MSFT_MicrosoftGraphIntuneSettingsCatalogFirewallRuleName_IntuneFirewallRulesHyperVPolicyWindows10", + "Parameters": [ + { + "CIMType": "String", + "Name": "Enabled", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "Name", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "Direction", + "Option": "Write" + }, + { + "CIMType": "SInt32", + "Name": "Priority", + "Option": "Write" + }, + { + "CIMType": "SInt32[]", + "Name": "Profiles", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "VMCreatorId", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "Action", + "Option": "Write" + }, + { + "CIMType": "String[]", + "Name": "LocalAddressRanges", + "Option": "Write" + }, + { + "CIMType": "String[]", + "Name": "RemoteAddressRanges", + "Option": "Write" + }, + { + "CIMType": "String[]", + "Name": "RemotePortRanges", + "Option": "Write" + }, + { + "CIMType": "SInt32", + "Name": "Protocol", + "Option": "Write" + }, + { + "CIMType": "String[]", + "Name": "LocalPortRanges", + "Option": "Write" + } + ] + }, + { + "ClassName": "MSFT_IntuneFirewallRulesHyperVPolicyWindows10", + "Parameters": [ + { + "CIMType": "String", + "Name": "Description", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "DisplayName", + "Option": "Key" + }, + { + "CIMType": "String[]", + "Name": "RoleScopeTagIds", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "Id", + "Option": "Write" + }, + { + "CIMType": "MSFT_MicrosoftGraphIntuneSettingsCatalogFirewallRuleName_IntuneFirewallRulesHyperVPolicyWindows10[]", + "Name": "FirewallRuleName", + "Option": "Write" + }, + { + "CIMType": "MSFT_DeviceManagementConfigurationPolicyAssignments[]", + "Name": "Assignments", + "Option": "Write" + }, + { + "CIMType": "string", + "Name": "Ensure", + "Option": "Write" + }, + { + "CIMType": "MSFT_Credential", + "Name": "Credential", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "ApplicationId", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "TenantId", + "Option": "Write" + }, + { + "CIMType": "MSFT_Credential", + "Name": "ApplicationSecret", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "CertificateThumbprint", + "Option": "Write" + }, + { + "CIMType": "Boolean", + "Name": "ManagedIdentity", + "Option": "Write" + }, + { + "CIMType": "String[]", + "Name": "AccessTokens", + "Option": "Write" + } + ] + }, { "ClassName": "MSFT_MicrosoftGraphIntuneSettingsCatalogFirewallRuleName", "Parameters": [ From 29e66b6ef388fa6d41e23d85bee19b5ab345be7d Mon Sep 17 00:00:00 2001 From: NikCharlebois Date: Thu, 14 Nov 2024 11:56:12 +0000 Subject: [PATCH 15/65] Updated {Create} Intune Integration Tests --- ...M365DSCIntegration.INTUNE.Create.Tests.ps1 | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/Tests/Integration/Microsoft365DSC/M365DSCIntegration.INTUNE.Create.Tests.ps1 b/Tests/Integration/Microsoft365DSC/M365DSCIntegration.INTUNE.Create.Tests.ps1 index a68b840aa5..74d4d62a1b 100644 --- a/Tests/Integration/Microsoft365DSC/M365DSCIntegration.INTUNE.Create.Tests.ps1 +++ b/Tests/Integration/Microsoft365DSC/M365DSCIntegration.INTUNE.Create.Tests.ps1 @@ -2703,6 +2703,34 @@ TenantId = $TenantId; CertificateThumbprint = $CertificateThumbprint; } + IntuneFirewallRulesHyperVPolicyWindows10 'myIntuneFirewallRulesHyperVPolicyWindows10' + { + Assignments = @( + MSFT_DeviceManagementConfigurationPolicyAssignments{ + deviceAndAppManagementAssignmentFilterType = 'none' + dataType = '#microsoft.graph.groupAssignmentTarget' + groupId = '11111111-1111-1111-1111-111111111111' + } + ); + FirewallRuleName = @( + MSFT_MicrosoftGraphIntuneSettingsCatalogFirewallRuleName_IntuneFirewallRulesHyperVPolicyWindows10{ + Direction = 'out' + RemotePortRanges = @('0-100') + Name = 'Rule1' + Protocol = 80 + Enabled = '1' + Action = '1' + } + ) + Description = 'Description' + DisplayName = "Intune Firewall Rules Hyper-V Policy Windows10"; + Ensure = "Present"; + Id = '00000000-0000-0000-0000-000000000000' + RoleScopeTagIds = @("0"); + ApplicationId = $ApplicationId; + TenantId = $TenantId; + CertificateThumbprint = $CertificateThumbprint; + } IntuneFirewallRulesPolicyWindows10 'myIntuneFirewallRulesPolicyWindows10' { Assignments = @( From afe61b9dc3898677c9d2a19c7293050a190c067f Mon Sep 17 00:00:00 2001 From: Alfred Schreuder Date: Thu, 14 Nov 2024 13:38:49 +0100 Subject: [PATCH 16/65] Added fixed to CHANGELOG --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b2602b09c6..a1c80dec73 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ # UNRELEASED +* AADConditionalAccessPolicy + * Fixed bug where a null value was passed in the request for the + excludePlatforms parameter when just values were assigned to includePlatforms, which throws an error. + * Fixed bug where a null value was passed in the request for the + sessionControl parameter when there are no session controls, which throws an error. + * Fixed bug where a null value was passed in the request for the + applicationEnforcedRestrictions parameter when value was set to false, which throws an error. * AADRoleEligibilityScheduleRequest * Adds support for custom role assignments at app scope. From edb0a5e6f1b42ebe86a22f8a1620c5b73b32bafd Mon Sep 17 00:00:00 2001 From: Fabien Tschanz Date: Thu, 14 Nov 2024 14:53:12 +0100 Subject: [PATCH 17/65] Add Intune Firewall rules policy for Windows10 ConfigMgr --- CHANGELOG.md | 2 + ...FirewallRulesPolicyWindows10ConfigMgr.psm1 | 641 ++++++++++++++++++ ...llRulesPolicyWindows10ConfigMgr.schema.mof | 51 ++ .../readme.md | 6 + .../settings.json | 44 ++ .../1-Create.ps1 | 56 ++ .../2-Update.ps1 | 56 ++ .../3-Remove.ps1 | 34 + ...allRulesPolicyWindows10ConfigMgr.Tests.ps1 | 584 ++++++++++++++++ 9 files changed, 1474 insertions(+) create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_IntuneFirewallRulesPolicyWindows10ConfigMgr/MSFT_IntuneFirewallRulesPolicyWindows10ConfigMgr.psm1 create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_IntuneFirewallRulesPolicyWindows10ConfigMgr/MSFT_IntuneFirewallRulesPolicyWindows10ConfigMgr.schema.mof create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_IntuneFirewallRulesPolicyWindows10ConfigMgr/readme.md create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_IntuneFirewallRulesPolicyWindows10ConfigMgr/settings.json create mode 100644 Modules/Microsoft365DSC/Examples/Resources/IntuneFirewallRulesPolicyWindows10ConfigMgr/1-Create.ps1 create mode 100644 Modules/Microsoft365DSC/Examples/Resources/IntuneFirewallRulesPolicyWindows10ConfigMgr/2-Update.ps1 create mode 100644 Modules/Microsoft365DSC/Examples/Resources/IntuneFirewallRulesPolicyWindows10ConfigMgr/3-Remove.ps1 create mode 100644 Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneFirewallRulesPolicyWindows10ConfigMgr.Tests.ps1 diff --git a/CHANGELOG.md b/CHANGELOG.md index 3380151965..3428bb4bbe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ * Adds support for custom role assignments at app scope. * IntuneFirewallRulesHyperVPolicyWindows10 * Initial release. +* IntuneFirewallRulesPolicyWindows10ConfigMgr + * Initial release. * M365DSCDRGUtil * Improve CIM instance detection for specific Intune resources. diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneFirewallRulesPolicyWindows10ConfigMgr/MSFT_IntuneFirewallRulesPolicyWindows10ConfigMgr.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneFirewallRulesPolicyWindows10ConfigMgr/MSFT_IntuneFirewallRulesPolicyWindows10ConfigMgr.psm1 new file mode 100644 index 0000000000..1ad95440d6 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneFirewallRulesPolicyWindows10ConfigMgr/MSFT_IntuneFirewallRulesPolicyWindows10ConfigMgr.psm1 @@ -0,0 +1,641 @@ +function Get-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + param + ( + #region resource generator code + [Parameter()] + [System.String] + $Description, + + [Parameter(Mandatory = $true)] + [System.String] + $DisplayName, + + [Parameter()] + [System.String[]] + $RoleScopeTagIds, + + [Parameter()] + [System.String] + $Id, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $FirewallRuleName, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $Assignments, + #endregion + + [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, + + [Parameter()] + [System.String[]] + $AccessTokens + ) + + 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 + #region resource generator code + $getValue = Get-MgBetaDeviceManagementConfigurationPolicy -DeviceManagementConfigurationPolicyId $Id -ErrorAction SilentlyContinue + + if ($null -eq $getValue) + { + Write-Verbose -Message "Could not find an Intune Firewall Rules Policy for Windows10 ConfigMgr with Id {$Id}" + + if (-not [System.String]::IsNullOrEmpty($DisplayName)) + { + $getValue = Get-MgBetaDeviceManagementConfigurationPolicy ` + -Filter "Name eq '$DisplayName'" ` + -All ` + -ErrorAction SilentlyContinue + } + } + #endregion + if ($null -eq $getValue) + { + Write-Verbose -Message "Could not find an Intune Firewall Rules Policy for Windows10 ConfigMgr with Name {$DisplayName}." + return $nullResult + } + $Id = $getValue.Id + Write-Verbose -Message "An Intune Firewall Rules Policy for Windows10 ConfigMgr with Id {$Id} and Name {$DisplayName} was found" + + # Retrieve policy specific settings + [array]$settings = Get-MgBetaDeviceManagementConfigurationPolicySetting ` + -DeviceManagementConfigurationPolicyId $Id ` + -ExpandProperty 'settingDefinitions' ` + -All ` + -ErrorAction Stop + + $policySettings = @{} + $policySettings = Export-IntuneSettingCatalogPolicySettings -Settings $settings -ReturnHashtable $policySettings + + #region resource generator code + $complexFirewallRuleName = @() + foreach ($currentFirewallRuleName in $policySettings.FirewallRuleName) + { + $myFirewallRuleName = @{} + foreach ($key in $currentFirewallRuleName.Keys) + { + $myFirewallRuleName.Add($key, $currentFirewallRuleName.$key) + } + if ($myFirewallRuleName.values.Where({$null -ne $_}).Count -gt 0) + { + $complexFirewallRuleName += $myFirewallRuleName + } + } + $policySettings.Remove('FirewallRuleName') | Out-Null + #endregion + + $results = @{ + #region resource generator code + Description = $getValue.Description + DisplayName = $getValue.Name + RoleScopeTagIds = $getValue.RoleScopeTagIds + Id = $getValue.Id + FirewallRuleName = $complexFirewallRuleName + Ensure = 'Present' + Credential = $Credential + ApplicationId = $ApplicationId + TenantId = $TenantId + ApplicationSecret = $ApplicationSecret + CertificateThumbprint = $CertificateThumbprint + ManagedIdentity = $ManagedIdentity.IsPresent + #endregion + } + $results += $policySettings + + $assignmentsValues = Get-MgBetaDeviceManagementConfigurationPolicyAssignment -DeviceManagementConfigurationPolicyId $Id + $assignmentResult = @() + if ($assignmentsValues.Count -gt 0) + { + $assignmentResult += ConvertFrom-IntunePolicyAssignment -Assignments $assignmentsValues -IncludeDeviceFilter $true + } + $results.Add('Assignments', $assignmentResult) + + 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()] + [System.String] + $Description, + + [Parameter(Mandatory = $true)] + [System.String] + $DisplayName, + + [Parameter()] + [System.String[]] + $RoleScopeTagIds, + + [Parameter()] + [System.String] + $Id, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $FirewallRuleName, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $Assignments, + #endregion + [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, + + [Parameter()] + [System.String[]] + $AccessTokens + ) + + #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 + + $templateReferenceId = '48da42ed-5df7-485e-8b9d-4844ed5a92bd_1' + $platforms = 'windows10' + $technologies = 'configManager' + + if ($Ensure -eq 'Present' -and $currentInstance.Ensure -eq 'Absent') + { + Write-Verbose -Message "Creating an Intune Firewall Rules Policy for Windows10 ConfigMgr with Name {$DisplayName}" + $BoundParameters.Remove("Assignments") | Out-Null + + $settings = Get-IntuneSettingCatalogPolicySetting ` + -DSCParams ([System.Collections.Hashtable]$BoundParameters) ` + -TemplateId $templateReferenceId + + $createParameters = @{ + Name = $DisplayName + Description = $Description + TemplateReference = @{ templateId = $templateReferenceId } + Platforms = $platforms + Technologies = $technologies + Settings = $settings + } + + #region resource generator code + $policy = New-MgBetaDeviceManagementConfigurationPolicy -BodyParameter $createParameters + + if ($policy.Id) + { + $assignmentsHash = ConvertTo-IntunePolicyAssignment -IncludeDeviceFilter:$true -Assignments $Assignments + Update-DeviceConfigurationPolicyAssignment ` + -DeviceConfigurationPolicyId $policy.Id ` + -Targets $assignmentsHash ` + -Repository 'deviceManagement/configurationPolicies' + } + #endregion + } + elseif ($Ensure -eq 'Present' -and $currentInstance.Ensure -eq 'Present') + { + Write-Verbose -Message "Updating the Intune Firewall Rules Policy for Windows10 ConfigMgr with Id {$($currentInstance.Id)}" + $BoundParameters.Remove("Assignments") | Out-Null + + $settings = Get-IntuneSettingCatalogPolicySetting ` + -DSCParams ([System.Collections.Hashtable]$BoundParameters) ` + -TemplateId $templateReferenceId + + Update-IntuneDeviceConfigurationPolicy ` + -DeviceConfigurationPolicyId $currentInstance.Id ` + -Name $DisplayName ` + -Description $Description ` + -TemplateReferenceId $templateReferenceId ` + -Platforms $platforms ` + -Technologies $technologies ` + -Settings $settings + + #region resource generator code + $assignmentsHash = ConvertTo-IntunePolicyAssignment -IncludeDeviceFilter:$true -Assignments $Assignments + Update-DeviceConfigurationPolicyAssignment ` + -DeviceConfigurationPolicyId $currentInstance.Id ` + -Targets $assignmentsHash ` + -Repository 'deviceManagement/configurationPolicies' + #endregion + } + elseif ($Ensure -eq 'Absent' -and $currentInstance.Ensure -eq 'Present') + { + Write-Verbose -Message "Removing the Intune Firewall Rules Policy for Windows10 ConfigMgr with Id {$($currentInstance.Id)}" + #region resource generator code + Remove-MgBetaDeviceManagementConfigurationPolicy -DeviceManagementConfigurationPolicyId $currentInstance.Id + #endregion + } +} + +function Test-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Boolean])] + param + ( + #region resource generator code + [Parameter()] + [System.String] + $Description, + + [Parameter(Mandatory = $true)] + [System.String] + $DisplayName, + + [Parameter()] + [System.String[]] + $RoleScopeTagIds, + + [Parameter()] + [System.String] + $Id, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $FirewallRuleName, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $Assignments, + #endregion + + [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, + + [Parameter()] + [System.String[]] + $AccessTokens + ) + + #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 Intune Firewall Rules Policy for Windows10 ConfigMgr with Id {$Id} and Name {$DisplayName}" + + $CurrentValues = Get-TargetResource @PSBoundParameters + [Hashtable]$ValuesToCheck = @{} + $MyInvocation.MyCommand.Parameters.GetEnumerator() | ForEach-Object { + if ($_.Key -notlike '*Variable' -or $_.Key -notin @('Verbose', 'Debug', 'ErrorAction', 'WarningAction', 'InformationAction')) + { + if ($null -ne $CurrentValues[$_.Key] -or $null -ne $PSBoundParameters[$_.Key]) + { + $ValuesToCheck.Add($_.Key, $null) + if (-not $PSBoundParameters.ContainsKey($_.Key)) + { + $PSBoundParameters.Add($_.Key, $null) + } + } + } + } + + if ($CurrentValues.Ensure -ne $Ensure) + { + Write-Verbose -Message "Test-TargetResource returned $false" + return $false + } + $testResult = $true + + #Compare Cim instances + foreach ($key in $PSBoundParameters.Keys) + { + $source = $PSBoundParameters.$key + $target = $CurrentValues.$key + if ($null -ne $source -and $source.GetType().Name -like '*CimInstance*') + { + $testResult = Compare-M365DSCComplexObject ` + -Source ($source) ` + -Target ($target) + + if (-not $testResult) + { + break + } + + $ValuesToCheck.Remove($key) | Out-Null + } + } + + $ValuesToCheck.Remove('Id') | Out-Null + $ValuesToCheck = Remove-M365DSCAuthenticationParameter -BoundParameters $ValuesToCheck + + Write-Verbose -Message "Current Values: $(Convert-M365DscHashtableToString -Hashtable $CurrentValues)" + Write-Verbose -Message "Target Values: $(Convert-M365DscHashtableToString -Hashtable $PSBoundParameters)" + + if ($testResult) + { + $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.String] + $Filter, + + [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, + + [Parameter()] + [System.String[]] + $AccessTokens + ) + + $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 + $policyTemplateID = "48da42ed-5df7-485e-8b9d-4844ed5a92bd_1" + [array]$getValue = Get-MgBetaDeviceManagementConfigurationPolicy ` + -Filter $Filter ` + -All ` + -ErrorAction Stop | Where-Object ` + -FilterScript { + $_.TemplateReference.TemplateId -eq $policyTemplateID + } + #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 + if (-not [String]::IsNullOrEmpty($config.displayName)) + { + $displayedKey = $config.displayName + } + elseif (-not [string]::IsNullOrEmpty($config.name)) + { + $displayedKey = $config.name + } + Write-Host " |---[$i/$($getValue.Count)] $displayedKey" -NoNewline + $params = @{ + Id = $config.Id + DisplayName = $config.Name + Ensure = 'Present' + Credential = $Credential + ApplicationId = $ApplicationId + TenantId = $TenantId + ApplicationSecret = $ApplicationSecret + CertificateThumbprint = $CertificateThumbprint + ManagedIdentity = $ManagedIdentity.IsPresent + AccessTokens = $AccessTokens + } + + $Results = Get-TargetResource @Params + $Results = Update-M365DSCExportAuthenticationResults -ConnectionMode $ConnectionMode ` + -Results $Results + if ($null -ne $Results.FirewallRuleName) + { + $complexTypeStringResult = Get-M365DSCDRGComplexTypeToString ` + -ComplexObject $Results.FirewallRuleName ` + -CIMInstanceName 'MicrosoftGraphIntuneSettingsCatalogFirewallRuleName_IntuneFirewallRulesPolicyWindows10ConfigMgr' + if (-not [String]::IsNullOrWhiteSpace($complexTypeStringResult)) + { + $Results.FirewallRuleName = $complexTypeStringResult + } + else + { + $Results.Remove('FirewallRuleName') | Out-Null + } + } + + if ($Results.Assignments) + { + $complexTypeStringResult = Get-M365DSCDRGComplexTypeToString -ComplexObject $Results.Assignments -CIMInstanceName DeviceManagementConfigurationPolicyAssignments + if ($complexTypeStringResult) + { + $Results.Assignments = $complexTypeStringResult + } + else + { + $Results.Remove('Assignments') | Out-Null + } + } + + $currentDSCBlock = Get-M365DSCExportContentForResource -ResourceName $ResourceName ` + -ConnectionMode $ConnectionMode ` + -ModulePath $PSScriptRoot ` + -Results $Results ` + -Credential $Credential + if ($Results.FirewallRuleName) + { + $currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock -ParameterName "FirewallRuleName" -IsCIMArray:$True + } + + if ($Results.Assignments) + { + $currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock -ParameterName "Assignments" -IsCIMArray:$true + } + + $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_IntuneFirewallRulesPolicyWindows10ConfigMgr/MSFT_IntuneFirewallRulesPolicyWindows10ConfigMgr.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneFirewallRulesPolicyWindows10ConfigMgr/MSFT_IntuneFirewallRulesPolicyWindows10ConfigMgr.schema.mof new file mode 100644 index 0000000000..8e6d4601ba --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneFirewallRulesPolicyWindows10ConfigMgr/MSFT_IntuneFirewallRulesPolicyWindows10ConfigMgr.schema.mof @@ -0,0 +1,51 @@ +[ClassVersion("1.0.0.0")] +class MSFT_DeviceManagementConfigurationPolicyAssignments +{ + [Write, Description("The type of the target assignment."), ValueMap{"#microsoft.graph.groupAssignmentTarget","#microsoft.graph.allLicensedUsersAssignmentTarget","#microsoft.graph.allDevicesAssignmentTarget","#microsoft.graph.exclusionGroupAssignmentTarget","#microsoft.graph.configurationManagerCollectionAssignmentTarget"}, Values{"#microsoft.graph.groupAssignmentTarget","#microsoft.graph.allLicensedUsersAssignmentTarget","#microsoft.graph.allDevicesAssignmentTarget","#microsoft.graph.exclusionGroupAssignmentTarget","#microsoft.graph.configurationManagerCollectionAssignmentTarget"}] String dataType; + [Write, Description("The type of filter of the target assignment i.e. Exclude or Include. Possible values are:none, include, exclude."), ValueMap{"none","include","exclude"}, Values{"none","include","exclude"}] String deviceAndAppManagementAssignmentFilterType; + [Write, Description("The Id of the filter for the target assignment.")] String deviceAndAppManagementAssignmentFilterId; + [Write, Description("The group Id that is the target of the assignment.")] String groupId; + [Write, Description("The group Display Name that is the target of the assignment.")] String groupDisplayName; + [Write, Description("The collection Id that is the target of the assignment.(ConfigMgr)")] String collectionId; +}; + +[ClassVersion("1.0.0.0")] +class MSFT_MicrosoftGraphIntuneSettingsCatalogFirewallRuleName_IntuneFirewallRulesPolicyWindows10ConfigMgr +{ + [Write, Description("Enabled - Depends on FirewallRuleName (0: Disabled, 1: Enabled)"), ValueMap{"0", "1"}, Values{"0", "1"}] String Enabled; + [Write, Description("Name - Depends on FirewallRuleName")] String Name; + [Write, Description("Interface Types - Depends on FirewallRuleName (remoteaccess: RemoteAccess, wireless: Wireless, lan: Lan, mobilebroadband: MobileBroadband, mbb: MBB, all: All)"), ValueMap{"remoteaccess", "wireless", "lan", "mobilebroadband", "mbb", "all"}, Values{"remoteaccess", "wireless", "lan", "mobilebroadband", "mbb", "all"}] String InterfaceTypes[]; + [Write, Description("File Path - Depends on FirewallRuleName")] String FilePath; + [Write, Description("Remote Port Ranges - Depends on FirewallRuleName")] String RemotePortRanges[]; + [Write, Description("Edge Traversal - Depends on FirewallRuleName (0: Disabled, 1: Enabled)"), ValueMap{"0", "1"}, Values{"0", "1"}] String EdgeTraversal; + [Write, Description("Local User Authorized List - Depends on FirewallRuleName")] String LocalUserAuthorizedList[]; + [Write, Description("Network Types - Depends on FirewallRuleName (1: FW_PROFILE_TYPE_DOMAIN: This value represents the profile for networks that are connected to domains., 2: FW_PROFILE_TYPE_STANDARD: This value represents the standard profile for networks. These networks are classified as private by the administrators in the server host. The classification happens the first time the host connects to the network. Usually these networks are behind Network Address Translation (NAT) devices, routers, and other edge devices, and they are in a private location, such as a home or an office. AND FW_PROFILE_TYPE_PRIVATE: This value represents the profile for private networks, which is represented by the same value as that used for FW_PROFILE_TYPE_STANDARD., 4: FW_PROFILE_TYPE_PUBLIC: This value represents the profile for public networks. These networks are classified as public by the administrators in the server host. The classification happens the first time the host connects to the network. Usually these networks are those at airports, coffee shops, and other public places where the peers in the network or the network administrator are not trusted., 2147483647: FW_PROFILE_TYPE_ALL: This value represents all these network sets and any future network sets., -2147483648: FW_PROFILE_TYPE_CURRENT: This value represents the current profiles to which the firewall and advanced security components determine the host is connected at the moment of the call. This value can be specified only in method calls, and it cannot be combined with other flags.)"), ValueMap{"1", "2", "4", "2147483647", "-2147483648"}, Values{"1", "2", "4", "2147483647", "-2147483648"}] SInt32 Profiles[]; + [Write, Description("Local Port Ranges - Depends on FirewallRuleName")] String LocalPortRanges[]; + [Write, Description("Description - Depends on FirewallRuleName")] String Description; + [Write, Description("Package Family Name - Depends on FirewallRuleName")] String PackageFamilyName; + [Write, Description("Local Address Ranges - Depends on FirewallRuleName")] String LocalAddressRanges[]; + [Write, Description("Direction - Depends on FirewallRuleName (in: The rule applies to inbound traffic., out: The rule applies to outbound traffic.)"), ValueMap{"in", "out"}, Values{"in", "out"}] String Direction; + [Write, Description("Service Name - Depends on FirewallRuleName")] String ServiceName; + [Write, Description("Remote Address Ranges - Depends on FirewallRuleName")] String RemoteAddressRanges[]; + [Write, Description("Action - Depends on FirewallRuleName (0: Block, 1: Allow)"), ValueMap{"0", "1"}, Values{"0", "1"}] String Type; + [Write, Description("Protocol - Depends on FirewallRuleName")] SInt32 Protocol; +}; + +[ClassVersion("1.0.0.0"), FriendlyName("IntuneFirewallRulesPolicyWindows10ConfigMgr")] +class MSFT_IntuneFirewallRulesPolicyWindows10ConfigMgr : OMI_BaseResource +{ + [Write, Description("Policy description")] String Description; + [Key, Description("Policy name")] String DisplayName; + [Write, Description("List of Scope Tags for this Entity instance.")] String RoleScopeTagIds[]; + [Write, Description("The unique identifier for an entity. Read-only.")] String Id; + [Write, Description("Firewall Rules"), EmbeddedInstance("MSFT_MicrosoftGraphIntuneSettingsCatalogFirewallRuleName_IntuneFirewallRulesPolicyWindows10ConfigMgr")] String FirewallRuleName[]; + [Write, Description("Represents the assignment to the Intune policy."), EmbeddedInstance("MSFT_DeviceManagementConfigurationPolicyAssignments")] String Assignments[]; + [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; + [Write, Description("Access token used for authentication.")] String AccessTokens[]; +}; diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneFirewallRulesPolicyWindows10ConfigMgr/readme.md b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneFirewallRulesPolicyWindows10ConfigMgr/readme.md new file mode 100644 index 0000000000..2f35dc93a3 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneFirewallRulesPolicyWindows10ConfigMgr/readme.md @@ -0,0 +1,6 @@ + +# IntuneFirewallRulesPolicyWindows10ConfigMgr + +## Description + +Intune Firewall Rules Policy for Windows10 ConfigMgr diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneFirewallRulesPolicyWindows10ConfigMgr/settings.json b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneFirewallRulesPolicyWindows10ConfigMgr/settings.json new file mode 100644 index 0000000000..5f53802e6a --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneFirewallRulesPolicyWindows10ConfigMgr/settings.json @@ -0,0 +1,44 @@ +{ + "resourceName":"IntuneFirewallRulesPolicyWindows10ConfigMgr", + "description":"This resource configures an Intune Firewall Rules Policy for Windows10 ConfigMgr.", + "permissions":{ + "graph":{ + "delegated":{ + "update":[ + { + "name":"DeviceManagementConfiguration.ReadWrite.All" + }, + { + "name":"Group.Read.All" + } + ], + "read":[ + { + "name":"DeviceManagementConfiguration.Read.All" + }, + { + "name":"Group.Read.All" + } + ] + }, + "application":{ + "update":[ + { + "name":"DeviceManagementConfiguration.ReadWrite.All" + }, + { + "name":"Group.Read.All" + } + ], + "read":[ + { + "name":"DeviceManagementConfiguration.Read.All" + }, + { + "name":"Group.Read.All" + } + ] + } + } + } +} \ No newline at end of file diff --git a/Modules/Microsoft365DSC/Examples/Resources/IntuneFirewallRulesPolicyWindows10ConfigMgr/1-Create.ps1 b/Modules/Microsoft365DSC/Examples/Resources/IntuneFirewallRulesPolicyWindows10ConfigMgr/1-Create.ps1 new file mode 100644 index 0000000000..7f5c6fcbd7 --- /dev/null +++ b/Modules/Microsoft365DSC/Examples/Resources/IntuneFirewallRulesPolicyWindows10ConfigMgr/1-Create.ps1 @@ -0,0 +1,56 @@ +<# +This example creates a new Intune Firewall Policy for Windows10. +#> + +Configuration Example +{ + param( + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint + ) + Import-DscResource -ModuleName Microsoft365DSC + + node localhost + { + IntuneFirewallRulesPolicyWindows10ConfigMgr 'myIntuneFirewallRulesPolicyWindows10ConfigMgr' + { + Assignments = @( + MSFT_DeviceManagementConfigurationPolicyAssignments{ + deviceAndAppManagementAssignmentFilterType = 'none' + dataType = '#microsoft.graph.groupAssignmentTarget' + groupId = '11111111-1111-1111-1111-111111111111' + } + ); + FirewallRuleName = @( + MSFT_MicrosoftGraphIntuneSettingsCatalogFirewallRuleName_IntuneFirewallRulesPolicyWindows10ConfigMgr{ + Direction = 'out' + InterfaceTypes = @('lan') + RemotePortRanges = @('0-100') + Name = 'Rule1' + FilePath = 'C:\Temp' + Protocol = 80 + ServiceName = 'mysvc' + Enabled = '1' + Type = '1' + } + ) + Description = 'Description' + DisplayName = "Intune Firewall Rules Policy Windows10 ConfigMgr"; + Ensure = "Present"; + Id = '00000000-0000-0000-0000-000000000000' + RoleScopeTagIds = @("0"); + ApplicationId = $ApplicationId; + TenantId = $TenantId; + CertificateThumbprint = $CertificateThumbprint; + } + } +} diff --git a/Modules/Microsoft365DSC/Examples/Resources/IntuneFirewallRulesPolicyWindows10ConfigMgr/2-Update.ps1 b/Modules/Microsoft365DSC/Examples/Resources/IntuneFirewallRulesPolicyWindows10ConfigMgr/2-Update.ps1 new file mode 100644 index 0000000000..b45c50a141 --- /dev/null +++ b/Modules/Microsoft365DSC/Examples/Resources/IntuneFirewallRulesPolicyWindows10ConfigMgr/2-Update.ps1 @@ -0,0 +1,56 @@ +<# +This example updates a Intune Firewall Policy for Windows10. +#> + +Configuration Example +{ + param( + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint + ) + Import-DscResource -ModuleName Microsoft365DSC + + node localhost + { + IntuneFirewallRulesPolicyWindows10ConfigMgr 'myIntuneFirewallRulesPolicyWindows10ConfigMgr' + { + Assignments = @( + MSFT_DeviceManagementConfigurationPolicyAssignments{ + deviceAndAppManagementAssignmentFilterType = 'none' + dataType = '#microsoft.graph.groupAssignmentTarget' + groupId = '11111111-1111-1111-1111-111111111111' + } + ); + FirewallRuleName = @( + MSFT_MicrosoftGraphIntuneSettingsCatalogFirewallRuleName_IntuneFirewallRulesPolicyWindows10ConfigMgr{ + Direction = 'in' # Updated property + InterfaceTypes = @('lan') + RemotePortRanges = @('0-100') + Name = 'Rule1' + FilePath = 'C:\Temp' + Protocol = 80 + ServiceName = 'mysvc' + Enabled = '1' + Type = '1' + } + ) + Description = 'Description' + DisplayName = "Intune Firewall Rules Policy Windows10 ConfigMgr"; + Ensure = "Present"; + Id = '00000000-0000-0000-0000-000000000000' + RoleScopeTagIds = @("0"); + ApplicationId = $ApplicationId; + TenantId = $TenantId; + CertificateThumbprint = $CertificateThumbprint; + } + } +} diff --git a/Modules/Microsoft365DSC/Examples/Resources/IntuneFirewallRulesPolicyWindows10ConfigMgr/3-Remove.ps1 b/Modules/Microsoft365DSC/Examples/Resources/IntuneFirewallRulesPolicyWindows10ConfigMgr/3-Remove.ps1 new file mode 100644 index 0000000000..adb77ecb27 --- /dev/null +++ b/Modules/Microsoft365DSC/Examples/Resources/IntuneFirewallRulesPolicyWindows10ConfigMgr/3-Remove.ps1 @@ -0,0 +1,34 @@ +<# +This example removes a Device Control Policy. +#> + +Configuration Example +{ + param( + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint + ) + Import-DscResource -ModuleName Microsoft365DSC + + node localhost + { + IntuneFirewallRulesPolicyWindows10ConfigMgr 'myIntuneFirewallRulesPolicyWindows10ConfigMgr' + { + Id = '00000000-0000-0000-0000-000000000000' + DisplayName = 'Intune Firewall Rules Policy Windows10 ConfigMgr' + Ensure = 'Absent' + ApplicationId = $ApplicationId; + TenantId = $TenantId; + CertificateThumbprint = $CertificateThumbprint; + } + } +} diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneFirewallRulesPolicyWindows10ConfigMgr.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneFirewallRulesPolicyWindows10ConfigMgr.Tests.ps1 new file mode 100644 index 0000000000..14506a6da8 --- /dev/null +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneFirewallRulesPolicyWindows10ConfigMgr.Tests.ps1 @@ -0,0 +1,584 @@ +[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 "IntuneFirewallRulesPolicyWindows10ConfigMgr" -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 (New-Guid | Out-String) -AsPlainText -Force + $Credential = New-Object System.Management.Automation.PSCredential ('tenantadmin@mydomain.com', $secpasswd) + + Mock -CommandName Confirm-M365DSCDependencies -MockWith { + } + + Mock -CommandName Get-PSSession -MockWith { + } + + Mock -CommandName Remove-PSSession -MockWith { + } + + Mock -CommandName Update-MgBetaDeviceManagementConfigurationPolicy -MockWith { + } + + Mock -CommandName New-MgBetaDeviceManagementConfigurationPolicy -MockWith { + return @{ + Id = '619bd4a4-3b3b-4441-bd6f-3f4c0c444870' + } + } + + Mock -CommandName Get-MgBetaDeviceManagementConfigurationPolicy -MockWith { + return @{ + Id = '12345-12345-12345-12345-12345' + Description = 'My Test' + Name = 'My Test' + RoleScopeTagIds = @("FakeStringValue") + TemplateReference = @{ + TemplateId = '48da42ed-5df7-485e-8b9d-4844ed5a92bd_1' + } + } + } + + Mock -CommandName Remove-MgBetaDeviceManagementConfigurationPolicy -MockWith { + } + + Mock -CommandName Update-IntuneDeviceConfigurationPolicy -MockWith { + } + + Mock -CommandName Get-IntuneSettingCatalogPolicySetting -MockWith { + } + + Mock -CommandName Get-MgBetaDeviceManagementConfigurationPolicySetting -MockWith { + return @( + @{ + Id = '0' + SettingDefinitions = @( + @{ + Id = 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}' + Name = '{FirewallRuleName}' + OffsetUri = '/MdmStore/FirewallRules/{0}' + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSettingGroupCollectionDefinition' + minimumCount = 0 + maximumCount = 150 + childIds = @( + 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}_firewallrulename' + 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}_direction' + 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}_interfacetypes' + 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}_remoteportranges' + 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}_name' + 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}_app_filepath' + 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}_protocol' + 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}_app_servicename' + 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}_enabled' + 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}_action_type' + ) + } + }, + @{ + Id = 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}_firewallrulename' + Name = 'FirewallRuleName' + OffsetUri = '/MdmStore/FirewallRules/{0}/FirewallRuleName' + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSimpleSettingDefinition' + dependentOn = @( + @{ + dependentOn = 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}' + parentSettingId = 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}' + } + ) + } + }, + @{ + Id = 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}_direction' + Name = 'Direction' + OffsetUri = '/MdmStore/FirewallRules/{0}/Direction' + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingDefinition' + options = @( + @{ + itemId = 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}_direction_out' + name = 'The rule applies to outbound traffic.' + dependentOn = @( + @{ + dependentOn = 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}' + parentSettingId = 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}' + } + ) + } + ) + } + }, + @{ + Id = 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}_interfacetypes' + Name = 'InterfaceTypes' + OffsetUri = '/MdmStore/FirewallRules/{0}/InterfaceTypes' + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingCollectionDefinition' + minimumCount = 0 + maximumCount = 100 + options = @( + @{ + itemId = 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}_interfacetypes_lan' + name = 'Lan' + dependentOn = @( + @{ + dependentOn = 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}' + parentSettingId = 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}' + } + ) + } + ) + } + }, + @{ + Id = 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}_remoteportranges' + Name = 'RemotePortRanges' + OffsetUri = '/MdmStore/FirewallRules/{0}/RemotePortRanges' + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSimpleSettingCollectionDefinition' + minimumCount = 0 + maximumCount = 600 + dependentOn = @( + @{ + dependentOn = 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}' + parentSettingId = 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}' + } + ) + } + }, + @{ + Id = 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}_name' + Name = 'Name' + OffsetUri = '/MdmStore/FirewallRules/{0}/Name' + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSimpleSettingDefinition' + dependentOn = @( + @{ + dependentOn = 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}' + parentSettingId = 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}' + } + ) + } + }, + @{ + Id = 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}_app_filepath' + Name = 'FilePath' + OffsetUri = '/MdmStore/FirewallRules/{0}/App/FilePath' + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSimpleSettingDefinition' + dependentOn = @( + @{ + dependentOn = 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}' + parentSettingId = 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}' + } + ) + } + }, + @{ + Id = 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}_protocol' + Name = 'Protocol' + OffsetUri = '/MdmStore/FirewallRules/{0}/Protocol' + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSimpleSettingDefinition' + dependentOn = @( + @{ + dependentOn = 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}' + parentSettingId = 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}' + } + ) + } + }, + @{ + Id = 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}_app_servicename' + Name = 'ServiceName' + OffsetUri = '/MdmStore/FirewallRules/{0}/App/ServiceName' + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSimpleSettingDefinition' + dependentOn = @( + @{ + dependentOn = 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}' + parentSettingId = 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}' + } + ) + } + }, + @{ + Id = 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}_enabled' + Name = 'Enabled' + OffsetUri = '/MdmStore/FirewallRules/{0}/Enabled' + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingDefinition' + options = @( + @{ + itemId = 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}_enabled_0' + name = 'Enabled' + dependentOn = @( + @{ + dependentOn = 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}' + parentSettingId = 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}' + } + ) + } + ) + } + }, + @{ + Id = 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}_action_type' + Name = 'Type' + OffsetUri = '/MdmStore/FirewallRules/{0}/Action/Type' + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingDefinition' + options = @( + @{ + itemId = 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}_action_type_1' + name = 'Allow' + dependentOn = @( + @{ + dependentOn = 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}' + parentSettingId = 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}' + } + ) + } + ) + } + } + ) + SettingInstance = @{ + SettingDefinitionId = 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}' + SettingInstanceTemplateReference = @{ + SettingInstanceTemplateId = '76c7a8be-67d2-44bf-81a5-38c94926b1a1' + } + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationGroupSettingCollectionInstance' + settingDefinitionId = 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}' + groupSettingCollectionValue = @( + @{ + children = @( + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' + settingDefinitionId = 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}_enabled' + choiceSettingValue = @{ + children = @() + value = 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}_enabled_1' + } + }, + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSimpleSettingInstance' + settingDefinitionId = 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}_name' + simpleSettingValue = @{ + value = '__Test' + } + }, + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingCollectionInstance' + settingDefinitionId = 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}_interfacetypes' + choiceSettingCollectionValue = @( + @{ + children = @() + value = 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}_interfacetypes_lan' + } + ) + }, + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSimpleSettingInstance' + settingDefinitionId = 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}_app_filepath' + simpleSettingValue = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationStringSettingValue' + value = 'C:\Temp\bla2' + } + }, + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSimpleSettingCollectionInstance' + settingDefinitionId = 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}_remoteportranges' + simpleSettingCollectionValue = @( + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationStringSettingValue' + value = '0-100' + } + ) + }, + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' + settingDefinitionId = 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}_direction' + choiceSettingValue = @{ + children = @() + value = 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}_direction_out' + } + }, + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSimpleSettingInstance' + settingDefinitionId = 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}_app_servicename' + simpleSettingValue = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationStringSettingValue' + value = 'mysvc' + } + }, + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' + settingDefinitionId = 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}_action_type' + choiceSettingValue = @{ + children = @() + value = 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}_action_type_1' + } + }, + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSimpleSettingInstance' + settingDefinitionId = 'vendor_msft_firewall_mdmstore_firewallrules_{firewallrulename}_protocol' + simpleSettingValue = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationIntegerSettingValue' + value = 80 + } + } + ) + } + ) + } + } + } + ) + } + + Mock -CommandName Update-DeviceConfigurationPolicyAssignment -MockWith { + } + + Mock -CommandName New-M365DSCConnection -MockWith { + return "Credentials" + } + + # Mock Write-Host to hide output during the tests + Mock -CommandName Write-Host -MockWith { + } + $Script:exportedInstances =$null + $Script:ExportMode = $false + + Mock -CommandName Get-MgBetaDeviceManagementConfigurationPolicyAssignment -MockWith { + return @(@{ + Id = '12345-12345-12345-12345-12345' + Source = 'direct' + SourceId = '12345-12345-12345-12345-12345' + Target = @{ + DeviceAndAppManagementAssignmentFilterId = '12345-12345-12345-12345-12345' + DeviceAndAppManagementAssignmentFilterType = 'none' + AdditionalProperties = @( + @{ + '@odata.type' = '#microsoft.graph.exclusionGroupAssignmentTarget' + groupId = '26d60dd1-fab6-47bf-8656-358194c1a49d' + } + ) + } + }) + } + + } + + # Test contexts + Context -Name "The IntuneFirewallRulesPolicyWindows10ConfigMgr should exist but it DOES NOT" -Fixture { + BeforeAll { + $testParams = @{ + Assignments = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_DeviceManagementConfigurationPolicyAssignments -Property @{ + DataType = '#microsoft.graph.exclusionGroupAssignmentTarget' + groupId = '26d60dd1-fab6-47bf-8656-358194c1a49d' + deviceAndAppManagementAssignmentFilterType = 'none' + } -ClientOnly) + ) + Description = "My Test" + FirewallRuleName = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_MicrosoftGraphIntuneSettingsCatalogFirewallRuleName_IntuneFirewallRulesPolicyWindows10ConfigMgr -Property @{ + Direction = 'out' + InterfaceTypes = @('lan') + RemotePortRanges = @('0-100') + Name = '__Test' + FilePath = 'C:\Temp\bla2' + Protocol = 80 + ServiceName = 'mysvc' + Enabled = '1' + Type = '1' + } -ClientOnly) + ) + Id = "619bd4a4-3b3b-4441-bd6f-3f4c0c444870" + DisplayName = "My Test" + RoleScopeTagIds = @("FakeStringValue") + Ensure = "Present" + Credential = $Credential; + } + + Mock -CommandName Get-MgBetaDeviceManagementConfigurationPolicy -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 + } + It 'Should Create the group from the Set method' { + Set-TargetResource @testParams + Should -Invoke -CommandName New-MgBetaDeviceManagementConfigurationPolicy -Exactly 1 + } + } + + Context -Name "The IntuneFirewallRulesPolicyWindows10ConfigMgr exists but it SHOULD NOT" -Fixture { + BeforeAll { + $testParams = @{ + Assignments = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_DeviceManagementConfigurationPolicyAssignments -Property @{ + DataType = '#microsoft.graph.exclusionGroupAssignmentTarget' + groupId = '26d60dd1-fab6-47bf-8656-358194c1a49d' + deviceAndAppManagementAssignmentFilterType = 'none' + } -ClientOnly) + ) + Description = "My Test" + FirewallRuleName = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_MicrosoftGraphIntuneSettingsCatalogFirewallRuleName_IntuneFirewallRulesPolicyWindows10ConfigMgr -Property @{ + Direction = 'out' + InterfaceTypes = @('lan') + RemotePortRanges = @('0-100') + Name = '__Test' + FilePath = 'C:\Temp\bla2' + Protocol = 80 + ServiceName = 'mysvc' + Enabled = '1' + Type = '1' + } -ClientOnly) + ) + Id = "619bd4a4-3b3b-4441-bd6f-3f4c0c444870" + DisplayName = "My Test" + RoleScopeTagIds = @("FakeStringValue") + Ensure = "Absent" + Credential = $Credential; + } + } + + 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-MgBetaDeviceManagementConfigurationPolicy -Exactly 1 + } + } + + Context -Name "The IntuneFirewallRulesPolicyWindows10ConfigMgr Exists and Values are already in the desired state" -Fixture { + BeforeAll { + $testParams = @{ + Assignments = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_DeviceManagementConfigurationPolicyAssignments -Property @{ + DataType = '#microsoft.graph.exclusionGroupAssignmentTarget' + groupId = '26d60dd1-fab6-47bf-8656-358194c1a49d' + deviceAndAppManagementAssignmentFilterType = 'none' + } -ClientOnly) + ) + Description = "My Test" + FirewallRuleName = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_MicrosoftGraphIntuneSettingsCatalogFirewallRuleName_IntuneFirewallRulesPolicyWindows10ConfigMgr -Property @{ + Direction = 'out' + InterfaceTypes = @('lan') + RemotePortRanges = @('0-100') + Name = '__Test' + FilePath = 'C:\Temp\bla2' + Protocol = 80 + ServiceName = 'mysvc' + Enabled = '1' + Type = '1' + } -ClientOnly) + ) + Id = "619bd4a4-3b3b-4441-bd6f-3f4c0c444870" + DisplayName = "My Test" + RoleScopeTagIds = @("FakeStringValue") + Ensure = "Present" + Credential = $Credential; + } + } + + It 'Should return true from the Test method' { + Test-TargetResource @testParams | Should -Be $true + } + } + + Context -Name "The IntuneFirewallRulesPolicyWindows10ConfigMgr exists and values are NOT in the desired state" -Fixture { + BeforeAll { + $testParams = @{ + Assignments = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_DeviceManagementConfigurationPolicyAssignments -Property @{ + DataType = '#microsoft.graph.exclusionGroupAssignmentTarget' + groupId = '26d60dd1-fab6-47bf-8656-358194c1a49d' + deviceAndAppManagementAssignmentFilterType = 'none' + } -ClientOnly) + ) + Description = "My Test" + FirewallRuleName = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_MicrosoftGraphIntuneSettingsCatalogFirewallRuleName_IntuneFirewallRulesPolicyWindows10ConfigMgr -Property @{ + Direction = 'in' # Drift + InterfaceTypes = @('lan') + RemotePortRanges = @('0-100') + Name = '__Test' + FilePath = 'C:\Temp\bla2' + Protocol = 80 + ServiceName = 'mysvc' + Enabled = '1' + Type = '1' + } -ClientOnly) + ) + Id = "619bd4a4-3b3b-4441-bd6f-3f4c0c444870" + DisplayName = "My Test" + RoleScopeTagIds = @("FakeStringValue") + Ensure = "Present" + 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-IntuneDeviceConfigurationPolicy -Exactly 1 + } + } + + Context -Name 'ReverseDSC Tests' -Fixture { + BeforeAll { + $Global:CurrentModeIsExport = $true + $Global:PartialExportFileName = "$(New-Guid).partial.ps1" + $testParams = @{ + Credential = $Credential + } + } + + 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 5fed672b464e50d16a351c0d37e7c4718d9a479b Mon Sep 17 00:00:00 2001 From: dannyKBjj Date: Thu, 14 Nov 2024 16:46:24 +0000 Subject: [PATCH 18/65] added tests.ps1 --- ...IntuneMobileAppConfigurationPolicyIOS.psm1 | 2 +- ...eMobileAppConfigurationPolicyIOS.Tests.ps1 | 281 ++++++++++++++++++ 2 files changed, 282 insertions(+), 1 deletion(-) create mode 100644 Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneMobileAppConfigurationPolicyIOS.Tests.ps1 diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/MSFT_IntuneMobileAppConfigurationPolicyIOS.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/MSFT_IntuneMobileAppConfigurationPolicyIOS.psm1 index 7349c643b8..bf6fe466f9 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/MSFT_IntuneMobileAppConfigurationPolicyIOS.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/MSFT_IntuneMobileAppConfigurationPolicyIOS.psm1 @@ -99,7 +99,7 @@ function Get-TargetResource try { if (-not [string]::IsNullOrWhiteSpace($id)){ $getValue = Get-MgBetaDeviceAppManagementMobileAppConfiguration -ManagedDeviceMobileAppConfigurationId $id -ErrorAction SilentlyContinue } - + #region resource generator code if ($null -eq $getValue) { diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneMobileAppConfigurationPolicyIOS.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneMobileAppConfigurationPolicyIOS.Tests.ps1 new file mode 100644 index 0000000000..b5c34c57f6 --- /dev/null +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneMobileAppConfigurationPolicyIOS.Tests.ps1 @@ -0,0 +1,281 @@ +[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 'IntuneMobileAppConfigurationPolicyIOS' -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 ((New-Guid).ToString()) -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 Update-MgBetaDeviceAppManagementMobileAppConfiguration -MockWith { + } + + Mock -CommandName New-MgBetaDeviceAppManagementMobileAppConfiguration -MockWith { + } + + Mock -CommandName Remove-MgBetaDeviceAppManagementMobileAppConfiguration -MockWith { + } + + Mock -CommandName Get-MgBetaDeviceManagementDeviceCompliancePolicyAssignment -MockWith { + + return @() + } + Mock -CommandName Update-DeviceConfigurationPolicyAssignment -MockWith { + } + # Mock Write-Host to hide output during the tests + Mock -CommandName Write-Host -MockWith { + } + $Script:exportedInstances =$null + $Script:ExportMode = $false + } + + # Test contexts + Context -Name "When the iOS Mobile App Configuration Policy doesn't already exist" -Fixture { + BeforeAll { + $testParams = @{ + DisplayName = 'Test iOS Mobile App Configuration Policy' + Description = 'Test iOS Mobile App Configuration Policy Description' + targetedMobileApps = "{FakeStringValue}" + settings = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_appConfigurationSettingItem -Property @{ + appConfigKey = "FakeStringValue" + appConfigKeyType = "stringType" + appConfigKeyValue = "FakeStringValue" + } -ClientOnly) + ) + encodedSettingXml = "" + Ensure = 'Present' + Credential = $Credential + } + + Mock -CommandName Get-MgBetaDeviceAppManagementMobileAppConfiguration -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 create the iOS Mobile App Configuration Policy from the Set method' { + Set-TargetResource @testParams + Should -Invoke -CommandName 'New-MgBetaDeviceAppManagementMobileAppConfiguration' -Exactly 1 + } + } + + Context -Name 'When the iOS Mobile App Configuration Policy already exists and is NOT in the Desired State' -Fixture { + BeforeAll { + $testParams = @{ + DisplayName = 'Test iOS Mobile App Configuration Policy' + Description = 'Test iOS Mobile App Configuration Policy Description' + targetedMobileApps = "{FakeStringValue}" + settings = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_appConfigurationSettingItem -Property @{ + appConfigKey = "FakeStringValue" + appConfigKeyType = "stringType" + appConfigKeyValue = "FakeStringValue" + } -ClientOnly) + ) + encodedSettingXml = "" + Ensure = 'Present' + Credential = $Credential + } + + Mock -CommandName Get-MgBetaDeviceAppManagementMobileAppConfiguration -MockWith { + return @{ + DisplayName = 'Test iOS Mobile App Configuration Policy' + Description = 'Different Value' + Id = 'e30954ac-a65e-4dcb-ab79-91d45f3c52b4' + targetedMobileApps = "{FakeStringValue}" + AdditionalProperties = @{ + settings = @( + @{ + appConfigKey = "FakeStringValue" + appConfigKeyType = "stringType" + appConfigKeyValue = "FakeStringValue" + } + ) + encodedSettingXml = "" + '@odata.type' = '#microsoft.graph.iosMobileAppConfiguration' + } + } + } + } + + It 'Should return Present 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 update the iOS Mobile App Configuration Policy from the Set method' { + Set-TargetResource @testParams + Should -Invoke -CommandName Update-MgBetaDeviceAppManagementMobileAppConfiguration -Exactly 1 + + } + } + + Context -Name 'When the policy already exists and IS in the Desired State' -Fixture { + BeforeAll { + $testParams = @{ + DisplayName = 'Test iOS Mobile App Configuration Policy' + Description = 'Test iOS Mobile App Configuration Policy Description' + targetedMobileApps = "{FakeStringValue}" + settings = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_appConfigurationSettingItem -Property @{ + appConfigKey = "FakeStringValue" + appConfigKeyType = "stringType" + appConfigKeyValue = "FakeStringValue" + } -ClientOnly) + ) + encodedSettingXml = "" + Ensure = 'Present' + Credential = $Credential + } + + Mock -CommandName Get-MgBetaDeviceAppManagementMobileAppConfiguration -MockWith { + return @{ + DisplayName = 'Test iOS Mobile App Configuration Policy' + Description = 'Test iOS Mobile App Configuration Policy Description' + Id = 'e30954ac-a65e-4dcb-ab79-91d45f3c52b4' + targetedMobileApps = "{FakeStringValue}" + AdditionalProperties = @{ + settings = @( + @{ + appConfigKey = "FakeStringValue" + appConfigKeyType = "stringType" + appConfigKeyValue = "FakeStringValue" + } + ) + encodedSettingXml = "" + '@odata.type' = '#microsoft.graph.iosMobileAppConfiguration' + } + } + } + } + + It 'Should return true from the Test method' { + Test-TargetResource @testParams | Should -Be $true + } + } + + Context -Name 'When the policy exists and it SHOULD NOT' -Fixture { + BeforeAll { + $testParams = @{ + DisplayName = 'Test iOS Mobile App Configuration Policy' + Description = 'Test iOS Mobile App Configuration Policy Description' + targetedMobileApps = "{FakeStringValue}" + settings = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_appConfigurationSettingItem -Property @{ + appConfigKey = "FakeStringValue" + appConfigKeyType = "stringType" + appConfigKeyValue = "FakeStringValue" + } -ClientOnly) + ) + encodedSettingXml = "" + Ensure = 'Absent' + Credential = $Credential + } + + Mock -CommandName Get-MgBetaDeviceAppManagementMobileAppConfiguration -MockWith { + return @{ + DisplayName = 'Test iOS Mobile App Configuration Policy' + Description = 'Test iOS Mobile App Configuration Policy Description' + Id = 'e30954ac-a65e-4dcb-ab79-91d45f3c52b4' + AdditionalProperties = @{ + targetedMobileApps = "{FakeStringValue}" + settings = @( + @{ + appConfigKey = "FakeStringValue" + appConfigKeyType = "stringType" + appConfigKeyValue = "FakeStringValue" + } + ) + encodedSettingXml = "" + '@odata.type' = '#microsoft.graph.iosMobileAppConfiguration' + } + } + } + } + + 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 remove the iOS Mobile App Configuration Policy from the Set method' { + Set-TargetResource @testParams + Should -Invoke -CommandName Remove-MgBetaDeviceAppManagementMobileAppConfiguration -Exactly 1 + } + } + + Context -Name 'ReverseDSC Tests' -Fixture { + BeforeAll { + $Global:CurrentModeIsExport = $true + $Global:PartialExportFileName = "$(New-Guid).partial.ps1" + $testParams = @{ + Credential = $Credential + } + + Mock -CommandName Get-MgBetaDeviceAppManagementMobileAppConfiguration -MockWith { + return @{ + DisplayName = 'Test iOS Mobile App Configuration Policy' + Description = 'Test iOS Mobile App Configuration Policy Description' + Id = 'e30954ac-a65e-4dcb-ab79-91d45f3c52b4' + targetedMobileApps = "{FakeStringValue}" + AdditionalProperties = @{ + settings = @( + @{ + appConfigKey = "FakeStringValue" + appConfigKeyType = "stringType" + appConfigKeyValue = "FakeStringValue" + } + ) + encodedSettingXml = "" + '@odata.type' = '#microsoft.graph.iosMobileAppConfiguration' + } + } + } + } + + It 'Should Reverse Engineer resource from the Export method' { + $result = Export-TargetResource @testParams + $result | Should -Not -BeNullOrEmpty + } + } + } +} + +Invoke-Command -ScriptBlock $Global:DscHelper.CleanupScript -NoNewScope \ No newline at end of file From 0fb436a66e98ce4150aebe2edae66f6c6e8269ed Mon Sep 17 00:00:00 2001 From: dannyKBjj Date: Thu, 14 Nov 2024 17:32:04 +0000 Subject: [PATCH 19/65] added examples create,update and remove examples added --- .../1-Create.ps1 | 49 +++++++++++++++++++ .../2-Update.ps1 | 46 +++++++++++++++++ .../3-Remove.ps1 | 36 ++++++++++++++ 3 files changed, 131 insertions(+) create mode 100644 Modules/Microsoft365DSC/Examples/Resources/IntuneMobileAppConfigurationPolicyIOS/1-Create.ps1 create mode 100644 Modules/Microsoft365DSC/Examples/Resources/IntuneMobileAppConfigurationPolicyIOS/2-Update.ps1 create mode 100644 Modules/Microsoft365DSC/Examples/Resources/IntuneMobileAppConfigurationPolicyIOS/3-Remove.ps1 diff --git a/Modules/Microsoft365DSC/Examples/Resources/IntuneMobileAppConfigurationPolicyIOS/1-Create.ps1 b/Modules/Microsoft365DSC/Examples/Resources/IntuneMobileAppConfigurationPolicyIOS/1-Create.ps1 new file mode 100644 index 0000000000..3a7985ec2b --- /dev/null +++ b/Modules/Microsoft365DSC/Examples/Resources/IntuneMobileAppConfigurationPolicyIOS/1-Create.ps1 @@ -0,0 +1,49 @@ +<# +This example creates a new Intune Mobile App Configuration Policy for iOs devices +#> + +Configuration Example +{ + param( + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint + ) + + + Import-DscResource -ModuleName 'Microsoft365DSC' + + Node localhost + { + IntuneMobileAppConfigurationPolicyIOS "ConfigureIntuneMobileAppConfigurationPolicyIOS" + { + Description = "IntuneMobileAppConfigurationPolicyIOS Description"; + DisplayName = "IntuneMobileAppConfigurationPolicyIOS DisplayName"; + Ensure = "Present"; + settings = @( + MSFT_appConfigurationSettingItem{ + appConfigKey = 'ConfigKey1' + appConfigKeyType = 'stringType' + appConfigKeyValue = 'KeyValue1' + } + MSFT_appConfigurationSettingItem{ + appConfigKey = 'ConfigKey2' + appConfigKeyType = 'stringType' + appConfigKeyValue = 'keyValue2' + } + ); + targetedMobileApps = @("06131066-8adf-42a9-86aa-e4b59e27da5d"); + ApplicationId = $ApplicationId; + TenantId = $TenantId; + CertificateThumbprint = $CertificateThumbprint; + } + } +} diff --git a/Modules/Microsoft365DSC/Examples/Resources/IntuneMobileAppConfigurationPolicyIOS/2-Update.ps1 b/Modules/Microsoft365DSC/Examples/Resources/IntuneMobileAppConfigurationPolicyIOS/2-Update.ps1 new file mode 100644 index 0000000000..93d0a39b85 --- /dev/null +++ b/Modules/Microsoft365DSC/Examples/Resources/IntuneMobileAppConfigurationPolicyIOS/2-Update.ps1 @@ -0,0 +1,46 @@ +<# +This example creates a new Intune Mobile App Configuration Policy for iOs devices +#> + +Configuration Example +{ + param( + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint + ) + + Node localhost + { + IntuneMobileAppConfigurationPolicyIOS "ConfigureIntuneMobileAppConfigurationPolicyIOS" + { + Description = "IntuneMobileAppConfigurationPolicyIOS Description"; + DisplayName = "IntuneMobileAppConfigurationPolicyIOS DisplayName"; + Ensure = "Present"; + settings = @( + MSFT_appConfigurationSettingItem{ + appConfigKey = 'ConfigKey1' + appConfigKeyType = 'stringType' + appConfigKeyValue = 'KeyValue1 updated' #updated property + } + MSFT_appConfigurationSettingItem{ + appConfigKey = 'ConfigKey2' + appConfigKeyType = 'stringType' + appConfigKeyValue = 'keyValue2' + } + ); + targetedMobileApps = @("06131066-8adf-42a9-86aa-e4b59e27da5d"); + ApplicationId = $ApplicationId; + TenantId = $TenantId; + CertificateThumbprint = $CertificateThumbprint; + } + } +} diff --git a/Modules/Microsoft365DSC/Examples/Resources/IntuneMobileAppConfigurationPolicyIOS/3-Remove.ps1 b/Modules/Microsoft365DSC/Examples/Resources/IntuneMobileAppConfigurationPolicyIOS/3-Remove.ps1 new file mode 100644 index 0000000000..83d7603515 --- /dev/null +++ b/Modules/Microsoft365DSC/Examples/Resources/IntuneMobileAppConfigurationPolicyIOS/3-Remove.ps1 @@ -0,0 +1,36 @@ +<# +This example creates a new Intune Mobile App Configuration Policy for iOs devices +#> + +Configuration Example +{ + param( + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint + ) + + + Import-DscResource -ModuleName 'Microsoft365DSC' + + Node localhost + { + IntuneMobileAppConfigurationPolicyIOS "ConfigureIntuneMobileAppConfigurationPolicyIOS" + { + Description = "IntuneMobileAppConfigurationPolicyIOS Description"; + DisplayName = "IntuneMobileAppConfigurationPolicyIOS DisplayName"; + Ensure = "Absent"; + ApplicationId = $ApplicationId; + TenantId = $TenantId; + CertificateThumbprint = $CertificateThumbprint; + } + } +} From 9cbc80ccac9a6a68599bd61231de70263160e4a2 Mon Sep 17 00:00:00 2001 From: Fabien Tschanz Date: Fri, 15 Nov 2024 13:35:36 +0100 Subject: [PATCH 20/65] Add Intune Disk Encryption for Personal Data Encryption Windows 10 --- CHANGELOG.md | 2 + ...ntuneDiskEncryptionPDEPolicyWindows10.psm1 | 653 ++++++++++++++++++ ...iskEncryptionPDEPolicyWindows10.schema.mof | 33 + .../readme.md | 6 + .../settings.json | 44 ++ .../1-Create.ps1 | 41 ++ .../2-Update.ps1 | 41 ++ .../3-Remove.ps1 | 34 + ...DiskEncryptionPDEPolicyWindows10.Tests.ps1 | 379 ++++++++++ 9 files changed, 1233 insertions(+) create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDiskEncryptionPDEPolicyWindows10/MSFT_IntuneDiskEncryptionPDEPolicyWindows10.psm1 create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDiskEncryptionPDEPolicyWindows10/MSFT_IntuneDiskEncryptionPDEPolicyWindows10.schema.mof create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDiskEncryptionPDEPolicyWindows10/readme.md create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDiskEncryptionPDEPolicyWindows10/settings.json create mode 100644 Modules/Microsoft365DSC/Examples/Resources/IntuneDiskEncryptionPDEPolicyWindows10/1-Create.ps1 create mode 100644 Modules/Microsoft365DSC/Examples/Resources/IntuneDiskEncryptionPDEPolicyWindows10/2-Update.ps1 create mode 100644 Modules/Microsoft365DSC/Examples/Resources/IntuneDiskEncryptionPDEPolicyWindows10/3-Remove.ps1 create mode 100644 Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneDiskEncryptionPDEPolicyWindows10.Tests.ps1 diff --git a/CHANGELOG.md b/CHANGELOG.md index 3380151965..3457a840c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ * AADRoleEligibilityScheduleRequest * Adds support for custom role assignments at app scope. +* IntuneDiskEncryptionPDEPolicyWindows10 + * Initial release. * IntuneFirewallRulesHyperVPolicyWindows10 * Initial release. * M365DSCDRGUtil diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDiskEncryptionPDEPolicyWindows10/MSFT_IntuneDiskEncryptionPDEPolicyWindows10.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDiskEncryptionPDEPolicyWindows10/MSFT_IntuneDiskEncryptionPDEPolicyWindows10.psm1 new file mode 100644 index 0000000000..c58bc20a13 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDiskEncryptionPDEPolicyWindows10/MSFT_IntuneDiskEncryptionPDEPolicyWindows10.psm1 @@ -0,0 +1,653 @@ +function Get-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + param + ( + #region resource generator code + [Parameter()] + [System.String] + $Description, + + [Parameter(Mandatory = $true)] + [System.String] + $DisplayName, + + [Parameter()] + [System.String[]] + $RoleScopeTagIds, + + [Parameter()] + [System.String] + $Id, + + [Parameter()] + [ValidateSet('0', '1')] + [System.String] + $EnablePersonalDataEncryption, + + [Parameter()] + [ValidateSet('0', '1')] + [System.String] + $ProtectDesktop, + + [Parameter()] + [ValidateSet('0', '1')] + [System.String] + $ProtectPictures, + + [Parameter()] + [ValidateSet('0', '1')] + [System.String] + $ProtectDocuments, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $Assignments, + #endregion + + [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, + + [Parameter()] + [System.String[]] + $AccessTokens + ) + + 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 + #region resource generator code + $getValue = Get-MgBetaDeviceManagementConfigurationPolicy -DeviceManagementConfigurationPolicyId $Id -ErrorAction SilentlyContinue + + if ($null -eq $getValue) + { + Write-Verbose -Message "Could not find an Intune Disk Encryption PDE Policy for Windows10 with Id {$Id}" + + if (-not [System.String]::IsNullOrEmpty($DisplayName)) + { + $getValue = Get-MgBetaDeviceManagementConfigurationPolicy ` + -Filter "Name eq '$DisplayName'" ` + -All ` + -ErrorAction SilentlyContinue + } + } + #endregion + if ($null -eq $getValue) + { + Write-Verbose -Message "Could not find an Intune Disk Encryption PDE Policy for Windows10 with Name {$DisplayName}." + return $nullResult + } + $Id = $getValue.Id + Write-Verbose -Message "An Intune Disk Encryption PDE Policy for Windows10 with Id {$Id} and Name {$DisplayName} was found" + + # Retrieve policy specific settings + [array]$settings = Get-MgBetaDeviceManagementConfigurationPolicySetting ` + -DeviceManagementConfigurationPolicyId $Id ` + -ExpandProperty 'settingDefinitions' ` + -All ` + -ErrorAction Stop + + $policySettings = @{} + $policySettings = Export-IntuneSettingCatalogPolicySettings -Settings $settings -ReturnHashtable $policySettings + + $results = @{ + #region resource generator code + Description = $getValue.Description + DisplayName = $getValue.Name + RoleScopeTagIds = $getValue.RoleScopeTagIds + Id = $getValue.Id + Ensure = 'Present' + Credential = $Credential + ApplicationId = $ApplicationId + TenantId = $TenantId + ApplicationSecret = $ApplicationSecret + CertificateThumbprint = $CertificateThumbprint + ManagedIdentity = $ManagedIdentity.IsPresent + #endregion + } + $results += $policySettings + + $assignmentsValues = Get-MgBetaDeviceManagementConfigurationPolicyAssignment -DeviceManagementConfigurationPolicyId $Id + $assignmentResult = @() + if ($assignmentsValues.Count -gt 0) + { + $assignmentResult += ConvertFrom-IntunePolicyAssignment -Assignments $assignmentsValues -IncludeDeviceFilter $true + } + $results.Add('Assignments', $assignmentResult) + + 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()] + [System.String] + $Description, + + [Parameter(Mandatory = $true)] + [System.String] + $DisplayName, + + [Parameter()] + [System.String[]] + $RoleScopeTagIds, + + [Parameter()] + [System.String] + $Id, + + [Parameter()] + [ValidateSet('0', '1')] + [System.String] + $EnablePersonalDataEncryption, + + [Parameter()] + [ValidateSet('0', '1')] + [System.String] + $ProtectDesktop, + + [Parameter()] + [ValidateSet('0', '1')] + [System.String] + $ProtectPictures, + + [Parameter()] + [ValidateSet('0', '1')] + [System.String] + $ProtectDocuments, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $Assignments, + #endregion + [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, + + [Parameter()] + [System.String[]] + $AccessTokens + ) + + #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 + + $templateReferenceId = '0b5708d9-9bc2-49a9-b4f7-ec463fcc41e0_1' + $platforms = 'windows10' + $technologies = 'mdm' + + if ($Ensure -eq 'Present' -and $currentInstance.Ensure -eq 'Absent') + { + Write-Verbose -Message "Creating an Intune Disk Encryption PDE Policy for Windows10 with Name {$DisplayName}" + $BoundParameters.Remove("Assignments") | Out-Null + + $settings = Get-IntuneSettingCatalogPolicySetting ` + -DSCParams ([System.Collections.Hashtable]$BoundParameters) ` + -TemplateId $templateReferenceId + + $createParameters = @{ + Name = $DisplayName + Description = $Description + TemplateReference = @{ templateId = $templateReferenceId } + Platforms = $platforms + Technologies = $technologies + Settings = $settings + } + + #region resource generator code + $policy = New-MgBetaDeviceManagementConfigurationPolicy -BodyParameter $createParameters + + if ($policy.Id) + { + $assignmentsHash = ConvertTo-IntunePolicyAssignment -IncludeDeviceFilter:$true -Assignments $Assignments + Update-DeviceConfigurationPolicyAssignment ` + -DeviceConfigurationPolicyId $policy.Id ` + -Targets $assignmentsHash ` + -Repository 'deviceManagement/configurationPolicies' + } + #endregion + } + elseif ($Ensure -eq 'Present' -and $currentInstance.Ensure -eq 'Present') + { + Write-Verbose -Message "Updating the Intune Disk Encryption PDE Policy for Windows10 with Id {$($currentInstance.Id)}" + $BoundParameters.Remove("Assignments") | Out-Null + + $settings = Get-IntuneSettingCatalogPolicySetting ` + -DSCParams ([System.Collections.Hashtable]$BoundParameters) ` + -TemplateId $templateReferenceId + + Update-IntuneDeviceConfigurationPolicy ` + -DeviceConfigurationPolicyId $currentInstance.Id ` + -Name $DisplayName ` + -Description $Description ` + -TemplateReferenceId $templateReferenceId ` + -Platforms $platforms ` + -Technologies $technologies ` + -Settings $settings + + #region resource generator code + $assignmentsHash = ConvertTo-IntunePolicyAssignment -IncludeDeviceFilter:$true -Assignments $Assignments + Update-DeviceConfigurationPolicyAssignment ` + -DeviceConfigurationPolicyId $currentInstance.Id ` + -Targets $assignmentsHash ` + -Repository 'deviceManagement/configurationPolicies' + #endregion + } + elseif ($Ensure -eq 'Absent' -and $currentInstance.Ensure -eq 'Present') + { + Write-Verbose -Message "Removing the Intune Disk Encryption PDE Policy for Windows10 with Id {$($currentInstance.Id)}" + #region resource generator code + Remove-MgBetaDeviceManagementConfigurationPolicy -DeviceManagementConfigurationPolicyId $currentInstance.Id + #endregion + } +} + +function Test-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Boolean])] + param + ( + #region resource generator code + [Parameter()] + [System.String] + $Description, + + [Parameter(Mandatory = $true)] + [System.String] + $DisplayName, + + [Parameter()] + [System.String[]] + $RoleScopeTagIds, + + [Parameter()] + [System.String] + $Id, + + [Parameter()] + [ValidateSet('0', '1')] + [System.String] + $EnablePersonalDataEncryption, + + [Parameter()] + [ValidateSet('0', '1')] + [System.String] + $ProtectDesktop, + + [Parameter()] + [ValidateSet('0', '1')] + [System.String] + $ProtectPictures, + + [Parameter()] + [ValidateSet('0', '1')] + [System.String] + $ProtectDocuments, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $Assignments, + #endregion + + [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, + + [Parameter()] + [System.String[]] + $AccessTokens + ) + + #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 Intune Disk Encryption PDE Policy for Windows10 with Id {$Id} and Name {$DisplayName}" + + $CurrentValues = Get-TargetResource @PSBoundParameters + [Hashtable]$ValuesToCheck = @{} + $MyInvocation.MyCommand.Parameters.GetEnumerator() | ForEach-Object { + if ($_.Key -notlike '*Variable' -or $_.Key -notin @('Verbose', 'Debug', 'ErrorAction', 'WarningAction', 'InformationAction')) + { + if ($null -ne $CurrentValues[$_.Key] -or $null -ne $PSBoundParameters[$_.Key]) + { + $ValuesToCheck.Add($_.Key, $null) + if (-not $PSBoundParameters.ContainsKey($_.Key)) + { + $PSBoundParameters.Add($_.Key, $null) + } + } + } + } + + if ($CurrentValues.Ensure -ne $Ensure) + { + Write-Verbose -Message "Test-TargetResource returned $false" + return $false + } + $testResult = $true + + #Compare Cim instances + foreach ($key in $PSBoundParameters.Keys) + { + $source = $PSBoundParameters.$key + $target = $CurrentValues.$key + if ($null -ne $source -and $source.GetType().Name -like '*CimInstance*') + { + $testResult = Compare-M365DSCComplexObject ` + -Source ($source) ` + -Target ($target) + + if (-not $testResult) + { + break + } + + $ValuesToCheck.Remove($key) | Out-Null + } + } + + $ValuesToCheck.Remove('Id') | Out-Null + $ValuesToCheck = Remove-M365DSCAuthenticationParameter -BoundParameters $ValuesToCheck + + Write-Verbose -Message "Current Values: $(Convert-M365DscHashtableToString -Hashtable $CurrentValues)" + Write-Verbose -Message "Target Values: $(Convert-M365DscHashtableToString -Hashtable $PSBoundParameters)" + + if ($testResult) + { + $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.String] + $Filter, + + [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, + + [Parameter()] + [System.String[]] + $AccessTokens + ) + + $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 + $policyTemplateID = "0b5708d9-9bc2-49a9-b4f7-ec463fcc41e0_1" + [array]$getValue = Get-MgBetaDeviceManagementConfigurationPolicy ` + -Filter $Filter ` + -All ` + -ErrorAction Stop | Where-Object ` + -FilterScript { + $_.TemplateReference.TemplateId -eq $policyTemplateID + } + #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 + if (-not [String]::IsNullOrEmpty($config.displayName)) + { + $displayedKey = $config.displayName + } + elseif (-not [string]::IsNullOrEmpty($config.name)) + { + $displayedKey = $config.name + } + Write-Host " |---[$i/$($getValue.Count)] $displayedKey" -NoNewline + $params = @{ + Id = $config.Id + DisplayName = $config.Name + Ensure = 'Present' + Credential = $Credential + ApplicationId = $ApplicationId + TenantId = $TenantId + ApplicationSecret = $ApplicationSecret + CertificateThumbprint = $CertificateThumbprint + ManagedIdentity = $ManagedIdentity.IsPresent + AccessTokens = $AccessTokens + } + + $Results = Get-TargetResource @Params + $Results = Update-M365DSCExportAuthenticationResults -ConnectionMode $ConnectionMode ` + -Results $Results + + if ($Results.Assignments) + { + $complexTypeStringResult = Get-M365DSCDRGComplexTypeToString -ComplexObject $Results.Assignments -CIMInstanceName DeviceManagementConfigurationPolicyAssignments + if ($complexTypeStringResult) + { + $Results.Assignments = $complexTypeStringResult + } + else + { + $Results.Remove('Assignments') | Out-Null + } + } + + $currentDSCBlock = Get-M365DSCExportContentForResource -ResourceName $ResourceName ` + -ConnectionMode $ConnectionMode ` + -ModulePath $PSScriptRoot ` + -Results $Results ` + -Credential $Credential + + if ($Results.Assignments) + { + $currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock -ParameterName "Assignments" -IsCIMArray:$true + } + + $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_IntuneDiskEncryptionPDEPolicyWindows10/MSFT_IntuneDiskEncryptionPDEPolicyWindows10.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDiskEncryptionPDEPolicyWindows10/MSFT_IntuneDiskEncryptionPDEPolicyWindows10.schema.mof new file mode 100644 index 0000000000..5147f6369a --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDiskEncryptionPDEPolicyWindows10/MSFT_IntuneDiskEncryptionPDEPolicyWindows10.schema.mof @@ -0,0 +1,33 @@ +[ClassVersion("1.0.0.0")] +class MSFT_DeviceManagementConfigurationPolicyAssignments +{ + [Write, Description("The type of the target assignment."), ValueMap{"#microsoft.graph.groupAssignmentTarget","#microsoft.graph.allLicensedUsersAssignmentTarget","#microsoft.graph.allDevicesAssignmentTarget","#microsoft.graph.exclusionGroupAssignmentTarget","#microsoft.graph.configurationManagerCollectionAssignmentTarget"}, Values{"#microsoft.graph.groupAssignmentTarget","#microsoft.graph.allLicensedUsersAssignmentTarget","#microsoft.graph.allDevicesAssignmentTarget","#microsoft.graph.exclusionGroupAssignmentTarget","#microsoft.graph.configurationManagerCollectionAssignmentTarget"}] String dataType; + [Write, Description("The type of filter of the target assignment i.e. Exclude or Include. Possible values are:none, include, exclude."), ValueMap{"none","include","exclude"}, Values{"none","include","exclude"}] String deviceAndAppManagementAssignmentFilterType; + [Write, Description("The Id of the filter for the target assignment.")] String deviceAndAppManagementAssignmentFilterId; + [Write, Description("The group Id that is the target of the assignment.")] String groupId; + [Write, Description("The group Display Name that is the target of the assignment.")] String groupDisplayName; + [Write, Description("The collection Id that is the target of the assignment.(ConfigMgr)")] String collectionId; +}; + + +[ClassVersion("1.0.0.0"), FriendlyName("IntuneDiskEncryptionPDEPolicyWindows10")] +class MSFT_IntuneDiskEncryptionPDEPolicyWindows10 : OMI_BaseResource +{ + [Write, Description("Policy description")] String Description; + [Key, Description("Policy name")] String DisplayName; + [Write, Description("List of Scope Tags for this Entity instance.")] String RoleScopeTagIds[]; + [Write, Description("The unique identifier for an entity. Read-only.")] String Id; + [Write, Description("Enable Personal Data Encryption (User) (0: Disable Personal Data Encryption., 1: Enable Personal Data Encryption.)"), ValueMap{"0", "1"}, Values{"0", "1"}] String EnablePersonalDataEncryption; + [Write, Description("Protect Desktop (User) (Windows Insiders only) - Depends on EnablePersonalDataEncryption (0: Disable PDE on the folder. If the folder is currently protected by PDE, this will result in unprotecting the folder., 1: Enable PDE on the folder.)"), ValueMap{"0", "1"}, Values{"0", "1"}] String ProtectDesktop; + [Write, Description("Protect Pictures (User) (Windows Insiders only) - Depends on EnablePersonalDataEncryption (0: Disable PDE on the folder. If the folder is currently protected by PDE, this will result in unprotecting the folder., 1: Enable PDE on the folder.)"), ValueMap{"0", "1"}, Values{"0", "1"}] String ProtectPictures; + [Write, Description("Protect Documents (User) (Windows Insiders only) - Depends on EnablePersonalDataEncryption (0: Disable PDE on the folder. If the folder is currently protected by PDE, this will result in unprotecting the folder., 1: Enable PDE on the folder.)"), ValueMap{"0", "1"}, Values{"0", "1"}] String ProtectDocuments; + [Write, Description("Represents the assignment to the Intune policy."), EmbeddedInstance("MSFT_DeviceManagementConfigurationPolicyAssignments")] String Assignments[]; + [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; + [Write, Description("Access token used for authentication.")] String AccessTokens[]; +}; diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDiskEncryptionPDEPolicyWindows10/readme.md b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDiskEncryptionPDEPolicyWindows10/readme.md new file mode 100644 index 0000000000..baa0279ae1 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDiskEncryptionPDEPolicyWindows10/readme.md @@ -0,0 +1,6 @@ + +# IntuneDiskEncryptionPDEPolicyWindows10 + +## Description + +Intune Disk Encryption Personal Data Encryption Policy for Windows10 diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDiskEncryptionPDEPolicyWindows10/settings.json b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDiskEncryptionPDEPolicyWindows10/settings.json new file mode 100644 index 0000000000..ff57f9891a --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDiskEncryptionPDEPolicyWindows10/settings.json @@ -0,0 +1,44 @@ +{ + "resourceName":"IntuneDiskEncryptionPDEPolicyWindows10", + "description":"This resource configures an Intune Disk Encryption P D E Policy for Windows10.", + "permissions":{ + "graph":{ + "application":{ + "update":[ + { + "name":"DeviceManagementConfiguration.ReadWrite.All" + }, + { + "name":"Group.Read.All" + } + ], + "read":[ + { + "name":"DeviceManagementConfiguration.Read.All" + }, + { + "name":"Group.Read.All" + } + ] + }, + "delegated":{ + "update":[ + { + "name":"DeviceManagementConfiguration.ReadWrite.All" + }, + { + "name":"Group.Read.All" + } + ], + "read":[ + { + "name":"DeviceManagementConfiguration.Read.All" + }, + { + "name":"Group.Read.All" + } + ] + } + } + } +} \ No newline at end of file diff --git a/Modules/Microsoft365DSC/Examples/Resources/IntuneDiskEncryptionPDEPolicyWindows10/1-Create.ps1 b/Modules/Microsoft365DSC/Examples/Resources/IntuneDiskEncryptionPDEPolicyWindows10/1-Create.ps1 new file mode 100644 index 0000000000..7424a7a585 --- /dev/null +++ b/Modules/Microsoft365DSC/Examples/Resources/IntuneDiskEncryptionPDEPolicyWindows10/1-Create.ps1 @@ -0,0 +1,41 @@ +<# +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()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint + ) + Import-DscResource -ModuleName Microsoft365DSC + + node localhost + { + IntuneDiskEncryptionPDEPolicyWindows10 "IntuneDiskEncryptionPDEPolicyWindows10" + { + Assignments = @(); + Description = "test"; + DisplayName = "test"; + Ensure = "Present"; + EnablePersonalDataEncryption = "1"; + ProtectDesktop = "0"; + ProtectDocuments = "0"; + ProtectPictures = "0"; + RoleScopeTagIds = @("0"); + ApplicationId = $ApplicationId; + TenantId = $TenantId; + CertificateThumbprint = $CertificateThumbprint; + } + } +} diff --git a/Modules/Microsoft365DSC/Examples/Resources/IntuneDiskEncryptionPDEPolicyWindows10/2-Update.ps1 b/Modules/Microsoft365DSC/Examples/Resources/IntuneDiskEncryptionPDEPolicyWindows10/2-Update.ps1 new file mode 100644 index 0000000000..c1cf50e0b5 --- /dev/null +++ b/Modules/Microsoft365DSC/Examples/Resources/IntuneDiskEncryptionPDEPolicyWindows10/2-Update.ps1 @@ -0,0 +1,41 @@ +<# +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()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint + ) + Import-DscResource -ModuleName Microsoft365DSC + + node localhost + { + IntuneDiskEncryptionPDEPolicyWindows10 "IntuneDiskEncryptionPDEPolicyWindows10" + { + Assignments = @(); + Description = "test"; + DisplayName = "test"; + Ensure = "Present"; + EnablePersonalDataEncryption = "1"; + ProtectDesktop = "0"; + ProtectDocuments = "1"; # Updated property + ProtectPictures = "1"; # Updated property + RoleScopeTagIds = @("0"); + ApplicationId = $ApplicationId; + TenantId = $TenantId; + CertificateThumbprint = $CertificateThumbprint; + } + } +} diff --git a/Modules/Microsoft365DSC/Examples/Resources/IntuneDiskEncryptionPDEPolicyWindows10/3-Remove.ps1 b/Modules/Microsoft365DSC/Examples/Resources/IntuneDiskEncryptionPDEPolicyWindows10/3-Remove.ps1 new file mode 100644 index 0000000000..3ec5e50a48 --- /dev/null +++ b/Modules/Microsoft365DSC/Examples/Resources/IntuneDiskEncryptionPDEPolicyWindows10/3-Remove.ps1 @@ -0,0 +1,34 @@ +<# +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()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint + ) + Import-DscResource -ModuleName Microsoft365DSC + + node localhost + { + IntuneDiskEncryptionPDEPolicyWindows10 "IntuneDiskEncryptionPDEPolicyWindows10" + { + DisplayName = "test"; + Ensure = "Absent"; + ApplicationId = $ApplicationId; + TenantId = $TenantId; + CertificateThumbprint = $CertificateThumbprint; + } + } +} diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneDiskEncryptionPDEPolicyWindows10.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneDiskEncryptionPDEPolicyWindows10.Tests.ps1 new file mode 100644 index 0000000000..0d4905e4bf --- /dev/null +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneDiskEncryptionPDEPolicyWindows10.Tests.ps1 @@ -0,0 +1,379 @@ +[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 "IntuneDiskEncryptionPDEPolicyWindows10" -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 (New-Guid | Out-String) -AsPlainText -Force + $Credential = New-Object System.Management.Automation.PSCredential ('tenantadmin@mydomain.com', $secpasswd) + + Mock -CommandName Confirm-M365DSCDependencies -MockWith { + } + + Mock -CommandName Get-PSSession -MockWith { + } + + Mock -CommandName Remove-PSSession -MockWith { + } + + Mock -CommandName Update-MgBetaDeviceManagementConfigurationPolicy -MockWith { + } + + Mock -CommandName New-MgBetaDeviceManagementConfigurationPolicy -MockWith { + return @{ + Id = '12345-12345-12345-12345-12345' + } + } + + Mock -CommandName Remove-MgBetaDeviceManagementConfigurationPolicy -MockWith { + } + + Mock -CommandName Get-MgBetaDeviceManagementConfigurationPolicy -MockWith { + return @{ + Id = '12345-12345-12345-12345-12345' + Description = 'My Test' + Name = 'My Test' + RoleScopeTagIds = @("FakeStringValue") + TemplateReference = @{ + TemplateId = '0b5708d9-9bc2-49a9-b4f7-ec463fcc41e0_1' + } + } + } + + Mock -CommandName Update-IntuneDeviceConfigurationPolicy -MockWith { + } + + Mock -CommandName Get-IntuneSettingCatalogPolicySetting -MockWith { + } + + Mock -CommandName Get-MgBetaDeviceManagementConfigurationPolicySetting -MockWith { + return @( + @{ + Id = '0' + SettingDefinitions = @( + @{ + Id = 'user_vendor_msft_pde_enablepersonaldataencryption' + Name = 'EnablePersonalDataEncryption' + OffsetUri = '/EnablePersonalDataEncryption' + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingDefinition' + options = @( + @{ + name = 'Enable Personal Data Encryption.' + itemId = 'user_vendor_msft_pde_enablepersonaldataencryption_1' + } + ) + } + }, + @{ + Id = 'user_vendor_msft_pde_protectfolders_protectdesktop' + Name = 'ProtectDesktop' + OffsetUri = '/ProtectFolders/ProtectDesktop' + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingDefinition' + options = @( + @{ + name = 'Disable PDE on the folder. If the folder is currently protected by PDE, this will result in unprotecting the folder.' + itemId = 'user_vendor_msft_pde_protectfolders_protectdesktop_0' + dependentOn = @( + @{ + dependentOn = 'user_vendor_msft_pde_enablepersonaldataencryption_1' + parentSettingId = 'user_vendor_msft_pde_enablepersonaldataencryption' + } + ) + } + ) + } + }, + @{ + Id = 'user_vendor_msft_pde_protectfolders_protectpictures' + Name = 'ProtectPictures' + OffsetUri = '/ProtectFolders/ProtectPictures' + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingDefinition' + options = @( + @{ + name = 'Disable PDE on the folder. If the folder is currently protected by PDE, this will result in unprotecting the folder.' + itemId = 'user_vendor_msft_pde_protectfolders_protectpictures_0' + dependentOn = @( + @{ + dependentOn = 'user_vendor_msft_pde_enablepersonaldataencryption_1' + parentSettingId = 'user_vendor_msft_pde_enablepersonaldataencryption' + } + ) + } + ) + } + }, + @{ + Id = 'user_vendor_msft_pde_protectfolders_protectdocuments' + Name = 'ProtectDocuments' + OffsetUri = '/ProtectFolders/ProtectDocuments' + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingDefinition' + options = @( + @{ + name = 'Disable PDE on the folder. If the folder is currently protected by PDE, this will result in unprotecting the folder.' + itemId = 'user_vendor_msft_pde_protectfolders_protectdocuments_1' + dependentOn = @( + @{ + dependentOn = 'user_vendor_msft_pde_enablepersonaldataencryption_1' + parentSettingId = 'user_vendor_msft_pde_enablepersonaldataencryption' + } + ) + } + ) + } + } + ) + SettingInstance = @{ + SettingDefinitionId = 'user_vendor_msft_pde_enablepersonaldataencryption' + SettingInstanceTemplateReference = @{ + SettingInstanceTemplateId = '1ba5dce6-3ba0-40f3-bde3-811ed766c14a' + } + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' + choiceSettingValue = @{ + value = 'user_vendor_msft_pde_enablepersonaldataencryption_1' + children = @( + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' + settingDefinitionId = 'user_vendor_msft_pde_protectfolders_protectdesktop' + choiceSettingValue = @{ + children = @() + value = 'user_vendor_msft_pde_protectfolders_protectdesktop_0' + } + }, + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' + settingDefinitionId = 'user_vendor_msft_pde_protectfolders_protectpictures' + choiceSettingValue = @{ + children = @() + value = 'user_vendor_msft_pde_protectfolders_protectpictures_0' + } + }, + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' + settingDefinitionId = 'user_vendor_msft_pde_protectfolders_protectdocuments' + choiceSettingValue = @{ + children = @() + value = 'user_vendor_msft_pde_protectfolders_protectdocuments_0' + } + } + ) + } + } + } + } + ) + } + + Mock -CommandName Update-DeviceConfigurationPolicyAssignment -MockWith { + } + + Mock -CommandName New-M365DSCConnection -MockWith { + return "Credentials" + } + + # Mock Write-Host to hide output during the tests + Mock -CommandName Write-Host -MockWith { + } + $Script:exportedInstances =$null + $Script:ExportMode = $false + + Mock -CommandName Get-MgBetaDeviceManagementConfigurationPolicyAssignment -MockWith { + return @(@{ + Id = '12345-12345-12345-12345-12345' + Source = 'direct' + SourceId = '12345-12345-12345-12345-12345' + Target = @{ + DeviceAndAppManagementAssignmentFilterId = '12345-12345-12345-12345-12345' + DeviceAndAppManagementAssignmentFilterType = 'none' + AdditionalProperties = @( + @{ + '@odata.type' = '#microsoft.graph.exclusionGroupAssignmentTarget' + groupId = '26d60dd1-fab6-47bf-8656-358194c1a49d' + } + ) + } + }) + } + + } + + # Test contexts + Context -Name "The IntuneDiskEncryptionPDEPolicyWindows10 should exist but it DOES NOT" -Fixture { + BeforeAll { + $testParams = @{ + Assignments = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_DeviceManagementConfigurationPolicyAssignments -Property @{ + DataType = '#microsoft.graph.exclusionGroupAssignmentTarget' + groupId = '26d60dd1-fab6-47bf-8656-358194c1a49d' + deviceAndAppManagementAssignmentFilterType = 'none' + } -ClientOnly) + ) + Description = "My Test" + Id = "12345-12345-12345-12345-12345" + DisplayName = "My Test" + EnablePersonalDataEncryption = "1"; + ProtectDesktop = "0"; + ProtectDocuments = "0"; + ProtectPictures = "0"; + RoleScopeTagIds = @("FakeStringValue") + Ensure = "Present" + Credential = $Credential; + } + + Mock -CommandName Get-MgBetaDeviceManagementConfigurationPolicy -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 + } + It 'Should Create the group from the Set method' { + Set-TargetResource @testParams + Should -Invoke -CommandName New-MgBetaDeviceManagementConfigurationPolicy -Exactly 1 + } + } + + Context -Name "The IntuneDiskEncryptionPDEPolicyWindows10 exists but it SHOULD NOT" -Fixture { + BeforeAll { + $testParams = @{ + Assignments = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_DeviceManagementConfigurationPolicyAssignments -Property @{ + DataType = '#microsoft.graph.exclusionGroupAssignmentTarget' + groupId = '26d60dd1-fab6-47bf-8656-358194c1a49d' + deviceAndAppManagementAssignmentFilterType = 'none' + } -ClientOnly) + ) + Description = "My Test" + Id = "12345-12345-12345-12345-12345" + DisplayName = "My Test" + EnablePersonalDataEncryption = "1"; + ProtectDesktop = "0"; + ProtectDocuments = "0"; + ProtectPictures = "0"; + RoleScopeTagIds = @("FakeStringValue") + Ensure = "Absent" + Credential = $Credential; + } + } + + 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-MgBetaDeviceManagementConfigurationPolicy -Exactly 1 + } + } + + Context -Name "The IntuneDiskEncryptionPDEPolicyWindows10 Exists and Values are already in the desired state" -Fixture { + BeforeAll { + $testParams = @{ + Assignments = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_DeviceManagementConfigurationPolicyAssignments -Property @{ + DataType = '#microsoft.graph.exclusionGroupAssignmentTarget' + groupId = '26d60dd1-fab6-47bf-8656-358194c1a49d' + deviceAndAppManagementAssignmentFilterType = 'none' + } -ClientOnly) + ) + Description = "My Test" + Id = "12345-12345-12345-12345-12345" + DisplayName = "My Test" + EnablePersonalDataEncryption = "1"; + ProtectDesktop = "0"; + ProtectDocuments = "0"; + ProtectPictures = "0"; + RoleScopeTagIds = @("FakeStringValue") + Ensure = "Present" + Credential = $Credential; + } + } + + It 'Should return true from the Test method' { + Test-TargetResource @testParams | Should -Be $true + } + } + + Context -Name "The IntuneDiskEncryptionPDEPolicyWindows10 exists and values are NOT in the desired state" -Fixture { + BeforeAll { + $testParams = @{ + Assignments = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_DeviceManagementConfigurationPolicyAssignments -Property @{ + DataType = '#microsoft.graph.exclusionGroupAssignmentTarget' + groupId = '26d60dd1-fab6-47bf-8656-358194c1a49d' + deviceAndAppManagementAssignmentFilterType = 'none' + } -ClientOnly) + ) + Description = "My Test" + Id = "12345-12345-12345-12345-12345" + DisplayName = "My Test" + EnablePersonalDataEncryption = "1"; + ProtectDesktop = "0"; + ProtectDocuments = "1"; # Drift + ProtectPictures = "0"; + RoleScopeTagIds = @("FakeStringValue") + Ensure = "Present" + 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-IntuneDeviceConfigurationPolicy -Exactly 1 + } + } + + Context -Name 'ReverseDSC Tests' -Fixture { + BeforeAll { + $Global:CurrentModeIsExport = $true + $Global:PartialExportFileName = "$(New-Guid).partial.ps1" + $testParams = @{ + Credential = $Credential + } + } + + 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 44cdaff1cb761188406630b584564e2e584469cf Mon Sep 17 00:00:00 2001 From: Ricardo Mestre Date: Fri, 15 Nov 2024 16:04:20 +0000 Subject: [PATCH 21/65] Fix request being sent --- CHANGELOG.md | 5 ++ ...ConfigurationPolicyAndroidDeviceOwner.psm1 | 90 ++++++++++++------- 2 files changed, 63 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c983de7fe7..4e15929948 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,11 @@ applicationEnforcedRestrictions parameter when value was set to false, which throws an error. * AADRoleEligibilityScheduleRequest * Adds support for custom role assignments at app scope. +* IntuneDeviceConfigurationPolicyAndroidDeviceOwner + * Fixed issue when properties `DetailedHelpText`, + `DeviceOwnerLockScreenMessage` or `ShortHelpText` were defined but the + request was not being sent correctly + FIXES [#5411](https://github.com/microsoft/Microsoft365DSC/issues/5411) * IntuneFirewallRulesHyperVPolicyWindows10 * Initial release. * M365DSCDRGUtil diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceConfigurationPolicyAndroidDeviceOwner/MSFT_IntuneDeviceConfigurationPolicyAndroidDeviceOwner.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceConfigurationPolicyAndroidDeviceOwner/MSFT_IntuneDeviceConfigurationPolicyAndroidDeviceOwner.psm1 index 20fd28f74c..19c44b7a7c 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceConfigurationPolicyAndroidDeviceOwner/MSFT_IntuneDeviceConfigurationPolicyAndroidDeviceOwner.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceConfigurationPolicyAndroidDeviceOwner/MSFT_IntuneDeviceConfigurationPolicyAndroidDeviceOwner.psm1 @@ -667,7 +667,7 @@ function Get-TargetResource $complexAzureAdSharedDeviceDataClearApps = @() $currentValueArray = $getValue.AdditionalProperties.azureAdSharedDeviceDataClearApps - if ($null -ne $currentValueArray -and $currentValueArray.count -gt 0 ) + if ($null -ne $currentValueArray -and $currentValueArray.count -gt 0) { foreach($currentValue in $currentValueArray) { @@ -686,10 +686,10 @@ function Get-TargetResource $currentValue = $getValue.AdditionalProperties.detailedHelpText if ($null -ne $currentValue) { - $complexDetailedHelpText.Add('DefaultMessage',$currentValue.defaultMessage) + $complexDetailedHelpText.Add('DefaultMessage', $currentValue.defaultMessage) $complexLocalizedMessages = @() $currentValueArray = $currentValue.localizedMessages - if ($null -ne $currentValueArray -and $currentValueArray.count -gt 0 ) + if ($null -ne $currentValueArray -and $currentValueArray.count -gt 0) { foreach($currentChildValue in $currentValueArray) { @@ -700,17 +700,17 @@ function Get-TargetResource $complexLocalizedMessages += $currentHash } } - $complexDetailedHelpText.Add('LocalizedMessages',$complexLocalizedMessages) + $complexDetailedHelpText.Add('LocalizedMessages', $complexLocalizedMessages) } $complexDeviceOwnerLockScreenMessage = @{} $currentValue = $getValue.AdditionalProperties.deviceOwnerLockScreenMessage if ($null -ne $currentValue) { - $complexDeviceOwnerLockScreenMessage.Add('DefaultMessage',$currentValue.defaultMessage) + $complexDeviceOwnerLockScreenMessage.Add('DefaultMessage', $currentValue.defaultMessage) $complexLocalizedMessages = @() $currentValueArray = $currentValue.localizedMessages - if ($null -ne $currentValueArray -and $currentValueArray.count -gt 0 ) + if ($null -ne $currentValueArray -and $currentValueArray.count -gt 0) { foreach($currentChildValue in $currentValueArray) { @@ -721,48 +721,48 @@ function Get-TargetResource $complexLocalizedMessages += $currentHash } } - $complexDeviceOwnerLockScreenMessage.Add('LocalizedMessages',$complexLocalizedMessages) + $complexDeviceOwnerLockScreenMessage.Add('LocalizedMessages', $complexLocalizedMessages) } $complexGlobalProxy = @{} $currentValue = $getValue.AdditionalProperties.globalProxy if ($null -ne $currentValue) { - $complexGlobalProxy.Add('ProxyAutoConfigURL',$currentValue.proxyAutoConfigURL) - $complexGlobalProxy.Add('ExcludedHosts',$currentValue.excludedHosts) - $complexGlobalProxy.Add('Host',$currentValue.host) - $complexGlobalProxy.Add('Port',$currentValue.port) - $complexGlobalProxy.Add('oDataType',$currentValue.'@odata.type') + $complexGlobalProxy.Add('ProxyAutoConfigURL', $currentValue.proxyAutoConfigURL) + $complexGlobalProxy.Add('ExcludedHosts', $currentValue.excludedHosts) + $complexGlobalProxy.Add('Host', $currentValue.host) + $complexGlobalProxy.Add('Port', $currentValue.port) + $complexGlobalProxy.Add('oDataType', $currentValue.'@odata.type') } $complexKioskModeApps = @() $currentValueArray = $getValue.AdditionalProperties.kioskModeApps - if ($null -ne $currentValueArray -and $currentValueArray.count -gt 0 ) + if ($null -ne $currentValueArray -and $currentValueArray.count -gt 0) { foreach($currentValue in $currentValueArray) { $currentHash = @{} - $currentHash.add('AppId',$currentValue.appid) - $currentHash.add('Publisher',$currentValue.publisher) - $currentHash.add('AppStoreUrl',$currentValue.appStoreUrl) - $currentHash.add('Name',$currentValue.name) - $currentHash.add('oDataType',$currentValue.'@odata.type') + $currentHash.add('AppId', $currentValue.appid) + $currentHash.add('Publisher', $currentValue.publisher) + $currentHash.add('AppStoreUrl', $currentValue.appStoreUrl) + $currentHash.add('Name', $currentValue.name) + $currentHash.add('oDataType', $currentValue.'@odata.type') $complexKioskModeApps += $currentHash } } $complexPersonalProfilePersonalApplications = @() $currentValueArray = $getValue.AdditionalProperties.personalProfilePersonalApplications - if ($null -ne $currentValueArray -and $currentValueArray.count -gt 0 ) + if ($null -ne $currentValueArray -and $currentValueArray.count -gt 0) { foreach($currentValue in $currentValueArray) { $currentHash = @{} - $currentHash.add('AppId',$currentValue.appid) - $currentHash.add('Publisher',$currentValue.publisher) - $currentHash.add('AppStoreUrl',$currentValue.appStoreUrl) - $currentHash.add('Name',$currentValue.name) - $currentHash.add('oDataType',$currentValue.'@odata.type') + $currentHash.add('AppId', $currentValue.appid) + $currentHash.add('Publisher', $currentValue.publisher) + $currentHash.add('AppStoreUrl', $currentValue.appStoreUrl) + $currentHash.add('Name', $currentValue.name) + $currentHash.add('oDataType', $currentValue.'@odata.type') $complexPersonalProfilePersonalApplications += $currentHash } } @@ -771,10 +771,10 @@ function Get-TargetResource $currentValue = $getValue.AdditionalProperties.shortHelpText if ($null -ne $currentValue) { - $complexShortHelpText.Add('DefaultMessage',$currentValue.defaultMessage) + $complexShortHelpText.Add('DefaultMessage', $currentValue.defaultMessage) $complexLocalizedMessages = @() $currentValueArray = $currentValue.localizedMessages - if ($null -ne $currentValueArray -and $currentValueArray.count -gt 0 ) + if ($null -ne $currentValueArray -and $currentValueArray.count -gt 0) { foreach($currentChildValue in $currentValueArray) { @@ -785,20 +785,20 @@ function Get-TargetResource $complexLocalizedMessages += $currentHash } } - $complexShortHelpText.Add('LocalizedMessages',$complexLocalizedMessages) + $complexShortHelpText.Add('LocalizedMessages', $complexLocalizedMessages) } $complexSystemUpdateFreezePeriods = @() $currentValueArray = $getValue.AdditionalProperties.systemUpdateFreezePeriods - if ($null -ne $currentValueArray -and $currentValueArray.count -gt 0 ) + if ($null -ne $currentValueArray -and $currentValueArray.count -gt 0) { foreach($currentValue in $currentValueArray) { $currentHash = @{} - $currentHash.Add('StartDay',$currentValue.startDay) - $currentHash.Add('EndDay',$currentValue.endDay) - $currentHash.Add('StartMonth',$currentValue.startMonth) - $currentHash.Add('EndMonth',$currentValue.endMonth) + $currentHash.Add('StartDay', $currentValue.startDay) + $currentHash.Add('EndDay', $currentValue.endDay) + $currentHash.Add('StartMonth', $currentValue.startMonth) + $currentHash.Add('EndMonth', $currentValue.endMonth) $complexSystemUpdateFreezePeriods += $currentHash } } @@ -1644,6 +1644,19 @@ function Set-TargetResource foreach ($key in ($CreateParameters.clone()).Keys) { + if ($key -eq 'DetailedHelpText' -or $key -eq 'DeviceOwnerLockScreenMessage' -or $key -eq 'ShortHelpText') + { + if ($null -ne $CreateParameters.$key.DefaultMessage -or $null -ne $CreateParameters.$key.LocalizedMessages) + { + $CreateParameters.$key.Add('@odata.type', '#microsoft.graph.androidDeviceOwnerUserFacingMessage') + } + + if ($null -eq $CreateParameters.$key.LocalizedMessages) + { + $CreateParameters.$key.Add('localizedMessages', @()) + } + } + if ($CreateParameters[$key].getType().Fullname -like '*CimInstance*') { $CreateParameters[$key] = Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject $CreateParameters[$key] @@ -1684,6 +1697,19 @@ function Set-TargetResource foreach ($key in (($UpdateParameters.clone()).Keys | Sort-Object)) { + if ($key -eq 'DetailedHelpText' -or $key -eq 'DeviceOwnerLockScreenMessage' -or $key -eq 'ShortHelpText') + { + if ($null -ne $UpdateParameters.$key.DefaultMessage -or $null -ne $UpdateParameters.$key.LocalizedMessages) + { + $UpdateParameters.$key.Add('@odata.type', '#microsoft.graph.androidDeviceOwnerUserFacingMessage') + } + + if ($null -eq $UpdateParameters.$key.LocalizedMessages) + { + $UpdateParameters.$key.Add('localizedMessages', @()) + } + } + if ($UpdateParameters.$key.getType().Fullname -like '*CimInstance*') { $UpdateParameters.$key = Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject $UpdateParameters.$key From 04c404598bcd80a4fcc2f882b2f8233f4c4af8e2 Mon Sep 17 00:00:00 2001 From: dannyKBjj Date: Sat, 16 Nov 2024 20:58:47 +0000 Subject: [PATCH 22/65] Requested changes made Group.Read.All permission added to settings.json Excessive number of blank lines reduced for readability. --- ...IntuneMobileAppConfigurationPolicyIOS.psm1 | 54 ++++--------------- .../settings.json | 12 +++++ 2 files changed, 21 insertions(+), 45 deletions(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/MSFT_IntuneMobileAppConfigurationPolicyIOS.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/MSFT_IntuneMobileAppConfigurationPolicyIOS.psm1 index bf6fe466f9..93a0f1e76c 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/MSFT_IntuneMobileAppConfigurationPolicyIOS.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/MSFT_IntuneMobileAppConfigurationPolicyIOS.psm1 @@ -4,7 +4,7 @@ function Get-TargetResource [OutputType([System.Collections.Hashtable])] param ( - #region resource generator code + #region Intune resource parameters [Parameter()] [System.String] $Id, @@ -29,11 +29,10 @@ function Get-TargetResource [System.String] $encodedSettingXml, - #====================== - #standard params [Parameter()] [Microsoft.Management.Infrastructure.CimInstance[]] $Assignments, + #endregion [Parameter()] @@ -68,7 +67,6 @@ function Get-TargetResource [Parameter()] [System.String[]] $AccessTokens - ) try @@ -133,19 +131,14 @@ function Get-TargetResource } } - - - $results = @{ #region resource generator code Id = $getValue.Id Description = $getValue.Description - DisplayName = $getValue.DisplayName - + DisplayName = $getValue.DisplayName targetedMobileApps = $getValue.TargetedMobileApps settings = $complexSettings #$getValue.AdditionalProperties.settings encodedSettingXml = $getValue.AdditionalProperties.encodedSettingXml - Ensure = 'Present' Credential = $Credential ApplicationId = $ApplicationId @@ -158,8 +151,6 @@ function Get-TargetResource } - - $assignmentsValues = Get-MgBetaDeviceAppManagementMobileAppConfigurationAssignment -ManagedDeviceMobileAppConfigurationId $Results.Id $assignmentResult = @() if ($assignmentsValues.Count -gt 0) @@ -189,7 +180,7 @@ function Set-TargetResource [CmdletBinding()] param ( - #region resource generator code + #region Intune resource parameters [Parameter()] [System.String] $Id, @@ -214,11 +205,10 @@ function Set-TargetResource [System.String] $encodedSettingXml, - #====================== - #standard params [Parameter()] [Microsoft.Management.Infrastructure.CimInstance[]] $Assignments, + #endregion [Parameter()] @@ -288,17 +278,12 @@ function Set-TargetResource $PSBoundParameters.Remove('ManagedIdentity') | Out-Null $PSBoundParameters.Remove('AccessTokens') | Out-Null - - - if ($Ensure -eq 'Present' -and $currentInstance.Ensure -eq 'Absent') { Write-Verbose -Message "Creating {$DisplayName}" $PSBoundParameters.Remove('Assignments') | Out-Null - $CreateParameters = ([Hashtable]$PSBoundParameters).clone() $CreateParameters = Rename-M365DSCCimInstanceParameter -Properties $CreateParameters - $AdditionalProperties = Get-M365DSCAdditionalProperties -Properties ($CreateParameters) foreach ($key in $AdditionalProperties.keys) @@ -321,8 +306,6 @@ function Set-TargetResource } } - - $CreateParameters.add('AdditionalProperties', $AdditionalProperties) #region resource generator code @@ -341,10 +324,8 @@ function Set-TargetResource { Write-Verbose -Message "Updating {$DisplayName}" $PSBoundParameters.Remove('Assignments') | Out-Null - $UpdateParameters = ([Hashtable]$PSBoundParameters).clone() $UpdateParameters = Rename-M365DSCCimInstanceParameter -Properties $UpdateParameters - $AdditionalProperties = Get-M365DSCAdditionalProperties -Properties ($UpdateParameters) foreach ($key in $AdditionalProperties.keys) { @@ -365,8 +346,8 @@ function Set-TargetResource $UpdateParameters[$key] = Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject $UpdateParameters[$key] } } - $UpdateParameters.add('AdditionalProperties', $AdditionalProperties) + $UpdateParameters.add('AdditionalProperties', $AdditionalProperties) #region resource generator code Update-MgBetaDeviceAppManagementMobileAppConfiguration @UpdateParameters ` @@ -392,7 +373,7 @@ function Test-TargetResource [OutputType([System.Boolean])] param ( - #region resource generator code + #region Intune resource parameters [Parameter()] [System.String] $Id, @@ -417,11 +398,10 @@ function Test-TargetResource [System.String] $encodedSettingXml, - #====================== - #standard params [Parameter()] [Microsoft.Management.Infrastructure.CimInstance[]] $Assignments, + #endregion [Parameter()] @@ -502,7 +482,6 @@ function Test-TargetResource $testResult = Compare-M365DSCComplexObject ` -Source (Get-M365DSCDRGComplexTypeToHashtable -ComplexObject $CIMArraySource[$i]) ` -Target ($CIMArrayTarget[$i]) - $i++ if (-Not $testResult) { @@ -603,7 +582,6 @@ function Export-TargetResource try { - #region resource generator code [array]$getValue = Get-MgBetaDeviceAppManagementMobileAppConfiguration -Filter $Filter -All ` -ErrorAction Stop | Where-Object ` @@ -660,8 +638,6 @@ function Export-TargetResource } } - - if ($null -ne $Results.settings) { $complexTypeStringResult = Get-M365DSCDRGComplexTypeToString ` @@ -677,22 +653,12 @@ function Export-TargetResource } } - - - - - - - $currentDSCBlock = Get-M365DSCExportContentForResource -ResourceName $ResourceName ` -ConnectionMode $ConnectionMode ` -ModulePath $PSScriptRoot ` -Results $Results ` -Credential $Credential - - - if ($Results.Assignments) { $isCIMArray = $false @@ -702,8 +668,7 @@ function Export-TargetResource } $currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock -ParameterName 'Assignments' -IsCIMArray:$isCIMArray } - - + if ($Results.settings) { $isCIMArray = $false @@ -714,7 +679,6 @@ function Export-TargetResource $currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock -ParameterName 'settings' -IsCIMArray:$isCIMArray } - $dscContent += $currentDSCBlock Save-M365DSCPartialExport -Content $currentDSCBlock ` -FileName $Global:PartialExportFileName diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/settings.json b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/settings.json index ebd0a5e8d5..520b5bcd32 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/settings.json +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/settings.json @@ -6,10 +6,16 @@ "delegated": { "read": [ { + "name": "Group.Read.All" + }, +{ "name": "DeviceManagementApps.Read.All" } ], "update": [ + { + "name": "Group.Read.All" + }, { "name": "DeviceManagementApps.ReadWrite.All" } @@ -17,11 +23,17 @@ }, "application": { "read": [ + { + "name": "Group.Read.All" + }, { "name": "DeviceManagementApps.Read.All" } ], "update": [ + { + "name": "Group.Read.All" + }, { "name": "DeviceManagementApps.ReadWrite.All" } From a0fc56654c6a911edb1dfcffdaa094a0b5d48461 Mon Sep 17 00:00:00 2001 From: dannyKBjj Date: Mon, 18 Nov 2024 08:54:51 +0000 Subject: [PATCH 23/65] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c8d1c06fd6..e74f859000 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,8 @@ * DEPENDENCIES * Updated DSCParser to version 2.0.0.12. * Updated MSCloudLoginAssistant to version 1.1.28. +* MSFT_IntuneMobileAppConfigurationPolicyIOS + * Initial release. # 1.24.1106.3 From 2e6d7d5cc8fb1f7e95376b3278df444f9fe6b140 Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Mon, 18 Nov 2024 15:55:33 -0500 Subject: [PATCH 24/65] AADRoleAssignmentScheduleRequest - Initial Request --- .../MSFT_AADApplication.psm1 | 8 +- ...MSFT_AADRoleAssignmentScheduleRequest.psm1 | 1078 +++++++++++++++++ ...ADRoleAssignmentScheduleRequest.schema.mof | 75 ++ .../readme.md | 6 + .../settings.json | 28 + .../settings.json | 2 +- .../1-Create.ps1 | 26 + .../2-Update.ps1 | 26 + .../3-Remove.ps1 | 26 + ...AADRoleAssignmentScheduleRequest.Tests.ps1 | 178 +++ 10 files changed, 1451 insertions(+), 2 deletions(-) create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleAssignmentScheduleRequest/MSFT_AADRoleAssignmentScheduleRequest.psm1 create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleAssignmentScheduleRequest/MSFT_AADRoleAssignmentScheduleRequest.schema.mof create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleAssignmentScheduleRequest/readme.md create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleAssignmentScheduleRequest/settings.json create mode 100644 Modules/Microsoft365DSC/Examples/Resources/AADRoleAssignmentScheduleRequest/1-Create.ps1 create mode 100644 Modules/Microsoft365DSC/Examples/Resources/AADRoleAssignmentScheduleRequest/2-Update.ps1 create mode 100644 Modules/Microsoft365DSC/Examples/Resources/AADRoleAssignmentScheduleRequest/3-Remove.ps1 create mode 100644 Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADRoleAssignmentScheduleRequest.Tests.ps1 diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADApplication/MSFT_AADApplication.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADApplication/MSFT_AADApplication.psm1 index 75b7e9a62a..69b7f58fa4 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADApplication/MSFT_AADApplication.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADApplication/MSFT_AADApplication.psm1 @@ -457,13 +457,19 @@ function Get-TargetResource } #endregion + $IdentifierUrisValue = @() + if ($null -ne $AADApp.IdentifierUris) + { + $IdentifierUrisValue = $AADApp.IdentifierUris + } + $result = @{ DisplayName = $AADApp.DisplayName AvailableToOtherTenants = $AvailableToOtherTenantsValue Description = $AADApp.Description GroupMembershipClaims = $AADApp.GroupMembershipClaims Homepage = $AADApp.web.HomepageUrl - IdentifierUris = $AADApp.IdentifierUris + IdentifierUris = $IdentifierUrisValue IsFallbackPublicClient = $IsFallbackPublicClientValue KnownClientApplications = $AADApp.Api.KnownClientApplications LogoutURL = $AADApp.web.LogoutURL diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleAssignmentScheduleRequest/MSFT_AADRoleAssignmentScheduleRequest.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleAssignmentScheduleRequest/MSFT_AADRoleAssignmentScheduleRequest.psm1 new file mode 100644 index 0000000000..bea1cf6526 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleAssignmentScheduleRequest/MSFT_AADRoleAssignmentScheduleRequest.psm1 @@ -0,0 +1,1078 @@ +function Get-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + param + ( + [Parameter(Mandatory = $true)] + [System.String] + $Principal, + + [Parameter(Mandatory = $true)] + [System.String] + $RoleDefinition, + + [Parameter()] + [ValidateSet('User', 'Group')] + [System.String] + $PrincipalType = 'User', + + [Parameter()] + [System.String] + $Id, + + [Parameter()] + [System.String] + $DirectoryScopeId, + + [Parameter()] + [System.String] + $AppScopeId, + + [Parameter()] + [ValidateSet("adminAssign", "adminUpdate", "adminRemove", "selfActivate", "selfDeactivate", "adminExtend", "adminRenew", "selfExtend", "selfRenew", "unknownFutureValue")] + [System.String] + $Action, + + [Parameter()] + [System.String] + $Justification, + + [Parameter()] + [System.Boolean] + $IsValidationOnly, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance] + $ScheduleInfo, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance] + $TicketInfo, + + [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, + + [Parameter()] + [System.String[]] + $AccessTokens + ) + try + { + $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` + -InboundParameters $PSBoundParameters + } + catch + { + Write-Verbose -Message ($_) + } + + #Ensure the proper dependencies are installed in the current environment. + Confirm-M365DSCDependencies + + #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' + try + { + $request = $null + if (-not [System.String]::IsNullOrEmpty($Id)) + { + if ($null -ne $Script:exportedInstances -and $Script:ExportMode) + { + $request = $Script:exportedInstances | Where-Object -FilterScript {$_.Id -eq $Id} + } + else + { + Write-Verbose -Message "Getting Role Eligibility by Id {$Id}" + $request = Get-MgBetaRoleManagementDirectoryRoleAssignmentScheduleRequest -UnifiedRoleAssignmentScheduleRequestId $Id ` + -ErrorAction SilentlyContinue + } + } + + if ($null -eq $request) + { + if ($null -ne $Script:exportedInstances -and $Script:ExportMode) + { + Write-Verbose -Message "Getting Role Eligibility by PrincipalId and RoleDefinitionId" + $PrincipalTypeValue = $null + if ($PrincipalType -eq 'User') + { + Write-Verbose -Message "Retrieving Principal by UserPrincipalName {$Principal}" + $PrincipalIdValue = Get-MgUser -Filter "UserPrincipalName eq '$Principal'" -ErrorAction SilentlyContinue + $PrincipalTypeValue = 'User' + } + if ($null -eq $PrincipalIdValue -or $PrincipalType -eq 'Group') + { + Write-Verbose -Message "Retrieving Principal by DisplayName {$Principal}" + $PrincipalIdValue = Get-MgGroup -Filter "DisplayName eq '$Principal'" -ErrorAction SilentlyContinue + $PrincipalTypeValue = 'Group' + } + + if ($null -ne $PrincipalIdValue) + { + $PrincipalId = $PrincipalIdValue.Id + } + else + { + return $nullResult + } + Write-Verbose -Message "Found Principal {$PrincipalId}" + $RoleDefinitionId = (Get-MgBetaRoleManagementDirectoryRoleDefinition -Filter "DisplayName eq '$RoleDefinition'").Id + $request = $Script:exportedInstances | Where-Object -FilterScript {$_.PrincipalId -eq $PrincipalId -and $_.RoleDefinitionId -eq $RoleDefinition} | Sort-Object -Property CompletedDateTime -Descending + } + else + { + Write-Verbose -Message "Getting Role Eligibility by PrincipalId and RoleDefinitionId" + if ($PrincipalType -eq 'User') + { + Write-Verbose -Message "Retrieving principal {$Principal} of type {$PrincipalType}" + $PrincipalIdValue = Get-MgUser -Filter "UserPrincipalName eq '$Principal'" -ErrorAction SilentlyContinue + $PrincipalTypeValue = 'User' + } + + if ($null -eq $PrincipalIdValue -or $PrincipalType -eq 'Group') + { + Write-Verbose -Message "Retrieving principal {$Principal} of type {$PrincipalType}" + $PrincipalIdValue = Get-MgGroup -Filter "DisplayName eq '$Principal'" -ErrorAction SilentlyContinue + $PrincipalTypeValue = 'Group' + } + + if ($null -ne $PrincipalIdValue) + { + $PrincipalId = $PrincipalIdValue.Id + } + else + { + return $nullResult + } + Write-Verbose -Message "Found Principal {$PrincipalId}" + $schedulesForPrincipal = Get-MgBetaRoleManagementDirectoryRoleAssignmentSchedule -Filter "PrincipalId eq '$PrincipalId'" + foreach ($instance in $schedulesForPrincipal) + { + $roleInfo = Get-MgBetaRoleManagementDirectoryRoleDefinition -UnifiedRoleDefinitionId $instance.RoleDefinitionId + if ($roleInfo.DisplayName -eq $RoleDefinition) + { + $schedule = $instance + } + } + [Array]$request = Get-MgBetaRoleManagementDirectoryRoleAssignmentScheduleRequest -Filter "PrincipalId eq '$PrincipalId'" | Where-Object -FilterScript {$_.RoleDefinitionId -eq $schedule.RoleDefinitionId} | Sort-Object -Property CompletedDateTime -Descending +` + if ($request.Length -gt 1) + { + $request = $request[0] + } + } + } + else + { + Write-Verbose -Message "Request is not null: $request" + $ObjectGuid = [System.Guid]::empty + if ($PrincipalType -eq 'User') + { + Write-Verbose -Message "Retrieving principal {$Principal} of type {$PrincipalType}" + + if ([System.Guid]::TryParse($Principal,[System.Management.Automation.PSReference]$ObjectGuid)) + { + $PrincipalIdValue = Get-MgUser -UserId $Principal -ErrorAction SilentlyContinue + } + else + { + $PrincipalIdValue = Get-MgUser -Filter "UserPrincipalName eq '$Principal'" -ErrorAction SilentlyContinue + } + $PrincipalTypeValue = 'User' + } + + if ($null -eq $PrincipalIdValue -or $PrincipalType -eq 'Group') + { + Write-Verbose -Message "Retrieving principal {$Principal} of type {$PrincipalType}" + if ([System.Guid]::TryParse($Principal,[System.Management.Automation.PSReference]$ObjectGuid)) + { + $PrincipalIdValue = Get-MgGroup -GroupId $Principal -ErrorAction SilentlyContinue + } + else + { + $PrincipalIdValue = Get-MgGroup -Filter "DisplayName eq '$Principal'" -ErrorAction SilentlyContinue + } + $PrincipalTypeValue = 'Group' + } + + if ($null -ne $PrincipalIdValue) + { + $PrincipalId = $PrincipalIdValue.Id + } + else + { + return $nullResult + } + $RoleDefinitionId = (Get-MgBetaRoleManagementDirectoryRoleDefinition -Filter "DisplayName eq '$RoleDefinition'").Id + $schedules = Get-MgBetaRoleManagementDirectoryRoleAssignmentSchedule -Filter "PrincipalId eq '$($request.PrincipalId)'" + $schedule = $schedules | Where-Object -FilterScript {$_.RoleDefinitionId -eq $RoleDefinitionId} + if ($null -eq $schedule) + { + foreach ($instance in $schedules) + { + $roleDefinitionInfo = Get-MgBetaRoleManagementDirectoryRoleDefinition -UnifiedRoleDefinitionId $instance.RoleDefinitionId + if ($null -ne $roleDefinitionInfo -and $RoleDefinitionInfo.DisplayName -eq $RoleDefinition) + { + $schedule = $instance + break + } + } + } + } + if ($null -eq $schedule -or $null -eq $request) + { + if ($null -eq $schedule) + { + Write-Verbose -Message "Could not retrieve the schedule for {$($request.PrincipalId)} & RoleDefinitionId {$RoleDefinitionId}" + } + if ($null -eq $request) + { + Write-Verbose -Message "Could not request the schedule for {$RoleDefinition}" + } + return $nullResult + } + + Write-Verbose -Message "Found existing AADRolelLigibilityScheduleRequest" + if ($PrincipalType -eq 'User') + { + Write-Verbose -Message "Retrieving Principal by UserId {$($request.PrincipalId)}" + $PrincipalInstance = Get-MgUser -UserId $request.PrincipalId -ErrorAction SilentlyContinue + $PrincipalTypeValue = 'User' + } + if ($null -eq $PrincipalInstance -or $PrincipalType -eq 'Group') + { + Write-Verbose -Message "Retrieving Principal by GroupId {$($request.PrincipalId)}" + $requestArray = [Array]$request + if ($requestArray.Count -gt 1) + { + $requestArray = $requestArray | Sort-Object -Property CreatedDateTime -Descending + $request = $requestArray[0] + } + $PrincipalInstance = Get-MGGroup -GroupId $request.PrincipalId -ErrorAction SilentlyContinue + $PrincipalTypeValue = 'Group' + } + + if ($null -eq $PrincipalInstance) + { + Write-Verbose -Message "Couldn't retrieve Principal {$($request.PrincipalId)}" + return $nullResult + } + + $ScheduleInfoValue = @{} + + if ($null -ne $schedule.ScheduleInfo.Expiration) + { + $expirationValue = @{ + duration = $schedule.ScheduleInfo.Expiration.Duration + type = $schedule.ScheduleInfo.Expiration.Type + } + if ($null -ne $schedule.ScheduleInfo.Expiration.EndDateTime) + { + $expirationValue.Add('endDateTime', $schedule.ScheduleInfo.Expiration.EndDateTime.ToString("yyyy-MM-ddThh:mm:ssZ")) + } + $ScheduleInfoValue.Add('expiration', $expirationValue) + } + if ($null -ne $schedule.ScheduleInfo.Recurrence) + { + $recurrenceValue = @{ + pattern = @{ + 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 = $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 $schedule.ScheduleInfo.StartDateTime) + { + $ScheduleInfoValue.Add('StartDateTime', $schedule.ScheduleInfo.StartDateTime.ToString("yyyy-MM-ddThh:mm:ssZ")) + } + + $ticketInfoValue = $null + if ($null -ne $request.TicketInfo) + { + $ticketInfoValue = @{ + ticketNumber = $request.TicketInfo.TicketNumber + ticketSystem = $request.TicketInfo.TicketSystem + } + } + + $PrincipalValue = $null + if ($PrincipalType -eq 'User') + { + $PrincipalValue = $PrincipalInstance.UserPrincipalName + } + if ($null -eq $PrincipalValue -or $PrincipalTypeValue -eq 'Group') + { + $PrincipalValue = $PrincipalInstance.DisplayName + } + + $results = @{ + Principal = $PrincipalValue + PrincipalType = $PrincipalTypeValue + RoleDefinition = $RoleDefinition + DirectoryScopeId = $request.DirectoryScopeId + AppScopeId = $request.AppScopeId + Action = $request.Action + Id = $request.Id + Justification = $request.Justification + IsValidationOnly = $request.IsValidationOnly + ScheduleInfo = $ScheduleInfoValue + TicketInfo = $ticketInfoValue + Ensure = 'Present' + Credential = $Credential + ApplicationId = $ApplicationId + TenantId = $TenantId + ApplicationSecret = $ApplicationSecret + CertificateThumbprint = $CertificateThumbprint + Managedidentity = $ManagedIdentity.IsPresent + AccessTokens = $AccessTokens + } + return $results + } + catch + { + Write-Verbose "Error: $_" + 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] + $Principal, + + [Parameter(Mandatory = $true)] + [System.String] + $RoleDefinition, + + [Parameter()] + [ValidateSet('User', 'Group')] + [System.String] + $PrincipalType = 'User', + + [Parameter()] + [System.String] + $Id, + + [Parameter()] + [System.String] + $DirectoryScopeId, + + [Parameter()] + [System.String] + $AppScopeId, + + [Parameter()] + [ValidateSet("adminAssign", "adminUpdate", "adminRemove", "selfActivate", "selfDeactivate", "adminExtend", "adminRenew", "selfExtend", "selfRenew", "unknownFutureValue")] + [System.String] + $Action, + + [Parameter()] + [System.String] + $Justification, + + [Parameter()] + [System.Boolean] + $IsValidationOnly, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance] + $ScheduleInfo, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance] + $TicketInfo, + + [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, + + [Parameter()] + [System.String[]] + $AccessTokens + ) + try + { + $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` + -InboundParameters $PSBoundParameters ` + } + catch + { + Write-Verbose -Message $_ + } + + #Ensure the proper dependencies are installed in the current environment. + Confirm-M365DSCDependencies + + #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 + + $PSBoundParameters.Remove('Ensure') | Out-Null + $PSBoundParameters.Remove('Credential') | Out-Null + $PSBoundParameters.Remove('ApplicationId') | Out-Null + $PSBoundParameters.Remove('ApplicationSecret') | Out-Null + $PSBoundParameters.Remove('TenantId') | Out-Null + $PSBoundParameters.Remove('CertificateThumbprint') | Out-Null + $PSBoundParameters.Remove('ManagedIdentity') | Out-Null + $PSBoundParameters.Remove('Verbose') | Out-Null + $PSBoundParameters.Remove('AccessTokens') | Out-Null + + $ParametersOps = ([Hashtable]$PSBoundParameters).clone() + + if ($PrincipalType -eq 'User') + { + [Array]$PrincipalIdValue = (Get-MgUser -Filter "UserPrincipalName eq '$Principal'").Id + } + elseif ($PrincipalType -eq 'Group') + { + [Array]$PrincipalIdValue = (Get-MgGroup -Filter "DisplayName eq '$Principal'").Id + } + + if ($null -eq $PrincipalIdValue) + { + throw "Couldn't find Principal {$PrincipalId} of type {$PrincipalType}" + } + elseif ($PrincipalIdValue.Length -gt 1) + { + throw "Multiple Principal with ID {$PrincipalId} of type {$PrincipalType} were found. Cannot create schedule." + } + $ParametersOps.Add("PrincipalId", $PrincipalIdValue[0]) + $ParametersOps.Remove("Principal") | Out-Null + + $RoleDefinitionIdValue = (Get-MgBetaRoleManagementDirectoryRoleDefinition -Filter "DisplayName eq '$RoleDefinition'").Id + $ParametersOps.Add("RoleDefinitionId", $RoleDefinitionIdValue) + $ParametersOps.Remove("RoleDefinition") | Out-Null + + if ($null -ne $ScheduleInfo) + { + $ScheduleInfoValue = @{} + + if ($ScheduleInfo.StartDateTime) + { + $ScheduleInfoValue.Add("startDateTime", $ScheduleInfo.StartDateTime) + } + + if ($ScheduleInfo.Expiration) + { + $expirationValue = @{ + endDateTime = $ScheduleInfo.Expiration.endDateTime + type = $ScheduleInfo.Expiration.type + } + if ($ScheduleInfo.Expiration.duration) + { + $expirationValue.Add('duration', $ScheduleInfo.Expiration.duration) + } + $ScheduleInfoValue.Add("Expiration", $expirationValue) + } + + if ($ScheduleInfo.Recurrence) + { + $Found = $false + $recurrenceValue = @{} + + if ($ScheduleInfo.Recurrence.Pattern) + { + $Found = $true + $patternValue = @{ + dayOfMonth = $ScheduleInfo.Recurrence.Pattern.dayOfMonth + daysOfWeek = $ScheduleInfo.Recurrence.Pattern.daysOfWeek + firstDayOfWeek = $ScheduleInfo.Recurrence.Pattern.firstDayOfWeek + index = $ScheduleInfo.Recurrence.Pattern.index + interval = $ScheduleInfo.Recurrence.Pattern.interval + month = $ScheduleInfo.Recurrence.Pattern.month + type = $ScheduleInfo.Recurrence.Pattern.type + } + $recurrenceValue.Add("Pattern", $patternValue) + } + if ($ScheduleInfo.Recurrence.Range) + { + $Found = $true + $rangeValue = @{ + endDate = $ScheduleInfo.Recurrence.Range.endDate + numberOfOccurrences = $ScheduleInfo.Recurrence.Range.numberOfOccurrences + recurrenceTimeZone = $ScheduleInfo.Recurrence.Range.recurrenceTimeZone + startDate = $ScheduleInfo.Recurrence.Range.startDate + type = $ScheduleInfo.Recurrence.Range.type + } + $recurrenceValue.Add("Range", $rangeValue) + } + if ($Found) + { + $ScheduleInfoValue.Add("Recurrence", $recurrenceValue) + } + } + Write-Verbose -Message "ScheduleInfo: $(Convert-M365DscHashtableToString -Hashtable $ScheduleInfoValue)" + $ParametersOps.ScheduleInfo = $ScheduleInfoValue + } + $ParametersOps.Remove("PrincipalType") | Out-Null + if ($Ensure -eq 'Present' -and $currentInstance.Ensure -eq 'Absent') + { + Write-Verbose -Message "Creating a Role Eligibility Schedule Request for user {$Principal} and role {$RoleDefinition}" + $ParametersOps.Remove("Id") | Out-Null + Write-Verbose -Message "Values: $(Convert-M365DscHashtableToString -Hashtable $ParametersOps)" + New-MgBetaRoleManagementDirectoryRoleAssignmentScheduleRequest @ParametersOps + } + elseif ($Ensure -eq 'Present' -and $currentInstance.Ensure -eq 'Present') + { + Write-Verbose -Message "Updating the Role Eligibility Schedule Request for user {$Principal} and role {$RoleDefinition}" + $ParametersOps.Remove("Id") | Out-Null + $ParametersOps.Action = 'AdminUpdate' + New-MgBetaRoleManagementDirectoryRoleAssignmentScheduleRequest @ParametersOps + } + elseif ($Ensure -eq 'Absent' -and $currentInstance.Ensure -eq 'Present') + { + Write-Verbose -Message "Removing the Role Eligibility Schedule Request for user {$Principal} and role {$RoleDefinition}" + $ParametersOps.Remove("Id") | Out-Null + $ParametersOps.Action = 'AdminRemove' + New-MgBetaRoleManagementDirectoryRoleAssignmentScheduleRequest @ParametersOps + } +} + +function Test-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Boolean])] + param + ( + [Parameter(Mandatory = $true)] + [System.String] + $Principal, + + [Parameter(Mandatory = $true)] + [System.String] + $RoleDefinition, + + [Parameter()] + [ValidateSet('User', 'Group')] + [System.String] + $PrincipalType = 'User', + + [Parameter()] + [System.String] + $Id, + + [Parameter()] + [System.String] + $DirectoryScopeId, + + [Parameter()] + [System.String] + $AppScopeId, + + [Parameter()] + [ValidateSet("adminAssign", "adminUpdate", "adminRemove", "selfActivate", "selfDeactivate", "adminExtend", "adminRenew", "selfExtend", "selfRenew", "unknownFutureValue")] + [System.String] + $Action, + + [Parameter()] + [System.String] + $Justification, + + [Parameter()] + [System.Boolean] + $IsValidationOnly, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance] + $ScheduleInfo, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance] + $TicketInfo, + + [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, + + [Parameter()] + [System.String[]] + $AccessTokens + ) + + #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 Azure AD Role Eligibility Schedule Request for user {$Principal} and role {$RoleDefinition}" + + $CurrentValues = Get-TargetResource @PSBoundParameters + $ValuesToCheck = ([Hashtable]$PSBoundParameters).clone() + $ValuesToCheck.Remove("Action") | Out-Null + if($null -ne $CurrentValues.ScheduleInfo -and $null -ne $ValuesToCheck.ScheduleInfo) + { + # Compare ScheduleInfo.Expiration + if ($CurrentValues.ScheduleInfo.Expiration.duration -ne $ValuesToCheck.ScheduleInfo.Expiration.duration -or ` + $CurrentValues.ScheduleInfo.Expiration.endDateTime -ne $ValuesToCheck.ScheduleInfo.Expiration.endDateTime -or ` + $CurrentValues.ScheduleInfo.Expiration.type -ne $ValuesToCheck.ScheduleInfo.Expiration.type) + { + Write-Verbose -Message "Discrepancy found in ScheduleInfo.Expiration" + Write-Verbose -Message "Current: $($CurrentValues.ScheduleInfo.Expiration | Out-String)" + Write-Verbose -Message "Desired: $($ValuesToCheck.ScheduleInfo.Expiration | Out-String)" + return $false + } + + # Compare ScheduleInfo.Recurrence.Pattern + if ($CurrentValues.ScheduleInfo.Recurrence.Pattern.dayOfMonth -ne $ValuesToCheck.ScheduleInfo.Recurrence.Pattern.dayOfMonth -or ` + $CurrentValues.ScheduleInfo.Recurrence.Pattern.daysOfWeek -ne $ValuesToCheck.ScheduleInfo.Recurrence.Pattern.daysOfWeek -or ` + $CurrentValues.ScheduleInfo.Recurrence.Pattern.firstDayOfWeek -ne $ValuesToCheck.ScheduleInfo.Recurrence.Pattern.firstDayOfWeek -or ` + $CurrentValues.ScheduleInfo.Recurrence.Pattern.index -ne $ValuesToCheck.ScheduleInfo.Recurrence.Pattern.index -or ` + $CurrentValues.ScheduleInfo.Recurrence.Pattern.interval -ne $ValuesToCheck.ScheduleInfo.Recurrence.Pattern.interval -or ` + $CurrentValues.ScheduleInfo.Recurrence.Pattern.month -ne $ValuesToCheck.ScheduleInfo.Recurrence.Pattern.month -or ` + $CurrentValues.ScheduleInfo.Recurrence.Pattern.type -ne $ValuesToCheck.ScheduleInfo.Recurrence.Pattern.type) + { + Write-Verbose -Message "Discrepancy found in ScheduleInfo.Recurrence.Pattern" + Write-Verbose -Message "Current: $($CurrentValues.ScheduleInfo.Recurrence.Pattern | Out-String)" + Write-Verbose -Message "Desired: $($ValuesToCheck.ScheduleInfo.Recurrence.Pattern | Out-String)" + return $false + } + + # Compare ScheduleInfo.Recurrence.Range + if ($CurrentValues.ScheduleInfo.Recurrence.Range.endDate -ne $ValuesToCheck.ScheduleInfo.Recurrence.Range.endDate -or ` + $CurrentValues.ScheduleInfo.Recurrence.Range.numberOfOccurrences -ne $ValuesToCheck.ScheduleInfo.Recurrence.Range.numberOfOccurrences -or ` + $CurrentValues.ScheduleInfo.Recurrence.Range.recurrenceTimeZone -ne $ValuesToCheck.ScheduleInfo.Recurrence.Range.recurrenceTimeZone -or ` + $CurrentValues.ScheduleInfo.Recurrence.Range.startDate -ne $ValuesToCheck.ScheduleInfo.Recurrence.Range.startDate -or ` + $CurrentValues.ScheduleInfo.Recurrence.Range.type -ne $ValuesToCheck.ScheduleInfo.Recurrence.Range.type) + { + Write-Verbose -Message "Discrepancy found in ScheduleInfo.Recurrence.Range" + Write-Verbose -Message "Current: $($CurrentValues.ScheduleInfo.Recurrence.Range | Out-String)" + Write-Verbose -Message "Desired: $($ValuesToCheck.ScheduleInfo.Recurrence.Range | Out-String)" + return $false + } + } + + Write-Verbose -Message "Current Values: $(Convert-M365DscHashtableToString -Hashtable $CurrentValues)" + Write-Verbose -Message "Target Values: $(Convert-M365DscHashtableToString -Hashtable $ValuesToCheck)" + + $ValuesToCheck.Remove("ScheduleInfo") | Out-Null + $testResult = Test-M365DSCParameterState -CurrentValues $CurrentValues ` + -Source $($MyInvocation.MyCommand.Source) ` + -DesiredValues $PSBoundParameters ` + -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, + + [Parameter()] + [System.String[]] + $AccessTokens + ) + + $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 + { + $Script:ExportMode = $true + #region resource generator code + $schedules = Get-MgBetaRoleManagementDirectoryRoleAssignmentSchedule -All -ErrorAction Stop + [array] $Script:exportedInstances = @() + [array] $allRequests = Get-MgBetaRoleManagementDirectoryRoleAssignmentScheduleRequest -All ` + -Filter "Status ne 'Revoked'" -ErrorAction Stop + foreach ($schedule in $schedules) + { + [array] $Script:exportedInstances += $allRequests | Where-Object -FilterScript {$_.TargetScheduleId -eq $schedule.Id} + } + #endregion + + $i = 1 + $dscContent = '' + if ($Script:exportedInstances.Length -eq 0) + { + Write-Host $Global:M365DSCEmojiGreenCheckMark + } + else + { + Write-Host "`r`n" -NoNewline + } + foreach ($request in $Script:exportedInstances) + { + if ($null -ne $Global:M365DSCExportResourceInstancesCount) + { + $Global:M365DSCExportResourceInstancesCount++ + } + + $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 = $RoleDefinitionId.DisplayName + Ensure = 'Present' + Credential = $Credential + ApplicationId = $ApplicationId + TenantId = $TenantId + ApplicationSecret = $ApplicationSecret + CertificateThumbprint = $CertificateThumbprint + ManagedIdentity = $ManagedIdentity.IsPresent + AccessTokens = $AccessTokens + } + + $Results = Get-TargetResource @Params + + $Results = Update-M365DSCExportAuthenticationResults -ConnectionMode $ConnectionMode ` + -Results $Results + try + { + if ($null -ne $results.ScheduleInfo) + { + $Results.ScheduleInfo = Get-M365DSCAzureADEligibilityRequestScheduleInfoAsString -ScheduleInfo $Results.ScheduleInfo + } + } + catch + { + Write-Verbose -Message "Error converting Schedule: $_" + } + if ($Results.TicketInfo) + { + $Results.TicketInfo = Get-M365DSCAzureADEligibilityRequestTicketInfoAsString -TicketInfo $Results.TicketInfo + } + $currentDSCBlock = Get-M365DSCExportContentForResource -ResourceName $ResourceName ` + -ConnectionMode $ConnectionMode ` + -ModulePath $PSScriptRoot ` + -Results $Results ` + -Credential $Credential + if ($null -ne $Results.ScheduleInfo) + { + $currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock ` + -ParameterName 'ScheduleInfo' + } + if ($null -ne $Results.TicketInfo) + { + $currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock ` + -ParameterName 'TicketInfo' + } + + $dscContent += $currentDSCBlock + Save-M365DSCPartialExport -Content $currentDSCBlock ` + -FileName $Global:PartialExportFileName + $i++ + Write-Host $Global:M365DSCEmojiGreenCheckMark + } + return $dscContent + } + catch + { + if ($_.ErrorDetails.Message -like "*The tenant needs an AAD Premium*" -or ` + $_.ErrorDetails.MEssage -like "*[AadPremiumLicenseRequired]*") + { + Write-Host "`r`n $($Global:M365DSCEmojiYellowCircle) Tenant does not meet license requirement to extract this component." + } + else + { + Write-Verbose -Message "Exception: $($_.Exception.Message)" + Write-Host $Global:M365DSCEmojiRedX + New-M365DSCLogEntry -Message 'Error during Export:' ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + } + + return '' + } +} + +function Get-M365DSCAzureADEligibilityRequestTicketInfoAsString +{ + [CmdletBinding()] + [OutputType([System.String])] + param( + [Parameter(Mandatory = $true)] + [System.Collections.Hashtable] + $TicketInfo + ) + + if ($TicketInfo.TicketNumber -or $TicketInfo.TicketSystem) + { + $StringContent = "MSFT_AADRoleAssignmentScheduleRequestTicketInfo {`r`n" + $StringContent += " ticketNumber = '$($TicketInfo.TicketNumber)'`r`n" + $StringContent += " ticketSystem = '$($TicketInfo.TicketSystem)'`r`n" + $StringContent += " }`r`n" + return $StringContent + } + else + { + return $null + } +} + +function Get-M365DSCAzureADEligibilityRequestScheduleInfoAsString +{ + [CmdletBinding()] + [OutputType([System.String])] + param( + [Parameter(Mandatory = $true)] + [System.Collections.Hashtable] + $ScheduleInfo + ) + + $Found = $false + $StringContent = "MSFT_AADRoleAssignmentScheduleRequestSchedule {`r`n" + if ($ScheduleInfo.StartDateTime) + { + $StringContent += " startDateTime = '$($ScheduleInfo.StartDateTime)'`r`n" + } + if ($ScheduleInfo.Expiration.Duration -or $ScheduleInfo.Expiration.EndDateTime -or $ScheduleInfo.Expiration.Type) + { + $Found = $true + $StringContent += " expiration = MSFT_AADRoleAssignmentScheduleRequestScheduleExpiration`r`n" + $StringContent += " {`r`n" + if ($ScheduleInfo.Expiration.Duration) + { + $StringContent += " duration = '$($ScheduleInfo.Expiration.Duration)'`r`n" + } + if ($ScheduleInfo.Expiration.EndDateTime) + { + $StringContent += " endDateTime = '$($ScheduleInfo.Expiration.EndDateTime.ToString())'`r`n" + } + if($ScheduleInfo.Expiration.Type) + { + $StringContent += " type = '$($ScheduleInfo.Expiration.Type)'`r`n" + } + $StringContent += " }`r`n" + } + if($ScheduleInfo.Recurrence.Pattern.DayOfMonth -or $ScheduleInfo.Recurrence.Pattern.DaysOfWeek -or ` + $ScheduleInfo.Recurrence.Pattern.firstDayOfWeek -or $ScheduleInfo.Recurrence.Pattern.Index -or ` + $ScheduleInfo.Recurrence.Pattern.Interval -or $ScheduleInfo.Recurrence.Pattern.Month -or ` + $ScheduleInfo.Recurrence.Pattern.Type -or $ScheduleInfo.Recurrence.Range.EndDate -or $ScheduleInfo.Recurrence.Range.numberOfOccurrences -or ` + $ScheduleInfo.Recurrence.Range.recurrenceTimeZone -or $ScheduleInfo.Recurrence.Range.startDate -or ` + $ScheduleInfo.Recurrence.Range.type) + { + $StringContent += " recurrence = MSFT_AADRoleAssignmentScheduleRequestScheduleRecurrence`r`n" + $StringContent += " {`r`n" + + if ($ScheduleInfo.Recurrence.Pattern.DayOfMonth -or $ScheduleInfo.Recurrence.Pattern.DaysOfWeek -or ` + $ScheduleInfo.Recurrence.Pattern.firstDayOfWeek -or $ScheduleInfo.Recurrence.Pattern.Index -or ` + $ScheduleInfo.Recurrence.Pattern.Interval -or $ScheduleInfo.Recurrence.Pattern.Month -or ` + $ScheduleInfo.Recurrence.Pattern.Type) + { + $Found = $true + $StringContent += " pattern = MSFT_AADRoleAssignmentScheduleRequestScheduleRecurrencePattern`r`n" + $StringContent += " {`r`n" + if ($ScheduleInfo.Recurrence.Pattern.DayOfMonth) + { + $StringContent += " dayOfMonth = $($ScheduleInfo.Recurrence.Pattern.DayOfMonth)`r`n" + } + if ($ScheduleInfo.Recurrence.Pattern.DaysOfWeek) + { + $StringContent += " daysOfWeek = @($($ScheduleInfo.Recurrence.Pattern.DaysOfWeek -join ','))`r`n" + } + if ($ScheduleInfo.Recurrence.Pattern.firstDayOfWeek) + { + $StringContent += " firstDayOfWeek = '$($ScheduleInfo.Recurrence.Pattern.firstDayOfWeek)'`r`n" + } + if ($ScheduleInfo.Recurrence.Pattern.Index) + { + $StringContent += " index = '$($ScheduleInfo.Recurrence.Pattern.Index)'`r`n" + } + if ($ScheduleInfo.Recurrence.Pattern.Interval) + { + $StringContent += " interval = $($ScheduleInfo.Recurrence.Pattern.Interval.ToString())`r`n" + } + if ($ScheduleInfo.Recurrence.Pattern.Month) + { + $StringContent += " month = $($ScheduleInfo.Recurrence.Pattern.Month.ToString())`r`n" + } + if ($ScheduleInfo.Recurrence.Pattern.Type) + { + $StringContent += " type = '$($ScheduleInfo.Recurrence.Pattern.Type)'`r`n" + } + $StringContent += " }`r`n" + } + if ($ScheduleInfo.Recurrence.Range.EndDate -or $ScheduleInfo.Recurrence.Range.numberOfOccurrences -or ` + $ScheduleInfo.Recurrence.Range.recurrenceTimeZone -or $ScheduleInfo.Recurrence.Range.startDate -or ` + $ScheduleInfo.Recurrence.Range.type) + { + $Found = $true + $StringContent += " range = MSFT_AADRoleAssignmentScheduleRequestScheduleRange`r`n" + $StringContent += " {`r`n" + $StringContent += " endDate = '$($ScheduleInfo.Recurrence.Range.EndDate)'`r`n" + $StringContent += " numberOfOccurrences = $($ScheduleInfo.Recurrence.Range.numberOfOccurrences)`r`n" + $StringContent += " recurrenceTimeZone = '$($ScheduleInfo.Recurrence.Range.recurrenceTimeZone)'`r`n" + $StringContent += " startDate = '$($ScheduleInfo.Recurrence.Range.startDate)'`r`n" + $StringContent += " type = '$($ScheduleInfo.Recurrence.Range.type)'`r`n" + $StringContent += " }`r`n" + } + + $StringContent += " }`r`n" + } + $StringContent += " }`r`n" + + if ($Found) + { + return $StringContent + } + return $null +} + +Export-ModuleMember -Function *-TargetResource diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleAssignmentScheduleRequest/MSFT_AADRoleAssignmentScheduleRequest.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleAssignmentScheduleRequest/MSFT_AADRoleAssignmentScheduleRequest.schema.mof new file mode 100644 index 0000000000..c940cf80b3 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleAssignmentScheduleRequest/MSFT_AADRoleAssignmentScheduleRequest.schema.mof @@ -0,0 +1,75 @@ +[ClassVersion("1.0.0")] +class MSFT_AADRoleAssignmentScheduleRequestScheduleRecurrenceRange +{ + [Required, Description("The date to stop applying the recurrence pattern. Depending on the recurrence pattern of the event, the last occurrence of the meeting may not be this date.")] String endDate; + [Write, Description("The number of times to repeat the event. Required and must be positive if type is numbered.")] UInt32 numberOfOccurrences; + [Write, Description("Time zone for the startDate and endDate properties.")] String recurrenceTimeZone; + [Required, Description("The date to start applying the recurrence pattern. The first occurrence of the meeting may be this date or later, depending on the recurrence pattern of the event. Must be the same value as the start property of the recurring event.")] String startDate; + [Required, Description("The recurrence range. The possible values are: endDate, noEnd, numbered."),ValueMap{"endDate","noEnd","numbered"}, Values{"endDate","noEnd","numbered"}] String type; +}; + +[ClassVersion("1.0.0")] +class MSFT_AADRoleAssignmentScheduleRequestScheduleRecurrencePattern +{ + [Write, Description("The day of the month on which the event occurs.")] UInt32 dayOfMonth; + [Write, Description("A collection of the days of the week on which the event occurs. The possible values are: sunday, monday, tuesday, wednesday, thursday, friday, saturday"), ValueMap{"sunday","monday","tuesday","wednesday","thursday","friday","saturday"}, Values{"sunday","monday","tuesday","wednesday","thursday","friday","saturday"}] String daysOfWeek[]; + [Write, Description("The first day of the week."), ValueMap{"sunday","monday","tuesday","wednesday","thursday","friday","saturday"}, Values{"sunday","monday","tuesday","wednesday","thursday","friday","saturday"}] String firstDayOfWeek; + [Write, Description("Specifies on which instance of the allowed days specified in daysOfWeek the event occurs, counted from the first instance in the month. The possible values are: first, second, third, fourth, last."), ValueMap{"first","second","third","fourth","last"}, Values{"first","second","third","fourth","last"}] String index; + [Write, Description("The number of units between occurrences, where units can be in days, weeks, months, or years, depending on the type.")] UInt32 interval; + [Write, Description("The month in which the event occurs. This is a number from 1 to 12.")] UInt32 month; + [Write, Description("The recurrence pattern type: daily, weekly, absoluteMonthly, relativeMonthly, absoluteYearly, relativeYearly."), ValueMap{"daily","weekly","absoluteMonthly","relativeMonthly","absoluteYearly","relativeYearly"}, Values{"daily","weekly","absoluteMonthly","relativeMonthly","absoluteYearly","relativeYearly"}] String type; +}; + +[ClassVersion("1.0.0")] +class MSFT_AADRoleAssignmentScheduleRequestScheduleRecurrence +{ + [Write, Description("The frequency of an event."), EmbeddedInstance("MSFT_AADRoleAssignmentScheduleRequestScheduleRecurrencePattern")] String pattern; + [Write, Description("The duration of an event."), EmbeddedInstance("MSFT_AADRoleAssignmentScheduleRequestScheduleRecurrenceRange")] String range; +}; + +[ClassVersion("1.0.0")] +class MSFT_AADRoleAssignmentScheduleRequestScheduleExpiration +{ + [Write, Description("The requestor's desired duration of access represented in ISO 8601 format for durations. For example, PT3H refers to three hours. If specified in a request, endDateTime should not be present and the type property should be set to afterDuration.")] String duration; + [Write, Description("Timestamp of date and time information using ISO 8601 format and is always in UTC time. For example, midnight UTC on Jan 1, 2014 is 2014-01-01T00:00:00Z.")] String endDateTime; + [Write, Description("The requestor's desired expiration pattern type. The possible values are: notSpecified, noExpiration, afterDateTime, afterDuration."), ValueMap{"notSpecified","noExpiration","afterDateTime","afterDuration"}, Values{"notSpecified","noExpiration","afterDateTime","afterDuration"}] String type; +}; + +[ClassVersion("1.0.0")] +class MSFT_AADRoleAssignmentScheduleRequestSchedule +{ + [Write, Description("When the eligible or active assignment expires."), EmbeddedInstance("MSFT_AADRoleAssignmentScheduleRequestScheduleExpiration")] String expiration; + [Write, Description("The frequency of the eligible or active assignment. This property is currently unsupported in PIM."), EmbeddedInstance("MSFT_AADRoleAssignmentScheduleRequestScheduleRecurrence")] String recurrence; + [Write, Description("When the eligible or active assignment becomes active.")] String startDateTime; +}; + +[ClassVersion("1.0.0")] +class MSFT_AADRoleAssignmentScheduleRequestTicketInfo +{ + [Write, Description("The ticket number.")] String ticketNumber; + [Write, Description("The description of the ticket system.")] String ticketSystem; +}; + +[ClassVersion("1.0.0.0"), FriendlyName("AADRoleAssignmentScheduleRequest")] +class MSFT_AADRoleAssignmentScheduleRequest : OMI_BaseResource +{ + [Key, Description("User Principal Name of the eligibility request.")] String Principal; + [Key, Description("Role associated with the eligibility request.")] String RoleDefinition; + [Write, Description("Represented the type of principal to assign the request to. Accepted values are: Group and User."), ValueMap{"Group","User"}, Values{"Group","User"}] String PrincipalType; + [Write, Description("Identifier of the directory object representing the scope of the role eligibility. The scope of an role eligibility determines the set of resources for which the principal has been granted access. Directory scopes are shared scopes stored in the directory that are understood by multiple applications. Use / for tenant-wide scope. Use appScopeId to limit the scope to an application only. Either directoryScopeId or appScopeId is required.")] String DirectoryScopeId; + [Write, Description("Identifier for the Role Eligibility Schedule Request.")] String Id; + [Write, Description("Identifier of the app-specific scope when the role eligibility is scoped to an app. The scope of a role eligibility determines the set of resources for which the principal is eligible to access. App scopes are scopes that are defined and understood by this application only. Use / for tenant-wide app scopes. Use directoryScopeId to limit the scope to particular directory objects, for example, administrative units. Either directoryScopeId or appScopeId is required.")] String AppScopeId; + [Write, Description("Represents the type of operation on the role eligibility request.The possible values are: adminAssign, adminUpdate, adminRemove, selfActivate, selfDeactivate, adminExtend, adminRenew, selfExtend, selfRenew, unknownFutureValue."), ValueMap{"adminAssign","adminUpdate","adminRemove","selfActivate","selfDeactivate","adminExtend","adminRenew","selfExtend","selfRenew","unknownFutureValue"}, Values{"adminAssign","adminUpdate","adminRemove","selfActivate","selfDeactivate","adminExtend","adminRenew","selfExtend","selfRenew","unknownFutureValue"}] String Action; + [Write, Description("Determines whether the call is a validation or an actual call. Only set this property if you want to check whether an activation is subject to additional rules like MFA before actually submitting the request.")] Boolean IsValidationOnly; + [Write, Description("A message provided by users and administrators when create they create the unifiedRoileAssignmentScheduleRequest object. Optional when action is adminRemove. Whether this property is required or optional is also dependent on the settings for the Azure AD role.")] String Justification; + [Write, Description("The period of the role eligibility. Optional when action is adminRemove. The period of eligibility is dependent on the settings of the Azure AD role."), EmbeddedInstance("MSFT_AADRoleAssignmentScheduleRequestSchedule")] String ScheduleInfo; + [Write, Description("Ticket details linked to the role eligibility request including details of the ticket number and ticket system."), EmbeddedInstance("MSFT_AADRoleAssignmentScheduleRequestTicketInfo")] String TicketInfo; + [Write, Description("Present ensures the instance exists, absent ensures it is removed."), ValueMap{"Present","Absent"}, Values{"Present","Absent"}] string Ensure; + [Write, Description("Credentials of the Intune Admin"), EmbeddedInstance("MSFT_Credential")] string Credential; + [Write, Description("Id of the Azure Active Directory application to authenticate with.")] String ApplicationId; + [Write, Description("Id of the Azure Active Directory tenant used for authentication.")] String TenantId; + [Write, Description("Secret of the Azure Active Directory application to authenticate with."), 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("Access token used for authentication.")] String AccessTokens[]; +}; diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleAssignmentScheduleRequest/readme.md b/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleAssignmentScheduleRequest/readme.md new file mode 100644 index 0000000000..bcec0502ad --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleAssignmentScheduleRequest/readme.md @@ -0,0 +1,6 @@ + +# AADRoleAssignmentScheduleRequest + +## Description + +This resource configures an Azure Active Directory Privilege Identity Management assignment. diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleAssignmentScheduleRequest/settings.json b/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleAssignmentScheduleRequest/settings.json new file mode 100644 index 0000000000..6bcd855bee --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleAssignmentScheduleRequest/settings.json @@ -0,0 +1,28 @@ +{ + "resourceName": "AADRoleAssignmentScheduleRequest", + "description": "This resource configures an Azure Active Directory Privilege Identity Management assignment.", + "roles": { + "read": [ + "Security Reader" + ], + "update": [ + "Privileged Role Administrator" + ] + }, + "permissions": { + "graph": { + "application": { + "read": [ + { + "name": "RoleAssignmentSchedule.Read.Directory" + } + ], + "update": [ + { + "name": "RoleAssignmentSchedule.ReadWrite.Directory" + } + ] + } + } + } +} diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleEligibilityScheduleRequest/settings.json b/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleEligibilityScheduleRequest/settings.json index 920f41deef..357f40c509 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleEligibilityScheduleRequest/settings.json +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleEligibilityScheduleRequest/settings.json @@ -1,6 +1,6 @@ { "resourceName": "AADRoleEligibilityScheduleRequest", - "description": "This resource configures an Azure Active Directory administrative unit.", + "description": "This resource configures an Azure Active Directory Privilege Identity Management eligibility request.", "roles": { "read": [ "Security Reader" diff --git a/Modules/Microsoft365DSC/Examples/Resources/AADRoleAssignmentScheduleRequest/1-Create.ps1 b/Modules/Microsoft365DSC/Examples/Resources/AADRoleAssignmentScheduleRequest/1-Create.ps1 new file mode 100644 index 0000000000..b516274848 --- /dev/null +++ b/Modules/Microsoft365DSC/Examples/Resources/AADRoleAssignmentScheduleRequest/1-Create.ps1 @@ -0,0 +1,26 @@ +<# +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()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint + ) + Import-DscResource -ModuleName Microsoft365DSC + node localhost + { + + } +} diff --git a/Modules/Microsoft365DSC/Examples/Resources/AADRoleAssignmentScheduleRequest/2-Update.ps1 b/Modules/Microsoft365DSC/Examples/Resources/AADRoleAssignmentScheduleRequest/2-Update.ps1 new file mode 100644 index 0000000000..b516274848 --- /dev/null +++ b/Modules/Microsoft365DSC/Examples/Resources/AADRoleAssignmentScheduleRequest/2-Update.ps1 @@ -0,0 +1,26 @@ +<# +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()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint + ) + Import-DscResource -ModuleName Microsoft365DSC + node localhost + { + + } +} diff --git a/Modules/Microsoft365DSC/Examples/Resources/AADRoleAssignmentScheduleRequest/3-Remove.ps1 b/Modules/Microsoft365DSC/Examples/Resources/AADRoleAssignmentScheduleRequest/3-Remove.ps1 new file mode 100644 index 0000000000..b516274848 --- /dev/null +++ b/Modules/Microsoft365DSC/Examples/Resources/AADRoleAssignmentScheduleRequest/3-Remove.ps1 @@ -0,0 +1,26 @@ +<# +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()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint + ) + Import-DscResource -ModuleName Microsoft365DSC + node localhost + { + + } +} diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADRoleAssignmentScheduleRequest.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADRoleAssignmentScheduleRequest.Tests.ps1 new file mode 100644 index 0000000000..780e0f343d --- /dev/null +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADRoleAssignmentScheduleRequest.Tests.ps1 @@ -0,0 +1,178 @@ +[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) + +$CurrentScriptPath = $PSCommandPath.Split('\') +$CurrentScriptName = $CurrentScriptPath[$CurrentScriptPath.Length -1] +$ResourceName = $CurrentScriptName.Split('.')[1] +$Global:DscHelper = New-M365DscUnitTestHelper -StubModule $CmdletModule ` + -DscResource $ResourceName -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 (New-Guid | Out-String) -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" + } + + ##TODO - Mock any Remove/Set/New cmdlets + + # Mock Write-Host to hide output during the tests + Mock -CommandName Write-Host -MockWith { + } + $Script:exportedInstances =$null + $Script:ExportMode = $false + } + # Test contexts + Context -Name "The instance should exist but it DOES NOT" -Fixture { + BeforeAll { + $testParams = @{ + ##TODO - Add Parameters + Ensure = 'Present' + Credential = $Credential; + } + + ##TODO - Mock the Get-Cmdlet to return $null + Mock -CommandName Get-Cmdlet -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 + } + + It 'Should create a new instance from the Set method' { + ##TODO - Replace the New-Cmdlet by the appropriate one + Set-TargetResource @testParams + Should -Invoke -CommandName New-Cmdlet -Exactly 1 + } + } + + Context -Name "The instance exists but it SHOULD NOT" -Fixture { + BeforeAll { + $testParams = @{ + ##TODO - Add Parameters + Ensure = 'Absent' + Credential = $Credential; + } + + ##TODO - Mock the Get-Cmdlet to return an instance + Mock -CommandName Get-Cmdlet -MockWith { + return @{ + + } + } + } + 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 remove the instance from the Set method' { + Set-TargetResource @testParams + ##TODO - Replace the Remove-Cmdlet by the appropriate one + Should -Invoke -CommandName Remove-Cmdlet -Exactly 1 + } + } + + Context -Name "The instance exists and values are already in the desired state" -Fixture { + BeforeAll { + $testParams = @{ + ##TODO - Add Parameters + Ensure = 'Present' + Credential = $Credential; + } + + ##TODO - Mock the Get-Cmdlet to return the desired values + Mock -CommandName Get-Cmdlet -MockWith { + return @{ + + } + } + } + + 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 = @{ + ##TODO - Add Parameters + Ensure = 'Present' + Credential = $Credential; + } + + ##TODO - Mock the Get-Cmdlet to return a drift + Mock -CommandName Get-Cmdlet -MockWith { + return @{ + + } + } + } + + 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 + ##TODO - Replace the Update-Cmdlet by the appropriate one + Should -Invoke -CommandName Update-Cmdlet -Exactly 1 + } + } + + Context -Name 'ReverseDSC Tests' -Fixture { + BeforeAll { + $Global:CurrentModeIsExport = $true + $Global:PartialExportFileName = "$(New-Guid).partial.ps1" + $testParams = @{ + Credential = $Credential; + } + + ##TODO - Mock the Get-Cmdlet to return an instance + Mock -CommandName Get-Cmdlet -MockWith { + return @{ + + } + } + } + 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 9983a329c6c0151992512d944f1ca883e520dafa Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Tue, 19 Nov 2024 13:02:15 +0100 Subject: [PATCH 25/65] Fixing #5420 --- CHANGELOG.md | 36 ++++ .../MSFT_AADAdminConsentRequestPolicy.psm1 | 20 ++- ...thenticationMethodPolicyAuthenticator.psm1 | 167 +++++++++++++++--- ...FT_AADAuthenticationMethodPolicyEmail.psm1 | 99 ++++++++--- ...AADAuthenticationMethodPolicyExternal.psm1 | 82 ++++++--- ...FT_AADAuthenticationMethodPolicyFido2.psm1 | 103 +++++++---- ...AADAuthenticationMethodPolicyHardware.psm1 | 63 +++++-- ...MSFT_AADAuthenticationMethodPolicySms.psm1 | 99 ++++++++--- ...AADAuthenticationMethodPolicySoftware.psm1 | 96 +++++++--- ...ADAuthenticationMethodPolicyTemporary.psm1 | 103 +++++++---- ...FT_AADAuthenticationMethodPolicyVoice.psm1 | 96 +++++++--- ...SFT_AADAuthenticationMethodPolicyX509.psm1 | 89 +++++++--- .../MSFT_AADDeviceRegistrationPolicy.psm1 | 68 ++++++- 13 files changed, 847 insertions(+), 274 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c983de7fe7..5a58cc57f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,39 @@ # UNRELEASED +* AADAdminConsentRequestPolicy + * Added error handling to Group display name retrieval to prevent errors + when an assigned group no longer exists. +* AADAuthenticationMethodPolicyAuthenticator + * Added error handling to Group display name retrieval to prevent errors + when an assigned group no longer exists. +* AADAuthenticationMethodPolicyEmail + * Added error handling to Group display name retrieval to prevent errors + when an assigned group no longer exists. +* AADAuthenticationMethodPolicyExternal + * Added error handling to Group display name retrieval to prevent errors + when an assigned group no longer exists. +* AADAuthenticationMethodPolicyFido2 + * Added error handling to Group display name retrieval to prevent errors + when an assigned group no longer exists. +* AADAuthenticationMethodPolicyHardware + * Added error handling to Group display name retrieval to prevent errors + when an assigned group no longer exists. +* AADAuthenticationMethodPolicySms + * Added error handling to Group display name retrieval to prevent errors + when an assigned group no longer exists. +* AADAuthenticationMethodPolicySoftware + * Added error handling to Group display name retrieval to prevent errors + when an assigned group no longer exists. +* AADAuthenticationMethodPolicyTemporary + * Added error handling to Group display name retrieval to prevent errors + when an assigned group no longer exists. +* AADAuthenticationMethodPolicyVoice + * Added error handling to Group display name retrieval to prevent errors + when an assigned group no longer exists. +* AADAuthenticationMethodPolicyX509 + * Added error handling to Group display name retrieval to prevent errors + when an assigned group no longer exists. * AADConditionalAccessPolicy * Fixed bug where a null value was passed in the request for the excludePlatforms parameter when just values were assigned to includePlatforms, which throws an error. @@ -9,6 +42,9 @@ sessionControl parameter when there are no session controls, which throws an error. * Fixed bug where a null value was passed in the request for the applicationEnforcedRestrictions parameter when value was set to false, which throws an error. +* AADDeviceRegistrationPolicy + * Added error handling to Group display name retrieval to prevent errors + when an assigned group no longer exists. * AADRoleEligibilityScheduleRequest * Adds support for custom role assignments at app scope. * IntuneFirewallRulesHyperVPolicyWindows10 diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAdminConsentRequestPolicy/MSFT_AADAdminConsentRequestPolicy.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAdminConsentRequestPolicy/MSFT_AADAdminConsentRequestPolicy.psm1 index 682756ab41..88b9e6c5f6 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAdminConsentRequestPolicy/MSFT_AADAdminConsentRequestPolicy.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAdminConsentRequestPolicy/MSFT_AADAdminConsentRequestPolicy.psm1 @@ -97,10 +97,22 @@ function Get-TargetResource elseif ($reviewer.Query.Contains('/groups/')) { $groupId = $reviewer.Query.Split('/')[3] - $groupInfo = Get-MgGroup -GroupId $groupId - $entry = @{ - ReviewerType = 'Group' - ReviewerId = $groupInfo.DisplayName + try + { + $groupInfo = Get-MgGroup -GroupId $groupId -ErrorAction SilentlyContinue + $entry = @{ + ReviewerType = 'Group' + ReviewerId = $groupInfo.DisplayName + } + } + catch + { + $message = "Group with ID $groupId specified in Reviewers not found" + New-M365DSCLogEntry -Message $message ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue } } elseif ($reviewer.Query.Contains('directory/roleAssignments?$')) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyAuthenticator/MSFT_AADAuthenticationMethodPolicyAuthenticator.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyAuthenticator/MSFT_AADAuthenticationMethodPolicyAuthenticator.psm1 index a06f995f97..121463a947 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyAuthenticator/MSFT_AADAuthenticationMethodPolicyAuthenticator.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyAuthenticator/MSFT_AADAuthenticationMethodPolicyAuthenticator.psm1 @@ -5,6 +5,10 @@ function Get-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [Microsoft.Management.Infrastructure.CimInstance] $FeatureSettings, @@ -25,10 +29,6 @@ function Get-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, #endregion [Parameter()] @@ -65,6 +65,8 @@ function Get-TargetResource $AccessTokens ) + Write-Verbose -Message "Getting the Azure AD Authentication Method Policy with Id {$Id}" + try { $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` @@ -100,12 +102,26 @@ function Get-TargetResource #region resource generator code $complexFeatureSettings = @{} + + Write-Verbose "Processing FeatureSettings > companionAppAllowedState > excludeTarget" $complexCompanionAppAllowedState = @{} $complexExcludeTarget = @{} if ($getValue.additionalProperties.featureSettings.companionAppAllowedState.excludeTarget.id -notmatch 'all_users|00000000-0000-0000-0000-000000000000') { - $myExcludeTargetsDisplayName = Get-MgGroup -GroupId $getValue.additionalProperties.featureSettings.companionAppAllowedState.excludeTarget.id - $complexExcludeTarget.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + try + { + $myExcludeTargetsDisplayName = Get-MgGroup -GroupId $getValue.additionalProperties.featureSettings.companionAppAllowedState.excludeTarget.id -ErrorAction Stop + $complexExcludeTarget.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($getValue.additionalProperties.featureSettings.companionAppAllowedState.excludeTarget.id) specified in excludeTarget. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + } } else { @@ -118,20 +134,36 @@ function Get-TargetResource $complexExcludeTarget.Add('Id', 'all_users') } } + if ($null -ne $getValue.additionalProperties.featureSettings.companionAppAllowedState.excludeTarget.targetType) { $complexExcludeTarget.Add('TargetType', $getValue.additionalProperties.featureSettings.companionAppAllowedState.excludeTarget.targetType.toString()) } + if ($complexExcludeTarget.values.Where({ $null -ne $_ }).count -eq 0) { $complexExcludeTarget = $null } $complexCompanionAppAllowedState.Add('ExcludeTarget', $complexExcludeTarget) + + Write-Verbose "Processing FeatureSettings > companionAppAllowedState > includeTarget" $complexIncludeTarget = @{} if ($getValue.additionalProperties.featureSettings.companionAppAllowedState.includeTarget.id -notmatch 'all_users|00000000-0000-0000-0000-000000000000') { - $myIncludeTargetsDisplayName = Get-MgGroup -GroupId $getValue.additionalProperties.featureSettings.companionAppAllowedState.includeTarget.id - $complexIncludeTarget.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + try + { + $myIncludeTargetsDisplayName = Get-MgGroup -GroupId $getValue.additionalProperties.featureSettings.companionAppAllowedState.includeTarget.id -ErrorAction Stop + $complexIncludeTarget.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($getValue.additionalProperties.featureSettings.companionAppAllowedState.includeTarget.id) specified in includeTarget. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + } } else { @@ -144,31 +176,50 @@ function Get-TargetResource $complexIncludeTarget.Add('Id', 'all_users') } } + if ($null -ne $getValue.additionalProperties.featureSettings.companionAppAllowedState.includeTarget.targetType) { $complexIncludeTarget.Add('TargetType', $getValue.additionalProperties.featureSettings.companionAppAllowedState.includeTarget.targetType.toString()) } + if ($complexIncludeTarget.values.Where({ $null -ne $_ }).count -eq 0) { $complexIncludeTarget = $null } $complexCompanionAppAllowedState.Add('IncludeTarget', $complexIncludeTarget) + + Write-Verbose "Processing FeatureSettings > companionAppAllowedState > state" if ($null -ne $getValue.additionalProperties.featureSettings.companionAppAllowedState.state) { $complexCompanionAppAllowedState.Add('State', $getValue.additionalProperties.featureSettings.companionAppAllowedState.state.toString()) } + if ($complexCompanionAppAllowedState.values.Where({ $null -ne $_ }).count -eq 0) { $complexCompanionAppAllowedState = $null } + $complexFeatureSettings.Add('CompanionAppAllowedState', $complexCompanionAppAllowedState) $complexDisplayAppInformationRequiredState = @{} + Write-Verbose "Processing FeatureSettings > displayAppInformationRequiredState > excludeTarget" $complexExcludeTarget = @{} if ($getValue.additionalProperties.featureSettings.displayAppInformationRequiredState.excludeTarget.id -notmatch 'all_users|00000000-0000-0000-0000-000000000000') { - $myExcludeTargetsDisplayName = Get-MgGroup -GroupId $getValue.additionalProperties.featureSettings.displayAppInformationRequiredState.excludeTarget.id - $complexExcludeTarget.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + try + { + $myExcludeTargetsDisplayName = Get-MgGroup -GroupId $getValue.additionalProperties.featureSettings.displayAppInformationRequiredState.excludeTarget.id -ErrorAction Stop + $complexExcludeTarget.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($getValue.additionalProperties.featureSettings.displayAppInformationRequiredState.excludeTarget.id) specified in excludeTarget. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + } } else { @@ -181,6 +232,7 @@ function Get-TargetResource $complexExcludeTarget.Add('Id', 'all_users') } } + if ($null -ne $getValue.additionalProperties.featureSettings.displayAppInformationRequiredState.excludeTarget.targetType) { $complexExcludeTarget.Add('TargetType', $getValue.additionalProperties.featureSettings.displayAppInformationRequiredState.excludeTarget.targetType.toString()) @@ -190,11 +242,25 @@ function Get-TargetResource $complexExcludeTarget = $null } $complexDisplayAppInformationRequiredState.Add('ExcludeTarget', $complexExcludeTarget) + + Write-Verbose "Processing FeatureSettings > displayAppInformationRequiredState > includeTarget" $complexIncludeTarget = @{} if ($getValue.additionalProperties.featureSettings.displayAppInformationRequiredState.includeTarget.id -notmatch 'all_users|00000000-0000-0000-0000-000000000000') { - $myIncludeTargetsDisplayName = Get-MgGroup -GroupId $getValue.additionalProperties.featureSettings.displayAppInformationRequiredState.includeTarget.id - $complexIncludeTarget.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + try + { + $myIncludeTargetsDisplayName = Get-MgGroup -GroupId $getValue.additionalProperties.featureSettings.displayAppInformationRequiredState.includeTarget.id -ErrorAction Stop + $complexIncludeTarget.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($getValue.additionalProperties.featureSettings.displayAppInformationRequiredState.includeTarget.id) specified in includeTarget. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + } } else { @@ -207,30 +273,50 @@ function Get-TargetResource $complexIncludeTarget.Add('Id', 'all_users') } } + if ($null -ne $getValue.additionalProperties.featureSettings.displayAppInformationRequiredState.includeTarget.targetType) { $complexIncludeTarget.Add('TargetType', $getValue.additionalProperties.featureSettings.displayAppInformationRequiredState.includeTarget.targetType.toString()) } + if ($complexIncludeTarget.values.Where({ $null -ne $_ }).count -eq 0) { $complexIncludeTarget = $null } $complexDisplayAppInformationRequiredState.Add('IncludeTarget', $complexIncludeTarget) + + Write-Verbose "Processing FeatureSettings > displayAppInformationRequiredState > state" if ($null -ne $getValue.additionalProperties.featureSettings.displayAppInformationRequiredState.state) { $complexDisplayAppInformationRequiredState.Add('State', $getValue.additionalProperties.featureSettings.displayAppInformationRequiredState.state.toString()) } + if ($complexDisplayAppInformationRequiredState.values.Where({ $null -ne $_ }).count -eq 0) { $complexDisplayAppInformationRequiredState = $null } + $complexFeatureSettings.Add('DisplayAppInformationRequiredState', $complexDisplayAppInformationRequiredState) + + Write-Verbose "Processing FeatureSettings > displayLocationInformationRequiredState > excludeTarget" $complexDisplayLocationInformationRequiredState = @{} $complexExcludeTarget = @{} if ($getValue.additionalProperties.featureSettings.displayLocationInformationRequiredState.excludeTarget.id -notmatch 'all_users|00000000-0000-0000-0000-000000000000') { - $myExcludeTargetsDisplayName = Get-MgGroup -GroupId $getValue.additionalProperties.featureSettings.displayLocationInformationRequiredState.excludeTarget.id - $complexExcludeTarget.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + try + { + $myExcludeTargetsDisplayName = Get-MgGroup -GroupId $getValue.additionalProperties.featureSettings.displayLocationInformationRequiredState.excludeTarget.id -ErrorAction Stop + $complexExcludeTarget.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($getValue.additionalProperties.featureSettings.displayLocationInformationRequiredState.excludeTarget.id) specified in excludeTarget. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + } } else { @@ -243,20 +329,37 @@ function Get-TargetResource $complexExcludeTarget.Add('Id', 'all_users') } } + if ($null -ne $getValue.additionalProperties.featureSettings.displayLocationInformationRequiredState.excludeTarget.targetType) { $complexExcludeTarget.Add('TargetType', $getValue.additionalProperties.featureSettings.displayLocationInformationRequiredState.excludeTarget.targetType.toString()) } + if ($complexExcludeTarget.values.Where({ $null -ne $_ }).count -eq 0) { $complexExcludeTarget = $null } + $complexDisplayLocationInformationRequiredState.Add('ExcludeTarget', $complexExcludeTarget) + + Write-Verbose "Processing FeatureSettings > displayLocationInformationRequiredState > includeTarget" $complexIncludeTarget = @{} if ($getValue.additionalProperties.featureSettings.displayLocationInformationRequiredState.includeTarget.id -notmatch 'all_users|00000000-0000-0000-0000-000000000000') { - $myIncludeTargetsDisplayName = Get-MgGroup -GroupId $getValue.additionalProperties.featureSettings.displayLocationInformationRequiredState.includeTarget.id - $complexIncludeTarget.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + try + { + $myIncludeTargetsDisplayName = Get-MgGroup -GroupId $getValue.additionalProperties.featureSettings.displayLocationInformationRequiredState.includeTarget.id -ErrorAction Stop + $complexIncludeTarget.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($getValue.additionalProperties.featureSettings.displayLocationInformationRequiredState.includeTarget.id) specified in includeTarget. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + } } else { @@ -269,23 +372,30 @@ function Get-TargetResource $complexIncludeTarget.Add('Id', 'all_users') } } + if ($null -ne $getValue.additionalProperties.featureSettings.displayLocationInformationRequiredState.includeTarget.targetType) { $complexIncludeTarget.Add('TargetType', $getValue.additionalProperties.featureSettings.displayLocationInformationRequiredState.includeTarget.targetType.toString()) } + if ($complexIncludeTarget.values.Where({ $null -ne $_ }).count -eq 0) { $complexIncludeTarget = $null } + $complexDisplayLocationInformationRequiredState.Add('IncludeTarget', $complexIncludeTarget) + + Write-Verbose "Processing FeatureSettings > displayLocationInformationRequiredState > state" if ($null -ne $getValue.additionalProperties.featureSettings.displayLocationInformationRequiredState.state) { $complexDisplayLocationInformationRequiredState.Add('State', $getValue.additionalProperties.featureSettings.displayLocationInformationRequiredState.state.toString()) } + if ($complexDisplayLocationInformationRequiredState.values.Where({ $null -ne $_ }).count -eq 0) { $complexDisplayLocationInformationRequiredState = $null } + $complexFeatureSettings.Add('DisplayLocationInformationRequiredState', $complexDisplayLocationInformationRequiredState) $complexExcludeTargets = @() @@ -305,10 +415,12 @@ function Get-TargetResource { $myExcludeTargets.Add('Id', $currentExcludeTargets.id) } + if ($null -ne $currentExcludeTargets.targetType) { $myExcludeTargets.Add('TargetType', $currentExcludeTargets.targetType.toString()) } + if ($myExcludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexExcludeTargets += $myExcludeTargets @@ -332,10 +444,12 @@ function Get-TargetResource { $myIncludeTargets.Add('Id', $currentIncludeTargets.id) } + if ($null -ne $currentIncludeTargets.targetType) { $myIncludeTargets.Add('TargetType', $currentIncludeTargets.targetType.toString()) } + if ($myIncludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexIncludeTargets += $myIncludeTargets @@ -389,6 +503,10 @@ function Set-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [Microsoft.Management.Infrastructure.CimInstance] $FeatureSettings, @@ -409,12 +527,8 @@ function Set-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion + [Parameter()] [System.String] [ValidateSet('Absent', 'Present')] @@ -449,6 +563,8 @@ function Set-TargetResource $AccessTokens ) + Write-Verbose -Message "Setting the Azure AD Authentication Method Policy Authenticator with Id {$Id}" + #Ensure the proper dependencies are installed in the current environment. Confirm-M365DSCDependencies @@ -589,6 +705,10 @@ function Test-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [Microsoft.Management.Infrastructure.CimInstance] $FeatureSettings, @@ -609,11 +729,6 @@ function Test-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion [Parameter()] diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyEmail/MSFT_AADAuthenticationMethodPolicyEmail.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyEmail/MSFT_AADAuthenticationMethodPolicyEmail.psm1 index 5ceea269ca..120f294f03 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyEmail/MSFT_AADAuthenticationMethodPolicyEmail.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyEmail/MSFT_AADAuthenticationMethodPolicyEmail.psm1 @@ -5,6 +5,10 @@ function Get-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [ValidateSet('default', 'enabled', 'disabled', 'unknownFutureValue')] [System.String] @@ -22,11 +26,6 @@ function Get-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion [Parameter()] @@ -63,6 +62,8 @@ function Get-TargetResource $AccessTokens ) + Write-Verbose -Message "Getting the Azure AD Authentication Method Policy Email with Id {$Id}" + try { $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` @@ -101,17 +102,34 @@ function Get-TargetResource foreach ($currentExcludeTargets in $getValue.excludeTargets) { $myExcludeTargets = @{} - if ($currentExcludeTargets.id -ne 'all_users'){ - $myExcludeTargetsDisplayName = get-MgGroup -GroupId $currentExcludeTargets.id - $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + if ($currentExcludeTargets.id -ne 'all_users') + { + try + { + $myExcludeTargetsDisplayName = Get-MgGroup -GroupId $currentExcludeTargets.id + $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($currentExcludeTargets.id) specified in ExcludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myExcludeTargets.Add('Id', $currentExcludeTargets.id) } + if ($null -ne $currentExcludeTargets.targetType) { $myExcludeTargets.Add('TargetType', $currentExcludeTargets.targetType.toString()) } + if ($myExcludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexExcludeTargets += $myExcludeTargets @@ -130,24 +148,40 @@ function Get-TargetResource foreach ($currentincludeTargets in $getValue.AdditionalProperties.includeTargets) { $myincludeTargets = @{} - if ($currentIncludeTargets.id -ne 'all_users'){ - $myIncludeTargetsDisplayName = get-MgGroup -GroupId $currentIncludeTargets.id - $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + if ($currentIncludeTargets.id -ne 'all_users') + { + try + { + $myIncludeTargetsDisplayName = Get-MgGroup -GroupId $currentIncludeTargets.id + $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($currentIncludeTargets.id) specified in IncludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myIncludeTargets.Add('Id', $currentIncludeTargets.id) } + if ($null -ne $currentincludeTargets.targetType) { $myincludeTargets.Add('TargetType', $currentincludeTargets.targetType.toString()) } + if ($myincludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexIncludeTargets += $myincludeTargets } } - $enumState = $null if ($null -ne $getValue.State) { @@ -193,6 +227,10 @@ function Set-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [ValidateSet('default', 'enabled', 'disabled', 'unknownFutureValue')] [System.String] @@ -210,12 +248,8 @@ function Set-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion + [Parameter()] [System.String] [ValidateSet('Absent', 'Present')] @@ -250,6 +284,8 @@ function Set-TargetResource $AccessTokens ) + Write-Verbose -Message "Setting the Azure AD Authentication Method Policy Email with Id {$Id}" + #Ensure the proper dependencies are installed in the current environment. Confirm-M365DSCDependencies @@ -284,24 +320,28 @@ function Set-TargetResource } if ($key -eq 'IncludeTargets') { + Write-Verbose -Message "Processing IncludeTargets" $i = 0 - foreach ($entry in $UpdateParameters.$key){ + foreach ($entry in $UpdateParameters.$key) + { if ($entry.id -notmatch '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$|all_users') { $Filter = "Displayname eq '$($entry.id)'" | Out-String - $UpdateParameters.$key[$i].foreach('id',(Get-MgGroup -Filter $Filter).id.ToString()) + $UpdateParameters.$key[$i].foreach('id', (Get-MgGroup -Filter $Filter).id.ToString()) } $i++ } } if ($key -eq 'ExcludeTargets') { + Write-Verbose -Message "Processing ExcludeTargets" $i = 0 - foreach ($entry in $UpdateParameters.$key){ + foreach ($entry in $UpdateParameters.$key) + { if ($entry.id -notmatch '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$|all_users') { $Filter = "Displayname eq '$($entry.id)'" | Out-String - $UpdateParameters.$key[$i].foreach('id',(Get-MgGroup -Filter $Filter).id.ToString()) + $UpdateParameters.$key[$i].foreach('id', (Get-MgGroup -Filter $Filter).id.ToString()) } $i++ } @@ -330,6 +370,10 @@ function Test-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [ValidateSet('default', 'enabled', 'disabled', 'unknownFutureValue')] [System.String] @@ -347,11 +391,6 @@ function Test-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion [Parameter()] @@ -388,6 +427,8 @@ function Test-TargetResource $AccessTokens ) + Write-Verbose -Message "Testing the Azure AD Authentication Method Policy Email with Id {$Id}" + #Ensure the proper dependencies are installed in the current environment. Confirm-M365DSCDependencies @@ -508,7 +549,7 @@ function Export-TargetResource #region resource generator code [array]$getValue = Get-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration ` -AuthenticationMethodConfigurationId Email ` - -ErrorAction Stop | Where-Object -FilterScript {$null -ne $_.Id} + -ErrorAction Stop | Where-Object -FilterScript { $null -ne $_.Id } #endregion $i = 1 diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyExternal/MSFT_AADAuthenticationMethodPolicyExternal.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyExternal/MSFT_AADAuthenticationMethodPolicyExternal.psm1 index bb71db082e..ecd65ce44b 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyExternal/MSFT_AADAuthenticationMethodPolicyExternal.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyExternal/MSFT_AADAuthenticationMethodPolicyExternal.psm1 @@ -92,12 +92,12 @@ function Get-TargetResource { if ($null -ne $Script:exportedInstances -and $Script:ExportMode) { - $getValue = $Script:exportedInstances | Where-Object -FilterScript {$_.DisplayName -eq $DisplayName} + $getValue = $Script:exportedInstances | Where-Object -FilterScript { $_.DisplayName -eq $DisplayName } } else { - $response = Invoke-MgGraphRequest -Method Get -Uri ($Global:MSCloudLoginConnectionProfile.MicrosoftGraph.ResourceUrl + "beta/policies/authenticationMethodsPolicy/") - $getValue = $response.authenticationMethodConfigurations | Where-Object -FilterScript {$_.DisplayName -eq $DisplayName} + $response = Invoke-MgGraphRequest -Method Get -Uri ($Global:MSCloudLoginConnectionProfile.MicrosoftGraph.ResourceUrl + 'beta/policies/authenticationMethodsPolicy/') + $getValue = $response.authenticationMethodConfigurations | Where-Object -FilterScript { $_.DisplayName -eq $DisplayName } } } @@ -115,17 +115,34 @@ function Get-TargetResource foreach ($currentExcludeTargets in $getValue.excludeTargets) { $myExcludeTargets = @{} - if ($currentExcludeTargets.id -ne 'all_users'){ - $myExcludeTargetsDisplayName = get-MgGroup -GroupId $currentExcludeTargets.id - $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + if ($currentExcludeTargets.id -ne 'all_users') + { + try + { + $myExcludeTargetsDisplayName = Get-MgGroup -GroupId $currentExcludeTargets.id -ErrorAction Stop + $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($currentExcludeTargets.id) specified in ExcludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myExcludeTargets.Add('Id', $currentExcludeTargets.id) } + if ($null -ne $currentExcludeTargets.targetType) { $myExcludeTargets.Add('TargetType', $currentExcludeTargets.targetType.toString()) } + if ($myExcludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexExcludeTargets += $myExcludeTargets @@ -137,17 +154,34 @@ function Get-TargetResource foreach ($currentincludeTargets in $getValue.includeTargets) { $myincludeTargets = @{} - if ($currentIncludeTargets.id -ne 'all_users'){ - $myIncludeTargetsDisplayName = get-MgGroup -GroupId $currentIncludeTargets.id - $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + if ($currentIncludeTargets.id -ne 'all_users') + { + try + { + $myIncludeTargetsDisplayName = Get-MgGroup -GroupId $currentIncludeTargets.id -ErrorAction Stop + $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($currentIncludeTargets.id) specified in IncludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myIncludeTargets.Add('Id', $currentIncludeTargets.id) } + if ($null -ne $currentincludeTargets.targetType) { $myincludeTargets.Add('TargetType', $currentincludeTargets.targetType.toString()) } + if ($myincludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexincludeTargets += $myincludeTargets @@ -155,7 +189,7 @@ function Get-TargetResource } $complexOpenIdConnectSetting = @{ - clientId = $getValue.OpenIdConnectSetting.ClientId + clientId = $getValue.OpenIdConnectSetting.ClientId discoveryUrl = $getValue.OpenIdConnectSetting.DiscoveryUrl } @@ -300,8 +334,8 @@ function Set-TargetResource { Write-Verbose -Message "Updating the Azure AD Authentication Method Policy External with name {$($currentInstance.displayName)}" - $response = Invoke-MgGraphRequest -Method Get -Uri ($Global:MSCloudLoginConnectionProfile.MicrosoftGraph.ResourceUrl + "beta/policies/authenticationMethodsPolicy/") - $getValue = $response.authenticationMethodConfigurations | Where-Object -FilterScript {$_.displayName -eq $currentInstance.displayName} + $response = Invoke-MgGraphRequest -Method Get -Uri ($Global:MSCloudLoginConnectionProfile.MicrosoftGraph.ResourceUrl + 'beta/policies/authenticationMethodsPolicy/') + $getValue = $response.authenticationMethodConfigurations | Where-Object -FilterScript { $_.displayName -eq $currentInstance.displayName } $params.Remove('displayName') | Out-Null @@ -313,8 +347,8 @@ function Set-TargetResource { Write-Verbose -Message "Removing the Azure AD Authentication Method Policy External with Id {$($currentInstance.displayName)}" - $response = Invoke-MgGraphRequest -Method Get -Uri ($Global:MSCloudLoginConnectionProfile.MicrosoftGraph.ResourceUrl + "beta/policies/authenticationMethodsPolicy/") - $getValue = $response.authenticationMethodConfigurations | Where-Object -FilterScript {$_.displayName -eq $currentInstance.displayName} + $response = Invoke-MgGraphRequest -Method Get -Uri ($Global:MSCloudLoginConnectionProfile.MicrosoftGraph.ResourceUrl + 'beta/policies/authenticationMethodsPolicy/') + $getValue = $response.authenticationMethodConfigurations | Where-Object -FilterScript { $_.displayName -eq $currentInstance.displayName } Remove-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration -AuthenticationMethodConfigurationId $getValue.Id } @@ -504,9 +538,9 @@ function Export-TargetResource try { #region resource generator code - $desiredType = "#microsoft.graph.externalAuthenticationMethodConfiguration" - $getPolicy = Invoke-MgGraphRequest -Method Get -Uri ($Global:MSCloudLoginConnectionProfile.MicrosoftGraph.ResourceUrl + "beta/policies/authenticationMethodsPolicy/") - $getValue = $getPolicy.AuthenticationMethodConfigurations | Where-Object -FilterScript {$_.'@odata.type' -eq $desiredType} + $desiredType = '#microsoft.graph.externalAuthenticationMethodConfiguration' + $getPolicy = Invoke-MgGraphRequest -Method Get -Uri ($Global:MSCloudLoginConnectionProfile.MicrosoftGraph.ResourceUrl + 'beta/policies/authenticationMethodsPolicy/') + $getValue = $getPolicy.AuthenticationMethodConfigurations | Where-Object -FilterScript { $_.'@odata.type' -eq $desiredType } #endregion $i = 1 @@ -649,11 +683,12 @@ function Get-UpdatedTargetProperty if ($key -eq 'IncludeTargets') { $i = 0 - foreach ($entry in $params.$key){ + foreach ($entry in $params.$key) + { if ($entry.id -notmatch '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$|all_users') { $Filter = "Displayname eq '$($entry.id)'" | Out-String - $params.$key[$i].foreach('id',(Get-MgGroup -Filter $Filter).id.ToString()) + $params.$key[$i].foreach('id', (Get-MgGroup -Filter $Filter).id.ToString()) } $i++ } @@ -661,11 +696,12 @@ function Get-UpdatedTargetProperty if ($key -eq 'ExcludeTargets') { $i = 0 - foreach ($entry in $params.$key){ + foreach ($entry in $params.$key) + { if ($entry.id -notmatch '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$|all_users') { $Filter = "Displayname eq '$($entry.id)'" | Out-String - $params.$key[$i].foreach('id',(Get-MgGroup -Filter $Filter).id.ToString()) + $params.$key[$i].foreach('id', (Get-MgGroup -Filter $Filter).id.ToString()) } $i++ } diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyFido2/MSFT_AADAuthenticationMethodPolicyFido2.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyFido2/MSFT_AADAuthenticationMethodPolicyFido2.psm1 index a5d2268cb8..66066badf9 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyFido2/MSFT_AADAuthenticationMethodPolicyFido2.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyFido2/MSFT_AADAuthenticationMethodPolicyFido2.psm1 @@ -5,6 +5,10 @@ function Get-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [System.Boolean] $IsAttestationEnforced, @@ -29,11 +33,6 @@ function Get-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion [Parameter()] @@ -70,6 +69,8 @@ function Get-TargetResource $AccessTokens ) + Write-Verbose -Message "Getting the Azure AD Authentication Method Policy Fido2 with Id {$Id}" + try { $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` @@ -104,6 +105,7 @@ function Get-TargetResource Write-Verbose -Message "An Azure AD Authentication Method Policy Fido2 with Id {$Id} was found." #region resource generator code + Write-Verbose "Processing KeyRestrictions" $complexKeyRestrictions = @{} $complexKeyRestrictions.Add('AaGuids', $getValue.AdditionalProperties.keyRestrictions.aaGuids) if ($null -ne $getValue.AdditionalProperties.keyRestrictions.enforcementType) @@ -116,21 +118,39 @@ function Get-TargetResource $complexKeyRestrictions = $null } + Write-Verbose "Processing ExcludeTargets" $complexExcludeTargets = @() foreach ($currentExcludeTargets in $getValue.excludeTargets) { $myExcludeTargets = @{} - if ($currentExcludeTargets.id -ne 'all_users'){ - $myExcludeTargetsDisplayName = get-MgGroup -GroupId $currentExcludeTargets.id - $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + if ($currentExcludeTargets.id -ne 'all_users') + { + try + { + $myExcludeTargetsDisplayName = Get-MgGroup -GroupId $currentExcludeTargets.id -ErrorAction Stop + $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($currentExcludeTargets.id) specified in ExcludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myExcludeTargets.Add('Id', $currentExcludeTargets.id) } + if ($null -ne $currentExcludeTargets.targetType) { $myExcludeTargets.Add('TargetType', $currentExcludeTargets.targetType.toString()) } + if ($myExcludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexExcludeTargets += $myExcludeTargets @@ -138,24 +158,42 @@ function Get-TargetResource } #endregion - $CoomplexIncludeTargets = @() + Write-Verbose "Processing IncludeTargets" + $complexIncludeTargets = @() foreach ($currentIncludeTargets in $getValue.AdditionalProperties.includeTargets) { $myIncludeTargets = @{} - if ($currentIncludeTargets.id -ne 'all_users'){ - $myIncludeTargetsDisplayName = get-MgGroup -GroupId $currentIncludeTargets.id - $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + if ($currentIncludeTargets.id -ne 'all_users') + { + try + { + $myIncludeTargetsDisplayName = Get-MgGroup -GroupId $currentIncludeTargets.id -ErrorAction Stop + $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($currentIncludeTargets.id) specified in IncludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myIncludeTargets.Add('Id', $currentIncludeTargets.id) } + if ($null -ne $currentIncludeTargets.targetType) { $myIncludeTargets.Add('TargetType', $currentIncludeTargets.targetType.toString()) } + if ($myIncludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { - $CoomplexIncludeTargets += $myIncludeTargets + $complexIncludeTargets += $myIncludeTargets } } @@ -173,7 +211,7 @@ function Get-TargetResource IsSelfServiceRegistrationAllowed = $getValue.AdditionalProperties.isSelfServiceRegistrationAllowed KeyRestrictions = $complexKeyRestrictions ExcludeTargets = $complexExcludeTargets - IncludeTargets = $CoomplexIncludeTargets + IncludeTargets = $complexIncludeTargets State = $enumState Id = $getValue.Id Ensure = 'Present' @@ -207,6 +245,10 @@ function Set-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [System.Boolean] $IsAttestationEnforced, @@ -231,12 +273,8 @@ function Set-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion + [Parameter()] [System.String] [ValidateSet('Absent', 'Present')] @@ -271,6 +309,8 @@ function Set-TargetResource $AccessTokens ) + Write-Verbose -Message "Setting the Azure AD Authentication Method Policy Fido2 with Id {$Id}" + #Ensure the proper dependencies are installed in the current environment. Confirm-M365DSCDependencies @@ -306,11 +346,12 @@ function Set-TargetResource if ($key -eq 'IncludeTargets') { $i = 0 - foreach ($entry in $UpdateParameters.$key){ + foreach ($entry in $UpdateParameters.$key) + { if ($entry.id -notmatch '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$|all_users') { $Filter = "Displayname eq '$($entry.id)'" | Out-String - $UpdateParameters.$key[$i].foreach('id',(Get-MgGroup -Filter $Filter).id.ToString()) + $UpdateParameters.$key[$i].foreach('id', (Get-MgGroup -Filter $Filter).id.ToString()) } $i++ } @@ -318,11 +359,12 @@ function Set-TargetResource if ($key -eq 'ExcludeTargets') { $i = 0 - foreach ($entry in $UpdateParameters.$key){ + foreach ($entry in $UpdateParameters.$key) + { if ($entry.id -notmatch '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$|all_users') { $Filter = "Displayname eq '$($entry.id)'" | Out-String - $UpdateParameters.$key[$i].foreach('id',(Get-MgGroup -Filter $Filter).id.ToString()) + $UpdateParameters.$key[$i].foreach('id', (Get-MgGroup -Filter $Filter).id.ToString()) } $i++ } @@ -351,6 +393,10 @@ function Test-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [System.Boolean] $IsAttestationEnforced, @@ -375,11 +421,6 @@ function Test-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion [Parameter()] @@ -536,7 +577,7 @@ function Export-TargetResource #region resource generator code [array]$getValue = Get-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration ` -AuthenticationMethodConfigurationId Fido2 ` - -ErrorAction Stop | Where-Object -FilterScript {$null -ne $_.Id} + -ErrorAction Stop | Where-Object -FilterScript { $null -ne $_.Id } #endregion $i = 1 diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyHardware/MSFT_AADAuthenticationMethodPolicyHardware.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyHardware/MSFT_AADAuthenticationMethodPolicyHardware.psm1 index 30be7f9089..d49a0965bc 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyHardware/MSFT_AADAuthenticationMethodPolicyHardware.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyHardware/MSFT_AADAuthenticationMethodPolicyHardware.psm1 @@ -96,17 +96,34 @@ function Get-TargetResource foreach ($currentExcludeTargets in $getValue.excludeTargets) { $myExcludeTargets = @{} - if ($currentExcludeTargets.id -ne 'all_users'){ - $myExcludeTargetsDisplayName = get-MgGroup -GroupId $currentExcludeTargets.id - $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + if ($currentExcludeTargets.id -ne 'all_users') + { + try + { + $myExcludeTargetsDisplayName = Get-MgGroup -GroupId $currentExcludeTargets.id -ErrorAction Stop + $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($currentExcludeTargets.id) specified in ExcludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myExcludeTargets.Add('Id', $currentExcludeTargets.id) } + if ($null -ne $currentExcludeTargets.targetType) { $myExcludeTargets.Add('TargetType', $currentExcludeTargets.targetType.toString()) } + if ($myExcludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexExcludeTargets += $myExcludeTargets @@ -118,17 +135,35 @@ function Get-TargetResource foreach ($currentincludeTargets in $getValue.AdditionalProperties.includeTargets) { $myincludeTargets = @{} - if ($currentIncludeTargets.id -ne 'all_users'){ - $myIncludeTargetsDisplayName = get-MgGroup -GroupId $currentIncludeTargets.id - $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + if ($currentIncludeTargets.id -ne 'all_users') + { + try + { + $myIncludeTargetsDisplayName = Get-MgGroup -GroupId $currentIncludeTargets.id -ErrorAction Stop + $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + + } + catch + { + $message = "Could not find a group with id $($currentIncludeTargets.id) specified in IncludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myIncludeTargets.Add('Id', $currentIncludeTargets.id) } + if ($null -ne $currentincludeTargets.targetType) { $myincludeTargets.Add('TargetType', $currentincludeTargets.targetType.toString()) } + if ($myincludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexincludeTargets += $myincludeTargets @@ -266,11 +301,12 @@ function Set-TargetResource if ($key -eq 'IncludeTargets') { $i = 0 - foreach ($entry in $UpdateParameters.$key){ + foreach ($entry in $UpdateParameters.$key) + { if ($entry.id -notmatch '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$|all_users') { $Filter = "Displayname eq '$($entry.id)'" | Out-String - $UpdateParameters.$key[$i].foreach('id',(Get-MgGroup -Filter $Filter).id.ToString()) + $UpdateParameters.$key[$i].foreach('id', (Get-MgGroup -Filter $Filter).id.ToString()) } $i++ } @@ -278,11 +314,12 @@ function Set-TargetResource if ($key -eq 'ExcludeTargets') { $i = 0 - foreach ($entry in $UpdateParameters.$key){ + foreach ($entry in $UpdateParameters.$key) + { if ($entry.id -notmatch '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$|all_users') { $Filter = "Displayname eq '$($entry.id)'" | Out-String - $UpdateParameters.$key[$i].foreach('id',(Get-MgGroup -Filter $Filter).id.ToString()) + $UpdateParameters.$key[$i].foreach('id', (Get-MgGroup -Filter $Filter).id.ToString()) } $i++ } @@ -484,7 +521,7 @@ function Export-TargetResource #region resource generator code [array]$getValue = Get-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration ` -AuthenticationMethodConfigurationId HardwareOath ` - -ErrorAction Stop | Where-Object -FilterScript {$null -ne $_.Id} + -ErrorAction Stop | Where-Object -FilterScript { $null -ne $_.Id } #endregion $i = 1 diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicySms/MSFT_AADAuthenticationMethodPolicySms.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicySms/MSFT_AADAuthenticationMethodPolicySms.psm1 index c04894b025..f0cc33f024 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicySms/MSFT_AADAuthenticationMethodPolicySms.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicySms/MSFT_AADAuthenticationMethodPolicySms.psm1 @@ -5,6 +5,10 @@ function Get-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [Microsoft.Management.Infrastructure.CimInstance[]] $ExcludeTargets, @@ -17,11 +21,6 @@ function Get-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion [Parameter()] @@ -58,6 +57,8 @@ function Get-TargetResource $AccessTokens ) + Write-Verbose -Message "Getting the Azure AD Authentication Method Policy Sms with Id {$Id}" + try { $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` @@ -92,21 +93,39 @@ function Get-TargetResource Write-Verbose -Message "An Azure AD Authentication Method Policy Sms with Id {$Id} was found." #region resource generator code + Write-Verbose -Message "Processing ExcludeTargets" $complexExcludeTargets = @() foreach ($currentExcludeTargets in $getValue.excludeTargets) { $myExcludeTargets = @{} - if ($currentExcludeTargets.id -ne 'all_users'){ - $myExcludeTargetsDisplayName = get-MgGroup -GroupId $currentExcludeTargets.id - $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + if ($currentExcludeTargets.id -ne 'all_users') + { + try + { + $myExcludeTargetsDisplayName = Get-MgGroup -GroupId $currentExcludeTargets.id -ErrorAction Stop + $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($currentExcludeTargets.id) specified in ExcludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myExcludeTargets.Add('Id', $currentExcludeTargets.id) } + if ($null -ne $currentExcludeTargets.targetType) { $myExcludeTargets.Add('TargetType', $currentExcludeTargets.targetType.toString()) } + if ($myExcludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexExcludeTargets += $myExcludeTargets @@ -114,21 +133,40 @@ function Get-TargetResource } #endregion + Write-Verbose -Message "Processing IncludeTargets" $complexincludeTargets = @() foreach ($currentincludeTargets in $getValue.AdditionalProperties.includeTargets) { $myincludeTargets = @{} - if ($currentIncludeTargets.id -ne 'all_users'){ - $myIncludeTargetsDisplayName = get-MgGroup -GroupId $currentIncludeTargets.id - $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + if ($currentIncludeTargets.id -ne 'all_users') + { + try + { + $myIncludeTargetsDisplayName = Get-MgGroup -GroupId $currentIncludeTargets.id -ErrorAction Stop + $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + + } + catch + { + $message = "Could not find a group with id $($currentIncludeTargets.id) specified in IncludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myIncludeTargets.Add('Id', $currentIncludeTargets.id) } + if ($null -ne $currentincludeTargets.targetType) { $myincludeTargets.Add('TargetType', $currentincludeTargets.targetType.toString()) } + if ($myincludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexincludeTargets += $myincludeTargets @@ -179,6 +217,10 @@ function Set-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [Microsoft.Management.Infrastructure.CimInstance[]] $ExcludeTargets, @@ -191,12 +233,8 @@ function Set-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion + [Parameter()] [System.String] [ValidateSet('Absent', 'Present')] @@ -231,6 +269,8 @@ function Set-TargetResource $AccessTokens ) + Write-Verbose -Message "Setting the Azure AD Authentication Method Policy Fido2 with Id {$Id}" + #Ensure the proper dependencies are installed in the current environment. Confirm-M365DSCDependencies @@ -266,11 +306,12 @@ function Set-TargetResource if ($key -eq 'IncludeTargets') { $i = 0 - foreach ($entry in $UpdateParameters.$key){ + foreach ($entry in $UpdateParameters.$key) + { if ($entry.id -notmatch '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$|all_users') { $Filter = "Displayname eq '$($entry.id)'" | Out-String - $UpdateParameters.$key[$i].foreach('id',(Get-MgGroup -Filter $Filter).id.ToString()) + $UpdateParameters.$key[$i].foreach('id', (Get-MgGroup -Filter $Filter).id.ToString()) } $i++ } @@ -278,11 +319,12 @@ function Set-TargetResource if ($key -eq 'ExcludeTargets') { $i = 0 - foreach ($entry in $UpdateParameters.$key){ + foreach ($entry in $UpdateParameters.$key) + { if ($entry.id -notmatch '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$|all_users') { $Filter = "Displayname eq '$($entry.id)'" | Out-String - $UpdateParameters.$key[$i].foreach('id',(Get-MgGroup -Filter $Filter).id.ToString()) + $UpdateParameters.$key[$i].foreach('id', (Get-MgGroup -Filter $Filter).id.ToString()) } $i++ } @@ -311,6 +353,10 @@ function Test-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [Microsoft.Management.Infrastructure.CimInstance[]] $ExcludeTargets, @@ -323,11 +369,6 @@ function Test-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion [Parameter()] @@ -484,7 +525,7 @@ function Export-TargetResource #region resource generator code [array]$getValue = Get-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration ` -AuthenticationMethodConfigurationId sms ` - -ErrorAction Stop | Where-Object -FilterScript {$null -ne $_.Id} + -ErrorAction Stop | Where-Object -FilterScript { $null -ne $_.Id } #endregion $i = 1 @@ -536,7 +577,7 @@ function Export-TargetResource } } - if($null -ne $Results.IncludeTargets) + if ($null -ne $Results.IncludeTargets) { $complexTypeStringResult = Get-M365DSCDRGComplexTypeToString ` -ComplexObject $Results.IncludeTargets ` diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicySoftware/MSFT_AADAuthenticationMethodPolicySoftware.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicySoftware/MSFT_AADAuthenticationMethodPolicySoftware.psm1 index a169bdd262..5d5ab861f5 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicySoftware/MSFT_AADAuthenticationMethodPolicySoftware.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicySoftware/MSFT_AADAuthenticationMethodPolicySoftware.psm1 @@ -5,6 +5,10 @@ function Get-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [Microsoft.Management.Infrastructure.CimInstance[]] $ExcludeTargets, @@ -17,11 +21,6 @@ function Get-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion [Parameter()] @@ -58,6 +57,8 @@ function Get-TargetResource $AccessTokens ) + Write-Verbose -Message "Getting the Azure AD Authentication Method Policy Software with Id {$Id}" + try { $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` @@ -92,21 +93,39 @@ function Get-TargetResource Write-Verbose -Message "An Azure AD Authentication Method Policy Software with Id {$Id} was found." #region resource generator code + Write-Verbose -Message "Processing ExcludeTargets" $complexExcludeTargets = @() foreach ($currentExcludeTargets in $getValue.excludeTargets) { $myExcludeTargets = @{} - if ($currentExcludeTargets.id -ne 'all_users'){ - $myExcludeTargetsDisplayName = get-MgGroup -GroupId $currentExcludeTargets.id - $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + if ($currentExcludeTargets.id -ne 'all_users') + { + try + { + $myExcludeTargetsDisplayName = Get-MgGroup -GroupId $currentExcludeTargets.id -ErrorAction Stop + $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($currentExcludeTargets.id) specified in ExcludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myExcludeTargets.Add('Id', $currentExcludeTargets.id) } + if ($null -ne $currentExcludeTargets.targetType) { $myExcludeTargets.Add('TargetType', $currentExcludeTargets.targetType.toString()) } + if ($myExcludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexExcludeTargets += $myExcludeTargets @@ -114,21 +133,39 @@ function Get-TargetResource } #endregion + Write-Verbose -Message "Processing IncludeTargets" $complexincludeTargets = @() foreach ($currentincludeTargets in $getValue.AdditionalProperties.includeTargets) { $myincludeTargets = @{} - if ($currentIncludeTargets.id -ne 'all_users'){ - $myIncludeTargetsDisplayName = get-MgGroup -GroupId $currentIncludeTargets.id - $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + if ($currentIncludeTargets.id -ne 'all_users') + { + try + { + $myIncludeTargetsDisplayName = Get-MgGroup -GroupId $currentIncludeTargets.id -ErrorAction Stop + $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($currentIncludeTargets.id) specified in IncludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myIncludeTargets.Add('Id', $currentIncludeTargets.id) } + if ($null -ne $currentincludeTargets.targetType) { $myincludeTargets.Add('TargetType', $currentincludeTargets.targetType.toString()) } + if ($myincludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexincludeTargets += $myincludeTargets @@ -179,6 +216,10 @@ function Set-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [Microsoft.Management.Infrastructure.CimInstance[]] $ExcludeTargets, @@ -191,12 +232,8 @@ function Set-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion + [Parameter()] [System.String] [ValidateSet('Absent', 'Present')] @@ -231,6 +268,8 @@ function Set-TargetResource $AccessTokens ) + Write-Verbose -Message "Setting the Azure AD Authentication Method Policy Software with Id {$Id}" + #Ensure the proper dependencies are installed in the current environment. Confirm-M365DSCDependencies @@ -266,11 +305,12 @@ function Set-TargetResource if ($key -eq 'IncludeTargets') { $i = 0 - foreach ($entry in $UpdateParameters.$key){ + foreach ($entry in $UpdateParameters.$key) + { if ($entry.id -notmatch '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$|all_users') { $Filter = "Displayname eq '$($entry.id)'" | Out-String - $UpdateParameters.$key[$i].foreach('id',(Get-MgGroup -Filter $Filter).id.ToString()) + $UpdateParameters.$key[$i].foreach('id', (Get-MgGroup -Filter $Filter).id.ToString()) } $i++ } @@ -278,11 +318,12 @@ function Set-TargetResource if ($key -eq 'ExcludeTargets') { $i = 0 - foreach ($entry in $UpdateParameters.$key){ + foreach ($entry in $UpdateParameters.$key) + { if ($entry.id -notmatch '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$|all_users') { $Filter = "Displayname eq '$($entry.id)'" | Out-String - $UpdateParameters.$key[$i].foreach('id',(Get-MgGroup -Filter $Filter).id.ToString()) + $UpdateParameters.$key[$i].foreach('id', (Get-MgGroup -Filter $Filter).id.ToString()) } $i++ } @@ -311,6 +352,10 @@ function Test-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [Microsoft.Management.Infrastructure.CimInstance[]] $ExcludeTargets, @@ -323,11 +368,6 @@ function Test-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion [Parameter()] @@ -484,7 +524,7 @@ function Export-TargetResource #region resource generator code [array]$getValue = Get-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration ` -AuthenticationMethodConfigurationId SoftwareOath ` - -ErrorAction Stop | Where-Object -FilterScript {$null -ne $_.Id} + -ErrorAction Stop | Where-Object -FilterScript { $null -ne $_.Id } #endregion $i = 1 diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyTemporary/MSFT_AADAuthenticationMethodPolicyTemporary.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyTemporary/MSFT_AADAuthenticationMethodPolicyTemporary.psm1 index 1a70718259..afbb27114f 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyTemporary/MSFT_AADAuthenticationMethodPolicyTemporary.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyTemporary/MSFT_AADAuthenticationMethodPolicyTemporary.psm1 @@ -5,6 +5,10 @@ function Get-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [System.Int32] $DefaultLength, @@ -37,11 +41,6 @@ function Get-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion [Parameter()] @@ -78,6 +77,8 @@ function Get-TargetResource $AccessTokens ) + Write-Verbose -Message "Getting the Azure AD Authentication Method Policy Temporary with Id {$Id}" + try { $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` @@ -105,29 +106,47 @@ function Get-TargetResource #endregion if ($null -eq $getValue) { - Write-Verbose -Message "Could not find an Azure AD Authentication Method Policy Temporary" + Write-Verbose -Message 'Could not find an Azure AD Authentication Method Policy Temporary' return $nullResult } $Id = $getValue.Id Write-Verbose -Message "An Azure AD Authentication Method Policy Temporary with Id {$($currentExcludeTargets.id))} was found." #region resource generator code + Write-Verbose -Message "Processing ExcludeTargets" $complexExcludeTargets = @() foreach ($currentExcludeTargets in $getValue.excludeTargets) { Write-Verbose -Message "Retrieving ExcludeTarget {$currentExcludeTargets}" $myExcludeTargets = @{} - if ($currentExcludeTargets.id -ne 'all_users'){ - $myExcludeTargetsDisplayName = get-MgGroup -GroupId $currentExcludeTargets.id - $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + if ($currentExcludeTargets.id -ne 'all_users') + { + try + { + $myExcludeTargetsDisplayName = Get-MgGroup -GroupId $currentExcludeTargets.id -ErrorAction Stop + $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($currentExcludeTargets.id) specified in ExcludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myExcludeTargets.Add('Id', $currentExcludeTargets.id) } + if ($null -ne $currentExcludeTargets.targetType) { $myExcludeTargets.Add('TargetType', $currentExcludeTargets.targetType.toString()) } + if ($myExcludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexExcludeTargets += $myExcludeTargets @@ -135,27 +154,46 @@ function Get-TargetResource } #endregion + Write-Verbose -Message "Processing IncludeTargets" $complexincludeTargets = @() foreach ($currentincludeTargets in $getValue.AdditionalProperties.includeTargets) { Write-Verbose -Message "Retrieving IncludeTarget {$($currentincludeTargets.id)}" $myincludeTargets = @{} - if ($currentIncludeTargets.id -ne 'all_users'){ - $myIncludeTargetsDisplayName = get-MgGroup -GroupId $currentIncludeTargets.id - $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + if ($currentIncludeTargets.id -ne 'all_users') + { + try + { + $myIncludeTargetsDisplayName = Get-MgGroup -GroupId $currentIncludeTargets.id -ErrorAction Stop + $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($currentIncludeTargets.id) specified in IncludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myIncludeTargets.Add('Id', $currentIncludeTargets.id) } + if ($null -ne $currentincludeTargets.targetType) { $myincludeTargets.Add('TargetType', $currentincludeTargets.targetType.toString()) } + if ($myincludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexincludeTargets += $myincludeTargets } } + #region resource generator code $enumState = $null if ($null -ne $getValue.State) @@ -164,7 +202,7 @@ function Get-TargetResource } #endregion - Write-Verbose -Message "Get-TargetResource returned values" + Write-Verbose -Message 'Get-TargetResource returned values' $results = @{ #region resource generator code DefaultLength = $getValue.AdditionalProperties.defaultLength @@ -207,6 +245,10 @@ function Set-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [System.Int32] $DefaultLength, @@ -239,12 +281,8 @@ function Set-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion + [Parameter()] [System.String] [ValidateSet('Absent', 'Present')] @@ -279,6 +317,8 @@ function Set-TargetResource $AccessTokens ) + Write-Verbose -Message "Setting the Azure AD Authentication Method Policy Temporary with Id {$Id}" + #Ensure the proper dependencies are installed in the current environment. Confirm-M365DSCDependencies @@ -314,11 +354,12 @@ function Set-TargetResource if ($key -eq 'IncludeTargets') { $i = 0 - foreach ($entry in $UpdateParameters.$key){ + foreach ($entry in $UpdateParameters.$key) + { if ($entry.id -notmatch '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$|all_users') { $Filter = "Displayname eq '$($entry.id)'" | Out-String - $UpdateParameters.$key[$i].foreach('id',(Get-MgGroup -Filter $Filter).id.ToString()) + $UpdateParameters.$key[$i].foreach('id', (Get-MgGroup -Filter $Filter).id.ToString()) } $i++ } @@ -326,11 +367,12 @@ function Set-TargetResource if ($key -eq 'ExcludeTargets') { $i = 0 - foreach ($entry in $UpdateParameters.$key){ + foreach ($entry in $UpdateParameters.$key) + { if ($entry.id -notmatch '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$|all_users') { $Filter = "Displayname eq '$($entry.id)'" | Out-String - $UpdateParameters.$key[$i].foreach('id',(Get-MgGroup -Filter $Filter).id.ToString()) + $UpdateParameters.$key[$i].foreach('id', (Get-MgGroup -Filter $Filter).id.ToString()) } $i++ } @@ -359,6 +401,10 @@ function Test-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [System.Int32] $DefaultLength, @@ -391,11 +437,6 @@ function Test-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion [Parameter()] @@ -457,7 +498,7 @@ function Test-TargetResource $testResult = $true #Compare Cim instances - Write-Verbose -Message "Evaluating keys" + Write-Verbose -Message 'Evaluating keys' foreach ($key in $PSBoundParameters.Keys) { $source = $PSBoundParameters.$key @@ -553,7 +594,7 @@ function Export-TargetResource #region resource generator code [array]$getValue = Get-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration ` -AuthenticationMethodConfigurationId TemporaryAccessPass ` - -ErrorAction Stop | Where-Object -FilterScript {$null -ne $_.Id} + -ErrorAction Stop | Where-Object -FilterScript { $null -ne $_.Id } #endregion $i = 1 diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyVoice/MSFT_AADAuthenticationMethodPolicyVoice.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyVoice/MSFT_AADAuthenticationMethodPolicyVoice.psm1 index de6206c2d9..c74b6b96e1 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyVoice/MSFT_AADAuthenticationMethodPolicyVoice.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyVoice/MSFT_AADAuthenticationMethodPolicyVoice.psm1 @@ -5,6 +5,10 @@ function Get-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [System.Boolean] $IsOfficePhoneAllowed, @@ -21,11 +25,6 @@ function Get-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion [Parameter()] @@ -62,6 +61,8 @@ function Get-TargetResource $AccessTokens ) + Write-Verbose -Message "Getting the Azure AD Authentication Method Policy Voice with Id {$Id}" + try { $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` @@ -96,21 +97,39 @@ function Get-TargetResource Write-Verbose -Message "An Azure AD Authentication Method Policy Voice with Id {$Id} was found." #region resource generator code + Write-Verbose -Message "Processing ExcludeTargets" $complexExcludeTargets = @() foreach ($currentExcludeTargets in $getValue.excludeTargets) { $myExcludeTargets = @{} - if ($currentExcludeTargets.id -ne 'all_users'){ - $myExcludeTargetsDisplayName = get-MgGroup -GroupId $currentExcludeTargets.id - $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + if ($currentExcludeTargets.id -ne 'all_users') + { + try + { + $myExcludeTargetsDisplayName = Get-MgGroup -GroupId $currentExcludeTargets.id -ErrorAction Stop + $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($currentExcludeTargets.id) specified in ExcludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myExcludeTargets.Add('Id', $currentExcludeTargets.id) } + if ($null -ne $currentExcludeTargets.targetType) { $myExcludeTargets.Add('TargetType', $currentExcludeTargets.targetType.toString()) } + if ($myExcludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexExcludeTargets += $myExcludeTargets @@ -118,21 +137,39 @@ function Get-TargetResource } #endregion + Write-Verbose -Message "Processing IncludeTargets" $complexincludeTargets = @() foreach ($currentincludeTargets in $getValue.AdditionalProperties.includeTargets) { $myincludeTargets = @{} - if ($currentIncludeTargets.id -ne 'all_users'){ - $myIncludeTargetsDisplayName = get-MgGroup -GroupId $currentIncludeTargets.id - $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + if ($currentIncludeTargets.id -ne 'all_users') + { + try + { + $myIncludeTargetsDisplayName = Get-MgGroup -GroupId $currentIncludeTargets.id -ErrorAction Stop + $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($currentIncludeTargets.id) specified in IncludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myIncludeTargets.Add('Id', $currentIncludeTargets.id) } + if ($null -ne $currentincludeTargets.targetType) { $myincludeTargets.Add('TargetType', $currentincludeTargets.targetType.toString()) } + if ($myincludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexincludeTargets += $myincludeTargets @@ -184,6 +221,10 @@ function Set-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [System.Boolean] $IsOfficePhoneAllowed, @@ -200,12 +241,8 @@ function Set-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion + [Parameter()] [System.String] [ValidateSet('Absent', 'Present')] @@ -240,6 +277,8 @@ function Set-TargetResource $AccessTokens ) + Write-Verbose -Message "Setting the Azure AD Authentication Method Policy Voice with Id {$Id}" + #Ensure the proper dependencies are installed in the current environment. Confirm-M365DSCDependencies @@ -275,11 +314,12 @@ function Set-TargetResource if ($key -eq 'IncludeTargets') { $i = 0 - foreach ($entry in $UpdateParameters.$key){ + foreach ($entry in $UpdateParameters.$key) + { if ($entry.id -notmatch '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$|all_users') { $Filter = "Displayname eq '$($entry.id)'" | Out-String - $UpdateParameters.$key[$i].foreach('id',(Get-MgGroup -Filter $Filter).id.ToString()) + $UpdateParameters.$key[$i].foreach('id', (Get-MgGroup -Filter $Filter).id.ToString()) } $i++ } @@ -287,11 +327,12 @@ function Set-TargetResource if ($key -eq 'ExcludeTargets') { $i = 0 - foreach ($entry in $UpdateParameters.$key){ + foreach ($entry in $UpdateParameters.$key) + { if ($entry.id -notmatch '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$|all_users') { $Filter = "Displayname eq '$($entry.id)'" | Out-String - $UpdateParameters.$key[$i].foreach('id',(Get-MgGroup -Filter $Filter).id.ToString()) + $UpdateParameters.$key[$i].foreach('id', (Get-MgGroup -Filter $Filter).id.ToString()) } $i++ } @@ -320,6 +361,10 @@ function Test-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [System.Boolean] $IsOfficePhoneAllowed, @@ -336,11 +381,6 @@ function Test-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion [Parameter()] @@ -497,7 +537,7 @@ function Export-TargetResource #region resource generator code [array]$getValue = Get-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration ` -AuthenticationMethodConfigurationId Voice ` - -ErrorAction Stop | Where-Object -FilterScript {$null -ne $_.Id} + -ErrorAction Stop | Where-Object -FilterScript { $null -ne $_.Id } #endregion $i = 1 diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyX509/MSFT_AADAuthenticationMethodPolicyX509.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyX509/MSFT_AADAuthenticationMethodPolicyX509.psm1 index 865bb4f957..d6f581c647 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyX509/MSFT_AADAuthenticationMethodPolicyX509.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyX509/MSFT_AADAuthenticationMethodPolicyX509.psm1 @@ -4,6 +4,10 @@ function Get-TargetResource [OutputType([System.Collections.Hashtable])] param ( + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [Microsoft.Management.Infrastructure.CimInstance] $AuthenticationModeConfiguration, @@ -25,10 +29,6 @@ function Get-TargetResource [System.String] $State, - [Parameter(Mandatory = $true)] - [System.String] - $Id, - [Parameter()] [System.String] [ValidateSet('Absent', 'Present')] @@ -63,6 +63,8 @@ function Get-TargetResource $AccessTokens ) + Write-Verbose -Message "Getting the Azure AD Authentication Method Policy X509 with Id {$Id}" + try { $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` @@ -99,7 +101,8 @@ function Get-TargetResource #region resource generator code $complexAuthenticationModeConfiguration = @{} $complexRules = @() - if ($getValue.AdditionalProperties.authenticationModeConfiguration.rules.length -ne 0){ + if ($getValue.AdditionalProperties.authenticationModeConfiguration.rules.length -ne 0) + { foreach ($currentRules in $getValue.AdditionalProperties.authenticationModeConfiguration.rules) { $myRules = @{} @@ -150,21 +153,39 @@ function Get-TargetResource } } + Write-Verbose 'Processing ExcludeTargets' $complexExcludeTargets = @() foreach ($currentExcludeTargets in $getValue.excludeTargets) { $myExcludeTargets = @{} - if ($currentExcludeTargets.id -ne 'all_users'){ - $myExcludeTargetsDisplayName = get-MgGroup -GroupId $currentExcludeTargets.id - $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + if ($currentExcludeTargets.id -ne 'all_users') + { + try + { + $myExcludeTargetsDisplayName = Get-MgGroup -GroupId $currentExcludeTargets.id -ErrorAction Stop + $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($currentExcludeTargets.id) specified in ExcludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myExcludeTargets.Add('Id', $currentExcludeTargets.id) } + if ($null -ne $currentExcludeTargets.targetType) { $myExcludeTargets.Add('TargetType', $currentExcludeTargets.targetType.toString()) } + if ($myExcludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexExcludeTargets += $myExcludeTargets @@ -172,25 +193,44 @@ function Get-TargetResource } #endregion + Write-Verbose 'Processing IncludeTargets' $complexIncludeTargets = @() foreach ($currentIncludeTargets in $getValue.AdditionalProperties.includeTargets) { $myIncludeTargets = @{} - if ($currentIncludeTargets.id -ne 'all_users'){ - $myIncludeTargetsDisplayName = get-MgGroup -GroupId $currentIncludeTargets.id - $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + if ($currentIncludeTargets.id -ne 'all_users') + { + try + { + $myIncludeTargetsDisplayName = Get-MgGroup -GroupId $currentIncludeTargets.id -ErrorAction Stop + $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($currentIncludeTargets.id) specified in IncludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myIncludeTargets.Add('Id', $currentIncludeTargets.id) } + if ($null -ne $currentIncludeTargets.targetType) { $myIncludeTargets.Add('TargetType', $currentIncludeTargets.targetType.toString()) } + if ($null -ne $currentIncludeTargets.isRegistrationRequired) { $myIncludeTargets.Add('isRegistrationRequired', [Boolean]$currentIncludeTargets.isRegistrationRequired) } + if ($myIncludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexIncludeTargets += $myIncludeTargets @@ -243,6 +283,10 @@ function Set-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [Microsoft.Management.Infrastructure.CimInstance] $AuthenticationModeConfiguration, @@ -263,12 +307,8 @@ function Set-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion + [Parameter()] [System.String] [ValidateSet('Absent', 'Present')] @@ -303,6 +343,8 @@ function Set-TargetResource $AccessTokens ) + Write-Verbose -Message "Setting the Azure AD Authentication Method Policy X509 with Id {$Id}" + #Ensure the proper dependencies are installed in the current environment. Confirm-M365DSCDependencies @@ -379,6 +421,10 @@ function Test-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [Microsoft.Management.Infrastructure.CimInstance] $AuthenticationModeConfiguration, @@ -399,11 +445,6 @@ function Test-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion [Parameter()] @@ -560,7 +601,7 @@ function Export-TargetResource #region resource generator code [array]$getValue = Get-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration ` -AuthenticationMethodConfigurationId X509Certificate ` - -ErrorAction Stop | Where-Object -FilterScript {$null -ne $_.Id} + -ErrorAction Stop | Where-Object -FilterScript { $null -ne $_.Id } #endregion $i = 1 diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADDeviceRegistrationPolicy/MSFT_AADDeviceRegistrationPolicy.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADDeviceRegistrationPolicy/MSFT_AADDeviceRegistrationPolicy.psm1 index c6d32acefa..8fe76dc299 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADDeviceRegistrationPolicy/MSFT_AADDeviceRegistrationPolicy.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADDeviceRegistrationPolicy/MSFT_AADDeviceRegistrationPolicy.psm1 @@ -116,14 +116,40 @@ function Get-TargetResource foreach ($userId in $getValue.AzureAdJoin.AllowedToJoin.AdditionalProperties.users) { - $userInfo = Get-MgUser -UserId $userId - $AzureADAllowedToJoinUsers += $userInfo.UserPrincipalName + try + { + $userInfo = Get-MgUser -UserId $userId -ErrorAction Stop + $AzureADAllowedToJoinUsers += $userInfo.UserPrincipalName + } + catch + { + $message = "Could not find a user with id $($userId) specified in AllowedToJoin. Skipping user!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } foreach ($groupId in $getValue.AzureAdJoin.AllowedToJoin.AdditionalProperties.groups) { - $groupInfo = Get-MgGroup -GroupId $groupId - $AzureADAllowedToJoinGroups += $groupInfo.DisplayName + try + { + $groupInfo = Get-MgGroup -GroupId $groupId -ErrorAction Stop + $AzureADAllowedToJoinGroups += $groupInfo.DisplayName + } + catch + { + $message = "Could not find a group with id $($groupId) specified in AllowedToJoin. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } } @@ -140,14 +166,40 @@ function Get-TargetResource $AzureAdJoinLocalAdminsRegisteringMode = 'Selected' foreach ($userId in $getValue.AzureAdJoin.LocalAdmins.RegisteringUsers.AdditionalProperties.users) { - $userInfo = Get-MgUser -UserId $userId - $AzureAdJoinLocalAdminsRegisteringUsers += $userInfo.UserPrincipalName + try + { + $userInfo = Get-MgUser -UserId $userId -ErrorAction Stop + $AzureAdJoinLocalAdminsRegisteringUsers += $userInfo.UserPrincipalName + } + catch + { + $message = "Could not find a user with id $($userId) specified in AllowedToJoin. Skipping user!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } foreach ($groupId in $getValue.AzureAdJoin.LocalAdmins.RegisteringUsers.AdditionalProperties.groups) { - $groupInfo = Get-MgGroup -GroupId $groupId - $AzureAdJoinLocalAdminsRegisteringGroups += $groupInfo.DisplayName + try + { + $groupInfo = Get-MgGroup -GroupId $groupId -ErrorAction Stop + $AzureAdJoinLocalAdminsRegisteringGroups += $groupInfo.DisplayName + } + catch + { + $message = "Could not find a group with id $($groupId) specified in AllowedToJoin. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } } From 950aaac872059e927dfd0b3bb75a1d295847d616 Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Tue, 19 Nov 2024 13:02:15 +0100 Subject: [PATCH 26/65] Fixing #5420 --- CHANGELOG.md | 36 ++++ .../MSFT_AADAdminConsentRequestPolicy.psm1 | 20 ++- ...thenticationMethodPolicyAuthenticator.psm1 | 167 +++++++++++++++--- ...FT_AADAuthenticationMethodPolicyEmail.psm1 | 99 ++++++++--- ...AADAuthenticationMethodPolicyExternal.psm1 | 82 ++++++--- ...FT_AADAuthenticationMethodPolicyFido2.psm1 | 103 +++++++---- ...AADAuthenticationMethodPolicyHardware.psm1 | 63 +++++-- ...MSFT_AADAuthenticationMethodPolicySms.psm1 | 99 ++++++++--- ...AADAuthenticationMethodPolicySoftware.psm1 | 96 +++++++--- ...ADAuthenticationMethodPolicyTemporary.psm1 | 103 +++++++---- ...FT_AADAuthenticationMethodPolicyVoice.psm1 | 96 +++++++--- ...SFT_AADAuthenticationMethodPolicyX509.psm1 | 89 +++++++--- .../MSFT_AADDeviceRegistrationPolicy.psm1 | 68 ++++++- 13 files changed, 847 insertions(+), 274 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e15929948..1357bbd671 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,39 @@ # UNRELEASED +* AADAdminConsentRequestPolicy + * Added error handling to Group display name retrieval to prevent errors + when an assigned group no longer exists. +* AADAuthenticationMethodPolicyAuthenticator + * Added error handling to Group display name retrieval to prevent errors + when an assigned group no longer exists. +* AADAuthenticationMethodPolicyEmail + * Added error handling to Group display name retrieval to prevent errors + when an assigned group no longer exists. +* AADAuthenticationMethodPolicyExternal + * Added error handling to Group display name retrieval to prevent errors + when an assigned group no longer exists. +* AADAuthenticationMethodPolicyFido2 + * Added error handling to Group display name retrieval to prevent errors + when an assigned group no longer exists. +* AADAuthenticationMethodPolicyHardware + * Added error handling to Group display name retrieval to prevent errors + when an assigned group no longer exists. +* AADAuthenticationMethodPolicySms + * Added error handling to Group display name retrieval to prevent errors + when an assigned group no longer exists. +* AADAuthenticationMethodPolicySoftware + * Added error handling to Group display name retrieval to prevent errors + when an assigned group no longer exists. +* AADAuthenticationMethodPolicyTemporary + * Added error handling to Group display name retrieval to prevent errors + when an assigned group no longer exists. +* AADAuthenticationMethodPolicyVoice + * Added error handling to Group display name retrieval to prevent errors + when an assigned group no longer exists. +* AADAuthenticationMethodPolicyX509 + * Added error handling to Group display name retrieval to prevent errors + when an assigned group no longer exists. * AADConditionalAccessPolicy * Fixed bug where a null value was passed in the request for the excludePlatforms parameter when just values were assigned to includePlatforms, which throws an error. @@ -9,6 +42,9 @@ sessionControl parameter when there are no session controls, which throws an error. * Fixed bug where a null value was passed in the request for the applicationEnforcedRestrictions parameter when value was set to false, which throws an error. +* AADDeviceRegistrationPolicy + * Added error handling to Group display name retrieval to prevent errors + when an assigned group no longer exists. * AADRoleEligibilityScheduleRequest * Adds support for custom role assignments at app scope. * IntuneDeviceConfigurationPolicyAndroidDeviceOwner diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAdminConsentRequestPolicy/MSFT_AADAdminConsentRequestPolicy.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAdminConsentRequestPolicy/MSFT_AADAdminConsentRequestPolicy.psm1 index 682756ab41..88b9e6c5f6 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAdminConsentRequestPolicy/MSFT_AADAdminConsentRequestPolicy.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAdminConsentRequestPolicy/MSFT_AADAdminConsentRequestPolicy.psm1 @@ -97,10 +97,22 @@ function Get-TargetResource elseif ($reviewer.Query.Contains('/groups/')) { $groupId = $reviewer.Query.Split('/')[3] - $groupInfo = Get-MgGroup -GroupId $groupId - $entry = @{ - ReviewerType = 'Group' - ReviewerId = $groupInfo.DisplayName + try + { + $groupInfo = Get-MgGroup -GroupId $groupId -ErrorAction SilentlyContinue + $entry = @{ + ReviewerType = 'Group' + ReviewerId = $groupInfo.DisplayName + } + } + catch + { + $message = "Group with ID $groupId specified in Reviewers not found" + New-M365DSCLogEntry -Message $message ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue } } elseif ($reviewer.Query.Contains('directory/roleAssignments?$')) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyAuthenticator/MSFT_AADAuthenticationMethodPolicyAuthenticator.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyAuthenticator/MSFT_AADAuthenticationMethodPolicyAuthenticator.psm1 index a06f995f97..121463a947 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyAuthenticator/MSFT_AADAuthenticationMethodPolicyAuthenticator.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyAuthenticator/MSFT_AADAuthenticationMethodPolicyAuthenticator.psm1 @@ -5,6 +5,10 @@ function Get-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [Microsoft.Management.Infrastructure.CimInstance] $FeatureSettings, @@ -25,10 +29,6 @@ function Get-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, #endregion [Parameter()] @@ -65,6 +65,8 @@ function Get-TargetResource $AccessTokens ) + Write-Verbose -Message "Getting the Azure AD Authentication Method Policy with Id {$Id}" + try { $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` @@ -100,12 +102,26 @@ function Get-TargetResource #region resource generator code $complexFeatureSettings = @{} + + Write-Verbose "Processing FeatureSettings > companionAppAllowedState > excludeTarget" $complexCompanionAppAllowedState = @{} $complexExcludeTarget = @{} if ($getValue.additionalProperties.featureSettings.companionAppAllowedState.excludeTarget.id -notmatch 'all_users|00000000-0000-0000-0000-000000000000') { - $myExcludeTargetsDisplayName = Get-MgGroup -GroupId $getValue.additionalProperties.featureSettings.companionAppAllowedState.excludeTarget.id - $complexExcludeTarget.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + try + { + $myExcludeTargetsDisplayName = Get-MgGroup -GroupId $getValue.additionalProperties.featureSettings.companionAppAllowedState.excludeTarget.id -ErrorAction Stop + $complexExcludeTarget.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($getValue.additionalProperties.featureSettings.companionAppAllowedState.excludeTarget.id) specified in excludeTarget. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + } } else { @@ -118,20 +134,36 @@ function Get-TargetResource $complexExcludeTarget.Add('Id', 'all_users') } } + if ($null -ne $getValue.additionalProperties.featureSettings.companionAppAllowedState.excludeTarget.targetType) { $complexExcludeTarget.Add('TargetType', $getValue.additionalProperties.featureSettings.companionAppAllowedState.excludeTarget.targetType.toString()) } + if ($complexExcludeTarget.values.Where({ $null -ne $_ }).count -eq 0) { $complexExcludeTarget = $null } $complexCompanionAppAllowedState.Add('ExcludeTarget', $complexExcludeTarget) + + Write-Verbose "Processing FeatureSettings > companionAppAllowedState > includeTarget" $complexIncludeTarget = @{} if ($getValue.additionalProperties.featureSettings.companionAppAllowedState.includeTarget.id -notmatch 'all_users|00000000-0000-0000-0000-000000000000') { - $myIncludeTargetsDisplayName = Get-MgGroup -GroupId $getValue.additionalProperties.featureSettings.companionAppAllowedState.includeTarget.id - $complexIncludeTarget.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + try + { + $myIncludeTargetsDisplayName = Get-MgGroup -GroupId $getValue.additionalProperties.featureSettings.companionAppAllowedState.includeTarget.id -ErrorAction Stop + $complexIncludeTarget.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($getValue.additionalProperties.featureSettings.companionAppAllowedState.includeTarget.id) specified in includeTarget. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + } } else { @@ -144,31 +176,50 @@ function Get-TargetResource $complexIncludeTarget.Add('Id', 'all_users') } } + if ($null -ne $getValue.additionalProperties.featureSettings.companionAppAllowedState.includeTarget.targetType) { $complexIncludeTarget.Add('TargetType', $getValue.additionalProperties.featureSettings.companionAppAllowedState.includeTarget.targetType.toString()) } + if ($complexIncludeTarget.values.Where({ $null -ne $_ }).count -eq 0) { $complexIncludeTarget = $null } $complexCompanionAppAllowedState.Add('IncludeTarget', $complexIncludeTarget) + + Write-Verbose "Processing FeatureSettings > companionAppAllowedState > state" if ($null -ne $getValue.additionalProperties.featureSettings.companionAppAllowedState.state) { $complexCompanionAppAllowedState.Add('State', $getValue.additionalProperties.featureSettings.companionAppAllowedState.state.toString()) } + if ($complexCompanionAppAllowedState.values.Where({ $null -ne $_ }).count -eq 0) { $complexCompanionAppAllowedState = $null } + $complexFeatureSettings.Add('CompanionAppAllowedState', $complexCompanionAppAllowedState) $complexDisplayAppInformationRequiredState = @{} + Write-Verbose "Processing FeatureSettings > displayAppInformationRequiredState > excludeTarget" $complexExcludeTarget = @{} if ($getValue.additionalProperties.featureSettings.displayAppInformationRequiredState.excludeTarget.id -notmatch 'all_users|00000000-0000-0000-0000-000000000000') { - $myExcludeTargetsDisplayName = Get-MgGroup -GroupId $getValue.additionalProperties.featureSettings.displayAppInformationRequiredState.excludeTarget.id - $complexExcludeTarget.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + try + { + $myExcludeTargetsDisplayName = Get-MgGroup -GroupId $getValue.additionalProperties.featureSettings.displayAppInformationRequiredState.excludeTarget.id -ErrorAction Stop + $complexExcludeTarget.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($getValue.additionalProperties.featureSettings.displayAppInformationRequiredState.excludeTarget.id) specified in excludeTarget. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + } } else { @@ -181,6 +232,7 @@ function Get-TargetResource $complexExcludeTarget.Add('Id', 'all_users') } } + if ($null -ne $getValue.additionalProperties.featureSettings.displayAppInformationRequiredState.excludeTarget.targetType) { $complexExcludeTarget.Add('TargetType', $getValue.additionalProperties.featureSettings.displayAppInformationRequiredState.excludeTarget.targetType.toString()) @@ -190,11 +242,25 @@ function Get-TargetResource $complexExcludeTarget = $null } $complexDisplayAppInformationRequiredState.Add('ExcludeTarget', $complexExcludeTarget) + + Write-Verbose "Processing FeatureSettings > displayAppInformationRequiredState > includeTarget" $complexIncludeTarget = @{} if ($getValue.additionalProperties.featureSettings.displayAppInformationRequiredState.includeTarget.id -notmatch 'all_users|00000000-0000-0000-0000-000000000000') { - $myIncludeTargetsDisplayName = Get-MgGroup -GroupId $getValue.additionalProperties.featureSettings.displayAppInformationRequiredState.includeTarget.id - $complexIncludeTarget.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + try + { + $myIncludeTargetsDisplayName = Get-MgGroup -GroupId $getValue.additionalProperties.featureSettings.displayAppInformationRequiredState.includeTarget.id -ErrorAction Stop + $complexIncludeTarget.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($getValue.additionalProperties.featureSettings.displayAppInformationRequiredState.includeTarget.id) specified in includeTarget. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + } } else { @@ -207,30 +273,50 @@ function Get-TargetResource $complexIncludeTarget.Add('Id', 'all_users') } } + if ($null -ne $getValue.additionalProperties.featureSettings.displayAppInformationRequiredState.includeTarget.targetType) { $complexIncludeTarget.Add('TargetType', $getValue.additionalProperties.featureSettings.displayAppInformationRequiredState.includeTarget.targetType.toString()) } + if ($complexIncludeTarget.values.Where({ $null -ne $_ }).count -eq 0) { $complexIncludeTarget = $null } $complexDisplayAppInformationRequiredState.Add('IncludeTarget', $complexIncludeTarget) + + Write-Verbose "Processing FeatureSettings > displayAppInformationRequiredState > state" if ($null -ne $getValue.additionalProperties.featureSettings.displayAppInformationRequiredState.state) { $complexDisplayAppInformationRequiredState.Add('State', $getValue.additionalProperties.featureSettings.displayAppInformationRequiredState.state.toString()) } + if ($complexDisplayAppInformationRequiredState.values.Where({ $null -ne $_ }).count -eq 0) { $complexDisplayAppInformationRequiredState = $null } + $complexFeatureSettings.Add('DisplayAppInformationRequiredState', $complexDisplayAppInformationRequiredState) + + Write-Verbose "Processing FeatureSettings > displayLocationInformationRequiredState > excludeTarget" $complexDisplayLocationInformationRequiredState = @{} $complexExcludeTarget = @{} if ($getValue.additionalProperties.featureSettings.displayLocationInformationRequiredState.excludeTarget.id -notmatch 'all_users|00000000-0000-0000-0000-000000000000') { - $myExcludeTargetsDisplayName = Get-MgGroup -GroupId $getValue.additionalProperties.featureSettings.displayLocationInformationRequiredState.excludeTarget.id - $complexExcludeTarget.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + try + { + $myExcludeTargetsDisplayName = Get-MgGroup -GroupId $getValue.additionalProperties.featureSettings.displayLocationInformationRequiredState.excludeTarget.id -ErrorAction Stop + $complexExcludeTarget.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($getValue.additionalProperties.featureSettings.displayLocationInformationRequiredState.excludeTarget.id) specified in excludeTarget. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + } } else { @@ -243,20 +329,37 @@ function Get-TargetResource $complexExcludeTarget.Add('Id', 'all_users') } } + if ($null -ne $getValue.additionalProperties.featureSettings.displayLocationInformationRequiredState.excludeTarget.targetType) { $complexExcludeTarget.Add('TargetType', $getValue.additionalProperties.featureSettings.displayLocationInformationRequiredState.excludeTarget.targetType.toString()) } + if ($complexExcludeTarget.values.Where({ $null -ne $_ }).count -eq 0) { $complexExcludeTarget = $null } + $complexDisplayLocationInformationRequiredState.Add('ExcludeTarget', $complexExcludeTarget) + + Write-Verbose "Processing FeatureSettings > displayLocationInformationRequiredState > includeTarget" $complexIncludeTarget = @{} if ($getValue.additionalProperties.featureSettings.displayLocationInformationRequiredState.includeTarget.id -notmatch 'all_users|00000000-0000-0000-0000-000000000000') { - $myIncludeTargetsDisplayName = Get-MgGroup -GroupId $getValue.additionalProperties.featureSettings.displayLocationInformationRequiredState.includeTarget.id - $complexIncludeTarget.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + try + { + $myIncludeTargetsDisplayName = Get-MgGroup -GroupId $getValue.additionalProperties.featureSettings.displayLocationInformationRequiredState.includeTarget.id -ErrorAction Stop + $complexIncludeTarget.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($getValue.additionalProperties.featureSettings.displayLocationInformationRequiredState.includeTarget.id) specified in includeTarget. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + } } else { @@ -269,23 +372,30 @@ function Get-TargetResource $complexIncludeTarget.Add('Id', 'all_users') } } + if ($null -ne $getValue.additionalProperties.featureSettings.displayLocationInformationRequiredState.includeTarget.targetType) { $complexIncludeTarget.Add('TargetType', $getValue.additionalProperties.featureSettings.displayLocationInformationRequiredState.includeTarget.targetType.toString()) } + if ($complexIncludeTarget.values.Where({ $null -ne $_ }).count -eq 0) { $complexIncludeTarget = $null } + $complexDisplayLocationInformationRequiredState.Add('IncludeTarget', $complexIncludeTarget) + + Write-Verbose "Processing FeatureSettings > displayLocationInformationRequiredState > state" if ($null -ne $getValue.additionalProperties.featureSettings.displayLocationInformationRequiredState.state) { $complexDisplayLocationInformationRequiredState.Add('State', $getValue.additionalProperties.featureSettings.displayLocationInformationRequiredState.state.toString()) } + if ($complexDisplayLocationInformationRequiredState.values.Where({ $null -ne $_ }).count -eq 0) { $complexDisplayLocationInformationRequiredState = $null } + $complexFeatureSettings.Add('DisplayLocationInformationRequiredState', $complexDisplayLocationInformationRequiredState) $complexExcludeTargets = @() @@ -305,10 +415,12 @@ function Get-TargetResource { $myExcludeTargets.Add('Id', $currentExcludeTargets.id) } + if ($null -ne $currentExcludeTargets.targetType) { $myExcludeTargets.Add('TargetType', $currentExcludeTargets.targetType.toString()) } + if ($myExcludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexExcludeTargets += $myExcludeTargets @@ -332,10 +444,12 @@ function Get-TargetResource { $myIncludeTargets.Add('Id', $currentIncludeTargets.id) } + if ($null -ne $currentIncludeTargets.targetType) { $myIncludeTargets.Add('TargetType', $currentIncludeTargets.targetType.toString()) } + if ($myIncludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexIncludeTargets += $myIncludeTargets @@ -389,6 +503,10 @@ function Set-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [Microsoft.Management.Infrastructure.CimInstance] $FeatureSettings, @@ -409,12 +527,8 @@ function Set-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion + [Parameter()] [System.String] [ValidateSet('Absent', 'Present')] @@ -449,6 +563,8 @@ function Set-TargetResource $AccessTokens ) + Write-Verbose -Message "Setting the Azure AD Authentication Method Policy Authenticator with Id {$Id}" + #Ensure the proper dependencies are installed in the current environment. Confirm-M365DSCDependencies @@ -589,6 +705,10 @@ function Test-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [Microsoft.Management.Infrastructure.CimInstance] $FeatureSettings, @@ -609,11 +729,6 @@ function Test-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion [Parameter()] diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyEmail/MSFT_AADAuthenticationMethodPolicyEmail.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyEmail/MSFT_AADAuthenticationMethodPolicyEmail.psm1 index 5ceea269ca..120f294f03 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyEmail/MSFT_AADAuthenticationMethodPolicyEmail.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyEmail/MSFT_AADAuthenticationMethodPolicyEmail.psm1 @@ -5,6 +5,10 @@ function Get-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [ValidateSet('default', 'enabled', 'disabled', 'unknownFutureValue')] [System.String] @@ -22,11 +26,6 @@ function Get-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion [Parameter()] @@ -63,6 +62,8 @@ function Get-TargetResource $AccessTokens ) + Write-Verbose -Message "Getting the Azure AD Authentication Method Policy Email with Id {$Id}" + try { $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` @@ -101,17 +102,34 @@ function Get-TargetResource foreach ($currentExcludeTargets in $getValue.excludeTargets) { $myExcludeTargets = @{} - if ($currentExcludeTargets.id -ne 'all_users'){ - $myExcludeTargetsDisplayName = get-MgGroup -GroupId $currentExcludeTargets.id - $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + if ($currentExcludeTargets.id -ne 'all_users') + { + try + { + $myExcludeTargetsDisplayName = Get-MgGroup -GroupId $currentExcludeTargets.id + $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($currentExcludeTargets.id) specified in ExcludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myExcludeTargets.Add('Id', $currentExcludeTargets.id) } + if ($null -ne $currentExcludeTargets.targetType) { $myExcludeTargets.Add('TargetType', $currentExcludeTargets.targetType.toString()) } + if ($myExcludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexExcludeTargets += $myExcludeTargets @@ -130,24 +148,40 @@ function Get-TargetResource foreach ($currentincludeTargets in $getValue.AdditionalProperties.includeTargets) { $myincludeTargets = @{} - if ($currentIncludeTargets.id -ne 'all_users'){ - $myIncludeTargetsDisplayName = get-MgGroup -GroupId $currentIncludeTargets.id - $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + if ($currentIncludeTargets.id -ne 'all_users') + { + try + { + $myIncludeTargetsDisplayName = Get-MgGroup -GroupId $currentIncludeTargets.id + $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($currentIncludeTargets.id) specified in IncludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myIncludeTargets.Add('Id', $currentIncludeTargets.id) } + if ($null -ne $currentincludeTargets.targetType) { $myincludeTargets.Add('TargetType', $currentincludeTargets.targetType.toString()) } + if ($myincludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexIncludeTargets += $myincludeTargets } } - $enumState = $null if ($null -ne $getValue.State) { @@ -193,6 +227,10 @@ function Set-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [ValidateSet('default', 'enabled', 'disabled', 'unknownFutureValue')] [System.String] @@ -210,12 +248,8 @@ function Set-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion + [Parameter()] [System.String] [ValidateSet('Absent', 'Present')] @@ -250,6 +284,8 @@ function Set-TargetResource $AccessTokens ) + Write-Verbose -Message "Setting the Azure AD Authentication Method Policy Email with Id {$Id}" + #Ensure the proper dependencies are installed in the current environment. Confirm-M365DSCDependencies @@ -284,24 +320,28 @@ function Set-TargetResource } if ($key -eq 'IncludeTargets') { + Write-Verbose -Message "Processing IncludeTargets" $i = 0 - foreach ($entry in $UpdateParameters.$key){ + foreach ($entry in $UpdateParameters.$key) + { if ($entry.id -notmatch '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$|all_users') { $Filter = "Displayname eq '$($entry.id)'" | Out-String - $UpdateParameters.$key[$i].foreach('id',(Get-MgGroup -Filter $Filter).id.ToString()) + $UpdateParameters.$key[$i].foreach('id', (Get-MgGroup -Filter $Filter).id.ToString()) } $i++ } } if ($key -eq 'ExcludeTargets') { + Write-Verbose -Message "Processing ExcludeTargets" $i = 0 - foreach ($entry in $UpdateParameters.$key){ + foreach ($entry in $UpdateParameters.$key) + { if ($entry.id -notmatch '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$|all_users') { $Filter = "Displayname eq '$($entry.id)'" | Out-String - $UpdateParameters.$key[$i].foreach('id',(Get-MgGroup -Filter $Filter).id.ToString()) + $UpdateParameters.$key[$i].foreach('id', (Get-MgGroup -Filter $Filter).id.ToString()) } $i++ } @@ -330,6 +370,10 @@ function Test-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [ValidateSet('default', 'enabled', 'disabled', 'unknownFutureValue')] [System.String] @@ -347,11 +391,6 @@ function Test-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion [Parameter()] @@ -388,6 +427,8 @@ function Test-TargetResource $AccessTokens ) + Write-Verbose -Message "Testing the Azure AD Authentication Method Policy Email with Id {$Id}" + #Ensure the proper dependencies are installed in the current environment. Confirm-M365DSCDependencies @@ -508,7 +549,7 @@ function Export-TargetResource #region resource generator code [array]$getValue = Get-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration ` -AuthenticationMethodConfigurationId Email ` - -ErrorAction Stop | Where-Object -FilterScript {$null -ne $_.Id} + -ErrorAction Stop | Where-Object -FilterScript { $null -ne $_.Id } #endregion $i = 1 diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyExternal/MSFT_AADAuthenticationMethodPolicyExternal.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyExternal/MSFT_AADAuthenticationMethodPolicyExternal.psm1 index bb71db082e..ecd65ce44b 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyExternal/MSFT_AADAuthenticationMethodPolicyExternal.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyExternal/MSFT_AADAuthenticationMethodPolicyExternal.psm1 @@ -92,12 +92,12 @@ function Get-TargetResource { if ($null -ne $Script:exportedInstances -and $Script:ExportMode) { - $getValue = $Script:exportedInstances | Where-Object -FilterScript {$_.DisplayName -eq $DisplayName} + $getValue = $Script:exportedInstances | Where-Object -FilterScript { $_.DisplayName -eq $DisplayName } } else { - $response = Invoke-MgGraphRequest -Method Get -Uri ($Global:MSCloudLoginConnectionProfile.MicrosoftGraph.ResourceUrl + "beta/policies/authenticationMethodsPolicy/") - $getValue = $response.authenticationMethodConfigurations | Where-Object -FilterScript {$_.DisplayName -eq $DisplayName} + $response = Invoke-MgGraphRequest -Method Get -Uri ($Global:MSCloudLoginConnectionProfile.MicrosoftGraph.ResourceUrl + 'beta/policies/authenticationMethodsPolicy/') + $getValue = $response.authenticationMethodConfigurations | Where-Object -FilterScript { $_.DisplayName -eq $DisplayName } } } @@ -115,17 +115,34 @@ function Get-TargetResource foreach ($currentExcludeTargets in $getValue.excludeTargets) { $myExcludeTargets = @{} - if ($currentExcludeTargets.id -ne 'all_users'){ - $myExcludeTargetsDisplayName = get-MgGroup -GroupId $currentExcludeTargets.id - $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + if ($currentExcludeTargets.id -ne 'all_users') + { + try + { + $myExcludeTargetsDisplayName = Get-MgGroup -GroupId $currentExcludeTargets.id -ErrorAction Stop + $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($currentExcludeTargets.id) specified in ExcludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myExcludeTargets.Add('Id', $currentExcludeTargets.id) } + if ($null -ne $currentExcludeTargets.targetType) { $myExcludeTargets.Add('TargetType', $currentExcludeTargets.targetType.toString()) } + if ($myExcludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexExcludeTargets += $myExcludeTargets @@ -137,17 +154,34 @@ function Get-TargetResource foreach ($currentincludeTargets in $getValue.includeTargets) { $myincludeTargets = @{} - if ($currentIncludeTargets.id -ne 'all_users'){ - $myIncludeTargetsDisplayName = get-MgGroup -GroupId $currentIncludeTargets.id - $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + if ($currentIncludeTargets.id -ne 'all_users') + { + try + { + $myIncludeTargetsDisplayName = Get-MgGroup -GroupId $currentIncludeTargets.id -ErrorAction Stop + $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($currentIncludeTargets.id) specified in IncludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myIncludeTargets.Add('Id', $currentIncludeTargets.id) } + if ($null -ne $currentincludeTargets.targetType) { $myincludeTargets.Add('TargetType', $currentincludeTargets.targetType.toString()) } + if ($myincludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexincludeTargets += $myincludeTargets @@ -155,7 +189,7 @@ function Get-TargetResource } $complexOpenIdConnectSetting = @{ - clientId = $getValue.OpenIdConnectSetting.ClientId + clientId = $getValue.OpenIdConnectSetting.ClientId discoveryUrl = $getValue.OpenIdConnectSetting.DiscoveryUrl } @@ -300,8 +334,8 @@ function Set-TargetResource { Write-Verbose -Message "Updating the Azure AD Authentication Method Policy External with name {$($currentInstance.displayName)}" - $response = Invoke-MgGraphRequest -Method Get -Uri ($Global:MSCloudLoginConnectionProfile.MicrosoftGraph.ResourceUrl + "beta/policies/authenticationMethodsPolicy/") - $getValue = $response.authenticationMethodConfigurations | Where-Object -FilterScript {$_.displayName -eq $currentInstance.displayName} + $response = Invoke-MgGraphRequest -Method Get -Uri ($Global:MSCloudLoginConnectionProfile.MicrosoftGraph.ResourceUrl + 'beta/policies/authenticationMethodsPolicy/') + $getValue = $response.authenticationMethodConfigurations | Where-Object -FilterScript { $_.displayName -eq $currentInstance.displayName } $params.Remove('displayName') | Out-Null @@ -313,8 +347,8 @@ function Set-TargetResource { Write-Verbose -Message "Removing the Azure AD Authentication Method Policy External with Id {$($currentInstance.displayName)}" - $response = Invoke-MgGraphRequest -Method Get -Uri ($Global:MSCloudLoginConnectionProfile.MicrosoftGraph.ResourceUrl + "beta/policies/authenticationMethodsPolicy/") - $getValue = $response.authenticationMethodConfigurations | Where-Object -FilterScript {$_.displayName -eq $currentInstance.displayName} + $response = Invoke-MgGraphRequest -Method Get -Uri ($Global:MSCloudLoginConnectionProfile.MicrosoftGraph.ResourceUrl + 'beta/policies/authenticationMethodsPolicy/') + $getValue = $response.authenticationMethodConfigurations | Where-Object -FilterScript { $_.displayName -eq $currentInstance.displayName } Remove-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration -AuthenticationMethodConfigurationId $getValue.Id } @@ -504,9 +538,9 @@ function Export-TargetResource try { #region resource generator code - $desiredType = "#microsoft.graph.externalAuthenticationMethodConfiguration" - $getPolicy = Invoke-MgGraphRequest -Method Get -Uri ($Global:MSCloudLoginConnectionProfile.MicrosoftGraph.ResourceUrl + "beta/policies/authenticationMethodsPolicy/") - $getValue = $getPolicy.AuthenticationMethodConfigurations | Where-Object -FilterScript {$_.'@odata.type' -eq $desiredType} + $desiredType = '#microsoft.graph.externalAuthenticationMethodConfiguration' + $getPolicy = Invoke-MgGraphRequest -Method Get -Uri ($Global:MSCloudLoginConnectionProfile.MicrosoftGraph.ResourceUrl + 'beta/policies/authenticationMethodsPolicy/') + $getValue = $getPolicy.AuthenticationMethodConfigurations | Where-Object -FilterScript { $_.'@odata.type' -eq $desiredType } #endregion $i = 1 @@ -649,11 +683,12 @@ function Get-UpdatedTargetProperty if ($key -eq 'IncludeTargets') { $i = 0 - foreach ($entry in $params.$key){ + foreach ($entry in $params.$key) + { if ($entry.id -notmatch '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$|all_users') { $Filter = "Displayname eq '$($entry.id)'" | Out-String - $params.$key[$i].foreach('id',(Get-MgGroup -Filter $Filter).id.ToString()) + $params.$key[$i].foreach('id', (Get-MgGroup -Filter $Filter).id.ToString()) } $i++ } @@ -661,11 +696,12 @@ function Get-UpdatedTargetProperty if ($key -eq 'ExcludeTargets') { $i = 0 - foreach ($entry in $params.$key){ + foreach ($entry in $params.$key) + { if ($entry.id -notmatch '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$|all_users') { $Filter = "Displayname eq '$($entry.id)'" | Out-String - $params.$key[$i].foreach('id',(Get-MgGroup -Filter $Filter).id.ToString()) + $params.$key[$i].foreach('id', (Get-MgGroup -Filter $Filter).id.ToString()) } $i++ } diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyFido2/MSFT_AADAuthenticationMethodPolicyFido2.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyFido2/MSFT_AADAuthenticationMethodPolicyFido2.psm1 index a5d2268cb8..66066badf9 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyFido2/MSFT_AADAuthenticationMethodPolicyFido2.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyFido2/MSFT_AADAuthenticationMethodPolicyFido2.psm1 @@ -5,6 +5,10 @@ function Get-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [System.Boolean] $IsAttestationEnforced, @@ -29,11 +33,6 @@ function Get-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion [Parameter()] @@ -70,6 +69,8 @@ function Get-TargetResource $AccessTokens ) + Write-Verbose -Message "Getting the Azure AD Authentication Method Policy Fido2 with Id {$Id}" + try { $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` @@ -104,6 +105,7 @@ function Get-TargetResource Write-Verbose -Message "An Azure AD Authentication Method Policy Fido2 with Id {$Id} was found." #region resource generator code + Write-Verbose "Processing KeyRestrictions" $complexKeyRestrictions = @{} $complexKeyRestrictions.Add('AaGuids', $getValue.AdditionalProperties.keyRestrictions.aaGuids) if ($null -ne $getValue.AdditionalProperties.keyRestrictions.enforcementType) @@ -116,21 +118,39 @@ function Get-TargetResource $complexKeyRestrictions = $null } + Write-Verbose "Processing ExcludeTargets" $complexExcludeTargets = @() foreach ($currentExcludeTargets in $getValue.excludeTargets) { $myExcludeTargets = @{} - if ($currentExcludeTargets.id -ne 'all_users'){ - $myExcludeTargetsDisplayName = get-MgGroup -GroupId $currentExcludeTargets.id - $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + if ($currentExcludeTargets.id -ne 'all_users') + { + try + { + $myExcludeTargetsDisplayName = Get-MgGroup -GroupId $currentExcludeTargets.id -ErrorAction Stop + $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($currentExcludeTargets.id) specified in ExcludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myExcludeTargets.Add('Id', $currentExcludeTargets.id) } + if ($null -ne $currentExcludeTargets.targetType) { $myExcludeTargets.Add('TargetType', $currentExcludeTargets.targetType.toString()) } + if ($myExcludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexExcludeTargets += $myExcludeTargets @@ -138,24 +158,42 @@ function Get-TargetResource } #endregion - $CoomplexIncludeTargets = @() + Write-Verbose "Processing IncludeTargets" + $complexIncludeTargets = @() foreach ($currentIncludeTargets in $getValue.AdditionalProperties.includeTargets) { $myIncludeTargets = @{} - if ($currentIncludeTargets.id -ne 'all_users'){ - $myIncludeTargetsDisplayName = get-MgGroup -GroupId $currentIncludeTargets.id - $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + if ($currentIncludeTargets.id -ne 'all_users') + { + try + { + $myIncludeTargetsDisplayName = Get-MgGroup -GroupId $currentIncludeTargets.id -ErrorAction Stop + $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($currentIncludeTargets.id) specified in IncludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myIncludeTargets.Add('Id', $currentIncludeTargets.id) } + if ($null -ne $currentIncludeTargets.targetType) { $myIncludeTargets.Add('TargetType', $currentIncludeTargets.targetType.toString()) } + if ($myIncludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { - $CoomplexIncludeTargets += $myIncludeTargets + $complexIncludeTargets += $myIncludeTargets } } @@ -173,7 +211,7 @@ function Get-TargetResource IsSelfServiceRegistrationAllowed = $getValue.AdditionalProperties.isSelfServiceRegistrationAllowed KeyRestrictions = $complexKeyRestrictions ExcludeTargets = $complexExcludeTargets - IncludeTargets = $CoomplexIncludeTargets + IncludeTargets = $complexIncludeTargets State = $enumState Id = $getValue.Id Ensure = 'Present' @@ -207,6 +245,10 @@ function Set-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [System.Boolean] $IsAttestationEnforced, @@ -231,12 +273,8 @@ function Set-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion + [Parameter()] [System.String] [ValidateSet('Absent', 'Present')] @@ -271,6 +309,8 @@ function Set-TargetResource $AccessTokens ) + Write-Verbose -Message "Setting the Azure AD Authentication Method Policy Fido2 with Id {$Id}" + #Ensure the proper dependencies are installed in the current environment. Confirm-M365DSCDependencies @@ -306,11 +346,12 @@ function Set-TargetResource if ($key -eq 'IncludeTargets') { $i = 0 - foreach ($entry in $UpdateParameters.$key){ + foreach ($entry in $UpdateParameters.$key) + { if ($entry.id -notmatch '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$|all_users') { $Filter = "Displayname eq '$($entry.id)'" | Out-String - $UpdateParameters.$key[$i].foreach('id',(Get-MgGroup -Filter $Filter).id.ToString()) + $UpdateParameters.$key[$i].foreach('id', (Get-MgGroup -Filter $Filter).id.ToString()) } $i++ } @@ -318,11 +359,12 @@ function Set-TargetResource if ($key -eq 'ExcludeTargets') { $i = 0 - foreach ($entry in $UpdateParameters.$key){ + foreach ($entry in $UpdateParameters.$key) + { if ($entry.id -notmatch '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$|all_users') { $Filter = "Displayname eq '$($entry.id)'" | Out-String - $UpdateParameters.$key[$i].foreach('id',(Get-MgGroup -Filter $Filter).id.ToString()) + $UpdateParameters.$key[$i].foreach('id', (Get-MgGroup -Filter $Filter).id.ToString()) } $i++ } @@ -351,6 +393,10 @@ function Test-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [System.Boolean] $IsAttestationEnforced, @@ -375,11 +421,6 @@ function Test-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion [Parameter()] @@ -536,7 +577,7 @@ function Export-TargetResource #region resource generator code [array]$getValue = Get-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration ` -AuthenticationMethodConfigurationId Fido2 ` - -ErrorAction Stop | Where-Object -FilterScript {$null -ne $_.Id} + -ErrorAction Stop | Where-Object -FilterScript { $null -ne $_.Id } #endregion $i = 1 diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyHardware/MSFT_AADAuthenticationMethodPolicyHardware.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyHardware/MSFT_AADAuthenticationMethodPolicyHardware.psm1 index 30be7f9089..d49a0965bc 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyHardware/MSFT_AADAuthenticationMethodPolicyHardware.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyHardware/MSFT_AADAuthenticationMethodPolicyHardware.psm1 @@ -96,17 +96,34 @@ function Get-TargetResource foreach ($currentExcludeTargets in $getValue.excludeTargets) { $myExcludeTargets = @{} - if ($currentExcludeTargets.id -ne 'all_users'){ - $myExcludeTargetsDisplayName = get-MgGroup -GroupId $currentExcludeTargets.id - $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + if ($currentExcludeTargets.id -ne 'all_users') + { + try + { + $myExcludeTargetsDisplayName = Get-MgGroup -GroupId $currentExcludeTargets.id -ErrorAction Stop + $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($currentExcludeTargets.id) specified in ExcludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myExcludeTargets.Add('Id', $currentExcludeTargets.id) } + if ($null -ne $currentExcludeTargets.targetType) { $myExcludeTargets.Add('TargetType', $currentExcludeTargets.targetType.toString()) } + if ($myExcludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexExcludeTargets += $myExcludeTargets @@ -118,17 +135,35 @@ function Get-TargetResource foreach ($currentincludeTargets in $getValue.AdditionalProperties.includeTargets) { $myincludeTargets = @{} - if ($currentIncludeTargets.id -ne 'all_users'){ - $myIncludeTargetsDisplayName = get-MgGroup -GroupId $currentIncludeTargets.id - $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + if ($currentIncludeTargets.id -ne 'all_users') + { + try + { + $myIncludeTargetsDisplayName = Get-MgGroup -GroupId $currentIncludeTargets.id -ErrorAction Stop + $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + + } + catch + { + $message = "Could not find a group with id $($currentIncludeTargets.id) specified in IncludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myIncludeTargets.Add('Id', $currentIncludeTargets.id) } + if ($null -ne $currentincludeTargets.targetType) { $myincludeTargets.Add('TargetType', $currentincludeTargets.targetType.toString()) } + if ($myincludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexincludeTargets += $myincludeTargets @@ -266,11 +301,12 @@ function Set-TargetResource if ($key -eq 'IncludeTargets') { $i = 0 - foreach ($entry in $UpdateParameters.$key){ + foreach ($entry in $UpdateParameters.$key) + { if ($entry.id -notmatch '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$|all_users') { $Filter = "Displayname eq '$($entry.id)'" | Out-String - $UpdateParameters.$key[$i].foreach('id',(Get-MgGroup -Filter $Filter).id.ToString()) + $UpdateParameters.$key[$i].foreach('id', (Get-MgGroup -Filter $Filter).id.ToString()) } $i++ } @@ -278,11 +314,12 @@ function Set-TargetResource if ($key -eq 'ExcludeTargets') { $i = 0 - foreach ($entry in $UpdateParameters.$key){ + foreach ($entry in $UpdateParameters.$key) + { if ($entry.id -notmatch '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$|all_users') { $Filter = "Displayname eq '$($entry.id)'" | Out-String - $UpdateParameters.$key[$i].foreach('id',(Get-MgGroup -Filter $Filter).id.ToString()) + $UpdateParameters.$key[$i].foreach('id', (Get-MgGroup -Filter $Filter).id.ToString()) } $i++ } @@ -484,7 +521,7 @@ function Export-TargetResource #region resource generator code [array]$getValue = Get-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration ` -AuthenticationMethodConfigurationId HardwareOath ` - -ErrorAction Stop | Where-Object -FilterScript {$null -ne $_.Id} + -ErrorAction Stop | Where-Object -FilterScript { $null -ne $_.Id } #endregion $i = 1 diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicySms/MSFT_AADAuthenticationMethodPolicySms.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicySms/MSFT_AADAuthenticationMethodPolicySms.psm1 index c04894b025..f0cc33f024 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicySms/MSFT_AADAuthenticationMethodPolicySms.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicySms/MSFT_AADAuthenticationMethodPolicySms.psm1 @@ -5,6 +5,10 @@ function Get-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [Microsoft.Management.Infrastructure.CimInstance[]] $ExcludeTargets, @@ -17,11 +21,6 @@ function Get-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion [Parameter()] @@ -58,6 +57,8 @@ function Get-TargetResource $AccessTokens ) + Write-Verbose -Message "Getting the Azure AD Authentication Method Policy Sms with Id {$Id}" + try { $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` @@ -92,21 +93,39 @@ function Get-TargetResource Write-Verbose -Message "An Azure AD Authentication Method Policy Sms with Id {$Id} was found." #region resource generator code + Write-Verbose -Message "Processing ExcludeTargets" $complexExcludeTargets = @() foreach ($currentExcludeTargets in $getValue.excludeTargets) { $myExcludeTargets = @{} - if ($currentExcludeTargets.id -ne 'all_users'){ - $myExcludeTargetsDisplayName = get-MgGroup -GroupId $currentExcludeTargets.id - $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + if ($currentExcludeTargets.id -ne 'all_users') + { + try + { + $myExcludeTargetsDisplayName = Get-MgGroup -GroupId $currentExcludeTargets.id -ErrorAction Stop + $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($currentExcludeTargets.id) specified in ExcludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myExcludeTargets.Add('Id', $currentExcludeTargets.id) } + if ($null -ne $currentExcludeTargets.targetType) { $myExcludeTargets.Add('TargetType', $currentExcludeTargets.targetType.toString()) } + if ($myExcludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexExcludeTargets += $myExcludeTargets @@ -114,21 +133,40 @@ function Get-TargetResource } #endregion + Write-Verbose -Message "Processing IncludeTargets" $complexincludeTargets = @() foreach ($currentincludeTargets in $getValue.AdditionalProperties.includeTargets) { $myincludeTargets = @{} - if ($currentIncludeTargets.id -ne 'all_users'){ - $myIncludeTargetsDisplayName = get-MgGroup -GroupId $currentIncludeTargets.id - $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + if ($currentIncludeTargets.id -ne 'all_users') + { + try + { + $myIncludeTargetsDisplayName = Get-MgGroup -GroupId $currentIncludeTargets.id -ErrorAction Stop + $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + + } + catch + { + $message = "Could not find a group with id $($currentIncludeTargets.id) specified in IncludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myIncludeTargets.Add('Id', $currentIncludeTargets.id) } + if ($null -ne $currentincludeTargets.targetType) { $myincludeTargets.Add('TargetType', $currentincludeTargets.targetType.toString()) } + if ($myincludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexincludeTargets += $myincludeTargets @@ -179,6 +217,10 @@ function Set-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [Microsoft.Management.Infrastructure.CimInstance[]] $ExcludeTargets, @@ -191,12 +233,8 @@ function Set-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion + [Parameter()] [System.String] [ValidateSet('Absent', 'Present')] @@ -231,6 +269,8 @@ function Set-TargetResource $AccessTokens ) + Write-Verbose -Message "Setting the Azure AD Authentication Method Policy Fido2 with Id {$Id}" + #Ensure the proper dependencies are installed in the current environment. Confirm-M365DSCDependencies @@ -266,11 +306,12 @@ function Set-TargetResource if ($key -eq 'IncludeTargets') { $i = 0 - foreach ($entry in $UpdateParameters.$key){ + foreach ($entry in $UpdateParameters.$key) + { if ($entry.id -notmatch '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$|all_users') { $Filter = "Displayname eq '$($entry.id)'" | Out-String - $UpdateParameters.$key[$i].foreach('id',(Get-MgGroup -Filter $Filter).id.ToString()) + $UpdateParameters.$key[$i].foreach('id', (Get-MgGroup -Filter $Filter).id.ToString()) } $i++ } @@ -278,11 +319,12 @@ function Set-TargetResource if ($key -eq 'ExcludeTargets') { $i = 0 - foreach ($entry in $UpdateParameters.$key){ + foreach ($entry in $UpdateParameters.$key) + { if ($entry.id -notmatch '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$|all_users') { $Filter = "Displayname eq '$($entry.id)'" | Out-String - $UpdateParameters.$key[$i].foreach('id',(Get-MgGroup -Filter $Filter).id.ToString()) + $UpdateParameters.$key[$i].foreach('id', (Get-MgGroup -Filter $Filter).id.ToString()) } $i++ } @@ -311,6 +353,10 @@ function Test-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [Microsoft.Management.Infrastructure.CimInstance[]] $ExcludeTargets, @@ -323,11 +369,6 @@ function Test-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion [Parameter()] @@ -484,7 +525,7 @@ function Export-TargetResource #region resource generator code [array]$getValue = Get-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration ` -AuthenticationMethodConfigurationId sms ` - -ErrorAction Stop | Where-Object -FilterScript {$null -ne $_.Id} + -ErrorAction Stop | Where-Object -FilterScript { $null -ne $_.Id } #endregion $i = 1 @@ -536,7 +577,7 @@ function Export-TargetResource } } - if($null -ne $Results.IncludeTargets) + if ($null -ne $Results.IncludeTargets) { $complexTypeStringResult = Get-M365DSCDRGComplexTypeToString ` -ComplexObject $Results.IncludeTargets ` diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicySoftware/MSFT_AADAuthenticationMethodPolicySoftware.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicySoftware/MSFT_AADAuthenticationMethodPolicySoftware.psm1 index a169bdd262..5d5ab861f5 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicySoftware/MSFT_AADAuthenticationMethodPolicySoftware.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicySoftware/MSFT_AADAuthenticationMethodPolicySoftware.psm1 @@ -5,6 +5,10 @@ function Get-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [Microsoft.Management.Infrastructure.CimInstance[]] $ExcludeTargets, @@ -17,11 +21,6 @@ function Get-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion [Parameter()] @@ -58,6 +57,8 @@ function Get-TargetResource $AccessTokens ) + Write-Verbose -Message "Getting the Azure AD Authentication Method Policy Software with Id {$Id}" + try { $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` @@ -92,21 +93,39 @@ function Get-TargetResource Write-Verbose -Message "An Azure AD Authentication Method Policy Software with Id {$Id} was found." #region resource generator code + Write-Verbose -Message "Processing ExcludeTargets" $complexExcludeTargets = @() foreach ($currentExcludeTargets in $getValue.excludeTargets) { $myExcludeTargets = @{} - if ($currentExcludeTargets.id -ne 'all_users'){ - $myExcludeTargetsDisplayName = get-MgGroup -GroupId $currentExcludeTargets.id - $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + if ($currentExcludeTargets.id -ne 'all_users') + { + try + { + $myExcludeTargetsDisplayName = Get-MgGroup -GroupId $currentExcludeTargets.id -ErrorAction Stop + $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($currentExcludeTargets.id) specified in ExcludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myExcludeTargets.Add('Id', $currentExcludeTargets.id) } + if ($null -ne $currentExcludeTargets.targetType) { $myExcludeTargets.Add('TargetType', $currentExcludeTargets.targetType.toString()) } + if ($myExcludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexExcludeTargets += $myExcludeTargets @@ -114,21 +133,39 @@ function Get-TargetResource } #endregion + Write-Verbose -Message "Processing IncludeTargets" $complexincludeTargets = @() foreach ($currentincludeTargets in $getValue.AdditionalProperties.includeTargets) { $myincludeTargets = @{} - if ($currentIncludeTargets.id -ne 'all_users'){ - $myIncludeTargetsDisplayName = get-MgGroup -GroupId $currentIncludeTargets.id - $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + if ($currentIncludeTargets.id -ne 'all_users') + { + try + { + $myIncludeTargetsDisplayName = Get-MgGroup -GroupId $currentIncludeTargets.id -ErrorAction Stop + $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($currentIncludeTargets.id) specified in IncludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myIncludeTargets.Add('Id', $currentIncludeTargets.id) } + if ($null -ne $currentincludeTargets.targetType) { $myincludeTargets.Add('TargetType', $currentincludeTargets.targetType.toString()) } + if ($myincludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexincludeTargets += $myincludeTargets @@ -179,6 +216,10 @@ function Set-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [Microsoft.Management.Infrastructure.CimInstance[]] $ExcludeTargets, @@ -191,12 +232,8 @@ function Set-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion + [Parameter()] [System.String] [ValidateSet('Absent', 'Present')] @@ -231,6 +268,8 @@ function Set-TargetResource $AccessTokens ) + Write-Verbose -Message "Setting the Azure AD Authentication Method Policy Software with Id {$Id}" + #Ensure the proper dependencies are installed in the current environment. Confirm-M365DSCDependencies @@ -266,11 +305,12 @@ function Set-TargetResource if ($key -eq 'IncludeTargets') { $i = 0 - foreach ($entry in $UpdateParameters.$key){ + foreach ($entry in $UpdateParameters.$key) + { if ($entry.id -notmatch '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$|all_users') { $Filter = "Displayname eq '$($entry.id)'" | Out-String - $UpdateParameters.$key[$i].foreach('id',(Get-MgGroup -Filter $Filter).id.ToString()) + $UpdateParameters.$key[$i].foreach('id', (Get-MgGroup -Filter $Filter).id.ToString()) } $i++ } @@ -278,11 +318,12 @@ function Set-TargetResource if ($key -eq 'ExcludeTargets') { $i = 0 - foreach ($entry in $UpdateParameters.$key){ + foreach ($entry in $UpdateParameters.$key) + { if ($entry.id -notmatch '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$|all_users') { $Filter = "Displayname eq '$($entry.id)'" | Out-String - $UpdateParameters.$key[$i].foreach('id',(Get-MgGroup -Filter $Filter).id.ToString()) + $UpdateParameters.$key[$i].foreach('id', (Get-MgGroup -Filter $Filter).id.ToString()) } $i++ } @@ -311,6 +352,10 @@ function Test-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [Microsoft.Management.Infrastructure.CimInstance[]] $ExcludeTargets, @@ -323,11 +368,6 @@ function Test-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion [Parameter()] @@ -484,7 +524,7 @@ function Export-TargetResource #region resource generator code [array]$getValue = Get-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration ` -AuthenticationMethodConfigurationId SoftwareOath ` - -ErrorAction Stop | Where-Object -FilterScript {$null -ne $_.Id} + -ErrorAction Stop | Where-Object -FilterScript { $null -ne $_.Id } #endregion $i = 1 diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyTemporary/MSFT_AADAuthenticationMethodPolicyTemporary.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyTemporary/MSFT_AADAuthenticationMethodPolicyTemporary.psm1 index 1a70718259..afbb27114f 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyTemporary/MSFT_AADAuthenticationMethodPolicyTemporary.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyTemporary/MSFT_AADAuthenticationMethodPolicyTemporary.psm1 @@ -5,6 +5,10 @@ function Get-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [System.Int32] $DefaultLength, @@ -37,11 +41,6 @@ function Get-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion [Parameter()] @@ -78,6 +77,8 @@ function Get-TargetResource $AccessTokens ) + Write-Verbose -Message "Getting the Azure AD Authentication Method Policy Temporary with Id {$Id}" + try { $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` @@ -105,29 +106,47 @@ function Get-TargetResource #endregion if ($null -eq $getValue) { - Write-Verbose -Message "Could not find an Azure AD Authentication Method Policy Temporary" + Write-Verbose -Message 'Could not find an Azure AD Authentication Method Policy Temporary' return $nullResult } $Id = $getValue.Id Write-Verbose -Message "An Azure AD Authentication Method Policy Temporary with Id {$($currentExcludeTargets.id))} was found." #region resource generator code + Write-Verbose -Message "Processing ExcludeTargets" $complexExcludeTargets = @() foreach ($currentExcludeTargets in $getValue.excludeTargets) { Write-Verbose -Message "Retrieving ExcludeTarget {$currentExcludeTargets}" $myExcludeTargets = @{} - if ($currentExcludeTargets.id -ne 'all_users'){ - $myExcludeTargetsDisplayName = get-MgGroup -GroupId $currentExcludeTargets.id - $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + if ($currentExcludeTargets.id -ne 'all_users') + { + try + { + $myExcludeTargetsDisplayName = Get-MgGroup -GroupId $currentExcludeTargets.id -ErrorAction Stop + $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($currentExcludeTargets.id) specified in ExcludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myExcludeTargets.Add('Id', $currentExcludeTargets.id) } + if ($null -ne $currentExcludeTargets.targetType) { $myExcludeTargets.Add('TargetType', $currentExcludeTargets.targetType.toString()) } + if ($myExcludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexExcludeTargets += $myExcludeTargets @@ -135,27 +154,46 @@ function Get-TargetResource } #endregion + Write-Verbose -Message "Processing IncludeTargets" $complexincludeTargets = @() foreach ($currentincludeTargets in $getValue.AdditionalProperties.includeTargets) { Write-Verbose -Message "Retrieving IncludeTarget {$($currentincludeTargets.id)}" $myincludeTargets = @{} - if ($currentIncludeTargets.id -ne 'all_users'){ - $myIncludeTargetsDisplayName = get-MgGroup -GroupId $currentIncludeTargets.id - $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + if ($currentIncludeTargets.id -ne 'all_users') + { + try + { + $myIncludeTargetsDisplayName = Get-MgGroup -GroupId $currentIncludeTargets.id -ErrorAction Stop + $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($currentIncludeTargets.id) specified in IncludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myIncludeTargets.Add('Id', $currentIncludeTargets.id) } + if ($null -ne $currentincludeTargets.targetType) { $myincludeTargets.Add('TargetType', $currentincludeTargets.targetType.toString()) } + if ($myincludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexincludeTargets += $myincludeTargets } } + #region resource generator code $enumState = $null if ($null -ne $getValue.State) @@ -164,7 +202,7 @@ function Get-TargetResource } #endregion - Write-Verbose -Message "Get-TargetResource returned values" + Write-Verbose -Message 'Get-TargetResource returned values' $results = @{ #region resource generator code DefaultLength = $getValue.AdditionalProperties.defaultLength @@ -207,6 +245,10 @@ function Set-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [System.Int32] $DefaultLength, @@ -239,12 +281,8 @@ function Set-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion + [Parameter()] [System.String] [ValidateSet('Absent', 'Present')] @@ -279,6 +317,8 @@ function Set-TargetResource $AccessTokens ) + Write-Verbose -Message "Setting the Azure AD Authentication Method Policy Temporary with Id {$Id}" + #Ensure the proper dependencies are installed in the current environment. Confirm-M365DSCDependencies @@ -314,11 +354,12 @@ function Set-TargetResource if ($key -eq 'IncludeTargets') { $i = 0 - foreach ($entry in $UpdateParameters.$key){ + foreach ($entry in $UpdateParameters.$key) + { if ($entry.id -notmatch '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$|all_users') { $Filter = "Displayname eq '$($entry.id)'" | Out-String - $UpdateParameters.$key[$i].foreach('id',(Get-MgGroup -Filter $Filter).id.ToString()) + $UpdateParameters.$key[$i].foreach('id', (Get-MgGroup -Filter $Filter).id.ToString()) } $i++ } @@ -326,11 +367,12 @@ function Set-TargetResource if ($key -eq 'ExcludeTargets') { $i = 0 - foreach ($entry in $UpdateParameters.$key){ + foreach ($entry in $UpdateParameters.$key) + { if ($entry.id -notmatch '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$|all_users') { $Filter = "Displayname eq '$($entry.id)'" | Out-String - $UpdateParameters.$key[$i].foreach('id',(Get-MgGroup -Filter $Filter).id.ToString()) + $UpdateParameters.$key[$i].foreach('id', (Get-MgGroup -Filter $Filter).id.ToString()) } $i++ } @@ -359,6 +401,10 @@ function Test-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [System.Int32] $DefaultLength, @@ -391,11 +437,6 @@ function Test-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion [Parameter()] @@ -457,7 +498,7 @@ function Test-TargetResource $testResult = $true #Compare Cim instances - Write-Verbose -Message "Evaluating keys" + Write-Verbose -Message 'Evaluating keys' foreach ($key in $PSBoundParameters.Keys) { $source = $PSBoundParameters.$key @@ -553,7 +594,7 @@ function Export-TargetResource #region resource generator code [array]$getValue = Get-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration ` -AuthenticationMethodConfigurationId TemporaryAccessPass ` - -ErrorAction Stop | Where-Object -FilterScript {$null -ne $_.Id} + -ErrorAction Stop | Where-Object -FilterScript { $null -ne $_.Id } #endregion $i = 1 diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyVoice/MSFT_AADAuthenticationMethodPolicyVoice.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyVoice/MSFT_AADAuthenticationMethodPolicyVoice.psm1 index de6206c2d9..c74b6b96e1 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyVoice/MSFT_AADAuthenticationMethodPolicyVoice.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyVoice/MSFT_AADAuthenticationMethodPolicyVoice.psm1 @@ -5,6 +5,10 @@ function Get-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [System.Boolean] $IsOfficePhoneAllowed, @@ -21,11 +25,6 @@ function Get-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion [Parameter()] @@ -62,6 +61,8 @@ function Get-TargetResource $AccessTokens ) + Write-Verbose -Message "Getting the Azure AD Authentication Method Policy Voice with Id {$Id}" + try { $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` @@ -96,21 +97,39 @@ function Get-TargetResource Write-Verbose -Message "An Azure AD Authentication Method Policy Voice with Id {$Id} was found." #region resource generator code + Write-Verbose -Message "Processing ExcludeTargets" $complexExcludeTargets = @() foreach ($currentExcludeTargets in $getValue.excludeTargets) { $myExcludeTargets = @{} - if ($currentExcludeTargets.id -ne 'all_users'){ - $myExcludeTargetsDisplayName = get-MgGroup -GroupId $currentExcludeTargets.id - $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + if ($currentExcludeTargets.id -ne 'all_users') + { + try + { + $myExcludeTargetsDisplayName = Get-MgGroup -GroupId $currentExcludeTargets.id -ErrorAction Stop + $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($currentExcludeTargets.id) specified in ExcludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myExcludeTargets.Add('Id', $currentExcludeTargets.id) } + if ($null -ne $currentExcludeTargets.targetType) { $myExcludeTargets.Add('TargetType', $currentExcludeTargets.targetType.toString()) } + if ($myExcludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexExcludeTargets += $myExcludeTargets @@ -118,21 +137,39 @@ function Get-TargetResource } #endregion + Write-Verbose -Message "Processing IncludeTargets" $complexincludeTargets = @() foreach ($currentincludeTargets in $getValue.AdditionalProperties.includeTargets) { $myincludeTargets = @{} - if ($currentIncludeTargets.id -ne 'all_users'){ - $myIncludeTargetsDisplayName = get-MgGroup -GroupId $currentIncludeTargets.id - $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + if ($currentIncludeTargets.id -ne 'all_users') + { + try + { + $myIncludeTargetsDisplayName = Get-MgGroup -GroupId $currentIncludeTargets.id -ErrorAction Stop + $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($currentIncludeTargets.id) specified in IncludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myIncludeTargets.Add('Id', $currentIncludeTargets.id) } + if ($null -ne $currentincludeTargets.targetType) { $myincludeTargets.Add('TargetType', $currentincludeTargets.targetType.toString()) } + if ($myincludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexincludeTargets += $myincludeTargets @@ -184,6 +221,10 @@ function Set-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [System.Boolean] $IsOfficePhoneAllowed, @@ -200,12 +241,8 @@ function Set-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion + [Parameter()] [System.String] [ValidateSet('Absent', 'Present')] @@ -240,6 +277,8 @@ function Set-TargetResource $AccessTokens ) + Write-Verbose -Message "Setting the Azure AD Authentication Method Policy Voice with Id {$Id}" + #Ensure the proper dependencies are installed in the current environment. Confirm-M365DSCDependencies @@ -275,11 +314,12 @@ function Set-TargetResource if ($key -eq 'IncludeTargets') { $i = 0 - foreach ($entry in $UpdateParameters.$key){ + foreach ($entry in $UpdateParameters.$key) + { if ($entry.id -notmatch '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$|all_users') { $Filter = "Displayname eq '$($entry.id)'" | Out-String - $UpdateParameters.$key[$i].foreach('id',(Get-MgGroup -Filter $Filter).id.ToString()) + $UpdateParameters.$key[$i].foreach('id', (Get-MgGroup -Filter $Filter).id.ToString()) } $i++ } @@ -287,11 +327,12 @@ function Set-TargetResource if ($key -eq 'ExcludeTargets') { $i = 0 - foreach ($entry in $UpdateParameters.$key){ + foreach ($entry in $UpdateParameters.$key) + { if ($entry.id -notmatch '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$|all_users') { $Filter = "Displayname eq '$($entry.id)'" | Out-String - $UpdateParameters.$key[$i].foreach('id',(Get-MgGroup -Filter $Filter).id.ToString()) + $UpdateParameters.$key[$i].foreach('id', (Get-MgGroup -Filter $Filter).id.ToString()) } $i++ } @@ -320,6 +361,10 @@ function Test-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [System.Boolean] $IsOfficePhoneAllowed, @@ -336,11 +381,6 @@ function Test-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion [Parameter()] @@ -497,7 +537,7 @@ function Export-TargetResource #region resource generator code [array]$getValue = Get-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration ` -AuthenticationMethodConfigurationId Voice ` - -ErrorAction Stop | Where-Object -FilterScript {$null -ne $_.Id} + -ErrorAction Stop | Where-Object -FilterScript { $null -ne $_.Id } #endregion $i = 1 diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyX509/MSFT_AADAuthenticationMethodPolicyX509.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyX509/MSFT_AADAuthenticationMethodPolicyX509.psm1 index 865bb4f957..d6f581c647 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyX509/MSFT_AADAuthenticationMethodPolicyX509.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyX509/MSFT_AADAuthenticationMethodPolicyX509.psm1 @@ -4,6 +4,10 @@ function Get-TargetResource [OutputType([System.Collections.Hashtable])] param ( + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [Microsoft.Management.Infrastructure.CimInstance] $AuthenticationModeConfiguration, @@ -25,10 +29,6 @@ function Get-TargetResource [System.String] $State, - [Parameter(Mandatory = $true)] - [System.String] - $Id, - [Parameter()] [System.String] [ValidateSet('Absent', 'Present')] @@ -63,6 +63,8 @@ function Get-TargetResource $AccessTokens ) + Write-Verbose -Message "Getting the Azure AD Authentication Method Policy X509 with Id {$Id}" + try { $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` @@ -99,7 +101,8 @@ function Get-TargetResource #region resource generator code $complexAuthenticationModeConfiguration = @{} $complexRules = @() - if ($getValue.AdditionalProperties.authenticationModeConfiguration.rules.length -ne 0){ + if ($getValue.AdditionalProperties.authenticationModeConfiguration.rules.length -ne 0) + { foreach ($currentRules in $getValue.AdditionalProperties.authenticationModeConfiguration.rules) { $myRules = @{} @@ -150,21 +153,39 @@ function Get-TargetResource } } + Write-Verbose 'Processing ExcludeTargets' $complexExcludeTargets = @() foreach ($currentExcludeTargets in $getValue.excludeTargets) { $myExcludeTargets = @{} - if ($currentExcludeTargets.id -ne 'all_users'){ - $myExcludeTargetsDisplayName = get-MgGroup -GroupId $currentExcludeTargets.id - $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + if ($currentExcludeTargets.id -ne 'all_users') + { + try + { + $myExcludeTargetsDisplayName = Get-MgGroup -GroupId $currentExcludeTargets.id -ErrorAction Stop + $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($currentExcludeTargets.id) specified in ExcludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myExcludeTargets.Add('Id', $currentExcludeTargets.id) } + if ($null -ne $currentExcludeTargets.targetType) { $myExcludeTargets.Add('TargetType', $currentExcludeTargets.targetType.toString()) } + if ($myExcludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexExcludeTargets += $myExcludeTargets @@ -172,25 +193,44 @@ function Get-TargetResource } #endregion + Write-Verbose 'Processing IncludeTargets' $complexIncludeTargets = @() foreach ($currentIncludeTargets in $getValue.AdditionalProperties.includeTargets) { $myIncludeTargets = @{} - if ($currentIncludeTargets.id -ne 'all_users'){ - $myIncludeTargetsDisplayName = get-MgGroup -GroupId $currentIncludeTargets.id - $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + if ($currentIncludeTargets.id -ne 'all_users') + { + try + { + $myIncludeTargetsDisplayName = Get-MgGroup -GroupId $currentIncludeTargets.id -ErrorAction Stop + $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($currentIncludeTargets.id) specified in IncludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myIncludeTargets.Add('Id', $currentIncludeTargets.id) } + if ($null -ne $currentIncludeTargets.targetType) { $myIncludeTargets.Add('TargetType', $currentIncludeTargets.targetType.toString()) } + if ($null -ne $currentIncludeTargets.isRegistrationRequired) { $myIncludeTargets.Add('isRegistrationRequired', [Boolean]$currentIncludeTargets.isRegistrationRequired) } + if ($myIncludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexIncludeTargets += $myIncludeTargets @@ -243,6 +283,10 @@ function Set-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [Microsoft.Management.Infrastructure.CimInstance] $AuthenticationModeConfiguration, @@ -263,12 +307,8 @@ function Set-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion + [Parameter()] [System.String] [ValidateSet('Absent', 'Present')] @@ -303,6 +343,8 @@ function Set-TargetResource $AccessTokens ) + Write-Verbose -Message "Setting the Azure AD Authentication Method Policy X509 with Id {$Id}" + #Ensure the proper dependencies are installed in the current environment. Confirm-M365DSCDependencies @@ -379,6 +421,10 @@ function Test-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [Microsoft.Management.Infrastructure.CimInstance] $AuthenticationModeConfiguration, @@ -399,11 +445,6 @@ function Test-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion [Parameter()] @@ -560,7 +601,7 @@ function Export-TargetResource #region resource generator code [array]$getValue = Get-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration ` -AuthenticationMethodConfigurationId X509Certificate ` - -ErrorAction Stop | Where-Object -FilterScript {$null -ne $_.Id} + -ErrorAction Stop | Where-Object -FilterScript { $null -ne $_.Id } #endregion $i = 1 diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADDeviceRegistrationPolicy/MSFT_AADDeviceRegistrationPolicy.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADDeviceRegistrationPolicy/MSFT_AADDeviceRegistrationPolicy.psm1 index c6d32acefa..8fe76dc299 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADDeviceRegistrationPolicy/MSFT_AADDeviceRegistrationPolicy.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADDeviceRegistrationPolicy/MSFT_AADDeviceRegistrationPolicy.psm1 @@ -116,14 +116,40 @@ function Get-TargetResource foreach ($userId in $getValue.AzureAdJoin.AllowedToJoin.AdditionalProperties.users) { - $userInfo = Get-MgUser -UserId $userId - $AzureADAllowedToJoinUsers += $userInfo.UserPrincipalName + try + { + $userInfo = Get-MgUser -UserId $userId -ErrorAction Stop + $AzureADAllowedToJoinUsers += $userInfo.UserPrincipalName + } + catch + { + $message = "Could not find a user with id $($userId) specified in AllowedToJoin. Skipping user!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } foreach ($groupId in $getValue.AzureAdJoin.AllowedToJoin.AdditionalProperties.groups) { - $groupInfo = Get-MgGroup -GroupId $groupId - $AzureADAllowedToJoinGroups += $groupInfo.DisplayName + try + { + $groupInfo = Get-MgGroup -GroupId $groupId -ErrorAction Stop + $AzureADAllowedToJoinGroups += $groupInfo.DisplayName + } + catch + { + $message = "Could not find a group with id $($groupId) specified in AllowedToJoin. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } } @@ -140,14 +166,40 @@ function Get-TargetResource $AzureAdJoinLocalAdminsRegisteringMode = 'Selected' foreach ($userId in $getValue.AzureAdJoin.LocalAdmins.RegisteringUsers.AdditionalProperties.users) { - $userInfo = Get-MgUser -UserId $userId - $AzureAdJoinLocalAdminsRegisteringUsers += $userInfo.UserPrincipalName + try + { + $userInfo = Get-MgUser -UserId $userId -ErrorAction Stop + $AzureAdJoinLocalAdminsRegisteringUsers += $userInfo.UserPrincipalName + } + catch + { + $message = "Could not find a user with id $($userId) specified in AllowedToJoin. Skipping user!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } foreach ($groupId in $getValue.AzureAdJoin.LocalAdmins.RegisteringUsers.AdditionalProperties.groups) { - $groupInfo = Get-MgGroup -GroupId $groupId - $AzureAdJoinLocalAdminsRegisteringGroups += $groupInfo.DisplayName + try + { + $groupInfo = Get-MgGroup -GroupId $groupId -ErrorAction Stop + $AzureAdJoinLocalAdminsRegisteringGroups += $groupInfo.DisplayName + } + catch + { + $message = "Could not find a group with id $($groupId) specified in AllowedToJoin. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } } From bec06b090414751b9482fe9a8339cb4735702dec Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Tue, 19 Nov 2024 13:02:15 +0100 Subject: [PATCH 27/65] Fixing #5420 --- CHANGELOG.md | 36 ++++ .../MSFT_AADAdminConsentRequestPolicy.psm1 | 20 ++- ...thenticationMethodPolicyAuthenticator.psm1 | 167 +++++++++++++++--- ...FT_AADAuthenticationMethodPolicyEmail.psm1 | 99 ++++++++--- ...AADAuthenticationMethodPolicyExternal.psm1 | 82 ++++++--- ...FT_AADAuthenticationMethodPolicyFido2.psm1 | 103 +++++++---- ...AADAuthenticationMethodPolicyHardware.psm1 | 63 +++++-- ...MSFT_AADAuthenticationMethodPolicySms.psm1 | 99 ++++++++--- ...AADAuthenticationMethodPolicySoftware.psm1 | 96 +++++++--- ...ADAuthenticationMethodPolicyTemporary.psm1 | 103 +++++++---- ...FT_AADAuthenticationMethodPolicyVoice.psm1 | 96 +++++++--- ...SFT_AADAuthenticationMethodPolicyX509.psm1 | 89 +++++++--- .../MSFT_AADDeviceRegistrationPolicy.psm1 | 68 ++++++- 13 files changed, 847 insertions(+), 274 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 813bba0899..1e56a4eda8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,39 @@ # UNRELEASED +* AADAdminConsentRequestPolicy + * Added error handling to Group display name retrieval to prevent errors + when an assigned group no longer exists. +* AADAuthenticationMethodPolicyAuthenticator + * Added error handling to Group display name retrieval to prevent errors + when an assigned group no longer exists. +* AADAuthenticationMethodPolicyEmail + * Added error handling to Group display name retrieval to prevent errors + when an assigned group no longer exists. +* AADAuthenticationMethodPolicyExternal + * Added error handling to Group display name retrieval to prevent errors + when an assigned group no longer exists. +* AADAuthenticationMethodPolicyFido2 + * Added error handling to Group display name retrieval to prevent errors + when an assigned group no longer exists. +* AADAuthenticationMethodPolicyHardware + * Added error handling to Group display name retrieval to prevent errors + when an assigned group no longer exists. +* AADAuthenticationMethodPolicySms + * Added error handling to Group display name retrieval to prevent errors + when an assigned group no longer exists. +* AADAuthenticationMethodPolicySoftware + * Added error handling to Group display name retrieval to prevent errors + when an assigned group no longer exists. +* AADAuthenticationMethodPolicyTemporary + * Added error handling to Group display name retrieval to prevent errors + when an assigned group no longer exists. +* AADAuthenticationMethodPolicyVoice + * Added error handling to Group display name retrieval to prevent errors + when an assigned group no longer exists. +* AADAuthenticationMethodPolicyX509 + * Added error handling to Group display name retrieval to prevent errors + when an assigned group no longer exists. * AADConditionalAccessPolicy * Fixed bug where a null value was passed in the request for the excludePlatforms parameter when just values were assigned to includePlatforms, which throws an error. @@ -9,6 +42,9 @@ sessionControl parameter when there are no session controls, which throws an error. * Fixed bug where a null value was passed in the request for the applicationEnforcedRestrictions parameter when value was set to false, which throws an error. +* AADDeviceRegistrationPolicy + * Added error handling to Group display name retrieval to prevent errors + when an assigned group no longer exists. * AADRoleEligibilityScheduleRequest * Adds support for custom role assignments at app scope. * IntuneDeviceConfigurationPolicyAndroidDeviceOwner diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAdminConsentRequestPolicy/MSFT_AADAdminConsentRequestPolicy.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAdminConsentRequestPolicy/MSFT_AADAdminConsentRequestPolicy.psm1 index 682756ab41..88b9e6c5f6 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAdminConsentRequestPolicy/MSFT_AADAdminConsentRequestPolicy.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAdminConsentRequestPolicy/MSFT_AADAdminConsentRequestPolicy.psm1 @@ -97,10 +97,22 @@ function Get-TargetResource elseif ($reviewer.Query.Contains('/groups/')) { $groupId = $reviewer.Query.Split('/')[3] - $groupInfo = Get-MgGroup -GroupId $groupId - $entry = @{ - ReviewerType = 'Group' - ReviewerId = $groupInfo.DisplayName + try + { + $groupInfo = Get-MgGroup -GroupId $groupId -ErrorAction SilentlyContinue + $entry = @{ + ReviewerType = 'Group' + ReviewerId = $groupInfo.DisplayName + } + } + catch + { + $message = "Group with ID $groupId specified in Reviewers not found" + New-M365DSCLogEntry -Message $message ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue } } elseif ($reviewer.Query.Contains('directory/roleAssignments?$')) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyAuthenticator/MSFT_AADAuthenticationMethodPolicyAuthenticator.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyAuthenticator/MSFT_AADAuthenticationMethodPolicyAuthenticator.psm1 index a06f995f97..121463a947 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyAuthenticator/MSFT_AADAuthenticationMethodPolicyAuthenticator.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyAuthenticator/MSFT_AADAuthenticationMethodPolicyAuthenticator.psm1 @@ -5,6 +5,10 @@ function Get-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [Microsoft.Management.Infrastructure.CimInstance] $FeatureSettings, @@ -25,10 +29,6 @@ function Get-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, #endregion [Parameter()] @@ -65,6 +65,8 @@ function Get-TargetResource $AccessTokens ) + Write-Verbose -Message "Getting the Azure AD Authentication Method Policy with Id {$Id}" + try { $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` @@ -100,12 +102,26 @@ function Get-TargetResource #region resource generator code $complexFeatureSettings = @{} + + Write-Verbose "Processing FeatureSettings > companionAppAllowedState > excludeTarget" $complexCompanionAppAllowedState = @{} $complexExcludeTarget = @{} if ($getValue.additionalProperties.featureSettings.companionAppAllowedState.excludeTarget.id -notmatch 'all_users|00000000-0000-0000-0000-000000000000') { - $myExcludeTargetsDisplayName = Get-MgGroup -GroupId $getValue.additionalProperties.featureSettings.companionAppAllowedState.excludeTarget.id - $complexExcludeTarget.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + try + { + $myExcludeTargetsDisplayName = Get-MgGroup -GroupId $getValue.additionalProperties.featureSettings.companionAppAllowedState.excludeTarget.id -ErrorAction Stop + $complexExcludeTarget.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($getValue.additionalProperties.featureSettings.companionAppAllowedState.excludeTarget.id) specified in excludeTarget. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + } } else { @@ -118,20 +134,36 @@ function Get-TargetResource $complexExcludeTarget.Add('Id', 'all_users') } } + if ($null -ne $getValue.additionalProperties.featureSettings.companionAppAllowedState.excludeTarget.targetType) { $complexExcludeTarget.Add('TargetType', $getValue.additionalProperties.featureSettings.companionAppAllowedState.excludeTarget.targetType.toString()) } + if ($complexExcludeTarget.values.Where({ $null -ne $_ }).count -eq 0) { $complexExcludeTarget = $null } $complexCompanionAppAllowedState.Add('ExcludeTarget', $complexExcludeTarget) + + Write-Verbose "Processing FeatureSettings > companionAppAllowedState > includeTarget" $complexIncludeTarget = @{} if ($getValue.additionalProperties.featureSettings.companionAppAllowedState.includeTarget.id -notmatch 'all_users|00000000-0000-0000-0000-000000000000') { - $myIncludeTargetsDisplayName = Get-MgGroup -GroupId $getValue.additionalProperties.featureSettings.companionAppAllowedState.includeTarget.id - $complexIncludeTarget.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + try + { + $myIncludeTargetsDisplayName = Get-MgGroup -GroupId $getValue.additionalProperties.featureSettings.companionAppAllowedState.includeTarget.id -ErrorAction Stop + $complexIncludeTarget.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($getValue.additionalProperties.featureSettings.companionAppAllowedState.includeTarget.id) specified in includeTarget. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + } } else { @@ -144,31 +176,50 @@ function Get-TargetResource $complexIncludeTarget.Add('Id', 'all_users') } } + if ($null -ne $getValue.additionalProperties.featureSettings.companionAppAllowedState.includeTarget.targetType) { $complexIncludeTarget.Add('TargetType', $getValue.additionalProperties.featureSettings.companionAppAllowedState.includeTarget.targetType.toString()) } + if ($complexIncludeTarget.values.Where({ $null -ne $_ }).count -eq 0) { $complexIncludeTarget = $null } $complexCompanionAppAllowedState.Add('IncludeTarget', $complexIncludeTarget) + + Write-Verbose "Processing FeatureSettings > companionAppAllowedState > state" if ($null -ne $getValue.additionalProperties.featureSettings.companionAppAllowedState.state) { $complexCompanionAppAllowedState.Add('State', $getValue.additionalProperties.featureSettings.companionAppAllowedState.state.toString()) } + if ($complexCompanionAppAllowedState.values.Where({ $null -ne $_ }).count -eq 0) { $complexCompanionAppAllowedState = $null } + $complexFeatureSettings.Add('CompanionAppAllowedState', $complexCompanionAppAllowedState) $complexDisplayAppInformationRequiredState = @{} + Write-Verbose "Processing FeatureSettings > displayAppInformationRequiredState > excludeTarget" $complexExcludeTarget = @{} if ($getValue.additionalProperties.featureSettings.displayAppInformationRequiredState.excludeTarget.id -notmatch 'all_users|00000000-0000-0000-0000-000000000000') { - $myExcludeTargetsDisplayName = Get-MgGroup -GroupId $getValue.additionalProperties.featureSettings.displayAppInformationRequiredState.excludeTarget.id - $complexExcludeTarget.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + try + { + $myExcludeTargetsDisplayName = Get-MgGroup -GroupId $getValue.additionalProperties.featureSettings.displayAppInformationRequiredState.excludeTarget.id -ErrorAction Stop + $complexExcludeTarget.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($getValue.additionalProperties.featureSettings.displayAppInformationRequiredState.excludeTarget.id) specified in excludeTarget. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + } } else { @@ -181,6 +232,7 @@ function Get-TargetResource $complexExcludeTarget.Add('Id', 'all_users') } } + if ($null -ne $getValue.additionalProperties.featureSettings.displayAppInformationRequiredState.excludeTarget.targetType) { $complexExcludeTarget.Add('TargetType', $getValue.additionalProperties.featureSettings.displayAppInformationRequiredState.excludeTarget.targetType.toString()) @@ -190,11 +242,25 @@ function Get-TargetResource $complexExcludeTarget = $null } $complexDisplayAppInformationRequiredState.Add('ExcludeTarget', $complexExcludeTarget) + + Write-Verbose "Processing FeatureSettings > displayAppInformationRequiredState > includeTarget" $complexIncludeTarget = @{} if ($getValue.additionalProperties.featureSettings.displayAppInformationRequiredState.includeTarget.id -notmatch 'all_users|00000000-0000-0000-0000-000000000000') { - $myIncludeTargetsDisplayName = Get-MgGroup -GroupId $getValue.additionalProperties.featureSettings.displayAppInformationRequiredState.includeTarget.id - $complexIncludeTarget.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + try + { + $myIncludeTargetsDisplayName = Get-MgGroup -GroupId $getValue.additionalProperties.featureSettings.displayAppInformationRequiredState.includeTarget.id -ErrorAction Stop + $complexIncludeTarget.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($getValue.additionalProperties.featureSettings.displayAppInformationRequiredState.includeTarget.id) specified in includeTarget. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + } } else { @@ -207,30 +273,50 @@ function Get-TargetResource $complexIncludeTarget.Add('Id', 'all_users') } } + if ($null -ne $getValue.additionalProperties.featureSettings.displayAppInformationRequiredState.includeTarget.targetType) { $complexIncludeTarget.Add('TargetType', $getValue.additionalProperties.featureSettings.displayAppInformationRequiredState.includeTarget.targetType.toString()) } + if ($complexIncludeTarget.values.Where({ $null -ne $_ }).count -eq 0) { $complexIncludeTarget = $null } $complexDisplayAppInformationRequiredState.Add('IncludeTarget', $complexIncludeTarget) + + Write-Verbose "Processing FeatureSettings > displayAppInformationRequiredState > state" if ($null -ne $getValue.additionalProperties.featureSettings.displayAppInformationRequiredState.state) { $complexDisplayAppInformationRequiredState.Add('State', $getValue.additionalProperties.featureSettings.displayAppInformationRequiredState.state.toString()) } + if ($complexDisplayAppInformationRequiredState.values.Where({ $null -ne $_ }).count -eq 0) { $complexDisplayAppInformationRequiredState = $null } + $complexFeatureSettings.Add('DisplayAppInformationRequiredState', $complexDisplayAppInformationRequiredState) + + Write-Verbose "Processing FeatureSettings > displayLocationInformationRequiredState > excludeTarget" $complexDisplayLocationInformationRequiredState = @{} $complexExcludeTarget = @{} if ($getValue.additionalProperties.featureSettings.displayLocationInformationRequiredState.excludeTarget.id -notmatch 'all_users|00000000-0000-0000-0000-000000000000') { - $myExcludeTargetsDisplayName = Get-MgGroup -GroupId $getValue.additionalProperties.featureSettings.displayLocationInformationRequiredState.excludeTarget.id - $complexExcludeTarget.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + try + { + $myExcludeTargetsDisplayName = Get-MgGroup -GroupId $getValue.additionalProperties.featureSettings.displayLocationInformationRequiredState.excludeTarget.id -ErrorAction Stop + $complexExcludeTarget.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($getValue.additionalProperties.featureSettings.displayLocationInformationRequiredState.excludeTarget.id) specified in excludeTarget. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + } } else { @@ -243,20 +329,37 @@ function Get-TargetResource $complexExcludeTarget.Add('Id', 'all_users') } } + if ($null -ne $getValue.additionalProperties.featureSettings.displayLocationInformationRequiredState.excludeTarget.targetType) { $complexExcludeTarget.Add('TargetType', $getValue.additionalProperties.featureSettings.displayLocationInformationRequiredState.excludeTarget.targetType.toString()) } + if ($complexExcludeTarget.values.Where({ $null -ne $_ }).count -eq 0) { $complexExcludeTarget = $null } + $complexDisplayLocationInformationRequiredState.Add('ExcludeTarget', $complexExcludeTarget) + + Write-Verbose "Processing FeatureSettings > displayLocationInformationRequiredState > includeTarget" $complexIncludeTarget = @{} if ($getValue.additionalProperties.featureSettings.displayLocationInformationRequiredState.includeTarget.id -notmatch 'all_users|00000000-0000-0000-0000-000000000000') { - $myIncludeTargetsDisplayName = Get-MgGroup -GroupId $getValue.additionalProperties.featureSettings.displayLocationInformationRequiredState.includeTarget.id - $complexIncludeTarget.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + try + { + $myIncludeTargetsDisplayName = Get-MgGroup -GroupId $getValue.additionalProperties.featureSettings.displayLocationInformationRequiredState.includeTarget.id -ErrorAction Stop + $complexIncludeTarget.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($getValue.additionalProperties.featureSettings.displayLocationInformationRequiredState.includeTarget.id) specified in includeTarget. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + } } else { @@ -269,23 +372,30 @@ function Get-TargetResource $complexIncludeTarget.Add('Id', 'all_users') } } + if ($null -ne $getValue.additionalProperties.featureSettings.displayLocationInformationRequiredState.includeTarget.targetType) { $complexIncludeTarget.Add('TargetType', $getValue.additionalProperties.featureSettings.displayLocationInformationRequiredState.includeTarget.targetType.toString()) } + if ($complexIncludeTarget.values.Where({ $null -ne $_ }).count -eq 0) { $complexIncludeTarget = $null } + $complexDisplayLocationInformationRequiredState.Add('IncludeTarget', $complexIncludeTarget) + + Write-Verbose "Processing FeatureSettings > displayLocationInformationRequiredState > state" if ($null -ne $getValue.additionalProperties.featureSettings.displayLocationInformationRequiredState.state) { $complexDisplayLocationInformationRequiredState.Add('State', $getValue.additionalProperties.featureSettings.displayLocationInformationRequiredState.state.toString()) } + if ($complexDisplayLocationInformationRequiredState.values.Where({ $null -ne $_ }).count -eq 0) { $complexDisplayLocationInformationRequiredState = $null } + $complexFeatureSettings.Add('DisplayLocationInformationRequiredState', $complexDisplayLocationInformationRequiredState) $complexExcludeTargets = @() @@ -305,10 +415,12 @@ function Get-TargetResource { $myExcludeTargets.Add('Id', $currentExcludeTargets.id) } + if ($null -ne $currentExcludeTargets.targetType) { $myExcludeTargets.Add('TargetType', $currentExcludeTargets.targetType.toString()) } + if ($myExcludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexExcludeTargets += $myExcludeTargets @@ -332,10 +444,12 @@ function Get-TargetResource { $myIncludeTargets.Add('Id', $currentIncludeTargets.id) } + if ($null -ne $currentIncludeTargets.targetType) { $myIncludeTargets.Add('TargetType', $currentIncludeTargets.targetType.toString()) } + if ($myIncludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexIncludeTargets += $myIncludeTargets @@ -389,6 +503,10 @@ function Set-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [Microsoft.Management.Infrastructure.CimInstance] $FeatureSettings, @@ -409,12 +527,8 @@ function Set-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion + [Parameter()] [System.String] [ValidateSet('Absent', 'Present')] @@ -449,6 +563,8 @@ function Set-TargetResource $AccessTokens ) + Write-Verbose -Message "Setting the Azure AD Authentication Method Policy Authenticator with Id {$Id}" + #Ensure the proper dependencies are installed in the current environment. Confirm-M365DSCDependencies @@ -589,6 +705,10 @@ function Test-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [Microsoft.Management.Infrastructure.CimInstance] $FeatureSettings, @@ -609,11 +729,6 @@ function Test-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion [Parameter()] diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyEmail/MSFT_AADAuthenticationMethodPolicyEmail.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyEmail/MSFT_AADAuthenticationMethodPolicyEmail.psm1 index 5ceea269ca..120f294f03 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyEmail/MSFT_AADAuthenticationMethodPolicyEmail.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyEmail/MSFT_AADAuthenticationMethodPolicyEmail.psm1 @@ -5,6 +5,10 @@ function Get-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [ValidateSet('default', 'enabled', 'disabled', 'unknownFutureValue')] [System.String] @@ -22,11 +26,6 @@ function Get-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion [Parameter()] @@ -63,6 +62,8 @@ function Get-TargetResource $AccessTokens ) + Write-Verbose -Message "Getting the Azure AD Authentication Method Policy Email with Id {$Id}" + try { $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` @@ -101,17 +102,34 @@ function Get-TargetResource foreach ($currentExcludeTargets in $getValue.excludeTargets) { $myExcludeTargets = @{} - if ($currentExcludeTargets.id -ne 'all_users'){ - $myExcludeTargetsDisplayName = get-MgGroup -GroupId $currentExcludeTargets.id - $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + if ($currentExcludeTargets.id -ne 'all_users') + { + try + { + $myExcludeTargetsDisplayName = Get-MgGroup -GroupId $currentExcludeTargets.id + $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($currentExcludeTargets.id) specified in ExcludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myExcludeTargets.Add('Id', $currentExcludeTargets.id) } + if ($null -ne $currentExcludeTargets.targetType) { $myExcludeTargets.Add('TargetType', $currentExcludeTargets.targetType.toString()) } + if ($myExcludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexExcludeTargets += $myExcludeTargets @@ -130,24 +148,40 @@ function Get-TargetResource foreach ($currentincludeTargets in $getValue.AdditionalProperties.includeTargets) { $myincludeTargets = @{} - if ($currentIncludeTargets.id -ne 'all_users'){ - $myIncludeTargetsDisplayName = get-MgGroup -GroupId $currentIncludeTargets.id - $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + if ($currentIncludeTargets.id -ne 'all_users') + { + try + { + $myIncludeTargetsDisplayName = Get-MgGroup -GroupId $currentIncludeTargets.id + $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($currentIncludeTargets.id) specified in IncludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myIncludeTargets.Add('Id', $currentIncludeTargets.id) } + if ($null -ne $currentincludeTargets.targetType) { $myincludeTargets.Add('TargetType', $currentincludeTargets.targetType.toString()) } + if ($myincludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexIncludeTargets += $myincludeTargets } } - $enumState = $null if ($null -ne $getValue.State) { @@ -193,6 +227,10 @@ function Set-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [ValidateSet('default', 'enabled', 'disabled', 'unknownFutureValue')] [System.String] @@ -210,12 +248,8 @@ function Set-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion + [Parameter()] [System.String] [ValidateSet('Absent', 'Present')] @@ -250,6 +284,8 @@ function Set-TargetResource $AccessTokens ) + Write-Verbose -Message "Setting the Azure AD Authentication Method Policy Email with Id {$Id}" + #Ensure the proper dependencies are installed in the current environment. Confirm-M365DSCDependencies @@ -284,24 +320,28 @@ function Set-TargetResource } if ($key -eq 'IncludeTargets') { + Write-Verbose -Message "Processing IncludeTargets" $i = 0 - foreach ($entry in $UpdateParameters.$key){ + foreach ($entry in $UpdateParameters.$key) + { if ($entry.id -notmatch '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$|all_users') { $Filter = "Displayname eq '$($entry.id)'" | Out-String - $UpdateParameters.$key[$i].foreach('id',(Get-MgGroup -Filter $Filter).id.ToString()) + $UpdateParameters.$key[$i].foreach('id', (Get-MgGroup -Filter $Filter).id.ToString()) } $i++ } } if ($key -eq 'ExcludeTargets') { + Write-Verbose -Message "Processing ExcludeTargets" $i = 0 - foreach ($entry in $UpdateParameters.$key){ + foreach ($entry in $UpdateParameters.$key) + { if ($entry.id -notmatch '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$|all_users') { $Filter = "Displayname eq '$($entry.id)'" | Out-String - $UpdateParameters.$key[$i].foreach('id',(Get-MgGroup -Filter $Filter).id.ToString()) + $UpdateParameters.$key[$i].foreach('id', (Get-MgGroup -Filter $Filter).id.ToString()) } $i++ } @@ -330,6 +370,10 @@ function Test-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [ValidateSet('default', 'enabled', 'disabled', 'unknownFutureValue')] [System.String] @@ -347,11 +391,6 @@ function Test-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion [Parameter()] @@ -388,6 +427,8 @@ function Test-TargetResource $AccessTokens ) + Write-Verbose -Message "Testing the Azure AD Authentication Method Policy Email with Id {$Id}" + #Ensure the proper dependencies are installed in the current environment. Confirm-M365DSCDependencies @@ -508,7 +549,7 @@ function Export-TargetResource #region resource generator code [array]$getValue = Get-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration ` -AuthenticationMethodConfigurationId Email ` - -ErrorAction Stop | Where-Object -FilterScript {$null -ne $_.Id} + -ErrorAction Stop | Where-Object -FilterScript { $null -ne $_.Id } #endregion $i = 1 diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyExternal/MSFT_AADAuthenticationMethodPolicyExternal.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyExternal/MSFT_AADAuthenticationMethodPolicyExternal.psm1 index bb71db082e..ecd65ce44b 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyExternal/MSFT_AADAuthenticationMethodPolicyExternal.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyExternal/MSFT_AADAuthenticationMethodPolicyExternal.psm1 @@ -92,12 +92,12 @@ function Get-TargetResource { if ($null -ne $Script:exportedInstances -and $Script:ExportMode) { - $getValue = $Script:exportedInstances | Where-Object -FilterScript {$_.DisplayName -eq $DisplayName} + $getValue = $Script:exportedInstances | Where-Object -FilterScript { $_.DisplayName -eq $DisplayName } } else { - $response = Invoke-MgGraphRequest -Method Get -Uri ($Global:MSCloudLoginConnectionProfile.MicrosoftGraph.ResourceUrl + "beta/policies/authenticationMethodsPolicy/") - $getValue = $response.authenticationMethodConfigurations | Where-Object -FilterScript {$_.DisplayName -eq $DisplayName} + $response = Invoke-MgGraphRequest -Method Get -Uri ($Global:MSCloudLoginConnectionProfile.MicrosoftGraph.ResourceUrl + 'beta/policies/authenticationMethodsPolicy/') + $getValue = $response.authenticationMethodConfigurations | Where-Object -FilterScript { $_.DisplayName -eq $DisplayName } } } @@ -115,17 +115,34 @@ function Get-TargetResource foreach ($currentExcludeTargets in $getValue.excludeTargets) { $myExcludeTargets = @{} - if ($currentExcludeTargets.id -ne 'all_users'){ - $myExcludeTargetsDisplayName = get-MgGroup -GroupId $currentExcludeTargets.id - $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + if ($currentExcludeTargets.id -ne 'all_users') + { + try + { + $myExcludeTargetsDisplayName = Get-MgGroup -GroupId $currentExcludeTargets.id -ErrorAction Stop + $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($currentExcludeTargets.id) specified in ExcludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myExcludeTargets.Add('Id', $currentExcludeTargets.id) } + if ($null -ne $currentExcludeTargets.targetType) { $myExcludeTargets.Add('TargetType', $currentExcludeTargets.targetType.toString()) } + if ($myExcludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexExcludeTargets += $myExcludeTargets @@ -137,17 +154,34 @@ function Get-TargetResource foreach ($currentincludeTargets in $getValue.includeTargets) { $myincludeTargets = @{} - if ($currentIncludeTargets.id -ne 'all_users'){ - $myIncludeTargetsDisplayName = get-MgGroup -GroupId $currentIncludeTargets.id - $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + if ($currentIncludeTargets.id -ne 'all_users') + { + try + { + $myIncludeTargetsDisplayName = Get-MgGroup -GroupId $currentIncludeTargets.id -ErrorAction Stop + $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($currentIncludeTargets.id) specified in IncludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myIncludeTargets.Add('Id', $currentIncludeTargets.id) } + if ($null -ne $currentincludeTargets.targetType) { $myincludeTargets.Add('TargetType', $currentincludeTargets.targetType.toString()) } + if ($myincludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexincludeTargets += $myincludeTargets @@ -155,7 +189,7 @@ function Get-TargetResource } $complexOpenIdConnectSetting = @{ - clientId = $getValue.OpenIdConnectSetting.ClientId + clientId = $getValue.OpenIdConnectSetting.ClientId discoveryUrl = $getValue.OpenIdConnectSetting.DiscoveryUrl } @@ -300,8 +334,8 @@ function Set-TargetResource { Write-Verbose -Message "Updating the Azure AD Authentication Method Policy External with name {$($currentInstance.displayName)}" - $response = Invoke-MgGraphRequest -Method Get -Uri ($Global:MSCloudLoginConnectionProfile.MicrosoftGraph.ResourceUrl + "beta/policies/authenticationMethodsPolicy/") - $getValue = $response.authenticationMethodConfigurations | Where-Object -FilterScript {$_.displayName -eq $currentInstance.displayName} + $response = Invoke-MgGraphRequest -Method Get -Uri ($Global:MSCloudLoginConnectionProfile.MicrosoftGraph.ResourceUrl + 'beta/policies/authenticationMethodsPolicy/') + $getValue = $response.authenticationMethodConfigurations | Where-Object -FilterScript { $_.displayName -eq $currentInstance.displayName } $params.Remove('displayName') | Out-Null @@ -313,8 +347,8 @@ function Set-TargetResource { Write-Verbose -Message "Removing the Azure AD Authentication Method Policy External with Id {$($currentInstance.displayName)}" - $response = Invoke-MgGraphRequest -Method Get -Uri ($Global:MSCloudLoginConnectionProfile.MicrosoftGraph.ResourceUrl + "beta/policies/authenticationMethodsPolicy/") - $getValue = $response.authenticationMethodConfigurations | Where-Object -FilterScript {$_.displayName -eq $currentInstance.displayName} + $response = Invoke-MgGraphRequest -Method Get -Uri ($Global:MSCloudLoginConnectionProfile.MicrosoftGraph.ResourceUrl + 'beta/policies/authenticationMethodsPolicy/') + $getValue = $response.authenticationMethodConfigurations | Where-Object -FilterScript { $_.displayName -eq $currentInstance.displayName } Remove-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration -AuthenticationMethodConfigurationId $getValue.Id } @@ -504,9 +538,9 @@ function Export-TargetResource try { #region resource generator code - $desiredType = "#microsoft.graph.externalAuthenticationMethodConfiguration" - $getPolicy = Invoke-MgGraphRequest -Method Get -Uri ($Global:MSCloudLoginConnectionProfile.MicrosoftGraph.ResourceUrl + "beta/policies/authenticationMethodsPolicy/") - $getValue = $getPolicy.AuthenticationMethodConfigurations | Where-Object -FilterScript {$_.'@odata.type' -eq $desiredType} + $desiredType = '#microsoft.graph.externalAuthenticationMethodConfiguration' + $getPolicy = Invoke-MgGraphRequest -Method Get -Uri ($Global:MSCloudLoginConnectionProfile.MicrosoftGraph.ResourceUrl + 'beta/policies/authenticationMethodsPolicy/') + $getValue = $getPolicy.AuthenticationMethodConfigurations | Where-Object -FilterScript { $_.'@odata.type' -eq $desiredType } #endregion $i = 1 @@ -649,11 +683,12 @@ function Get-UpdatedTargetProperty if ($key -eq 'IncludeTargets') { $i = 0 - foreach ($entry in $params.$key){ + foreach ($entry in $params.$key) + { if ($entry.id -notmatch '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$|all_users') { $Filter = "Displayname eq '$($entry.id)'" | Out-String - $params.$key[$i].foreach('id',(Get-MgGroup -Filter $Filter).id.ToString()) + $params.$key[$i].foreach('id', (Get-MgGroup -Filter $Filter).id.ToString()) } $i++ } @@ -661,11 +696,12 @@ function Get-UpdatedTargetProperty if ($key -eq 'ExcludeTargets') { $i = 0 - foreach ($entry in $params.$key){ + foreach ($entry in $params.$key) + { if ($entry.id -notmatch '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$|all_users') { $Filter = "Displayname eq '$($entry.id)'" | Out-String - $params.$key[$i].foreach('id',(Get-MgGroup -Filter $Filter).id.ToString()) + $params.$key[$i].foreach('id', (Get-MgGroup -Filter $Filter).id.ToString()) } $i++ } diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyFido2/MSFT_AADAuthenticationMethodPolicyFido2.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyFido2/MSFT_AADAuthenticationMethodPolicyFido2.psm1 index a5d2268cb8..66066badf9 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyFido2/MSFT_AADAuthenticationMethodPolicyFido2.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyFido2/MSFT_AADAuthenticationMethodPolicyFido2.psm1 @@ -5,6 +5,10 @@ function Get-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [System.Boolean] $IsAttestationEnforced, @@ -29,11 +33,6 @@ function Get-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion [Parameter()] @@ -70,6 +69,8 @@ function Get-TargetResource $AccessTokens ) + Write-Verbose -Message "Getting the Azure AD Authentication Method Policy Fido2 with Id {$Id}" + try { $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` @@ -104,6 +105,7 @@ function Get-TargetResource Write-Verbose -Message "An Azure AD Authentication Method Policy Fido2 with Id {$Id} was found." #region resource generator code + Write-Verbose "Processing KeyRestrictions" $complexKeyRestrictions = @{} $complexKeyRestrictions.Add('AaGuids', $getValue.AdditionalProperties.keyRestrictions.aaGuids) if ($null -ne $getValue.AdditionalProperties.keyRestrictions.enforcementType) @@ -116,21 +118,39 @@ function Get-TargetResource $complexKeyRestrictions = $null } + Write-Verbose "Processing ExcludeTargets" $complexExcludeTargets = @() foreach ($currentExcludeTargets in $getValue.excludeTargets) { $myExcludeTargets = @{} - if ($currentExcludeTargets.id -ne 'all_users'){ - $myExcludeTargetsDisplayName = get-MgGroup -GroupId $currentExcludeTargets.id - $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + if ($currentExcludeTargets.id -ne 'all_users') + { + try + { + $myExcludeTargetsDisplayName = Get-MgGroup -GroupId $currentExcludeTargets.id -ErrorAction Stop + $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($currentExcludeTargets.id) specified in ExcludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myExcludeTargets.Add('Id', $currentExcludeTargets.id) } + if ($null -ne $currentExcludeTargets.targetType) { $myExcludeTargets.Add('TargetType', $currentExcludeTargets.targetType.toString()) } + if ($myExcludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexExcludeTargets += $myExcludeTargets @@ -138,24 +158,42 @@ function Get-TargetResource } #endregion - $CoomplexIncludeTargets = @() + Write-Verbose "Processing IncludeTargets" + $complexIncludeTargets = @() foreach ($currentIncludeTargets in $getValue.AdditionalProperties.includeTargets) { $myIncludeTargets = @{} - if ($currentIncludeTargets.id -ne 'all_users'){ - $myIncludeTargetsDisplayName = get-MgGroup -GroupId $currentIncludeTargets.id - $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + if ($currentIncludeTargets.id -ne 'all_users') + { + try + { + $myIncludeTargetsDisplayName = Get-MgGroup -GroupId $currentIncludeTargets.id -ErrorAction Stop + $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($currentIncludeTargets.id) specified in IncludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myIncludeTargets.Add('Id', $currentIncludeTargets.id) } + if ($null -ne $currentIncludeTargets.targetType) { $myIncludeTargets.Add('TargetType', $currentIncludeTargets.targetType.toString()) } + if ($myIncludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { - $CoomplexIncludeTargets += $myIncludeTargets + $complexIncludeTargets += $myIncludeTargets } } @@ -173,7 +211,7 @@ function Get-TargetResource IsSelfServiceRegistrationAllowed = $getValue.AdditionalProperties.isSelfServiceRegistrationAllowed KeyRestrictions = $complexKeyRestrictions ExcludeTargets = $complexExcludeTargets - IncludeTargets = $CoomplexIncludeTargets + IncludeTargets = $complexIncludeTargets State = $enumState Id = $getValue.Id Ensure = 'Present' @@ -207,6 +245,10 @@ function Set-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [System.Boolean] $IsAttestationEnforced, @@ -231,12 +273,8 @@ function Set-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion + [Parameter()] [System.String] [ValidateSet('Absent', 'Present')] @@ -271,6 +309,8 @@ function Set-TargetResource $AccessTokens ) + Write-Verbose -Message "Setting the Azure AD Authentication Method Policy Fido2 with Id {$Id}" + #Ensure the proper dependencies are installed in the current environment. Confirm-M365DSCDependencies @@ -306,11 +346,12 @@ function Set-TargetResource if ($key -eq 'IncludeTargets') { $i = 0 - foreach ($entry in $UpdateParameters.$key){ + foreach ($entry in $UpdateParameters.$key) + { if ($entry.id -notmatch '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$|all_users') { $Filter = "Displayname eq '$($entry.id)'" | Out-String - $UpdateParameters.$key[$i].foreach('id',(Get-MgGroup -Filter $Filter).id.ToString()) + $UpdateParameters.$key[$i].foreach('id', (Get-MgGroup -Filter $Filter).id.ToString()) } $i++ } @@ -318,11 +359,12 @@ function Set-TargetResource if ($key -eq 'ExcludeTargets') { $i = 0 - foreach ($entry in $UpdateParameters.$key){ + foreach ($entry in $UpdateParameters.$key) + { if ($entry.id -notmatch '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$|all_users') { $Filter = "Displayname eq '$($entry.id)'" | Out-String - $UpdateParameters.$key[$i].foreach('id',(Get-MgGroup -Filter $Filter).id.ToString()) + $UpdateParameters.$key[$i].foreach('id', (Get-MgGroup -Filter $Filter).id.ToString()) } $i++ } @@ -351,6 +393,10 @@ function Test-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [System.Boolean] $IsAttestationEnforced, @@ -375,11 +421,6 @@ function Test-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion [Parameter()] @@ -536,7 +577,7 @@ function Export-TargetResource #region resource generator code [array]$getValue = Get-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration ` -AuthenticationMethodConfigurationId Fido2 ` - -ErrorAction Stop | Where-Object -FilterScript {$null -ne $_.Id} + -ErrorAction Stop | Where-Object -FilterScript { $null -ne $_.Id } #endregion $i = 1 diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyHardware/MSFT_AADAuthenticationMethodPolicyHardware.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyHardware/MSFT_AADAuthenticationMethodPolicyHardware.psm1 index 30be7f9089..d49a0965bc 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyHardware/MSFT_AADAuthenticationMethodPolicyHardware.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyHardware/MSFT_AADAuthenticationMethodPolicyHardware.psm1 @@ -96,17 +96,34 @@ function Get-TargetResource foreach ($currentExcludeTargets in $getValue.excludeTargets) { $myExcludeTargets = @{} - if ($currentExcludeTargets.id -ne 'all_users'){ - $myExcludeTargetsDisplayName = get-MgGroup -GroupId $currentExcludeTargets.id - $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + if ($currentExcludeTargets.id -ne 'all_users') + { + try + { + $myExcludeTargetsDisplayName = Get-MgGroup -GroupId $currentExcludeTargets.id -ErrorAction Stop + $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($currentExcludeTargets.id) specified in ExcludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myExcludeTargets.Add('Id', $currentExcludeTargets.id) } + if ($null -ne $currentExcludeTargets.targetType) { $myExcludeTargets.Add('TargetType', $currentExcludeTargets.targetType.toString()) } + if ($myExcludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexExcludeTargets += $myExcludeTargets @@ -118,17 +135,35 @@ function Get-TargetResource foreach ($currentincludeTargets in $getValue.AdditionalProperties.includeTargets) { $myincludeTargets = @{} - if ($currentIncludeTargets.id -ne 'all_users'){ - $myIncludeTargetsDisplayName = get-MgGroup -GroupId $currentIncludeTargets.id - $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + if ($currentIncludeTargets.id -ne 'all_users') + { + try + { + $myIncludeTargetsDisplayName = Get-MgGroup -GroupId $currentIncludeTargets.id -ErrorAction Stop + $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + + } + catch + { + $message = "Could not find a group with id $($currentIncludeTargets.id) specified in IncludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myIncludeTargets.Add('Id', $currentIncludeTargets.id) } + if ($null -ne $currentincludeTargets.targetType) { $myincludeTargets.Add('TargetType', $currentincludeTargets.targetType.toString()) } + if ($myincludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexincludeTargets += $myincludeTargets @@ -266,11 +301,12 @@ function Set-TargetResource if ($key -eq 'IncludeTargets') { $i = 0 - foreach ($entry in $UpdateParameters.$key){ + foreach ($entry in $UpdateParameters.$key) + { if ($entry.id -notmatch '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$|all_users') { $Filter = "Displayname eq '$($entry.id)'" | Out-String - $UpdateParameters.$key[$i].foreach('id',(Get-MgGroup -Filter $Filter).id.ToString()) + $UpdateParameters.$key[$i].foreach('id', (Get-MgGroup -Filter $Filter).id.ToString()) } $i++ } @@ -278,11 +314,12 @@ function Set-TargetResource if ($key -eq 'ExcludeTargets') { $i = 0 - foreach ($entry in $UpdateParameters.$key){ + foreach ($entry in $UpdateParameters.$key) + { if ($entry.id -notmatch '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$|all_users') { $Filter = "Displayname eq '$($entry.id)'" | Out-String - $UpdateParameters.$key[$i].foreach('id',(Get-MgGroup -Filter $Filter).id.ToString()) + $UpdateParameters.$key[$i].foreach('id', (Get-MgGroup -Filter $Filter).id.ToString()) } $i++ } @@ -484,7 +521,7 @@ function Export-TargetResource #region resource generator code [array]$getValue = Get-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration ` -AuthenticationMethodConfigurationId HardwareOath ` - -ErrorAction Stop | Where-Object -FilterScript {$null -ne $_.Id} + -ErrorAction Stop | Where-Object -FilterScript { $null -ne $_.Id } #endregion $i = 1 diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicySms/MSFT_AADAuthenticationMethodPolicySms.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicySms/MSFT_AADAuthenticationMethodPolicySms.psm1 index c04894b025..f0cc33f024 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicySms/MSFT_AADAuthenticationMethodPolicySms.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicySms/MSFT_AADAuthenticationMethodPolicySms.psm1 @@ -5,6 +5,10 @@ function Get-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [Microsoft.Management.Infrastructure.CimInstance[]] $ExcludeTargets, @@ -17,11 +21,6 @@ function Get-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion [Parameter()] @@ -58,6 +57,8 @@ function Get-TargetResource $AccessTokens ) + Write-Verbose -Message "Getting the Azure AD Authentication Method Policy Sms with Id {$Id}" + try { $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` @@ -92,21 +93,39 @@ function Get-TargetResource Write-Verbose -Message "An Azure AD Authentication Method Policy Sms with Id {$Id} was found." #region resource generator code + Write-Verbose -Message "Processing ExcludeTargets" $complexExcludeTargets = @() foreach ($currentExcludeTargets in $getValue.excludeTargets) { $myExcludeTargets = @{} - if ($currentExcludeTargets.id -ne 'all_users'){ - $myExcludeTargetsDisplayName = get-MgGroup -GroupId $currentExcludeTargets.id - $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + if ($currentExcludeTargets.id -ne 'all_users') + { + try + { + $myExcludeTargetsDisplayName = Get-MgGroup -GroupId $currentExcludeTargets.id -ErrorAction Stop + $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($currentExcludeTargets.id) specified in ExcludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myExcludeTargets.Add('Id', $currentExcludeTargets.id) } + if ($null -ne $currentExcludeTargets.targetType) { $myExcludeTargets.Add('TargetType', $currentExcludeTargets.targetType.toString()) } + if ($myExcludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexExcludeTargets += $myExcludeTargets @@ -114,21 +133,40 @@ function Get-TargetResource } #endregion + Write-Verbose -Message "Processing IncludeTargets" $complexincludeTargets = @() foreach ($currentincludeTargets in $getValue.AdditionalProperties.includeTargets) { $myincludeTargets = @{} - if ($currentIncludeTargets.id -ne 'all_users'){ - $myIncludeTargetsDisplayName = get-MgGroup -GroupId $currentIncludeTargets.id - $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + if ($currentIncludeTargets.id -ne 'all_users') + { + try + { + $myIncludeTargetsDisplayName = Get-MgGroup -GroupId $currentIncludeTargets.id -ErrorAction Stop + $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + + } + catch + { + $message = "Could not find a group with id $($currentIncludeTargets.id) specified in IncludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myIncludeTargets.Add('Id', $currentIncludeTargets.id) } + if ($null -ne $currentincludeTargets.targetType) { $myincludeTargets.Add('TargetType', $currentincludeTargets.targetType.toString()) } + if ($myincludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexincludeTargets += $myincludeTargets @@ -179,6 +217,10 @@ function Set-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [Microsoft.Management.Infrastructure.CimInstance[]] $ExcludeTargets, @@ -191,12 +233,8 @@ function Set-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion + [Parameter()] [System.String] [ValidateSet('Absent', 'Present')] @@ -231,6 +269,8 @@ function Set-TargetResource $AccessTokens ) + Write-Verbose -Message "Setting the Azure AD Authentication Method Policy Fido2 with Id {$Id}" + #Ensure the proper dependencies are installed in the current environment. Confirm-M365DSCDependencies @@ -266,11 +306,12 @@ function Set-TargetResource if ($key -eq 'IncludeTargets') { $i = 0 - foreach ($entry in $UpdateParameters.$key){ + foreach ($entry in $UpdateParameters.$key) + { if ($entry.id -notmatch '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$|all_users') { $Filter = "Displayname eq '$($entry.id)'" | Out-String - $UpdateParameters.$key[$i].foreach('id',(Get-MgGroup -Filter $Filter).id.ToString()) + $UpdateParameters.$key[$i].foreach('id', (Get-MgGroup -Filter $Filter).id.ToString()) } $i++ } @@ -278,11 +319,12 @@ function Set-TargetResource if ($key -eq 'ExcludeTargets') { $i = 0 - foreach ($entry in $UpdateParameters.$key){ + foreach ($entry in $UpdateParameters.$key) + { if ($entry.id -notmatch '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$|all_users') { $Filter = "Displayname eq '$($entry.id)'" | Out-String - $UpdateParameters.$key[$i].foreach('id',(Get-MgGroup -Filter $Filter).id.ToString()) + $UpdateParameters.$key[$i].foreach('id', (Get-MgGroup -Filter $Filter).id.ToString()) } $i++ } @@ -311,6 +353,10 @@ function Test-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [Microsoft.Management.Infrastructure.CimInstance[]] $ExcludeTargets, @@ -323,11 +369,6 @@ function Test-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion [Parameter()] @@ -484,7 +525,7 @@ function Export-TargetResource #region resource generator code [array]$getValue = Get-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration ` -AuthenticationMethodConfigurationId sms ` - -ErrorAction Stop | Where-Object -FilterScript {$null -ne $_.Id} + -ErrorAction Stop | Where-Object -FilterScript { $null -ne $_.Id } #endregion $i = 1 @@ -536,7 +577,7 @@ function Export-TargetResource } } - if($null -ne $Results.IncludeTargets) + if ($null -ne $Results.IncludeTargets) { $complexTypeStringResult = Get-M365DSCDRGComplexTypeToString ` -ComplexObject $Results.IncludeTargets ` diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicySoftware/MSFT_AADAuthenticationMethodPolicySoftware.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicySoftware/MSFT_AADAuthenticationMethodPolicySoftware.psm1 index a169bdd262..5d5ab861f5 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicySoftware/MSFT_AADAuthenticationMethodPolicySoftware.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicySoftware/MSFT_AADAuthenticationMethodPolicySoftware.psm1 @@ -5,6 +5,10 @@ function Get-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [Microsoft.Management.Infrastructure.CimInstance[]] $ExcludeTargets, @@ -17,11 +21,6 @@ function Get-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion [Parameter()] @@ -58,6 +57,8 @@ function Get-TargetResource $AccessTokens ) + Write-Verbose -Message "Getting the Azure AD Authentication Method Policy Software with Id {$Id}" + try { $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` @@ -92,21 +93,39 @@ function Get-TargetResource Write-Verbose -Message "An Azure AD Authentication Method Policy Software with Id {$Id} was found." #region resource generator code + Write-Verbose -Message "Processing ExcludeTargets" $complexExcludeTargets = @() foreach ($currentExcludeTargets in $getValue.excludeTargets) { $myExcludeTargets = @{} - if ($currentExcludeTargets.id -ne 'all_users'){ - $myExcludeTargetsDisplayName = get-MgGroup -GroupId $currentExcludeTargets.id - $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + if ($currentExcludeTargets.id -ne 'all_users') + { + try + { + $myExcludeTargetsDisplayName = Get-MgGroup -GroupId $currentExcludeTargets.id -ErrorAction Stop + $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($currentExcludeTargets.id) specified in ExcludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myExcludeTargets.Add('Id', $currentExcludeTargets.id) } + if ($null -ne $currentExcludeTargets.targetType) { $myExcludeTargets.Add('TargetType', $currentExcludeTargets.targetType.toString()) } + if ($myExcludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexExcludeTargets += $myExcludeTargets @@ -114,21 +133,39 @@ function Get-TargetResource } #endregion + Write-Verbose -Message "Processing IncludeTargets" $complexincludeTargets = @() foreach ($currentincludeTargets in $getValue.AdditionalProperties.includeTargets) { $myincludeTargets = @{} - if ($currentIncludeTargets.id -ne 'all_users'){ - $myIncludeTargetsDisplayName = get-MgGroup -GroupId $currentIncludeTargets.id - $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + if ($currentIncludeTargets.id -ne 'all_users') + { + try + { + $myIncludeTargetsDisplayName = Get-MgGroup -GroupId $currentIncludeTargets.id -ErrorAction Stop + $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($currentIncludeTargets.id) specified in IncludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myIncludeTargets.Add('Id', $currentIncludeTargets.id) } + if ($null -ne $currentincludeTargets.targetType) { $myincludeTargets.Add('TargetType', $currentincludeTargets.targetType.toString()) } + if ($myincludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexincludeTargets += $myincludeTargets @@ -179,6 +216,10 @@ function Set-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [Microsoft.Management.Infrastructure.CimInstance[]] $ExcludeTargets, @@ -191,12 +232,8 @@ function Set-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion + [Parameter()] [System.String] [ValidateSet('Absent', 'Present')] @@ -231,6 +268,8 @@ function Set-TargetResource $AccessTokens ) + Write-Verbose -Message "Setting the Azure AD Authentication Method Policy Software with Id {$Id}" + #Ensure the proper dependencies are installed in the current environment. Confirm-M365DSCDependencies @@ -266,11 +305,12 @@ function Set-TargetResource if ($key -eq 'IncludeTargets') { $i = 0 - foreach ($entry in $UpdateParameters.$key){ + foreach ($entry in $UpdateParameters.$key) + { if ($entry.id -notmatch '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$|all_users') { $Filter = "Displayname eq '$($entry.id)'" | Out-String - $UpdateParameters.$key[$i].foreach('id',(Get-MgGroup -Filter $Filter).id.ToString()) + $UpdateParameters.$key[$i].foreach('id', (Get-MgGroup -Filter $Filter).id.ToString()) } $i++ } @@ -278,11 +318,12 @@ function Set-TargetResource if ($key -eq 'ExcludeTargets') { $i = 0 - foreach ($entry in $UpdateParameters.$key){ + foreach ($entry in $UpdateParameters.$key) + { if ($entry.id -notmatch '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$|all_users') { $Filter = "Displayname eq '$($entry.id)'" | Out-String - $UpdateParameters.$key[$i].foreach('id',(Get-MgGroup -Filter $Filter).id.ToString()) + $UpdateParameters.$key[$i].foreach('id', (Get-MgGroup -Filter $Filter).id.ToString()) } $i++ } @@ -311,6 +352,10 @@ function Test-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [Microsoft.Management.Infrastructure.CimInstance[]] $ExcludeTargets, @@ -323,11 +368,6 @@ function Test-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion [Parameter()] @@ -484,7 +524,7 @@ function Export-TargetResource #region resource generator code [array]$getValue = Get-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration ` -AuthenticationMethodConfigurationId SoftwareOath ` - -ErrorAction Stop | Where-Object -FilterScript {$null -ne $_.Id} + -ErrorAction Stop | Where-Object -FilterScript { $null -ne $_.Id } #endregion $i = 1 diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyTemporary/MSFT_AADAuthenticationMethodPolicyTemporary.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyTemporary/MSFT_AADAuthenticationMethodPolicyTemporary.psm1 index 1a70718259..afbb27114f 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyTemporary/MSFT_AADAuthenticationMethodPolicyTemporary.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyTemporary/MSFT_AADAuthenticationMethodPolicyTemporary.psm1 @@ -5,6 +5,10 @@ function Get-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [System.Int32] $DefaultLength, @@ -37,11 +41,6 @@ function Get-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion [Parameter()] @@ -78,6 +77,8 @@ function Get-TargetResource $AccessTokens ) + Write-Verbose -Message "Getting the Azure AD Authentication Method Policy Temporary with Id {$Id}" + try { $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` @@ -105,29 +106,47 @@ function Get-TargetResource #endregion if ($null -eq $getValue) { - Write-Verbose -Message "Could not find an Azure AD Authentication Method Policy Temporary" + Write-Verbose -Message 'Could not find an Azure AD Authentication Method Policy Temporary' return $nullResult } $Id = $getValue.Id Write-Verbose -Message "An Azure AD Authentication Method Policy Temporary with Id {$($currentExcludeTargets.id))} was found." #region resource generator code + Write-Verbose -Message "Processing ExcludeTargets" $complexExcludeTargets = @() foreach ($currentExcludeTargets in $getValue.excludeTargets) { Write-Verbose -Message "Retrieving ExcludeTarget {$currentExcludeTargets}" $myExcludeTargets = @{} - if ($currentExcludeTargets.id -ne 'all_users'){ - $myExcludeTargetsDisplayName = get-MgGroup -GroupId $currentExcludeTargets.id - $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + if ($currentExcludeTargets.id -ne 'all_users') + { + try + { + $myExcludeTargetsDisplayName = Get-MgGroup -GroupId $currentExcludeTargets.id -ErrorAction Stop + $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($currentExcludeTargets.id) specified in ExcludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myExcludeTargets.Add('Id', $currentExcludeTargets.id) } + if ($null -ne $currentExcludeTargets.targetType) { $myExcludeTargets.Add('TargetType', $currentExcludeTargets.targetType.toString()) } + if ($myExcludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexExcludeTargets += $myExcludeTargets @@ -135,27 +154,46 @@ function Get-TargetResource } #endregion + Write-Verbose -Message "Processing IncludeTargets" $complexincludeTargets = @() foreach ($currentincludeTargets in $getValue.AdditionalProperties.includeTargets) { Write-Verbose -Message "Retrieving IncludeTarget {$($currentincludeTargets.id)}" $myincludeTargets = @{} - if ($currentIncludeTargets.id -ne 'all_users'){ - $myIncludeTargetsDisplayName = get-MgGroup -GroupId $currentIncludeTargets.id - $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + if ($currentIncludeTargets.id -ne 'all_users') + { + try + { + $myIncludeTargetsDisplayName = Get-MgGroup -GroupId $currentIncludeTargets.id -ErrorAction Stop + $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($currentIncludeTargets.id) specified in IncludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myIncludeTargets.Add('Id', $currentIncludeTargets.id) } + if ($null -ne $currentincludeTargets.targetType) { $myincludeTargets.Add('TargetType', $currentincludeTargets.targetType.toString()) } + if ($myincludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexincludeTargets += $myincludeTargets } } + #region resource generator code $enumState = $null if ($null -ne $getValue.State) @@ -164,7 +202,7 @@ function Get-TargetResource } #endregion - Write-Verbose -Message "Get-TargetResource returned values" + Write-Verbose -Message 'Get-TargetResource returned values' $results = @{ #region resource generator code DefaultLength = $getValue.AdditionalProperties.defaultLength @@ -207,6 +245,10 @@ function Set-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [System.Int32] $DefaultLength, @@ -239,12 +281,8 @@ function Set-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion + [Parameter()] [System.String] [ValidateSet('Absent', 'Present')] @@ -279,6 +317,8 @@ function Set-TargetResource $AccessTokens ) + Write-Verbose -Message "Setting the Azure AD Authentication Method Policy Temporary with Id {$Id}" + #Ensure the proper dependencies are installed in the current environment. Confirm-M365DSCDependencies @@ -314,11 +354,12 @@ function Set-TargetResource if ($key -eq 'IncludeTargets') { $i = 0 - foreach ($entry in $UpdateParameters.$key){ + foreach ($entry in $UpdateParameters.$key) + { if ($entry.id -notmatch '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$|all_users') { $Filter = "Displayname eq '$($entry.id)'" | Out-String - $UpdateParameters.$key[$i].foreach('id',(Get-MgGroup -Filter $Filter).id.ToString()) + $UpdateParameters.$key[$i].foreach('id', (Get-MgGroup -Filter $Filter).id.ToString()) } $i++ } @@ -326,11 +367,12 @@ function Set-TargetResource if ($key -eq 'ExcludeTargets') { $i = 0 - foreach ($entry in $UpdateParameters.$key){ + foreach ($entry in $UpdateParameters.$key) + { if ($entry.id -notmatch '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$|all_users') { $Filter = "Displayname eq '$($entry.id)'" | Out-String - $UpdateParameters.$key[$i].foreach('id',(Get-MgGroup -Filter $Filter).id.ToString()) + $UpdateParameters.$key[$i].foreach('id', (Get-MgGroup -Filter $Filter).id.ToString()) } $i++ } @@ -359,6 +401,10 @@ function Test-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [System.Int32] $DefaultLength, @@ -391,11 +437,6 @@ function Test-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion [Parameter()] @@ -457,7 +498,7 @@ function Test-TargetResource $testResult = $true #Compare Cim instances - Write-Verbose -Message "Evaluating keys" + Write-Verbose -Message 'Evaluating keys' foreach ($key in $PSBoundParameters.Keys) { $source = $PSBoundParameters.$key @@ -553,7 +594,7 @@ function Export-TargetResource #region resource generator code [array]$getValue = Get-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration ` -AuthenticationMethodConfigurationId TemporaryAccessPass ` - -ErrorAction Stop | Where-Object -FilterScript {$null -ne $_.Id} + -ErrorAction Stop | Where-Object -FilterScript { $null -ne $_.Id } #endregion $i = 1 diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyVoice/MSFT_AADAuthenticationMethodPolicyVoice.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyVoice/MSFT_AADAuthenticationMethodPolicyVoice.psm1 index de6206c2d9..c74b6b96e1 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyVoice/MSFT_AADAuthenticationMethodPolicyVoice.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyVoice/MSFT_AADAuthenticationMethodPolicyVoice.psm1 @@ -5,6 +5,10 @@ function Get-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [System.Boolean] $IsOfficePhoneAllowed, @@ -21,11 +25,6 @@ function Get-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion [Parameter()] @@ -62,6 +61,8 @@ function Get-TargetResource $AccessTokens ) + Write-Verbose -Message "Getting the Azure AD Authentication Method Policy Voice with Id {$Id}" + try { $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` @@ -96,21 +97,39 @@ function Get-TargetResource Write-Verbose -Message "An Azure AD Authentication Method Policy Voice with Id {$Id} was found." #region resource generator code + Write-Verbose -Message "Processing ExcludeTargets" $complexExcludeTargets = @() foreach ($currentExcludeTargets in $getValue.excludeTargets) { $myExcludeTargets = @{} - if ($currentExcludeTargets.id -ne 'all_users'){ - $myExcludeTargetsDisplayName = get-MgGroup -GroupId $currentExcludeTargets.id - $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + if ($currentExcludeTargets.id -ne 'all_users') + { + try + { + $myExcludeTargetsDisplayName = Get-MgGroup -GroupId $currentExcludeTargets.id -ErrorAction Stop + $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($currentExcludeTargets.id) specified in ExcludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myExcludeTargets.Add('Id', $currentExcludeTargets.id) } + if ($null -ne $currentExcludeTargets.targetType) { $myExcludeTargets.Add('TargetType', $currentExcludeTargets.targetType.toString()) } + if ($myExcludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexExcludeTargets += $myExcludeTargets @@ -118,21 +137,39 @@ function Get-TargetResource } #endregion + Write-Verbose -Message "Processing IncludeTargets" $complexincludeTargets = @() foreach ($currentincludeTargets in $getValue.AdditionalProperties.includeTargets) { $myincludeTargets = @{} - if ($currentIncludeTargets.id -ne 'all_users'){ - $myIncludeTargetsDisplayName = get-MgGroup -GroupId $currentIncludeTargets.id - $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + if ($currentIncludeTargets.id -ne 'all_users') + { + try + { + $myIncludeTargetsDisplayName = Get-MgGroup -GroupId $currentIncludeTargets.id -ErrorAction Stop + $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($currentIncludeTargets.id) specified in IncludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myIncludeTargets.Add('Id', $currentIncludeTargets.id) } + if ($null -ne $currentincludeTargets.targetType) { $myincludeTargets.Add('TargetType', $currentincludeTargets.targetType.toString()) } + if ($myincludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexincludeTargets += $myincludeTargets @@ -184,6 +221,10 @@ function Set-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [System.Boolean] $IsOfficePhoneAllowed, @@ -200,12 +241,8 @@ function Set-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion + [Parameter()] [System.String] [ValidateSet('Absent', 'Present')] @@ -240,6 +277,8 @@ function Set-TargetResource $AccessTokens ) + Write-Verbose -Message "Setting the Azure AD Authentication Method Policy Voice with Id {$Id}" + #Ensure the proper dependencies are installed in the current environment. Confirm-M365DSCDependencies @@ -275,11 +314,12 @@ function Set-TargetResource if ($key -eq 'IncludeTargets') { $i = 0 - foreach ($entry in $UpdateParameters.$key){ + foreach ($entry in $UpdateParameters.$key) + { if ($entry.id -notmatch '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$|all_users') { $Filter = "Displayname eq '$($entry.id)'" | Out-String - $UpdateParameters.$key[$i].foreach('id',(Get-MgGroup -Filter $Filter).id.ToString()) + $UpdateParameters.$key[$i].foreach('id', (Get-MgGroup -Filter $Filter).id.ToString()) } $i++ } @@ -287,11 +327,12 @@ function Set-TargetResource if ($key -eq 'ExcludeTargets') { $i = 0 - foreach ($entry in $UpdateParameters.$key){ + foreach ($entry in $UpdateParameters.$key) + { if ($entry.id -notmatch '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$|all_users') { $Filter = "Displayname eq '$($entry.id)'" | Out-String - $UpdateParameters.$key[$i].foreach('id',(Get-MgGroup -Filter $Filter).id.ToString()) + $UpdateParameters.$key[$i].foreach('id', (Get-MgGroup -Filter $Filter).id.ToString()) } $i++ } @@ -320,6 +361,10 @@ function Test-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [System.Boolean] $IsOfficePhoneAllowed, @@ -336,11 +381,6 @@ function Test-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion [Parameter()] @@ -497,7 +537,7 @@ function Export-TargetResource #region resource generator code [array]$getValue = Get-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration ` -AuthenticationMethodConfigurationId Voice ` - -ErrorAction Stop | Where-Object -FilterScript {$null -ne $_.Id} + -ErrorAction Stop | Where-Object -FilterScript { $null -ne $_.Id } #endregion $i = 1 diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyX509/MSFT_AADAuthenticationMethodPolicyX509.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyX509/MSFT_AADAuthenticationMethodPolicyX509.psm1 index 865bb4f957..d6f581c647 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyX509/MSFT_AADAuthenticationMethodPolicyX509.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyX509/MSFT_AADAuthenticationMethodPolicyX509.psm1 @@ -4,6 +4,10 @@ function Get-TargetResource [OutputType([System.Collections.Hashtable])] param ( + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [Microsoft.Management.Infrastructure.CimInstance] $AuthenticationModeConfiguration, @@ -25,10 +29,6 @@ function Get-TargetResource [System.String] $State, - [Parameter(Mandatory = $true)] - [System.String] - $Id, - [Parameter()] [System.String] [ValidateSet('Absent', 'Present')] @@ -63,6 +63,8 @@ function Get-TargetResource $AccessTokens ) + Write-Verbose -Message "Getting the Azure AD Authentication Method Policy X509 with Id {$Id}" + try { $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` @@ -99,7 +101,8 @@ function Get-TargetResource #region resource generator code $complexAuthenticationModeConfiguration = @{} $complexRules = @() - if ($getValue.AdditionalProperties.authenticationModeConfiguration.rules.length -ne 0){ + if ($getValue.AdditionalProperties.authenticationModeConfiguration.rules.length -ne 0) + { foreach ($currentRules in $getValue.AdditionalProperties.authenticationModeConfiguration.rules) { $myRules = @{} @@ -150,21 +153,39 @@ function Get-TargetResource } } + Write-Verbose 'Processing ExcludeTargets' $complexExcludeTargets = @() foreach ($currentExcludeTargets in $getValue.excludeTargets) { $myExcludeTargets = @{} - if ($currentExcludeTargets.id -ne 'all_users'){ - $myExcludeTargetsDisplayName = get-MgGroup -GroupId $currentExcludeTargets.id - $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + if ($currentExcludeTargets.id -ne 'all_users') + { + try + { + $myExcludeTargetsDisplayName = Get-MgGroup -GroupId $currentExcludeTargets.id -ErrorAction Stop + $myExcludeTargets.Add('Id', $myExcludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($currentExcludeTargets.id) specified in ExcludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myExcludeTargets.Add('Id', $currentExcludeTargets.id) } + if ($null -ne $currentExcludeTargets.targetType) { $myExcludeTargets.Add('TargetType', $currentExcludeTargets.targetType.toString()) } + if ($myExcludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexExcludeTargets += $myExcludeTargets @@ -172,25 +193,44 @@ function Get-TargetResource } #endregion + Write-Verbose 'Processing IncludeTargets' $complexIncludeTargets = @() foreach ($currentIncludeTargets in $getValue.AdditionalProperties.includeTargets) { $myIncludeTargets = @{} - if ($currentIncludeTargets.id -ne 'all_users'){ - $myIncludeTargetsDisplayName = get-MgGroup -GroupId $currentIncludeTargets.id - $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + if ($currentIncludeTargets.id -ne 'all_users') + { + try + { + $myIncludeTargetsDisplayName = Get-MgGroup -GroupId $currentIncludeTargets.id -ErrorAction Stop + $myIncludeTargets.Add('Id', $myIncludeTargetsDisplayName.DisplayName) + } + catch + { + $message = "Could not find a group with id $($currentIncludeTargets.id) specified in IncludeTargets. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } - else{ + else + { $myIncludeTargets.Add('Id', $currentIncludeTargets.id) } + if ($null -ne $currentIncludeTargets.targetType) { $myIncludeTargets.Add('TargetType', $currentIncludeTargets.targetType.toString()) } + if ($null -ne $currentIncludeTargets.isRegistrationRequired) { $myIncludeTargets.Add('isRegistrationRequired', [Boolean]$currentIncludeTargets.isRegistrationRequired) } + if ($myIncludeTargets.values.Where({ $null -ne $_ }).count -gt 0) { $complexIncludeTargets += $myIncludeTargets @@ -243,6 +283,10 @@ function Set-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [Microsoft.Management.Infrastructure.CimInstance] $AuthenticationModeConfiguration, @@ -263,12 +307,8 @@ function Set-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion + [Parameter()] [System.String] [ValidateSet('Absent', 'Present')] @@ -303,6 +343,8 @@ function Set-TargetResource $AccessTokens ) + Write-Verbose -Message "Setting the Azure AD Authentication Method Policy X509 with Id {$Id}" + #Ensure the proper dependencies are installed in the current environment. Confirm-M365DSCDependencies @@ -379,6 +421,10 @@ function Test-TargetResource param ( #region resource generator code + [Parameter(Mandatory = $true)] + [System.String] + $Id, + [Parameter()] [Microsoft.Management.Infrastructure.CimInstance] $AuthenticationModeConfiguration, @@ -399,11 +445,6 @@ function Test-TargetResource [ValidateSet('enabled', 'disabled')] [System.String] $State, - - [Parameter(Mandatory = $true)] - [System.String] - $Id, - #endregion [Parameter()] @@ -560,7 +601,7 @@ function Export-TargetResource #region resource generator code [array]$getValue = Get-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration ` -AuthenticationMethodConfigurationId X509Certificate ` - -ErrorAction Stop | Where-Object -FilterScript {$null -ne $_.Id} + -ErrorAction Stop | Where-Object -FilterScript { $null -ne $_.Id } #endregion $i = 1 diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADDeviceRegistrationPolicy/MSFT_AADDeviceRegistrationPolicy.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADDeviceRegistrationPolicy/MSFT_AADDeviceRegistrationPolicy.psm1 index c6d32acefa..8fe76dc299 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADDeviceRegistrationPolicy/MSFT_AADDeviceRegistrationPolicy.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADDeviceRegistrationPolicy/MSFT_AADDeviceRegistrationPolicy.psm1 @@ -116,14 +116,40 @@ function Get-TargetResource foreach ($userId in $getValue.AzureAdJoin.AllowedToJoin.AdditionalProperties.users) { - $userInfo = Get-MgUser -UserId $userId - $AzureADAllowedToJoinUsers += $userInfo.UserPrincipalName + try + { + $userInfo = Get-MgUser -UserId $userId -ErrorAction Stop + $AzureADAllowedToJoinUsers += $userInfo.UserPrincipalName + } + catch + { + $message = "Could not find a user with id $($userId) specified in AllowedToJoin. Skipping user!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } foreach ($groupId in $getValue.AzureAdJoin.AllowedToJoin.AdditionalProperties.groups) { - $groupInfo = Get-MgGroup -GroupId $groupId - $AzureADAllowedToJoinGroups += $groupInfo.DisplayName + try + { + $groupInfo = Get-MgGroup -GroupId $groupId -ErrorAction Stop + $AzureADAllowedToJoinGroups += $groupInfo.DisplayName + } + catch + { + $message = "Could not find a group with id $($groupId) specified in AllowedToJoin. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } } @@ -140,14 +166,40 @@ function Get-TargetResource $AzureAdJoinLocalAdminsRegisteringMode = 'Selected' foreach ($userId in $getValue.AzureAdJoin.LocalAdmins.RegisteringUsers.AdditionalProperties.users) { - $userInfo = Get-MgUser -UserId $userId - $AzureAdJoinLocalAdminsRegisteringUsers += $userInfo.UserPrincipalName + try + { + $userInfo = Get-MgUser -UserId $userId -ErrorAction Stop + $AzureAdJoinLocalAdminsRegisteringUsers += $userInfo.UserPrincipalName + } + catch + { + $message = "Could not find a user with id $($userId) specified in AllowedToJoin. Skipping user!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } foreach ($groupId in $getValue.AzureAdJoin.LocalAdmins.RegisteringUsers.AdditionalProperties.groups) { - $groupInfo = Get-MgGroup -GroupId $groupId - $AzureAdJoinLocalAdminsRegisteringGroups += $groupInfo.DisplayName + try + { + $groupInfo = Get-MgGroup -GroupId $groupId -ErrorAction Stop + $AzureAdJoinLocalAdminsRegisteringGroups += $groupInfo.DisplayName + } + catch + { + $message = "Could not find a group with id $($groupId) specified in AllowedToJoin. Skipping group!" + New-M365DSCLogEntry -Message $message ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + continue + } } } From 8fdcb20b0b3880d24352d7899ea5879818cf39ac Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Tue, 19 Nov 2024 13:11:33 +0100 Subject: [PATCH 28/65] Corrected changelog --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e56a4eda8..317402c274 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,8 @@ when an assigned group no longer exists. * AADRoleEligibilityScheduleRequest * Adds support for custom role assignments at app scope. +* AzureBillingAccountPolicy + * Initial release. * IntuneDeviceConfigurationPolicyAndroidDeviceOwner * Fixed issue when properties `DetailedHelpText`, `DeviceOwnerLockScreenMessage` or `ShortHelpText` were defined but the @@ -69,8 +71,6 @@ * AADRoleEligibilityScheduleRequest * FIXES [#3787](https://github.com/microsoft/Microsoft365DSC/issues/3787) * FIXES [#5089](https://github.com/microsoft/Microsoft365DSC/issues/5089) -* AzureBillingAccountPolicy - * Initial release. * EXOATPBuiltInProtectionRule, EXOEOPProtectionRule * Fixed issue where empty arrays were being compared incorrectly to null strings From dfd6839170aea5ce62edc184b310fb4c8f9fc247 Mon Sep 17 00:00:00 2001 From: NikCharlebois Date: Tue, 19 Nov 2024 12:12:01 +0000 Subject: [PATCH 29/65] Updated Resources and Cmdlet documentation pages --- .../azure/AzureBillingAccountPolicy.md | 105 ++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 docs/docs/resources/azure/AzureBillingAccountPolicy.md diff --git a/docs/docs/resources/azure/AzureBillingAccountPolicy.md b/docs/docs/resources/azure/AzureBillingAccountPolicy.md new file mode 100644 index 0000000000..c1a200a8a8 --- /dev/null +++ b/docs/docs/resources/azure/AzureBillingAccountPolicy.md @@ -0,0 +1,105 @@ +# AzureBillingAccountPolicy + +## Parameters + +| Parameter | Attribute | DataType | Description | Allowed Values | +| --- | --- | --- | --- | --- | +| **BillingAccount** | Key | String | Unique identifier of the associated billing account. | | +| **Name** | Write | String | Name of the policy. | | +| **EnterpriseAgreementPolicies** | Write | MSFT_AzureBillingAccountPolicyEnterpriseAgreementPolicy | The policies for Enterprise Agreement enrollments. | | +| **MarketplacePurchases** | Write | String | The policy that controls whether Azure marketplace purchases are allowed. | | +| **ReservationPurchases** | Write | String | The policy that controls whether Azure reservation purchases are allowed. | | +| **SavingsPlanPurchases** | Write | String | The policy that controls whether users with Azure savings plan purchase are allowed. | | +| **Ensure** | Write | String | Present ensures the instance exists, absent ensures it is removed. | `Absent`, `Present` | +| **Credential** | Write | PSCredential | Credentials of the workload's 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. | | +| **ManagedIdentity** | Write | Boolean | Managed ID being used for authentication. | | +| **AccessTokens** | Write | StringArray[] | Access token used for authentication. | | + +### MSFT_AzureBillingAccountPolicyEnterpriseAgreementPolicy + +#### Parameters + +| Parameter | Attribute | DataType | Description | Allowed Values | +| --- | --- | --- | --- | --- | +| **accountOwnerViewCharges** | Write | String | The policy that controls whether account owner can view charges. | | +| **authenticationType** | Write | String | The state showing the enrollment auth level. | | +| **departmentAdminViewCharges** | Write | String | The policy that controls whether department admin can view charges. | | + + +## Description + +Configures policies settings for an Azure billing account. + +## 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()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint + ) + Import-DscResource -ModuleName Microsoft365DSC + node localhost + { + AzureBillingAccountPolicy "MyBillingAccountPolicy" + { + BillingAccount = "1e5b9e50-a1ea-581e-fb3a-xxxxxxxxx:6487d5cf-0a7b-42e6-9549-xxxxxxx_2019-05-31"; + Name = "default" + ApplicationId = $ApplicationId + TenantId = $TenantId + CertificateThumbprint = $CertificateThumbprint + EnterpriseAgreementPolicies = MSFT_AzureBillingAccountPolicyEnterpriseAgreementPolicy { + authenticationType = "OrganizationalAccountOnly" + } + MarketplacePurchases = "AllAllowed" + ReservationPurchases = "Allowed" + SavingsPlanPurchases = "NotAllowed" + } + } +} +``` + From 6d76c30dc6306f759e21e19359c6fe73aaeab6de Mon Sep 17 00:00:00 2001 From: NikCharlebois Date: Tue, 19 Nov 2024 12:14:33 +0000 Subject: [PATCH 30/65] Updated Schema Definition --- Modules/Microsoft365DSC/SchemaDefinition.json | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/Modules/Microsoft365DSC/SchemaDefinition.json b/Modules/Microsoft365DSC/SchemaDefinition.json index 2ebfcaead9..35f76dc9dd 100644 --- a/Modules/Microsoft365DSC/SchemaDefinition.json +++ b/Modules/Microsoft365DSC/SchemaDefinition.json @@ -9955,6 +9955,96 @@ } ] }, + { + "ClassName": "MSFT_AzureBillingAccountPolicyEnterpriseAgreementPolicy", + "Parameters": [ + { + "CIMType": "String", + "Name": "accountOwnerViewCharges", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "authenticationType", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "departmentAdminViewCharges", + "Option": "Write" + } + ] + }, + { + "ClassName": "MSFT_AzureBillingAccountPolicy", + "Parameters": [ + { + "CIMType": "String", + "Name": "BillingAccount", + "Option": "Key" + }, + { + "CIMType": "String", + "Name": "Name", + "Option": "Write" + }, + { + "CIMType": "MSFT_AzureBillingAccountPolicyEnterpriseAgreementPolicy", + "Name": "EnterpriseAgreementPolicies", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "MarketplacePurchases", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "ReservationPurchases", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "SavingsPlanPurchases", + "Option": "Write" + }, + { + "CIMType": "string", + "Name": "Ensure", + "Option": "Write" + }, + { + "CIMType": "MSFT_Credential", + "Name": "Credential", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "ApplicationId", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "TenantId", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "CertificateThumbprint", + "Option": "Write" + }, + { + "CIMType": "Boolean", + "Name": "ManagedIdentity", + "Option": "Write" + }, + { + "CIMType": "String[]", + "Name": "AccessTokens", + "Option": "Write" + } + ] + }, { "ClassName": "MSFT_AzureBillingAccountsAssociatedTenant", "Parameters": [ From 450baaef3e0183302c3e7a9bcfe2ea64804895e3 Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Tue, 19 Nov 2024 08:25:24 -0500 Subject: [PATCH 31/65] Fixes --- ...MSFT_AADRoleAssignmentScheduleRequest.psm1 | 263 ++++++------------ ...ADRoleAssignmentScheduleRequest.schema.mof | 2 +- 2 files changed, 86 insertions(+), 179 deletions(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleAssignmentScheduleRequest/MSFT_AADRoleAssignmentScheduleRequest.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleAssignmentScheduleRequest/MSFT_AADRoleAssignmentScheduleRequest.psm1 index bea1cf6526..53dcf44137 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleAssignmentScheduleRequest/MSFT_AADRoleAssignmentScheduleRequest.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleAssignmentScheduleRequest/MSFT_AADRoleAssignmentScheduleRequest.psm1 @@ -12,10 +12,10 @@ function Get-TargetResource [System.String] $RoleDefinition, - [Parameter()] - [ValidateSet('User', 'Group')] + [Parameter(Mandatory = $true)] + [ValidateSet('User', 'Group', 'ServicePrincipal')] [System.String] - $PrincipalType = 'User', + $PrincipalType, [Parameter()] [System.String] @@ -83,18 +83,11 @@ function Get-TargetResource [System.String[]] $AccessTokens ) - try - { - $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` - -InboundParameters $PSBoundParameters - } - catch - { - Write-Verbose -Message ($_) - } + $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` + -InboundParameters $PSBoundParameters - #Ensure the proper dependencies are installed in the current environment. - Confirm-M365DSCDependencies + #Ensure the proper dependencies are installed in the current environment. + Confirm-M365DSCDependencies #region Telemetry $ResourceName = $MyInvocation.MyCommand.ModuleName.Replace('MSFT_', '') @@ -124,137 +117,58 @@ function Get-TargetResource } } - if ($null -eq $request) + Write-Verbose -Message "Getting Role Eligibility by PrincipalId and RoleDefinitionId" + $PrincipalValue = $null + if ($PrincipalType -eq 'User') { - if ($null -ne $Script:exportedInstances -and $Script:ExportMode) - { - Write-Verbose -Message "Getting Role Eligibility by PrincipalId and RoleDefinitionId" - $PrincipalTypeValue = $null - if ($PrincipalType -eq 'User') - { - Write-Verbose -Message "Retrieving Principal by UserPrincipalName {$Principal}" - $PrincipalIdValue = Get-MgUser -Filter "UserPrincipalName eq '$Principal'" -ErrorAction SilentlyContinue - $PrincipalTypeValue = 'User' - } - if ($null -eq $PrincipalIdValue -or $PrincipalType -eq 'Group') - { - Write-Verbose -Message "Retrieving Principal by DisplayName {$Principal}" - $PrincipalIdValue = Get-MgGroup -Filter "DisplayName eq '$Principal'" -ErrorAction SilentlyContinue - $PrincipalTypeValue = 'Group' - } - - if ($null -ne $PrincipalIdValue) - { - $PrincipalId = $PrincipalIdValue.Id - } - else - { - return $nullResult - } - Write-Verbose -Message "Found Principal {$PrincipalId}" - $RoleDefinitionId = (Get-MgBetaRoleManagementDirectoryRoleDefinition -Filter "DisplayName eq '$RoleDefinition'").Id - $request = $Script:exportedInstances | Where-Object -FilterScript {$_.PrincipalId -eq $PrincipalId -and $_.RoleDefinitionId -eq $RoleDefinition} | Sort-Object -Property CompletedDateTime -Descending - } - else - { - Write-Verbose -Message "Getting Role Eligibility by PrincipalId and RoleDefinitionId" - if ($PrincipalType -eq 'User') - { - Write-Verbose -Message "Retrieving principal {$Principal} of type {$PrincipalType}" - $PrincipalIdValue = Get-MgUser -Filter "UserPrincipalName eq '$Principal'" -ErrorAction SilentlyContinue - $PrincipalTypeValue = 'User' - } - - if ($null -eq $PrincipalIdValue -or $PrincipalType -eq 'Group') - { - Write-Verbose -Message "Retrieving principal {$Principal} of type {$PrincipalType}" - $PrincipalIdValue = Get-MgGroup -Filter "DisplayName eq '$Principal'" -ErrorAction SilentlyContinue - $PrincipalTypeValue = 'Group' - } - - if ($null -ne $PrincipalIdValue) - { - $PrincipalId = $PrincipalIdValue.Id - } - else - { - return $nullResult - } - Write-Verbose -Message "Found Principal {$PrincipalId}" - $schedulesForPrincipal = Get-MgBetaRoleManagementDirectoryRoleAssignmentSchedule -Filter "PrincipalId eq '$PrincipalId'" - foreach ($instance in $schedulesForPrincipal) - { - $roleInfo = Get-MgBetaRoleManagementDirectoryRoleDefinition -UnifiedRoleDefinitionId $instance.RoleDefinitionId - if ($roleInfo.DisplayName -eq $RoleDefinition) - { - $schedule = $instance - } - } - [Array]$request = Get-MgBetaRoleManagementDirectoryRoleAssignmentScheduleRequest -Filter "PrincipalId eq '$PrincipalId'" | Where-Object -FilterScript {$_.RoleDefinitionId -eq $schedule.RoleDefinitionId} | Sort-Object -Property CompletedDateTime -Descending -` - if ($request.Length -gt 1) - { - $request = $request[0] - } - } + Write-Verbose -Message "Retrieving Principal by UserPrincipalName {$Principal}" + $PrincipalInstance = Get-MgUser -Filter "UserPrincipalName eq '$Principal'" -ErrorAction SilentlyContinue + $PrincipalValue = $PrincipalInstance.UserPrincipalName + } + elseif ($null -eq $PrincipalIdValue -and $PrincipalType -eq 'Group') + { + Write-Verbose -Message "Retrieving Principal by DisplayName {$Principal}" + $PrincipalInstance = Get-MgGroup -Filter "DisplayName eq '$Principal'" -ErrorAction SilentlyContinue + $PrincipalValue = $PrincipalInstance.DisplayName } else { - Write-Verbose -Message "Request is not null: $request" - $ObjectGuid = [System.Guid]::empty - if ($PrincipalType -eq 'User') - { - Write-Verbose -Message "Retrieving principal {$Principal} of type {$PrincipalType}" - - if ([System.Guid]::TryParse($Principal,[System.Management.Automation.PSReference]$ObjectGuid)) - { - $PrincipalIdValue = Get-MgUser -UserId $Principal -ErrorAction SilentlyContinue - } - else - { - $PrincipalIdValue = Get-MgUser -Filter "UserPrincipalName eq '$Principal'" -ErrorAction SilentlyContinue - } - $PrincipalTypeValue = 'User' - } + Write-Verbose -Message "Retrieving Principal by DisplayName {$Principal}" + $PrincipalInstance = Get-MgServicePrincipal -Filter "DisplayName eq '$Principal'" -ErrorAction SilentlyContinue + $PrincipalValue = $PrincipalInstance.DisplayName + } - if ($null -eq $PrincipalIdValue -or $PrincipalType -eq 'Group') - { - Write-Verbose -Message "Retrieving principal {$Principal} of type {$PrincipalType}" - if ([System.Guid]::TryParse($Principal,[System.Management.Automation.PSReference]$ObjectGuid)) - { - $PrincipalIdValue = Get-MgGroup -GroupId $Principal -ErrorAction SilentlyContinue - } - else - { - $PrincipalIdValue = Get-MgGroup -Filter "DisplayName eq '$Principal'" -ErrorAction SilentlyContinue - } - $PrincipalTypeValue = 'Group' - } + Write-Verbose -Message "Found Principal" + $RoleDefinitionId = (Get-MgBetaRoleManagementDirectoryRoleDefinition -Filter "DisplayName eq '$RoleDefinition'").Id + Write-Verbose -Message "Retrieved role definition {$RoleDefinition} with ID {$RoleDefinitionId}" - if ($null -ne $PrincipalIdValue) - { - $PrincipalId = $PrincipalIdValue.Id - } - else + if ($null -eq $request) + { + Write-Verbose -Message "Retrieving the request by PrincipalId {$($PrincipalInstance.Id)}, RoleDefinitionId {$($RoleDefinitionId)} and DirectoryScopeId {$($DirectoryScopeId)}" + [Array] $requests = Get-MgBetaRoleManagementDirectoryRoleAssignmentScheduleRequest -Filter "PrincipalId eq '$($PrincipalInstance.Id)' and RoleDefinitionId eq '$($RoleDefinitionId)' and DirectoryScopeId eq '$($DirectoryScopeId)'" + if ($requests.Length -eq 0) { return $nullResult } - $RoleDefinitionId = (Get-MgBetaRoleManagementDirectoryRoleDefinition -Filter "DisplayName eq '$RoleDefinition'").Id - $schedules = Get-MgBetaRoleManagementDirectoryRoleAssignmentSchedule -Filter "PrincipalId eq '$($request.PrincipalId)'" - $schedule = $schedules | Where-Object -FilterScript {$_.RoleDefinitionId -eq $RoleDefinitionId} - if ($null -eq $schedule) + + $request = $requests[0] + } + + $schedules = Get-MgBetaRoleManagementDirectoryRoleAssignmentSchedule -Filter "PrincipalId eq '$($request.PrincipalId)'" + $schedule = $schedules | Where-Object -FilterScript {$_.RoleDefinitionId -eq $RoleDefinitionId} + if ($null -eq $schedule) + { + foreach ($instance in $schedules) { - foreach ($instance in $schedules) + $roleDefinitionInfo = Get-MgBetaRoleManagementDirectoryRoleDefinition -UnifiedRoleDefinitionId $instance.RoleDefinitionId + if ($null -ne $roleDefinitionInfo -and $RoleDefinitionInfo.DisplayName -eq $RoleDefinition) { - $roleDefinitionInfo = Get-MgBetaRoleManagementDirectoryRoleDefinition -UnifiedRoleDefinitionId $instance.RoleDefinitionId - if ($null -ne $roleDefinitionInfo -and $RoleDefinitionInfo.DisplayName -eq $RoleDefinition) - { - $schedule = $instance - break - } + $schedule = $instance + break } } } + if ($null -eq $schedule -or $null -eq $request) { if ($null -eq $schedule) @@ -268,32 +182,6 @@ function Get-TargetResource return $nullResult } - Write-Verbose -Message "Found existing AADRolelLigibilityScheduleRequest" - if ($PrincipalType -eq 'User') - { - Write-Verbose -Message "Retrieving Principal by UserId {$($request.PrincipalId)}" - $PrincipalInstance = Get-MgUser -UserId $request.PrincipalId -ErrorAction SilentlyContinue - $PrincipalTypeValue = 'User' - } - if ($null -eq $PrincipalInstance -or $PrincipalType -eq 'Group') - { - Write-Verbose -Message "Retrieving Principal by GroupId {$($request.PrincipalId)}" - $requestArray = [Array]$request - if ($requestArray.Count -gt 1) - { - $requestArray = $requestArray | Sort-Object -Property CreatedDateTime -Descending - $request = $requestArray[0] - } - $PrincipalInstance = Get-MGGroup -GroupId $request.PrincipalId -ErrorAction SilentlyContinue - $PrincipalTypeValue = 'Group' - } - - if ($null -eq $PrincipalInstance) - { - Write-Verbose -Message "Couldn't retrieve Principal {$($request.PrincipalId)}" - return $nullResult - } - $ScheduleInfoValue = @{} if ($null -ne $schedule.ScheduleInfo.Expiration) @@ -344,19 +232,9 @@ function Get-TargetResource } } - $PrincipalValue = $null - if ($PrincipalType -eq 'User') - { - $PrincipalValue = $PrincipalInstance.UserPrincipalName - } - if ($null -eq $PrincipalValue -or $PrincipalTypeValue -eq 'Group') - { - $PrincipalValue = $PrincipalInstance.DisplayName - } - $results = @{ Principal = $PrincipalValue - PrincipalType = $PrincipalTypeValue + PrincipalType = $PrincipalType RoleDefinition = $RoleDefinition DirectoryScopeId = $request.DirectoryScopeId AppScopeId = $request.AppScopeId @@ -403,10 +281,10 @@ function Set-TargetResource [System.String] $RoleDefinition, - [Parameter()] - [ValidateSet('User', 'Group')] + [Parameter(Mandatory = $true)] + [ValidateSet('User', 'Group', 'ServicePrincipal')] [System.String] - $PrincipalType = 'User', + $PrincipalType, [Parameter()] [System.String] @@ -518,6 +396,10 @@ function Set-TargetResource { [Array]$PrincipalIdValue = (Get-MgGroup -Filter "DisplayName eq '$Principal'").Id } + elseif ($PrincipalType -eq 'ServicePrincipal') + { + [Array]$PrincipalIdValue = (Get-MgServicePrincipal -Filter "DisplayName eq '$Principal'").Id + } if ($null -eq $PrincipalIdValue) { @@ -598,21 +480,21 @@ function Set-TargetResource $ParametersOps.Remove("PrincipalType") | Out-Null if ($Ensure -eq 'Present' -and $currentInstance.Ensure -eq 'Absent') { - Write-Verbose -Message "Creating a Role Eligibility Schedule Request for user {$Principal} and role {$RoleDefinition}" + Write-Verbose -Message "Creating a Role Assignment Schedule Request for principal {$Principal} and role {$RoleDefinition}" $ParametersOps.Remove("Id") | Out-Null Write-Verbose -Message "Values: $(Convert-M365DscHashtableToString -Hashtable $ParametersOps)" New-MgBetaRoleManagementDirectoryRoleAssignmentScheduleRequest @ParametersOps } elseif ($Ensure -eq 'Present' -and $currentInstance.Ensure -eq 'Present') { - Write-Verbose -Message "Updating the Role Eligibility Schedule Request for user {$Principal} and role {$RoleDefinition}" + Write-Verbose -Message "Updating the Role Assignment Schedule Request for principal {$Principal} and role {$RoleDefinition}" $ParametersOps.Remove("Id") | Out-Null $ParametersOps.Action = 'AdminUpdate' New-MgBetaRoleManagementDirectoryRoleAssignmentScheduleRequest @ParametersOps } elseif ($Ensure -eq 'Absent' -and $currentInstance.Ensure -eq 'Present') { - Write-Verbose -Message "Removing the Role Eligibility Schedule Request for user {$Principal} and role {$RoleDefinition}" + Write-Verbose -Message "Removing the Role Assignment Schedule Request for principal {$Principal} and role {$RoleDefinition}" $ParametersOps.Remove("Id") | Out-Null $ParametersOps.Action = 'AdminRemove' New-MgBetaRoleManagementDirectoryRoleAssignmentScheduleRequest @ParametersOps @@ -633,10 +515,10 @@ function Test-TargetResource [System.String] $RoleDefinition, - [Parameter()] - [ValidateSet('User', 'Group')] + [Parameter(Mandatory = $true)] + [ValidateSet('User', 'Group', 'ServicePrincipal')] [System.String] - $PrincipalType = 'User', + $PrincipalType, [Parameter()] [System.String] @@ -862,10 +744,35 @@ function Export-TargetResource $displayedKey = $request.Id Write-Host " |---[$i/$($Script:exportedInstances.Count)] $displayedKey" -NoNewline + # Find the Principal Type + $principalType = 'User' + $userInfo = Get-MgUser -UserId $request.PrincipalId -ErrorAction SilentlyContinue + + if ($null -eq $userInfo) + { + $principalType = 'Group' + $groupInfo = Get-MgGroup -GroupId $request.PrincipalId -ErrorAction SilentlyContinue + if ($null -eq $groupInfo) + { + $principalType = 'ServicePrincipal' + $spnInfo = Get-MgServicePrincipal -ServicePrincipalId $request.PrincipalId + $PrincipalValue = $spnInfo.DisplayName + } + else + { + $PrincipalValue = $groupInfo.DisplayName + } + } + else + { + $PrincipalValue = $userInfo.UserPrincipalName + } + $RoleDefinitionId = Get-MgBetaRoleManagementDirectoryRoleDefinition -UnifiedRoleDefinitionId $request.RoleDefinitionId $params = @{ Id = $request.Id - Principal = $request.PrincipalId + Principal = $PrincipalValue + PrincipalType = $principalType RoleDefinition = $RoleDefinitionId.DisplayName Ensure = 'Present' Credential = $Credential diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleAssignmentScheduleRequest/MSFT_AADRoleAssignmentScheduleRequest.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleAssignmentScheduleRequest/MSFT_AADRoleAssignmentScheduleRequest.schema.mof index c940cf80b3..06953d873c 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleAssignmentScheduleRequest/MSFT_AADRoleAssignmentScheduleRequest.schema.mof +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleAssignmentScheduleRequest/MSFT_AADRoleAssignmentScheduleRequest.schema.mof @@ -55,7 +55,7 @@ class MSFT_AADRoleAssignmentScheduleRequest : OMI_BaseResource { [Key, Description("User Principal Name of the eligibility request.")] String Principal; [Key, Description("Role associated with the eligibility request.")] String RoleDefinition; - [Write, Description("Represented the type of principal to assign the request to. Accepted values are: Group and User."), ValueMap{"Group","User"}, Values{"Group","User"}] String PrincipalType; + [Write, Description("Represented the type of principal to assign the request to. Accepted values are: Group and User."), ValueMap{"Group","User","ServicePrincipal"}, Values{"Group","User","ServicePrincipal"}] String PrincipalType; [Write, Description("Identifier of the directory object representing the scope of the role eligibility. The scope of an role eligibility determines the set of resources for which the principal has been granted access. Directory scopes are shared scopes stored in the directory that are understood by multiple applications. Use / for tenant-wide scope. Use appScopeId to limit the scope to an application only. Either directoryScopeId or appScopeId is required.")] String DirectoryScopeId; [Write, Description("Identifier for the Role Eligibility Schedule Request.")] String Id; [Write, Description("Identifier of the app-specific scope when the role eligibility is scoped to an app. The scope of a role eligibility determines the set of resources for which the principal is eligible to access. App scopes are scopes that are defined and understood by this application only. Use / for tenant-wide app scopes. Use directoryScopeId to limit the scope to particular directory objects, for example, administrative units. Either directoryScopeId or appScopeId is required.")] String AppScopeId; From cbe4930877e61382d18ea8f14522ea93819da024 Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Tue, 19 Nov 2024 09:06:12 -0500 Subject: [PATCH 32/65] AADRoleAssignmentScheduleRequest - Initial Release --- CHANGELOG.md | 2 + ...MSFT_AADRoleAssignmentScheduleRequest.psm1 | 7 +- ...ADRoleAssignmentScheduleRequest.schema.mof | 2 +- .../1-Create.ps1 | 21 +- .../2-Update.ps1 | 21 +- .../3-Remove.ps1 | 21 +- ...AADRoleAssignmentScheduleRequest.Tests.ps1 | 242 +++++++--- Tests/Unit/Stubs/Microsoft365.psm1 | 429 +++++++++--------- 8 files changed, 458 insertions(+), 287 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c983de7fe7..63006d0b92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ sessionControl parameter when there are no session controls, which throws an error. * Fixed bug where a null value was passed in the request for the applicationEnforcedRestrictions parameter when value was set to false, which throws an error. +* AADRoleAssignmentScheduleRequest + * Initial release. * AADRoleEligibilityScheduleRequest * Adds support for custom role assignments at app scope. * IntuneFirewallRulesHyperVPolicyWindows10 diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleAssignmentScheduleRequest/MSFT_AADRoleAssignmentScheduleRequest.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleAssignmentScheduleRequest/MSFT_AADRoleAssignmentScheduleRequest.psm1 index 53dcf44137..609c174b67 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleAssignmentScheduleRequest/MSFT_AADRoleAssignmentScheduleRequest.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleAssignmentScheduleRequest/MSFT_AADRoleAssignmentScheduleRequest.psm1 @@ -21,7 +21,7 @@ function Get-TargetResource [System.String] $Id, - [Parameter()] + [Parameter(Mandatory = $true)] [System.String] $DirectoryScopeId, @@ -290,7 +290,7 @@ function Set-TargetResource [System.String] $Id, - [Parameter()] + [Parameter(Mandatory = $true)] [System.String] $DirectoryScopeId, @@ -524,7 +524,7 @@ function Test-TargetResource [System.String] $Id, - [Parameter()] + [Parameter(Mandatory = $true)] [System.String] $DirectoryScopeId, @@ -773,6 +773,7 @@ function Export-TargetResource Id = $request.Id Principal = $PrincipalValue PrincipalType = $principalType + DirectoryScopeId = $request.DirectoryScopeId RoleDefinition = $RoleDefinitionId.DisplayName Ensure = 'Present' Credential = $Credential diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleAssignmentScheduleRequest/MSFT_AADRoleAssignmentScheduleRequest.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleAssignmentScheduleRequest/MSFT_AADRoleAssignmentScheduleRequest.schema.mof index 06953d873c..276dfb57ef 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleAssignmentScheduleRequest/MSFT_AADRoleAssignmentScheduleRequest.schema.mof +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleAssignmentScheduleRequest/MSFT_AADRoleAssignmentScheduleRequest.schema.mof @@ -56,7 +56,7 @@ class MSFT_AADRoleAssignmentScheduleRequest : OMI_BaseResource [Key, Description("User Principal Name of the eligibility request.")] String Principal; [Key, Description("Role associated with the eligibility request.")] String RoleDefinition; [Write, Description("Represented the type of principal to assign the request to. Accepted values are: Group and User."), ValueMap{"Group","User","ServicePrincipal"}, Values{"Group","User","ServicePrincipal"}] String PrincipalType; - [Write, Description("Identifier of the directory object representing the scope of the role eligibility. The scope of an role eligibility determines the set of resources for which the principal has been granted access. Directory scopes are shared scopes stored in the directory that are understood by multiple applications. Use / for tenant-wide scope. Use appScopeId to limit the scope to an application only. Either directoryScopeId or appScopeId is required.")] String DirectoryScopeId; + [Key, Description("Identifier of the directory object representing the scope of the role eligibility. The scope of an role eligibility determines the set of resources for which the principal has been granted access. Directory scopes are shared scopes stored in the directory that are understood by multiple applications. Use / for tenant-wide scope. Use appScopeId to limit the scope to an application only. Either directoryScopeId or appScopeId is required.")] String DirectoryScopeId; [Write, Description("Identifier for the Role Eligibility Schedule Request.")] String Id; [Write, Description("Identifier of the app-specific scope when the role eligibility is scoped to an app. The scope of a role eligibility determines the set of resources for which the principal is eligible to access. App scopes are scopes that are defined and understood by this application only. Use / for tenant-wide app scopes. Use directoryScopeId to limit the scope to particular directory objects, for example, administrative units. Either directoryScopeId or appScopeId is required.")] String AppScopeId; [Write, Description("Represents the type of operation on the role eligibility request.The possible values are: adminAssign, adminUpdate, adminRemove, selfActivate, selfDeactivate, adminExtend, adminRenew, selfExtend, selfRenew, unknownFutureValue."), ValueMap{"adminAssign","adminUpdate","adminRemove","selfActivate","selfDeactivate","adminExtend","adminRenew","selfExtend","selfRenew","unknownFutureValue"}, Values{"adminAssign","adminUpdate","adminRemove","selfActivate","selfDeactivate","adminExtend","adminRenew","selfExtend","selfRenew","unknownFutureValue"}] String Action; diff --git a/Modules/Microsoft365DSC/Examples/Resources/AADRoleAssignmentScheduleRequest/1-Create.ps1 b/Modules/Microsoft365DSC/Examples/Resources/AADRoleAssignmentScheduleRequest/1-Create.ps1 index b516274848..28973b551b 100644 --- a/Modules/Microsoft365DSC/Examples/Resources/AADRoleAssignmentScheduleRequest/1-Create.ps1 +++ b/Modules/Microsoft365DSC/Examples/Resources/AADRoleAssignmentScheduleRequest/1-Create.ps1 @@ -21,6 +21,25 @@ Configuration Example Import-DscResource -ModuleName Microsoft365DSC node localhost { - + AADRoleAssignmentScheduleRequest "MyRequest" + { + Action = "AdminAssign"; + ApplicationId = $ApplicationId + TenantId = $TenantId + CertificateThumbprint = $CertificateThumbprint + DirectoryScopeId = "/"; + Ensure = "Present"; + IsValidationOnly = $False; + Principal = "AdeleV@$TenantId"; + RoleDefinition = "Teams Communications Administrator"; + ScheduleInfo = MSFT_AADRoleAssignmentScheduleRequestSchedule { + startDateTime = '2023-09-01T02:40:44Z' + expiration = MSFT_AADRoleAssignmentScheduleRequestScheduleExpiration + { + endDateTime = '2025-10-31T02:40:09Z' + type = 'afterDateTime' + } + }; + } } } diff --git a/Modules/Microsoft365DSC/Examples/Resources/AADRoleAssignmentScheduleRequest/2-Update.ps1 b/Modules/Microsoft365DSC/Examples/Resources/AADRoleAssignmentScheduleRequest/2-Update.ps1 index b516274848..201957e4dc 100644 --- a/Modules/Microsoft365DSC/Examples/Resources/AADRoleAssignmentScheduleRequest/2-Update.ps1 +++ b/Modules/Microsoft365DSC/Examples/Resources/AADRoleAssignmentScheduleRequest/2-Update.ps1 @@ -21,6 +21,25 @@ Configuration Example Import-DscResource -ModuleName Microsoft365DSC node localhost { - + AADRoleAssignmentScheduleRequest "MyRequest" + { + Action = "AdminUpdate"; + ApplicationId = $ApplicationId + TenantId = $TenantId + CertificateThumbprint = $CertificateThumbprint + DirectoryScopeId = "/"; + Ensure = "Present"; + IsValidationOnly = $False; + Principal = "AdeleV@$TenantId"; + RoleDefinition = "Teams Communications Administrator"; + ScheduleInfo = MSFT_AADRoleAssignmentScheduleRequestSchedule { + startDateTime = '2023-09-01T02:45:44Z' # Updated Property + expiration = MSFT_AADRoleAssignmentScheduleRequestScheduleExpiration + { + endDateTime = '2025-10-31T02:40:09Z' + type = 'afterDateTime' + } + }; + } } } diff --git a/Modules/Microsoft365DSC/Examples/Resources/AADRoleAssignmentScheduleRequest/3-Remove.ps1 b/Modules/Microsoft365DSC/Examples/Resources/AADRoleAssignmentScheduleRequest/3-Remove.ps1 index b516274848..3b5f3d400b 100644 --- a/Modules/Microsoft365DSC/Examples/Resources/AADRoleAssignmentScheduleRequest/3-Remove.ps1 +++ b/Modules/Microsoft365DSC/Examples/Resources/AADRoleAssignmentScheduleRequest/3-Remove.ps1 @@ -21,6 +21,25 @@ Configuration Example Import-DscResource -ModuleName Microsoft365DSC node localhost { - + AADRoleAssignmentScheduleRequest "MyRequest" + { + Action = "AdminAssign"; + ApplicationId = $ApplicationId + TenantId = $TenantId + CertificateThumbprint = $CertificateThumbprint + DirectoryScopeId = "/"; + Ensure = "Absent"; + IsValidationOnly = $True; # Updated Property + Principal = "AdeleV@$TenantId"; + RoleDefinition = "Teams Communications Administrator"; + ScheduleInfo = MSFT_AADRoleAssignmentScheduleRequestSchedule { + startDateTime = '2023-09-01T02:40:44Z' + expiration = MSFT_AADRoleAssignmentScheduleRequestScheduleExpiration + { + endDateTime = '2025-10-31T02:40:09Z' + type = 'afterDateTime' + } + }; + } } } diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADRoleAssignmentScheduleRequest.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADRoleAssignmentScheduleRequest.Tests.ps1 index 780e0f343d..af3ab222ef 100644 --- a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADRoleAssignmentScheduleRequest.Tests.ps1 +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADRoleAssignmentScheduleRequest.Tests.ps1 @@ -1,41 +1,63 @@ [CmdletBinding()] param( ) + $M365DSCTestFolder = Join-Path -Path $PSScriptRoot ` - -ChildPath '..\..\Unit' ` - -Resolve + -ChildPath '..\..\Unit' ` + -Resolve $CmdletModule = (Join-Path -Path $M365DSCTestFolder ` - -ChildPath '\Stubs\Microsoft365.psm1' ` - -Resolve) + -ChildPath '\Stubs\Microsoft365.psm1' ` + -Resolve) $GenericStubPath = (Join-Path -Path $M365DSCTestFolder ` - -ChildPath '\Stubs\Generic.psm1' ` - -Resolve) + -ChildPath '\Stubs\Generic.psm1' ` + -Resolve) Import-Module -Name (Join-Path -Path $M365DSCTestFolder ` -ChildPath '\UnitTestHelper.psm1' ` -Resolve) - -$CurrentScriptPath = $PSCommandPath.Split('\') -$CurrentScriptName = $CurrentScriptPath[$CurrentScriptPath.Length -1] -$ResourceName = $CurrentScriptName.Split('.')[1] $Global:DscHelper = New-M365DscUnitTestHelper -StubModule $CmdletModule ` - -DscResource $ResourceName -GenericStubModule $GenericStubPath + -DscResource 'AADRoleAssignmentScheduleRequest' -GenericStubModule $GenericStubPath Describe -Name $Global:DscHelper.DescribeHeader -Fixture { InModuleScope -ModuleName $Global:DscHelper.ModuleName -ScriptBlock { Invoke-Command -ScriptBlock $Global:DscHelper.InitializeScript -NoNewScope BeforeAll { - + $Global:CurrentModeIsExport = $false $secpasswd = ConvertTo-SecureString (New-Guid | Out-String) -AsPlainText -Force $Credential = New-Object System.Management.Automation.PSCredential ('tenantadmin@mydomain.com', $secpasswd) + $Script:exportedInstances = $null + $Script:ExportMode = $null + Mock -CommandName Add-M365DSCTelemetryEvent -MockWith { + } Mock -CommandName Confirm-M365DSCDependencies -MockWith { } Mock -CommandName New-M365DSCConnection -MockWith { - return "Credentials" + return 'Credentials' + } + + Mock -CommandName New-MgBetaRoleManagementDirectoryRoleAssignmentScheduleRequest -MockWith { } - ##TODO - Mock any Remove/Set/New cmdlets + Mock -CommandName Get-MgUser -MockWith { + return @{ + Id = '123456' + UserPrincipalName = 'John.Smith@contoso.com' + } + } + + Mock -CommandName Get-MgBetaRoleManagementDirectoryRoleDefinition -MockWith { + return @{ + DisplayName = 'Teams Communications Administrator' + Id = '12345' + } + } + Mock -CommandName Get-MgBetaRoleManagementDirectoryRoleAssignmentSchedule -MockWith { + return @{ + Id = '12345-12345-12345-12345-12345' + RoleDefinitionId = "12345" + } + } # Mock Write-Host to hide output during the tests Mock -CommandName Write-Host -MockWith { @@ -44,16 +66,27 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { $Script:ExportMode = $false } # Test contexts - Context -Name "The instance should exist but it DOES NOT" -Fixture { + Context -Name 'The instance should exist but it DOES NOT' -Fixture { BeforeAll { $testParams = @{ - ##TODO - Add Parameters - Ensure = 'Present' - Credential = $Credential; + Action = "AdminAssign"; + DirectoryScopeId = "/"; + Ensure = "Present"; + IsValidationOnly = $False; + Principal = "John.Smith@contoso.com"; + PrincipalType = "User" + RoleDefinition = "Teams Communications Administrator"; + ScheduleInfo = New-CimInstance -ClassName MSFT_AADRoleAssignmentScheduleRequestSchedule -Property @{ + startDateTime = '2023-09-01T02:40:44Z' + expiration = New-CimInstance -ClassName MSFT_AADRoleAssignmentScheduleRequestScheduleExpiration -Property @{ + endDateTime = '2025-10-31T02:40:09Z' + type = 'afterDateTime' + } -ClientOnly + } -ClientOnly + Credential = $Credential } - ##TODO - Mock the Get-Cmdlet to return $null - Mock -CommandName Get-Cmdlet -MockWith { + Mock -CommandName Get-MgBetaRoleManagementDirectoryRoleAssignmentScheduleRequest -MockWith { return $null } } @@ -63,78 +96,161 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { It 'Should return false from the Test method' { Test-TargetResource @testParams | Should -Be $false } - - It 'Should create a new instance from the Set method' { - ##TODO - Replace the New-Cmdlet by the appropriate one + It 'Should Create the instance from the Set method' { Set-TargetResource @testParams - Should -Invoke -CommandName New-Cmdlet -Exactly 1 + Should -Invoke -CommandName New-MgBetaRoleManagementDirectoryRoleAssignmentScheduleRequest -Exactly 1 } } - Context -Name "The instance exists but it SHOULD NOT" -Fixture { + Context -Name 'The instance exists but it SHOULD NOT' -Fixture { BeforeAll { $testParams = @{ - ##TODO - Add Parameters - Ensure = 'Absent' - Credential = $Credential; + Action = "AdminAssign"; + DirectoryScopeId = "/"; + Ensure = "Absent"; + IsValidationOnly = $False; + PrincipalType = "User" + Principal = "John.Smith@contoso.com"; + RoleDefinition = "Teams Communications Administrator"; + ScheduleInfo = New-CimInstance -ClassName MSFT_AADRoleAssignmentScheduleRequestSchedule -Property @{ + + expiration = New-CimInstance -ClassName MSFT_AADRoleAssignmentScheduleRequestScheduleExpiration -Property @{ + + type = 'afterDateTime' + } -ClientOnly + } -ClientOnly + Credential = $Credential } - ##TODO - Mock the Get-Cmdlet to return an instance - Mock -CommandName Get-Cmdlet -MockWith { + Mock -CommandName Get-MgBetaRoleManagementDirectoryRoleAssignmentScheduleRequest -MockWith { return @{ - + Action = "AdminAssign"; + Id = '12345-12345-12345-12345-12345' + DirectoryScopeId = "/"; + IsValidationOnly = $False; + PrincipalId = "123456"; + RoleDefinitionId = "12345"; + ScheduleInfo = @{ + startDateTime = [System.DateTime]::Parse('2023-09-01T02:40:44Z') + expiration = @{ + endDateTime = [System.DateTime]::Parse('2025-10-31T02:40:09Z') + type = 'afterDateTime' + } + }; } } } + 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 remove the instance from the Set method' { + It 'Should Remove the instance from the Set method' { Set-TargetResource @testParams - ##TODO - Replace the Remove-Cmdlet by the appropriate one - Should -Invoke -CommandName Remove-Cmdlet -Exactly 1 + Should -Invoke -CommandName New-MgBetaRoleManagementDirectoryRoleAssignmentScheduleRequest -Exactly 1 } } - - Context -Name "The instance 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 = @{ - ##TODO - Add Parameters - Ensure = 'Present' - Credential = $Credential; + Action = "AdminAssign"; + DirectoryScopeId = "/"; + Ensure = "Present"; + IsValidationOnly = $False; + PrincipalType = "User" + Principal = "John.Smith@contoso.com"; + RoleDefinition = "Teams Communications Administrator"; + ScheduleInfo = New-CimInstance -ClassName MSFT_AADRoleAssignmentScheduleRequestSchedule -Property @{ + + expiration = New-CimInstance -ClassName MSFT_AADRoleAssignmentScheduleRequestScheduleExpiration -Property @{ + type = 'afterDateTime' + } -ClientOnly + } -ClientOnly + Credential = $Credential } - ##TODO - Mock the Get-Cmdlet to return the desired values - Mock -CommandName Get-Cmdlet -MockWith { + Mock -CommandName Get-MgBetaRoleManagementDirectoryRoleAssignmentScheduleRequest -MockWith { return @{ - + Action = "AdminAssign"; + Id = '12345-12345-12345-12345-12345' + DirectoryScopeId = "/"; + IsValidationOnly = $False; + PrincipalId = "123456"; + RoleDefinitionId = "12345"; + ScheduleInfo = @{ + expiration = @{ + type = 'afterDateTime' + } + }; + } + } + Mock -CommandName Get-MgBetaRoleManagementDirectoryRoleAssignmentSchedule -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' { + (Get-TargetResource @testParams).Ensure | Should -Be 'Present' + } + 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 { + Context -Name 'The instance Exists and specified Values are NOT in the desired state' -Fixture { BeforeAll { $testParams = @{ - ##TODO - Add Parameters - Ensure = 'Present' - Credential = $Credential; + Action = "AdminAssign"; + DirectoryScopeId = "/"; + Ensure = "Present"; + IsValidationOnly = $False; + PrincipalType = "User" + Principal = "John.Smith@contoso.com"; + RoleDefinition = "Teams Communications Administrator"; + ScheduleInfo = New-CimInstance -ClassName MSFT_AADRoleAssignmentScheduleRequestSchedule -Property @{ + + expiration = New-CimInstance -ClassName MSFT_AADRoleAssignmentScheduleRequestScheduleExpiration -Property @{ + + type = 'afterDateTime' + } -ClientOnly + } -ClientOnly + Credential = $Credential } - ##TODO - Mock the Get-Cmdlet to return a drift - Mock -CommandName Get-Cmdlet -MockWith { + Mock -CommandName Get-MgBetaRoleManagementDirectoryRoleAssignmentScheduleRequest -MockWith { return @{ - + Action = "AdminAssign"; + Id = '12345-12345-12345-12345-12345' + DirectoryScopeId = "/"; + IsValidationOnly = $False; + PrincipalId = "123456"; + RoleDefinitionId = "12345"; + ScheduleInfo = @{ + startDateTime = [System.DateTime]::Parse('2023-09-01T02:40:44Z') + expiration = @{ + endDateTime = [System.DateTime]::Parse('2025-10-31T02:40:09Z') + type = 'afterDateTime' + } + }; } } + } It 'Should return Values from the Get method' { @@ -145,25 +261,35 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { Test-TargetResource @testParams | Should -Be $false } - It 'Should call the Set method' { + It 'Should call the Set to Update the instance' { Set-TargetResource @testParams - ##TODO - Replace the Update-Cmdlet by the appropriate one - Should -Invoke -CommandName Update-Cmdlet -Exactly 1 + Should -Invoke -CommandName Get-MgBetaRoleManagementDirectoryRoleAssignmentScheduleRequest -Exactly 1 } } - Context -Name 'ReverseDSC Tests' -Fixture { BeforeAll { $Global:CurrentModeIsExport = $true $Global:PartialExportFileName = "$(New-Guid).partial.ps1" $testParams = @{ - Credential = $Credential; + Credential = $Credential } - ##TODO - Mock the Get-Cmdlet to return an instance - Mock -CommandName Get-Cmdlet -MockWith { + Mock -CommandName Get-MgBetaRoleManagementDirectoryRoleAssignmentScheduleRequest -MockWith { return @{ - + Action = "AdminAssign"; + Id = '12345-12345-12345-12345-12345' + DirectoryScopeId = "/"; + IsValidationOnly = $False; + PrincipalId = "123456"; + RoleDefinitionId = "12345"; + ScheduleInfo = @{ + startDateTime = [System.DateTime]::Parse('2023-09-01T02:40:44Z') + expiration = @{ + endDateTime = [System.DateTime]::Parse('2025-10-31T02:40:09Z') + type = 'afterDateTime' + } + }; + TargetScheduleId = "12345-12345-12345-12345-12345" } } } diff --git a/Tests/Unit/Stubs/Microsoft365.psm1 b/Tests/Unit/Stubs/Microsoft365.psm1 index ac7c4b04d9..5e512d8f32 100644 --- a/Tests/Unit/Stubs/Microsoft365.psm1 +++ b/Tests/Unit/Stubs/Microsoft365.psm1 @@ -33371,6 +33371,83 @@ function Get-MgBetaRoleManagementDirectoryRoleEligibilityScheduleRequest $HttpPipelineAppend ) } +function Get-MgBetaRoleManagementDirectoryRoleEAssignmentScheduleRequest +{ + [CmdletBinding()] + param( + [Parameter()] + [System.String[]] + $Property, + + [Parameter()] + [System.String] + $UnifiedRoleEligibilityScheduleRequestId, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $ProxyUseDefaultCredentials, + + [Parameter()] + [System.Int32] + $PageSize, + + [Parameter()] + [PSObject] + $HttpPipelinePrepend, + + [Parameter()] + [System.Int32] + $Skip, + + [Parameter()] + [PSObject] + $InputObject, + + [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 New-MgBetaEntitlementManagementAccessPackage { [CmdletBinding()] @@ -34654,6 +34731,136 @@ function New-MgBetaRoleManagementDirectoryRoleEligibilityScheduleRequest $HttpPipelineAppend ) } + +function New-MgBetaRoleManagementDirectoryRoleAssignmentScheduleRequest +{ + [CmdletBinding()] + param( + [Parameter()] + [System.String] + $Justification, + + [Parameter()] + [PSObject] + $Principal, + + [Parameter()] + [System.DateTime] + $CreatedDateTime, + + [Parameter()] + [System.String] + $Action, + + [Parameter()] + [System.Collections.Hashtable] + $AdditionalProperties, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $ProxyUseDefaultCredentials, + + [Parameter()] + [PSObject] + $ScheduleInfo, + + [Parameter()] + [PSObject] + $DirectoryScope, + + [Parameter()] + [PSObject] + $TargetSchedule, + + [Parameter()] + [System.String] + $ApprovalId, + + [Parameter()] + [PSObject] + $HttpPipelinePrepend, + + [Parameter()] + [System.String] + $CustomData, + + [Parameter()] + [PSObject] + $CreatedBy, + + [Parameter()] + [System.String] + $PrincipalId, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $IsValidationOnly, + + [Parameter()] + [System.DateTime] + $CompletedDateTime, + + [Parameter()] + [PSObject] + $TicketInfo, + + [Parameter()] + [System.Uri] + $Proxy, + + [Parameter()] + [PSObject] + $BodyParameter, + + [Parameter()] + [System.String] + $Status, + + [Parameter()] + [System.String] + $Id, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Confirm, + + [Parameter()] + [System.String] + $TargetScheduleId, + + [Parameter()] + [System.String] + $RoleDefinitionId, + + [Parameter()] + [PSObject] + $RoleDefinition, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ProxyCredential, + + [Parameter()] + [PSObject] + $AppScope, + + [Parameter()] + [System.String] + $DirectoryScopeId, + + [Parameter()] + [System.String] + $AppScopeId, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Break, + + [Parameter()] + [PSObject] + $HttpPipelineAppend + ) +} function Remove-MgBetaEntitlementManagementAccessPackage { [CmdletBinding()] @@ -43390,91 +43597,6 @@ function Get-MgBetaRoleManagementDirectoryRoleEligibilitySchedule $HttpPipelineAppend ) } -function Get-MgBetaRoleManagementDirectoryRoleEligibilityScheduleRequest -{ - [CmdletBinding()] - param( - [Parameter()] - [System.String[]] - $Property, - - [Parameter()] - [System.String] - $UnifiedRoleEligibilityScheduleRequestId, - - [Parameter()] - [System.Management.Automation.SwitchParameter] - $ProxyUseDefaultCredentials, - - [Parameter()] - [System.Int32] - $PageSize, - - [Parameter()] - [PSObject] - $HttpPipelinePrepend, - - [Parameter()] - [System.Int32] - $Skip, - - [Parameter()] - [PSObject] - $InputObject, - - [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] - $ResponseHeadersVariable, - - [Parameter()] - [System.Management.Automation.SwitchParameter] - $Break, - - [Parameter()] - [System.String[]] - $ExpandProperty, - - [Parameter()] - [System.Collections.IDictionary] - $Headers, - - [Parameter()] - [PSObject] - $HttpPipelineAppend - ) -} function Get-MgBetaRoleManagementEntitlementManagement { [CmdletBinding()] @@ -44960,143 +45082,6 @@ function New-MgBetaRoleManagementDirectoryRoleEligibilitySchedule $HttpPipelineAppend ) } -function New-MgBetaRoleManagementDirectoryRoleEligibilityScheduleRequest -{ - [CmdletBinding()] - param( - [Parameter()] - [System.String] - $Justification, - - [Parameter()] - [PSObject] - $Principal, - - [Parameter()] - [System.DateTime] - $CreatedDateTime, - - [Parameter()] - [System.String] - $Action, - - [Parameter()] - [System.Collections.Hashtable] - $AdditionalProperties, - - [Parameter()] - [System.Management.Automation.SwitchParameter] - $ProxyUseDefaultCredentials, - - [Parameter()] - [PSObject] - $ScheduleInfo, - - [Parameter()] - [PSObject] - $DirectoryScope, - - [Parameter()] - [PSObject] - $TargetSchedule, - - [Parameter()] - [System.String] - $ApprovalId, - - [Parameter()] - [PSObject] - $HttpPipelinePrepend, - - [Parameter()] - [System.String] - $CustomData, - - [Parameter()] - [PSObject] - $CreatedBy, - - [Parameter()] - [System.String] - $PrincipalId, - - [Parameter()] - [System.Management.Automation.SwitchParameter] - $IsValidationOnly, - - [Parameter()] - [System.DateTime] - $CompletedDateTime, - - [Parameter()] - [PSObject] - $TicketInfo, - - [Parameter()] - [System.Uri] - $Proxy, - - [Parameter()] - [PSObject] - $BodyParameter, - - [Parameter()] - [System.String] - $Status, - - [Parameter()] - [System.String] - $Id, - - [Parameter()] - [System.Management.Automation.SwitchParameter] - $Confirm, - - [Parameter()] - [System.String] - $TargetScheduleId, - - [Parameter()] - [System.String] - $RoleDefinitionId, - - [Parameter()] - [PSObject] - $RoleDefinition, - - [Parameter()] - [System.Management.Automation.PSCredential] - $ProxyCredential, - - [Parameter()] - [PSObject] - $AppScope, - - [Parameter()] - [System.String] - $DirectoryScopeId, - - [Parameter()] - [System.String] - $ResponseHeadersVariable, - - [Parameter()] - [System.String] - $AppScopeId, - - [Parameter()] - [System.Management.Automation.SwitchParameter] - $Break, - - [Parameter()] - [System.Collections.IDictionary] - $Headers, - - [Parameter()] - [PSObject] - $HttpPipelineAppend - ) -} function New-MgBetaRoleManagementEntitlementManagementRoleAssignment { [CmdletBinding()] From 5ea62b1493cdf37abc227d147e8da9bf9a0a96b5 Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Tue, 19 Nov 2024 15:49:11 +0100 Subject: [PATCH 33/65] Fixes #5423 --- CHANGELOG.md | 7 +++++ .../MSFT_AADRoleSetting.psm1 | 30 +++++++------------ 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 317402c274..f57211c503 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,10 @@ when an assigned group no longer exists. * AADRoleEligibilityScheduleRequest * Adds support for custom role assignments at app scope. +* AADRoleSettings + * Fixing issue where the ActivateApprover parameter isn't processed correctly + when an approver does not exist. + FIXES [#5423](https://github.com/microsoft/Microsoft365DSC/issues/5423) * AzureBillingAccountPolicy * Initial release. * IntuneDeviceConfigurationPolicyAndroidDeviceOwner @@ -56,6 +60,9 @@ FIXES [#5411](https://github.com/microsoft/Microsoft365DSC/issues/5411) * IntuneFirewallRulesHyperVPolicyWindows10 * Initial release. +* TeamsUpdateManagementPolicy + * Added conversion of the UpdateTimeOfDay parameter to the local culture format + so that the comparison will work consistently. * M365DSCDRGUtil * Improve CIM instance detection for specific Intune resources. diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleSetting/MSFT_AADRoleSetting.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleSetting/MSFT_AADRoleSetting.psm1 index ee5cc80c73..43cd0c3f04 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleSetting/MSFT_AADRoleSetting.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleSetting/MSFT_AADRoleSetting.psm1 @@ -968,15 +968,8 @@ function Set-TargetResource { #is not a guid try with user $Filter = "UserPrincipalName eq '" + $item + "'" - try - { - $user = Get-MgUser -Filter $Filter -ErrorAction Stop - } - catch - { - Write-Verbose -Message 'User not found, try with group' - } - if ($user.length -gt 0) + $user = Get-MgUser -Filter $Filter + if ($null -ne $user) { $ActivateApprovers = @{} $ActivateApprovers.Add('@odata.type', '#microsoft.graph.singleUser') @@ -986,17 +979,11 @@ function Set-TargetResource } else { - #try with group + Write-Verbose -Message "User '$item' not found, trying with group" + $Filter = "displayName eq '" + $item + "'" - try - { - $group = Get-MgGroup -Filter $Filter -ErrorAction Stop - } - catch - { - Write-Verbose -Message 'Group not found' - } - if ($group.length -gt 0) + $group = Get-MgGroup -Filter $Filter + if ($null -ne $group) { $ActivateApprovers = @{} $ActivateApprovers.Add('@odata.type', '#microsoft.graph.groupMembers') @@ -1004,6 +991,10 @@ function Set-TargetResource $primaryApprovers += $ActivateApprovers $group = $null } + else + { + throw "Group '$item' not found. Cannot add as approver." + } } } } @@ -1012,6 +1003,7 @@ function Set-TargetResource $approvalStages.Add('isApproverJustificationRequired', 'true') $approvalStages.Add('escalationTimeInMinutes', '0') $approvalStages.Add('isEscalationEnabled', 'False') + if ($primaryApprovers.Count -gt 0) { $approvalStages.Add('primaryApprovers', @($primaryApprovers)) From a1b5c0d5f81538deed472b0b335ab050785e6866 Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Tue, 19 Nov 2024 15:53:26 +0100 Subject: [PATCH 34/65] Fixes #5424 --- CHANGELOG.md | 1 + .../MSFT_TeamsUpdateManagementPolicy.psm1 | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f57211c503..0b75d93eeb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -63,6 +63,7 @@ * TeamsUpdateManagementPolicy * Added conversion of the UpdateTimeOfDay parameter to the local culture format so that the comparison will work consistently. + FIXES [#5424](https://github.com/microsoft/Microsoft365DSC/issues/5424) * M365DSCDRGUtil * Improve CIM instance detection for specific Intune resources. diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsUpdateManagementPolicy/MSFT_TeamsUpdateManagementPolicy.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsUpdateManagementPolicy/MSFT_TeamsUpdateManagementPolicy.psm1 index f971163f12..aeb131dbd2 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsUpdateManagementPolicy/MSFT_TeamsUpdateManagementPolicy.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsUpdateManagementPolicy/MSFT_TeamsUpdateManagementPolicy.psm1 @@ -351,6 +351,14 @@ function Test-TargetResource $ValuesToCheck = Remove-M365DSCAuthenticationParameter -BoundParameters $ValuesToCheck + if ($PSBoundParameters.ContainsKey('UpdateTimeOfDay')) + { + Write-Verbose -Message "Converting UpdateTimeOfDay ($UpdateTimeOfDay) to the current culture format" + $dtUpdateTimeOfDay = [datetime]::Parse($PSBoundParameters.UpdateTimeOfDay) + $PSBoundParameters.UpdateTimeOfDay = $dtUpdateTimeOfDay.ToShortTimeString() + Write-Verbose -Message " Converted value $($PSBoundParameters.UpdateTimeOfDay))" + } + Write-Verbose -Message "Current Values: $(Convert-M365DscHashtableToString -Hashtable $CurrentValues)" Write-Verbose -Message "Target Values: $(Convert-M365DscHashtableToString -Hashtable $PSBoundParameters)" From 4e29d3ea31acc772fce25e7a5474cc6ee6910e44 Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Tue, 19 Nov 2024 10:05:54 -0500 Subject: [PATCH 35/65] Update Microsoft365.psm1 --- Tests/Unit/Stubs/Microsoft365.psm1 | 87 ++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/Tests/Unit/Stubs/Microsoft365.psm1 b/Tests/Unit/Stubs/Microsoft365.psm1 index 5e512d8f32..fb374ff977 100644 --- a/Tests/Unit/Stubs/Microsoft365.psm1 +++ b/Tests/Unit/Stubs/Microsoft365.psm1 @@ -104401,3 +104401,90 @@ function Get-MigrationUser ) } #endregion +#region Microsoft.Graph.Authentication +function Get-MgBetaRoleManagementDirectoryRoleAssignmentSchedule +{ + [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.String] + $UnifiedRoleAssignmentScheduleId, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $All, + + [Parameter()] + [System.String] + $Filter, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ProxyCredential, + + [Parameter()] + [System.String] + $Search, + + [Parameter()] + [System.String] + $ResponseHeadersVariable, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Break, + + [Parameter()] + [System.String[]] + $ExpandProperty, + + [Parameter()] + [System.Collections.IDictionary] + $Headers, + + [Parameter()] + [PSObject] + $HttpPipelineAppend + ) +} +#endregion From 31ae7ff7bd07e0dfb269e991f5a47459c3998543 Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Tue, 19 Nov 2024 10:29:57 -0500 Subject: [PATCH 36/65] Update Microsoft365.psm1 --- Tests/Unit/Stubs/Microsoft365.psm1 | 88 ++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/Tests/Unit/Stubs/Microsoft365.psm1 b/Tests/Unit/Stubs/Microsoft365.psm1 index fb374ff977..e29324881e 100644 --- a/Tests/Unit/Stubs/Microsoft365.psm1 +++ b/Tests/Unit/Stubs/Microsoft365.psm1 @@ -104488,3 +104488,91 @@ function Get-MgBetaRoleManagementDirectoryRoleAssignmentSchedule ) } #endregion + +#region Microsoft.Graph.Authentication +function Get-MgBetaRoleManagementDirectoryRoleAssignmentScheduleRequest +{ + [CmdletBinding()] + param( + [Parameter()] + [System.String[]] + $Property, + + [Parameter()] + [PSObject] + $InputObject, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $ProxyUseDefaultCredentials, + + [Parameter()] + [System.String] + $UnifiedRoleAssignmentScheduleRequestId, + + [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] + $ResponseHeadersVariable, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Break, + + [Parameter()] + [System.String[]] + $ExpandProperty, + + [Parameter()] + [System.Collections.IDictionary] + $Headers, + + [Parameter()] + [PSObject] + $HttpPipelineAppend + ) +} +#endregion From ab645b519285eb6717118872eec1a66960d3247e Mon Sep 17 00:00:00 2001 From: dannyKBjj Date: Tue, 19 Nov 2024 15:51:21 +0000 Subject: [PATCH 37/65] Update Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/MSFT_IntuneMobileAppConfigurationPolicyIOS.psm1 Co-authored-by: FabienTschanz <71251572+FabienTschanz@users.noreply.github.com> --- .../MSFT_IntuneMobileAppConfigurationPolicyIOS.psm1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/MSFT_IntuneMobileAppConfigurationPolicyIOS.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/MSFT_IntuneMobileAppConfigurationPolicyIOS.psm1 index 93a0f1e76c..12deb1f16e 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/MSFT_IntuneMobileAppConfigurationPolicyIOS.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/MSFT_IntuneMobileAppConfigurationPolicyIOS.psm1 @@ -114,7 +114,7 @@ function Get-TargetResource return $nullResult } - Write-Verbose -Message "Found something with id {$id}" + Write-Verbose -Message "An Intune Mobile App Configuration Policy for iOS with Id {$id} and DisplayName {$DisplayName} was found" #need to convert dictionary object into a hashtable array so we can work with it $complexSettings = @() From 629911f0aca102b1947f4b212176d230c2c0152e Mon Sep 17 00:00:00 2001 From: dannyKBjj Date: Tue, 19 Nov 2024 15:51:29 +0000 Subject: [PATCH 38/65] Update Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/MSFT_IntuneMobileAppConfigurationPolicyIOS.psm1 Co-authored-by: FabienTschanz <71251572+FabienTschanz@users.noreply.github.com> --- .../MSFT_IntuneMobileAppConfigurationPolicyIOS.psm1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/MSFT_IntuneMobileAppConfigurationPolicyIOS.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/MSFT_IntuneMobileAppConfigurationPolicyIOS.psm1 index 12deb1f16e..435b3082f5 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/MSFT_IntuneMobileAppConfigurationPolicyIOS.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/MSFT_IntuneMobileAppConfigurationPolicyIOS.psm1 @@ -110,7 +110,7 @@ function Get-TargetResource if ($null -eq $getValue) { - Write-Verbose -Message "Nothing with id {$id} was found" + Write-Verbose -Message "No Intune Mobile App Configuration Policy for iOS with Id {$id} was found" return $nullResult } From b917c16920eec9e311e47c8cd2f380017647fa32 Mon Sep 17 00:00:00 2001 From: dannyKBjj Date: Tue, 19 Nov 2024 15:52:28 +0000 Subject: [PATCH 39/65] Removed blank lines from schema.mof --- ...IntuneMobileAppConfigurationPolicyIOS.psm1 | 4 ++-- ...MobileAppConfigurationPolicyIOS.schema.mof | Bin 7984 -> 7964 bytes 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/MSFT_IntuneMobileAppConfigurationPolicyIOS.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/MSFT_IntuneMobileAppConfigurationPolicyIOS.psm1 index 93a0f1e76c..435b3082f5 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/MSFT_IntuneMobileAppConfigurationPolicyIOS.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/MSFT_IntuneMobileAppConfigurationPolicyIOS.psm1 @@ -110,11 +110,11 @@ function Get-TargetResource if ($null -eq $getValue) { - Write-Verbose -Message "Nothing with id {$id} was found" + Write-Verbose -Message "No Intune Mobile App Configuration Policy for iOS with Id {$id} was found" return $nullResult } - Write-Verbose -Message "Found something with id {$id}" + Write-Verbose -Message "An Intune Mobile App Configuration Policy for iOS with Id {$id} and DisplayName {$DisplayName} was found" #need to convert dictionary object into a hashtable array so we can work with it $complexSettings = @() diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/MSFT_IntuneMobileAppConfigurationPolicyIOS.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppConfigurationPolicyIOS/MSFT_IntuneMobileAppConfigurationPolicyIOS.schema.mof index d09774961eca88ea67455f618794f1c369cb29e0..e35b7bfd7e830e2da307639e00a117e49ab0e2f3 100644 GIT binary patch delta 48 zcmdmBH^**+3ioCOZZnq2D%=K}`}mWXC+`q6+N>r#jS0;7B&x^BQOjV>z{|kJ004fo B4bK1o delta 51 zcmbPZx4~|M3isqFeuK>s+)ON+gZO7LPuyU(Sx$Hw)8-ALDVzel3|tH#T+3h$rU9BH B42A#z From 09f17c468e79fc0cef8c38172cd9f448e8c5ec4a Mon Sep 17 00:00:00 2001 From: NikCharlebois Date: Tue, 19 Nov 2024 15:59:19 +0000 Subject: [PATCH 40/65] Updated Resources and Cmdlet documentation pages --- .../AADRoleAssignmentScheduleRequest.md | 267 ++++++++++++++++++ 1 file changed, 267 insertions(+) create mode 100644 docs/docs/resources/azure-ad/AADRoleAssignmentScheduleRequest.md diff --git a/docs/docs/resources/azure-ad/AADRoleAssignmentScheduleRequest.md b/docs/docs/resources/azure-ad/AADRoleAssignmentScheduleRequest.md new file mode 100644 index 0000000000..1f3ec5eeae --- /dev/null +++ b/docs/docs/resources/azure-ad/AADRoleAssignmentScheduleRequest.md @@ -0,0 +1,267 @@ +# AADRoleAssignmentScheduleRequest + +## Parameters + +| Parameter | Attribute | DataType | Description | Allowed Values | +| --- | --- | --- | --- | --- | +| **Principal** | Key | String | User Principal Name of the eligibility request. | | +| **RoleDefinition** | Key | String | Role associated with the eligibility request. | | +| **PrincipalType** | Write | String | Represented the type of principal to assign the request to. Accepted values are: Group and User. | `Group`, `User`, `ServicePrincipal` | +| **DirectoryScopeId** | Key | String | Identifier of the directory object representing the scope of the role eligibility. The scope of an role eligibility determines the set of resources for which the principal has been granted access. Directory scopes are shared scopes stored in the directory that are understood by multiple applications. Use / for tenant-wide scope. Use appScopeId to limit the scope to an application only. Either directoryScopeId or appScopeId is required. | | +| **Id** | Write | String | Identifier for the Role Eligibility Schedule Request. | | +| **AppScopeId** | Write | String | Identifier of the app-specific scope when the role eligibility is scoped to an app. The scope of a role eligibility determines the set of resources for which the principal is eligible to access. App scopes are scopes that are defined and understood by this application only. Use / for tenant-wide app scopes. Use directoryScopeId to limit the scope to particular directory objects, for example, administrative units. Either directoryScopeId or appScopeId is required. | | +| **Action** | Write | String | Represents the type of operation on the role eligibility request.The possible values are: adminAssign, adminUpdate, adminRemove, selfActivate, selfDeactivate, adminExtend, adminRenew, selfExtend, selfRenew, unknownFutureValue. | `adminAssign`, `adminUpdate`, `adminRemove`, `selfActivate`, `selfDeactivate`, `adminExtend`, `adminRenew`, `selfExtend`, `selfRenew`, `unknownFutureValue` | +| **IsValidationOnly** | Write | Boolean | Determines whether the call is a validation or an actual call. Only set this property if you want to check whether an activation is subject to additional rules like MFA before actually submitting the request. | | +| **Justification** | Write | String | A message provided by users and administrators when create they create the unifiedRoileAssignmentScheduleRequest object. Optional when action is adminRemove. Whether this property is required or optional is also dependent on the settings for the Azure AD role. | | +| **ScheduleInfo** | Write | MSFT_AADRoleAssignmentScheduleRequestSchedule | The period of the role eligibility. Optional when action is adminRemove. The period of eligibility is dependent on the settings of the Azure AD role. | | +| **TicketInfo** | Write | MSFT_AADRoleAssignmentScheduleRequestTicketInfo | Ticket details linked to the role eligibility request including details of the ticket number and ticket system. | | +| **Ensure** | Write | String | Present ensures the instance exists, absent ensures it is removed. | `Present`, `Absent` | +| **Credential** | Write | PSCredential | Credentials of the Intune 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 application to authenticate with. | | +| **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. | | +| **AccessTokens** | Write | StringArray[] | Access token used for authentication. | | + +### MSFT_AADRoleAssignmentScheduleRequestScheduleRecurrenceRange + +#### Parameters + +| Parameter | Attribute | DataType | Description | Allowed Values | +| --- | --- | --- | --- | --- | +| **endDate** | Required | String | The date to stop applying the recurrence pattern. Depending on the recurrence pattern of the event, the last occurrence of the meeting may not be this date. | | +| **numberOfOccurrences** | Write | UInt32 | The number of times to repeat the event. Required and must be positive if type is numbered. | | +| **recurrenceTimeZone** | Write | String | Time zone for the startDate and endDate properties. | | +| **startDate** | Required | String | The date to start applying the recurrence pattern. The first occurrence of the meeting may be this date or later, depending on the recurrence pattern of the event. Must be the same value as the start property of the recurring event. | | +| **type** | Required | String | The recurrence range. The possible values are: endDate, noEnd, numbered. | `endDate`, `noEnd`, `numbered` | + +### MSFT_AADRoleAssignmentScheduleRequestScheduleRecurrencePattern + +#### Parameters + +| Parameter | Attribute | DataType | Description | Allowed Values | +| --- | --- | --- | --- | --- | +| **dayOfMonth** | Write | UInt32 | The day of the month on which the event occurs. | | +| **daysOfWeek** | Write | StringArray[] | A collection of the days of the week on which the event occurs. The possible values are: sunday, monday, tuesday, wednesday, thursday, friday, saturday | `sunday`, `monday`, `tuesday`, `wednesday`, `thursday`, `friday`, `saturday` | +| **firstDayOfWeek** | Write | String | The first day of the week. | `sunday`, `monday`, `tuesday`, `wednesday`, `thursday`, `friday`, `saturday` | +| **index** | Write | String | Specifies on which instance of the allowed days specified in daysOfWeek the event occurs, counted from the first instance in the month. The possible values are: first, second, third, fourth, last. | `first`, `second`, `third`, `fourth`, `last` | +| **interval** | Write | UInt32 | The number of units between occurrences, where units can be in days, weeks, months, or years, depending on the type. | | +| **month** | Write | UInt32 | The month in which the event occurs. This is a number from 1 to 12. | | +| **type** | Write | String | The recurrence pattern type: daily, weekly, absoluteMonthly, relativeMonthly, absoluteYearly, relativeYearly. | `daily`, `weekly`, `absoluteMonthly`, `relativeMonthly`, `absoluteYearly`, `relativeYearly` | + +### MSFT_AADRoleAssignmentScheduleRequestScheduleRecurrence + +#### Parameters + +| Parameter | Attribute | DataType | Description | Allowed Values | +| --- | --- | --- | --- | --- | +| **pattern** | Write | MSFT_AADRoleAssignmentScheduleRequestScheduleRecurrencePattern | The frequency of an event. | | +| **range** | Write | MSFT_AADRoleAssignmentScheduleRequestScheduleRecurrenceRange | The duration of an event. | | + +### MSFT_AADRoleAssignmentScheduleRequestScheduleExpiration + +#### Parameters + +| Parameter | Attribute | DataType | Description | Allowed Values | +| --- | --- | --- | --- | --- | +| **duration** | Write | String | The requestor's desired duration of access represented in ISO 8601 format for durations. For example, PT3H refers to three hours. If specified in a request, endDateTime should not be present and the type property should be set to afterDuration. | | +| **endDateTime** | Write | String | Timestamp of date and time information using ISO 8601 format and is always in UTC time. For example, midnight UTC on Jan 1, 2014 is 2014-01-01T00:00:00Z. | | +| **type** | Write | String | The requestor's desired expiration pattern type. The possible values are: notSpecified, noExpiration, afterDateTime, afterDuration. | `notSpecified`, `noExpiration`, `afterDateTime`, `afterDuration` | + +### MSFT_AADRoleAssignmentScheduleRequestSchedule + +#### Parameters + +| Parameter | Attribute | DataType | Description | Allowed Values | +| --- | --- | --- | --- | --- | +| **expiration** | Write | MSFT_AADRoleAssignmentScheduleRequestScheduleExpiration | When the eligible or active assignment expires. | | +| **recurrence** | Write | MSFT_AADRoleAssignmentScheduleRequestScheduleRecurrence | The frequency of the eligible or active assignment. This property is currently unsupported in PIM. | | +| **startDateTime** | Write | String | When the eligible or active assignment becomes active. | | + +### MSFT_AADRoleAssignmentScheduleRequestTicketInfo + +#### Parameters + +| Parameter | Attribute | DataType | Description | Allowed Values | +| --- | --- | --- | --- | --- | +| **ticketNumber** | Write | String | The ticket number. | | +| **ticketSystem** | Write | String | The description of the ticket system. | | + + +## Description + +This resource configures an Azure Active Directory Privilege Identity Management assignment. + +## 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** + + - RoleAssignmentSchedule.Read.Directory + +- **Update** + + - RoleAssignmentSchedule.ReadWrite.Directory + +## 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()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint + ) + Import-DscResource -ModuleName Microsoft365DSC + node localhost + { + AADRoleAssignmentScheduleRequest "MyRequest" + { + Action = "AdminAssign"; + ApplicationId = $ApplicationId + TenantId = $TenantId + CertificateThumbprint = $CertificateThumbprint + DirectoryScopeId = "/"; + Ensure = "Present"; + IsValidationOnly = $False; + Principal = "AdeleV@$TenantId"; + RoleDefinition = "Teams Communications Administrator"; + ScheduleInfo = MSFT_AADRoleAssignmentScheduleRequestSchedule { + startDateTime = '2023-09-01T02:40:44Z' + expiration = MSFT_AADRoleAssignmentScheduleRequestScheduleExpiration + { + endDateTime = '2025-10-31T02:40:09Z' + type = 'afterDateTime' + } + }; + } + } +} +``` + +### Example 2 + +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()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint + ) + Import-DscResource -ModuleName Microsoft365DSC + node localhost + { + AADRoleAssignmentScheduleRequest "MyRequest" + { + Action = "AdminUpdate"; + ApplicationId = $ApplicationId + TenantId = $TenantId + CertificateThumbprint = $CertificateThumbprint + DirectoryScopeId = "/"; + Ensure = "Present"; + IsValidationOnly = $False; + Principal = "AdeleV@$TenantId"; + RoleDefinition = "Teams Communications Administrator"; + ScheduleInfo = MSFT_AADRoleAssignmentScheduleRequestSchedule { + startDateTime = '2023-09-01T02:45:44Z' # Updated Property + expiration = MSFT_AADRoleAssignmentScheduleRequestScheduleExpiration + { + endDateTime = '2025-10-31T02:40:09Z' + type = 'afterDateTime' + } + }; + } + } +} +``` + +### Example 3 + +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()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint + ) + Import-DscResource -ModuleName Microsoft365DSC + node localhost + { + AADRoleAssignmentScheduleRequest "MyRequest" + { + Action = "AdminAssign"; + ApplicationId = $ApplicationId + TenantId = $TenantId + CertificateThumbprint = $CertificateThumbprint + DirectoryScopeId = "/"; + Ensure = "Absent"; + IsValidationOnly = $True; # Updated Property + Principal = "AdeleV@$TenantId"; + RoleDefinition = "Teams Communications Administrator"; + ScheduleInfo = MSFT_AADRoleAssignmentScheduleRequestSchedule { + startDateTime = '2023-09-01T02:40:44Z' + expiration = MSFT_AADRoleAssignmentScheduleRequestScheduleExpiration + { + endDateTime = '2025-10-31T02:40:09Z' + type = 'afterDateTime' + } + }; + } + } +} +``` + From 97d27bfa73578274b0e1b94a839c9f7c55275d92 Mon Sep 17 00:00:00 2001 From: NikCharlebois Date: Tue, 19 Nov 2024 15:59:36 +0000 Subject: [PATCH 41/65] Updated {Create} AAD Integration Tests --- .../M365DSCIntegration.AAD.Create.Tests.ps1 | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Tests/Integration/Microsoft365DSC/M365DSCIntegration.AAD.Create.Tests.ps1 b/Tests/Integration/Microsoft365DSC/M365DSCIntegration.AAD.Create.Tests.ps1 index a46d077fd1..2c71a4dbc3 100644 --- a/Tests/Integration/Microsoft365DSC/M365DSCIntegration.AAD.Create.Tests.ps1 +++ b/Tests/Integration/Microsoft365DSC/M365DSCIntegration.AAD.Create.Tests.ps1 @@ -876,6 +876,26 @@ } ); } + AADRoleAssignmentScheduleRequest 'MyRequest' + { + Action = "AdminAssign"; + ApplicationId = $ApplicationId + TenantId = $TenantId + CertificateThumbprint = $CertificateThumbprint + DirectoryScopeId = "/"; + Ensure = "Present"; + IsValidationOnly = $False; + Principal = "AdeleV@$TenantId"; + RoleDefinition = "Teams Communications Administrator"; + ScheduleInfo = MSFT_AADRoleAssignmentScheduleRequestSchedule { + startDateTime = '2023-09-01T02:40:44Z' + expiration = MSFT_AADRoleAssignmentScheduleRequestScheduleExpiration + { + endDateTime = '2025-10-31T02:40:09Z' + type = 'afterDateTime' + } + }; + } AADRoleDefinition 'AADRoleDefinition1' { DisplayName = "DSCRole1" From c040bea5af4816ec0feee832c6555132b3aa5da0 Mon Sep 17 00:00:00 2001 From: NikCharlebois Date: Tue, 19 Nov 2024 16:00:14 +0000 Subject: [PATCH 42/65] Updated {Update} AAD Integration Tests --- .../M365DSCIntegration.AAD.Update.Tests.ps1 | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Tests/Integration/Microsoft365DSC/M365DSCIntegration.AAD.Update.Tests.ps1 b/Tests/Integration/Microsoft365DSC/M365DSCIntegration.AAD.Update.Tests.ps1 index e51178069f..2d595e86c1 100644 --- a/Tests/Integration/Microsoft365DSC/M365DSCIntegration.AAD.Update.Tests.ps1 +++ b/Tests/Integration/Microsoft365DSC/M365DSCIntegration.AAD.Update.Tests.ps1 @@ -1439,6 +1439,26 @@ } ); } + AADRoleAssignmentScheduleRequest 'MyRequest' + { + Action = "AdminUpdate"; + ApplicationId = $ApplicationId + TenantId = $TenantId + CertificateThumbprint = $CertificateThumbprint + DirectoryScopeId = "/"; + Ensure = "Present"; + IsValidationOnly = $False; + Principal = "AdeleV@$TenantId"; + RoleDefinition = "Teams Communications Administrator"; + ScheduleInfo = MSFT_AADRoleAssignmentScheduleRequestSchedule { + startDateTime = '2023-09-01T02:45:44Z' # Updated Property + expiration = MSFT_AADRoleAssignmentScheduleRequestScheduleExpiration + { + endDateTime = '2025-10-31T02:40:09Z' + type = 'afterDateTime' + } + }; + } AADRoleDefinition 'AADRoleDefinition1' { DisplayName = "DSCRole1" From 1f55b20e3c47f2f536fc449035ed3b9b109d9342 Mon Sep 17 00:00:00 2001 From: NikCharlebois Date: Tue, 19 Nov 2024 16:00:44 +0000 Subject: [PATCH 43/65] Updated {Update} AAD Integration Tests --- .../M365DSCIntegration.AAD.Remove.Tests.ps1 | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Tests/Integration/Microsoft365DSC/M365DSCIntegration.AAD.Remove.Tests.ps1 b/Tests/Integration/Microsoft365DSC/M365DSCIntegration.AAD.Remove.Tests.ps1 index aa51a57c7a..236a28b797 100644 --- a/Tests/Integration/Microsoft365DSC/M365DSCIntegration.AAD.Remove.Tests.ps1 +++ b/Tests/Integration/Microsoft365DSC/M365DSCIntegration.AAD.Remove.Tests.ps1 @@ -565,6 +565,26 @@ } ); } + AADRoleAssignmentScheduleRequest 'MyRequest' + { + Action = "AdminAssign"; + ApplicationId = $ApplicationId + TenantId = $TenantId + CertificateThumbprint = $CertificateThumbprint + DirectoryScopeId = "/"; + Ensure = "Absent"; + IsValidationOnly = $True; # Updated Property + Principal = "AdeleV@$TenantId"; + RoleDefinition = "Teams Communications Administrator"; + ScheduleInfo = MSFT_AADRoleAssignmentScheduleRequestSchedule { + startDateTime = '2023-09-01T02:40:44Z' + expiration = MSFT_AADRoleAssignmentScheduleRequestScheduleExpiration + { + endDateTime = '2025-10-31T02:40:09Z' + type = 'afterDateTime' + } + }; + } AADRoleDefinition 'AADRoleDefinition1' { IsEnabled = $true From 3f7158ffa01fb07628790c7fdaa3475bc82d887d Mon Sep 17 00:00:00 2001 From: NikCharlebois Date: Tue, 19 Nov 2024 16:02:49 +0000 Subject: [PATCH 44/65] Updated Schema Definition --- Modules/Microsoft365DSC/SchemaDefinition.json | 240 ++++++++++++++++++ 1 file changed, 240 insertions(+) diff --git a/Modules/Microsoft365DSC/SchemaDefinition.json b/Modules/Microsoft365DSC/SchemaDefinition.json index 35f76dc9dd..ca31d9dd0c 100644 --- a/Modules/Microsoft365DSC/SchemaDefinition.json +++ b/Modules/Microsoft365DSC/SchemaDefinition.json @@ -7724,6 +7724,246 @@ } ] }, + { + "ClassName": "MSFT_AADRoleAssignmentScheduleRequestScheduleRecurrenceRange", + "Parameters": [ + { + "CIMType": "String", + "Name": "endDate", + "Option": "Required" + }, + { + "CIMType": "UInt32", + "Name": "numberOfOccurrences", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "recurrenceTimeZone", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "startDate", + "Option": "Required" + }, + { + "CIMType": "String", + "Name": "type", + "Option": "Required" + } + ] + }, + { + "ClassName": "MSFT_AADRoleAssignmentScheduleRequestScheduleRecurrencePattern", + "Parameters": [ + { + "CIMType": "UInt32", + "Name": "dayOfMonth", + "Option": "Write" + }, + { + "CIMType": "String[]", + "Name": "daysOfWeek", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "firstDayOfWeek", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "index", + "Option": "Write" + }, + { + "CIMType": "UInt32", + "Name": "interval", + "Option": "Write" + }, + { + "CIMType": "UInt32", + "Name": "month", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "type", + "Option": "Write" + } + ] + }, + { + "ClassName": "MSFT_AADRoleAssignmentScheduleRequestScheduleRecurrence", + "Parameters": [ + { + "CIMType": "MSFT_AADRoleAssignmentScheduleRequestScheduleRecurrencePattern", + "Name": "pattern", + "Option": "Write" + }, + { + "CIMType": "MSFT_AADRoleAssignmentScheduleRequestScheduleRecurrenceRange", + "Name": "range", + "Option": "Write" + } + ] + }, + { + "ClassName": "MSFT_AADRoleAssignmentScheduleRequestScheduleExpiration", + "Parameters": [ + { + "CIMType": "String", + "Name": "duration", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "endDateTime", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "type", + "Option": "Write" + } + ] + }, + { + "ClassName": "MSFT_AADRoleAssignmentScheduleRequestSchedule", + "Parameters": [ + { + "CIMType": "MSFT_AADRoleAssignmentScheduleRequestScheduleExpiration", + "Name": "expiration", + "Option": "Write" + }, + { + "CIMType": "MSFT_AADRoleAssignmentScheduleRequestScheduleRecurrence", + "Name": "recurrence", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "startDateTime", + "Option": "Write" + } + ] + }, + { + "ClassName": "MSFT_AADRoleAssignmentScheduleRequestTicketInfo", + "Parameters": [ + { + "CIMType": "String", + "Name": "ticketNumber", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "ticketSystem", + "Option": "Write" + } + ] + }, + { + "ClassName": "MSFT_AADRoleAssignmentScheduleRequest", + "Parameters": [ + { + "CIMType": "String", + "Name": "Principal", + "Option": "Key" + }, + { + "CIMType": "String", + "Name": "RoleDefinition", + "Option": "Key" + }, + { + "CIMType": "String", + "Name": "PrincipalType", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "DirectoryScopeId", + "Option": "Key" + }, + { + "CIMType": "String", + "Name": "Id", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "AppScopeId", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "Action", + "Option": "Write" + }, + { + "CIMType": "Boolean", + "Name": "IsValidationOnly", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "Justification", + "Option": "Write" + }, + { + "CIMType": "MSFT_AADRoleAssignmentScheduleRequestSchedule", + "Name": "ScheduleInfo", + "Option": "Write" + }, + { + "CIMType": "MSFT_AADRoleAssignmentScheduleRequestTicketInfo", + "Name": "TicketInfo", + "Option": "Write" + }, + { + "CIMType": "string", + "Name": "Ensure", + "Option": "Write" + }, + { + "CIMType": "MSFT_Credential", + "Name": "Credential", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "ApplicationId", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "TenantId", + "Option": "Write" + }, + { + "CIMType": "MSFT_Credential", + "Name": "ApplicationSecret", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "CertificateThumbprint", + "Option": "Write" + }, + { + "CIMType": "Boolean", + "Name": "ManagedIdentity", + "Option": "Write" + }, + { + "CIMType": "String[]", + "Name": "AccessTokens", + "Option": "Write" + } + ] + }, { "ClassName": "MSFT_AADRoleDefinition", "Parameters": [ From 6da6b80a9a26aa840fa31482d87eb55f24d32db0 Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Tue, 19 Nov 2024 11:27:57 -0500 Subject: [PATCH 45/65] AADRoleEligibilityScheduleRequest - Improvements --- CHANGELOG.md | 1 + ...SFT_AADRoleEligibilityScheduleRequest.psm1 | 270 ++++++------------ ...DRoleEligibilityScheduleRequest.schema.mof | 2 +- 3 files changed, 91 insertions(+), 182 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 90aa028eef..384174c018 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,6 +49,7 @@ * Initial release. * AADRoleEligibilityScheduleRequest * Adds support for custom role assignments at app scope. + FIXES [#5415](https://github.com/microsoft/Microsoft365DSC/issues/5415) * AzureBillingAccountPolicy * Initial release. * IntuneDeviceConfigurationPolicyAndroidDeviceOwner diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleEligibilityScheduleRequest/MSFT_AADRoleEligibilityScheduleRequest.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleEligibilityScheduleRequest/MSFT_AADRoleEligibilityScheduleRequest.psm1 index 51c06e3cf2..6ebb336f0d 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleEligibilityScheduleRequest/MSFT_AADRoleEligibilityScheduleRequest.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleEligibilityScheduleRequest/MSFT_AADRoleEligibilityScheduleRequest.psm1 @@ -12,16 +12,16 @@ [System.String] $RoleDefinition, - [Parameter()] - [ValidateSet('User', 'Group')] + [Parameter(Mandatory = $true)] + [ValidateSet('User', 'Group', 'ServicePrincipal')] [System.String] - $PrincipalType = 'User', + $PrincipalType, [Parameter()] [System.String] $Id, - [Parameter()] + [Parameter(Mandatory = $true)] [System.String] $DirectoryScopeId, @@ -83,18 +83,11 @@ [System.String[]] $AccessTokens ) - try - { - $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` - -InboundParameters $PSBoundParameters - } - catch - { - Write-Verbose -Message ($_) - } + $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` + -InboundParameters $PSBoundParameters - #Ensure the proper dependencies are installed in the current environment. - Confirm-M365DSCDependencies + #Ensure the proper dependencies are installed in the current environment. + Confirm-M365DSCDependencies #region Telemetry $ResourceName = $MyInvocation.MyCommand.ModuleName.Replace('MSFT_', '') @@ -124,137 +117,58 @@ } } - if ($null -eq $request) + Write-Verbose -Message "Getting Role Eligibility by PrincipalId and RoleDefinitionId" + $PrincipalValue = $null + if ($PrincipalType -eq 'User') { - if ($null -ne $Script:exportedInstances -and $Script:ExportMode) - { - Write-Verbose -Message "Getting Role Eligibility by PrincipalId and RoleDefinitionId" - $PrincipalTypeValue = $null - if ($PrincipalType -eq 'User') - { - Write-Verbose -Message "Retrieving Principal by UserPrincipalName {$Principal}" - $PrincipalIdValue = Get-MgUser -Filter "UserPrincipalName eq '$Principal'" -ErrorAction SilentlyContinue - $PrincipalTypeValue = 'User' - } - if ($null -eq $PrincipalIdValue -or $PrincipalType -eq 'Group') - { - Write-Verbose -Message "Retrieving Principal by DisplayName {$Principal}" - $PrincipalIdValue = Get-MgGroup -Filter "DisplayName eq '$Principal'" -ErrorAction SilentlyContinue - $PrincipalTypeValue = 'Group' - } - - if ($null -ne $PrincipalIdValue) - { - $PrincipalId = $PrincipalIdValue.Id - } - else - { - return $nullResult - } - Write-Verbose -Message "Found Principal {$PrincipalId}" - $RoleDefinitionId = (Get-MgBetaRoleManagementDirectoryRoleDefinition -Filter "DisplayName eq '$RoleDefinition'").Id - $request = $Script:exportedInstances | Where-Object -FilterScript {$_.PrincipalId -eq $PrincipalId -and $_.RoleDefinitionId -eq $RoleDefinition} | Sort-Object -Property CompletedDateTime -Descending - } - else - { - Write-Verbose -Message "Getting Role Eligibility by PrincipalId and RoleDefinitionId" - if ($PrincipalType -eq 'User') - { - Write-Verbose -Message "Retrieving principal {$Principal} of type {$PrincipalType}" - $PrincipalIdValue = Get-MgUser -Filter "UserPrincipalName eq '$Principal'" -ErrorAction SilentlyContinue - $PrincipalTypeValue = 'User' - } - - if ($null -eq $PrincipalIdValue -or $PrincipalType -eq 'Group') - { - Write-Verbose -Message "Retrieving principal {$Principal} of type {$PrincipalType}" - $PrincipalIdValue = Get-MgGroup -Filter "DisplayName eq '$Principal'" -ErrorAction SilentlyContinue - $PrincipalTypeValue = 'Group' - } - - if ($null -ne $PrincipalIdValue) - { - $PrincipalId = $PrincipalIdValue.Id - } - else - { - return $nullResult - } - Write-Verbose -Message "Found Principal {$PrincipalId}" - $schedulesForPrincipal = Get-MgBetaRoleManagementDirectoryRoleEligibilitySchedule -Filter "PrincipalId eq '$PrincipalId'" - foreach ($instance in $schedulesForPrincipal) - { - $roleInfo = Get-MgBetaRoleManagementDirectoryRoleDefinition -UnifiedRoleDefinitionId $instance.RoleDefinitionId - if ($roleInfo.DisplayName -eq $RoleDefinition) - { - $schedule = $instance - } - } - [Array]$request = Get-MgBetaRoleManagementDirectoryRoleEligibilityScheduleRequest -Filter "PrincipalId eq '$PrincipalId'" | Where-Object -FilterScript {$_.RoleDefinitionId -eq $schedule.RoleDefinitionId} | Sort-Object -Property CompletedDateTime -Descending -` - if ($request.Length -gt 1) - { - $request = $request[0] - } - } + Write-Verbose -Message "Retrieving Principal by UserPrincipalName {$Principal}" + $PrincipalInstance = Get-MgUser -Filter "UserPrincipalName eq '$Principal'" -ErrorAction SilentlyContinue + $PrincipalValue = $PrincipalInstance.UserPrincipalName + } + elseif ($null -eq $PrincipalIdValue -and $PrincipalType -eq 'Group') + { + Write-Verbose -Message "Retrieving Principal by DisplayName {$Principal}" + $PrincipalInstance = Get-MgGroup -Filter "DisplayName eq '$Principal'" -ErrorAction SilentlyContinue + $PrincipalValue = $PrincipalInstance.DisplayName } else { - Write-Verbose -Message "Request is not null: $request" - $ObjectGuid = [System.Guid]::empty - if ($PrincipalType -eq 'User') - { - Write-Verbose -Message "Retrieving principal {$Principal} of type {$PrincipalType}" - - if ([System.Guid]::TryParse($Principal,[System.Management.Automation.PSReference]$ObjectGuid)) - { - $PrincipalIdValue = Get-MgUser -UserId $Principal -ErrorAction SilentlyContinue - } - else - { - $PrincipalIdValue = Get-MgUser -Filter "UserPrincipalName eq '$Principal'" -ErrorAction SilentlyContinue - } - $PrincipalTypeValue = 'User' - } + Write-Verbose -Message "Retrieving Principal by DisplayName {$Principal}" + $PrincipalInstance = Get-MgServicePrincipal -Filter "DisplayName eq '$Principal'" -ErrorAction SilentlyContinue + $PrincipalValue = $PrincipalInstance.DisplayName + } - if ($null -eq $PrincipalIdValue -or $PrincipalType -eq 'Group') - { - Write-Verbose -Message "Retrieving principal {$Principal} of type {$PrincipalType}" - if ([System.Guid]::TryParse($Principal,[System.Management.Automation.PSReference]$ObjectGuid)) - { - $PrincipalIdValue = Get-MgGroup -GroupId $Principal -ErrorAction SilentlyContinue - } - else - { - $PrincipalIdValue = Get-MgGroup -Filter "DisplayName eq '$Principal'" -ErrorAction SilentlyContinue - } - $PrincipalTypeValue = 'Group' - } + Write-Verbose -Message "Found Principal" + $RoleDefinitionId = (Get-MgBetaRoleManagementDirectoryRoleDefinition -Filter "DisplayName eq '$RoleDefinition'").Id + Write-Verbose -Message "Retrieved role definition {$RoleDefinition} with ID {$RoleDefinitionId}" - if ($null -ne $PrincipalIdValue) - { - $PrincipalId = $PrincipalIdValue.Id - } - else + if ($null -eq $request) + { + Write-Verbose -Message "Retrieving the request by PrincipalId {$($PrincipalInstance.Id)}, RoleDefinitionId {$($RoleDefinitionId)} and DirectoryScopeId {$($DirectoryScopeId)}" + [Array] $requests = Get-MgBetaRoleManagementDirectoryRoleEligibilityScheduleRequest -Filter "PrincipalId eq '$($PrincipalInstance.Id)' and RoleDefinitionId eq '$($RoleDefinitionId)' and DirectoryScopeId eq '$($DirectoryScopeId)'" + if ($requests.Length -eq 0) { return $nullResult } - $RoleDefinitionId = (Get-MgBetaRoleManagementDirectoryRoleDefinition -Filter "DisplayName eq '$RoleDefinition'").Id - $schedules = Get-MgBetaRoleManagementDirectoryRoleEligibilitySchedule -Filter "PrincipalId eq '$($request.PrincipalId)'" - $schedule = $schedules | Where-Object -FilterScript {$_.RoleDefinitionId -eq $RoleDefinitionId} - if ($null -eq $schedule) + + $request = $requests[0] + } + + $schedules = Get-MgBetaRoleManagementDirectoryRoleEligibilitySchedule -Filter "PrincipalId eq '$($request.PrincipalId)'" + $schedule = $schedules | Where-Object -FilterScript {$_.RoleDefinitionId -eq $RoleDefinitionId} + if ($null -eq $schedule) + { + foreach ($instance in $schedules) { - foreach ($instance in $schedules) + $roleDefinitionInfo = Get-MgBetaRoleManagementDirectoryRoleDefinition -UnifiedRoleDefinitionId $instance.RoleDefinitionId + if ($null -ne $roleDefinitionInfo -and $RoleDefinitionInfo.DisplayName -eq $RoleDefinition) { - $roleDefinitionInfo = Get-MgBetaRoleManagementDirectoryRoleDefinition -UnifiedRoleDefinitionId $instance.RoleDefinitionId - if ($null -ne $roleDefinitionInfo -and $RoleDefinitionInfo.DisplayName -eq $RoleDefinition) - { - $schedule = $instance - break - } + $schedule = $instance + break } } } + if ($null -eq $schedule -or $null -eq $request) { if ($null -eq $schedule) @@ -268,32 +182,6 @@ return $nullResult } - Write-Verbose -Message "Found existing AADRolelLigibilityScheduleRequest" - if ($PrincipalType -eq 'User') - { - Write-Verbose -Message "Retrieving Principal by UserId {$($request.PrincipalId)}" - $PrincipalInstance = Get-MgUser -UserId $request.PrincipalId -ErrorAction SilentlyContinue - $PrincipalTypeValue = 'User' - } - if ($null -eq $PrincipalInstance -or $PrincipalType -eq 'Group') - { - Write-Verbose -Message "Retrieving Principal by GroupId {$($request.PrincipalId)}" - $requestArray = [Array]$request - if ($requestArray.Count -gt 1) - { - $requestArray = $requestArray | Sort-Object -Property CreatedDateTime -Descending - $request = $requestArray[0] - } - $PrincipalInstance = Get-MGGroup -GroupId $request.PrincipalId -ErrorAction SilentlyContinue - $PrincipalTypeValue = 'Group' - } - - if ($null -eq $PrincipalInstance) - { - Write-Verbose -Message "Couldn't retrieve Principal {$($request.PrincipalId)}" - return $nullResult - } - $ScheduleInfoValue = @{} if ($null -ne $schedule.ScheduleInfo.Expiration) @@ -344,19 +232,9 @@ } } - $PrincipalValue = $null - if ($PrincipalType -eq 'User') - { - $PrincipalValue = $PrincipalInstance.UserPrincipalName - } - if ($null -eq $PrincipalValue -or $PrincipalTypeValue -eq 'Group') - { - $PrincipalValue = $PrincipalInstance.DisplayName - } - $results = @{ Principal = $PrincipalValue - PrincipalType = $PrincipalTypeValue + PrincipalType = $PrincipalType RoleDefinition = $RoleDefinition DirectoryScopeId = $request.DirectoryScopeId AppScopeId = $request.AppScopeId @@ -403,16 +281,16 @@ function Set-TargetResource [System.String] $RoleDefinition, - [Parameter()] - [ValidateSet('User', 'Group')] + [Parameter(Mandatory = $true)] + [ValidateSet('User', 'Group', 'ServicePrincipal')] [System.String] - $PrincipalType = 'User', + $PrincipalType, [Parameter()] [System.String] $Id, - [Parameter()] + [Parameter(Mandatory = $true)] [System.String] $DirectoryScopeId, @@ -518,6 +396,10 @@ function Set-TargetResource { [Array]$PrincipalIdValue = (Get-MgGroup -Filter "DisplayName eq '$Principal'").Id } + elseif ($PrincipalType -eq 'ServicePrincipal') + { + [Array]$PrincipalIdValue = (Get-MgServicePrincipal -Filter "DisplayName eq '$Principal'").Id + } if ($null -eq $PrincipalIdValue) { @@ -598,21 +480,21 @@ function Set-TargetResource $ParametersOps.Remove("PrincipalType") | Out-Null if ($Ensure -eq 'Present' -and $currentInstance.Ensure -eq 'Absent') { - Write-Verbose -Message "Creating a Role Eligibility Schedule Request for user {$Principal} and role {$RoleDefinition}" + Write-Verbose -Message "Creating a Role Assignment Schedule Request for principal {$Principal} and role {$RoleDefinition}" $ParametersOps.Remove("Id") | Out-Null Write-Verbose -Message "Values: $(Convert-M365DscHashtableToString -Hashtable $ParametersOps)" New-MgBetaRoleManagementDirectoryRoleEligibilityScheduleRequest @ParametersOps } elseif ($Ensure -eq 'Present' -and $currentInstance.Ensure -eq 'Present') { - Write-Verbose -Message "Updating the Role Eligibility Schedule Request for user {$Principal} and role {$RoleDefinition}" + Write-Verbose -Message "Updating the Role Assignment Schedule Request for principal {$Principal} and role {$RoleDefinition}" $ParametersOps.Remove("Id") | Out-Null $ParametersOps.Action = 'AdminUpdate' New-MgBetaRoleManagementDirectoryRoleEligibilityScheduleRequest @ParametersOps } elseif ($Ensure -eq 'Absent' -and $currentInstance.Ensure -eq 'Present') { - Write-Verbose -Message "Removing the Role Eligibility Schedule Request for user {$Principal} and role {$RoleDefinition}" + Write-Verbose -Message "Removing the Role Assignment Schedule Request for principal {$Principal} and role {$RoleDefinition}" $ParametersOps.Remove("Id") | Out-Null $ParametersOps.Action = 'AdminRemove' New-MgBetaRoleManagementDirectoryRoleEligibilityScheduleRequest @ParametersOps @@ -633,16 +515,16 @@ function Test-TargetResource [System.String] $RoleDefinition, - [Parameter()] - [ValidateSet('User', 'Group')] + [Parameter(Mandatory = $true)] + [ValidateSet('User', 'Group', 'ServicePrincipal')] [System.String] - $PrincipalType = 'User', + $PrincipalType, [Parameter()] [System.String] $Id, - [Parameter()] + [Parameter(Mandatory = $true)] [System.String] $DirectoryScopeId, @@ -862,10 +744,36 @@ function Export-TargetResource $displayedKey = $request.Id Write-Host " |---[$i/$($Script:exportedInstances.Count)] $displayedKey" -NoNewline + # Find the Principal Type + $principalType = 'User' + $userInfo = Get-MgUser -UserId $request.PrincipalId -ErrorAction SilentlyContinue + + if ($null -eq $userInfo) + { + $principalType = 'Group' + $groupInfo = Get-MgGroup -GroupId $request.PrincipalId -ErrorAction SilentlyContinue + if ($null -eq $groupInfo) + { + $principalType = 'ServicePrincipal' + $spnInfo = Get-MgServicePrincipal -ServicePrincipalId $request.PrincipalId + $PrincipalValue = $spnInfo.DisplayName + } + else + { + $PrincipalValue = $groupInfo.DisplayName + } + } + else + { + $PrincipalValue = $userInfo.UserPrincipalName + } + $RoleDefinitionId = Get-MgBetaRoleManagementDirectoryRoleDefinition -UnifiedRoleDefinitionId $request.RoleDefinitionId $params = @{ Id = $request.Id - Principal = $request.PrincipalId + Principal = $PrincipalValue + PrincipalType = $principalType + DirectoryScopeId = $request.DirectoryScopeId RoleDefinition = $RoleDefinitionId.DisplayName Ensure = 'Present' Credential = $Credential diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleEligibilityScheduleRequest/MSFT_AADRoleEligibilityScheduleRequest.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleEligibilityScheduleRequest/MSFT_AADRoleEligibilityScheduleRequest.schema.mof index e679dd288e..7e81112f40 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleEligibilityScheduleRequest/MSFT_AADRoleEligibilityScheduleRequest.schema.mof +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleEligibilityScheduleRequest/MSFT_AADRoleEligibilityScheduleRequest.schema.mof @@ -56,7 +56,7 @@ class MSFT_AADRoleEligibilityScheduleRequest : OMI_BaseResource [Key, Description("User Principal Name of the eligibility request.")] String Principal; [Key, Description("Role associated with the eligibility request.")] String RoleDefinition; [Write, Description("Represented the type of principal to assign the request to. Accepted values are: Group and User."), ValueMap{"Group","User"}, Values{"Group","User"}] String PrincipalType; - [Write, Description("Identifier of the directory object representing the scope of the role eligibility. The scope of an role eligibility determines the set of resources for which the principal has been granted access. Directory scopes are shared scopes stored in the directory that are understood by multiple applications. Use / for tenant-wide scope. Use appScopeId to limit the scope to an application only. Either directoryScopeId or appScopeId is required.")] String DirectoryScopeId; + [Key, Description("Identifier of the directory object representing the scope of the role eligibility. The scope of an role eligibility determines the set of resources for which the principal has been granted access. Directory scopes are shared scopes stored in the directory that are understood by multiple applications. Use / for tenant-wide scope. Use appScopeId to limit the scope to an application only. Either directoryScopeId or appScopeId is required.")] String DirectoryScopeId; [Write, Description("Identifier for the Role Eligibility Schedule Request.")] String Id; [Write, Description("Identifier of the app-specific scope when the role eligibility is scoped to an app. The scope of a role eligibility determines the set of resources for which the principal is eligible to access. App scopes are scopes that are defined and understood by this application only. Use / for tenant-wide app scopes. Use directoryScopeId to limit the scope to particular directory objects, for example, administrative units. Either directoryScopeId or appScopeId is required.")] String AppScopeId; [Write, Description("Represents the type of operation on the role eligibility request.The possible values are: adminAssign, adminUpdate, adminRemove, selfActivate, selfDeactivate, adminExtend, adminRenew, selfExtend, selfRenew, unknownFutureValue."), ValueMap{"adminAssign","adminUpdate","adminRemove","selfActivate","selfDeactivate","adminExtend","adminRenew","selfExtend","selfRenew","unknownFutureValue"}, Values{"adminAssign","adminUpdate","adminRemove","selfActivate","selfDeactivate","adminExtend","adminRenew","selfExtend","selfRenew","unknownFutureValue"}] String Action; From 2b349d7a33d4da94db3b239423a9e7ce908889d4 Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Tue, 19 Nov 2024 11:49:38 -0500 Subject: [PATCH 46/65] Update Microsoft365DSC.AADRoleEligibilityScheduleRequest.Tests.ps1 --- ...icrosoft365DSC.AADRoleEligibilityScheduleRequest.Tests.ps1 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADRoleEligibilityScheduleRequest.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADRoleEligibilityScheduleRequest.Tests.ps1 index be713c3108..6f84a2bcd2 100644 --- a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADRoleEligibilityScheduleRequest.Tests.ps1 +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADRoleEligibilityScheduleRequest.Tests.ps1 @@ -74,6 +74,7 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { Ensure = "Present"; IsValidationOnly = $False; Principal = "John.Smith@contoso.com"; + PrincipalType = "User" RoleDefinition = "Teams Communications Administrator"; ScheduleInfo = New-CimInstance -ClassName MSFT_AADRoleEligibilityScheduleRequestSchedule -Property @{ startDateTime = '2023-09-01T02:40:44Z' @@ -108,6 +109,7 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { DirectoryScopeId = "/"; Ensure = "Absent"; IsValidationOnly = $False; + PrincipalType = "User" Principal = "John.Smith@contoso.com"; RoleDefinition = "Teams Communications Administrator"; ScheduleInfo = New-CimInstance -ClassName MSFT_AADRoleEligibilityScheduleRequestSchedule -Property @{ @@ -159,6 +161,7 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { DirectoryScopeId = "/"; Ensure = "Present"; IsValidationOnly = $False; + PrincipalType = "User" Principal = "John.Smith@contoso.com"; RoleDefinition = "Teams Communications Administrator"; ScheduleInfo = New-CimInstance -ClassName MSFT_AADRoleEligibilityScheduleRequestSchedule -Property @{ @@ -217,6 +220,7 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { DirectoryScopeId = "/"; Ensure = "Present"; IsValidationOnly = $False; + PrincipalType = "User" Principal = "John.Smith@contoso.com"; RoleDefinition = "Teams Communications Administrator"; ScheduleInfo = New-CimInstance -ClassName MSFT_AADRoleEligibilityScheduleRequestSchedule -Property @{ From f306d8138109ca6d911d0d5b222f03963188e314 Mon Sep 17 00:00:00 2001 From: NikCharlebois Date: Tue, 19 Nov 2024 18:03:48 +0000 Subject: [PATCH 47/65] Updated Resources and Cmdlet documentation pages --- .../resources/azure-ad/AADRoleEligibilityScheduleRequest.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/resources/azure-ad/AADRoleEligibilityScheduleRequest.md b/docs/docs/resources/azure-ad/AADRoleEligibilityScheduleRequest.md index 112b40bd04..2091ca9513 100644 --- a/docs/docs/resources/azure-ad/AADRoleEligibilityScheduleRequest.md +++ b/docs/docs/resources/azure-ad/AADRoleEligibilityScheduleRequest.md @@ -7,7 +7,7 @@ | **Principal** | Key | String | User Principal Name of the eligibility request. | | | **RoleDefinition** | Key | String | Role associated with the eligibility request. | | | **PrincipalType** | Write | String | Represented the type of principal to assign the request to. Accepted values are: Group and User. | `Group`, `User` | -| **DirectoryScopeId** | Write | String | Identifier of the directory object representing the scope of the role eligibility. The scope of an role eligibility determines the set of resources for which the principal has been granted access. Directory scopes are shared scopes stored in the directory that are understood by multiple applications. Use / for tenant-wide scope. Use appScopeId to limit the scope to an application only. Either directoryScopeId or appScopeId is required. | | +| **DirectoryScopeId** | Key | String | Identifier of the directory object representing the scope of the role eligibility. The scope of an role eligibility determines the set of resources for which the principal has been granted access. Directory scopes are shared scopes stored in the directory that are understood by multiple applications. Use / for tenant-wide scope. Use appScopeId to limit the scope to an application only. Either directoryScopeId or appScopeId is required. | | | **Id** | Write | String | Identifier for the Role Eligibility Schedule Request. | | | **AppScopeId** | Write | String | Identifier of the app-specific scope when the role eligibility is scoped to an app. The scope of a role eligibility determines the set of resources for which the principal is eligible to access. App scopes are scopes that are defined and understood by this application only. Use / for tenant-wide app scopes. Use directoryScopeId to limit the scope to particular directory objects, for example, administrative units. Either directoryScopeId or appScopeId is required. | | | **Action** | Write | String | Represents the type of operation on the role eligibility request.The possible values are: adminAssign, adminUpdate, adminRemove, selfActivate, selfDeactivate, adminExtend, adminRenew, selfExtend, selfRenew, unknownFutureValue. | `adminAssign`, `adminUpdate`, `adminRemove`, `selfActivate`, `selfDeactivate`, `adminExtend`, `adminRenew`, `selfExtend`, `selfRenew`, `unknownFutureValue` | From 1a5aa1809f55f6bfa1b6c55d28f6193b8b271d58 Mon Sep 17 00:00:00 2001 From: NikCharlebois Date: Tue, 19 Nov 2024 18:06:40 +0000 Subject: [PATCH 48/65] Updated Schema Definition --- Modules/Microsoft365DSC/SchemaDefinition.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/Microsoft365DSC/SchemaDefinition.json b/Modules/Microsoft365DSC/SchemaDefinition.json index ca31d9dd0c..97d7c64e53 100644 --- a/Modules/Microsoft365DSC/SchemaDefinition.json +++ b/Modules/Microsoft365DSC/SchemaDefinition.json @@ -8210,7 +8210,7 @@ { "CIMType": "String", "Name": "DirectoryScopeId", - "Option": "Write" + "Option": "Key" }, { "CIMType": "String", From 7f907f5584f33756bd94f971bd1548951c9df293 Mon Sep 17 00:00:00 2001 From: NikCharlebois Date: Tue, 19 Nov 2024 18:49:28 +0000 Subject: [PATCH 49/65] Updated Resources and Cmdlet documentation pages --- .../IntuneDiskEncryptionPDEPolicyWindows10.md | 195 ++++++++++++++++++ 1 file changed, 195 insertions(+) create mode 100644 docs/docs/resources/intune/IntuneDiskEncryptionPDEPolicyWindows10.md diff --git a/docs/docs/resources/intune/IntuneDiskEncryptionPDEPolicyWindows10.md b/docs/docs/resources/intune/IntuneDiskEncryptionPDEPolicyWindows10.md new file mode 100644 index 0000000000..9ce02d8f49 --- /dev/null +++ b/docs/docs/resources/intune/IntuneDiskEncryptionPDEPolicyWindows10.md @@ -0,0 +1,195 @@ +# IntuneDiskEncryptionPDEPolicyWindows10 + +## Parameters + +| Parameter | Attribute | DataType | Description | Allowed Values | +| --- | --- | --- | --- | --- | +| **Description** | Write | String | Policy description | | +| **DisplayName** | Key | String | Policy name | | +| **RoleScopeTagIds** | Write | StringArray[] | List of Scope Tags for this Entity instance. | | +| **Id** | Write | String | The unique identifier for an entity. Read-only. | | +| **EnablePersonalDataEncryption** | Write | String | Enable Personal Data Encryption (User) (0: Disable Personal Data Encryption., 1: Enable Personal Data Encryption.) | `0`, `1` | +| **ProtectDesktop** | Write | String | Protect Desktop (User) (Windows Insiders only) - Depends on EnablePersonalDataEncryption (0: Disable PDE on the folder. If the folder is currently protected by PDE, this will result in unprotecting the folder., 1: Enable PDE on the folder.) | `0`, `1` | +| **ProtectPictures** | Write | String | Protect Pictures (User) (Windows Insiders only) - Depends on EnablePersonalDataEncryption (0: Disable PDE on the folder. If the folder is currently protected by PDE, this will result in unprotecting the folder., 1: Enable PDE on the folder.) | `0`, `1` | +| **ProtectDocuments** | Write | String | Protect Documents (User) (Windows Insiders only) - Depends on EnablePersonalDataEncryption (0: Disable PDE on the folder. If the folder is currently protected by PDE, this will result in unprotecting the folder., 1: Enable PDE on the folder.) | `0`, `1` | +| **Assignments** | Write | MSFT_DeviceManagementConfigurationPolicyAssignments[] | Represents the assignment to the Intune policy. | | +| **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. | | +| **AccessTokens** | Write | StringArray[] | Access token used for authentication. | | + +### MSFT_DeviceManagementConfigurationPolicyAssignments + +#### Parameters + +| Parameter | Attribute | DataType | Description | Allowed Values | +| --- | --- | --- | --- | --- | +| **dataType** | Write | String | The type of the target assignment. | `#microsoft.graph.groupAssignmentTarget`, `#microsoft.graph.allLicensedUsersAssignmentTarget`, `#microsoft.graph.allDevicesAssignmentTarget`, `#microsoft.graph.exclusionGroupAssignmentTarget`, `#microsoft.graph.configurationManagerCollectionAssignmentTarget` | +| **deviceAndAppManagementAssignmentFilterType** | Write | String | The type of filter of the target assignment i.e. Exclude or Include. Possible values are:none, include, exclude. | `none`, `include`, `exclude` | +| **deviceAndAppManagementAssignmentFilterId** | Write | String | The Id of the filter for the target assignment. | | +| **groupId** | Write | String | The group Id that is the target of the assignment. | | +| **groupDisplayName** | Write | String | The group Display Name that is the target of the assignment. | | +| **collectionId** | Write | String | The collection Id that is the target of the assignment.(ConfigMgr) | | + + +## Description + +Intune Disk Encryption Personal Data Encryption Policy for Windows10 + +## Permissions + +### Microsoft Graph + +To authenticate with the Microsoft Graph API, this resource required the following permissions: + +#### Delegated permissions + +- **Read** + + - DeviceManagementConfiguration.Read.All, Group.Read.All + +- **Update** + + - DeviceManagementConfiguration.ReadWrite.All, Group.Read.All + +#### Application permissions + +- **Read** + + - DeviceManagementConfiguration.Read.All, Group.Read.All + +- **Update** + + - DeviceManagementConfiguration.ReadWrite.All, Group.Read.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()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint + ) + Import-DscResource -ModuleName Microsoft365DSC + + node localhost + { + IntuneDiskEncryptionPDEPolicyWindows10 "IntuneDiskEncryptionPDEPolicyWindows10" + { + Assignments = @(); + Description = "test"; + DisplayName = "test"; + Ensure = "Present"; + EnablePersonalDataEncryption = "1"; + ProtectDesktop = "0"; + ProtectDocuments = "0"; + ProtectPictures = "0"; + RoleScopeTagIds = @("0"); + ApplicationId = $ApplicationId; + TenantId = $TenantId; + CertificateThumbprint = $CertificateThumbprint; + } + } +} +``` + +### Example 2 + +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()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint + ) + Import-DscResource -ModuleName Microsoft365DSC + + node localhost + { + IntuneDiskEncryptionPDEPolicyWindows10 "IntuneDiskEncryptionPDEPolicyWindows10" + { + Assignments = @(); + Description = "test"; + DisplayName = "test"; + Ensure = "Present"; + EnablePersonalDataEncryption = "1"; + ProtectDesktop = "0"; + ProtectDocuments = "1"; # Updated property + ProtectPictures = "1"; # Updated property + RoleScopeTagIds = @("0"); + ApplicationId = $ApplicationId; + TenantId = $TenantId; + CertificateThumbprint = $CertificateThumbprint; + } + } +} +``` + +### Example 3 + +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()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint + ) + Import-DscResource -ModuleName Microsoft365DSC + + node localhost + { + IntuneDiskEncryptionPDEPolicyWindows10 "IntuneDiskEncryptionPDEPolicyWindows10" + { + DisplayName = "test"; + Ensure = "Absent"; + ApplicationId = $ApplicationId; + TenantId = $TenantId; + CertificateThumbprint = $CertificateThumbprint; + } + } +} +``` + From cb7b94e5eecb71657116b23f28860de596dae00b Mon Sep 17 00:00:00 2001 From: NikCharlebois Date: Tue, 19 Nov 2024 18:51:56 +0000 Subject: [PATCH 50/65] Updated Schema Definition --- Modules/Microsoft365DSC/SchemaDefinition.json | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/Modules/Microsoft365DSC/SchemaDefinition.json b/Modules/Microsoft365DSC/SchemaDefinition.json index 97d7c64e53..8e112519dc 100644 --- a/Modules/Microsoft365DSC/SchemaDefinition.json +++ b/Modules/Microsoft365DSC/SchemaDefinition.json @@ -40540,6 +40540,96 @@ } ] }, + { + "ClassName": "MSFT_IntuneDiskEncryptionPDEPolicyWindows10", + "Parameters": [ + { + "CIMType": "String", + "Name": "Description", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "DisplayName", + "Option": "Key" + }, + { + "CIMType": "String[]", + "Name": "RoleScopeTagIds", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "Id", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "EnablePersonalDataEncryption", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "ProtectDesktop", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "ProtectPictures", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "ProtectDocuments", + "Option": "Write" + }, + { + "CIMType": "MSFT_DeviceManagementConfigurationPolicyAssignments[]", + "Name": "Assignments", + "Option": "Write" + }, + { + "CIMType": "string", + "Name": "Ensure", + "Option": "Write" + }, + { + "CIMType": "MSFT_Credential", + "Name": "Credential", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "ApplicationId", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "TenantId", + "Option": "Write" + }, + { + "CIMType": "MSFT_Credential", + "Name": "ApplicationSecret", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "CertificateThumbprint", + "Option": "Write" + }, + { + "CIMType": "Boolean", + "Name": "ManagedIdentity", + "Option": "Write" + }, + { + "CIMType": "String[]", + "Name": "AccessTokens", + "Option": "Write" + } + ] + }, { "ClassName": "MSFT_IntuneDiskEncryptionWindows10", "Parameters": [ From ba9e95d9942dc58cea783af8d4db89ff31ec6a5c Mon Sep 17 00:00:00 2001 From: NikCharlebois Date: Tue, 19 Nov 2024 18:52:21 +0000 Subject: [PATCH 51/65] Updated {Create} Intune Integration Tests --- .../M365DSCIntegration.INTUNE.Create.Tests.ps1 | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Tests/Integration/Microsoft365DSC/M365DSCIntegration.INTUNE.Create.Tests.ps1 b/Tests/Integration/Microsoft365DSC/M365DSCIntegration.INTUNE.Create.Tests.ps1 index 74d4d62a1b..d9d38af909 100644 --- a/Tests/Integration/Microsoft365DSC/M365DSCIntegration.INTUNE.Create.Tests.ps1 +++ b/Tests/Integration/Microsoft365DSC/M365DSCIntegration.INTUNE.Create.Tests.ps1 @@ -2458,6 +2458,21 @@ TenantId = $TenantId; CertificateThumbprint = $CertificateThumbprint; } + IntuneDiskEncryptionPDEPolicyWindows10 'IntuneDiskEncryptionPDEPolicyWindows10' + { + Assignments = @(); + Description = "test"; + DisplayName = "test"; + Ensure = "Present"; + EnablePersonalDataEncryption = "1"; + ProtectDesktop = "0"; + ProtectDocuments = "0"; + ProtectPictures = "0"; + RoleScopeTagIds = @("0"); + ApplicationId = $ApplicationId; + TenantId = $TenantId; + CertificateThumbprint = $CertificateThumbprint; + } IntuneDiskEncryptionWindows10 'myDiskEncryption' { DisplayName = 'Disk Encryption' From b0adc0128489be261a2ea0be6b4d1e590192530f Mon Sep 17 00:00:00 2001 From: Fabien Tschanz Date: Tue, 19 Nov 2024 22:56:57 +0100 Subject: [PATCH 52/65] Fix example descriptions to match resource name --- .../IntuneFirewallRulesPolicyWindows10ConfigMgr/1-Create.ps1 | 2 +- .../IntuneFirewallRulesPolicyWindows10ConfigMgr/2-Update.ps1 | 2 +- .../IntuneFirewallRulesPolicyWindows10ConfigMgr/3-Remove.ps1 | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/Microsoft365DSC/Examples/Resources/IntuneFirewallRulesPolicyWindows10ConfigMgr/1-Create.ps1 b/Modules/Microsoft365DSC/Examples/Resources/IntuneFirewallRulesPolicyWindows10ConfigMgr/1-Create.ps1 index 7f5c6fcbd7..ed80bb3d12 100644 --- a/Modules/Microsoft365DSC/Examples/Resources/IntuneFirewallRulesPolicyWindows10ConfigMgr/1-Create.ps1 +++ b/Modules/Microsoft365DSC/Examples/Resources/IntuneFirewallRulesPolicyWindows10ConfigMgr/1-Create.ps1 @@ -1,5 +1,5 @@ <# -This example creates a new Intune Firewall Policy for Windows10. +This example creates a new Intune Firewall Rules Policy for Windows10 Configuration Manager. #> Configuration Example diff --git a/Modules/Microsoft365DSC/Examples/Resources/IntuneFirewallRulesPolicyWindows10ConfigMgr/2-Update.ps1 b/Modules/Microsoft365DSC/Examples/Resources/IntuneFirewallRulesPolicyWindows10ConfigMgr/2-Update.ps1 index b45c50a141..443f73bbba 100644 --- a/Modules/Microsoft365DSC/Examples/Resources/IntuneFirewallRulesPolicyWindows10ConfigMgr/2-Update.ps1 +++ b/Modules/Microsoft365DSC/Examples/Resources/IntuneFirewallRulesPolicyWindows10ConfigMgr/2-Update.ps1 @@ -1,5 +1,5 @@ <# -This example updates a Intune Firewall Policy for Windows10. +This example updates a Intune Firewall Rules Policy for Windows10 Configuration Manager. #> Configuration Example diff --git a/Modules/Microsoft365DSC/Examples/Resources/IntuneFirewallRulesPolicyWindows10ConfigMgr/3-Remove.ps1 b/Modules/Microsoft365DSC/Examples/Resources/IntuneFirewallRulesPolicyWindows10ConfigMgr/3-Remove.ps1 index adb77ecb27..064323c5b7 100644 --- a/Modules/Microsoft365DSC/Examples/Resources/IntuneFirewallRulesPolicyWindows10ConfigMgr/3-Remove.ps1 +++ b/Modules/Microsoft365DSC/Examples/Resources/IntuneFirewallRulesPolicyWindows10ConfigMgr/3-Remove.ps1 @@ -1,5 +1,5 @@ <# -This example removes a Device Control Policy. +This example removes a Intune Firewall Rules Policy for Windows10 Configuration Manager. #> Configuration Example From 38c215d0d447271fa9357ac244f7182feb3e7052 Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Tue, 19 Nov 2024 22:57:03 +0100 Subject: [PATCH 53/65] Updated PR template --- .github/PULL_REQUEST_TEMPLATE.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index b2682287f6..d25e9d9c84 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -11,3 +11,23 @@ - Fixes #123 - Fixes #124 --> + +#### Task list + + + +- [ ] Added an entry to the change log under the Unreleased section of the file CHANGELOG.md. + Entry should say what was changed and how that affects users (if applicable), and + reference the issue being resolved (if applicable). +- [ ] Resource parameter descriptions added/updated in the schema.mof. +- [ ] Resource documentation added/updated in README.md. +- [ ] Resource settings.json file contains all required permissions. +- [ ] Examples appropriately added/updated. +- [ ] Unit tests added/updated. +- [ ] New/changed code adheres to [DSC Community Style Guidelines](https://dsccommunity.org/styleguidelines). From b568cfa1de8d7ca184c57c5c065c01b6f5d53d41 Mon Sep 17 00:00:00 2001 From: Fabien Tschanz Date: Wed, 20 Nov 2024 13:12:59 +0100 Subject: [PATCH 54/65] Add verbose message to Get- and Set- method --- .../MSFT_IntuneFirewallRulesPolicyWindows10ConfigMgr.psm1 | 4 ++++ .../Modules/M365DSCIntuneSettingsCatalogUtil.psm1 | 1 + ResourceGenerator/M365DSCResourceGenerator.psm1 | 6 +++++- ResourceGenerator/Module.Template.psm1 | 4 ++++ 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneFirewallRulesPolicyWindows10ConfigMgr/MSFT_IntuneFirewallRulesPolicyWindows10ConfigMgr.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneFirewallRulesPolicyWindows10ConfigMgr/MSFT_IntuneFirewallRulesPolicyWindows10ConfigMgr.psm1 index 1ad95440d6..6ae0abfd01 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneFirewallRulesPolicyWindows10ConfigMgr/MSFT_IntuneFirewallRulesPolicyWindows10ConfigMgr.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneFirewallRulesPolicyWindows10ConfigMgr/MSFT_IntuneFirewallRulesPolicyWindows10ConfigMgr.psm1 @@ -64,6 +64,8 @@ function Get-TargetResource $AccessTokens ) + Write-Verbose -Message "Getting configuration of the Intune Firewall Rules Policy for Windows10 ConfigMgr with Id {$Id} and Name {$DisplayName}" + try { $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` @@ -240,6 +242,8 @@ function Set-TargetResource $AccessTokens ) + Write-Verbose -Message "Setting configuration of the Intune Firewall Rules Policy for Windows10 ConfigMgr with Id {$Id} and Name {$DisplayName}" + #Ensure the proper dependencies are installed in the current environment. Confirm-M365DSCDependencies diff --git a/Modules/Microsoft365DSC/Modules/M365DSCIntuneSettingsCatalogUtil.psm1 b/Modules/Microsoft365DSC/Modules/M365DSCIntuneSettingsCatalogUtil.psm1 index 465189fd7a..795c291c35 100644 --- a/Modules/Microsoft365DSC/Modules/M365DSCIntuneSettingsCatalogUtil.psm1 +++ b/Modules/Microsoft365DSC/Modules/M365DSCIntuneSettingsCatalogUtil.psm1 @@ -99,6 +99,7 @@ 'pub16v3~Policy~L_MicrosoftOfficePublisher~*' { $settingName = $settingName.Replace('pub16v3~Policy~L_MicrosoftOfficePublisher', 'MicrosoftPublisherV3_') } 'microsoft_edge~Policy~microsoft_edge~*' { $settingName = $settingName.Replace('microsoft_edge~Policy~microsoft_edge', 'MicrosoftEdge_') } 'edge~httpauthentication*' { $settingName = $settingName.Replace('edge~httpauthentication', 'MicrosoftEdge_HTTPAuthentication') } + 'edge~contentsettings*' { $settingName = $settingName.Replace('edge~contentsettings', 'MicrosoftEdge_ContentSettings') } '*~L_Security~*' { $settingName = $settingName.Replace('~L_Security', 'Security') } '*~L_TrustCenter*' { $settingName = $settingName.Replace('~L_TrustCenter', '_TrustCenter') } '*~L_ProtectedView_*' { $settingName = $settingName.Replace('~L_ProtectedView', 'ProtectedView') } diff --git a/ResourceGenerator/M365DSCResourceGenerator.psm1 b/ResourceGenerator/M365DSCResourceGenerator.psm1 index 546378e4ee..c23fd156db 100644 --- a/ResourceGenerator/M365DSCResourceGenerator.psm1 +++ b/ResourceGenerator/M365DSCResourceGenerator.psm1 @@ -370,6 +370,10 @@ $($userDefinitionSettings.MOF -join "`r`n") "@ ) } + + $definitionSettings.MOFInstance = ($deviceDefinitionSettings.MOFInstance -join "`r`n") + "`r`n" + ($definitionSettings.MOFInstance -join "`r`n") + $definitionSettings.MOFInstance = ($userDefinitionSettings.MOFInstance -join "`r`n") + "`r`n" + ($definitionSettings.MOFInstance -join "`r`n") + $definitionSettings.MOFInstance = ($defaultDefinitionSettings.MOFInstance -join "`r`n") + "`r`n" + ($definitionSettings.MOFInstance -join "`r`n") } else { @@ -4039,7 +4043,7 @@ class } $mofDefinition = $mofDefinition.Replace("", $TemplateSetting.Name) - $isCollection = ($TemplateSetting.Type -like "*Collection" -and $TemplateSetting.Type -ne "GroupCollection") -or $TemplateSetting.Type -eq "GroupColletionCollection" + $isCollection = ($TemplateSetting.Type -like "*Collection" -and $TemplateSetting.Type -ne "GroupCollection") -or $TemplateSetting.Type -eq "GroupCollectionCollection" $mofDefinition = $mofDefinition.Replace("", $( if ($isCollection) { "[]" } else { "" } )) $powerShellDefinition = $powerShellParameterTemplate.Replace("", $TemplateSetting.Name) diff --git a/ResourceGenerator/Module.Template.psm1 b/ResourceGenerator/Module.Template.psm1 index b389ecfab3..1a58061fe1 100644 --- a/ResourceGenerator/Module.Template.psm1 +++ b/ResourceGenerator/Module.Template.psm1 @@ -41,6 +41,8 @@ function Get-TargetResource $AccessTokens ) + Write-Verbose -Message "Getting configuration of the with {$} and {$}" + try { $ConnectionMode = New-M365DSCConnection -Workload '<#Workload#>' ` @@ -144,6 +146,8 @@ function Set-TargetResource $AccessTokens ) + Write-Verbose -Message "Setting configuration of the with {$} and {$}" + #Ensure the proper dependencies are installed in the current environment. Confirm-M365DSCDependencies From 3d70c541cde836c780e44e643b64f6b6f0570969 Mon Sep 17 00:00:00 2001 From: dannyKBjj Date: Wed, 20 Nov 2024 12:38:11 +0000 Subject: [PATCH 55/65] Fixed issues raised on previous pull request --- CHANGELOG.md | 4 ++-- .../IntuneMobileAppConfigurationPolicyIOS/1-Create.ps1 | 2 -- .../IntuneMobileAppConfigurationPolicyIOS/2-Update.ps1 | 1 + .../IntuneMobileAppConfigurationPolicyIOS/3-Remove.ps1 | 2 -- 4 files changed, 3 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e74f859000..04512b2702 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ * IntuneAntivirusPolicyWindows10SettingCatalog * Update properties to be upper-case. Fixes [#5373](https://github.com/microsoft/Microsoft365DSC/issues/5373) +* IntuneMobileAppConfigurationPolicyIOS + * Initial release. * IntuneSecurityBaselineMicrosoftEdge * Deprecate property `authschemes` and replace with `AuthSchemes_AuthSchemes` * M365DSCDRGUtil @@ -23,8 +25,6 @@ * DEPENDENCIES * Updated DSCParser to version 2.0.0.12. * Updated MSCloudLoginAssistant to version 1.1.28. -* MSFT_IntuneMobileAppConfigurationPolicyIOS - * Initial release. # 1.24.1106.3 diff --git a/Modules/Microsoft365DSC/Examples/Resources/IntuneMobileAppConfigurationPolicyIOS/1-Create.ps1 b/Modules/Microsoft365DSC/Examples/Resources/IntuneMobileAppConfigurationPolicyIOS/1-Create.ps1 index 3a7985ec2b..80d6ca10e7 100644 --- a/Modules/Microsoft365DSC/Examples/Resources/IntuneMobileAppConfigurationPolicyIOS/1-Create.ps1 +++ b/Modules/Microsoft365DSC/Examples/Resources/IntuneMobileAppConfigurationPolicyIOS/1-Create.ps1 @@ -17,8 +17,6 @@ Configuration Example [System.String] $CertificateThumbprint ) - - Import-DscResource -ModuleName 'Microsoft365DSC' Node localhost diff --git a/Modules/Microsoft365DSC/Examples/Resources/IntuneMobileAppConfigurationPolicyIOS/2-Update.ps1 b/Modules/Microsoft365DSC/Examples/Resources/IntuneMobileAppConfigurationPolicyIOS/2-Update.ps1 index 93d0a39b85..860a8c9732 100644 --- a/Modules/Microsoft365DSC/Examples/Resources/IntuneMobileAppConfigurationPolicyIOS/2-Update.ps1 +++ b/Modules/Microsoft365DSC/Examples/Resources/IntuneMobileAppConfigurationPolicyIOS/2-Update.ps1 @@ -17,6 +17,7 @@ Configuration Example [System.String] $CertificateThumbprint ) + Import-DscResource -ModuleName 'Microsoft365DSC' Node localhost { diff --git a/Modules/Microsoft365DSC/Examples/Resources/IntuneMobileAppConfigurationPolicyIOS/3-Remove.ps1 b/Modules/Microsoft365DSC/Examples/Resources/IntuneMobileAppConfigurationPolicyIOS/3-Remove.ps1 index 83d7603515..6e04d55179 100644 --- a/Modules/Microsoft365DSC/Examples/Resources/IntuneMobileAppConfigurationPolicyIOS/3-Remove.ps1 +++ b/Modules/Microsoft365DSC/Examples/Resources/IntuneMobileAppConfigurationPolicyIOS/3-Remove.ps1 @@ -17,8 +17,6 @@ Configuration Example [System.String] $CertificateThumbprint ) - - Import-DscResource -ModuleName 'Microsoft365DSC' Node localhost From 2c386998ace4d1df35888baaeae109a270d1ab78 Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Wed, 20 Nov 2024 07:40:40 -0500 Subject: [PATCH 56/65] SCPolicyConfig - Fixes Extracting Empty Groups --- CHANGELOG.md | 2 ++ .../MSFT_SCPolicyConfig/MSFT_SCPolicyConfig.psm1 | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bf3c189bb1..dda5eb5b0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -65,6 +65,8 @@ * Initial release. * IntuneFirewallRulesHyperVPolicyWindows10 * Initial release. +* SCPolicyConfig + * Fixed an issue extracting empty groups properties. * TeamsUpdateManagementPolicy * Added conversion of the UpdateTimeOfDay parameter to the local culture format so that the comparison will work consistently. diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_SCPolicyConfig/MSFT_SCPolicyConfig.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_SCPolicyConfig/MSFT_SCPolicyConfig.psm1 index 729655eb21..e0f76fbaa1 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_SCPolicyConfig/MSFT_SCPolicyConfig.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_SCPolicyConfig/MSFT_SCPolicyConfig.psm1 @@ -1287,12 +1287,12 @@ function Export-TargetResource $Results.BusinessJustificationList = ConvertTo-BusinessJustificationListString -ObjectHash $Results.BusinessJustificationList } - if ($null -ne $Results.DLPAppGroups) + if ($null -ne $Results.DLPAppGroups -and $Results.DLPAppGroups.Length -gt 0) { $Results.DLPAppGroups = ConvertTo-DLPAppGroupsString -ObjectHash $Results.DLPAppGroups } - if ($null -ne $Results.DLPNetworkShareGroups) + if ($null -ne $Results.DLPNetworkShareGroups -and $Results.DLPNetworkShareGroups.Length -gt 0) { $Results.DLPNetworkShareGroups = ConvertTo-DLPNetworkShareGroupsString -ObjectHash $Results.DLPNetworkShareGroups } @@ -1302,7 +1302,7 @@ function Export-TargetResource $Results.DLPPrinterGroups = ConvertTo-DLPPrinterGroupsString -ObjectHash $Results.DLPPrinterGroups } - if ($null -ne $Results.DLPRemovableMediaGroups) + if ($null -ne $Results.DLPRemovableMediaGroups -and $Results.DLPRemovableMediaGroups.Length -gt 0) { $Results.DLPRemovableMediaGroups = ConvertTo-DLPRemovableMediaGroupsString -ObjectHash $Results.DLPRemovableMediaGroups } @@ -1312,7 +1312,7 @@ function Export-TargetResource $Results.EvidenceStoreSettings = ConvertTo-EvidenceStoreSettingsString -ObjectHash $Results.EvidenceStoreSettings } - if ($null -ne $Results.SiteGroups) + if ($null -ne $Results.SiteGroups -and $Results.SiteGroups.Length -gt 0) { $Results.SiteGroups = ConvertTo-SiteGroupsString -ObjectHash $Results.SiteGroups } From b5e35d7ba236f46cc198706b6edcae87edbdf87e Mon Sep 17 00:00:00 2001 From: NikCharlebois Date: Wed, 20 Nov 2024 13:53:39 +0000 Subject: [PATCH 57/65] Updated Resources and Cmdlet documentation pages --- ...neFirewallRulesPolicyWindows10ConfigMgr.md | 246 ++++++++++++++++++ 1 file changed, 246 insertions(+) create mode 100644 docs/docs/resources/intune/IntuneFirewallRulesPolicyWindows10ConfigMgr.md diff --git a/docs/docs/resources/intune/IntuneFirewallRulesPolicyWindows10ConfigMgr.md b/docs/docs/resources/intune/IntuneFirewallRulesPolicyWindows10ConfigMgr.md new file mode 100644 index 0000000000..378399ca1f --- /dev/null +++ b/docs/docs/resources/intune/IntuneFirewallRulesPolicyWindows10ConfigMgr.md @@ -0,0 +1,246 @@ +# IntuneFirewallRulesPolicyWindows10ConfigMgr + +## Parameters + +| Parameter | Attribute | DataType | Description | Allowed Values | +| --- | --- | --- | --- | --- | +| **Description** | Write | String | Policy description | | +| **DisplayName** | Key | String | Policy name | | +| **RoleScopeTagIds** | Write | StringArray[] | List of Scope Tags for this Entity instance. | | +| **Id** | Write | String | The unique identifier for an entity. Read-only. | | +| **FirewallRuleName** | Write | MSFT_MicrosoftGraphIntuneSettingsCatalogFirewallRuleName_IntuneFirewallRulesPolicyWindows10ConfigMgr[] | Firewall Rules | | +| **Assignments** | Write | MSFT_DeviceManagementConfigurationPolicyAssignments[] | Represents the assignment to the Intune policy. | | +| **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. | | +| **AccessTokens** | Write | StringArray[] | Access token used for authentication. | | + +### MSFT_DeviceManagementConfigurationPolicyAssignments + +#### Parameters + +| Parameter | Attribute | DataType | Description | Allowed Values | +| --- | --- | --- | --- | --- | +| **dataType** | Write | String | The type of the target assignment. | `#microsoft.graph.groupAssignmentTarget`, `#microsoft.graph.allLicensedUsersAssignmentTarget`, `#microsoft.graph.allDevicesAssignmentTarget`, `#microsoft.graph.exclusionGroupAssignmentTarget`, `#microsoft.graph.configurationManagerCollectionAssignmentTarget` | +| **deviceAndAppManagementAssignmentFilterType** | Write | String | The type of filter of the target assignment i.e. Exclude or Include. Possible values are:none, include, exclude. | `none`, `include`, `exclude` | +| **deviceAndAppManagementAssignmentFilterId** | Write | String | The Id of the filter for the target assignment. | | +| **groupId** | Write | String | The group Id that is the target of the assignment. | | +| **groupDisplayName** | Write | String | The group Display Name that is the target of the assignment. | | +| **collectionId** | Write | String | The collection Id that is the target of the assignment.(ConfigMgr) | | + +### MSFT_MicrosoftGraphIntuneSettingsCatalogFirewallRuleName_IntuneFirewallRulesPolicyWindows10ConfigMgr + +#### Parameters + +| Parameter | Attribute | DataType | Description | Allowed Values | +| --- | --- | --- | --- | --- | +| **Enabled** | Write | String | Enabled - Depends on FirewallRuleName (0: Disabled, 1: Enabled) | `0`, `1` | +| **Name** | Write | String | Name - Depends on FirewallRuleName | | +| **InterfaceTypes** | Write | StringArray[] | Interface Types - Depends on FirewallRuleName (remoteaccess: RemoteAccess, wireless: Wireless, lan: Lan, mobilebroadband: MobileBroadband, mbb: MBB, all: All) | `remoteaccess`, `wireless`, `lan`, `mobilebroadband`, `mbb`, `all` | +| **FilePath** | Write | String | File Path - Depends on FirewallRuleName | | +| **RemotePortRanges** | Write | StringArray[] | Remote Port Ranges - Depends on FirewallRuleName | | +| **EdgeTraversal** | Write | String | Edge Traversal - Depends on FirewallRuleName (0: Disabled, 1: Enabled) | `0`, `1` | +| **LocalUserAuthorizedList** | Write | StringArray[] | Local User Authorized List - Depends on FirewallRuleName | | +| **Profiles** | Write | SInt32Array[] | Network Types - Depends on FirewallRuleName (1: FW_PROFILE_TYPE_DOMAIN: This value represents the profile for networks that are connected to domains., 2: FW_PROFILE_TYPE_STANDARD: This value represents the standard profile for networks. These networks are classified as private by the administrators in the server host. The classification happens the first time the host connects to the network. Usually these networks are behind Network Address Translation (NAT) devices, routers, and other edge devices, and they are in a private location, such as a home or an office. AND FW_PROFILE_TYPE_PRIVATE: This value represents the profile for private networks, which is represented by the same value as that used for FW_PROFILE_TYPE_STANDARD., 4: FW_PROFILE_TYPE_PUBLIC: This value represents the profile for public networks. These networks are classified as public by the administrators in the server host. The classification happens the first time the host connects to the network. Usually these networks are those at airports, coffee shops, and other public places where the peers in the network or the network administrator are not trusted., 2147483647: FW_PROFILE_TYPE_ALL: This value represents all these network sets and any future network sets., -2147483648: FW_PROFILE_TYPE_CURRENT: This value represents the current profiles to which the firewall and advanced security components determine the host is connected at the moment of the call. This value can be specified only in method calls, and it cannot be combined with other flags.) | `1`, `2`, `4`, `2147483647`, `-2147483648` | +| **LocalPortRanges** | Write | StringArray[] | Local Port Ranges - Depends on FirewallRuleName | | +| **Description** | Write | String | Description - Depends on FirewallRuleName | | +| **PackageFamilyName** | Write | String | Package Family Name - Depends on FirewallRuleName | | +| **LocalAddressRanges** | Write | StringArray[] | Local Address Ranges - Depends on FirewallRuleName | | +| **Direction** | Write | String | Direction - Depends on FirewallRuleName (in: The rule applies to inbound traffic., out: The rule applies to outbound traffic.) | `in`, `out` | +| **ServiceName** | Write | String | Service Name - Depends on FirewallRuleName | | +| **RemoteAddressRanges** | Write | StringArray[] | Remote Address Ranges - Depends on FirewallRuleName | | +| **Type** | Write | String | Action - Depends on FirewallRuleName (0: Block, 1: Allow) | `0`, `1` | +| **Protocol** | Write | SInt32 | Protocol - Depends on FirewallRuleName | | + + +## Description + +Intune Firewall Rules Policy for Windows10 ConfigMgr + +## Permissions + +### Microsoft Graph + +To authenticate with the Microsoft Graph API, this resource required the following permissions: + +#### Delegated permissions + +- **Read** + + - DeviceManagementConfiguration.Read.All, Group.Read.All + +- **Update** + + - DeviceManagementConfiguration.ReadWrite.All, Group.Read.All + +#### Application permissions + +- **Read** + + - DeviceManagementConfiguration.Read.All, Group.Read.All + +- **Update** + + - DeviceManagementConfiguration.ReadWrite.All, Group.Read.All + +## Examples + +### Example 1 + +This example creates a new Intune Firewall Rules Policy for Windows10 Configuration Manager. + +```powershell +Configuration Example +{ + param( + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint + ) + Import-DscResource -ModuleName Microsoft365DSC + + node localhost + { + IntuneFirewallRulesPolicyWindows10ConfigMgr 'myIntuneFirewallRulesPolicyWindows10ConfigMgr' + { + Assignments = @( + MSFT_DeviceManagementConfigurationPolicyAssignments{ + deviceAndAppManagementAssignmentFilterType = 'none' + dataType = '#microsoft.graph.groupAssignmentTarget' + groupId = '11111111-1111-1111-1111-111111111111' + } + ); + FirewallRuleName = @( + MSFT_MicrosoftGraphIntuneSettingsCatalogFirewallRuleName_IntuneFirewallRulesPolicyWindows10ConfigMgr{ + Direction = 'out' + InterfaceTypes = @('lan') + RemotePortRanges = @('0-100') + Name = 'Rule1' + FilePath = 'C:\Temp' + Protocol = 80 + ServiceName = 'mysvc' + Enabled = '1' + Type = '1' + } + ) + Description = 'Description' + DisplayName = "Intune Firewall Rules Policy Windows10 ConfigMgr"; + Ensure = "Present"; + Id = '00000000-0000-0000-0000-000000000000' + RoleScopeTagIds = @("0"); + ApplicationId = $ApplicationId; + TenantId = $TenantId; + CertificateThumbprint = $CertificateThumbprint; + } + } +} +``` + +### Example 2 + +This example updates a Intune Firewall Rules Policy for Windows10 Configuration Manager. + +```powershell +Configuration Example +{ + param( + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint + ) + Import-DscResource -ModuleName Microsoft365DSC + + node localhost + { + IntuneFirewallRulesPolicyWindows10ConfigMgr 'myIntuneFirewallRulesPolicyWindows10ConfigMgr' + { + Assignments = @( + MSFT_DeviceManagementConfigurationPolicyAssignments{ + deviceAndAppManagementAssignmentFilterType = 'none' + dataType = '#microsoft.graph.groupAssignmentTarget' + groupId = '11111111-1111-1111-1111-111111111111' + } + ); + FirewallRuleName = @( + MSFT_MicrosoftGraphIntuneSettingsCatalogFirewallRuleName_IntuneFirewallRulesPolicyWindows10ConfigMgr{ + Direction = 'in' # Updated property + InterfaceTypes = @('lan') + RemotePortRanges = @('0-100') + Name = 'Rule1' + FilePath = 'C:\Temp' + Protocol = 80 + ServiceName = 'mysvc' + Enabled = '1' + Type = '1' + } + ) + Description = 'Description' + DisplayName = "Intune Firewall Rules Policy Windows10 ConfigMgr"; + Ensure = "Present"; + Id = '00000000-0000-0000-0000-000000000000' + RoleScopeTagIds = @("0"); + ApplicationId = $ApplicationId; + TenantId = $TenantId; + CertificateThumbprint = $CertificateThumbprint; + } + } +} +``` + +### Example 3 + +This example removes a Intune Firewall Rules Policy for Windows10 Configuration Manager. + +```powershell +Configuration Example +{ + param( + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint + ) + Import-DscResource -ModuleName Microsoft365DSC + + node localhost + { + IntuneFirewallRulesPolicyWindows10ConfigMgr 'myIntuneFirewallRulesPolicyWindows10ConfigMgr' + { + Id = '00000000-0000-0000-0000-000000000000' + DisplayName = 'Intune Firewall Rules Policy Windows10 ConfigMgr' + Ensure = 'Absent' + ApplicationId = $ApplicationId; + TenantId = $TenantId; + CertificateThumbprint = $CertificateThumbprint; + } + } +} +``` + From 11646054f95714e1930b19e85e7426eedd404e04 Mon Sep 17 00:00:00 2001 From: NikCharlebois Date: Wed, 20 Nov 2024 13:56:09 +0000 Subject: [PATCH 58/65] Updated Schema Definition --- Modules/Microsoft365DSC/SchemaDefinition.json | 165 ++++++++++++++++++ 1 file changed, 165 insertions(+) diff --git a/Modules/Microsoft365DSC/SchemaDefinition.json b/Modules/Microsoft365DSC/SchemaDefinition.json index 8e112519dc..ee60f0bd47 100644 --- a/Modules/Microsoft365DSC/SchemaDefinition.json +++ b/Modules/Microsoft365DSC/SchemaDefinition.json @@ -42070,6 +42070,171 @@ } ] }, + { + "ClassName": "MSFT_MicrosoftGraphIntuneSettingsCatalogFirewallRuleName_IntuneFirewallRulesPolicyWindows10ConfigMgr", + "Parameters": [ + { + "CIMType": "String", + "Name": "Enabled", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "Name", + "Option": "Write" + }, + { + "CIMType": "String[]", + "Name": "InterfaceTypes", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "FilePath", + "Option": "Write" + }, + { + "CIMType": "String[]", + "Name": "RemotePortRanges", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "EdgeTraversal", + "Option": "Write" + }, + { + "CIMType": "String[]", + "Name": "LocalUserAuthorizedList", + "Option": "Write" + }, + { + "CIMType": "SInt32[]", + "Name": "Profiles", + "Option": "Write" + }, + { + "CIMType": "String[]", + "Name": "LocalPortRanges", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "Description", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "PackageFamilyName", + "Option": "Write" + }, + { + "CIMType": "String[]", + "Name": "LocalAddressRanges", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "Direction", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "ServiceName", + "Option": "Write" + }, + { + "CIMType": "String[]", + "Name": "RemoteAddressRanges", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "Type", + "Option": "Write" + }, + { + "CIMType": "SInt32", + "Name": "Protocol", + "Option": "Write" + } + ] + }, + { + "ClassName": "MSFT_IntuneFirewallRulesPolicyWindows10ConfigMgr", + "Parameters": [ + { + "CIMType": "String", + "Name": "Description", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "DisplayName", + "Option": "Key" + }, + { + "CIMType": "String[]", + "Name": "RoleScopeTagIds", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "Id", + "Option": "Write" + }, + { + "CIMType": "MSFT_MicrosoftGraphIntuneSettingsCatalogFirewallRuleName_IntuneFirewallRulesPolicyWindows10ConfigMgr[]", + "Name": "FirewallRuleName", + "Option": "Write" + }, + { + "CIMType": "MSFT_DeviceManagementConfigurationPolicyAssignments[]", + "Name": "Assignments", + "Option": "Write" + }, + { + "CIMType": "string", + "Name": "Ensure", + "Option": "Write" + }, + { + "CIMType": "MSFT_Credential", + "Name": "Credential", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "ApplicationId", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "TenantId", + "Option": "Write" + }, + { + "CIMType": "MSFT_Credential", + "Name": "ApplicationSecret", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "CertificateThumbprint", + "Option": "Write" + }, + { + "CIMType": "Boolean", + "Name": "ManagedIdentity", + "Option": "Write" + }, + { + "CIMType": "String[]", + "Name": "AccessTokens", + "Option": "Write" + } + ] + }, { "ClassName": "MSFT_DeviceManagementMobileAppAssignment", "Parameters": [ From 0a8ecfc07254eda2b3e612803c50c642a8df2254 Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Wed, 20 Nov 2024 09:07:24 -0500 Subject: [PATCH 59/65] ADOSecurityPolicy - Export Fix --- CHANGELOG.md | 2 ++ .../MSFT_ADOSecurityPolicy/MSFT_ADOSecurityPolicy.psm1 | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dda5eb5b0a..e9aecd66ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -54,6 +54,8 @@ when an approver does not exist. FIXES [#5423](https://github.com/microsoft/Microsoft365DSC/issues/5423) FIXES [#5415](https://github.com/microsoft/Microsoft365DSC/issues/5415) +* ADOSecurityPolicy + * Fixed an error in the export when using a Service Principal to authenticate. * AzureBillingAccountPolicy * Initial release. * IntuneDeviceConfigurationPolicyAndroidDeviceOwner diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_ADOSecurityPolicy/MSFT_ADOSecurityPolicy.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_ADOSecurityPolicy/MSFT_ADOSecurityPolicy.psm1 index e6c10774cd..675182e6c3 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_ADOSecurityPolicy/MSFT_ADOSecurityPolicy.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_ADOSecurityPolicy/MSFT_ADOSecurityPolicy.psm1 @@ -480,16 +480,16 @@ function Export-TargetResource { Write-Host "`r`n" -NoNewline } - foreach ($account in $accounts) + foreach ($account in $accounts.Value) { - $organization = $account.Value.accountName + $organization = $account.accountName if ($null -ne $Global:M365DSCExportResourceInstancesCount) { $Global:M365DSCExportResourceInstancesCount++ } $displayedKey = $organization - Write-Host " |---[$i/$($accounts.Count)] $displayedKey" -NoNewline + Write-Host " |---[$i/$($accounts.Value.Count)] $displayedKey" -NoNewline $params = @{ OrganizationName = $organization Credential = $Credential From 00ae0ed48247b5db8ed49595ea88eac238fd1a0b Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Tue, 19 Nov 2024 22:57:03 +0100 Subject: [PATCH 60/65] Updated PR template --- .github/PULL_REQUEST_TEMPLATE.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index b2682287f6..d25e9d9c84 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -11,3 +11,23 @@ - Fixes #123 - Fixes #124 --> + +#### Task list + + + +- [ ] Added an entry to the change log under the Unreleased section of the file CHANGELOG.md. + Entry should say what was changed and how that affects users (if applicable), and + reference the issue being resolved (if applicable). +- [ ] Resource parameter descriptions added/updated in the schema.mof. +- [ ] Resource documentation added/updated in README.md. +- [ ] Resource settings.json file contains all required permissions. +- [ ] Examples appropriately added/updated. +- [ ] Unit tests added/updated. +- [ ] New/changed code adheres to [DSC Community Style Guidelines](https://dsccommunity.org/styleguidelines). From d550162c9069a8c7f788fafdce407298cce30d07 Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Wed, 20 Nov 2024 15:21:14 +0100 Subject: [PATCH 61/65] Corrected changelog --- CHANGELOG.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1987c08d26..55aa5b7e31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -102,7 +102,13 @@ * IntuneAntivirusPolicyWindows10SettingCatalog * Update properties to be upper-case. Fixes [#5373](https://github.com/microsoft/Microsoft365DSC/issues/5373) -* IntuneSecurityBaselineMicrosoftEdge +* IntuneDeviceConfigurationCustomPolicyWindows10 + * Fixed issue where `Value`, from `OmaSettings`, could not be compared + correctly if it was boolean and set to `$False` + FIXES [#5384](https://github.com/microsoft/Microsoft365DSC/issues/5384) +* IntuneEndpointDetectionAndResponsePolicyWindows10 + * Remove changed property name from export. + FIXES [#5300](https://github.com/microsoft/Microsoft365DSC/issues/5300)* IntuneSecurityBaselineMicrosoftEdge * Deprecate property `authschemes` and replace with `AuthSchemes_AuthSchemes` * M365DSCDRGUtil * Restrict CIM instance access to properties that appear multiple times. From 7451dd5fc963b541250157296fafcd8fa8cd9dc7 Mon Sep 17 00:00:00 2001 From: NikCharlebois Date: Wed, 20 Nov 2024 14:21:34 +0000 Subject: [PATCH 62/65] Updated Resources and Cmdlet documentation pages --- .../IntuneMobileAppConfigurationPolicyIOS.md | 215 ++++++++++++++++++ 1 file changed, 215 insertions(+) create mode 100644 docs/docs/resources/intune/IntuneMobileAppConfigurationPolicyIOS.md diff --git a/docs/docs/resources/intune/IntuneMobileAppConfigurationPolicyIOS.md b/docs/docs/resources/intune/IntuneMobileAppConfigurationPolicyIOS.md new file mode 100644 index 0000000000..7185143012 --- /dev/null +++ b/docs/docs/resources/intune/IntuneMobileAppConfigurationPolicyIOS.md @@ -0,0 +1,215 @@ +# IntuneMobileAppConfigurationPolicyIOS + +## Parameters + +| Parameter | Attribute | DataType | Description | Allowed Values | +| --- | --- | --- | --- | --- | +| **Id** | Write | String | Id of the Intune policy. | | +| **DisplayName** | Key | String | Display name of the Intune policy. | | +| **Description** | Write | String | Admin provided description of the Device Configuration. Inherited from managedDeviceMobileAppConfiguration | | +| **targetedMobileApps** | Write | StringArray[] | the associated app. Inherited from managedDeviceMobileAppConfiguration | | +| **settings** | Write | MSFT_appConfigurationSettingItem[] | app configuration setting items. | | +| **encodedSettingXml** | Write | String | MDM app configuration Base64 binary. | | +| **Ensure** | Write | String | Present ensures the policy exists, absent ensures it is removed. | `Present`, `Absent` | +| **Assignments** | Write | MSFT_DeviceManagementConfigurationPolicyAssignments[] | Represents the assignment to the Intune policy. | | +| **Credential** | Write | PSCredential | Credentials of the Intune 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. | | +| **AccessTokens** | Write | StringArray[] | Access token used for authentication. | | + +### MSFT_DeviceManagementConfigurationPolicyAssignments + +#### Parameters + +| Parameter | Attribute | DataType | Description | Allowed Values | +| --- | --- | --- | --- | --- | +| **dataType** | Write | String | The type of the target assignment. | `#microsoft.graph.groupAssignmentTarget`, `#microsoft.graph.allLicensedUsersAssignmentTarget`, `#microsoft.graph.allDevicesAssignmentTarget`, `#microsoft.graph.exclusionGroupAssignmentTarget`, `#microsoft.graph.configurationManagerCollectionAssignmentTarget` | +| **deviceAndAppManagementAssignmentFilterType** | Write | String | The type of filter of the target assignment i.e. Exclude or Include. Possible values are:none, include, exclude. | `none`, `include`, `exclude` | +| **deviceAndAppManagementAssignmentFilterId** | Write | String | The Id of the filter for the target assignment. | | +| **groupId** | Write | String | The group Id that is the target of the assignment. | | +| **groupDisplayName** | Write | String | The group Display Name that is the target of the assignment. | | +| **collectionId** | Write | String | The collection Id that is the target of the assignment.(ConfigMgr) | | + +### MSFT_appConfigurationSettingItem + +#### Parameters + +| Parameter | Attribute | DataType | Description | Allowed Values | +| --- | --- | --- | --- | --- | +| **appConfigKey** | Write | String | app configuration key. | | +| **appConfigKeyType** | Write | String | app configuration key type. Possible values are: stringType, integerType, realType, booleanType, tokenType. | `stringType`, `integerType`, `realType`, `booleanType`, `tokenType` | +| **appConfigKeyValue** | Write | String | app configuration key value. | | + + +## Description + +This resource configures an Intune Managed Device Mobile App Configuration Policy for iOS Device. + +## Permissions + +### Microsoft Graph + +To authenticate with the Microsoft Graph API, this resource required the following permissions: + +#### Delegated permissions + +- **Read** + + - Group.Read.All, DeviceManagementApps.Read.All + +- **Update** + + - Group.Read.All, DeviceManagementApps.ReadWrite.All + +#### Application permissions + +- **Read** + + - Group.Read.All, DeviceManagementApps.Read.All + +- **Update** + + - Group.Read.All, DeviceManagementApps.ReadWrite.All + +## Examples + +### Example 1 + +This example creates a new Intune Mobile App Configuration Policy for iOs devices + +```powershell +Configuration Example +{ + param( + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint + ) + Import-DscResource -ModuleName 'Microsoft365DSC' + + Node localhost + { + IntuneMobileAppConfigurationPolicyIOS "ConfigureIntuneMobileAppConfigurationPolicyIOS" + { + Description = "IntuneMobileAppConfigurationPolicyIOS Description"; + DisplayName = "IntuneMobileAppConfigurationPolicyIOS DisplayName"; + Ensure = "Present"; + settings = @( + MSFT_appConfigurationSettingItem{ + appConfigKey = 'ConfigKey1' + appConfigKeyType = 'stringType' + appConfigKeyValue = 'KeyValue1' + } + MSFT_appConfigurationSettingItem{ + appConfigKey = 'ConfigKey2' + appConfigKeyType = 'stringType' + appConfigKeyValue = 'keyValue2' + } + ); + targetedMobileApps = @("06131066-8adf-42a9-86aa-e4b59e27da5d"); + ApplicationId = $ApplicationId; + TenantId = $TenantId; + CertificateThumbprint = $CertificateThumbprint; + } + } +} +``` + +### Example 2 + +This example creates a new Intune Mobile App Configuration Policy for iOs devices + +```powershell +Configuration Example +{ + param( + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint + ) + Import-DscResource -ModuleName 'Microsoft365DSC' + + Node localhost + { + IntuneMobileAppConfigurationPolicyIOS "ConfigureIntuneMobileAppConfigurationPolicyIOS" + { + Description = "IntuneMobileAppConfigurationPolicyIOS Description"; + DisplayName = "IntuneMobileAppConfigurationPolicyIOS DisplayName"; + Ensure = "Present"; + settings = @( + MSFT_appConfigurationSettingItem{ + appConfigKey = 'ConfigKey1' + appConfigKeyType = 'stringType' + appConfigKeyValue = 'KeyValue1 updated' #updated property + } + MSFT_appConfigurationSettingItem{ + appConfigKey = 'ConfigKey2' + appConfigKeyType = 'stringType' + appConfigKeyValue = 'keyValue2' + } + ); + targetedMobileApps = @("06131066-8adf-42a9-86aa-e4b59e27da5d"); + ApplicationId = $ApplicationId; + TenantId = $TenantId; + CertificateThumbprint = $CertificateThumbprint; + } + } +} +``` + +### Example 3 + +This example creates a new Intune Mobile App Configuration Policy for iOs devices + +```powershell +Configuration Example +{ + param( + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint + ) + Import-DscResource -ModuleName 'Microsoft365DSC' + + Node localhost + { + IntuneMobileAppConfigurationPolicyIOS "ConfigureIntuneMobileAppConfigurationPolicyIOS" + { + Description = "IntuneMobileAppConfigurationPolicyIOS Description"; + DisplayName = "IntuneMobileAppConfigurationPolicyIOS DisplayName"; + Ensure = "Absent"; + ApplicationId = $ApplicationId; + TenantId = $TenantId; + CertificateThumbprint = $CertificateThumbprint; + } + } +} +``` + From c2d4fb922a9c92851b1228973dffe6ce2c300e28 Mon Sep 17 00:00:00 2001 From: NikCharlebois Date: Wed, 20 Nov 2024 14:23:57 +0000 Subject: [PATCH 63/65] Updated Schema Definition --- Modules/Microsoft365DSC/SchemaDefinition.json | 100 ++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/Modules/Microsoft365DSC/SchemaDefinition.json b/Modules/Microsoft365DSC/SchemaDefinition.json index ee60f0bd47..bed7654e83 100644 --- a/Modules/Microsoft365DSC/SchemaDefinition.json +++ b/Modules/Microsoft365DSC/SchemaDefinition.json @@ -42235,6 +42235,106 @@ } ] }, + { + "ClassName": "MSFT_appConfigurationSettingItem", + "Parameters": [ + { + "CIMType": "String", + "Name": "appConfigKey", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "appConfigKeyType", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "appConfigKeyValue", + "Option": "Write" + } + ] + }, + { + "ClassName": "MSFT_IntuneMobileAppConfigurationPolicyIOS", + "Parameters": [ + { + "CIMType": "String", + "Name": "Id", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "DisplayName", + "Option": "Key" + }, + { + "CIMType": "String", + "Name": "Description", + "Option": "Write" + }, + { + "CIMType": "String[]", + "Name": "targetedMobileApps", + "Option": "Write" + }, + { + "CIMType": "MSFT_appConfigurationSettingItem[]", + "Name": "settings", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "encodedSettingXml", + "Option": "Write" + }, + { + "CIMType": "string", + "Name": "Ensure", + "Option": "Write" + }, + { + "CIMType": "MSFT_DeviceManagementConfigurationPolicyAssignments[]", + "Name": "Assignments", + "Option": "Write" + }, + { + "CIMType": "MSFT_Credential", + "Name": "Credential", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "ApplicationId", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "TenantId", + "Option": "Write" + }, + { + "CIMType": "MSFT_Credential", + "Name": "ApplicationSecret", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "CertificateThumbprint", + "Option": "Write" + }, + { + "CIMType": "Boolean", + "Name": "ManagedIdentity", + "Option": "Write" + }, + { + "CIMType": "String[]", + "Name": "AccessTokens", + "Option": "Write" + } + ] + }, { "ClassName": "MSFT_DeviceManagementMobileAppAssignment", "Parameters": [ From 6b4b5ea77c06922869f76704fed61f1bcb31156b Mon Sep 17 00:00:00 2001 From: NikCharlebois Date: Wed, 20 Nov 2024 14:24:48 +0000 Subject: [PATCH 64/65] Updated {Create} Intune Integration Tests --- ...M365DSCIntegration.INTUNE.Create.Tests.ps1 | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/Tests/Integration/Microsoft365DSC/M365DSCIntegration.INTUNE.Create.Tests.ps1 b/Tests/Integration/Microsoft365DSC/M365DSCIntegration.INTUNE.Create.Tests.ps1 index d9d38af909..fa3c3fa3c3 100644 --- a/Tests/Integration/Microsoft365DSC/M365DSCIntegration.INTUNE.Create.Tests.ps1 +++ b/Tests/Integration/Microsoft365DSC/M365DSCIntegration.INTUNE.Create.Tests.ps1 @@ -2777,6 +2777,59 @@ TenantId = $TenantId; CertificateThumbprint = $CertificateThumbprint; } + IntuneFirewallRulesPolicyWindows10ConfigMgr 'myIntuneFirewallRulesPolicyWindows10ConfigMgr' + { + Assignments = @( + MSFT_DeviceManagementConfigurationPolicyAssignments{ + deviceAndAppManagementAssignmentFilterType = 'none' + dataType = '#microsoft.graph.groupAssignmentTarget' + groupId = '11111111-1111-1111-1111-111111111111' + } + ); + FirewallRuleName = @( + MSFT_MicrosoftGraphIntuneSettingsCatalogFirewallRuleName_IntuneFirewallRulesPolicyWindows10ConfigMgr{ + Direction = 'out' + InterfaceTypes = @('lan') + RemotePortRanges = @('0-100') + Name = 'Rule1' + FilePath = 'C:\Temp' + Protocol = 80 + ServiceName = 'mysvc' + Enabled = '1' + Type = '1' + } + ) + Description = 'Description' + DisplayName = "Intune Firewall Rules Policy Windows10 ConfigMgr"; + Ensure = "Present"; + Id = '00000000-0000-0000-0000-000000000000' + RoleScopeTagIds = @("0"); + ApplicationId = $ApplicationId; + TenantId = $TenantId; + CertificateThumbprint = $CertificateThumbprint; + } + IntuneMobileAppConfigurationPolicyIOS 'ConfigureIntuneMobileAppConfigurationPolicyIOS' + { + Description = "IntuneMobileAppConfigurationPolicyIOS Description"; + DisplayName = "IntuneMobileAppConfigurationPolicyIOS DisplayName"; + Ensure = "Present"; + settings = @( + MSFT_appConfigurationSettingItem{ + appConfigKey = 'ConfigKey1' + appConfigKeyType = 'stringType' + appConfigKeyValue = 'KeyValue1' + } + MSFT_appConfigurationSettingItem{ + appConfigKey = 'ConfigKey2' + appConfigKeyType = 'stringType' + appConfigKeyValue = 'keyValue2' + } + ); + targetedMobileApps = @("06131066-8adf-42a9-86aa-e4b59e27da5d"); + ApplicationId = $ApplicationId; + TenantId = $TenantId; + CertificateThumbprint = $CertificateThumbprint; + } IntuneMobileAppsMacOSLobApp 'IntuneMobileAppsMacOSLobApp-TeamsForBusinessInstaller' { Id = "8d027f94-0682-431e-97c1-827d1879fa79"; From 8f230f5737008e26a3545d9d4291cb4672e66e30 Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Wed, 20 Nov 2024 15:49:11 +0100 Subject: [PATCH 65/65] Release v1.24.1120.1 --- CHANGELOG.md | 2 +- Modules/Microsoft365DSC/Microsoft365DSC.psd1 | 115 ++++++++++++------- 2 files changed, 75 insertions(+), 42 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 55aa5b7e31..553418c0e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Change log for Microsoft365DSC -# UNRELEASED +# 1.24.1120.1 * AADAdminConsentRequestPolicy * Added error handling to Group display name retrieval to prevent errors diff --git a/Modules/Microsoft365DSC/Microsoft365DSC.psd1 b/Modules/Microsoft365DSC/Microsoft365DSC.psd1 index 1c924e4bb9..8a18fa8a84 100644 --- a/Modules/Microsoft365DSC/Microsoft365DSC.psd1 +++ b/Modules/Microsoft365DSC/Microsoft365DSC.psd1 @@ -3,7 +3,7 @@ # # Generated by: Microsoft Corporation # -# Generated on: 2024-11-13 +# Generated on: 2024-11-20 @{ @@ -11,7 +11,7 @@ # RootModule = '' # Version number of this module. - ModuleVersion = '1.24.1113.1' + ModuleVersion = '1.24.1120.1' # Supported PSEditions # CompatiblePSEditions = @() @@ -147,48 +147,81 @@ IconUri = 'https://github.com/microsoft/Microsoft365DSC/blob/Dev/Modules/Microsoft365DSC/Dependencies/Images/Logo.png?raw=true' # ReleaseNotes of this module - ReleaseNotes = '* AADConditionalAccessPolicy - * Fixed bug where an empty value was passed in the request for the - insiderRiskLevels parameter, which throws an error. - FIXES [#5389](https://github.com/microsoft/Microsoft365DSC/issues/5389) - * Fixes a bug where 3P apps could not be assigned by DisplayName for both - IncludeApplications and ExcludeApplications - FIXES [#5390](https://github.com/microsoft/Microsoft365DSC/issues/5390) + ReleaseNotes = '* AADAdminConsentRequestPolicy + * Added error handling to Group display name retrieval to prevent errors + when an assigned group no longer exists. +* AADAuthenticationMethodPolicyAuthenticator + * Added error handling to Group display name retrieval to prevent errors + when an assigned group no longer exists. +* AADAuthenticationMethodPolicyEmail + * Added error handling to Group display name retrieval to prevent errors + when an assigned group no longer exists. +* AADAuthenticationMethodPolicyExternal + * Added error handling to Group display name retrieval to prevent errors + when an assigned group no longer exists. +* AADAuthenticationMethodPolicyFido2 + * Added error handling to Group display name retrieval to prevent errors + when an assigned group no longer exists. +* AADAuthenticationMethodPolicyHardware + * Added error handling to Group display name retrieval to prevent errors + when an assigned group no longer exists. +* AADAuthenticationMethodPolicySms + * Added error handling to Group display name retrieval to prevent errors + when an assigned group no longer exists. +* AADAuthenticationMethodPolicySoftware + * Added error handling to Group display name retrieval to prevent errors + when an assigned group no longer exists. +* AADAuthenticationMethodPolicyTemporary + * Added error handling to Group display name retrieval to prevent errors + when an assigned group no longer exists. +* AADAuthenticationMethodPolicyVoice + * Added error handling to Group display name retrieval to prevent errors + when an assigned group no longer exists. +* AADAuthenticationMethodPolicyX509 + * Added error handling to Group display name retrieval to prevent errors + when an assigned group no longer exists. +* AADConditionalAccessPolicy + * Fixed bug where a null value was passed in the request for the + excludePlatforms parameter when just values were assigned to includePlatforms, which throws an error. + * Fixed bug where a null value was passed in the request for the + sessionControl parameter when there are no session controls, which throws an error. + * Fixed bug where a null value was passed in the request for the + applicationEnforcedRestrictions parameter when value was set to false, which throws an error. +* AADDeviceRegistrationPolicy + * Added error handling to Group display name retrieval to prevent errors + when an assigned group no longer exists. +* AADRoleAssignmentScheduleRequest + * Initial release. * AADRoleEligibilityScheduleRequest - * FIXES [#3787](https://github.com/microsoft/Microsoft365DSC/issues/3787) - * FIXES [#5089](https://github.com/microsoft/Microsoft365DSC/issues/5089) -* EXOATPBuiltInProtectionRule, EXOEOPProtectionRule - * Fixed issue where empty arrays were being compared incorrectly to null - strings - FIXES [#5394](https://github.com/microsoft/Microsoft365DSC/issues/5394) -* IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy - * Update property `PasswordAgeDays_AAD` to be lower-case. - FIXES [#5378](https://github.com/microsoft/Microsoft365DSC/issues/5378) (1/2) -* IntuneAntivirusExclusionsPolicyMacOS + * Adds support for custom role assignments at app scope. +* AADRoleSettings + * Fixing issue where the ActivateApprover parameter is not processed correctly + when an approver does not exist. + FIXES [#5423](https://github.com/microsoft/Microsoft365DSC/issues/5423) + FIXES [#5415](https://github.com/microsoft/Microsoft365DSC/issues/5415) +* AzureBillingAccountPolicy + * Initial release. +* IntuneDeviceConfigurationPolicyAndroidDeviceOwner + * Fixed issue when properties `DetailedHelpText`, + `DeviceOwnerLockScreenMessage` or `ShortHelpText` were defined but the + request was not being sent correctly + FIXES [#5411](https://github.com/microsoft/Microsoft365DSC/issues/5411) +* IntuneDiskEncryptionPDEPolicyWindows10 + * Initial release. +* IntuneFirewallRulesHyperVPolicyWindows10 + * Initial release. +* IntuneFirewallRulesPolicyWindows10ConfigMgr + * Initial release. +* IntuneMobileAppConfigurationPolicyIOS * Initial release. -* IntuneAntivirusPolicyWindows10SettingCatalog - * Update properties to be upper-case. - Fixes [#5373](https://github.com/microsoft/Microsoft365DSC/issues/5373) -* IntuneDeviceConfigurationCustomPolicyWindows10 - * Fixed issue where `Value`, from `OmaSettings`, could not be compared - correctly if it was boolean and set to `$False` - FIXES [#5384](https://github.com/microsoft/Microsoft365DSC/issues/5384) -* IntuneEndpointDetectionAndResponsePolicyWindows10 - * Remove changed property name from export. - FIXES [#5300](https://github.com/microsoft/Microsoft365DSC/issues/5300) -* IntuneSecurityBaselineMicrosoftEdge - * Deprecate property `authschemes` and replace with `AuthSchemes_AuthSchemes` +* SCPolicyConfig + * Fixed an issue extracting empty groups properties. +* TeamsUpdateManagementPolicy + * Added conversion of the UpdateTimeOfDay parameter to the local culture format + so that the comparison will work consistently. + FIXES [#5424](https://github.com/microsoft/Microsoft365DSC/issues/5424) * M365DSCDRGUtil - * Restrict CIM instance access to properties that appear multiple times. - * Switch log type for not found Intune assignments to `Warning`. -* M365DSCIntuneSettingsCatalogUtil - * Add ADMX handling for `edge~httpauthentication_`. - FIXES [#5378](https://github.com/microsoft/Microsoft365DSC/issues/5378) (2/2) -* TeamsUpgradePolicy - * Changes to how we are retrieving the users to improve performance. -* DEPENDENCIES - * Updated DSCParser to version 2.0.0.12. - * Updated MSCloudLoginAssistant to version 1.1.28.' + * Improve CIM instance detection for specific Intune resources.' # Flag to indicate whether the module requires explicit user acceptance for install/update # RequireLicenseAcceptance = $false