diff --git a/CHANGELOG.md b/CHANGELOG.md index 132727cb49..734102a4d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,23 @@ # Change log for Microsoft365DSC +# 1.24.605.1 + +* AADAuthenticationFlowPolicy + * Initial Release. +* AADEntitlementManagementRoleAssignment + * Initial Release. +* IntuneAppConfigurationDevicePolicy + * Add assignment group display name and fix compilation + FIXES [#4724](https://github.com/microsoft/Microsoft365DSC/issues/4724) +* M365DSCResourceGenerator + * Add support for generating Intune settings catalog policies +* M365DSCDRGUtil + * Add multiple commands for Intune policies that use the settings catalog + * Improve comparison of Intune assignments in `Compare-M365DSCIntunePolicyAssignment` +* DEPENDENCIES + * Updated MSCloudLoginAssistant to version 1.1.17. + * Updated ReverseDSC to version 2.0.0.20. + # 1.24.529.1 * AADAdministrativeUnit diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationFlowPolicy/MSFT_AADAuthenticationFlowPolicy.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationFlowPolicy/MSFT_AADAuthenticationFlowPolicy.psm1 new file mode 100644 index 0000000000..42658b0e94 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationFlowPolicy/MSFT_AADAuthenticationFlowPolicy.psm1 @@ -0,0 +1,382 @@ +function Get-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + param + ( + [Parameter(Mandatory = $true)] + [System.String] + $IsSingleInstance, + + [Parameter()] + [System.String] + $Id, + + [Parameter()] + [System.String] + $DisplayName, + + [Parameter()] + [System.String] + $Description, + + [Parameter()] + [System.Boolean] + $SelfServiceSignUpEnabled, + + [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 + ) + + Write-Verbose -Message 'Getting configuration of Authentication Flow Policy' + $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 + + $nullReturn = @{ + IsSingleInstance = 'Yes' + } + + try + { + $flowPolicy = Get-MgBetaPolicyAuthenticationFlowPolicy -ErrorAction 'SilentlyContinue' + + if ($null -eq $flowPolicy) + { + throw 'Could not retrieve Authentication Flow Policy' + } + else + { + Write-Verbose -Message 'Found existing Authentication Flow Policy' + $result = @{ + IsSingleInstance = 'Yes' + Id = $flowPolicy.Id + DisplayName = $flowPolicy.DisplayName + Description = $flowPolicy.Description + SelfServiceSignUpEnabled = [Boolean]$flowPolicy.SelfServiceSignUp.IsEnabled + Credential = $Credential + ApplicationId = $ApplicationId + TenantId = $TenantId + ApplicationSecret = $ApplicationSecret + CertificateThumbprint = $CertificateThumbprint + Managedidentity = $ManagedIdentity.IsPresent + AccessTokens = $AccessTokens + } + Write-Verbose -Message "Get-TargetResource Result: `n $(Convert-M365DscHashtableToString -Hashtable $result)" + return $result + } + } + catch + { + New-M365DSCLogEntry -Message 'Error retrieving data:' ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + + return $nullReturn + } +} + +function Set-TargetResource +{ + [CmdletBinding()] + param + ( + [Parameter(Mandatory = $true)] + [System.String] + $IsSingleInstance, + + [Parameter()] + [System.String] + $Id, + + [Parameter()] + [System.String] + $DisplayName, + + [Parameter()] + [System.String] + $Description, + + [Parameter()] + [System.Boolean] + $SelfServiceSignUpEnabled, + + [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 + ) + + Write-Verbose -Message 'Setting configuration of Authentication flow policy.' + $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 + { + Update-MgBetaPolicyAuthenticationFlowPolicy -SelfServiceSignUp $SelfServiceSignUpEnabled | Out-Null + } + catch + { + Write-Verbose -Message 'Cannot update the authentication flow policy.' + } +} + +function Test-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Boolean])] + param + ( + [Parameter(Mandatory = $true)] + [System.String] + $IsSingleInstance, + + [Parameter()] + [System.String] + $Id, + + [Parameter()] + [System.String] + $DisplayName, + + [Parameter()] + [System.String] + $Description, + + [Parameter()] + [System.Boolean] + $SelfServiceSignUpEnabled, + + [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 Authentication Flow Policy' + + $CurrentValues = Get-TargetResource @PSBoundParameters + + Write-Verbose -Message "Current Values: $(Convert-M365DscHashtableToString -Hashtable $CurrentValues)" + Write-Verbose -Message "Target Values: $(Convert-M365DscHashtableToString -Hashtable $PSBoundParameters)" + + $ValuesToCheck = $PSBoundParameters + + $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 + + $dscContent = '' + try + { + $Params = @{ + IsSingleInstance = 'Yes' + Credential = $Credential + ApplicationId = $ApplicationId + ApplicationSecret = $ApplicationSecret + TenantId = $TenantId + CertificateThumbprint = $CertificateThumbprint + ManagedIdentity = $ManagedIdentity.IsPresent + AccessTokens = $AccessTokens + } + $Results = Get-TargetResource @Params + + if ($Results -is [System.Collections.Hashtable] -and $Results.Count -gt 1) + { + $Results = Update-M365DSCExportAuthenticationResults -ConnectionMode $ConnectionMode -Results $Results + $currentDSCBlock = Get-M365DSCExportContentForResource -ResourceName $ResourceName -ConnectionMode $ConnectionMode ` + -ModulePath $PSScriptRoot ` + -Results $Results ` + -Credential $Credential + $dscContent += $currentDSCBlock + + Save-M365DSCPartialExport -Content $currentDSCBlock ` + -FileName $Global:PartialExportFileName + + Write-Host $Global:M365DSCEmojiGreenCheckMark + } + else + { + Write-Host $Global:M365DSCEmojiRedX + } + + 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_AADAuthenticationFlowPolicy/MSFT_AADAuthenticationFlowPolicy.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationFlowPolicy/MSFT_AADAuthenticationFlowPolicy.schema.mof new file mode 100644 index 0000000000..cffeaae1e1 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationFlowPolicy/MSFT_AADAuthenticationFlowPolicy.schema.mof @@ -0,0 +1,16 @@ +[ClassVersion("1.0.0.0"), FriendlyName("AADAuthenticationFlowPolicy")] +class MSFT_AADAuthenticationFlowPolicy : OMI_BaseResource +{ + [Key, Description("Only valid value is 'Yes'."), ValueMap{"Yes"}, Values{"Yes"}] String IsSingleInstance; + [Write, Description("Unique identifier of the Authentication Flow Policy.")] String Id; + [Write, Description("Display name of the Authentication Flow Policy.")] String DisplayName; + [Write, Description("Description of the Authentication Flow Policy.")] String Description; + [Write, Description("Indicates whether self-service sign-up flow is enabled or disabled. The default value is false. This property isn't a key. Required.")] String SelfServiceSignUpEnabled; + [Write, Description("Credentials of the Azure Active Directory 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_AADAuthenticationFlowPolicy/readme.md b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationFlowPolicy/readme.md new file mode 100644 index 0000000000..cf21367ab0 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationFlowPolicy/readme.md @@ -0,0 +1,5 @@ +# AADAuthenticationFlowPolicy + +## Description + +Represents the policy configuration of self-service sign-up experience at a tenant level that lets external users request to sign up for approval. It contains information, such as the identifier, display name, and description, and indicates whether self-service sign-up is enabled for the policy. diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationFlowPolicy/settings.json b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationFlowPolicy/settings.json new file mode 100644 index 0000000000..51caff057e --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationFlowPolicy/settings.json @@ -0,0 +1,29 @@ +{ + "resourceName": "AADAuthenticationFlowPolicy", + "description": "Represents the policy configuration of self-service sign-up experience at a tenant level that lets external users request to sign up for approval. It contains information, such as the identifier, display name, and description, and indicates whether self-service sign-up is enabled for the policy.", + "roles": { + "read": [ + "Security Reader" + ], + "update": [ + "Authentication Policy Administrator" + ] + }, + "permissions": { + "graph": { + "delegated": {}, + "application": { + "read": [ + { + "name": "Policy.Read.All" + } + ], + "update": [ + { + "name": "Policy.ReadWrite.AuthenticationFlows" + } + ] + } + } + } +} diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyAuthenticator/MSFT_AADAuthenticationMethodPolicyAuthenticator.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyAuthenticator/MSFT_AADAuthenticationMethodPolicyAuthenticator.schema.mof index b608631f79..8a647d34da 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyAuthenticator/MSFT_AADAuthenticationMethodPolicyAuthenticator.schema.mof +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAuthenticationMethodPolicyAuthenticator/MSFT_AADAuthenticationMethodPolicyAuthenticator.schema.mof @@ -35,7 +35,7 @@ class MSFT_AADAuthenticationMethodPolicyAuthenticatorIncludeTarget [ClassVersion("1.0.0.0"), FriendlyName("AADAuthenticationMethodPolicyAuthenticator")] class MSFT_AADAuthenticationMethodPolicyAuthenticator : OMI_BaseResource { - [Write, Description("A collection of Microsoft Authenticator settings such as number matching and location context, and whether they are enabled for all users or specific users only."), EmbeddedInstance("MSFT_MicrosoftGraphmicrosoftAuthenticatorFeatureSettings")] String FeatureSettings; + [Write, Description("A collection of Microsoft Authenticator settings such as number matching and location context, and whether they are enabled for all users or specific users only."), EmbeddedInstance("MSFT_MicrosoftGraphMicrosoftAuthenticatorFeatureSettings")] String FeatureSettings; [Write, Description("true if users can use the OTP code generated by the Microsoft Authenticator app, false otherwise.")] Boolean IsSoftwareOathEnabled; [Write, Description("Displayname of the groups of users that are excluded from a policy."), EmbeddedInstance("MSFT_AADAuthenticationMethodPolicyAuthenticatorExcludeTarget")] String ExcludeTargets[]; [Write, Description("Displayname of the groups of users that are included from a policy."), EmbeddedInstance("MSFT_AADAuthenticationMethodPolicyAuthenticatorIncludeTarget")] String IncludeTargets[]; diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADEntitlementManagementRoleAssignment/MSFT_AADEntitlementManagementRoleAssignment.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADEntitlementManagementRoleAssignment/MSFT_AADEntitlementManagementRoleAssignment.psm1 new file mode 100644 index 0000000000..abfd1c0bba --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADEntitlementManagementRoleAssignment/MSFT_AADEntitlementManagementRoleAssignment.psm1 @@ -0,0 +1,514 @@ +function Get-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + param + ( + #region resource generator code + [Parameter()] + [System.String] + $Id, + + [Parameter(Mandatory = $true)] + [System.String] + $Principal, + + [Parameter(Mandatory)] + [System.String] + $RoleDefinition, + + [Parameter()] + [System.String] + $AppScopeId, + + [Parameter()] + [System.String] + $DirectoryScopeId, + #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 + + $nullResult = $PSBoundParameters + $nullResult.Ensure = 'Absent' + try + { + $getValue = $null + + if (-not [System.String]::IsNullOrEmpty($Id)) + { + $getValue = Get-MgBetaRoleManagementEntitlementManagementRoleAssignment -UnifiedRoleAssignmentId $Id + } + + $user = Get-mguser -UserId $Principal + $roleInfo = Get-MgBetaRoleManagementEntitlementManagementRoleDefinition -Filter "DisplayName eq '$RoleDefinition'" + + if ($null -eq $getValue) + { + if(-not [System.String]::IsNullOrEmpty($Id)) + { + Write-Verbose -Message "Nothing with id {$Id} was found" + } + + if (-Not [string]::IsNullOrEmpty($Principal)) + { + $PrincipalId = $null + if ($null -ne $user) + { + $PrincipalId = $user.Id + } + + $RoleDefinitionId = $null + if ($null -ne $roleInfo) + { + $RoleDefinitionId = $roleInfo.Id + } + $getValue = Get-MgBetaRoleManagementEntitlementManagementRoleAssignment -Filter "PrincipalId eq '$PrincipalId' and RoleDefinitionId eq '$RoleDefinitionId'" + } + } + + if ($null -eq $getValue) + { + Write-Verbose -Message "No existing assignments were found" + return $nullResult + } + + Write-Verbose -Message "Found existing role assignment with ID {$($getValue.id)}." + + $results = @{ + Id = $getValue.Id + Principal = $user.UserPrincipalName + RoleDefinition = $roleInfo.DisplayName + DisplayName = $getValue.DisplayName + AppScopeId = $getValue.AppScopeId + DirectoryScopeId = $getValue.DirectoryScopeId + Ensure = 'Present' + Credential = $Credential + ApplicationId = $ApplicationId + TenantId = $TenantId + ApplicationSecret = $ApplicationSecret + CertificateThumbprint = $CertificateThumbprint + Managedidentity = $ManagedIdentity.IsPresent + AccessTokens = $AccessTokens + } + + 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] + $Principal, + + [Parameter(Mandatory)] + [System.String] + $RoleDefinition, + + [Parameter()] + [System.String] + $AppScopeId, + + [Parameter()] + [System.String] + $DirectoryScopeId, + #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 + + $setParameters = ([Hashtable]$PSBoundParameters).clone() + $userInfo = Get-MgUser -UserId $Principal + $roleInfo = Get-MgBetaRoleManagementEntitlementManagementRoleDefinition -Filter "DisplayName eq '$RoleDefinition'" + $setParameters.Add('PrincipalId', $userInfo.Id) + $setParameters.Add('RoleDefinitionId', $roleInfo.Id) + $setParameters.Remove('Principal') | Out-Null + $setParameters.Remove('RoleDefinition') | Out-Null + if ($Ensure -eq 'Present' -and $currentInstance.Ensure -eq 'Absent') + { + $setParameters.Remove('Id') | Out-Null + Write-Verbose -Message "Creating a new Entitlement Management Role Assignment with:`r`n$($setParameters | Out-String)" + New-MgBetaRoleManagementEntitlementManagementRoleAssignment @setParameters + } + elseif ($Ensure -eq 'Present' -and $currentInstance.Ensure -eq 'Present') + { + Write-Verbose -Message "Entitlement Management Role Assignments cannot be updated." + } + elseif ($Ensure -eq 'Absent' -and $currentInstance.Ensure -eq 'Present') + { + Remove-MgBetaRoleManagementEntitlementManagementRoleAssignment -UnifiedRoleAssignmentId $currentInstance.Id + } +} + +function Test-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Boolean])] + param + ( + #region resource generator code + [Parameter()] + [System.String] + $Id, + + [Parameter(Mandatory = $true)] + [System.String] + $Principal, + + [Parameter(Mandatory)] + [System.String] + $RoleDefinition, + + [Parameter()] + [System.String] + $AppScopeId, + + [Parameter()] + [System.String] + $DirectoryScopeId, + #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 Assignment" + + $CurrentValues = Get-TargetResource @PSBoundParameters + $ValuesToCheck = ([Hashtable]$PSBoundParameters).clone() + + if ($CurrentValues.Ensure -eq 'Absent' -and $Ensure -eq 'Absent') + { + Write-Verbose -Message "Test-TargetResource returned $true" + return $true + } + $testResult = $true + + Write-Verbose -Message "Current Values: $(Convert-M365DscHashtableToString -Hashtable $CurrentValues)" + Write-Verbose -Message "Target Values: $(Convert-M365DscHashtableToString -Hashtable $ValuesToCheck)" + + 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 '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-MgBetaRoleManagementEntitlementManagementRoleAssignment ` + -All ` + -ErrorAction Stop + + #endregion + $i = 1 + $dscContent = '' + if ($getValue.Length -eq 0) + { + Write-Host $Global:M365DSCEmojiGreenCheckMark + } + else + { + Write-Host "`r`n" -NoNewline + } + foreach ($config in $getValue) + { + $displayedKey = $config.id + if (-not [String]::IsNullOrEmpty($config.displayName)) + { + $displayedKey = $config.displayName + } + Write-Host " |---[$i/$($getValue.Count)] $displayedKey" -NoNewline + $roleInfo = Get-MgBetaRoleManagementEntitlementManagementRoleDefinition -UnifiedRoleDefinitionId $config.RoleDefinitionId + $params = @{ + Id = $config.Id + Principal = $config.PrincipalId + RoleDefinition = $roleInfo.DisplayName + 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 + + $currentDSCBlock = Get-M365DSCExportContentForResource -ResourceName $ResourceName ` + -ConnectionMode $ConnectionMode ` + -ModulePath $PSScriptRoot ` + -Results $Results ` + -Credential $Credential + + $dscContent += $currentDSCBlock + Save-M365DSCPartialExport -Content $currentDSCBlock ` + -FileName $Global:PartialExportFileName + + Write-Host $Global:M365DSCEmojiGreenCheckMark + $i++ + } + + return $dscContent + } + catch + { + if ($_.ErrorDetails.Message -like '*User is not authorized to perform the operation.*') + { + Write-Host "`r`n $($Global:M365DSCEmojiYellowCircle) Tenant does not meet license requirement to extract this component or the user has not been granted the proper permissions." + } + else + { + 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_AADEntitlementManagementRoleAssignment/MSFT_AADEntitlementManagementRoleAssignment.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_AADEntitlementManagementRoleAssignment/MSFT_AADEntitlementManagementRoleAssignment.schema.mof new file mode 100644 index 0000000000..195ae49b57 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADEntitlementManagementRoleAssignment/MSFT_AADEntitlementManagementRoleAssignment.schema.mof @@ -0,0 +1,17 @@ +[ClassVersion("1.0.0.0"), FriendlyName("AADEntitlementManagementRoleAssignment")] +class MSFT_AADEntitlementManagementRoleAssignment : OMI_BaseResource +{ + [Write, Description("Unique Id of the role assignment.")] String Id; + [Key, Description("Identifier of the principal to which the assignment is granted.")] String Principal; + [Key, Description("Identifier of the unifiedRoleDefinition the assignment is for.")] String RoleDefinition; + [Write, Description("Identifier of the app specific scope when the assignment scope is app specific. The scope of an assignment determines the set of resources for which the principal has been granted access. App scopes are scopes that are defined and understood by a resource application only.")] String AppScopeId; + [Write, Description("Identifier of the directory object representing the scope of the assignment. The scope of an assignment 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, unlike app scopes that are defined and understood by a resource application only.")] String DirectoryScopeId; + [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 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 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_AADEntitlementManagementRoleAssignment/readme.md b/Modules/Microsoft365DSC/DSCResources/MSFT_AADEntitlementManagementRoleAssignment/readme.md new file mode 100644 index 0000000000..ef8b90de6a --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADEntitlementManagementRoleAssignment/readme.md @@ -0,0 +1,6 @@ + +# AADEntitlementManagementRoleAssignment + +## Description + +This resource configures an Azure AD Entitlement Management Role assignments. diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADEntitlementManagementRoleAssignment/settings.json b/Modules/Microsoft365DSC/DSCResources/MSFT_AADEntitlementManagementRoleAssignment/settings.json new file mode 100644 index 0000000000..5eb3981dd3 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADEntitlementManagementRoleAssignment/settings.json @@ -0,0 +1,49 @@ +{ + "resourceName": "AADEntitlementManagementRoleAssignment", + "description": "This resource configures an Azure AD Entitlement Management Role Assignments.", + "roles": { + "read": [ + "Security Reader" + ], + "update": [ + "Identity Governance Administrator" + ] + }, + "permissions": { + "graph": { + "delegated": { + "read": [ + { + "name": "EntitlementManagement.Read.All" + } + ], + "update": [ + { + "name": "EntitlementManagement.Read.All" + }, + { + "name": "EntitlementManagement.ReadWrite.All" + } + ] + }, + "application": { + "read": [ + { + "name": "EntitlementManagement.Read.All" + } + ], + "update": [ + { + "name": "EntitlementManagement.Read.All" + }, + { + "name": "EntitlementManagement.ReadWrite.All" + }, + { + "name" : "RoleManagement.ReadWrite.Directory" + } + ] + } + } + } +} diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAppConfigurationDevicePolicy/MSFT_IntuneAppConfigurationDevicePolicy.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAppConfigurationDevicePolicy/MSFT_IntuneAppConfigurationDevicePolicy.psm1 index b4c78353bb..358626cb85 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAppConfigurationDevicePolicy/MSFT_IntuneAppConfigurationDevicePolicy.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAppConfigurationDevicePolicy/MSFT_IntuneAppConfigurationDevicePolicy.psm1 @@ -180,6 +180,26 @@ function Get-TargetResource } #endregion + $platform = 'android' + if ($null -ne $getValue.AdditionalProperties.encodedSettingXml -or $null -ne $getValue.AdditionalProperties.settings) + { + $platform = 'ios' + } + + $targetedApps = @() + foreach ($targetedApp in $getValue.TargetedMobileApps) + { + $app = Get-MgBetaDeviceAppManagementMobileApp -MobileAppId $targetedApp + if ($platform -eq 'android') + { + $targetedApps += $app.AdditionalProperties.packageId + } + else + { + $targetedApps += $app.AdditionalProperties.bundleId + } + } + $results = @{ #region resource generator code ConnectedAppsEnabled = $getValue.AdditionalProperties.connectedAppsEnabled @@ -192,7 +212,7 @@ function Get-TargetResource Description = $getValue.Description DisplayName = $getValue.DisplayName RoleScopeTagIds = $getValue.RoleScopeTagIds - TargetedMobileApps = $getValue.TargetedMobileApps + TargetedMobileApps = $targetedApps Id = $getValue.Id Ensure = 'Present' Credential = $Credential @@ -204,17 +224,11 @@ function Get-TargetResource #endregion } $assignmentsValues = Get-MgBetaDeviceAppManagementMobileAppConfigurationAssignment -ManagedDeviceMobileAppConfigurationId $Id + $assignmentResult = @() - foreach ($assignmentEntry in $AssignmentsValues) + if ($assignmentsValues.Count -gt 0) { - $assignmentValue = @{ - dataType = $assignmentEntry.Target.AdditionalProperties.'@odata.type' - deviceAndAppManagementAssignmentFilterType = $(if ($null -ne $assignmentEntry.Target.DeviceAndAppManagementAssignmentFilterType) - {$assignmentEntry.Target.DeviceAndAppManagementAssignmentFilterType.ToString()}) - deviceAndAppManagementAssignmentFilterId = $assignmentEntry.Target.DeviceAndAppManagementAssignmentFilterId - groupId = $assignmentEntry.Target.AdditionalProperties.groupId - } - $assignmentResult += $assignmentValue + $assignmentResult += ConvertFrom-IntunePolicyAssignment -Assignments $assignmentsValues -IncludeDeviceFilter $true } $results.Add('Assignments', $assignmentResult) @@ -348,6 +362,23 @@ function Set-TargetResource $platform = 'ios' } + $mobileApps = Get-MgBetaDeviceAppManagementMobileApp -All + $targetedApps = @() + foreach ($targetedApp in $TargetedMobileApps) + { + $app = $mobileApps | Where-Object -FilterScript { + ($platform -eq 'android' -and $_.AdditionalProperties.packageId -eq $targetedApp -and $_.AdditionalProperties.'@odata.type' -eq '#microsoft.graph.androidManagedStoreApp') -or ` + ($platform -eq 'ios' -and $_.AdditionalProperties.bundleId -eq $targetedApp) + } + + if ($null -eq $app) + { + throw "Could not find a mobile app with packageId or bundleId {$targetedApp}" + } + $targetedApps += $app.Id + } + $BoundParameters.TargetedMobileApps = $targetedApps + if ($Ensure -eq 'Present' -and $currentInstance.Ensure -eq 'Absent') { Write-Verbose -Message "Creating an Intune App Configuration Device Policy with DisplayName {$DisplayName}" @@ -382,9 +413,10 @@ function Set-TargetResource $assignmentsHash += Get-M365DSCDRGComplexTypeToHashtable -ComplexObject $Assignment } - if ($policy.id) + if ($policy.Id) { - Update-DeviceConfigurationPolicyAssignment -DeviceConfigurationPolicyId $policy.id ` + Update-DeviceConfigurationPolicyAssignment ` + -DeviceConfigurationPolicyId "$($policy.Id)/microsoft.graph.managedDeviceMobileAppConfiguration" ` -Targets $assignmentsHash ` -Repository 'deviceAppManagement/mobileAppConfigurations' } @@ -420,20 +452,21 @@ function Set-TargetResource Update-MgBetaDeviceAppManagementMobileAppConfiguration ` -ManagedDeviceMobileAppConfigurationId $currentInstance.Id ` -BodyParameter $UpdateParameters + $assignmentsHash = @() foreach ($assignment in $Assignments) { - $assignmentsHash += Get-M365DSCDRGComplexTypeToHashtable -ComplexObject $Assignment + $assignmentsHash += Get-M365DSCDRGComplexTypeToHashtable -ComplexObject $assignment } Update-DeviceConfigurationPolicyAssignment ` - -DeviceConfigurationPolicyId $currentInstance.id ` + -DeviceConfigurationPolicyId "$($currentInstance.Id)/microsoft.graph.managedDeviceMobileAppConfiguration" ` -Targets $assignmentsHash ` -Repository 'deviceAppManagement/mobileAppConfigurations' #endregion } elseif ($Ensure -eq 'Absent' -and $currentInstance.Ensure -eq 'Present') { - Write-Verbose -Message "Removing the Intune App Configuration Device Policy with Id {$($currentInstance.Id)}" + Write-Verbose -Message "Removing the Intune App Configuration Device Policy with Id {$($currentInstance.Id)}" #region resource generator code Remove-MgBetaDeviceAppManagementMobileAppConfiguration -ManagedDeviceMobileAppConfigurationId $currentInstance.Id #endregion @@ -552,7 +585,7 @@ function Test-TargetResource Write-Verbose -Message "Testing configuration of the Intune App Configuration Device Policy with Id {$Id} and DisplayName {$DisplayName}" $CurrentValues = Get-TargetResource @PSBoundParameters - $ValuesToCheck = ([Hashtable]$PSBoundParameters).clone() + $ValuesToCheck = ([Hashtable]$PSBoundParameters).Clone() if ($CurrentValues.Ensure -ne $Ensure) { @@ -566,29 +599,27 @@ function Test-TargetResource { $source = $PSBoundParameters.$key $target = $CurrentValues.$key - if ($source.getType().Name -like '*CimInstance*') + if ($source.GetType().Name -like '*CimInstance*') { $source = Get-M365DSCDRGComplexTypeToHashtable -ComplexObject $source - $testResult = Compare-M365DSCComplexObject ` - -Source ($source) ` - -Target ($target) - - if (-Not $testResult) + if ($key -eq "Assignments") { - $testResult = $false - break + $testResult = Compare-M365DSCIntunePolicyAssignment -Source $source -Target $target } + else + { + $testResult = Compare-M365DSCComplexObject -Source ($source) -Target ($target) + } + + if (-not $testResult) { break } $ValuesToCheck.Remove($key) | Out-Null } } - $ValuesToCheck.remove('Id') | Out-Null - $ValuesToCheck.Remove('Credential') | Out-Null - $ValuesToCheck.Remove('ApplicationId') | Out-Null - $ValuesToCheck.Remove('TenantId') | Out-Null - $ValuesToCheck.Remove('ApplicationSecret') | 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 $ValuesToCheck)" @@ -614,7 +645,7 @@ function Export-TargetResource ( [Parameter()] [System.String] - $Filter, + $Filter, [Parameter()] [System.Management.Automation.PSCredential] @@ -721,7 +752,7 @@ function Export-TargetResource { $complexTypeStringResult = Get-M365DSCDRGComplexTypeToString ` -ComplexObject $Results.Settings ` - -CIMInstanceName 'MicrosoftGraphappConfigurationSettingItem1' + -CIMInstanceName 'MicrosoftGraphappConfigurationSettingItem' if (-Not [String]::IsNullOrWhiteSpace($complexTypeStringResult)) { $Results.Settings = $complexTypeStringResult diff --git a/Modules/Microsoft365DSC/Dependencies/Manifest.psd1 b/Modules/Microsoft365DSC/Dependencies/Manifest.psd1 index 0f2ec20daa..72e0d0d0be 100644 --- a/Modules/Microsoft365DSC/Dependencies/Manifest.psd1 +++ b/Modules/Microsoft365DSC/Dependencies/Manifest.psd1 @@ -90,7 +90,7 @@ }, @{ ModuleName = "MSCloudLoginAssistant" - RequiredVersion = "1.1.16" + RequiredVersion = "1.1.17" }, @{ ModuleName = 'PnP.PowerShell' @@ -98,7 +98,7 @@ }, @{ ModuleName = 'ReverseDSC' - RequiredVersion = '2.0.0.19' + RequiredVersion = '2.0.0.20' } ) } diff --git a/Modules/Microsoft365DSC/Examples/Resources/AADAuthenticationFlowPolicy/2-Update.ps1 b/Modules/Microsoft365DSC/Examples/Resources/AADAuthenticationFlowPolicy/2-Update.ps1 new file mode 100644 index 0000000000..6e8e006574 --- /dev/null +++ b/Modules/Microsoft365DSC/Examples/Resources/AADAuthenticationFlowPolicy/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( + [System.Management.Automation.PSCredential] + $credsCredential + ) + + Import-DscResource -ModuleName Microsoft365DSC + + Node Localhost + { + AADAuthenticationFlowPolicy "AADAuthenticationFlowPolicy" + { + Credential = $credsCredential; + Description = "Authentication flows policy allows modification of settings related to authentication flows in AAD tenant, such as self-service sign up configuration."; + DisplayName = "Authentication flows policy"; + Id = "authenticationFlowsPolicy"; + IsSingleInstance = "Yes"; + SelfServiceSignUpEnabled = $True; + } + } +} diff --git a/Modules/Microsoft365DSC/Examples/Resources/AADEntitlementManagementRoleAssignment/1-Create.ps1 b/Modules/Microsoft365DSC/Examples/Resources/AADEntitlementManagementRoleAssignment/1-Create.ps1 new file mode 100644 index 0000000000..62fb587326 --- /dev/null +++ b/Modules/Microsoft365DSC/Examples/Resources/AADEntitlementManagementRoleAssignment/1-Create.ps1 @@ -0,0 +1,27 @@ +<# +This example is used to test new resources and showcase the usage of new resources being worked on. +It is not meant to use as a production baseline. +#> + +Configuration Example +{ + param( + [Parameter(Mandatory = $true)] + [PSCredential] + $Credscredential + ) + Import-DscResource -ModuleName Microsoft365DSC + + $Domain = $Credscredential.Username.Split('@')[1] + node localhost + { + AADEntitlementManagementRoleAssignment "AADEntitlementManagementRoleAssignment-Create" + { + AppScopeId = "/"; + Credential = $Credscredential + Ensure = "Present"; + Principal = "John.Smith@$Domain"; + RoleDefinition = "Catalog creator"; + } + } +} diff --git a/Modules/Microsoft365DSC/Examples/Resources/AADEntitlementManagementRoleAssignment/3-Remove.ps1 b/Modules/Microsoft365DSC/Examples/Resources/AADEntitlementManagementRoleAssignment/3-Remove.ps1 new file mode 100644 index 0000000000..c6fa5e0a91 --- /dev/null +++ b/Modules/Microsoft365DSC/Examples/Resources/AADEntitlementManagementRoleAssignment/3-Remove.ps1 @@ -0,0 +1,27 @@ +<# +This example is used to test new resources and showcase the usage of new resources being worked on. +It is not meant to use as a production baseline. +#> + +Configuration Example +{ + param( + [Parameter(Mandatory = $true)] + [PSCredential] + $Credscredential + ) + Import-DscResource -ModuleName Microsoft365DSC + + $Domain = $Credscredential.Username.Split('@')[1] + node localhost + { + AADEntitlementManagementRoleAssignment "AADEntitlementManagementRoleAssignment-Remove" + { + AppScopeId = "/"; + Credential = $Credscredential + Ensure = "Absent"; + Principal = "John.Smith@$Domain"; + RoleDefinition = "Catalog creator"; + } + } +} diff --git a/Modules/Microsoft365DSC/Microsoft365DSC.psd1 b/Modules/Microsoft365DSC/Microsoft365DSC.psd1 index 96ae26e63d..cfe31609ea 100644 --- a/Modules/Microsoft365DSC/Microsoft365DSC.psd1 +++ b/Modules/Microsoft365DSC/Microsoft365DSC.psd1 @@ -3,7 +3,7 @@ # # Generated by: Microsoft Corporation # -# Generated on: 2024-05-29 +# Generated on: 2024-06-05 @{ @@ -11,7 +11,7 @@ # RootModule = '' # Version number of this module. - ModuleVersion = '1.24.529.1' + ModuleVersion = '1.24.605.1' # Supported PSEditions # CompatiblePSEditions = @() @@ -142,30 +142,15 @@ IconUri = 'https://github.com/microsoft/Microsoft365DSC/blob/Dev/Modules/Microsoft365DSC/Dependencies/Images/Logo.png?raw=true' # ReleaseNotes of this module - ReleaseNotes = '* AADAdministrativeUnit - * Implemented advanced query based on - https://learn.microsoft.com/en-us/graph/aad-advanced-queries?tabs=http#administrative-unit-properties - * AADAuthenticationMethodPolicy - * Add support for disabled policies - * AADConditionalAccessPolicy - * Fix get method if value is null instead of false - * IntuneAppConfigurationDevicePolicy - * Initial release - * IntuneDeviceRemediation - * Added support for Access Tokens - * IntuneDiskEncryptionMacOS - * Initial Release - * IntuneSettingCatalogASRRulesPolicyWindows10 - * Add missing properties - FIXES [#4713](https://github.com/microsoft/Microsoft365DSC/issues/4713) - * O365AdminAuditLogConfig - * Fix logging of exception if Set-AdminAuditLogConfig fails - FIXES [#4645](https://github.com/microsoft/Microsoft365DSC/issues/4645) - * ResourceGenerator - * Added `AccessTokens` parameter to PS1 and MOF template + ReleaseNotes = '* AADEntitlementManagementRoleAssignment + * Initial Release. + * M365DSCResourceGenerator + * Add support for generating Intune settings catalog policies + * M365DSCDRGUtil + * Add multiple commands for Intune policies that use the settings catalog * DEPENDENCIES - * Updated DSCParser to version 2.0.0.5. - * Rolling back ExchangeOnlineManagement to version 3.4.0.' + * Updated MSCloudLoginAssistant to version 1.1.17. + * Updated ReverseDSC to version 2.0.0.20.' # Flag to indicate whether the module requires explicit user acceptance for install/update # RequireLicenseAcceptance = $false diff --git a/Modules/Microsoft365DSC/Modules/M365DSCDRGUtil.psm1 b/Modules/Microsoft365DSC/Modules/M365DSCDRGUtil.psm1 index 3c92111b1f..412350e301 100644 --- a/Modules/Microsoft365DSC/Modules/M365DSCDRGUtil.psm1 +++ b/Modules/Microsoft365DSC/Modules/M365DSCDRGUtil.psm1 @@ -1275,29 +1275,46 @@ function Compare-M365DSCIntunePolicyAssignment $Target ) - $testResult = $source.count -eq $target.count + $testResult = $Source.Count -eq $Target.Count if ($testResult) { - foreach ($assignment in $source) + foreach ($assignment in $Source) { - if ($assignment.dataType -like '*GroupAssignmentTarget') + if ($assignment.dataType -like '*groupAssignmentTarget') { - $testResult = $null -ne ($target | Where-Object {$_.dataType -eq $assignment.DataType -and $_.groupId -eq $assignment.groupId}) - #Using assignment groupDisplayName only if the groupId is not found in the directory otherwise groupId should be the key + $assignmentTarget = $Target | Where-Object -FilterScript { $_.dataType -eq $assignment.DataType -and $_.groupId -eq $assignment.groupId } + $testResult = $null -ne $assignmentTarget + # Using assignment groupDisplayName only if the groupId is not found in the directory otherwise groupId should be the key if (-not $testResult) { $groupNotFound = $null -eq (Get-MgGroup -GroupId ($assignment.groupId) -ErrorAction SilentlyContinue) } if (-not $testResult -and $groupNotFound) { - $testResult = $null -ne ($target | Where-Object {$_.dataType -eq $assignment.DataType -and $_.groupDisplayName -eq $assignment.groupDisplayName}) + $assignmentTarget = $Target | Where-Object -FilterScript { $_.dataType -eq $assignment.DataType -and $_.groupDisplayName -eq $assignment.groupDisplayName } + $testResult = $null -ne $assignmentTarget + } + + if ($testResult) + { + $isFilterIdSpecified = $assignment.deviceAndAppManagementAssignmentFilterType -ne 'none' + $testResult = $assignment.deviceAndAppManagementAssignmentFilterType -eq $assignmentTarget.deviceAndAppManagementAssignmentFilterType + if ($testResult -and $isFilterIdSpecified) + { + $testResult = $assignment.deviceAndAppManagementAssignmentFilterId -eq $assignmentTarget.deviceAndAppManagementAssignmentFilterId + } + } + + if ($testResult) + { + $testResult = $assignment.collectionId -eq $assignmentTarget.collectionId } } else { - $testResult = $null -ne ($target | Where-Object {$_.dataType -eq $assignment.DataType}) + $testResult = $null -ne ($Target | Where-Object -FilterScript { $_.dataType -eq $assignment.DataType }) } - if (-Not $testResult) { break } + if (-not $testResult) { break } } } @@ -1474,3 +1491,520 @@ function Get-OmaSettingPlainTextValue return $null } } + +function Get-IntuneSettingCatalogPolicySetting +{ + [CmdletBinding()] + [OutputType([System.Array])] + param( + [Parameter(Mandatory = 'true')] + [System.Collections.Hashtable] + $DSCParams, + [Parameter(Mandatory = 'true')] + [System.String] + $TemplateId + ) + + $global:excludedDefinitionIds = @() + + $DSCParams.Remove('Identity') | Out-Null + $DSCParams.Remove('DisplayName') | Out-Null + $DSCParams.Remove('Description') | Out-Null + + #Prepare setting definitions mapping + $settingTemplates = Get-MgBetaDeviceManagementConfigurationPolicyTemplateSettingTemplate -DeviceManagementConfigurationPolicyTemplateId $TemplateId -ExpandProperty 'SettingDefinitions' + $settingInstances = @() + foreach ($settingInstanceTemplate in $settingTemplates.SettingInstanceTemplate) + { + $settingInstance = @{} + $settingDefinition = $settingTemplates.SettingDefinitions | Where-Object { + $_.Id -eq $settingInstanceTemplate.SettingDefinitionId -and ` + ($_.AdditionalProperties.dependentOn.Count -eq 0 -and $_.AdditionalProperties.options.dependentOn.Count -eq 0) + } + $settingName = $settingInstanceTemplate.SettingDefinitionId.split('_') | Select-Object -Last 1 + $settingType = $settingInstanceTemplate.AdditionalProperties.'@odata.type'.Replace('InstanceTemplate', 'Instance') + $settingInstance.Add('settingDefinitionId', $settingInstanceTemplate.settingDefinitionId) + $settingInstance.Add('@odata.type', $settingType) + if (-not [string]::IsNullOrEmpty($settingInstanceTemplate.settingInstanceTemplateId)) + { + $settingInstance.Add('settingInstanceTemplateReference', @{'settingInstanceTemplateId' = $settingInstanceTemplate.settingInstanceTemplateId }) + } + $settingValueName = $settingType.Replace('#microsoft.graph.deviceManagementConfiguration', '').Replace('Instance', 'Value') + $settingValueName = $settingValueName.Substring(0, 1).ToLower() + $settingValueName.Substring(1, $settingValueName.length - 1 ) + $settingValueType = $settingInstanceTemplate.AdditionalProperties."$($settingValueName)Template".'@odata.type' + if ($null -ne $settingValueType) + { + $settingValueType = $settingValueType.Replace('ValueTemplate', 'Value') + } + $settingValueTemplateId = $settingInstanceTemplate.AdditionalProperties."$($settingValueName)Template".settingValueTemplateId + $settingValue = Get-IntuneSettingCatalogPolicySettingInstanceValue ` + -DSCParams $DSCParams ` + -SettingDefinition $settingDefinition ` + -SettingTemplates $settingTemplates ` + -SettingName $settingName ` + -SettingType $settingType ` + -SettingValueName $settingValueName ` + -SettingValueType $settingValueType ` + -SettingValueTemplateId $settingValueTemplateId + if ($settingValue.Count -gt 0) + { + $settingInstance += [Hashtable]$settingValue + $settingInstances += @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting' + 'settingInstance' = $settingInstance + } + } + } + + return $settingInstances +} + +function Get-IntuneSettingCatalogPolicySettingInstanceValue +{ + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + param( + [Parameter(Mandatory = 'true')] + [System.Collections.Hashtable] + $DSCParams, + + [Parameter()] + $SettingDefinition, + + [Parameter()] + $SettingTemplates, + + [Parameter()] + [System.String] + $SettingType, + + [Parameter()] + [System.String] + $SettingName, + + [Parameter()] + [System.String] + $SettingValueName, + + [Parameter()] + [System.String] + $SettingValueType, + + [Parameter()] + [System.String] + $SettingValueTemplateId + ) + + $settingValuesToReturn = @{} + if ($null -eq $global:excludedDefinitionIds) + { + $global:excludedDefinitionIds = @() + } + switch ($settingType) + { + '#microsoft.graph.deviceManagementConfigurationGroupSettingCollectionInstance' + { + $groupSettingCollectionValue = @{} + $groupSettingCollectionValueChildren = @() + + $groupSettingCollectionDefinitionChildren = $SettingTemplates.SettingDefinitions | Where-Object { + ($_.AdditionalProperties.dependentOn.Count -gt 0 -and $_.AdditionalProperties.dependentOn.parentSettingId.Contains($SettingDefinition.Id)) -or + ($_.AdditionalProperties.options.dependentOn.Count -gt 0 -and $_.AdditionalProperties.options.dependentOn.parentSettingId.Contains($SettingDefinition.Id)) + } + foreach ($childDefinition in $groupSettingCollectionDefinitionChildren) + { + $childSettingName = $childDefinition.Name + $childSettingType = $childDefinition.AdditionalProperties.'@odata.type'.Replace('Definition', 'Instance') + $childSettingValueName = $childSettingType.Replace('#microsoft.graph.deviceManagementConfiguration', '').Replace('Instance', 'Value') + $childSettingValueType = "#microsoft.graph.deviceManagementConfiguration$($childSettingValueName)" + $childSettingValueName = $childSettingValueName.Substring(0, 1).ToLower() + $childSettingValueName.Substring(1, $childSettingValueName.length - 1 ) + $childSettingValue = Get-IntuneSettingCatalogPolicySettingInstanceValue ` + -DSCParams $DSCParams ` + -SettingDefinition $childDefinition ` + -SettingTemplates $SettingTemplates ` + -SettingName $childSettingName ` + -SettingType $childDefinition.AdditionalProperties.'@odata.type' ` + -SettingValueName $childSettingValueName ` + -SettingValueType $childSettingValueType ` + + if ($null -ne $childSettingValue) + { + $childSettingValue.Add('settingDefinitionId', $childDefinition.Id) + $childSettingValue.Add('@odata.type', $childSettingType) + $groupSettingCollectionValueChildren += $childSettingValue + } + } + + if ($groupSettingCollectionDefinitionChildren.Count -gt 0) { + $groupSettingCollectionValue.Add('children', $groupSettingCollectionValueChildren) + $settingValuesToReturn.Add('groupSettingCollectionValue', @($groupSettingCollectionValue)) + } + } + { $_ -eq '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' -or $_ -eq '#microsoft.graph.deviceManagementConfigurationChoiceSettingDefinition' } + { + $choiceSettingValue = @{} + $choiceSettingValueChildren = @() + + $choiceSettingDefinitionChildren = $SettingTemplates.SettingDefinitions | Where-Object { + ($_.AdditionalProperties.dependentOn.Count -gt 0 -and $_.AdditionalProperties.dependentOn.parentSettingId.Contains($SettingDefinition.Id)) -or + ($_.AdditionalProperties.options.dependentOn.Count -gt 0 -and $_.AdditionalProperties.options.dependentOn.parentSettingId.Contains($SettingDefinition.Id)) + } + foreach ($childDefinition in $choiceSettingDefinitionChildren) + { + $childSettingName = $childDefinition.Name + $childSettingType = $childDefinition.AdditionalProperties.'@odata.type'.Replace('Definition', 'Instance') + $childSettingValueName = $childSettingType.Replace('#microsoft.graph.deviceManagementConfiguration', '').Replace('Instance', 'Value') + $childSettingValueType = "#microsoft.graph.deviceManagementConfiguration$($childSettingValueName)" + $childSettingValueName = $childSettingValueName.Substring(0, 1).ToLower() + $childSettingValueName.Substring(1, $childSettingValueName.length - 1 ) + $childSettingValue = Get-IntuneSettingCatalogPolicySettingInstanceValue ` + -DSCParams $DSCParams ` + -SettingDefinition $childDefinition ` + -SettingTemplates $SettingTemplates ` + -SettingName $childSettingName ` + -SettingType $childDefinition.AdditionalProperties.'@odata.type' ` + -SettingValueName $childSettingValueName ` + -SettingValueType $childSettingValueType ` + + if ($childSettingValue.Keys.Count -gt 0) + { + $childSettingValue.Add('settingDefinitionId', $childDefinition.Id) + $childSettingValue.Add('@odata.type', $childSettingValueType) + $choiceSettingValueChildren += $childSettingValue + } + } + + if ($choiceSettingDefinitionChildren.Count -gt 0) { + $choiceSettingValue.Add('children', $choiceSettingValueChildren) + } + if ($null -ne $DSCParams[$SettingName]) + { + $value = "$($SettingDefinition.Id)_$($DSCParams[$SettingName])" + $choiceSettingValue.Add('value', $value) + $choiceSettingValue.Add('@odata.type', $SettingType.Replace('Instance', 'Value')) + if (-Not [string]::IsNullOrEmpty($SettingValueTemplateId)) + { + $choiceSettingValue.Add('settingValueTemplateReference', @{'settingValueTemplateId' = $SettingValueTemplateId }) + } + } + if ($choiceSettingValue.Keys.Count -gt 0) + { + $settingValuesToReturn.Add('choiceSettingValue', $choiceSettingValue) + } + } + { $_ -eq '#microsoft.graph.deviceManagementConfigurationSimpleSettingCollectionInstance' -or $_ -eq '#microsoft.graph.deviceManagementConfigurationSimpleSettingCollectionDefinition' } + { + $values = @() + foreach ($key in $DSCParams.Keys) + { + $matchCombined = $false + $matchesId = $false + $name = $SettingTemplates.SettingDefinitions.Name | Where-Object -FilterScript { $_ -eq $key } + if ($name.Count -ne 1) + { + # Key might have been combined with parent setting, try to split it + if ($key -like "*_*") + { + $parentSettingName = $key.Split('_')[0] + $childSettingName = $key.Replace("$($parentSettingName)_", '') + $parentDefinition = $SettingTemplates.SettingDefinitions | Where-Object { $_.Name -eq $parentSettingName } + $childDefinition = $SettingTemplates.SettingDefinitions | Where-Object { $_.Name -eq $childSettingName -and $_.AdditionalProperties.dependentOn.parentSettingId.Contains($parentDefinition.Id) } + if ($null -ne $parentDefinition -and $null -ne $childDefinition) + { + $matchCombined = $true + } + } + + if (-not $matchCombined) + { + # Parent was not combined, look for the id + $SettingTemplates.SettingDefinitions | ForEach-Object { + if ($_.Id -notin $global:excludedDefinitionIds -and $_.Name -eq $SettingName -and $_.Id -like "*$key") + { + $global:excludedDefinitionIds += $_.Id + $matchesId = $true + } + } + } + } + if (($name.Count -eq 1 -and $SettingName -eq $key) -or $matchCombined -or $matchesId) + { + $values = $DSCParams[$key] + break + } + } + $settingValueCollection = @() + foreach ($v in $values) + { + $settingValueCollection += @{ + value = $v + '@odata.type' = $settingValueType + } + } + if ($settingValueCollection.Count -gt 0) { + $settingValuesToReturn.Add($settingValueName, $settingValueCollection) + } + } + Default + { + $value = $null + foreach ($key in $DSCParams.Keys) + { + $matchCombined = $false + $matchesId = $false + $name = $SettingTemplates.SettingDefinitions.Name | Where-Object -FilterScript { $_ -eq $key } + if ($name.Count -ne 1) + { + # Key might have been combined with parent setting, try to split it + if ($key -like "*_*") + { + $parentSettingName = $key.Split('_')[0] + $childSettingName = $key.Replace("$($parentSettingName)_", '') + $parentDefinition = $SettingTemplates.SettingDefinitions | Where-Object { $_.Name -eq $parentSettingName } + $childDefinition = $SettingTemplates.SettingDefinitions | Where-Object { $_.Name -eq $childSettingName } + if ($null -ne $parentDefinition -and $null -ne $childDefinition) + { + # Parent was combined with child setting + $matchCombined = $true + } + } + + if (-not $matchCombined) + { + # Parent was not combined, look for the id + $SettingTemplates.SettingDefinitions | ForEach-Object { + if ($_.Id -notin $global:excludedDefinitionIds -and $_.Name -eq $SettingName -and $_.Id -like "*$key") + { + $global:excludedDefinitionIds += $_.Id + $matchesId = $true + } + } + } + } + if (($name.Count -eq 1 -and $SettingName -eq $key) -or $matchCombined -or $matchesId) + { + if ($SettingValueType -like "*Simple*" -or $SettingValueType -in @("#microsoft.graph.deviceManagementConfigurationIntegerSettingValue", "#microsoft.graph.deviceManagementConfigurationStringSettingValue")) + { + $value = $DSCParams[$key] + } + else + { + $value = "$($SettingDefinition.Id)_$($DSCParams[$key])" + } + break + } + } + + if ($null -eq $value) + { + return $null + } + + $settingValue = @{} + if (-Not [string]::IsNullOrEmpty($settingValueType)) + { + $settingValue.Add('@odata.type', $settingValueType) + } + if (-Not [string]::IsNullOrEmpty($settingValueTemplateId)) + { + $settingValue.Add('settingValueTemplateReference', @{'settingValueTemplateId' = $settingValueTemplateId }) + } + $settingValue.Add('value', $value) + + $settingValuesToReturn.Add($settingValueName, $settingValue) + } + } + return $settingValuesToReturn +} + +function Export-IntuneSettingCatalogPolicySettings +{ + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + param( + [Parameter( + Mandatory = $true, + ParameterSetName = 'Start' + )] + $Settings, + + [Parameter( + Mandatory = $true + )] + [System.Collections.Hashtable]$ReturnHashtable, + + [Parameter( + Mandatory = $true, + ParameterSetName = 'Setting' + )] + $SettingInstance, + + [Parameter( + Mandatory = $true, + ParameterSetName = 'Setting' + )] + $SettingDefinitions, + + [Parameter( + ParameterSetName = 'Setting' + )] + [switch]$IsRoot + ) + + if ($PSCmdlet.ParameterSetName -eq 'Start') + { + foreach ($setting in $Settings) + { + Export-IntuneSettingCatalogPolicySettings -SettingInstance $setting.SettingInstance -SettingDefinitions $setting.SettingDefinitions -ReturnHashtable $ReturnHashtable -IsRoot + } + return $ReturnHashtable + } + + $addToParameters = $true + $settingDefinition = $SettingDefinitions | Where-Object -FilterScript { $_.Id -eq $SettingInstance.settingDefinitionId } + $settingName = $settingDefinition | Select-Object -ExpandProperty Name + + # Check if the name is unique + $settingMatches = $SettingDefinitions | Where-Object -FilterScript { $_.Name -eq $settingName } + if ($settingMatches.Count -gt 1) + { + if ($settingDefinition.AdditionalProperties.dependentOn.parentSettingId.Count -gt 0) + { + $parentSetting = $SettingDefinitions | Where-Object -FilterScript { $_.Id -eq $($settingDefinition.AdditionalProperties.dependentOn.parentSettingId | Select-Object -Unique -First 1) } + } + elseif ($settingDefinition.AdditionalProperties.options.dependentOn.parentSettingId.Count -gt 0) + { + $parentSetting = $SettingDefinitions | Where-Object -FilterScript { $_.Id -eq $($settingDefinition.AdditionalProperties.dependentOn.parentSettingId | Select-Object -Unique -First 1) } + } + + $combinationMatches = $SettingDefinitions | Where-Object -FilterScript { + $_.Name -eq $settingName -and ` + (($_.AdditionalProperties.dependentOn.parentSettingId.Count -gt 0 -and $_.AdditionalProperties.dependentOn.parentSettingId.Contains($parentSetting.Id)) -or ` + ($_.AdditionalProperties.options.dependentOn.parentSettingId.Count -gt 0 -and $_.AdditionalProperties.options.dependentOn.parentSettingId.Contains($parentSetting.Id))) + } + + # If the combination of parent setting and setting name is unique, add the parent setting name to the setting name + if ($combinationMatches.Count -eq 1) + { + $settingName = $($parentSetting.Name) + "_" + $settingName + } + # If the combination of parent setting and setting name is still not unique, grab the last part of the setting id + else + { + $parentSettingIdProperty = $parentSetting.Id.Split('_')[-1] + $parentSettingIdWithoutProperty = $parentSetting.Id.Replace("_$parentSettingIdProperty", "") + # We can't use the entire setting here, because the child setting id does not have to come after the parent setting id + $settingName = $settingDefinition.Id.Replace($parentSettingIdWithoutProperty + "_", "").Replace($parentSettingIdProperty + "_", "") + } + } + + $odataType = if ($IsRoot) { $SettingInstance.AdditionalProperties.'@odata.type' } else { $SettingInstance.'@odata.type' } + switch ($odataType) + { + '#microsoft.graph.deviceManagementConfigurationSimpleSettingInstance' + { + $settingValue = if ($IsRoot) { $SettingInstance.AdditionalProperties.simpleSettingValue.value } else { $SettingInstance.simpleSettingValue.value } + } + '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' + { + $settingValue = if ($IsRoot) { $SettingInstance.AdditionalProperties.choiceSettingValue.value } else { $SettingInstance.choiceSettingValue.value } + $settingValue = $settingValue.Split('_') | Select-Object -Last 1 + $childSettings = if ($IsRoot) { $SettingInstance.AdditionalProperties.choiceSettingValue.children } else { $SettingInstance.choiceSettingValue.children } + foreach ($childSetting in $childSettings) + { + Export-IntuneSettingCatalogPolicySettings -SettingInstance $childSetting -SettingDefinitions $SettingDefinitions -ReturnHashtable $ReturnHashtable + } + } + '#microsoft.graph.deviceManagementConfigurationGroupSettingCollectionInstance' + { + $values = @() + $childSettings = if ($IsRoot) { $SettingInstance.AdditionalProperties.groupSettingCollectionValue.children } else { $SettingInstance.groupSettingCollectionValue.children } + foreach ($value in $childSettings) + { + Export-IntuneSettingCatalogPolicySettings -SettingInstance $value -SettingDefinitions $SettingDefinitions -ReturnHashtable $ReturnHashtable + $addToParameters = $false + } + } + '#microsoft.graph.deviceManagementConfigurationSimpleSettingCollectionInstance' + { + $values = @() + $childValues = if ($IsRoot) { $SettingInstance.AdditionalProperties.simpleSettingCollectionValue.value } else { $SettingInstance.simpleSettingCollectionValue.value } + foreach ($value in $childValues) + { + $values += $value + } + $settingValue = $values + } + Default + { + $settingValue = $SettingInstance.value + } + } + + if ($addToParameters) + { + $ReturnHashtable.Add($settingName, $settingValue) + } +} + +function Update-IntuneDeviceConfigurationPolicy +{ + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + param + ( + [Parameter(Mandatory = 'true')] + [System.String] + $DeviceConfigurationPolicyId, + + [Parameter()] + [System.String] + $Name, + + [Parameter()] + [System.String] + $Description, + + [Parameter()] + [System.String] + $Platforms, + + [Parameter()] + [System.String] + $Technologies, + + [Parameter()] + [System.String] + $TemplateReferenceId, + + [Parameter()] + [Array] + $Settings + ) + + try + { + $Uri = "https://graph.microsoft.com/beta/deviceManagement/configurationPolicies/$DeviceConfigurationPolicyId" + + $policy = @{ + 'name' = $Name + 'description' = $Description + 'platforms' = $Platforms + 'templateReference' = @{'templateId' = $TemplateReferenceId } + 'technologies' = $Technologies + 'settings' = $Settings + } + $body = $policy | ConvertTo-Json -Depth 20 + #write-verbose -Message $body + Invoke-MgGraphRequest -Method PUT -Uri $Uri -Body $body -ErrorAction Stop + } + catch + { + New-M365DSCLogEntry -Message 'Error updating data:' ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + + return $null + } +} \ No newline at end of file diff --git a/Modules/Microsoft365DSC/SchemaDefinition.json b/Modules/Microsoft365DSC/SchemaDefinition.json index 6d074602d7..75eb5f802a 100644 --- a/Modules/Microsoft365DSC/SchemaDefinition.json +++ b/Modules/Microsoft365DSC/SchemaDefinition.json @@ -748,7 +748,7 @@ "ClassName": "MSFT_AADAuthenticationMethodPolicyAuthenticator", "Parameters": [ { - "CIMType": "MSFT_MicrosoftGraphmicrosoftAuthenticatorFeatureSettings", + "CIMType": "MSFT_MicrosoftGraphMicrosoftAuthenticatorFeatureSettings", "Name": "FeatureSettings", "Option": "Write" }, @@ -3279,6 +3279,76 @@ } ] }, + { + "ClassName": "MSFT_AADEntitlementManagementRoleAssignment", + "Parameters": [ + { + "CIMType": "String", + "Name": "Id", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "Principal", + "Option": "Key" + }, + { + "CIMType": "String", + "Name": "RoleDefinition", + "Option": "Key" + }, + { + "CIMType": "String", + "Name": "AppScopeId", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "DirectoryScopeId", + "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_AADExternalIdentityPolicy", "Parameters": [ diff --git a/ResourceGenerator/M365DSCResourceGenerator.psm1 b/ResourceGenerator/M365DSCResourceGenerator.psm1 index 496e53bddf..3c5c585ac9 100644 --- a/ResourceGenerator/M365DSCResourceGenerator.psm1 +++ b/ResourceGenerator/M365DSCResourceGenerator.psm1 @@ -55,7 +55,12 @@ function New-M365DSCResource [Parameter()] [System.String] - $DateFormat="o", + $DateFormat = "o", + + # SettingTemplates for DeviceManagementConfigurationPolicy + [Parameter()] + [System.Array] + $SettingsCatalogSettingTemplates, # Use this switch with caution. # Navigation Properties could cause the DRG to enter an infinite loop @@ -63,7 +68,7 @@ function New-M365DSCResource # Only include if it contains a property which is NOT read-only. [Parameter()] [System.Boolean] - $IncludeNavigationProperties=$false, + $IncludeNavigationProperties = $false, [Parameter()] [System.Management.Automation.PSCredential] @@ -76,7 +81,7 @@ function New-M365DSCResource $readmeFilePath = New-M365DSCReadmeFile -ResourceName $ResourceName -Path $Path $unitTestPath = New-M365DSCUnitTest -ResourceName $ResourceName -Path $UnitTestPath - $graphWorkloads=@('MicrosoftGraph','Intune') + $graphWorkloads = @('MicrosoftGraph','Intune') if ($Workload -in $graphWorkloads) { $Global:CIMInstancesAlreadyFound = @() @@ -131,7 +136,7 @@ function New-M365DSCResource -APIVersion $ApiVersion #Check if the actual type returns multiple type of policies - $policyTypes=($cmdletDefinition.EntityType|Where-Object -FilterScript {$_.basetype -like "*$actualType"}).Name + $policyTypes = ($cmdletDefinition.EntityType | Where-Object -FilterScript { $_.basetype -like "*$actualType" }).Name if ($null -ne $policyTypes -and $policyTypes.GetType().Name -like '*[[\]]') { if ([String]::IsNullOrEmpty($AdditionalPropertiesType)) @@ -141,8 +146,7 @@ function New-M365DSCResource { $policyTypeChoices += [System.Management.Automation.Host.ChoiceDescription]("$($policyTypes[$i])") } - $typeChoice = $host.UI.PromptForChoice('Additional Type Information', 'Please select an addtional type', $policyTypeChoices, 0) + 1 - + $typeChoice = $host.UI.PromptForChoice('Additional Type Information', 'Please select an additional type', $policyTypeChoices, 0) + 1 $selectedODataType = $policyTypes[$typeChoice - 1] } @@ -174,7 +178,7 @@ function New-M365DSCResource $AssignmentsConvertComplexToString = '' $AssignmentsConvertComplexToVariable = '' - $global:ComplexList=@() + $global:ComplexList = @() $cimClasses = Get-Microsoft365DSCModuleCimClass -ResourceName $ResourceName $global:searchedEntity = $selectedODataType $typeProperties = Get-TypeProperties ` @@ -183,6 +187,9 @@ function New-M365DSCResource -IncludeNavigationProperties $IncludeNavigationProperties ` -CimClasses $cimClasses ` -Workload $Workload + $typeProperties = $typeProperties | Where-Object -FilterScript { + $_.Name -notin @('createdDateTime', 'isAssigned', 'lastModifiedDateTime', 'priorityMetaData', 'retryCount', 'settingCount', 'templateReference') + } $global:ComplexList = $null $global:searchedEntity = $null [Hashtable[]]$parameterInformation = Get-ParameterBlockInformation ` @@ -192,11 +199,11 @@ function New-M365DSCResource #retrieve assignment details if ($Workload -in @('Intune', 'MicrosoftGraph')) { - $repository=($commandDetails|where-Object -filterScript {$_.variants -eq 'List'}).URI - $repository=$repository.Substring(1,($repository.Length - 1)) - $assignmentCmdlet=Get-Command ($cmdletFound.Name+'Assignment') -Module $GraphModule -ErrorAction SilentlyContinue + $repository = ($commandDetails | Where-Object -FilterScript {$_.variants -eq 'List'}).URI + $repository = $repository.Substring(1, ($repository.Length - 1)) + $assignmentCmdlet = Get-Command -Name ($cmdletFound.Name + 'Assignment') -Module $GraphModule -ErrorAction SilentlyContinue $assignmentCmdletNoun = $assignmentCmdlet.Noun - $assignmentKey = (($assignmentCmdlet.ParameterSets|where-Object -filterScript {$_.Name -eq 'List'}).Parameters | where-Object -filterScript {$_.IsMandatory}).Name + $assignmentKey = (($assignmentCmdlet.ParameterSets | Where-Object -FilterScript { $_.Name -eq 'List' }).Parameters | Where-Object -FilterScript { $_.IsMandatory }).Name if (-not [String]::IsNullOrWhiteSpace($repository) ` -and -not [String]::IsNullOrWhiteSpace($assignmentCmdletNoun) ` -and -not [String]::IsNullOrWhiteSpace($assignmentKey)) @@ -236,6 +243,32 @@ function New-M365DSCResource -DateFormat $DateFormat $hashTableMapping = $hashtableResults.StringContent + if ($CmdLetNoun -like "*DeviceManagementConfigurationPolicy") + { + if ($SettingsCatalogSettingTemplates.Count -eq 0) + { + throw "SettingsCatalogSettingTemplates is required for DeviceManagementConfigurationPolicy resources" + } + + $templateSettings = @() + foreach ($settingTemplate in $SettingsCatalogSettingTemplates) + { + $templateSettings += New-SettingsCatalogSettingDefinitionSettingsFromTemplate ` + -FromRoot ` + -SettingTemplate $settingTemplate + } + + $definitionSettings = @() + foreach ($templateSetting in $templateSettings) + { + $definitionSettings += New-ParameterDefinitionFromSettingsCatalogTemplateSetting ` + -TemplateSetting $templateSetting + } + + $parameterString += $definitionSettings.PowerShell -join ",`r`n`r`n" + $parameterString += ",`r`n`r`n" + } + #region UnitTests $fakeValues = Get-M365DSCFakeValues ` -ParametersInformation $parameterInformation ` @@ -259,12 +292,12 @@ function New-M365DSCResource $assignmentMock += " }`r`n" } - Write-TokenReplacement -Token '' -value $assignmentMock -FilePath $unitTestPath - Write-TokenReplacement -Token '' -value $fakeValuesString -FilePath $unitTestPath - Write-TokenReplacement -Token '' -value $targetResourceFakeValuesString -FilePath $unitTestPath + Write-TokenReplacement -Token '' -Value $assignmentMock -FilePath $unitTestPath + Write-TokenReplacement -Token '' -Value $fakeValuesString -FilePath $unitTestPath + Write-TokenReplacement -Token '' -Value $targetResourceFakeValuesString -FilePath $unitTestPath $fakeValues2 = $fakeValues $fakeValuesString2 = Get-M365DSCHashAsString -Values $fakeValues2 -isCmdletCall $true - Write-TokenReplacement -Token '' -value $fakeValuesString2 -FilePath $unitTestPath + Write-TokenReplacement -Token '' -Value $fakeValuesString2 -FilePath $unitTestPath $fakeDriftValues = Get-M365DSCFakeValues -ParametersInformation $parameterInformation ` -IntroduceDrift $true ` @@ -273,15 +306,15 @@ function New-M365DSCResource -Workload $Workload ` -DateFormat $DateFormat $fakeDriftValuesString = Get-M365DSCHashAsString -Values $fakeDriftValues -isCmdletCall $true - Write-TokenReplacement -Token '' -value $fakeDriftValuesString -FilePath $unitTestPath - Write-TokenReplacement -Token '' -value $ResourceName -FilePath $unitTestPath + Write-TokenReplacement -Token '' -Value $fakeDriftValuesString -FilePath $unitTestPath + Write-TokenReplacement -Token '' -Value $ResourceName -FilePath $unitTestPath - Write-TokenReplacement -Token '' -value $GetcmdletName -FilePath $unitTestPath - $updateVerb='Update' - $updateCmdlet=Find-MgGraphCommand -Command "$updateVerb-$CmdLetNoun" -ApiVersion $ApiVersion -errorAction SilentlyContinue + Write-TokenReplacement -Token '' -Value $GetcmdletName -FilePath $unitTestPath + $updateVerb = 'Update' + $updateCmdlet = Find-MgGraphCommand -Command "$updateVerb-$CmdLetNoun" -ApiVersion $ApiVersion -ErrorAction SilentlyContinue if ($null -eq $updateCmdlet) { - $updateVerb='Set' + $updateVerb = 'Set' } Write-TokenReplacement -Token '' -value "$updateVerb-$($CmdLetNoun)" -FilePath $unitTestPath Write-TokenReplacement -Token '' -value "Remove-$($CmdLetNoun)" -FilePath $unitTestPath @@ -295,6 +328,7 @@ function New-M365DSCResource #region Module $platforms = @{ 'Windows10' = 'for Windows10' + 'Windows11' = 'for Windows11' 'Android' = 'for Android' 'Mac O S' = 'for macOS' 'I O S' = 'for iOS' @@ -305,7 +339,7 @@ function New-M365DSCResource { if ($resourceDescription -like "*$platform*") { - $resourceDescription = $resourceDescription.replace($platform, $platforms.$platform) + $resourceDescription = $resourceDescription.Replace($platform, $platforms.$platform) } $resourceDescription = $resourceDescription.Replace('Azure A D','Azure AD') } @@ -314,7 +348,7 @@ function New-M365DSCResource $getDefaultParameterSet = $getCmdlet.ParameterSets | Where-Object -FilterScript { $_.Name -eq 'Get' } $getKeyIdentifier = ($getDefaultParameterSet.Parameters | Where-Object -FilterScript { $_.IsMandatory }).Name - if ([String]::isNullOrEmpty($getKeyIdentifier)) + if ([String]::IsNullOrEmpty($getKeyIdentifier)) { $getDefaultParameterSet = $getCmdlet.ParameterSets | Where-Object -FilterScript { $_.IsDefault } $getKeyIdentifier = ($getDefaultParameterSet.Parameters | Where-Object -FilterScript { $_.IsMandatory }).Name @@ -332,44 +366,44 @@ function New-M365DSCResource } } - if ($null -ne $getKeyIdentifier ) + if ($null -ne $getKeyIdentifier) { $getParameterString = [System.Text.StringBuilder]::New() - foreach ($key in $getKeyIdentifier ) + foreach ($key in $getKeyIdentifier) { if ($getKeyIdentifier.Count -gt 1) { - $getParameterString.append("```r`n") |out-null - $getParameterString.append(" ") |out-null + $getParameterString.Append("```r`n") | Out-Null + $getParameterString.Append(" ") | Out-Null } $keyValue = $key if ($key -eq "$($actualtype)Id") { $keyValue = $primaryKey } - $getParameterString.append("-$key `$$keyValue ") |out-null + $getParameterString.Append("-$key `$$keyValue ") | Out-Null } [String]$getKeyIdentifier = $getParameterString.ToString() } $getDefaultParameterSet = $getCmdlet.ParameterSets | Where-Object -FilterScript { $_.Name -eq 'List' } - $getListIdentifier =$getDefaultParameterSet.Parameters.Name + $getListIdentifier = $getDefaultParameterSet.Parameters.Name $getAlternativeFilterString = [System.Text.StringBuilder]::New() if ($getListIdentifier -contains 'Filter') { - $getAlternativeFilterString.appendline(" -Filter `"$alternativeKey eq '`$$alternativeKey'`" ``")|out-null - $getAlternativeFilterString.appendline(" -ErrorAction SilentlyContinue | Where-Object ``")|out-null - $getAlternativeFilterString.appendline(" -FilterScript { ``")|out-null - $getAlternativeFilterString.appendline(" `$_.AdditionalProperties.'@odata.type' -eq `"`#microsoft.graph.$SelectedODataType`" ``")|out-null - $getAlternativeFilterString.append(" }")|out-null + $getAlternativeFilterString.AppendLine(" -Filter `"$alternativeKey eq '`$$alternativeKey'`" ``") | Out-Null + $getAlternativeFilterString.AppendLine(" -ErrorAction SilentlyContinue | Where-Object ``") | Out-Null + $getAlternativeFilterString.AppendLine(" -FilterScript { ``") | Out-Null + $getAlternativeFilterString.AppendLine(" `$_.AdditionalProperties.'@odata.type' -eq `"`#microsoft.graph.$SelectedODataType`" ``") | Out-Null + $getAlternativeFilterString.Append(" }") | Out-Null } else { - $getAlternativeFilterString.appendline(" -ErrorAction SilentlyContinue | Where-Object ``")|out-null - $getAlternativeFilterString.appendline(" -FilterScript { ``")|out-null - $getAlternativeFilterString.appendline(" `$_.$alternativeKey -eq `"`$(`$$alternativeKey)`" ``")|out-null - $getAlternativeFilterString.appendline(" -and `$_.AdditionalProperties.'@odata.type' -eq `"`#microsoft.graph.$SelectedODataType`" ``")|out-null - $getAlternativeFilterString.append(" }")|out-null + $getAlternativeFilterString.AppendLine(" -ErrorAction SilentlyContinue | Where-Object ``") | Out-Null + $getAlternativeFilterString.AppendLine(" -FilterScript { ``") | Out-Null + $getAlternativeFilterString.AppendLine(" `$_.$alternativeKey -eq `"`$(`$$alternativeKey)`" ``") | Out-Null + $getAlternativeFilterString.AppendLine(" -and `$_.AdditionalProperties.'@odata.type' -eq `"`#microsoft.graph.$SelectedODataType`" ``") | Out-Null + $getAlternativeFilterString.Append(" }") | Out-Null } Write-TokenReplacement -Token '' -Value $getAlternativeFilterString.ToString() -FilePath $moduleFilePath @@ -380,8 +414,27 @@ function New-M365DSCResource Write-TokenReplacement -Token '' -Value $getKeyIdentifier -FilePath $moduleFilePath Write-TokenReplacement -Token '' -Value "Get-$($CmdLetNoun)" -FilePath $moduleFilePath - $complexTypeConstructor="" - if (-Not [String]::IsNullOrEmpty($hashtableResults.ComplexTypeConstructor)) + $settingsCatalogGetSettings = "" + $settingsCatalogAddSettings = "" + if ($CmdLetNoun -like "*DeviceManagementConfigurationPolicy") + { + $settingsCatalogGetSettings = @" +`r`n # Retrieve policy specific settings + [array]`$settings = Get-$($CmdLetNoun)Setting `` + -DeviceManagementConfigurationPolicyId `$Id `` + -ExpandProperty 'settingDefinitions' `` + -ErrorAction Stop + + `$policySettings = @{} + `$policySettings = Export-IntuneSettingCatalogPolicySettings -Settings `$settings -ReturnHashtable `$policySettings `r`n +"@ + $settingsCatalogAddSettings = " `$results += `$policySettings`r`n`r`n" + } + Write-TokenReplacement -Token '' -Value $settingsCatalogGetSettings -FilePath $moduleFilePath + Write-TokenReplacement -Token '<#SettingsCatalogAddSettings#>' -Value $settingsCatalogAddSettings -FilePath $moduleFilePath + + $complexTypeConstructor = "" + if (-not [String]::IsNullOrEmpty($hashtableResults.ComplexTypeConstructor)) { $complexTypeConstructor = $hashtableResults.ComplexTypeConstructor $complexTypeConstructor = "`r`n #region resource generator code`r`n" + $complexTypeConstructor @@ -390,8 +443,8 @@ function New-M365DSCResource } Write-TokenReplacement -Token '' -Value $complexTypeConstructor -FilePath $moduleFilePath - $enumTypeConstructor="" - if (-Not [String]::IsNullOrEmpty($hashtableResults.EnumTypeConstructor)) + $enumTypeConstructor = "" + if (-not [String]::IsNullOrEmpty($hashtableResults.EnumTypeConstructor)) { $enumTypeConstructor = $hashtableResults.EnumTypeConstructor $enumTypeConstructor = "`r`n #region resource generator code`r`n" + $enumTypeConstructor @@ -400,8 +453,8 @@ function New-M365DSCResource } Write-TokenReplacement -Token '' -Value $enumTypeConstructor -FilePath $moduleFilePath - $dateTypeConstructor="" - if (-Not [String]::IsNullOrEmpty($hashtableResults.DateTypeConstructor)) + $dateTypeConstructor = "" + if (-not [String]::IsNullOrEmpty($hashtableResults.DateTypeConstructor)) { $dateTypeConstructor = $hashtableResults.DateTypeConstructor $dateTypeConstructor = "`r`n #region resource generator code`r`n" + $dateTypeConstructor @@ -410,8 +463,8 @@ function New-M365DSCResource } Write-TokenReplacement -Token '' -Value $dateTypeConstructor -FilePath $moduleFilePath - $timeTypeConstructor="" - if (-Not [String]::IsNullOrEmpty($hashtableResults.TimeTypeConstructor)) + $timeTypeConstructor = "" + if (-not [String]::IsNullOrEmpty($hashtableResults.TimeTypeConstructor)) { $timeTypeConstructor = $hashtableResults.TimeTypeConstructor $timeTypeConstructor = "`r`n #region resource generator code`r`n" + $timeTypeConstructor @@ -420,35 +473,94 @@ function New-M365DSCResource } Write-TokenReplacement -Token '' -Value $timeTypeConstructor -FilePath $moduleFilePath - $newCmdlet = Get-Command -Name "New-$($CmdLetNoun)" $newDefaultParameterSet = $newCmdlet.ParameterSets | Where-Object -FilterScript { $_.Name -eq 'Create' } [Array]$newKeyIdentifier = ($newDefaultParameterSet.Parameters | Where-Object -FilterScript { $_.IsMandatory }).Name + $defaultCreateParameters = @" + `$CreateParameters = ([Hashtable]`$BoundParameters).clone() + `$CreateParameters = Rename-M365DSCCimInstanceParameter -Properties `$CreateParameters + `$CreateParameters.Remove('Id') | Out-Null + + `$keys = (([Hashtable]`$CreateParameters).clone()).Keys + foreach (`$key in `$keys) + { + if (`$null -ne `$CreateParameters.`$key -and `$CreateParameters.`$key.getType().Name -like '*cimInstance*') + { + `$CreateParameters.`$key = Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject `$CreateParameters.`$key + } + } +"@ + $defaultUpdateParameters = @" + `$UpdateParameters = ([Hashtable]`$BoundParameters).clone() + `$UpdateParameters = Rename-M365DSCCimInstanceParameter -Properties $`UpdateParameters + + `$UpdateParameters.Remove('Id') | Out-Null - if ($null -ne $newKeyIdentifier ) + `$keys = (([Hashtable]`$UpdateParameters).clone()).Keys + foreach (`$key in `$keys) + { + if (`$null -ne `$UpdateParameters.`$key -and `$UpdateParameters.`$key.getType().Name -like '*cimInstance*') + { + `$UpdateParameters.`$key = Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject `$UpdateParameters.$key + } + } + +"@ + + if ($null -ne $newKeyIdentifier) { $newParameterString = [System.Text.StringBuilder]::New() - foreach ($key in $newKeyIdentifier ) + foreach ($key in $newKeyIdentifier) { if ($newKeyIdentifier.Count -gt 1) { - $newParameterString.append(" ```r`n") |out-null - $newParameterString.append(" ") |out-null + $newParameterString.Append(" ```r`n") | Out-Null + $newParameterString.Append(" ") | Out-Null } $keyValue = $key if ($key -eq 'BodyParameter') { $keyValue = 'CreateParameters' } - $newParameterString.append("-$key `$$keyValue") |out-null + $newParameterString.Append("-$key `$$keyValue") | Out-Null } [String]$newKeyIdentifier = $newParameterString.ToString() } - $odataType=$null + $odataType = $null if ($true)#$isAdditionalProperty) { - $odataType=" `$CreateParameters.Add(`"@odata.type`", `"#microsoft.graph.$SelectedODataType`")`r`n" + $odataType = " `$CreateParameters.Add(`"@odata.type`", `"#microsoft.graph.$SelectedODataType`")`r`n" + } + + $settingsCatalogProperties = "" + $defaultCreateParameters = "" + if ($CmdLetNoun -like "*DeviceManagementConfigurationPolicy") + { + $odataType = "" + $settingsCatalogProperties = @" + `$templateReferenceId = '' + `$platforms = '' + `$technologies = ''`r`n +"@ + + $defaultCreateParameters = @" + `$settings = Get-IntuneSettingCatalogPolicySetting ` + -DSCParams ([System.Collections.Hashtable]`$BoundParameters) ` + -TemplateId `$templateReferenceId + + `$CreateParameters = @{ + Name = `$DisplayName + Description = `$Description + TemplateReference = @{templateId = `$templateReferenceId } + Platforms = `$platforms + Technologies = `$technologies + Settings = `$settings + }`r`n +"@ } + Write-TokenReplacement -Token '<#SettingsCatalogProperties#>' -Value $settingsCatalogProperties -FilePath $moduleFilePath + + Write-TokenReplacement -Token '<#DefaultCreateParameters#>' -Value $defaultCreateParameters -FilePath $moduleFilePath Write-TokenReplacement -Token '' -Value "$odataType" -FilePath $moduleFilePath Write-TokenReplacement -Token '<#NewKeyIdentifier#>' -Value $newKeyIdentifier -FilePath $moduleFilePath Write-TokenReplacement -Token '' -Value "New-$($CmdLetNoun)" -FilePath $moduleFilePath @@ -458,27 +570,42 @@ function New-M365DSCResource Write-TokenReplacement -Token '' -Value $alternativeKey -FilePath $moduleFilePath $exportGetCommand = [System.Text.StringBuilder]::New() - $exportGetCommand.AppendLine(" [array]`$getValue = Get-$CmdLetNoun ``") |out-null + if ($CmdLetNoun -like "*DeviceManagementConfigurationPolicy") + { + $exportGetCommand.AppendLine(" `$policyTemplateID = `"`"") | Out-Null + } + $exportGetCommand.AppendLine(" [array]`$getValue = Get-$CmdLetNoun ``") | Out-Null + if ($getDefaultParameterSet.Parameters.Name -contains "Filter") + { + $exportGetCommand.AppendLine(" -Filter `$Filter ``") | Out-Null + } if ($getDefaultParameterSet.Parameters.Name -contains "All") { - $exportGetCommand.AppendLine(" -All ``")|out-null + $exportGetCommand.AppendLine(" -All ``") | Out-Null + } + if ($isAdditionalProperty -and $CmdletNoun -notlike "*DeviceManagementConfigurationPolicy") + { + $exportGetCommand.AppendLine(" -ErrorAction Stop | Where-Object ``") | Out-Null + $exportGetCommand.AppendLine(" -FilterScript { ``") | Out-Null + $exportGetCommand.AppendLine(" `$_.AdditionalProperties.'@odata.type' -eq '#microsoft.graph.$($selectedODataType)' ``") | Out-Null + $exportGetCommand.AppendLine(" }") | Out-Null } - if ($isAdditionalProperty) + elseif ($CmdletNoun -like "*DeviceManagementConfigurationPolicy") { - $exportGetCommand.AppendLine(" -ErrorAction Stop | Where-Object ``")|out-null - $exportGetCommand.AppendLine(" -FilterScript { ``")|out-null - $exportGetCommand.AppendLine(" `$_.AdditionalProperties.'@odata.type' -eq '#microsoft.graph.$($selectedODataType)' ``")|out-null - $exportGetCommand.AppendLine(" }")|out-null + $exportGetCommand.AppendLine(" -ErrorAction Stop | Where-Object ``") | Out-Null + $exportGetCommand.AppendLine(" -FilterScript { ``") | Out-Null + $exportGetCommand.AppendLine(" `$_.TemplateReference.TemplateId -eq `$policyTemplateID ``") | Out-Null + $exportGetCommand.AppendLine(" }") | Out-Null } else { - $exportGetCommand.AppendLine(" -ErrorAction Stop")|out-null + $exportGetCommand.AppendLine(" -ErrorAction Stop") | Out-Null } - $trailingCharRemoval="" - if ($cimInstances.count -gt 0) + $trailingCharRemoval = "" + if ($cimInstances.Count -gt 0) { - $trailingCharRemoval=@' + $trailingCharRemoval = @' '@ } $requiredKey = '' @@ -494,25 +621,25 @@ function New-M365DSCResource Write-TokenReplacement -Token '<#ConvertComplexToVariable#>' -Value $hashtableResults.ConvertToVariable -FilePath $moduleFilePath Write-TokenReplacement -Token '<#TrailingCharRemoval#>' -Value $trailingCharRemoval -FilePath $moduleFilePath - $updateVerb='Update' - $updateCmdlet=Find-MgGraphCommand -Command "$updateVerb-$CmdLetNoun" -ApiVersion $ApiVersion -errorAction SilentlyContinue + $updateVerb = 'Update' + $updateCmdlet = Find-MgGraphCommand -Command "$updateVerb-$CmdLetNoun" -ApiVersion $ApiVersion -ErrorAction SilentlyContinue if ($null -eq $updateCmdlet) { - $updateVerb='Set' + $updateVerb = 'Set' } $updateCmdlet = Get-Command -Name "$updateVerb-$CmdLetNoun" $updateDefaultParameterSet = $updateCmdlet.ParameterSets | Where-Object -FilterScript { $_.Name -eq "$updateVerb" } [Array]$updateKeyIdentifier = ($updateDefaultParameterSet.Parameters | Where-Object -FilterScript { $_.IsMandatory }).Name - if ($null -ne $updateKeyIdentifier ) + if ($null -ne $updateKeyIdentifier) { $updateParameterString = [System.Text.StringBuilder]::New() - foreach ($key in $updateKeyIdentifier ) + foreach ($key in $updateKeyIdentifier) { if ($updateKeyIdentifier.Count -gt 1) { - $updateParameterString.append(" ```r`n") |out-null - $updateParameterString.append(" ") |out-null + $updateParameterString.Append(" ```r`n") | Out-Null + $updateParameterString.Append(" ") | Out-Null } $keyValue = $key if ($key -eq 'BodyParameter') @@ -521,41 +648,65 @@ function New-M365DSCResource } if ($key -eq "$($actualtype)Id") { - $keyValue = 'currentInstance.'+$primaryKey + $keyValue = 'currentInstance.' + $primaryKey } - $updateParameterString.append("-$key `$$keyValue") |out-null + $updateParameterString.Append("-$key `$$keyValue") | Out-Null } [String]$updateKeyIdentifier = $updateParameterString.ToString() } - $odataType=$null + $odataType = $null if ($true)#$isAdditionalProperty) { - $odataType=" `$UpdateParameters.Add(`"@odata.type`", `"#microsoft.graph.$SelectedODataType`")`r`n" + $odataType = " `$UpdateParameters.Add(`"@odata.type`", `"#microsoft.graph.$SelectedODataType`")`r`n" + } + + $updateCmdletName = " $updateVerb-$CmdLetNoun" + $defaultUpdateParameters = "" + if ($CmdLetNoun -like "*DeviceManagementConfigurationPolicy") + { + $odataType = "" + $updateKeyIdentifier = "" + $updateCmdletName = "" + $defaultUpdateParameters = @" + `$settings = Get-IntuneSettingCatalogPolicySetting ` + -DSCParams ([System.Collections.Hashtable]`$BoundParameters) ` + -TemplateId `$templateReferenceId + + Update-DeviceManagementConfigurationPolicy ` + -DeviceManagementConfigurationPolicyId `$currentInstance.Id ` + -DisplayName `$DisplayName ` + -Description `$Description ` + -TemplateReference `$templateReferenceId ` + -Platforms `$platforms ` + -Technologies `$technologies ` + -Settings `$settings`r`n +"@ } + Write-TokenReplacement -Token '<#DefaultUpdateParameters#>' -Value $defaultUpdateParameters -FilePath $moduleFilePath Write-TokenReplacement -Token '' -Value "$odataType" -FilePath $moduleFilePath - Write-TokenReplacement -Token '' -Value "$updateVerb-$CmdLetNoun" -FilePath $moduleFilePath + Write-TokenReplacement -Token '' -Value $updateCmdletName -FilePath $moduleFilePath Write-TokenReplacement -Token '<#UpdateKeyIdentifier#>' -Value $updateKeyIdentifier -FilePath $moduleFilePath $removeCmdlet = Get-Command -Name "Remove-$($CmdLetNoun)" $removeDefaultParameterSet = $removeCmdlet.ParameterSets | Where-Object -FilterScript { $_.Name -eq 'Delete' } [Array]$removeKeyIdentifier = ($removeDefaultParameterSet.Parameters | Where-Object -FilterScript { $_.IsMandatory }).Name - if ($null -ne $removeKeyIdentifier ) + if ($null -ne $removeKeyIdentifier) { $removeParameterString = [System.Text.StringBuilder]::New() - foreach ($key in $removeKeyIdentifier ) + foreach ($key in $removeKeyIdentifier) { if ($removeKeyIdentifier.Count -gt 1) { - $removeParameterString.append(" ```r`n") |out-null - $removeParameterString.append(" ") |out-null + $removeParameterString.Append(" ```r`n") | Out-Null + $removeParameterString.Append(" ") | Out-Null } $keyValue = $key if ($removeKeyIdentifier.Count -eq 1) { - $keyValue='currentInstance.'+$primaryKey + $keyValue = 'currentInstance.' + $primaryKey } - $removeParameterString.append("-$key `$$keyValue") |out-null + $removeParameterString.Append("-$key `$$keyValue") | Out-Null } [String]$removeKeyIdentifier = $removeParameterString.ToString() } @@ -571,16 +722,9 @@ function New-M365DSCResource $AssignmentsGet += " `$assignmentsValues = Get-$($assignmentCmdLetNoun) -$($assignmentKey) `$$primaryKey`r`n" $AssignmentsGet += " `$assignmentResult = @()`r`n" - $AssignmentsGet += " foreach (`$assignmentEntry in `$AssignmentsValues)`r`n" + $AssignmentsGet += " if (`$assignmentsValues.Count -gt 0)`r`n" $AssignmentsGet += " {`r`n" - $AssignmentsGet += " `$assignmentValue = @{`r`n" - $AssignmentsGet += " dataType = `$assignmentEntry.Target.AdditionalProperties.'@odata.type'`r`n" - $AssignmentsGet += " deviceAndAppManagementAssignmentFilterType = `$(if (`$null -ne `$assignmentEntry.Target.DeviceAndAppManagementAssignmentFilterType)`r`n" - $AssignmentsGet += " {`$assignmentEntry.Target.DeviceAndAppManagementAssignmentFilterType.ToString()})`r`n" - $AssignmentsGet += " deviceAndAppManagementAssignmentFilterId = `$assignmentEntry.Target.DeviceAndAppManagementAssignmentFilterId`r`n" - $AssignmentsGet += " groupId = `$assignmentEntry.Target.AdditionalProperties.groupId`r`n" - $AssignmentsGet += " }`r`n" - $AssignmentsGet += " `$assignmentResult += `$assignmentValue`r`n" + $AssignmentsGet += " `$assignmentResult += ConvertFrom-IntunePolicyAssignment -Assignments `$assignmentsValues -IncludeDeviceFilter `$true`r`n" $AssignmentsGet += " }`r`n" $AssignmentsGet += " `$results.Add('Assignments', `$assignmentResult)`r`n" @@ -592,9 +736,9 @@ function New-M365DSCResource $AssignmentsNew += " `$assignmentsHash += Get-M365DSCDRGComplexTypeToHashtable -ComplexObject `$Assignment`r`n" $AssignmentsNew += " }`r`n" $AssignmentsNew += "`r`n" - $AssignmentsNew += " if (`$policy.id)`r`n" + $AssignmentsNew += " if (`$policy.Id)`r`n" $AssignmentsNew += " {`r`n" - $AssignmentsNew += " Update-DeviceConfigurationPolicyAssignment -DeviceConfigurationPolicyId `$policy.id ```r`n" + $AssignmentsNew += " Update-DeviceConfigurationPolicyAssignment -DeviceConfigurationPolicyId `$policy.Id ```r`n" $AssignmentsNew += " -Targets `$assignmentsHash ```r`n" $AssignmentsNew += " -Repository '$repository'`r`n" $AssignmentsNew += " }`r`n" @@ -605,7 +749,7 @@ function New-M365DSCResource $AssignmentsUpdate += " `$assignmentsHash += Get-M365DSCDRGComplexTypeToHashtable -ComplexObject `$Assignment`r`n" $AssignmentsUpdate += " }`r`n" $AssignmentsUpdate += " Update-DeviceConfigurationPolicyAssignment ```r`n" - $AssignmentsUpdate += " -DeviceConfigurationPolicyId `$currentInstance.id ```r`n" + $AssignmentsUpdate += " -DeviceConfigurationPolicyId `$currentInstance.Id ```r`n" $AssignmentsUpdate += " -Targets `$assignmentsHash ```r`n" $AssignmentsUpdate += " -Repository '$repository'`r`n" @@ -617,6 +761,7 @@ class MSFT_DeviceManagementConfigurationPolicyAssignments [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; }; @@ -653,6 +798,48 @@ class MSFT_DeviceManagementConfigurationPolicyAssignments Write-TokenReplacement -Token '<#AssignmentsConvertComplexToString#>' -Value $AssignmentsConvertComplexToString -FilePath $moduleFilePath Write-TokenReplacement -Token '<#AssignmentsConvertComplexToVariable#>' -Value $AssignmentsConvertComplexToVariable -FilePath $moduleFilePath + $defaultTestValuesToCheck = " `$ValuesToCheck = ([Hashtable]`$PSBoundParameters).clone()" + if ($CmdLetNoun -like "*DeviceManagementConfigurationPolicy") + { + $defaultTestValuesToCheck = @" + [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)) + { + `$value = `$null + switch (`$CurrentValues[`$_.Key].GetType().Name) + { + 'Boolean' + { + `$value = `$false + } + 'String' + { + `$value = '' + } + 'Int32' + { + `$value = 0 + } + 'String[]' + { + `$value = @() + } + } + `$PSBoundParameters.Add(`$_.Key, `$value) + } + } + } + } +"@ + } + Write-TokenReplacement -Token '<#DefaultTestValuesToCheck#>' -Value $defaultTestValuesToCheck -FilePath $moduleFilePath + # Remove comments Write-TokenReplacement -Token '<#ResourceGenerator' -Value '' -FilePath $moduleFilePath Write-TokenReplacement -Token 'ResourceGenerator#>' -Value '' -FilePath $moduleFilePath @@ -662,6 +849,11 @@ class MSFT_DeviceManagementConfigurationPolicyAssignments $schemaProperties = New-M365SchemaPropertySet -Properties $parameterInformation ` -Workload $Workload + if ($CmdLetNoun -like "*DeviceManagementConfigurationPolicy") + { + $schemaProperties += $definitionSettings.MOF -join "`r`n" + } + Write-TokenReplacement -Token '' -Value $AssignmentsCIM -FilePath $schemaFilePath Write-TokenReplacement -Token '' -Value $AssignmentsProperty -FilePath $schemaFilePath Write-TokenReplacement -Token '' -Value $CimInstancesSchemaContent -FilePath $schemaFilePath @@ -670,7 +862,7 @@ class MSFT_DeviceManagementConfigurationPolicyAssignments Write-TokenReplacement -Token '' -Value $schemaProperties -FilePath $schemaFilePath #endregion #region Settings - $resourcePermissions = (get-M365DSCResourcePermission ` + $resourcePermissions = (Get-M365DSCResourcePermission ` -Workload $Workload ` -CmdLetNoun $CmdLetNoun ` -ApiVersion $ApiVersion ` @@ -702,13 +894,13 @@ class MSFT_DeviceManagementConfigurationPolicyAssignments $defaultParameterSetProperties = $cmdlet.ParameterSets | Where-Object -FilterScript {$_.IsDefault} $properties = $defaultParameterSetProperties.Parameters | Where-Object -FilterScript {-not $ParametersToFilterOut.Contains($_.Name) -and -not $_.Name.StartsWith('MsftInternal')} - #region Get longuest parametername - $longuestParameterName = ("CertificateThumbprint").Length + #region Get longest parametername + $longestParameterName = ("CertificateThumbprint").Length foreach ($property in $properties) { - if ($property.Name.Length -gt $longuestParameterName) + if ($property.Name.Length -gt $longestParameterName) { - $longuestParameterName = $property.Name.Length + $longestParameterName = $property.Name.Length } } #endregion @@ -752,7 +944,7 @@ class MSFT_DeviceManagementConfigurationPolicyAssignments $fakeValues.Add($property.Name, (Get-M365DSCDRGFakeValueForParameter -ParameterType $property.ParameterType.Name)) $spacingRequired = " " - for ($i = 0; $i -lt ($longuestParameterName - $property.Name.Length); $i++) + for ($i = 0; $i -lt ($longestParameterName - $property.Name.Length); $i++) { $spacingRequired += " " } @@ -765,7 +957,7 @@ class MSFT_DeviceManagementConfigurationPolicyAssignments # Ensure $spacingRequired = " " - for ($i = 0; $i -lt ($longuestParameterName - ("Ensure").Length); $i++) + for ($i = 0; $i -lt ($longestParameterName - ("Ensure").Length); $i++) { $spacingRequired += " " } @@ -780,7 +972,7 @@ class MSFT_DeviceManagementConfigurationPolicyAssignments # Credential $spacingRequired = " " - for ($i = 0; $i -lt ($longuestParameterName - ("Credential").Length); $i++) + for ($i = 0; $i -lt ($longestParameterName - ("Credential").Length); $i++) { $spacingRequired += " " } @@ -796,7 +988,7 @@ class MSFT_DeviceManagementConfigurationPolicyAssignments { # Application Id $spacingRequired = " " - for ($i = 0; $i -lt ($longuestParameterName - ("ApplicationId").Length); $i++) + for ($i = 0; $i -lt ($longestParameterName - ("ApplicationId").Length); $i++) { $spacingRequired += " " } @@ -812,7 +1004,7 @@ class MSFT_DeviceManagementConfigurationPolicyAssignments # Tenant Id $spacingRequired = " " - for ($i = 0; $i -lt ($longuestParameterName - ("TenantId").Length); $i++) + for ($i = 0; $i -lt ($longestParameterName - ("TenantId").Length); $i++) { $spacingRequired += " " } @@ -828,7 +1020,7 @@ class MSFT_DeviceManagementConfigurationPolicyAssignments # CertificateThumbprint $spacingRequired = " " - for ($i = 0; $i -lt ($longuestParameterName - ("CertificateThumbprint").Length); $i++) + for ($i = 0; $i -lt ($longestParameterName - ("CertificateThumbprint").Length); $i++) { $spacingRequired += " " } @@ -846,7 +1038,7 @@ class MSFT_DeviceManagementConfigurationPolicyAssignments { # ApplicationSecret $spacingRequired = " " - for ($i = 0; $i -lt ($longuestParameterName - ("ApplicationSecret").Length); $i++) + for ($i = 0; $i -lt ($longestParameterName - ("ApplicationSecret").Length); $i++) { $spacingRequired += " " } @@ -906,7 +1098,7 @@ class MSFT_DeviceManagementConfigurationPolicyAssignments { $spacingRequired = ' ' - for ($i = 0; $i -lt ($longuestParameterName - $key.Length); $i++) + for ($i = 0; $i -lt ($longestParameterName - $key.Length); $i++) { $spacingRequired += " " } @@ -1080,7 +1272,7 @@ function New-M365DSCResourceForGraphCmdLet { Write-Verbose -Message "- $($noun)" - $nounCommands = $commands | Where-Object { $_.Noun -eq $noun } + $nounCommands = $commands | Where-Object -FilterScript { $_.Noun -eq $noun } if ($nounCommands.Verb -notcontains 'Get' -or ` $nounCommands.Verb -notcontains 'Update' -or ` $nounCommands.Verb -notcontains 'New') @@ -1109,14 +1301,14 @@ function Get-CmdletDefinition if ($ApiVersion -eq 'v1.0') { - $Uri='https://raw.githubusercontent.com/microsoftgraph/msgraph-metadata/master/clean_v10_metadata/cleanMetadataWithDescriptionsAndAnnotationsv1.0.xml' + $Uri = 'https://raw.githubusercontent.com/microsoftgraph/msgraph-metadata/master/clean_v10_metadata/cleanMetadataWithDescriptionsAndAnnotationsv1.0.xml' } else { - $Uri='https://raw.githubusercontent.com/microsoftgraph/msgraph-metadata/master/clean_beta_metadata/cleanMetadataWithDescriptionsAndAnnotationsbeta.xml' + $Uri = 'https://raw.githubusercontent.com/microsoftgraph/msgraph-metadata/master/clean_beta_metadata/cleanMetadataWithDescriptionsAndAnnotationsbeta.xml' } - $metadata=([XML](Invoke-RestMethod -Uri $Uri)).Edmx.DataServices.schema + $metadata = ([XML](Invoke-RestMethod -Uri $Uri)).Edmx.DataServices.schema return $metadata } @@ -1134,7 +1326,7 @@ function Get-TypeProperties [Parameter()] [System.Boolean] - $IncludeNavigationProperties=$false, + $IncludeNavigationProperties = $false, [Parameter()] [System.String[]] @@ -1146,46 +1338,46 @@ function Get-TypeProperties [Parameter()] [System.String] - $ParentPropertyName="" + $ParentPropertyName = "" ) - $namespace=$CmdletDefinition|Where-Object -FilterScript {$_.EntityType.Name -contains $Entity} + $namespace = $CmdletDefinition | Where-Object -FilterScript { $_.EntityType.Name -contains $Entity } if ($null -eq $namespace) { - $namespace=$CmdletDefinition|Where-Object -FilterScript {$_.ComplexType.Name -contains $Entity} + $namespace = $CmdletDefinition | Where-Object -FilterScript { $_.ComplexType.Name -contains $Entity } } - $properties=@() - $baseType=$Entity + $properties = @() + $baseType = $Entity #Get all properties for the entity or complex do { - $isComplex=$false - $entityType=$namespace.EntityType|Where-Object -FilterScript{$_.Name -eq $baseType} - $isAbstract=$false + $isComplex = $false + $entityType = $namespace.EntityType | Where-Object -FilterScript { $_.Name -eq $baseType } + $isAbstract = $false if ($entityType.Abstract -eq 'True') { - $isAbstract=$true + $isAbstract = $true } if ($null -eq $entityType) { - $isComplex=$true - $entityType=$namespace.ComplexType|Where-Object -FilterScript{$_.Name -eq $baseType} + $isComplex = $true + $entityType = $namespace.ComplexType | Where-Object -FilterScript { $_.Name -eq $baseType } #if ($entityType.Abstract -eq 'true') if ($null -eq $entityType.BaseType) { - $isAbstract=$true + $isAbstract = $true } } if ($null -ne $entityType.Property) { - $rawProperties=$entityType.Property + $rawProperties = $entityType.Property foreach ($property in $rawProperties) { - $IsRootProperty=$false + $IsRootProperty = $false if (($entityType.BaseType -eq "graph.Entity") -or ($entityType.Name -eq "entity") -or ($isAbstract -and $entityType.Name -eq $global:searchedEntity)) { - $IsRootProperty=$true + $IsRootProperty = $true } $myProperty = @{} @@ -1196,38 +1388,37 @@ function Get-TypeProperties $description = '' if (-not [String]::IsNullOrWhiteSpace($property.Annotation.String)) { - $description =$property.Annotation.String.replace('"',"'") - $description =$description -replace '[^\p{L}\p{Nd}/(/}/_ -.,=:)'']', '' + $description = $property.Annotation.String.Replace('"',"'") + $description = $description -replace '[^\p{L}\p{Nd}/(/}/_ -.,=:)'']', '' } else { - $annotation = $CmdletDefinition.Annotations | where-object -FilterScript {$_.Target -like "microsoft.graph.$($property.ParentNode.Name)/$($property.Name)" } + $annotation = $CmdletDefinition.Annotations | Where-Object -FilterScript {$_.Target -like "microsoft.graph.$($property.ParentNode.Name)/$($property.Name)" } if (-not [String]::IsNullOrWhiteSpace($annotation.Annotation.String)) { - $description =$annotation.Annotation.String.replace('"',"'") - $description =$description -replace '[^\p{L}\p{Nd}/(/}/_ -.,=:)'']', '' + $description = $annotation.Annotation.String.Replace('"',"'") + $description = $description -replace '[^\p{L}\p{Nd}/(/}/_ -.,=:)'']', '' } } $myProperty.Add('Description', $description) - - $properties+=$myProperty + $properties += $myProperty } } if ($isComplex) { - $abstractType=$namespace.ComplexType|Where-Object -FilterScript {$_.BaseType -eq "graph.$baseType"} + $abstractType = $namespace.ComplexType | Where-Object -FilterScript {$_.BaseType -eq "graph.$baseType"} foreach ($subType in $abstractType) { - $rawProperties=$subType.Property + $rawProperties = $subType.Property foreach ($property in $rawProperties) { - $IsRootProperty=$false + $IsRootProperty = $false if ($entityType.BaseType -eq "graph.Entity" -or $entityType.Name -eq "entity" ) { - $IsRootProperty=$true + $IsRootProperty = $true } if ($property.Name -notin ($properties.Name)) @@ -1240,21 +1431,21 @@ function Get-TypeProperties $description = '' if (-not [String]::IsNullOrWhiteSpace($property.Annotation.String)) { - $description =$property.Annotation.String.replace('"',"'") - $description =$description -replace '[^\p{L}\p{Nd}/(/}/_ -.,=:)'']', '' + $description = $property.Annotation.String.Replace('"',"'") + $description = $description -replace '[^\p{L}\p{Nd}/(/}/_ -.,=:)'']', '' } else { - $annotation = $CmdletDefinition.Annotations | where-object -FilterScript {$_.Target -like "microsoft.graph.$($property.ParentNode.Name)/$($property.Name)" } + $annotation = $CmdletDefinition.Annotations | Where-Object -FilterScript { $_.Target -like "microsoft.graph.$($property.ParentNode.Name)/$($property.Name)" } if (-not [String]::IsNullOrWhiteSpace($annotation.Annotation.String)) { - $description =$annotation.Annotation.String.replace('"',"'") - $description =$description -replace '[^\p{L}\p{Nd}/(/}/_ -.,=:)'']', '' + $description = $annotation.Annotation.String.Replace('"',"'") + $description = $description -replace '[^\p{L}\p{Nd}/(/}/_ -.,=:)'']', '' } } $myProperty.Add('Description', $description) - $properties+=$myProperty + $properties += $myProperty } } } @@ -1269,19 +1460,19 @@ function Get-TypeProperties $myProperty.Add('Description','The type of the entity.') $myProperty.Add('ParentType',$entityType.Name) - $properties+=$myProperty + $properties += $myProperty } } if ($IncludeNavigationProperties -and $null -ne $entityType.NavigationProperty) { - $rawProperties=$entityType.NavigationProperty + $rawProperties = $entityType.NavigationProperty foreach ($property in $rawProperties) { - $IsRootProperty=$false + $IsRootProperty = $false if ($entityType.BaseType -eq "graph.Entity" -or $entityType.Name -eq "entity" ) { - $IsRootProperty=$true + $IsRootProperty = $true } $myProperty = @{} @@ -1290,37 +1481,37 @@ function Get-TypeProperties $myProperty.Add('IsNavigationProperty', $true) $myProperty.Add('IsRootProperty',$IsRootProperty) $myProperty.Add('ParentType',$entityType.Name) - $myProperty.Add('Description', $property.Annotation.String.replace('"',"'")) + $myProperty.Add('Description', $property.Annotation.String.Replace('"',"'")) - $properties+=$myProperty + $properties += $myProperty } } - $baseType=$null + $baseType = $null if (-not [String]::IsNullOrEmpty($entityType.BaseType)) { - $baseType=$entityType.BaseType.replace('graph.','') + $baseType = $entityType.BaseType.Replace('graph.','') } - } - while($null -ne $baseType) + } while ($null -ne $baseType) + # Enrich properties - $result=@() + $result = @() foreach ($property in $properties) { - $derivedType=$property.Type + $derivedType = $property.Type #Array - $isArray=$false - $isEnum=$false + $isArray = $false + $isEnum = $false if ($derivedType -eq 'Custom.Enum') { - $isEnum=$true + $isEnum = $true } - $isComplex=$false + $isComplex = $false if ($derivedType -like "Collection(*)") { - $isArray=$true - $derivedType=$derivedType.Replace('Collection(','').replace(')','') + $isArray = $true + $derivedType = $derivedType.Replace('Collection(','').Replace(')','') } $property.Add('IsArray',$isArray) @@ -1330,27 +1521,26 @@ function Get-TypeProperties #DerivedType if ($derivedType -like ('graph.*')) { - $derivedType=$derivedType.Replace('graph.','') + $derivedType = $derivedType.Replace('graph.','') #Enum if ($derivedType -in $namespace.EnumType.Name) { - $isEnum=$true - $enumType=$namespace.EnumType | where-Object -FilterScript {$_.Name -eq $derivedType} + $isEnum = $true + $enumType = $namespace.EnumType | where-Object -FilterScript {$_.Name -eq $derivedType} $property.Add('Members',$enumType.Member.Name) - } #Complex if (($derivedType -in $namespace.ComplexType.Name) -or ($property.IsNavigationProperty)) { - $complexName=$ParentPropertyName+"-"+$property.Name+"-"+$property.Type - $isComplex=$true + $complexName = $ParentPropertyName + "-" + $property.Name + "-" + $property.Type + $isComplex = $true if ($complexName -notin $global:ComplexList) { if ($ParentPropertyName -ne "") { - $global:ComplexList+= $complexName + $global:ComplexList += $complexName } $nestedProperties = Get-TypeProperties ` -CmdletDefinition $CmdletDefinition ` @@ -1364,33 +1554,34 @@ function Get-TypeProperties } if ($derivedType -like ('Edm.*')) { - $derivedType=$derivedType.Replace('Edm','System') + $derivedType = $derivedType.Replace('Edm','System') if ($derivedType -like ('*.TimeOfDay')) { - $derivedType='System.TimeSpan' + $derivedType = 'System.TimeSpan' } if ($derivedType -like ('*.Date')) { - $derivedType='System.DateTime' + $derivedType = 'System.DateTime' } } if ($cimClasses -contains "MSFT_$Workload$derivedType") { - $cimCounter = ([Array]($CimClasses | where-object {$_ -like "MSFT_$Workload$derivedType*"})).count + $cimCounter = ([Array]($CimClasses | Where-Object -FilterScript { $_ -like "MSFT_$Workload$derivedType*" })).Count $derivedType += $cimCounter.ToString() } if ($isEnum) { - $derivedType='System.String' + $derivedType = 'System.String' } $property.Add('DerivedType', $derivedType) $property.Add('IsComplexType', $isComplex) $property.Add('IsEnumType', $isEnum) - $result+=$property + $result += $property } + return $result } function Get-Microsoft365DSCModuleCimClass @@ -1403,8 +1594,8 @@ function Get-Microsoft365DSCModuleCimClass $ResourceName ) - import-module Microsoft365DSC -Force - $modulePath = Split-Path -Path (get-module microsoft365dsc).Path + Import-Module -Name Microsoft365DSC -Force + $modulePath = Split-Path -Path (Get-Module -Name Microsoft365DSC).Path $resourcesPath = "$modulePath\DSCResources\*\*.mof" $resources = (Get-ChildItem $resourcesPath).FullName $resources = $resources | Where-Object -FilterScript {$_ -notlike "*MSFT_$ResourceName.schema.mof"} @@ -1417,10 +1608,10 @@ function Get-Microsoft365DSCModuleCimClass { if ($line -like "class MSFT_*") { - $class = $line.replace("class ","").replace("Class ","") + $class = $line.Replace("class ","").Replace("Class ","") if ($line -like "*:*") { - $class = $class.split(":")[0].trim() + $class = $class.Split(":")[0].trim() } if ($class -notin $cimClasses) { @@ -1442,7 +1633,7 @@ function Get-StringFirstCharacterToUpper $Value ) - return $Value.Substring(0,1).ToUpper() + $Value.Substring(1,$Value.length-1) + return $Value.Substring(0, 1).ToUpper() + $Value.Substring(1, $Value.Length - 1) } function Get-StringFirstCharacterToLower @@ -1455,7 +1646,7 @@ function Get-StringFirstCharacterToLower $Value ) - return $Value.Substring(0,1).ToLower() + $Value.Substring(1,$Value.length-1) + return $Value.Substring(0, 1).ToLower() + $Value.Substring(1, $Value.Length - 1) } function Get-ComplexTypeConstructorToString @@ -1464,7 +1655,7 @@ function Get-ComplexTypeConstructorToString [OutputType([System.String])] param ( [Parameter(Mandatory = $true)] - [ValidateScript({$_.IsComplexType})] + [ValidateScript({ $_.IsComplexType })] $Property, [Parameter()] @@ -1477,11 +1668,11 @@ function Get-ComplexTypeConstructorToString [Parameter()] [System.String] - $IsParentFromAdditionalProperties=$False, + $IsParentFromAdditionalProperties = $False, [Parameter()] [System.Int32] - $IndentCount=0, + $IndentCount = 0, [Parameter()] [System.String] @@ -1489,15 +1680,15 @@ function Get-ComplexTypeConstructorToString [Parameter()] [System.Boolean] - $IsNested=$false + $IsNested = $false ) $complexString = [System.Text.StringBuilder]::New() - $indent=" " + $indent = " " $spacing = $indent * $IndentCount $propertyName = Get-StringFirstCharacterToUpper -Value $Property.Name - $returnPropertyName= "complex"+ $propertyName - $tempPropertyName=$returnPropertyName + $returnPropertyName = "complex" + $propertyName + $tempPropertyName = $returnPropertyName $valuePrefix = "getValue." $referencePrefix = "getValue." @@ -1506,17 +1697,16 @@ function Get-ComplexTypeConstructorToString #$valuePrefix = "`$current$propertyName." $valuePrefix = "$ParentPropertyValuePath" $referencePrefix = "$ParentPropertyValuePath" - } - $loopPropertyName= $Property.Name + $loopPropertyName = $Property.Name if ($isParentfromAdditionalProperties) { - $loopPropertyName=Get-StringFirstCharacterToLower -Value $loopPropertyName + $loopPropertyName = Get-StringFirstCharacterToLower -Value $loopPropertyName } if ($Property.IsRootProperty -eq $false -and -not $IsNested) { - $loopPropertyName=Get-StringFirstCharacterToLower -Value $Property.Name + $loopPropertyName = Get-StringFirstCharacterToLower -Value $Property.Name $propertyName = Get-StringFirstCharacterToLower -Value $Property.Name $valuePrefix += "AdditionalProperties." $referencePrefix += "AdditionalProperties." @@ -1525,29 +1715,29 @@ function Get-ComplexTypeConstructorToString if ($property.IsArray) { - $tempPropertyName="my$propertyName" + $tempPropertyName = "my$propertyName" if ($isNested) { - $valuePrefix=$ParentPropertyValuePath + $valuePrefix = $ParentPropertyValuePath if ($null -eq $valuePrefix) { - $propRoot=$ParentPropertyName.replace("my","") - $valuePrefix="current$propRoot." + $propRoot = $ParentPropertyName.Replace("my","") + $valuePrefix = "current$propRoot." #if ($property.IsRootProperty -eq $false -and -not $IsNested) #{ # $valuePrefix += "AdditionalProperties." #} } } - $iterationPropertyName="current$propertyName" - $complexString.appendLine($spacing + "`$$returnPropertyName" + " = @()") | Out-Null - $complexString.appendLine($spacing + "foreach (`$$iterationPropertyName in `$$valuePrefix" + $loopPropertyName + ")" ) | Out-Null - $complexString.appendLine($spacing + "{" ) | Out-Null + $iterationPropertyName = "current$propertyName" + $complexString.AppendLine($spacing + "`$$returnPropertyName" + " = @()") | Out-Null + $complexString.AppendLine($spacing + "foreach (`$$iterationPropertyName in `$$valuePrefix" + $loopPropertyName + ")" ) | Out-Null + $complexString.AppendLine($spacing + "{" ) | Out-Null $IndentCount ++ $spacing = $indent * $IndentCount } - $complexString.appendLine($spacing + "`$$tempPropertyName" + " = @{}") | Out-Null + $complexString.AppendLine($spacing + "`$$tempPropertyName" + " = @{}") | Out-Null foreach ($nestedProperty in $property.Properties) { @@ -1564,7 +1754,7 @@ function Get-ComplexTypeConstructorToString } if ($isNested -and -not $Property.IsArray) { - $propRoot=$ParentPropertyName.replace("my","") + $propRoot = $ParentPropertyName.Replace("my","") #$valuePrefix = "current$propRoot." $valuePrefix = "$referencePrefix" @@ -1573,7 +1763,7 @@ function Get-ComplexTypeConstructorToString { #$recallProperty=Get-StringFirstCharacterToLower -Value $propertyName $referencePrefixElements = @() - foreach ($elt in ($referencePrefix.split('.') | where-object {-not [String]::IsNullOrWhiteSpace($_)})) + foreach ($elt in ($referencePrefix.Split('.') | Where-Object -FilterScript { -not [String]::IsNullOrWhiteSpace($_) })) { $referencePrefixElements += Get-StringFirstCharacterToLower -Value $elt #$referencePrefix = "$valuePrefix$recallProperty." @@ -1596,7 +1786,7 @@ function Get-ComplexTypeConstructorToString if ($AssignedPropertyName.contains("@")) { - $AssignedPropertyName="'$AssignedPropertyName'" + $AssignedPropertyName = "'$AssignedPropertyName'" } if ((-not $isNested) -and (-not $Property.IsArray) -and ([String]::IsNullOrWhiteSpace($ParentPropertyValuePath))) { @@ -1604,12 +1794,12 @@ function Get-ComplexTypeConstructorToString } if ($nestedProperty.IsComplexType) { - $complexName=$Property.Name+"-"+$nestedProperty.Type + $complexName = $Property.Name + "-" + $nestedProperty.Type #if ($complexName -notin $global:ComplexList) #{ - $global:ComplexList+= $complexName + $global:ComplexList += $complexName $nestedString = '' $nestedString = Get-ComplexTypeConstructorToString ` -Property $nestedProperty ` @@ -1620,68 +1810,67 @@ function Get-ComplexTypeConstructorToString -IsParentFromAdditionalProperties $(if ($isNested) {$isParentfromAdditionalProperties} else {-not $Property.IsRootProperty}) #-IsParentFromAdditionalProperties (-not $Property.IsRootProperty) - $complexString.append($nestedString ) | Out-Null + $complexString.Append($nestedString) | Out-Null #} } else { - if ($nestedProperty.Type -like "*.Date*") { - $nestedPropertyType=$nestedProperty.Type.split(".")|select-object -last 1 + $nestedPropertyType = $nestedProperty.Type.Split(".") | Select-Object -Last 1 if ($isNested) { - $complexString.appendLine($spacing + "if (`$null -ne `$$valuePrefix$AssignedPropertyName)" ) | Out-Null + $complexString.AppendLine($spacing + "if (`$null -ne `$$valuePrefix$AssignedPropertyName)" ) | Out-Null } else { - $complexString.appendLine($spacing + "if (`$null -ne `$$referencePrefix$AssignedPropertyName)" ) | Out-Null + $complexString.AppendLine($spacing + "if (`$null -ne `$$referencePrefix$AssignedPropertyName)" ) | Out-Null } - $complexString.appendLine($spacing + "{" ) | Out-Null - $IndentCount ++ + $complexString.AppendLine($spacing + "{" ) | Out-Null + $IndentCount++ $spacing = $indent * $IndentCount $AssignedPropertyName += ").ToString('$DateFormat')" if ($isNested) { - $complexString.appendLine($spacing + "`$$tempPropertyName.Add('" + $nestedPropertyName + "', ([$nestedPropertyType]`$$valuePrefix$AssignedPropertyName)" ) | Out-Null + $complexString.AppendLine($spacing + "`$$tempPropertyName.Add('" + $nestedPropertyName + "', ([$nestedPropertyType]`$$valuePrefix$AssignedPropertyName)" ) | Out-Null } else { - $complexString.appendLine($spacing + "`$$tempPropertyName.Add('" + $nestedPropertyName + "', ([$nestedPropertyType]`$$referencePrefix$AssignedPropertyName)" ) | Out-Null + $complexString.AppendLine($spacing + "`$$tempPropertyName.Add('" + $nestedPropertyName + "', ([$nestedPropertyType]`$$referencePrefix$AssignedPropertyName)" ) | Out-Null } - $IndentCount -- + $IndentCount-- $spacing = $indent * $IndentCount - $complexString.appendLine($spacing + "}" ) | Out-Null + $complexString.AppendLine($spacing + "}" ) | Out-Null } elseif ($nestedProperty.Type -like "*.Time*") { - $nestedPropertyType=$nestedProperty.Type.split(".")|select-object -last 1 + $nestedPropertyType = $nestedProperty.Type.Split(".") | Select-Object -Last 1 if ($isNested) { - $complexString.appendLine($spacing + "if (`$null -ne `$$valuePrefix$AssignedPropertyName)" ) | Out-Null + $complexString.AppendLine($spacing + "if (`$null -ne `$$valuePrefix$AssignedPropertyName)" ) | Out-Null } else { - $complexString.appendLine($spacing + "if (`$null -ne `$$referencePrefix$AssignedPropertyName)" ) | Out-Null + $complexString.AppendLine($spacing + "if (`$null -ne `$$referencePrefix$AssignedPropertyName)" ) | Out-Null } - $complexString.appendLine($spacing + "{" ) | Out-Null - $IndentCount ++ + $complexString.AppendLine($spacing + "{" ) | Out-Null + $IndentCount++ $spacing = $indent * $IndentCount $AssignedPropertyName += ").ToString()" if ($isNested) { - $complexString.appendLine($spacing + "`$$tempPropertyName.Add('" + $nestedPropertyName + "', ([$nestedPropertyType]`$$valuePrefix$AssignedPropertyName)" ) | Out-Null + $complexString.AppendLine($spacing + "`$$tempPropertyName.Add('" + $nestedPropertyName + "', ([$nestedPropertyType]`$$valuePrefix$AssignedPropertyName)" ) | Out-Null } else { - $complexString.appendLine($spacing + "`$$tempPropertyName.Add('" + $nestedPropertyName + "', ([$nestedPropertyType]`$$referencePrefix$AssignedPropertyName)" ) | Out-Null + $complexString.AppendLine($spacing + "`$$tempPropertyName.Add('" + $nestedPropertyName + "', ([$nestedPropertyType]`$$referencePrefix$AssignedPropertyName)" ) | Out-Null } - $IndentCount -- + $IndentCount-- $spacing = $indent * $IndentCount - $complexString.appendLine($spacing + "}" ) | Out-Null + $complexString.AppendLine($spacing + "}" ) | Out-Null } else @@ -1691,37 +1880,37 @@ function Get-ComplexTypeConstructorToString { if ($isNested) { - $complexString.appendLine($spacing + "if (`$null -ne `$$valuePrefix$AssignedPropertyName)" ) | Out-Null + $complexString.AppendLine($spacing + "if (`$null -ne `$$valuePrefix$AssignedPropertyName)" ) | Out-Null } else { - $complexString.appendLine($spacing + "if (`$null -ne `$$referencePrefix$AssignedPropertyName)" ) | Out-Null + $complexString.AppendLine($spacing + "if (`$null -ne `$$referencePrefix$AssignedPropertyName)" ) | Out-Null } - $complexString.appendLine($spacing + "{" ) | Out-Null - $IndentCount ++ + $complexString.AppendLine($spacing + "{" ) | Out-Null + $IndentCount++ $spacing = $indent * $IndentCount if ($isNested) { - $complexString.append($spacing + "`$$tempPropertyName.Add('" + $nestedPropertyName + "', `$$valuePrefix$AssignedPropertyName.toString()" ) | Out-Null + $complexString.Append($spacing + "`$$tempPropertyName.Add('" + $nestedPropertyName + "', `$$valuePrefix$AssignedPropertyName.ToString()" ) | Out-Null } else { - $complexString.append($spacing + "`$$tempPropertyName.Add('" + $nestedPropertyName + "', `$$referencePrefix$AssignedPropertyName.toString()" ) | Out-Null + $complexString.Append($spacing + "`$$tempPropertyName.Add('" + $nestedPropertyName + "', `$$referencePrefix$AssignedPropertyName.ToString()" ) | Out-Null } - $complexString.append(")`r`n" ) | Out-Null - $IndentCount -- + $complexString.Append(")`r`n" ) | Out-Null + $IndentCount-- $spacing = $indent * $IndentCount - $complexString.appendLine($spacing + "}" ) | Out-Null + $complexString.AppendLine($spacing + "}" ) | Out-Null } else { if ($isNested) { - $complexString.appendLine($spacing + "`$$tempPropertyName.Add('" + $nestedPropertyName + "', `$$valuePrefix$AssignedPropertyName)" ) | Out-Null + $complexString.AppendLine($spacing + "`$$tempPropertyName.Add('" + $nestedPropertyName + "', `$$valuePrefix$AssignedPropertyName)" ) | Out-Null } else { - $complexString.appendLine($spacing + "`$$tempPropertyName.Add('" + $nestedPropertyName + "', `$$referencePrefix$AssignedPropertyName)" ) | Out-Null + $complexString.AppendLine($spacing + "`$$tempPropertyName.Add('" + $nestedPropertyName + "', `$$referencePrefix$AssignedPropertyName)" ) | Out-Null } } @@ -1731,39 +1920,39 @@ function Get-ComplexTypeConstructorToString if ($property.IsArray) { - $complexString.appendLine($spacing + "if (`$$tempPropertyName.values.Where({`$null -ne `$_}).count -gt 0)" ) | Out-Null - $complexString.appendLine($spacing + "{" ) | Out-Null - $IndentCount ++ + $complexString.AppendLine($spacing + "if (`$$tempPropertyName.values.Where({`$null -ne `$_}).Count -gt 0)" ) | Out-Null + $complexString.AppendLine($spacing + "{" ) | Out-Null + $IndentCount++ $spacing = $indent * $IndentCount - $complexString.appendLine($spacing + "`$$returnPropertyName += `$$tempPropertyName" ) | Out-Null - $IndentCount -- + $complexString.AppendLine($spacing + "`$$returnPropertyName += `$$tempPropertyName" ) | Out-Null + $IndentCount-- $spacing = $indent * $IndentCount - $complexString.appendLine($spacing + "}" ) | Out-Null - $IndentCount -- + $complexString.AppendLine($spacing + "}" ) | Out-Null + $IndentCount-- $spacing = $indent * $IndentCount - $complexString.appendLine($spacing + "}" ) | Out-Null + $complexString.AppendLine($spacing + "}" ) | Out-Null if ($IsNested) { - $complexString.appendLine($spacing + "`$$ParentPropertyName" +".Add('$propertyName',`$$returnPropertyName" +")" ) | Out-Null + $complexString.AppendLine($spacing + "`$$ParentPropertyName" +".Add('$propertyName',`$$returnPropertyName" +")" ) | Out-Null } } else { - $complexString.appendLine($spacing + "if (`$$tempPropertyName.values.Where({`$null -ne `$_}).count -eq 0)" ) | Out-Null - $complexString.appendLine($spacing + "{" ) | Out-Null - $IndentCount ++ + $complexString.AppendLine($spacing + "if (`$$tempPropertyName.values.Where({`$null -ne `$_}).Count -eq 0)" ) | Out-Null + $complexString.AppendLine($spacing + "{" ) | Out-Null + $IndentCount++ $spacing = $indent * $IndentCount - $complexString.appendLine($spacing + "`$$returnPropertyName = `$null" ) | Out-Null - $IndentCount -- + $complexString.AppendLine($spacing + "`$$returnPropertyName = `$null" ) | Out-Null + $IndentCount-- $spacing = $indent * $IndentCount - $complexString.appendLine($spacing + "}" ) | Out-Null + $complexString.AppendLine($spacing + "}" ) | Out-Null if ($IsNested) { - $complexString.appendLine($spacing + "`$$ParentPropertyName" +".Add('$propertyName',`$$returnPropertyName" +")" ) | Out-Null + $complexString.AppendLine($spacing + "`$$ParentPropertyName" +".Add('$propertyName',`$$returnPropertyName" +")" ) | Out-Null } } - return [String]($complexString.toString()) + return [String]($complexString.ToString()) } function Get-DateTypeConstructorToString @@ -1781,7 +1970,7 @@ function Get-DateTypeConstructorToString [Parameter()] [System.Int32] - $IndentCount=0, + $IndentCount = 0, [Parameter()] [System.String] @@ -1789,17 +1978,17 @@ function Get-DateTypeConstructorToString [Parameter()] [System.Boolean] - $IsNested=$false + $IsNested = $false ) $dateString = [System.Text.StringBuilder]::New() - $indent=" " + $indent = " " $spacing = $indent * $IndentCount $valuePrefix = "getValue." $propertyName = Get-StringFirstCharacterToUpper -Value $Property.Name - $returnPropertyName= "date"+ $propertyName - $propertyType=$Property.Type.split(".")|select-object -last 1 + $returnPropertyName = "date"+ $propertyName + $propertyType = $Property.Type.Split(".") | Select-Object -Last 1 if ($Property.IsRootProperty -eq $false) @@ -1810,27 +1999,27 @@ function Get-DateTypeConstructorToString if ($property.IsArray) { - $dateString.appendLine($spacing + "`$$returnPropertyName" + " = @()") | Out-Null - $dateString.appendLine($spacing + "foreach (`$current$propertyName in `$$valuePrefix$PropertyName)" ) | Out-Null - $dateString.appendLine($spacing + "{" ) | Out-Null - $IndentCount ++ + $dateString.AppendLine($spacing + "`$$returnPropertyName" + " = @()") | Out-Null + $dateString.AppendLine($spacing + "foreach (`$current$propertyName in `$$valuePrefix$PropertyName)" ) | Out-Null + $dateString.AppendLine($spacing + "{" ) | Out-Null + $IndentCount++ $spacing = $indent * $IndentCount - $dateString.appendLine($spacing + "`$$returnPropertyName += ([$propertyType]`$current$propertyName).ToString('$DateFormat')") | Out-Null - $IndentCount -- + $dateString.AppendLine($spacing + "`$$returnPropertyName += ([$propertyType]`$current$propertyName).ToString('$DateFormat')") | Out-Null + $IndentCount-- $spacing = $indent * $IndentCount - $dateString.appendLine($spacing + "}" ) | Out-Null + $dateString.AppendLine($spacing + "}" ) | Out-Null } else { - $dateString.appendLine($spacing + "`$$returnPropertyName" + " = `$null") | Out-Null - $dateString.appendLine($spacing + "if (`$null -ne `$$valuePrefix$PropertyName)" ) | Out-Null - $dateString.appendLine($spacing + "{" ) | Out-Null - $IndentCount ++ + $dateString.AppendLine($spacing + "`$$returnPropertyName" + " = `$null") | Out-Null + $dateString.AppendLine($spacing + "if (`$null -ne `$$valuePrefix$PropertyName)" ) | Out-Null + $dateString.AppendLine($spacing + "{" ) | Out-Null + $IndentCount++ $spacing = $indent * $IndentCount - $dateString.appendLine($spacing + "`$$returnPropertyName = ([$propertyType]`$$valuePrefix$PropertyName).ToString('$DateFormat')") | Out-Null - $IndentCount -- + $dateString.AppendLine($spacing + "`$$returnPropertyName = ([$propertyType]`$$valuePrefix$PropertyName).ToString('$DateFormat')") | Out-Null + $IndentCount-- $spacing = $indent * $IndentCount - $dateString.appendLine($spacing + "}" ) | Out-Null + $dateString.AppendLine($spacing + "}" ) | Out-Null } return $dateString.ToString() @@ -1842,7 +2031,7 @@ function Get-TimeTypeConstructorToString [OutputType([System.String[]])] param ( [Parameter(Mandatory = $true)] - [ValidateScript({$_.Type -like "System.Time*"})] + [ValidateScript({ $_.Type -like "System.Time*" })] $Property, [Parameter()] @@ -1851,7 +2040,7 @@ function Get-TimeTypeConstructorToString [Parameter()] [System.Int32] - $IndentCount=0, + $IndentCount = 0, [Parameter()] [System.String] @@ -1859,17 +2048,17 @@ function Get-TimeTypeConstructorToString [Parameter()] [System.Boolean] - $IsNested=$false + $IsNested = $false ) $timeString = [System.Text.StringBuilder]::New() - $indent=" " + $indent = " " $spacing = $indent * $IndentCount $valuePrefix = "getValue." $propertyName = Get-StringFirstCharacterToUpper -Value $Property.Name - $returnPropertyName= "time"+ $propertyName - $propertyType=$Property.Type.split(".")|select-object -last 1 + $returnPropertyName = "time"+ $propertyName + $propertyType = $Property.Type.Split(".") | Select-Object -Last 1 if ($Property.IsRootProperty -eq $false) @@ -1880,27 +2069,27 @@ function Get-TimeTypeConstructorToString if ($property.IsArray) { - $timeString.appendLine($spacing + "`$$returnPropertyName" + " = @()") | Out-Null - $timeString.appendLine($spacing + "foreach (`$current$propertyName in `$$valuePrefix$PropertyName)" ) | Out-Null - $timeString.appendLine($spacing + "{" ) | Out-Null - $IndentCount ++ + $timeString.AppendLine($spacing + "`$$returnPropertyName" + " = @()") | Out-Null + $timeString.AppendLine($spacing + "foreach (`$current$propertyName in `$$valuePrefix$PropertyName)" ) | Out-Null + $timeString.AppendLine($spacing + "{" ) | Out-Null + $IndentCount++ $spacing = $indent * $IndentCount - $timeString.appendLine($spacing + "`$$returnPropertyName += ([$propertyType]`$current$propertyName).ToString()") | Out-Null - $IndentCount -- + $timeString.AppendLine($spacing + "`$$returnPropertyName += ([$propertyType]`$current$propertyName).ToString()") | Out-Null + $IndentCount-- $spacing = $indent * $IndentCount - $timeString.appendLine($spacing + "}" ) | Out-Null + $timeString.AppendLine($spacing + "}" ) | Out-Null } else { - $timeString.appendLine($spacing + "`$$returnPropertyName" + " = `$null") | Out-Null - $timeString.appendLine($spacing + "if (`$null -ne `$$valuePrefix$PropertyName)" ) | Out-Null - $timeString.appendLine($spacing + "{" ) | Out-Null - $IndentCount ++ + $timeString.AppendLine($spacing + "`$$returnPropertyName" + " = `$null") | Out-Null + $timeString.AppendLine($spacing + "if (`$null -ne `$$valuePrefix$PropertyName)" ) | Out-Null + $timeString.AppendLine($spacing + "{" ) | Out-Null + $IndentCount++ $spacing = $indent * $IndentCount - $timeString.appendLine($spacing + "`$$returnPropertyName = ([$propertyType]`$$valuePrefix$PropertyName).ToString()") | Out-Null - $IndentCount -- + $timeString.AppendLine($spacing + "`$$returnPropertyName = ([$propertyType]`$$valuePrefix$PropertyName).ToString()") | Out-Null + $IndentCount-- $spacing = $indent * $IndentCount - $timeString.appendLine($spacing + "}" ) | Out-Null + $timeString.AppendLine($spacing + "}" ) | Out-Null } return $timeString.ToString() @@ -1921,7 +2110,7 @@ function Get-EnumTypeConstructorToString [Parameter()] [System.Int32] - $IndentCount=0, + $IndentCount = 0, [Parameter()] [System.String] @@ -1929,7 +2118,7 @@ function Get-EnumTypeConstructorToString ) $enumString = [System.Text.StringBuilder]::New() - $indent=" " + $indent = " " $spacing = $indent * $IndentCount $valuePrefix = "getValue." @@ -1942,15 +2131,15 @@ function Get-EnumTypeConstructorToString $valuePrefix += "AdditionalProperties." } - $enumString.appendLine($spacing + "`$$returnPropertyName" + " = `$null") | Out-Null - $enumString.appendLine($spacing + "if (`$null -ne `$$valuePrefix$PropertyName)" ) | Out-Null - $enumString.appendLine($spacing + "{" ) | Out-Null - $IndentCount ++ + $enumString.AppendLine($spacing + "`$$returnPropertyName" + " = `$null") | Out-Null + $enumString.AppendLine($spacing + "if (`$null -ne `$$valuePrefix$PropertyName)" ) | Out-Null + $enumString.AppendLine($spacing + "{" ) | Out-Null + $IndentCount++ $spacing = $indent * $IndentCount - $enumString.appendLine($spacing + "`$$returnPropertyName = `$$valuePrefix$PropertyName.ToString()") | Out-Null - $IndentCount -- + $enumString.AppendLine($spacing + "`$$returnPropertyName = `$$valuePrefix$PropertyName.ToString()") | Out-Null + $IndentCount-- $spacing = $indent * $IndentCount - $enumString.appendLine($spacing + "}" ) | Out-Null + $enumString.AppendLine($spacing + "}" ) | Out-Null return $enumString.ToString() @@ -2008,16 +2197,16 @@ function Get-ParameterBlockInformation } if ($property.IsEnumType) { - $myParam.add('Members', $property.Members) + $myParam.Add('Members', $property.Members) } if ($property.IsComplexType) { - $myParam.add('Properties', (Get-ParameterBlockInformation ` + $myParam.Add('Properties', (Get-ParameterBlockInformation ` -Properties $property.Properties ` -DefaultParameterSetProperties $DefaultParameterSetProperties)) } - $parameterBlock+=$myParam + $parameterBlock += $myParam } return $parameterBlock } @@ -2073,12 +2262,12 @@ function Get-M365DSCDRGParameterType } 'edm.*' { - $parameterType = $Type.replace('Edm', 'System') + $parameterType = $Type.Replace('Edm', 'System') break; } 'C(*)' { - $typeName = $Type.replace('C(', '').replace(')', '') + $typeName = $Type.Replace('C(', '').Replace(')', '') $parameterType = (Get-M365DSCDRGParameterType -Type $typeName) + '[]' break; } @@ -2182,11 +2371,7 @@ function Get-M365DSCDRGFakeValueForParameter { "String" { - if ($ValidateSetValues -ne $null -and $ValidateSetValues.Length -gt 0) - { - - } - else + if ($null -eq $ValidateSetValues -or $ValidateSetValues.Length -eq 0) { if ($Drift) { @@ -2260,7 +2445,7 @@ function Get-M365DSCFakeValues [Parameter()] [System.String] - $DateFormat="o" + $DateFormat = "o" ) $result = @{} @@ -2290,17 +2475,17 @@ function Get-M365DSCFakeValues if ($IsGetTargetResource) { $propertyType = "MSFT_$propertyType" - $hashValue.add('CIMType', $propertyType) + $hashValue.Add('CIMType', $propertyType) } if (-not $isRecursive) { - $IsParentFromAdditionalProperties=$false + $IsParentFromAdditionalProperties = $false if (-not $parameter.IsRootProperty) { - $IsParentFromAdditionalProperties=$true + $IsParentFromAdditionalProperties = $true } } - $hashValue.add('isArray', $parameter.IsArray) + $hashValue.Add('isArray', $parameter.IsArray) $nestedProperties = @() if ($null -ne $parameter.Properties) { @@ -2312,8 +2497,8 @@ function Get-M365DSCFakeValues -IsGetTargetResource $IsGetTargetResource ` -IsParentFromAdditionalProperties $IsParentFromAdditionalProperties } - $hashValue.add('Properties', $nestedProperties) - $hashValue.add('Name', $parameterName) + $hashValue.Add('Properties', $nestedProperties) + $hashValue.Add('Name', $parameterName) } else { @@ -2375,21 +2560,21 @@ function Get-M365DSCFakeValues '*.DateTime' { [String]$hashValue = '' - $fakeValue = ([DateTime]"2023-01-01T00:00:00").toString("$DateFormat") + $fakeValue = ([DateTime]"2023-01-01T00:00:00").ToString("$DateFormat") $hashValue = $fakeValue break } '*.DateTimeOffset' { [String]$hashValue = '' - $fakeValue = ([DateTimeOffset]"2023-01-01T00:00:00").toString("$DateFormat") + $fakeValue = ([DateTimeOffset]"2023-01-01T00:00:00").ToString("$DateFormat") $hashValue = $fakeValue break } '*.Time*' { [String]$hashValue = '' - $fakeValue = [Datetime]::Parse("00:00:00").TimeOfDay.toString() + $fakeValue = [Datetime]::Parse("00:00:00").TimeOfDay.ToString() $hashValue = $fakeValue break } @@ -2398,7 +2583,7 @@ function Get-M365DSCFakeValues if ($hashValue) { - if ((-Not $parameter.IsRootProperty ) -and -not $IsGetTargetResource -and -not $isRecursive) + if ((-not $parameter.IsRootProperty) -and -not $IsGetTargetResource -and -not $isRecursive) { $parameterName = Get-StringFirstCharacterToLower -Value $parameterName $additionalProperties.Add($parameterName, $hashValue) @@ -2414,12 +2599,12 @@ function Get-M365DSCFakeValues } } } - if (-not [String]::isNullorEmpty($AdditionalPropertiesType)) + if (-not [String]::IsNullOrEmpty($AdditionalPropertiesType)) { $additionalProperties.Add('@odata.type', '#microsoft.graph.' + $AdditionalPropertiesType) } - if ($additionalProperties.count -gt 0) + if ($additionalProperties.Count -gt 0) { $result.Add('AdditionalProperties', $additionalProperties) } @@ -2509,8 +2694,8 @@ function Get-M365DSCHashAsString { if ($isCmdletCall -and $prop.contains('odataType')) { - $prop.add('@odata.type', $prop.odataType) - $prop.remove('odataType') + $prop.Add('@odata.type', $prop.odataType) + $prop.Remove('odataType') } $l = (Get-M365DSCHashAsString -Values $prop -Space "$Space$extraSpace " -isCmdletCall $isCmdletCall) $propLine += $l @@ -2522,7 +2707,7 @@ function Get-M365DSCHashAsString $sb.Append((Get-M365DSCHashAsString -Values $Values.$key -Space "$Space " -isCmdletCall $isCmdletCall)) | Out-Null } $endLine = "$Space$extraSpace}" - if ($Values.$Key.CIMType ) + if ($Values.$Key.CIMType) { $endLine += ' -ClientOnly)' } @@ -2554,12 +2739,12 @@ function Get-M365DSCResourcePermission [Parameter()] [System.String] - $UpdateVerb='Update', + $UpdateVerb = 'Update', [Parameter()] [ValidateSet('v1.0','beta')] [System.String] - $APIVersion='v1.0' + $APIVersion = 'v1.0' ) $readPermissionsNames = (Find-MgGraphCommand -Command "Get-$CmdLetNoun" -ApiVersion $ApiVersion| Select-Object -First 1 -ExpandProperty Permissions).Name @@ -2608,19 +2793,19 @@ function Get-M365DSCResourcePermission } $delegatedPermissions = @{} - $delegatedPermissions.add('read', $readPermissions) - $delegatedPermissions.add('update', $updatePermissions) + $delegatedPermissions.Add('read', $readPermissions) + $delegatedPermissions.Add('update', $updatePermissions) $applicationPermissions = @{} - $applicationPermissions.add('read', $readPermissions) - $applicationPermissions.add('update', $updatePermissions) + $applicationPermissions.Add('read', $readPermissions) + $applicationPermissions.Add('update', $updatePermissions) $workloadPermissions = @{} - $workloadPermissions.add('delegated', $delegatedPermissions) - $workloadPermissions.add('application', $applicationPermissions) + $workloadPermissions.Add('delegated', $delegatedPermissions) + $workloadPermissions.Add('application', $applicationPermissions) $permissions = @{} - $permissions.add($nodeWorkloadName, $workloadPermissions) + $permissions.Add($nodeWorkloadName, $workloadPermissions) $return = @{'permissions' = $permissions } @@ -2685,7 +2870,7 @@ function Get-M365DSCDRGCimInstancesSchemaStringContent { if ($property.Name -eq "@odata.type") { - $member="#microsoft.graph."+$member + $member = "#microsoft.graph." + $member } $mySet += "`"" + $member + "`"," } @@ -2695,7 +2880,7 @@ function Get-M365DSCDRGCimInstancesSchemaStringContent $propertyName = $property.Name if ($property.Name -eq "@odata.type") { - $propertyName="odataType" + $propertyName = "odataType" } $stringResult += " [Write, Description(`"$($property.Description)`")$propertySet] $($propertyType) $($propertyName)" if ($property.IsArray) @@ -2886,7 +3071,7 @@ function New-M365DSCExampleFile $start = $exportContent.IndexOf("`r`n $ResourceName ") $end = $exportContent.IndexOf("`r`n }", $start) $start = $exportContent.IndexOf("{", $start) + 1 - $exampleContent = $exportContent.Substring($start, $end-$start) + $exampleContent = $exportContent.Substring($start, $end - $start) $exampleFileFullPath = "$Path\$ResourceName\1-$ResourceName-Example.ps1" $folderPath = "$Path\$ResourceName" @@ -2991,12 +3176,12 @@ function Get-ComplexTypeMapping ) $complexMapping = @() $propertyType = Get-StringFirstCharacterToUpper -Value $Property.Type - $isRequired=$false + $isRequired = $false if ($property.Description -like "* Required.*") { - $isRequired=$true + $isRequired = $true } - $map=@{ + $map = @{ Name = $Property.Name CimInstanceName = $Workload+ $PropertyType IsRequired = $isRequired @@ -3047,18 +3232,18 @@ function New-M365HashTableMapping $complexTypeContent = '' $convertToString = '' $convertToVariable = '' - $addtionalProperties = '' + $additionalProperties = '' $complexTypeConstructor = [System.Text.StringBuilder]::New() $enumTypeConstructor = [System.Text.StringBuilder]::New() $dateTypeConstructor = [System.Text.StringBuilder]::New() $timeTypeConstructor = [System.Text.StringBuilder]::New() - $biggestParamaterLength = 'CertificateThumbprint'.length + $biggestParameterLength = 'CertificateThumbprint'.Length foreach ($property in $properties.Name) { - If ($property.length -gt $biggestParamaterLength) + If ($property.Length -gt $biggestParameterLength) { - $biggestParamaterLength = $property.length + $biggestParameterLength = $property.Length } } @@ -3067,7 +3252,7 @@ function New-M365HashTableMapping $cmdletParameter = $DefaultParameterSetProperties | Where-Object -FilterScript { $_.Name -eq $property.Name } if ($null -eq $cmdletParameter) { - $UseAddtionalProperties = $true + $UseAdditionalProperties = $true } if ($property.Name -ne 'CreatedDateTime' -and $property.Name -ne 'LastModifiedDateTime') { @@ -3080,40 +3265,40 @@ function New-M365HashTableMapping $CimInstanceName = $CimInstanceName -replace '[[\]]', '' $CimInstanceName = $Workload + $CimInstanceName $global:ComplexList = @() - $complexTypeConstructor.appendLine((Get-ComplexTypeConstructorToString -Property $property -IndentCount 2 -DateFormat $DateFormat)) + $complexTypeConstructor.AppendLine((Get-ComplexTypeConstructorToString -Property $property -IndentCount 2 -DateFormat $DateFormat)) $global:ComplexList = $null [Array]$complexMapping = Get-ComplexTypeMapping -Property $property -Workload $Workload $complexMappingString = [System.Text.StringBuilder]::New() - if ($complexMapping.count -gt 1) + if ($complexMapping.Count -gt 1) { - $complexMappingString.appendLine(" `$complexMapping = @(") | out-null + $complexMappingString.AppendLine(" `$complexMapping = @(") | Out-Null foreach ($map in $complexMapping) { - $complexMappingString.appendLine(" @{")| out-null - $complexMappingString.appendLine(" Name = '" + $map.Name + "'")| out-null - $complexMappingString.appendLine(" CimInstanceName = '" + $map.CimInstanceName + "'")| out-null - $complexMappingString.appendLine(" IsRequired = `$" + $map.IsRequired.ToString())| out-null - $complexMappingString.appendLine(" }")| out-null + $complexMappingString.AppendLine(" @{") | Out-Null + $complexMappingString.AppendLine(" Name = '" + $map.Name + "'") | Out-Null + $complexMappingString.AppendLine(" CimInstanceName = '" + $map.CimInstanceName + "'") | Out-Null + $complexMappingString.AppendLine(" IsRequired = `$" + $map.IsRequired.ToString()) | Out-Null + $complexMappingString.AppendLine(" }") | Out-Null } - $complexMappingString.appendLine(" )")| out-null + $complexMappingString.AppendLine(" )") | Out-Null } $convertToString += " if (`$null -ne `$Results.$parameterName)`r`n" $convertToString += " {`r`n" - if (-Not ([String]::IsNullOrEmpty($complexMappingString.toString()))) + if (-not ([String]::IsNullOrEmpty($complexMappingString.ToString()))) { - $convertToString += $complexMappingString.toString() + $convertToString += $complexMappingString.ToString() } $convertToString += " `$complexTypeStringResult = Get-M365DSCDRGComplexTypeToString ```r`n" $convertToString += " -ComplexObject `$Results.$parameterName ```r`n" $convertToString += " -CIMInstanceName '$CimInstanceName'" - if (-Not ([String]::IsNullOrEmpty($complexMappingString.toString()))) + if (-not ([String]::IsNullOrEmpty($complexMappingString.ToString()))) { $convertToString += " ```r`n" $convertToString += " -ComplexTypeMapping `$complexMapping`r`n" } $convertToString += "`r`n" - $convertToString += " if (-Not [String]::IsNullOrWhiteSpace(`$complexTypeStringResult))`r`n" + $convertToString += " if (-not [String]::IsNullOrWhiteSpace(`$complexTypeStringResult))`r`n" $convertToString += " {`r`n" $convertToString += " `$Results.$parameterName = `$complexTypeStringResult`r`n" $convertToString += " }`r`n" @@ -3127,23 +3312,21 @@ function New-M365HashTableMapping $convertToVariable += " {`r`n" $convertToVariable += " `$currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock `$currentDSCBlock -ParameterName `"$parameterName`" -isCIMArray:`$$($property.IsArray)`r`n" $convertToVariable += " }`r`n" - - } if ($property.IsEnumType) { - $enumTypeConstructor.appendLine((Get-EnumTypeConstructorToString -Property $property -IndentCount 2 -DateFormat $DateFormat)) + $enumTypeConstructor.AppendLine((Get-EnumTypeConstructorToString -Property $property -IndentCount 2 -DateFormat $DateFormat)) } if ($property.Type -like "System.Date*") { - $dateTypeConstructor.appendLine((Get-DateTypeConstructorToString -Property $property -IndentCount 2 -DateFormat $DateFormat)) + $dateTypeConstructor.AppendLine((Get-DateTypeConstructorToString -Property $property -IndentCount 2 -DateFormat $DateFormat)) } if ($property.Type -like "System.Time*") { - $timeTypeConstructor.appendLine((Get-TimeTypeConstructorToString -Property $property -IndentCount 2 -DateFormat $DateFormat)) + $timeTypeConstructor.AppendLine((Get-TimeTypeConstructorToString -Property $property -IndentCount 2 -DateFormat $DateFormat)) } - $spacing = $biggestParamaterLength - $property.Name.length + $spacing = $biggestParameterLength - $property.Name.Length $propertyName = Get-StringFirstCharacterToUpper -Value $property.Name $hashtable += " $($parameterName + (' ' * $spacing) ) = " if ($property.IsComplexType) @@ -3164,7 +3347,7 @@ function New-M365HashTableMapping } else { - $propertyPrefix="`$getValue." + $propertyPrefix = "`$getValue." if ($property.IsRootProperty -eq $false) { $propertyName = Get-StringFirstCharacterToLower -Value $property.Name @@ -3177,14 +3360,14 @@ function New-M365HashTableMapping } } - $defaultKeys=@( + $defaultKeys = @( 'Ensure' 'Credential' 'ApplicationId' 'TenantId' 'ApplicationSecret' 'CertificateThumbprint' - 'Managedidentity' + 'ManagedIdentity' ) foreach ($key in $defaultKeys) { @@ -3198,7 +3381,7 @@ function New-M365HashTableMapping $keyValue = '$ManagedIdentity.IsPresent' } - $spacing = $biggestParamaterLength - $key.length + $spacing = $biggestParameterLength - $key.Length $hashtable += " $($key + ' ' * $spacing) = $keyValue`r`n" } $results.Add('ConvertToVariable', $convertToVariable) @@ -3206,7 +3389,7 @@ function New-M365HashTableMapping $results.Add('EnumTypeConstructor', $enumTypeConstructor.ToString()) $results.Add('DateTypeConstructor', $dateTypeConstructor.ToString()) $results.Add('TimeTypeConstructor', $timeTypeConstructor.ToString()) - $results.Add('addtionalProperties', $addtionalProperties) + $results.Add('additionalProperties', $additionalProperties) $results.Add('ConvertToString', $convertToString) $results.Add('StringContent', $hashtable) $results.Add('ComplexTypeContent', $complexTypeContent) @@ -3233,7 +3416,7 @@ function Get-ParameterBlockStringForModule { $validateSet += "'" + $member + "'," } - $validateSet = $validateSet.substring(0, $validateSet.length - 1) + $validateSet = $validateSet.Substring(0, $validateSet.Length - 1) $validateSet += ')]' $parameterBlockOutput += " $($ValidateSet)`r`n" } @@ -3256,7 +3439,7 @@ function Get-ParameterBlockStringForModule } else { - $parameterBlockOutput += " [$($_.Type.replace('[]',''))" + $parameterBlockOutput += " [$($_.Type.Replace('[]',''))" } if ($_.IsArray) { @@ -3277,7 +3460,7 @@ function Get-ResourceStub $CmdletNoun ) - $parametersToSkip=@( + $parametersToSkip = @( 'InformationVariable' 'WhatIf' 'WarningVariable' @@ -3292,27 +3475,27 @@ function Get-ResourceStub 'InformationAction' 'PipelineVariable' ) - $stub=[System.Text.StringBuilder]::New() - $version= (get-Command -Noun $cmdletNoun | select-object -Unique Version | Sort-Object -Descending | Select-Object -First 1).Version.toString() - $commands = get-Command -Noun $cmdletNoun |where-object { $_.Version -eq $version } + $stub = [System.Text.StringBuilder]::New() + $version = (Get-Command -Noun $cmdletNoun | Select-Object -Unique Version | Sort-Object -Descending | Select-Object -First 1).Version.ToString() + $commands = Get-Command -Noun $cmdletNoun | Where-Object -FilterScript { $_.Version -eq $version } foreach ($command in $commands) { - $command= get-Command -Name $command.Name |where-object { $_.Version -eq $version } - $stub.AppendLine("function $($command.Name)")|out-null - $stub.AppendLine("{")|out-null - $stub.AppendLine(" [CmdletBinding()]")|out-null - $stub.AppendLine(" param")|out-null - $stub.AppendLine(" (")|out-null + $command= get-Command -Name $command.Name | Where-Object -FilterScript { $_.Version -eq $version } + $stub.AppendLine("function $($command.Name)") | Out-Null + $stub.AppendLine("{") | Out-Null + $stub.AppendLine(" [CmdletBinding()]") | Out-Null + $stub.AppendLine(" param") | Out-Null + $stub.AppendLine(" (") | Out-Null $parameters = $command.Parameters - $i=0 - $keys= ($parameters.keys) | where-object { $_ -notin $parametersToSkip } - $keyCount = $keys.count + $i = 0 + $keys= ($parameters.Keys) | Where-Object -FilterScript { $_ -notin $parametersToSkip } + $keyCount = $keys.Count foreach ($key in $keys) { - $stub.AppendLine(" [Parameter()]")|out-null + $stub.AppendLine(" [Parameter()]") | Out-Null $name = ($parameters.$key).Name - $type = ($parameters.$key).ParameterType.toString() + $type = ($parameters.$key).ParameterType.ToString() $isArray = $false if ($type -like "*[[\]]") { @@ -3327,20 +3510,20 @@ function Get-ResourceStub $type += "[]" } } - $stub.AppendLine(" [$type]")|out-null - $stub.Append(" `$$name")|out-null - if ($i -lt $keyCount -1 ) + $stub.AppendLine(" [$type]") | Out-Null + $stub.Append(" `$$name") | Out-Null + if ($i -lt $keyCount -1) { - $stub.Append(",`r`n")|out-null + $stub.Append(",`r`n") | Out-Null } - $stub.Append("`r`n")|out-null + $stub.Append("`r`n") | Out-Null $i++ } - $stub.AppendLine(" )")|out-null - $stub.AppendLine("}`r`n")|out-null + $stub.AppendLine(" )") | Out-Null + $stub.AppendLine("}`r`n") | Out-Null } - $stub.toString() + $stub.ToString() } function Update-Microsoft365StubFile @@ -3356,12 +3539,12 @@ function Update-Microsoft365StubFile $M365DSCTestFolder = Join-Path -Path $PSScriptRoot ` -ChildPath "..\Tests\Unit" ` -Resolve - $filePath=(Join-Path -Path $M365DSCTestFolder ` + $filePath = (Join-Path -Path $M365DSCTestFolder ` -ChildPath "\Stubs\Microsoft365.psm1" ` -Resolve) $content = Get-Content -Path $FilePath - if (($content|select-string -pattern "function Get-$CmdletNoun$").count -eq 0) + if (($content | Select-String -Pattern "function Get-$CmdletNoun$").Count -eq 0) { $content += "#region $CmdletNoun`r`n" + (Get-ResourceStub -CmdletNoun $CmdletNoun) + "#endregion`r`n" Set-Content -Path $FilePath -Value $content @@ -3375,4 +3558,329 @@ function Update-Microsoft365StubFile Write-Error $_ } } -Export-ModuleMember -Function Get-MgGraphModuleCmdLetDifference, New-M365DSCResourceForGraphCmdLet, New-M365DSCResource, * + +function Get-SettingsCatalogSettingDefinitionValueDefinition { + param( + [Parameter(Mandatory = $true)] + $SettingDefinition, + + [Parameter(Mandatory = $true)] + [System.String] + $SettingDefinitionOdataTypeBase + ) + + if (-not $SettingDefinition.AdditionalProperties.valueDefinition) { + return $null + } + + $description = "" + $type = $SettingDefinition.AdditionalProperties.valueDefinition.'@odata.type'.Replace($settingDefinitionOdataTypeBase, "").Replace("SettingValueDefinition", "") + switch ($type) { + "String" { + $max = $SettingDefinition.AdditionalProperties.valueDefinition.maximumLength + $min = $SettingDefinition.AdditionalProperties.valueDefinition.minimumLength + $description = "Length must be between $min and $max characters." + } "Integer" { + $max = $SettingDefinition.AdditionalProperties.valueDefinition.maximumValue + $min = $SettingDefinition.AdditionalProperties.valueDefinition.minimumValue + $description = "Value must be between $min and $max." + } + } + + return @{ + Max = $max + Min = $min + Description = $description + Type = $type + } +} + +function Get-SettingsCatalogSettingDefinitionValueOption { + param( + [Parameter(Mandatory = $true)] + $SettingDefinition, + + [Parameter(Mandatory = $true)] + [System.String] + $SettingDefinitionOdataTypeBase + ) + + $options = @() + foreach ($option in $SettingDefinition.AdditionalProperties.options) { + $options += @{ + Name = $option.name + Id = $option.itemId.Split("_")[-1] + Type = $option.optionValue.'@odata.type'.Replace($SettingDefinitionOdataTypeBase, "").Replace("SettingValue", "") + DisplayName = $option.displayName + } + } + + $options +} + +function Get-SettingsCatalogSettingDefinitionDefaultValue { + param( + [Parameter(Mandatory = $true)] + $SettingDefinition, + + [Parameter(Mandatory = $true)] + [System.String] + $SettingDefinitionOdataTypeBase + ) + + $type = Get-SettingsCatalogSettingDefinitionValueType -SettingDefinition $SettingDefinition -SettingDefinitionOdataTypeBase $SettingDefinitionOdataTypeBase + + # Either they are a "simple" setting or a "choice" setting + # If they are a simple setting, they have a default value + if ($type -like "Simple*") { + # There might be a default value specified in the setting definition + $value = $SettingDefinition.AdditionalProperties.defaultValue.value + $nullOrEmpty = [String]::IsNullOrEmpty($value) + + # If the value is not null or empty, return the value, otherwise return the default value for the type + switch ($type) { + "String" { if (-not $nullOrEmpty) { $value } else { "" } } + "Integer" { if (-not $nullOrEmpty) { [System.Int32]::Parse($value) } else { 0 } } + "Boolean" { if (-not $nullOrEmpty) { [System.Boolean]::Parse($value) } else { $false } } + default { $value } + } + } else { + # If the setting is a choice setting, the default value is the default option id + if (-not [String]::IsNullOrEmpty($SettingDefinition.AdditionalProperties.defaultOptionId)) { + $SettingDefinition.AdditionalProperties.defaultOptionId.Split("_")[-1] + } else { + $null + } + } +} + +function Get-SettingsCatalogSettingDefinitionValueType { + param( + [Parameter(Mandatory = $true)] + $SettingDefinition, + + [Parameter(Mandatory = $true)] + [System.String] + $SettingDefinitionOdataTypeBase + ) + + # Type can be Choice, Simple or *Collection + $type = $SettingDefinition.AdditionalProperties.'@odata.type'.Replace($settingDefinitionOdataTypeBase, "").Replace("Setting", "").Replace("Definition", "") + if ($type -eq 'Simple') { + $type += $SettingDefinition.AdditionalProperties.defaultValue.'@odata.type'.Replace($settingDefinitionOdataTypeBase, "").Replace("SettingValue", "") + } elseif ($type -eq 'SimpleCollection') { + $type = $type.Replace("Collection", $SettingDefinition.AdditionalProperties.defaultValue.'@odata.type'.Replace($settingDefinitionOdataTypeBase, "").Replace("SettingValue", "") + "Collection") + } else { + # Type is GroupCollection and does not have a default value to narrow down the type + } + + return $type +} + +function New-SettingsCatalogSettingDefinitionSettingsFromTemplate { + param( + [Parameter(Mandatory = $true)] + $SettingTemplate, + + [Parameter(ParameterSetName = "ParseRoot")] + [Parameter(ParameterSetName = "ParseChild")] + [System.String] + $SettingDefinitionIdPrefix, + + [Parameter(ParameterSetName = "ParseChild")] + $SettingDefinition, + + [Parameter(ParameterSetName = "ParseRoot")] + [System.Array] + $RootSettingDefinitions, + + [Parameter(ParameterSetName = "Start")] + [switch] $FromRoot + ) + + $settingDefinitionOdataTypeBase = "#microsoft.graph.deviceManagementConfiguration" + if ($FromRoot) { + $RootSettingDefinitions = $SettingTemplate.SettingDefinitions | Where-Object -FilterScript { + $_.Id -eq $SettingTemplate.SettingInstanceTemplate.SettingDefinitionId -and ` + ($_.AdditionalProperties.dependentOn.Count -eq 0 -and $_.AdditionalProperties.options.dependentOn.Count -eq 0) + } + $settingDefinitionIdPrefix = $SettingTemplate.SettingInstanceTemplate.SettingDefinitionId.Split("_")[0..-1] -join "_" + return New-SettingsCatalogSettingDefinitionSettingsFromTemplate ` + -SettingTemplate $SettingTemplate ` + -RootSettingDefinitions $RootSettingDefinitions ` + -SettingDefinitionIdPrefix $settingDefinitionIdPrefix + } + + if ($PSCmdlet.ParameterSetName -eq "ParseRoot") { + $settings = @() + foreach ($RootSettingDefinition in $RootSettingDefinitions) { + $settings += New-SettingsCatalogSettingDefinitionSettingsFromTemplate ` + -SettingTemplate $SettingTemplate ` + -SettingDefinition $RootSettingDefinition ` + -SettingDefinitionIdPrefix $settingDefinitionIdPrefix + } + return $settings + } + + $type = Get-SettingsCatalogSettingDefinitionValueType -SettingDefinition $SettingDefinition -SettingDefinitionOdataTypeBase $settingDefinitionOdataTypeBase + $defaultValue = Get-SettingsCatalogSettingDefinitionDefaultValue -SettingDefinition $SettingDefinition -SettingDefinitionOdataTypeBase $settingDefinitionOdataTypeBase + $options = Get-SettingsCatalogSettingDefinitionValueOption -SettingDefinition $SettingDefinition -SettingDefinitionOdataTypeBase $settingDefinitionOdataTypeBase + $valueRestriction = Get-SettingsCatalogSettingDefinitionValueDefinition -SettingDefinition $SettingDefinition -SettingDefinitionOdataTypeBase $settingDefinitionOdataTypeBase + + $settingName = $SettingDefinition.Name + $settingNameLowercase = "" + $settingNameLowercase = $SettingDefinition.Id.Replace($SettingDefinitionIdPrefix, "") + + if ($SettingDefinition.AdditionalProperties.dependentOn.Count -gt 0) { + $possibleParentSettingId = $SettingDefinition.AdditionalProperties.dependentOn.parentSettingId.Replace($SettingDefinitionIdPrefix, "") + } elseif ($SettingDefinition.AdditionalProperties.options.dependentOn.Count -gt 0) { + $possibleParentSettingId = $SettingDefinition.AdditionalProperties.options.dependentOn.parentSettingId | Select-Object -Unique + $possibleParentSettingId = $possibleParentSettingId.Replace($SettingDefinitionIdPrefix, "") + } + $regex = [Regex]::new($possibleParentSettingId + "_") + $settingNameLowercase = $regex.Replace($settingNameLowercase, "", 1) + + if ($settingNameLowercase -match "_.*_.*") { + $settingNameLowercase = $settingNameLowercase.Split("_")[1..2] -join "_" + } + + $settingsWithSameName = $SettingTemplate.SettingDefinitions | Where-Object -FilterScript { $_.Name -eq $settingName } + if ($settingsWithSameName.Count -gt 1) { + # Add parent setting name to the child setting name + if ($SettingDefinition.AdditionalProperties.dependentOn.parentSettingId.Count -gt 0) + { + $parentSetting = $SettingTemplate.SettingDefinitions | Where-Object -FilterScript { + $_.Id -eq ($SettingDefinition.AdditionalProperties.dependentOn.parentSettingId | Select-Object -Unique -First 1) + } + } + elseif ($SettingDefinition.AdditionalProperties.options.dependentOn.parentSettingId.Count -gt 0) + { + $parentSetting = $SettingTemplate.SettingDefinitions | Where-Object -FilterScript { + $_.Id -eq ($SettingDefinition.AdditionalProperties.options.dependentOn.parentSettingId | Select-Object -Unique -First 1) + } + } + + $combinationMatches = $SettingTemplate.SettingDefinitions | Where-Object -FilterScript { + $_.Name -eq $settingName -and ` + (($_.AdditionalProperties.dependentOn.Count -gt 0 -and $_.AdditionalProperties.dependentOn.parentSettingId.Contains($parentSetting.Id)) -or ` + ($_.AdditionalProperties.options.dependentOn.Count -gt 0 -and $_.AdditionalProperties.options.dependentOn.parentSettingId.Contains($parentSetting.Id))) + } + + # If the combination of parent setting and setting name is unique, add the parent setting name to the setting name + if ($combinationMatches.Count -eq 1) { + $settingName = $parentSetting.Name + "_" + $settingName + } + # If the combination of parent setting and setting name is still not unique, grab the last part of the setting id + else + { + $parentSettingIdProperty = $parentSetting.Id.Split('_')[-1] + $parentSettingIdWithoutProperty = $parentSetting.Id.Replace("_$parentSettingIdProperty", "") + # We can't use the entire setting here, because the child setting id does not have to come after the parent setting id + $settingName = $settingDefinition.Id.Replace($parentSettingIdWithoutProperty + "_", "").Replace($parentSettingIdProperty + "_", "") + } + } + + $childSettings = @() + $childSettings += $SettingTemplate.SettingDefinitions | Where-Object -FilterScript { + ($_.AdditionalProperties.dependentOn.Count -gt 0 -and $_.AdditionalProperties.dependentOn.parentSettingId.Contains($SettingDefinition.Id)) -or + ($_.AdditionalProperties.options.dependentOn.Count -gt 0 -and $_.AdditionalProperties.options.dependentOn.parentSettingId.Contains($SettingDefinition.Id)) + } + + $setting = [ordered]@{ + NameFromId = $settingNameLowercase + Name = $settingName + DisplayName = $SettingDefinition.DisplayName + Type = $type + DefaultValue = $defaultValue + Options = $options + ValueRestriction = $valueRestriction + ChildSettings = foreach ($childSetting in $childSettings) { + New-SettingsCatalogSettingDefinitionSettingsFromTemplate -SettingTemplate $SettingTemplate -SettingDefinition $childSetting -SettingDefinitionIdPrefix $SettingDefinitionIdPrefix + } + } + + $setting +} + +function New-ParameterDefinitionFromSettingsCatalogTemplateSetting { + param( + [Parameter(Mandatory = $true)] + $TemplateSetting + ) + + $mofTypeMapping = @{ + "Choice" = "String" + "SimpleString" = "String" + "String" = "String" + "SimpleInteger" = "SInt32" + "Integer" = "SInt32" + "Boolean" = "Boolean" + "SimpleStringCollection" = "String" + "SimpleIntegerCollection" = "SInt32" + } + $powerShellTypeMapping = @{ + "Choice" = "System.String" + "SimpleString" = "System.String" + "String" = "System.String" + "SimpleInteger" = "System.Int32" + "Integer" = "System.Int32" + "Boolean" = "System.Boolean" + "DateTime" = "System.DateTime" + "SimpleStringCollection" = "System.String[]" + "SimpleIntegerCollection" = "System.Int32[]" + } + + $mofParameterTemplate = " [Write, Description("" "")] ;" + $powerShellParameterTemplate = @" + [Parameter()] + [] + $ +"@ + + $mofDefinition = $mofParameterTemplate.Replace("", $TemplateSetting.DisplayName) + if ($TemplateSetting.Options) { + $options = @() + $values = @() + $TemplateSetting.Options | ForEach-Object { + $options += "$($_.Id)" + ": " + $_.Name.Replace("""", "'") + $values += """$($_.Id)""" + } + $optionsString = "(" + ($options -join ", ") + ")" + $ValueMapString = ", ValueMap{$($values -join ", ")}, Values{$($values -join ", ")}" + } + $mofDefinition = $mofDefinition.Replace("", $optionsString) + $mofDefinition = $mofDefinition.Replace("", $ValueMapString) + $mofDefinition = $mofDefinition.Replace("", $mofTypeMapping[$TemplateSetting.Type]) + $mofDefinition = $mofDefinition.Replace("", $TemplateSetting.Name) + $isCollection = $TemplateSetting.Type -like "*Collection" + $mofDefinition = $mofDefinition.Replace("", $( if ($isCollection) { "[]" } else { "" } )) + + $powerShellDefinition = $powerShellParameterTemplate.Replace("", $TemplateSetting.Name) + $powerShellDefinition = $powerShellDefinition.Replace("", $powerShellTypeMapping[$TemplateSetting.Type]) + $restriction = '' + if ($null -ne $TemplateSetting.ValueRestriction) { + if ($TemplateSetting.ValueRestriction.Type -like "*String") { + $restriction = " [ValidateLength($($TemplateSetting.ValueRestriction.Min), $($TemplateSetting.ValueRestriction.Max))]" + } elseif ($TemplateSetting.ValueRestriction.Type -like "*Integer") { + $restriction = " [ValidateRange($($TemplateSetting.ValueRestriction.Min), $($TemplateSetting.ValueRestriction.Max))]" + } + } + if ($null -ne $TemplateSetting.Options) { + $restriction = " [ValidateSet('$($TemplateSetting.Options.Id -join "', '")')]" + } + $powerShellDefinition = $powerShellDefinition.Replace("", $( if ($restriction) { "`n $restriction" } else { "" })) + + $definition = @{} + if ($TemplateSetting.Type -ne "GroupCollection") { + $definition.Add("MOF", @($mofDefinition)) + $definition.Add("PowerShell", @($powerShellDefinition)) + } + + $TemplateSetting.ChildSettings | ForEach-Object { + $childDefinitions = New-ParameterDefinitionFromSettingsCatalogTemplateSetting -TemplateSetting $_ + $definition.MOF += $childDefinitions.MOF + $definition.PowerShell += $childDefinitions.PowerShell + } + + $definition +} diff --git a/ResourceGenerator/Module.Template.psm1 b/ResourceGenerator/Module.Template.psm1 index 7d34a0eee6..a03262750a 100644 --- a/ResourceGenerator/Module.Template.psm1 +++ b/ResourceGenerator/Module.Template.psm1 @@ -69,7 +69,7 @@ function Get-TargetResource { Write-Verbose -Message "Could not find an with {$}" - if (-Not [string]::IsNullOrEmpty($)) + if (-not [string]::IsNullOrEmpty($)) { $getValue = ` @@ -83,12 +83,12 @@ function Get-TargetResource } $ = $getValue. Write-Verbose -Message "An with {$} and {$} was found."<#ResourceGenerator -ResourceGenerator#> +ResourceGenerator#> $results = @{<#ResourceGenerator #region resource generator code #endregionResourceGenerator#> } -<#ComplexTypeContent#><#AssignmentsGet#> +<#ComplexTypeContent#><#SettingsCatalogAddSettings#><#AssignmentsGet#> return [System.Collections.Hashtable] $results } catch @@ -160,22 +160,12 @@ function Set-TargetResource $BoundParameters = Remove-M365DSCAuthenticationParameter -BoundParameters $PSBoundParameters +<#SettingsCatalogProperties#> if ($Ensure -eq 'Present' -and $currentInstance.Ensure -eq 'Absent') { Write-Verbose -Message "Creating an with {$DisplayName}" <#AssignmentsRemove#> - $CreateParameters = ([Hashtable]$BoundParameters).clone() - $CreateParameters = Rename-M365DSCCimInstanceParameter -Properties $CreateParameters - $CreateParameters.Remove('Id') | Out-Null - - $keys = (([Hashtable]$CreateParameters).clone()).Keys - foreach ($key in $keys) - { - if ($null -ne $CreateParameters.$key -and $CreateParameters.$key.getType().Name -like '*cimInstance*') - { - $CreateParameters.$key = Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject $CreateParameters.$key - } - }<#ResourceGenerator +<#DefaultCreateParameters#><#ResourceGenerator #region resource generator code $policy = <#NewKeyIdentifier#> <#AssignmentsNew#> #endregionResourceGenerator#> @@ -184,28 +174,16 @@ function Set-TargetResource { Write-Verbose -Message "Updating the with {$($currentInstance.)}" <#AssignmentsRemove#> - $UpdateParameters = ([Hashtable]$BoundParameters).clone() - $UpdateParameters = Rename-M365DSCCimInstanceParameter -Properties $UpdateParameters - - $UpdateParameters.Remove('Id') | Out-Null - - $keys = (([Hashtable]$UpdateParameters).clone()).Keys - foreach ($key in $keys) - { - if ($null -ne $UpdateParameters.$key -and $UpdateParameters.$key.getType().Name -like '*cimInstance*') - { - $UpdateParameters.$key = Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject $UpdateParameters.$key - } - }<#ResourceGenerator +<#DefaultUpdateParameters#><#ResourceGenerator #region resource generator code - <#UpdateKeyIdentifier#> + <#UpdateKeyIdentifier#> <#AssignmentsUpdate#> #endregionResourceGenerator#> } elseif ($Ensure -eq 'Absent' -and $currentInstance.Ensure -eq 'Present') { Write-Verbose -Message "Removing the with {$($currentInstance.)}" <#ResourceGenerator #region resource generator code - <#removeKeyIdentifier#> + <#removeKeyIdentifier#> #endregionResourceGenerator#> } } @@ -268,7 +246,7 @@ function Test-TargetResource Write-Verbose -Message "Testing configuration of the with {$} and {$}" $CurrentValues = Get-TargetResource @PSBoundParameters - $ValuesToCheck = ([Hashtable]$PSBoundParameters).clone() +<#DefaultTestValuesToCheck#> if ($CurrentValues.Ensure -ne $Ensure) { @@ -282,17 +260,25 @@ function Test-TargetResource { $source = $PSBoundParameters.$key $target = $CurrentValues.$key - if ($source.getType().Name -like '*CimInstance*') + if ($source.GetType().Name -like '*CimInstance*') { $source = Get-M365DSCDRGComplexTypeToHashtable -ComplexObject $source - $testResult = Compare-M365DSCComplexObject ` - -Source ($source) ` - -Target ($target) + if ($key -eq "Assignments") + { + $testResult = Compare-M365DSCIntunePolicyAssignment ` + -Source $source ` + -Target $target + } + else + { + $testResult = Compare-M365DSCComplexObject ` + -Source ($source) ` + -Target ($target) + } - if (-Not $testResult) + if (-not $testResult) { - $testResult = $false break } @@ -300,11 +286,8 @@ function Test-TargetResource } } - $ValuesToCheck.remove('Id') | Out-Null - $ValuesToCheck.Remove('Credential') | Out-Null - $ValuesToCheck.Remove('ApplicationId') | Out-Null - $ValuesToCheck.Remove('TenantId') | Out-Null - $ValuesToCheck.Remove('ApplicationSecret') | 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 $ValuesToCheck)" @@ -328,6 +311,10 @@ function Export-TargetResource [OutputType([System.String])] param ( + [Parameter()] + [System.String] + $Filter, + [Parameter()] [System.Management.Automation.PSCredential] $Credential, diff --git a/Tests/Integration/Microsoft365DSC/M365DSCIntegration.AAD.Create.Tests.ps1 b/Tests/Integration/Microsoft365DSC/M365DSCIntegration.AAD.Create.Tests.ps1 index 918571ce7a..6f8c8a7041 100644 --- a/Tests/Integration/Microsoft365DSC/M365DSCIntegration.AAD.Create.Tests.ps1 +++ b/Tests/Integration/Microsoft365DSC/M365DSCIntegration.AAD.Create.Tests.ps1 @@ -229,6 +229,14 @@ Ensure = "Present" Credential = $Credscredential } + AADEntitlementManagementRoleAssignment 'AADEntitlementManagementRoleAssignment-Create' + { + AppScopeId = "/"; + Credential = $Credscredential + Ensure = "Present"; + Principal = "John.Smith@$Domain"; + RoleDefinition = "Catalog creator"; + } AADGroup 'MyGroups' { DisplayName = "DSCGroup" diff --git a/Tests/QA/Microsoft365DSC.SettingsJson.Tests.ps1 b/Tests/QA/Microsoft365DSC.SettingsJson.Tests.ps1 index 7a21fd4b45..de2e26c128 100644 --- a/Tests/QA/Microsoft365DSC.SettingsJson.Tests.ps1 +++ b/Tests/QA/Microsoft365DSC.SettingsJson.Tests.ps1 @@ -17,12 +17,32 @@ Describe -Name 'Successfully import Settings.json files' { Describe -Name 'Successfully validate all used permissions in Settings.json files ' { BeforeAll { - $data = Invoke-WebRequest -Uri 'https://graphpermissions.azurewebsites.net/api/GetPermissionList' - $roles = $data.Content.Split('|')[0].Split(',') + $allModules = Get-module Microsoft.graph.* -ListAvailable + $allPermissions = @() + foreach ($module in $allModules) + { + $cmds = Get-Command -Module $module.Name + foreach ($cmd in $cmds) + { + $graphInfo = Find-MgGraphCommand -Command $cmd.Name -ErrorAction SilentlyContinue + if ($null -ne $graphInfo) + { + $permissions = $graphInfo.Permissions | Where-Object -FilterScript {$_.PermissionType -eq 'Application'} + $allPermissions += $permissions.Name + } + } + } - # Fix for the Tasks name not matching the UI. - $roles += @('Tasks.Read.All', 'Tasks.ReadWrite.All') - $delegated = $data.Content.Split('|')[1].Split(',') + $allPermissions+= @('OrgSettings-Microsoft365Install.Read.All', ` + 'OrgSettings-Forms.Read.All', ` + 'OrgSettings-Todo.Read.All', ` + 'OrgSettings-AppsAndServices.Read.All', ` + 'OrgSettings-DynamicsVoice.Read.All', ` + 'ReportSettings.Read.All', ` + 'RoleManagementPolicy.Read.Directory', ` + 'RoleEligibilitySchedule.Read.Directory', ` + 'Agreement.Read.All') + $roles = $allPermissions | Select-Object -Unique | Sort-Object -Descending:$false } It "Permissions used in settings.json file for '' should exist" -TestCases $settingsFiles { diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADAuthenticationFlowPolicy.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADAuthenticationFlowPolicy.Tests.ps1 new file mode 100644 index 0000000000..fc033f1191 --- /dev/null +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADAuthenticationFlowPolicy.Tests.ps1 @@ -0,0 +1,136 @@ +[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 'AADAuthenticationFlowPolicy' -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@contoso.onmicrosoft.com', $secpasswd) + + Mock -CommandName Confirm-M365DSCDependencies -MockWith { + } + + Mock -CommandName Update-MgBetaPolicyAuthenticationFlowPolicy -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 + } + + # Test contexts + Context -Name 'Value is already in the desired state.' -Fixture { + BeforeAll { + $testParams = @{ + Credential = $Credential; + Description = "Description Text."; + DisplayName = "Authentication flows policy"; + Id = "authenticationFlowsPolicy"; + IsSingleInstance = "Yes"; + SelfServiceSignUpEnabled = $True; + } + + Mock -CommandName Get-MgBetaPolicyAuthenticationFlowPolicy -MockWith { + $result = @{ + Id = 'authenticationFlowsPolicy' + DisplayName = 'Authentication flows policy' + Description = 'Description Text.' + SelfServiceSignUp = @{ + IsEnabled = $true + } + } + return $result + } + } + + It 'Should return true from the test method' { + Test-TargetResource @testParams | Should -Be $true + } + } + + Context -Name 'Value is already in the desired state.' -Fixture { + BeforeAll { + $testParams = @{ + Credential = $Credential; + Description = "Description Text."; + DisplayName = "Authentication flows policy"; + Id = "authenticationFlowsPolicy"; + IsSingleInstance = "Yes"; + SelfServiceSignUpEnabled = $True; + } + + Mock -CommandName Get-MgBetaPolicyAuthenticationFlowPolicy -MockWith { + $result = @{ + Id = 'authenticationFlowsPolicy' + DisplayName = 'Authentication flows policy' + Description = 'Description Text.' + SelfServiceSignUp = @{ + IsEnabled = $false #drift + } + } + return $result + } + } + + It 'Should return true from the test method' { + Test-TargetResource @testParams | Should -Be $false + } + + It 'Should update from the Set method' { + Set-TargetResource @testParams + Should -Invoke -CommandName Update-MgBetaPolicyAuthenticationFlowPolicy -Exactly 1 + } + } + + Context -Name 'ReverseDSC Tests' -Fixture { + BeforeAll { + $Global:CurrentModeIsExport = $true + $Global:PartialExportFileName = "$(New-Guid).partial.ps1" + $testParams = @{ + Credential = $Credential + } + + Mock -CommandName Get-MgBetaPolicyAuthenticationFlowPolicy -MockWith { + $result = @{ + Id = 'authenticationFlowsPolicy' + DisplayName = 'Authentication flows policy' + Description = 'Description Text.' + SelfServiceSignUp = @{ + IsEnabled = $true + } + } + return $result + } + } + + 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.AADEntitlementManagementRoleAssignment.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADEntitlementManagementRoleAssignment.Tests.ps1 new file mode 100644 index 0000000000..11f0847417 --- /dev/null +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADEntitlementManagementRoleAssignment.Tests.ps1 @@ -0,0 +1,153 @@ +[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 'AADEntitlementManagementRoleAssignment' -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 Add-M365DSCTelemetryEvent -MockWith { + } + + Mock -CommandName Confirm-M365DSCDependencies -MockWith { + } + + Mock -CommandName Get-PSSession -MockWith { + } + + Mock -CommandName Remove-PSSession -MockWith { + } + + Mock -CommandName Invoke-MgGraphRequest -MockWith { + } + + Mock -CommandName New-MgBetaRoleManagementEntitlementManagementRoleAssignment -MockWith { + } + + Mock -CommandName Remove-MgBetaRoleManagementEntitlementManagementRoleAssignment -MockWith { + } + + Mock -CommandName Get-MgUser -MockWith { + return @{ + UserPrincipalName = "John.Smith@contoso.com" + Id = "12345-12345-12345-12345-12345" + } + } + + Mock -CommandName Get-MgBetaRoleManagementEntitlementManagementRoleDefinition -MockWith { + return @{ + DisplayName = "Catalog creator" + Id = "12345-12345-12345-12345-12345" + } + } + + 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 + } + # Test contexts + Context -Name "The assignment doesn't exist" -Fixture { + BeforeAll { + $testParams = @{ + AppScopeId = "/"; + Ensure = "Present"; + Principal = "John.Smith@contoso.com"; + RoleDefinition = "Catalog creator"; + Credential = $Credential + } + + Mock -CommandName Get-MgBetaRoleManagementEntitlementManagementRoleAssignment -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 instance from the Set method' { + Set-TargetResource @testParams + Should -Invoke -CommandName New-MgBetaRoleManagementEntitlementManagementRoleAssignment -Exactly 1 + } + } + + Context -Name "The assignment already exists" -Fixture { + BeforeAll { + $testParams = @{ + AppScopeId = "/"; + Ensure = "Present"; + Principal = "John.Smith@contoso.com"; + RoleDefinition = "Catalog creator"; + Credential = $Credential + } + + Mock -CommandName Get-MgBetaRoleManagementEntitlementManagementRoleAssignment -MockWith { + return @{ + AppScopeId = "/" + PrincipalId = 'xxxxx-xxxxx-xxxxx-xxxxx-xxxxx' + RoleDefinitionId = 'xxxxx-xxxxx-xxxxx-xxxxx-xxxxx' + DirectoryScopeId = '' + } + } + } + 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 $true + } + } + + + Context -Name 'ReverseDSC Tests' -Fixture { + BeforeAll { + $Global:CurrentModeIsExport = $true + $Global:PartialExportFileName = "$(New-Guid).partial.ps1" + $testParams = @{ + Credential = $Credential + } + Mock -CommandName Get-MgBetaRoleManagementEntitlementManagementRoleAssignment -MockWith { + return @{ + AppScopeId = "/" + PrincipalId = 'xxxxx-xxxxx-xxxxx-xxxxx-xxxxx' + RoleDefinitionId = 'xxxxx-xxxxx-xxxxx-xxxxx-xxxxx' + DirectoryScopeId = '' + } + } + } + + 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.IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy.Tests.ps1 index 00c4b0c10a..8a5bc91381 100644 --- a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy.Tests.ps1 +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy.Tests.ps1 @@ -208,6 +208,7 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { (New-CimInstance -ClassName MSFT_IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicyAssignments -Property @{ DataType = '#microsoft.graph.exclusionGroupAssignmentTarget' groupId = '26d60dd1-fab6-47bf-8656-358194c1a49d' + deviceAndAppManagementAssignmentFilterType = 'none' } -ClientOnly) ) BackupDirectory = '1' diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneAppConfigurationDevicePolicy.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneAppConfigurationDevicePolicy.Tests.ps1 index 8d87957ab8..8d66e2ec3d 100644 --- a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneAppConfigurationDevicePolicy.Tests.ps1 +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneAppConfigurationDevicePolicy.Tests.ps1 @@ -58,6 +58,9 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { Mock -CommandName Get-MgBetaDeviceAppManagementMobileAppConfigurationAssignment -MockWith { } + Mock -CommandName Get-MgBetaDeviceAppManagementMobileApp -MockWith { + } + } # Test contexts Context -Name "The IntuneAppConfigurationDevicePolicy should exist but it DOES NOT" -Fixture { @@ -82,6 +85,16 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { Credential = $Credential; } + Mock -CommandName Get-MgBetaDeviceAppManagementMobileApp -MockWith { + return @{ + Id = "FakeStringValue" + AdditionalProperties = @{ + packageId = "FakeStringValue" + '@odata.type' = "#microsoft.graph.androidManagedStoreApp" + } + } + } + Mock -CommandName Get-MgBetaDeviceAppManagementMobileAppConfiguration -MockWith { return $null } @@ -120,6 +133,16 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { Credential = $Credential; } + Mock -CommandName Get-MgBetaDeviceAppManagementMobileApp -MockWith { + return @{ + Id = "FakeStringValue" + AdditionalProperties = @{ + packageId = "FakeStringValue" + '@odata.type' = "#microsoft.graph.androidManagedStoreApp" + } + } + } + Mock -CommandName Get-MgBetaDeviceAppManagementMobileAppConfiguration -MockWith { return @{ AdditionalProperties = @{ @@ -183,6 +206,16 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { Credential = $Credential; } + Mock -CommandName Get-MgBetaDeviceAppManagementMobileApp -MockWith { + return @{ + Id = "FakeStringValue" + AdditionalProperties = @{ + packageId = "FakeStringValue" + '@odata.type' = "#microsoft.graph.androidManagedStoreApp" + } + } + } + Mock -CommandName Get-MgBetaDeviceAppManagementMobileAppConfiguration -MockWith { return @{ AdditionalProperties = @{ @@ -219,6 +252,7 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { Context -Name "The IntuneAppConfigurationDevicePolicy exists and values are NOT in the desired state" -Fixture { BeforeAll { $testParams = @{ + Assignments = @() ConnectedAppsEnabled = $True description = "FakeStringValue" displayName = "FakeStringValue" @@ -238,6 +272,16 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { Credential = $Credential; } + Mock -CommandName Get-MgBetaDeviceAppManagementMobileApp -MockWith { + return @{ + Id = "FakeStringValue" + AdditionalProperties = @{ + packageId = "FakeStringValue" + '@odata.type' = "#microsoft.graph.androidManagedStoreApp" + } + } + } + Mock -CommandName Get-MgBetaDeviceAppManagementMobileAppConfiguration -MockWith { return @{ AdditionalProperties = @{ diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneEndpointDetectionAndResponsePolicyWindows10.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneEndpointDetectionAndResponsePolicyWindows10.Tests.ps1 index c609591652..bd2a7728fb 100644 --- a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneEndpointDetectionAndResponsePolicyWindows10.Tests.ps1 +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneEndpointDetectionAndResponsePolicyWindows10.Tests.ps1 @@ -61,7 +61,7 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { AdditionalProperties = @( @{ "@odata.type" = '#microsoft.graph.exclusionGroupAssignmentTarget' - collectionId = '26d60dd1-fab6-47bf-8656-358194c1a49d' + groupId = '26d60dd1-fab6-47bf-8656-358194c1a49d' } ) } @@ -97,7 +97,7 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { Assignments = @( (New-CimInstance -ClassName MSFT_DeviceManagementConfigurationPolicyAssignments -Property @{ DataType = '#microsoft.graph.exclusionGroupAssignmentTarget' - CollectionId = '26d60dd1-fab6-47bf-8656-358194c1a49d' + GroupId = '26d60dd1-fab6-47bf-8656-358194c1a49d' } -ClientOnly) ) Credential = $Credential @@ -133,7 +133,7 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { Assignments = [CimInstance[]]@( (New-CimInstance -ClassName MSFT_DeviceManagementConfigurationPolicyAssignments -Property @{ DataType = '#microsoft.graph.exclusionGroupAssignmentTarget' - CollectionId = '26d60dd1-fab6-47bf-8656-358194c1a49d' + GroupId = '26d60dd1-fab6-47bf-8656-358194c1a49d' } -ClientOnly) ) Credential = $Credential @@ -202,7 +202,8 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { Assignments = [CimInstance[]]@( (New-CimInstance -ClassName MSFT_DeviceManagementConfigurationPolicyAssignments -Property @{ DataType = '#microsoft.graph.exclusionGroupAssignmentTarget' - CollectionId = '26d60dd1-fab6-47bf-8656-358194c1a49d' + GroupId = '26d60dd1-fab6-47bf-8656-358194c1a49d' + DeviceAndAppManagementAssignmentFilterType = 'none' } -ClientOnly) ) } @@ -232,27 +233,6 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { } } } - - <#Mock -CommandName Get-MgBetaDeviceManagementConfigurationPolicySetting -MockWith { - return @{ - Id = 0 - SettingDefinitions = $null - SettingInstance = @{ - SettingDefinitionId = 'device_vendor_msft_windowsadvancedthreatprotection_configuration_samplesharing' - SettingInstanceTemplateReference = @{ - SettingInstanceTemplateId = '6998c81e-2814-4f5e-b492-a6159128a97b' - } - AdditionalProperties = @{ - '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' - choiceSettingValue = @{ - children = @() - value = "device_vendor_msft_windowsadvancedthreatprotection_configuration_samplesharing_0" - } - } - } - AdditionalProperties = $null - } - }#> } It 'Should return true from the Test method' { @@ -266,7 +246,7 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { Assignments = @( (New-CimInstance -ClassName MSFT_DeviceManagementConfigurationPolicyAssignments -Property @{ DataType = '#microsoft.graph.exclusionGroupAssignmentTarget' - CollectionId = '26d60dd1-fab6-47bf-8656-358194c1a49d' + GroupId = '26d60dd1-fab6-47bf-8656-358194c1a49d' } -ClientOnly) ) Credential = $Credential diff --git a/Tests/Unit/Stubs/Microsoft365.psm1 b/Tests/Unit/Stubs/Microsoft365.psm1 index 3d57e93c31..ffd351c456 100644 --- a/Tests/Unit/Stubs/Microsoft365.psm1 +++ b/Tests/Unit/Stubs/Microsoft365.psm1 @@ -1171,6 +1171,90 @@ function Get-ManagementRoleEntry ) } +function Get-MgBetaRoleManagementEntitlementManagementRoleAssignment +{ + [CmdletBinding()] + param( + [Parameter()] + [System.String] + $UnifiedRoleAssignmentId, + + [Parameter()] + [System.String] + $Filter, + + [Parameter()] + [Switch] + $All + ) +} + +function Get-MgBetaRoleManagementEntitlementManagementRoleDefinition +{ + [CmdletBinding()] + param( + [Parameter()] + [System.String] + $UnifiedRoleDefinitionId, + + [Parameter()] + [System.String] + $Filter, + + [Parameter()] + [Switch] + $All + ) +} + +function Get-MgBetaPolicyAuthenticationFlowPolicy +{ + [CmdletBinding()] + param() +} + +function Update-MgBetaPolicyAuthenticationFlowPolicy +{ + [CmdletBinding()] + param( + [Parameter()] + [System.Boolean] + $SelfServiceSignUp + ) +} + +function New-MgBetaRoleManagementEntitlementManagementRoleAssignment +{ + [CmdletBinding()] + param( + [Parameter()] + [System.String] + $AppScopeId, + + [Parameter()] + [System.String] + $DirectoryScopeId, + + [Parameter()] + [System.String] + $PrincipalId, + + [Parameter()] + [System.String] + $RoleDefinitionId + ) +} + +function Remove-MgBetaRoleManagementEntitlementManagementRoleAssignment +{ + [CmdletBinding()] + param( + [Parameter()] + [System.String] + $UnifiedRoleAssignmentId + ) +} + function Set-ManagementRoleEntry { [CmdletBinding()] diff --git a/docs/docs/resources/azure-ad/AADAuthenticationMethodPolicyAuthenticator.md b/docs/docs/resources/azure-ad/AADAuthenticationMethodPolicyAuthenticator.md index f629757ebb..95f6bf00db 100644 --- a/docs/docs/resources/azure-ad/AADAuthenticationMethodPolicyAuthenticator.md +++ b/docs/docs/resources/azure-ad/AADAuthenticationMethodPolicyAuthenticator.md @@ -4,7 +4,7 @@ | Parameter | Attribute | DataType | Description | Allowed Values | | --- | --- | --- | --- | --- | -| **FeatureSettings** | Write | MSFT_MicrosoftGraphmicrosoftAuthenticatorFeatureSettings | A collection of Microsoft Authenticator settings such as number matching and location context, and whether they are enabled for all users or specific users only. | | +| **FeatureSettings** | Write | MSFT_MicrosoftGraphMicrosoftAuthenticatorFeatureSettings | A collection of Microsoft Authenticator settings such as number matching and location context, and whether they are enabled for all users or specific users only. | | | **IsSoftwareOathEnabled** | Write | Boolean | true if users can use the OTP code generated by the Microsoft Authenticator app, false otherwise. | | | **ExcludeTargets** | Write | MSFT_AADAuthenticationMethodPolicyAuthenticatorExcludeTarget[] | Displayname of the groups of users that are excluded from a policy. | | | **IncludeTargets** | Write | MSFT_AADAuthenticationMethodPolicyAuthenticatorIncludeTarget[] | Displayname of the groups of users that are included from a policy. | | diff --git a/docs/docs/resources/azure-ad/AADEntitlementManagementRoleAssignment.md b/docs/docs/resources/azure-ad/AADEntitlementManagementRoleAssignment.md new file mode 100644 index 0000000000..0370fd5913 --- /dev/null +++ b/docs/docs/resources/azure-ad/AADEntitlementManagementRoleAssignment.md @@ -0,0 +1,113 @@ +# AADEntitlementManagementRoleAssignment + +## Parameters + +| Parameter | Attribute | DataType | Description | Allowed Values | +| --- | --- | --- | --- | --- | +| **Id** | Write | String | Unique Id of the role assignment. | | +| **Principal** | Key | String | Identifier of the principal to which the assignment is granted. | | +| **RoleDefinition** | Key | String | Identifier of the unifiedRoleDefinition the assignment is for. | | +| **AppScopeId** | Write | String | Identifier of the app specific scope when the assignment scope is app specific. The scope of an assignment determines the set of resources for which the principal has been granted access. App scopes are scopes that are defined and understood by a resource application only. | | +| **DirectoryScopeId** | Write | String | Identifier of the directory object representing the scope of the assignment. The scope of an assignment 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, unlike app scopes that are defined and understood by a resource application only. | | +| **Ensure** | Write | String | Present ensures the policy 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 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. | | + + +## Description + +This resource configures an Azure AD Entitlement Management Role assignments. + +## Permissions + +### Microsoft Graph + +To authenticate with the Microsoft Graph API, this resource required the following permissions: + +#### Delegated permissions + +- **Read** + + - EntitlementManagement.Read.All + +- **Update** + + - EntitlementManagement.Read.All, EntitlementManagement.ReadWrite.All + +#### Application permissions + +- **Read** + + - EntitlementManagement.Read.All + +- **Update** + + - EntitlementManagement.Read.All, EntitlementManagement.ReadWrite.All, RoleManagement.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(Mandatory = $true)] + [PSCredential] + $Credscredential + ) + Import-DscResource -ModuleName Microsoft365DSC + + $Domain = $Credscredential.Username.Split('@')[1] + node localhost + { + AADEntitlementManagementRoleAssignment "AADEntitlementManagementRoleAssignment-Create" + { + AppScopeId = "/"; + Credential = $Credscredential + Ensure = "Present"; + Principal = "John.Smith@$Domain"; + RoleDefinition = "Catalog creator"; + } + } +} +``` + +### 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(Mandatory = $true)] + [PSCredential] + $Credscredential + ) + Import-DscResource -ModuleName Microsoft365DSC + + $Domain = $Credscredential.Username.Split('@')[1] + node localhost + { + AADEntitlementManagementRoleAssignment "AADEntitlementManagementRoleAssignment-Remove" + { + AppScopeId = "/"; + Credential = $Credscredential + Ensure = "Absent"; + Principal = "John.Smith@$Domain"; + RoleDefinition = "Catalog creator"; + } + } +} +``` +