From 1433feefa4995d407d1fb76f8d13129224ed8e8d Mon Sep 17 00:00:00 2001 From: William-francillette Date: Sun, 30 Apr 2023 12:47:07 +0100 Subject: [PATCH 1/2] repost --- ...gurationEditionUpgradePolicyWindows10.psm1 | 1421 +++++++++++++++++ ...onEditionUpgradePolicyWindows10.schema.mof | 30 + .../readme.md | 6 + .../settings.json | 33 + ...nEditionUpgradePolicyWindows10-Example.ps1 | 37 + ...ionEditionUpgradePolicyWindows10.Tests.ps1 | 253 +++ 6 files changed, 1780 insertions(+) create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceConfigurationEditionUpgradePolicyWindows10/MSFT_IntuneDeviceConfigurationEditionUpgradePolicyWindows10.psm1 create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceConfigurationEditionUpgradePolicyWindows10/MSFT_IntuneDeviceConfigurationEditionUpgradePolicyWindows10.schema.mof create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceConfigurationEditionUpgradePolicyWindows10/readme.md create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceConfigurationEditionUpgradePolicyWindows10/settings.json create mode 100644 Modules/Microsoft365DSC/Examples/Resources/IntuneDeviceConfigurationEditionUpgradePolicyWindows10/1-IntuneDeviceConfigurationEditionUpgradePolicyWindows10-Example.ps1 create mode 100644 Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneDeviceConfigurationEditionUpgradePolicyWindows10.Tests.ps1 diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceConfigurationEditionUpgradePolicyWindows10/MSFT_IntuneDeviceConfigurationEditionUpgradePolicyWindows10.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceConfigurationEditionUpgradePolicyWindows10/MSFT_IntuneDeviceConfigurationEditionUpgradePolicyWindows10.psm1 new file mode 100644 index 0000000000..d675cff23b --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceConfigurationEditionUpgradePolicyWindows10/MSFT_IntuneDeviceConfigurationEditionUpgradePolicyWindows10.psm1 @@ -0,0 +1,1421 @@ +function Get-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + param + ( + #region resource generator code + [Parameter()] + [System.String] + $License, + + [Parameter()] + [ValidateSet('productKey', 'licenseFile', 'notConfigured')] + [System.String] + $LicenseType, + + [Parameter()] + [System.String] + $ProductKey, + + [Parameter()] + [ValidateSet('windows10Enterprise', 'windows10EnterpriseN', 'windows10Education', 'windows10EducationN', 'windows10MobileEnterprise', 'windows10HolographicEnterprise', 'windows10Professional', 'windows10ProfessionalN', 'windows10ProfessionalEducation', 'windows10ProfessionalEducationN', 'windows10ProfessionalWorkstation', 'windows10ProfessionalWorkstationN', 'notConfigured', 'windows10Home', 'windows10HomeChina', 'windows10HomeN', 'windows10HomeSingleLanguage', 'windows10Mobile', 'windows10IoTCore', 'windows10IoTCoreCommercial')] + [System.String] + $TargetEdition, + + [Parameter()] + [ValidateSet('noRestriction', 'block', 'unlock')] + [System.String] + $WindowsSMode, + + [Parameter()] + [System.String] + $Description, + + [Parameter(Mandatory = $true)] + [System.String] + $DisplayName, + + [Parameter(Mandatory = $true)] + [System.String] + $Id, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $Assignments, + #endregion + + [Parameter()] + [System.String] + [ValidateSet('Absent', 'Present')] + $Ensure = 'Present', + + [Parameter()] + [System.Management.Automation.PSCredential] + $Credential, + + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ApplicationSecret, + + [Parameter()] + [System.String] + $CertificateThumbprint, + + [Parameter()] + [Switch] + $ManagedIdentity + ) + + try + { + $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` + -InboundParameters $PSBoundParameters ` + -ProfileName 'beta' + + #Ensure the proper dependencies are installed in the current environment. + Confirm-M365DSCDependencies + + #region Telemetry + $ResourceName = $MyInvocation.MyCommand.ModuleName.Replace('MSFT_', '') + $CommandName = $MyInvocation.MyCommand + $data = Format-M365DSCTelemetryParameters -ResourceName $ResourceName ` + -CommandName $CommandName ` + -Parameters $PSBoundParameters + Add-M365DSCTelemetryEvent -Data $data + #endregion + + $nullResult = $PSBoundParameters + $nullResult.Ensure = 'Absent' + + $getValue = $null + #region resource generator code + $getValue = Get-MgDeviceManagementDeviceConfiguration -DeviceConfigurationId $Id -ErrorAction SilentlyContinue + + if ($null -eq $getValue) + { + Write-Verbose -Message "Could not find an Intune Device Configuration Edition Upgrade Policy for Windows10 with Id {$Id}" + + if (-Not [string]::IsNullOrEmpty($DisplayName)) + { + $getValue = Get-MgDeviceManagementDeviceConfiguration ` + -Filter "DisplayName eq '$DisplayName'" ` + -ErrorAction SilentlyContinue | Where-Object ` + -FilterScript { ` + $_.AdditionalProperties.'@odata.type' -eq '#microsoft.graph.editionUpgradeConfiguration' ` + } + } + } + #endregion + if ($null -eq $getValue) + { + Write-Verbose -Message "Could not find an Intune Device Configuration Edition Upgrade Policy for Windows10 with DisplayName {$DisplayName}" + return $nullResult + } + $Id = $getValue.Id + Write-Verbose -Message "An Intune Device Configuration Edition Upgrade Policy for Windows10 with Id {$Id} and DisplayName {$DisplayName} was found." + + #region resource generator code + $enumLicenseType = $null + if ($null -ne $getValue.AdditionalProperties.licenseType) + { + $enumLicenseType = $getValue.AdditionalProperties.licenseType.ToString() + } + + $enumTargetEdition = $null + if ($null -ne $getValue.AdditionalProperties.targetEdition) + { + $enumTargetEdition = $getValue.AdditionalProperties.targetEdition.ToString() + } + + $enumWindowsSMode = $null + if ($null -ne $getValue.AdditionalProperties.windowsSMode) + { + $enumWindowsSMode = $getValue.AdditionalProperties.windowsSMode.ToString() + } + #endregion + + $results = @{ + #region resource generator code + License = $getValue.AdditionalProperties.license + LicenseType = $enumLicenseType + ProductKey = $getValue.AdditionalProperties.productKey + TargetEdition = $enumTargetEdition + WindowsSMode = $enumWindowsSMode + Description = $getValue.Description + DisplayName = $getValue.DisplayName + Id = $getValue.Id + Ensure = 'Present' + Credential = $Credential + ApplicationId = $ApplicationId + TenantId = $TenantId + ApplicationSecret = $ApplicationSecret + CertificateThumbprint = $CertificateThumbprint + Managedidentity = $ManagedIdentity.IsPresent + #endregion + } + $assignmentsValues = Get-MgDeviceManagementDeviceConfigurationAssignment -DeviceConfigurationId $Id + $assignmentResult = @() + foreach ($assignmentEntry in $AssignmentsValues) + { + $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 + } + $results.Add('Assignments', $assignmentResult) + + return [System.Collections.Hashtable] $results + } + catch + { + New-M365DSCLogEntry -Message 'Error retrieving data:' ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + + return $nullResult + } +} + +function Set-TargetResource +{ + [CmdletBinding()] + param + ( + #region resource generator code + [Parameter()] + [System.String] + $License, + + [Parameter()] + [ValidateSet('productKey', 'licenseFile', 'notConfigured')] + [System.String] + $LicenseType, + + [Parameter()] + [System.String] + $ProductKey, + + [Parameter()] + [ValidateSet('windows10Enterprise', 'windows10EnterpriseN', 'windows10Education', 'windows10EducationN', 'windows10MobileEnterprise', 'windows10HolographicEnterprise', 'windows10Professional', 'windows10ProfessionalN', 'windows10ProfessionalEducation', 'windows10ProfessionalEducationN', 'windows10ProfessionalWorkstation', 'windows10ProfessionalWorkstationN', 'notConfigured', 'windows10Home', 'windows10HomeChina', 'windows10HomeN', 'windows10HomeSingleLanguage', 'windows10Mobile', 'windows10IoTCore', 'windows10IoTCoreCommercial')] + [System.String] + $TargetEdition, + + [Parameter()] + [ValidateSet('noRestriction', 'block', 'unlock')] + [System.String] + $WindowsSMode, + + [Parameter()] + [System.String] + $Description, + + [Parameter(Mandatory = $true)] + [System.String] + $DisplayName, + + [Parameter(Mandatory = $true)] + [System.String] + $Id, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $Assignments, + #endregion + [Parameter()] + [System.String] + [ValidateSet('Absent', 'Present')] + $Ensure = 'Present', + + [Parameter()] + [System.Management.Automation.PSCredential] + $Credential, + + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ApplicationSecret, + + [Parameter()] + [System.String] + $CertificateThumbprint, + + [Parameter()] + [Switch] + $ManagedIdentity + ) + + #Ensure the proper dependencies are installed in the current environment. + Confirm-M365DSCDependencies + + #region Telemetry + $ResourceName = $MyInvocation.MyCommand.ModuleName.Replace('MSFT_', '') + $CommandName = $MyInvocation.MyCommand + $data = Format-M365DSCTelemetryParameters -ResourceName $ResourceName ` + -CommandName $CommandName ` + -Parameters $PSBoundParameters + Add-M365DSCTelemetryEvent -Data $data + #endregion + + $currentInstance = Get-TargetResource @PSBoundParameters + + $BoundParameters = Remove-M365DSCAuthenticationParameter -BoundParameters $PSBoundParameters + + if ($Ensure -eq 'Present' -and $currentInstance.Ensure -eq 'Absent') + { + Write-Verbose -Message "Creating an Intune Device Configuration Edition Upgrade Policy for Windows10 with DisplayName {$DisplayName}" + $BoundParameters.Remove('Assignments') | Out-Null + + $CreateParameters = ([Hashtable]$BoundParameters).clone() + $CreateParameters = Rename-M365DSCCimInstanceParameter -Properties $CreateParameters + $CreateParameters.Remove('Id') | Out-Null + + #Removing ProductKey if obfuscated + if (-not [String]::IsNullOrEmpty($ProductKey) -and $ProductKey.Contains('#')) + { + $CreateParameters.Remove('ProductKey') | 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 + } + } + #region resource generator code + $CreateParameters.Add('@odata.type', '#microsoft.graph.editionUpgradeConfiguration') + $policy = New-MgDeviceManagementDeviceConfiguration -BodyParameter $CreateParameters + $assignmentsHash = @() + foreach ($assignment in $Assignments) + { + $assignmentsHash += Get-M365DSCDRGComplexTypeToHashtable -ComplexObject $Assignment + } + + if ($policy.id) + { + Update-DeviceConfigurationPolicyAssignment -DeviceConfigurationPolicyId $policy.id ` + -Targets $assignmentsHash ` + -Repository 'deviceManagement/deviceConfigurations' + } + #endregion + } + elseif ($Ensure -eq 'Present' -and $currentInstance.Ensure -eq 'Present') + { + Write-Verbose -Message "Updating the Intune Device Configuration Edition Upgrade Policy for Windows10 with Id {$($currentInstance.Id)}" + $BoundParameters.Remove('Assignments') | Out-Null + + $UpdateParameters = ([Hashtable]$BoundParameters).clone() + $UpdateParameters = Rename-M365DSCCimInstanceParameter -Properties $UpdateParameters + + $UpdateParameters.Remove('Id') | Out-Null + + #Removing ProductKey if obfuscated + if (-not [String]::IsNullOrEmpty($ProductKey) -and $ProductKey.Contains('#')) + { + $UpdateParameters.Remove('ProductKey') | Out-Null + } + $keys = (([Hashtable]$UpdateParameters).clone()).Keys + foreach ($key in $keys) + { + if ($null -ne $UpdateParameters.$key -and $UpdateParameters.$key.getType().Name -like '*cimInstance*') + { + $UpdateParameters.$key = Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject $UpdateParameters.$key + } + } + #region resource generator code + $UpdateParameters.Add('@odata.type', '#microsoft.graph.editionUpgradeConfiguration') + Update-MgDeviceManagementDeviceConfiguration ` + -DeviceConfigurationId $currentInstance.Id ` + -BodyParameter $UpdateParameters + $assignmentsHash = @() + foreach ($assignment in $Assignments) + { + $assignmentsHash += Get-M365DSCDRGComplexTypeToHashtable -ComplexObject $Assignment + } + Update-DeviceConfigurationPolicyAssignment ` + -DeviceConfigurationPolicyId $currentInstance.id ` + -Targets $assignmentsHash ` + -Repository 'deviceManagement/deviceConfigurations' + #endregion + } + elseif ($Ensure -eq 'Absent' -and $currentInstance.Ensure -eq 'Present') + { + Write-Verbose -Message "Removing the Intune Device Configuration Edition Upgrade Policy for Windows10 with Id {$($currentInstance.Id)}" + #region resource generator code + Remove-MgDeviceManagementDeviceConfiguration -DeviceConfigurationId $currentInstance.Id + #endregion + } +} + +function Test-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Boolean])] + param + ( + #region resource generator code + [Parameter()] + [System.String] + $License, + + [Parameter()] + [ValidateSet('productKey', 'licenseFile', 'notConfigured')] + [System.String] + $LicenseType, + + [Parameter()] + [System.String] + $ProductKey, + + [Parameter()] + [ValidateSet('windows10Enterprise', 'windows10EnterpriseN', 'windows10Education', 'windows10EducationN', 'windows10MobileEnterprise', 'windows10HolographicEnterprise', 'windows10Professional', 'windows10ProfessionalN', 'windows10ProfessionalEducation', 'windows10ProfessionalEducationN', 'windows10ProfessionalWorkstation', 'windows10ProfessionalWorkstationN', 'notConfigured', 'windows10Home', 'windows10HomeChina', 'windows10HomeN', 'windows10HomeSingleLanguage', 'windows10Mobile', 'windows10IoTCore', 'windows10IoTCoreCommercial')] + [System.String] + $TargetEdition, + + [Parameter()] + [ValidateSet('noRestriction', 'block', 'unlock')] + [System.String] + $WindowsSMode, + + [Parameter()] + [System.String] + $Description, + + [Parameter(Mandatory = $true)] + [System.String] + $DisplayName, + + [Parameter(Mandatory = $true)] + [System.String] + $Id, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $Assignments, + #endregion + + [Parameter()] + [System.String] + [ValidateSet('Absent', 'Present')] + $Ensure = 'Present', + + [Parameter()] + [System.Management.Automation.PSCredential] + $Credential, + + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ApplicationSecret, + + [Parameter()] + [System.String] + $CertificateThumbprint, + + [Parameter()] + [Switch] + $ManagedIdentity + ) + + #Ensure the proper dependencies are installed in the current environment. + Confirm-M365DSCDependencies + + #region Telemetry + $ResourceName = $MyInvocation.MyCommand.ModuleName.Replace('MSFT_', '') + $CommandName = $MyInvocation.MyCommand + $data = Format-M365DSCTelemetryParameters -ResourceName $ResourceName ` + -CommandName $CommandName ` + -Parameters $PSBoundParameters + Add-M365DSCTelemetryEvent -Data $data + #endregion + + Write-Verbose -Message "Testing configuration of the Intune Device Configuration Edition Upgrade Policy for Windows10 with Id {$Id} and DisplayName {$DisplayName}" + + $CurrentValues = Get-TargetResource @PSBoundParameters + $ValuesToCheck = ([Hashtable]$PSBoundParameters).clone() + + if ($CurrentValues.Ensure -ne $PSBoundParameters.Ensure) + { + Write-Verbose -Message "Test-TargetResource returned $false" + return $false + } + $testResult = $true + + #Compare Cim instances + foreach ($key in $PSBoundParameters.Keys) + { + $source = $PSBoundParameters.$key + $target = $CurrentValues.$key + if ($source.getType().Name -like '*CimInstance*') + { + $source = Get-M365DSCDRGComplexTypeToHashtable -ComplexObject $source + + $testResult = Compare-M365DSCComplexObject ` + -Source ($source) ` + -Target ($target) + + if (-Not $testResult) + { + $testResult = $false + 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 + + #Checking last 4 digits of the productkey as obfuscated by Intune + $ValuesToCheck.Remove('ProductKey') | Out-Null + if ($ProductKey -ne $CurrentValues.ProductKey) + { + if ([String]::IsNullOrWhiteSpace($ProductKey) -xor [String]::IsNullOrWhiteSpace($CurrentValues.ProductKey)) + { + $testResult = $false + } + elseif ($ProductKey.substring($ProductKey.length - 4) -ne $CurrentValues.ProductKey.substring($CurrentValues.ProductKey.length - 4)) + { + $testResult = $false + } + } + + 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 + ) + + $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` + -InboundParameters $PSBoundParameters ` + -ProfileName 'beta' + + #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-MgDeviceManagementDeviceConfiguration ` + -All ` + -ErrorAction Stop | Where-Object ` + -FilterScript { ` + $_.AdditionalProperties.'@odata.type' -eq '#microsoft.graph.editionUpgradeConfiguration' ` + } + #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 + $params = @{ + Id = $config.Id + DisplayName = $config.DisplayName + Ensure = 'Present' + Credential = $Credential + ApplicationId = $ApplicationId + TenantId = $TenantId + ApplicationSecret = $ApplicationSecret + CertificateThumbprint = $CertificateThumbprint + Managedidentity = $ManagedIdentity.IsPresent + } + + $Results = Get-TargetResource @Params + $Results = Update-M365DSCExportAuthenticationResults -ConnectionMode $ConnectionMode ` + -Results $Results + if ($Results.Assignments) + { + $complexTypeStringResult = Get-M365DSCDRGComplexTypeToString -ComplexObject $Results.Assignments -CIMInstanceName DeviceManagementConfigurationPolicyAssignments + if ($complexTypeStringResult) + { + $Results.Assignments = $complexTypeStringResult + } + else + { + $Results.Remove('Assignments') | Out-Null + } + } + $currentDSCBlock = Get-M365DSCExportContentForResource -ResourceName $ResourceName ` + -ConnectionMode $ConnectionMode ` + -ModulePath $PSScriptRoot ` + -Results $Results ` + -Credential $Credential + if ($Results.Assignments) + { + $currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock -ParameterName 'Assignments' -IsCIMArray:$true + } + + $dscContent += $currentDSCBlock + Save-M365DSCPartialExport -Content $currentDSCBlock ` + -FileName $Global:PartialExportFileName + $i++ + Write-Host $Global:M365DSCEmojiGreenCheckMark + } + return $dscContent + } + catch + { + Write-Host $Global:M365DSCEmojiRedX + + New-M365DSCLogEntry -Message 'Error during Export:' ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + + return '' + } +} + +function Update-DeviceConfigurationPolicyAssignment +{ + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + param ( + [Parameter(Mandatory = 'true')] + [System.String] + $DeviceConfigurationPolicyId, + + [Parameter()] + [Array] + $Targets, + + [Parameter()] + [System.String] + $Repository = 'deviceManagement/configurationPolicies', + + [Parameter()] + [ValidateSet('v1.0', 'beta')] + [System.String] + $APIVersion = 'beta' + ) + try + { + $deviceManagementPolicyAssignments = @() + $Uri = "https://graph.microsoft.com/$APIVersion/$Repository/$DeviceConfigurationPolicyId/assign" + + foreach ($target in $targets) + { + $formattedTarget = @{'@odata.type' = $target.dataType } + if ($target.groupId) + { + $formattedTarget.Add('groupId', $target.groupId) + } + if ($target.collectionId) + { + $formattedTarget.Add('collectionId', $target.collectionId) + } + if ($target.deviceAndAppManagementAssignmentFilterType) + { + $formattedTarget.Add('deviceAndAppManagementAssignmentFilterType', $target.deviceAndAppManagementAssignmentFilterType) + } + if ($target.deviceAndAppManagementAssignmentFilterId) + { + $formattedTarget.Add('deviceAndAppManagementAssignmentFilterId', $target.deviceAndAppManagementAssignmentFilterId) + } + $deviceManagementPolicyAssignments += @{'target' = $formattedTarget } + } + $body = @{'assignments' = $deviceManagementPolicyAssignments } | ConvertTo-Json -Depth 20 + #write-verbose -Message $body + Invoke-MgGraphRequest -Method POST -Uri $Uri -Body $body -ErrorAction Stop + } + catch + { + New-M365DSCLogEntry -Message 'Error updating data:' ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + + return $null + } +} +function Rename-M365DSCCimInstanceParameter +{ + [CmdletBinding()] + [OutputType([System.Collections.Hashtable], [System.Collections.Hashtable[]])] + param( + [Parameter(Mandatory = 'true')] + $Properties + ) + + $keyToRename = @{ + 'odataType' = '@odata.type' + } + + $result = $Properties + + $type = $Properties.getType().FullName + + #region Array + if ($type -like '*[[\]]') + { + $values = @() + foreach ($item in $Properties) + { + $values += Rename-M365DSCCimInstanceParameter $item + } + $result = $values + + return , $result + } + #endregion + + #region Single + if ($type -like '*Hashtable') + { + $result = ([Hashtable]$Properties).clone() + } + if ($type -like '*CimInstance*' -or $type -like '*Hashtable*' -or $type -like '*Object*') + { + $hashProperties = Get-M365DSCDRGComplexTypeToHashtable -ComplexObject $result + $keys = ($hashProperties.clone()).keys + foreach ($key in $keys) + { + $keyName = $key.substring(0, 1).tolower() + $key.substring(1, $key.length - 1) + if ($key -in $keyToRename.Keys) + { + $keyName = $keyToRename.$key + } + + $property = $hashProperties.$key + if ($null -ne $property) + { + $hashProperties.Remove($key) + $hashProperties.add($keyName, (Rename-M365DSCCimInstanceParameter $property)) + } + } + $result = $hashProperties + } + return $result + #endregion +} + +function Get-M365DSCDRGComplexTypeToHashtable +{ + [CmdletBinding()] + [OutputType([hashtable], [hashtable[]])] + param( + [Parameter()] + $ComplexObject + ) + + if ($null -eq $ComplexObject) + { + return $null + } + + if ($ComplexObject.gettype().fullname -like '*[[\]]') + { + $results = @() + + foreach ($item in $ComplexObject) + { + if ($item) + { + $hash = Get-M365DSCDRGComplexTypeToHashtable -ComplexObject $item + $results += $hash + } + } + + # PowerShell returns all non-captured stream output, not just the argument of the return statement. + #An empty array is mangled into $null in the process. + #However, an array can be preserved on return by prepending it with the array construction operator (,) + return , [hashtable[]]$results + } + + if ($ComplexObject.getType().fullname -like '*Dictionary*') + { + $results = @{} + + $ComplexObject = [hashtable]::new($ComplexObject) + $keys = $ComplexObject.Keys + foreach ($key in $keys) + { + if ($null -ne $ComplexObject.$key) + { + $keyName = $key + + $keyType = $ComplexObject.$key.gettype().fullname + + if ($keyType -like '*CimInstance*' -or $keyType -like '*Dictionary*' -or $keyType -like 'Microsoft.Graph.PowerShell.Models.*' -or $keyType -like '*[[\]]') + { + $hash = Get-M365DSCDRGComplexTypeToHashtable -ComplexObject $ComplexObject.$key + + $results.Add($keyName, $hash) + } + else + { + $results.Add($keyName, $ComplexObject.$key) + } + } + } + return [hashtable]$results + } + + $results = @{} + + if ($ComplexObject.getType().Fullname -like '*hashtable') + { + $keys = $ComplexObject.keys + } + else + { + $keys = $ComplexObject | Get-Member | Where-Object -FilterScript { $_.MemberType -eq 'Property' } + } + + foreach ($key in $keys) + { + $keyName = $key + if ($ComplexObject.getType().Fullname -notlike '*hashtable') + { + $keyName = $key.Name + } + + if ($null -ne $ComplexObject.$keyName) + { + $keyType = $ComplexObject.$keyName.gettype().fullname + if ($keyType -like '*CimInstance*' -or $keyType -like '*Dictionary*' -or $keyType -like 'Microsoft.Graph.PowerShell.Models.*') + { + $hash = Get-M365DSCDRGComplexTypeToHashtable -ComplexObject $ComplexObject.$keyName + + $results.Add($keyName, $hash) + } + else + { + $results.Add($keyName, $ComplexObject.$keyName) + } + } + } + return [hashtable]$results +} + +<# + Use ComplexTypeMapping to overwrite the type of nested CIM + Example + $complexMapping=@( + @{ + Name="ApprovalStages" + CimInstanceName="MSFT_MicrosoftGraphapprovalstage1" + IsRequired=$false + } + @{ + Name="PrimaryApprovers" + CimInstanceName="MicrosoftGraphuserset" + IsRequired=$false + } + @{ + Name="EscalationApprovers" + CimInstanceName="MicrosoftGraphuserset" + IsRequired=$false + } + ) + With + Name: the name of the parameter to be overwritten + CimInstanceName: The type of the CIM instance (can include or not the prefix MSFT_) + IsRequired: If isRequired equals true, an empty hashtable or array will be returned. Some of the Graph parameters are required even though they are empty +#> +function Get-M365DSCDRGComplexTypeToString +{ + [CmdletBinding()] + param( + [Parameter()] + $ComplexObject, + + [Parameter(Mandatory = $true)] + [System.String] + $CIMInstanceName, + + [Parameter()] + [Array] + $ComplexTypeMapping, + + [Parameter()] + [System.String] + $Whitespace = '', + + [Parameter()] + [System.uint32] + $IndentLevel = 3, + + [Parameter()] + [switch] + $isArray = $false + ) + + if ($null -eq $ComplexObject) + { + return $null + } + + $indent = '' + for ($i = 0; $i -lt $IndentLevel ; $i++) + { + $indent += ' ' + } + #If ComplexObject is an Array + if ($ComplexObject.GetType().FullName -like '*[[\]]') + { + $currentProperty = @() + $IndentLevel++ + foreach ($item in $ComplexObject) + { + $splat = @{ + 'ComplexObject' = $item + 'CIMInstanceName' = $CIMInstanceName + 'IndentLevel' = $IndentLevel + } + if ($ComplexTypeMapping) + { + $splat.add('ComplexTypeMapping', $ComplexTypeMapping) + } + + $currentProperty += Get-M365DSCDRGComplexTypeToString -isArray:$true @splat + } + + # PowerShell returns all non-captured stream output, not just the argument of the return statement. + #An empty array is mangled into $null in the process. + #However, an array can be preserved on return by prepending it with the array construction operator (,) + return , $currentProperty + } + + $currentProperty = '' + if ($isArray) + { + $currentProperty += "`r`n" + $currentProperty += $indent + } + + $CIMInstanceName = $CIMInstanceName.replace('MSFT_', '') + $currentProperty += "MSFT_$CIMInstanceName{`r`n" + $IndentLevel++ + $indent = '' + for ($i = 0; $i -lt $IndentLevel ; $i++) + { + $indent += ' ' + } + $keyNotNull = 0 + + if ($ComplexObject.Keys.count -eq 0) + { + return $null + } + + foreach ($key in $ComplexObject.Keys) + { + if ($null -ne $ComplexObject.$key) + { + $keyNotNull++ + if ($ComplexObject.$key.GetType().FullName -like 'Microsoft.Graph.PowerShell.Models.*' -or $key -in $ComplexTypeMapping.Name) + { + $hashPropertyType = $ComplexObject[$key].GetType().Name.tolower() + + $isArray = $false + if ($ComplexObject[$key].GetType().FullName -like '*[[\]]') + { + $isArray = $true + } + #overwrite type if object defined in mapping complextypemapping + if ($key -in $ComplexTypeMapping.Name) + { + $hashPropertyType = ([Array]($ComplexTypeMapping | Where-Object -FilterScript { $_.Name -eq $key }).CimInstanceName)[0] + $hashProperty = $ComplexObject[$key] + } + else + { + $hashProperty = Get-M365DSCDRGComplexTypeToHashtable -ComplexObject $ComplexObject[$key] + } + + if (-not $isArray) + { + $currentProperty += $indent + $key + ' = ' + } + + if ($isArray -and $key -in $ComplexTypeMapping.Name) + { + if ($ComplexObject.$key.count -gt 0) + { + $currentProperty += $indent + $key + ' = ' + $currentProperty += '@(' + } + } + + if ($isArray) + { + $IndentLevel++ + foreach ($item in $ComplexObject[$key]) + { + if ($ComplexObject.$key.GetType().FullName -like 'Microsoft.Graph.PowerShell.Models.*') + { + $item = Get-M365DSCDRGComplexTypeToHashtable -ComplexObject $item + } + $nestedPropertyString = Get-M365DSCDRGComplexTypeToString ` + -ComplexObject $item ` + -CIMInstanceName $hashPropertyType ` + -IndentLevel $IndentLevel ` + -ComplexTypeMapping $ComplexTypeMapping ` + -IsArray:$true + if ([string]::IsNullOrWhiteSpace($nestedPropertyString)) + { + $nestedPropertyString = "@()`r`n" + } + $currentProperty += $nestedPropertyString + } + $IndentLevel-- + } + else + { + $nestedPropertyString = Get-M365DSCDRGComplexTypeToString ` + -ComplexObject $hashProperty ` + -CIMInstanceName $hashPropertyType ` + -IndentLevel $IndentLevel ` + -ComplexTypeMapping $ComplexTypeMapping + if ([string]::IsNullOrWhiteSpace($nestedPropertyString)) + { + $nestedPropertyString = "`$null`r`n" + } + $currentProperty += $nestedPropertyString + } + if ($isArray) + { + if ($ComplexObject.$key.count -gt 0) + { + $currentProperty += $indent + $currentProperty += ')' + $currentProperty += "`r`n" + } + } + $isArray = $PSBoundParameters.IsArray + } + else + { + $currentProperty += Get-M365DSCDRGSimpleObjectTypeToString -Key $key -Value $ComplexObject[$key] -Space ($indent) + } + } + else + { + $mappedKey = $ComplexTypeMapping | Where-Object -FilterScript { $_.name -eq $key } + + if ($mappedKey -and $mappedKey.isRequired) + { + if ($mappedKey.isArray) + { + $currentProperty += "$indent$key = @()`r`n" + } + else + { + $currentProperty += "$indent$key = `$null`r`n" + } + } + } + } + $indent = '' + for ($i = 0; $i -lt $IndentLevel - 1 ; $i++) + { + $indent += ' ' + } + $currentProperty += "$indent}" + if ($isArray -or $IndentLevel -gt 4) + { + $currentProperty += "`r`n" + } + + #Indenting last parenthese when the cim instance is an array + if ($IndentLevel -eq 5) + { + $indent = '' + for ($i = 0; $i -lt $IndentLevel - 2 ; $i++) + { + $indent += ' ' + } + $currentProperty += $indent + } + + $emptyCIM = $currentProperty.replace(' ', '').replace("`r`n", '') + if ($emptyCIM -eq "MSFT_$CIMInstanceName{}") + { + $currentProperty = $null + } + return $currentProperty +} + +Function Get-M365DSCDRGSimpleObjectTypeToString +{ + [CmdletBinding()] + [OutputType([System.String])] + param( + [Parameter(Mandatory = 'true')] + [System.String] + $Key, + + [Parameter(Mandatory = 'true')] + $Value, + + [Parameter()] + [System.String] + $Space = ' ' + + ) + + $returnValue = '' + switch -Wildcard ($Value.GetType().Fullname ) + { + '*.Boolean' + { + $returnValue = $Space + $Key + " = `$" + $Value.ToString() + "`r`n" + } + '*.String' + { + if ($key -eq '@odata.type') + { + $key = 'odataType' + } + $returnValue = $Space + $Key + " = '" + $Value + "'`r`n" + } + '*.DateTime' + { + $returnValue = $Space + $Key + " = '" + $Value + "'`r`n" + } + '*[[\]]' + { + $returnValue = $Space + $key + ' = @(' + $whitespace = '' + $newline = '' + if ($Value.count -gt 1) + { + $returnValue += "`r`n" + $whitespace = $Space + ' ' + $newline = "`r`n" + } + foreach ($item in ($Value | Where-Object -FilterScript { $null -ne $_ })) + { + switch -Wildcard ($item.GetType().Fullname) + { + '*.String' + { + $returnValue += "$whitespace'$item'$newline" + } + '*.DateTime' + { + $returnValue += "$whitespace'$item'$newline" + } + Default + { + $returnValue += "$whitespace$item$newline" + } + } + } + if ($Value.count -gt 1) + { + $returnValue += "$Space)`r`n" + } + else + { + $returnValue += ")`r`n" + + } + } + Default + { + $returnValue = $Space + $Key + ' = ' + $Value + "`r`n" + } + } + return $returnValue +} + +function Compare-M365DSCComplexObject +{ + [CmdletBinding()] + [OutputType([System.Boolean])] + param( + [Parameter()] + $Source, + [Parameter()] + $Target + ) + + #Comparing full objects + if ($null -eq $Source -and $null -eq $Target) + { + return $true + } + + $sourceValue = '' + $targetValue = '' + if (($null -eq $Source) -xor ($null -eq $Target)) + { + if ($null -eq $Source) + { + $sourceValue = 'Source is null' + } + + if ($null -eq $Target) + { + $targetValue = 'Target is null' + } + Write-Verbose -Message "Configuration drift - Complex object: {$sourceValue$targetValue}" + return $false + } + + if ($Source.getType().FullName -like '*CimInstance[[\]]' -or $Source.getType().FullName -like '*Hashtable[[\]]') + { + if ($source.count -ne $target.count) + { + Write-Verbose -Message "Configuration drift - The complex array have different number of items: Source {$($source.count)} Target {$($target.count)}" + return $false + } + if ($source.count -eq 0) + { + return $true + } + + foreach ($item in $Source) + { + $hashSource = Get-M365DSCDRGComplexTypeToHashtable -ComplexObject $item + foreach ($targetItem in $Target) + { + $compareResult = Compare-M365DSCComplexObject ` + -Source $hashSource ` + -Target $targetItem + + if ($compareResult) + { + break + } + } + + if (-not $compareResult) + { + Write-Verbose -Message 'Configuration drift - The complex array items are not identical' + return $false + } + } + return $true + } + + $keys = $Source.Keys | Where-Object -FilterScript { $_ -ne 'PSComputerName' } + foreach ($key in $keys) + { + #Matching possible key names between Source and Target + $skey = $key + $tkey = $key + + $sourceValue = $Source.$key + $targetValue = $Target.$tkey + #One of the item is null and not the other + if (($null -eq $Source.$key) -xor ($null -eq $Target.$tkey)) + { + + if ($null -eq $Source.$key) + { + $sourceValue = 'null' + } + + if ($null -eq $Target.$tkey) + { + $targetValue = 'null' + } + + #Write-Verbose -Message "Configuration drift - key: $key Source {$sourceValue} Target {$targetValue}" + return $false + } + + #Both keys aren't null or empty + if (($null -ne $Source.$key) -and ($null -ne $Target.$tkey)) + { + if ($Source.$key.getType().FullName -like '*CimInstance*' -or $Source.$key.getType().FullName -like '*hashtable*') + { + #Recursive call for complex object + $compareResult = Compare-M365DSCComplexObject ` + -Source (Get-M365DSCDRGComplexTypeToHashtable -ComplexObject $Source.$key) ` + -Target $Target.$tkey + + if (-not $compareResult) + { + #Write-Verbose -Message "Configuration drift - complex object key: $key Source {$sourceValue} Target {$targetValue}" + return $false + } + } + else + { + #Simple object comparison + $referenceObject = $Target.$tkey + $differenceObject = $Source.$key + + #Identifying date from the current values + $targetType = ($Target.$tkey.getType()).Name + if ($targetType -like '*Date*') + { + $compareResult = $true + $sourceDate = [DateTime]$Source.$key + if ($sourceDate -ne $targetType) + { + $compareResult = $null + } + } + else + { + $compareResult = Compare-Object ` + -ReferenceObject ($referenceObject) ` + -DifferenceObject ($differenceObject) + } + + if ($null -ne $compareResult) + { + #Write-Verbose -Message "Configuration drift - simple object key: $key Source {$sourceValue} Target {$targetValue}" + return $false + } + } + } + } + return $true +} + +function Convert-M365DSCDRGComplexTypeToHashtable +{ + [CmdletBinding()] + [OutputType([hashtable], [hashtable[]])] + param( + [Parameter(Mandatory = 'true')] + $ComplexObject + ) + + if ($ComplexObject.getType().Fullname -like '*[[\]]') + { + $results = @() + foreach ($item in $ComplexObject) + { + $hash = Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject $item + $results += $hash + } + + #Write-Verbose -Message ("Convert-M365DSCDRGComplexTypeToHashtable >>> results: "+(convertTo-JSON $results -Depth 20)) + # PowerShell returns all non-captured stream output, not just the argument of the return statement. + #An empty array is mangled into $null in the process. + #However, an array can be preserved on return by prepending it with the array construction operator (,) + return , [hashtable[]]$results + } + $hashComplexObject = Get-M365DSCDRGComplexTypeToHashtable -ComplexObject $ComplexObject + + if ($null -ne $hashComplexObject) + { + $results = $hashComplexObject.clone() + $keys = $hashComplexObject.Keys | Where-Object -FilterScript { $_ -ne 'PSComputerName' } + foreach ($key in $keys) + { + if ($hashComplexObject[$key] -and $hashComplexObject[$key].getType().Fullname -like '*CimInstance*') + { + $results[$key] = Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject $hashComplexObject[$key] + } + else + { + $propertyName = $key[0].ToString().ToLower() + $key.Substring(1, $key.Length - 1) + $propertyValue = $results[$key] + $results.remove($key) | Out-Null + $results.add($propertyName, $propertyValue) + } + } + } + return [hashtable]$results +} + +Export-ModuleMember -Function *-TargetResource diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceConfigurationEditionUpgradePolicyWindows10/MSFT_IntuneDeviceConfigurationEditionUpgradePolicyWindows10.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceConfigurationEditionUpgradePolicyWindows10/MSFT_IntuneDeviceConfigurationEditionUpgradePolicyWindows10.schema.mof new file mode 100644 index 0000000000..8625ef37f3 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceConfigurationEditionUpgradePolicyWindows10/MSFT_IntuneDeviceConfigurationEditionUpgradePolicyWindows10.schema.mof @@ -0,0 +1,30 @@ +[ClassVersion("1.0.0.0")] +class MSFT_DeviceManagementConfigurationPolicyAssignments +{ + [Write, Description("The type of the target assignment."), ValueMap{"#microsoft.graph.groupAssignmentTarget","#microsoft.graph.allLicensedUsersAssignmentTarget","#microsoft.graph.allDevicesAssignmentTarget","#microsoft.graph.exclusionGroupAssignmentTarget","#microsoft.graph.configurationManagerCollectionAssignmentTarget"}, Values{"#microsoft.graph.groupAssignmentTarget","#microsoft.graph.allLicensedUsersAssignmentTarget","#microsoft.graph.allDevicesAssignmentTarget","#microsoft.graph.exclusionGroupAssignmentTarget","#microsoft.graph.configurationManagerCollectionAssignmentTarget"}] String dataType; + [Write, Description("The type of filter of the target assignment i.e. Exclude or Include. Possible values are:none, include, exclude."), ValueMap{"none","include","exclude"}, Values{"none","include","exclude"}] String deviceAndAppManagementAssignmentFilterType; + [Write, Description("The Id of the filter for the target assignment.")] String deviceAndAppManagementAssignmentFilterId; + [Write, Description("The group Id that is the target of the assignment.")] String groupId; + [Write, Description("The collection Id that is the target of the assignment.(ConfigMgr)")] String collectionId; +}; + +[ClassVersion("1.0.0.0"), FriendlyName("IntuneDeviceConfigurationEditionUpgradePolicyWindows10")] +class MSFT_IntuneDeviceConfigurationEditionUpgradePolicyWindows10 : OMI_BaseResource +{ + [Write, Description("Edition Upgrade License File Content.")] String License; + [Write, Description("Edition Upgrade License Type. Possible values are: productKey, licenseFile, notConfigured."), ValueMap{"productKey","licenseFile","notConfigured"}, Values{"productKey","licenseFile","notConfigured"}] String LicenseType; + [Write, Description("Edition Upgrade Product Key.")] String ProductKey; + [Write, Description("Edition Upgrade Target Edition. Possible values are: windows10Enterprise, windows10EnterpriseN, windows10Education, windows10EducationN, windows10MobileEnterprise, windows10HolographicEnterprise, windows10Professional, windows10ProfessionalN, windows10ProfessionalEducation, windows10ProfessionalEducationN, windows10ProfessionalWorkstation, windows10ProfessionalWorkstationN, notConfigured, windows10Home, windows10HomeChina, windows10HomeN, windows10HomeSingleLanguage, windows10Mobile, windows10IoTCore, windows10IoTCoreCommercial."), ValueMap{"windows10Enterprise","windows10EnterpriseN","windows10Education","windows10EducationN","windows10MobileEnterprise","windows10HolographicEnterprise","windows10Professional","windows10ProfessionalN","windows10ProfessionalEducation","windows10ProfessionalEducationN","windows10ProfessionalWorkstation","windows10ProfessionalWorkstationN","notConfigured","windows10Home","windows10HomeChina","windows10HomeN","windows10HomeSingleLanguage","windows10Mobile","windows10IoTCore","windows10IoTCoreCommercial"}, Values{"windows10Enterprise","windows10EnterpriseN","windows10Education","windows10EducationN","windows10MobileEnterprise","windows10HolographicEnterprise","windows10Professional","windows10ProfessionalN","windows10ProfessionalEducation","windows10ProfessionalEducationN","windows10ProfessionalWorkstation","windows10ProfessionalWorkstationN","notConfigured","windows10Home","windows10HomeChina","windows10HomeN","windows10HomeSingleLanguage","windows10Mobile","windows10IoTCore","windows10IoTCoreCommercial"}] String TargetEdition; + [Write, Description("S mode configuration. Possible values are: noRestriction, block, unlock."), ValueMap{"noRestriction","block","unlock"}, Values{"noRestriction","block","unlock"}] String WindowsSMode; + [Write, Description("Admin provided description of the Device Configuration.")] String Description; + [Required, Description("Admin provided name of the device configuration.")] String DisplayName; + [Key, Description("The unique identifier for an entity. Read-only.")] String Id; + [Write, Description("Represents the assignment to the Intune policy."), EmbeddedInstance("MSFT_DeviceManagementConfigurationPolicyAssignments")] String Assignments[]; + [Write, Description("Present ensures the policy exists, absent ensures it is removed."), ValueMap{"Present","Absent"}, Values{"Present","Absent"}] string Ensure; + [Write, Description("Credentials of the Admin"), EmbeddedInstance("MSFT_Credential")] string Credential; + [Write, Description("Id of the Azure Active Directory application to authenticate with.")] String ApplicationId; + [Write, Description("Id of the Azure Active Directory tenant used for authentication.")] String TenantId; + [Write, Description("Secret of the Azure Active Directory tenant used for authentication."), EmbeddedInstance("MSFT_Credential")] String ApplicationSecret; + [Write, Description("Thumbprint of the Azure Active Directory application's authentication certificate to use for authentication.")] String CertificateThumbprint; + [Write, Description("Managed ID being used for authentication.")] Boolean ManagedIdentity; +}; diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceConfigurationEditionUpgradePolicyWindows10/readme.md b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceConfigurationEditionUpgradePolicyWindows10/readme.md new file mode 100644 index 0000000000..1d435cab08 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceConfigurationEditionUpgradePolicyWindows10/readme.md @@ -0,0 +1,6 @@ + +# IntuneDeviceConfigurationEditionUpgradePolicyWindows10 + +## Description + +Intune Device Configuration Edition Upgrade Policy for Windows10 diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceConfigurationEditionUpgradePolicyWindows10/settings.json b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceConfigurationEditionUpgradePolicyWindows10/settings.json new file mode 100644 index 0000000000..a50cca3eeb --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceConfigurationEditionUpgradePolicyWindows10/settings.json @@ -0,0 +1,33 @@ +{ + "resourceName": "IntuneDeviceConfigurationEditionUpgradePolicyWindows10", + "description": "This resource configures an Intune Device Configuration Edition Upgrade Policy for Windows10.", + "permissions": { + "graph": { + "delegated": { + "read": [ + { + "name": "DeviceManagementConfiguration.Read.All" + } + ], + "update": [ + { + "name": "DeviceManagementConfiguration.ReadWrite.All" + } + ] + }, + "application": { + "read": [ + { + "name": "DeviceManagementConfiguration.Read.All" + } + ], + "update": [ + { + "name": "DeviceManagementConfiguration.ReadWrite.All" + } + ] + } + } +} + +} diff --git a/Modules/Microsoft365DSC/Examples/Resources/IntuneDeviceConfigurationEditionUpgradePolicyWindows10/1-IntuneDeviceConfigurationEditionUpgradePolicyWindows10-Example.ps1 b/Modules/Microsoft365DSC/Examples/Resources/IntuneDeviceConfigurationEditionUpgradePolicyWindows10/1-IntuneDeviceConfigurationEditionUpgradePolicyWindows10-Example.ps1 new file mode 100644 index 0000000000..bbc487de64 --- /dev/null +++ b/Modules/Microsoft365DSC/Examples/Resources/IntuneDeviceConfigurationEditionUpgradePolicyWindows10/1-IntuneDeviceConfigurationEditionUpgradePolicyWindows10-Example.ps1 @@ -0,0 +1,37 @@ +<# +This example is used to test new resources and showcase the usage of new resources being worked on. +It is not meant to use as a production baseline. +#> + +Configuration Example +{ + param( + [Parameter(Mandatory = $true)] + [PSCredential] + $Credscredential + ) + Import-DscResource -ModuleName Microsoft365DSC + + node localhost + { + IntuneDeviceConfigurationEditionUpgradePolicyWindows10 'Example' + { + Assignments = @( + MSFT_DeviceManagementConfigurationPolicyAssignments{ + deviceAndAppManagementAssignmentFilterType = 'none' + dataType = '#microsoft.graph.allDevicesAssignmentTarget' + } + ); + Credential = $Credscredential; + Description = ""; + DisplayName = "Edition upgrade and mode switch - update"; + Ensure = "Present"; + Id = "3e4222e0-c172-4081-bf9a-2e17ddfc34ca"; + License = ""; + LicenseType = "productKey"; + ProductKey = "#####-#####-#####-#####-#2345"; + TargetEdition = "windows10Professional"; + WindowsSMode = "block"; + } + } +} diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneDeviceConfigurationEditionUpgradePolicyWindows10.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneDeviceConfigurationEditionUpgradePolicyWindows10.Tests.ps1 new file mode 100644 index 0000000000..f360fb173a --- /dev/null +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneDeviceConfigurationEditionUpgradePolicyWindows10.Tests.ps1 @@ -0,0 +1,253 @@ +[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 "IntuneDeviceConfigurationEditionUpgradePolicyWindows10" -GenericStubModule $GenericStubPath +Describe -Name $Global:DscHelper.DescribeHeader -Fixture { + InModuleScope -ModuleName $Global:DscHelper.ModuleName -ScriptBlock { + Invoke-Command -ScriptBlock $Global:DscHelper.InitializeScript -NoNewScope + BeforeAll { + + $secpasswd = ConvertTo-SecureString "f@kepassword1" -AsPlainText -Force + $Credential = New-Object System.Management.Automation.PSCredential ('tenantadmin@mydomain.com', $secpasswd) + + Mock -CommandName Confirm-M365DSCDependencies -MockWith { + } + + Mock -CommandName Get-PSSession -MockWith { + } + + Mock -CommandName Remove-PSSession -MockWith { + } + + Mock -CommandName Update-MgDeviceManagementDeviceConfiguration -MockWith { + } + + Mock -CommandName New-MgDeviceManagementDeviceConfiguration -MockWith { + } + + Mock -CommandName Remove-MgDeviceManagementDeviceConfiguration -MockWith { + } + + Mock -CommandName New-M365DSCConnection -MockWith { + return "Credentials" + } + + # Mock Write-Host to hide output during the tests + Mock -CommandName Write-Host -MockWith { + } + + Mock -CommandName Get-MgDeviceManagementDeviceConfigurationAssignment -MockWith { + } + + } + # Test contexts + Context -Name "The IntuneDeviceConfigurationEditionUpgradePolicyWindows10 should exist but it DOES NOT" -Fixture { + BeforeAll { + $testParams = @{ + Description = "FakeStringValue" + DisplayName = "FakeStringValue" + Id = "FakeStringValue" + License = "FakeStringValue" + LicenseType = "productKey" + ProductKey = "FakeStringValue" + TargetEdition = "windows10Enterprise" + WindowsSMode = "noRestriction" + Ensure = "Present" + Credential = $Credential; + } + + Mock -CommandName Get-MgDeviceManagementDeviceConfiguration -MockWith { + return $null + } + } + It 'Should return Values from the Get method' { + (Get-TargetResource @testParams).Ensure | Should -Be 'Absent' + } + It 'Should return false from the Test method' { + Test-TargetResource @testParams | Should -Be $false + } + It 'Should Create the group from the Set method' { + Set-TargetResource @testParams + Should -Invoke -CommandName New-MgDeviceManagementDeviceConfiguration -Exactly 1 + } + } + + Context -Name "The IntuneDeviceConfigurationEditionUpgradePolicyWindows10 exists but it SHOULD NOT" -Fixture { + BeforeAll { + $testParams = @{ + Description = "FakeStringValue" + DisplayName = "FakeStringValue" + Id = "FakeStringValue" + License = "FakeStringValue" + LicenseType = "productKey" + ProductKey = "FakeStringValue" + TargetEdition = "windows10Enterprise" + WindowsSMode = "noRestriction" + Ensure = 'Absent' + Credential = $Credential; + } + + Mock -CommandName Get-MgDeviceManagementDeviceConfiguration -MockWith { + return @{ + AdditionalProperties = @{ + windowsSMode = "noRestriction" + '@odata.type' = "#microsoft.graph.editionUpgradeConfiguration" + productKey = "FakeStringValue" + targetEdition = "windows10Enterprise" + license = "FakeStringValue" + licenseType = "productKey" + } + Description = "FakeStringValue" + DisplayName = "FakeStringValue" + Id = "FakeStringValue" + + } + } + } + + It 'Should return Values from the Get method' { + (Get-TargetResource @testParams).Ensure | Should -Be 'Present' + } + + It 'Should return true from the Test method' { + Test-TargetResource @testParams | Should -Be $false + } + + It 'Should Remove the group from the Set method' { + Set-TargetResource @testParams + Should -Invoke -CommandName Remove-MgDeviceManagementDeviceConfiguration -Exactly 1 + } + } + Context -Name "The IntuneDeviceConfigurationEditionUpgradePolicyWindows10 Exists and Values are already in the desired state" -Fixture { + BeforeAll { + $testParams = @{ + Description = "FakeStringValue" + DisplayName = "FakeStringValue" + Id = "FakeStringValue" + License = "FakeStringValue" + LicenseType = "productKey" + ProductKey = "FakeStringValue" + TargetEdition = "windows10Enterprise" + WindowsSMode = "noRestriction" + Ensure = 'Present' + Credential = $Credential; + } + + Mock -CommandName Get-MgDeviceManagementDeviceConfiguration -MockWith { + return @{ + AdditionalProperties = @{ + windowsSMode = "noRestriction" + '@odata.type' = "#microsoft.graph.editionUpgradeConfiguration" + productKey = "FakeStringValue" + targetEdition = "windows10Enterprise" + license = "FakeStringValue" + licenseType = "productKey" + } + Description = "FakeStringValue" + DisplayName = "FakeStringValue" + Id = "FakeStringValue" + + } + } + } + + + It 'Should return true from the Test method' { + Test-TargetResource @testParams | Should -Be $true + } + } + + Context -Name "The IntuneDeviceConfigurationEditionUpgradePolicyWindows10 exists and values are NOT in the desired state" -Fixture { + BeforeAll { + $testParams = @{ + Description = "FakeStringValue" + DisplayName = "FakeStringValue" + Id = "FakeStringValue" + License = "FakeStringValue" + LicenseType = "productKey" + ProductKey = "FakeStringValue" + TargetEdition = "windows10Enterprise" + WindowsSMode = "noRestriction" + Ensure = 'Present' + Credential = $Credential; + } + + Mock -CommandName Get-MgDeviceManagementDeviceConfiguration -MockWith { + return @{ + AdditionalProperties = @{ + windowsSMode = "noRestriction" + '@odata.type' = "#microsoft.graph.editionUpgradeConfiguration" + productKey = "12345-12345-12345-12345-12345" + targetEdition = "windows10Enterprise" + license = "FakeStringValue" + licenseType = "productKey" + } + Description = "FakeStringValue" + DisplayName = "FakeStringValue" + Id = "FakeStringValue" + } + } + } + + It 'Should return Values from the Get method' { + (Get-TargetResource @testParams).Ensure | Should -Be 'Present' + } + + It 'Should return false from the Test method' { + Test-TargetResource @testParams | Should -Be $false + } + + It 'Should call the Set method' { + Set-TargetResource @testParams + Should -Invoke -CommandName Update-MgDeviceManagementDeviceConfiguration -Exactly 1 + } + } + + Context -Name 'ReverseDSC Tests' -Fixture { + BeforeAll { + $Global:CurrentModeIsExport = $true + $Global:PartialExportFileName = "$(New-Guid).partial.ps1" + $testParams = @{ + Credential = $Credential + } + + Mock -CommandName Get-MgDeviceManagementDeviceConfiguration -MockWith { + return @{ + AdditionalProperties = @{ + windowsSMode = "noRestriction" + '@odata.type' = "#microsoft.graph.editionUpgradeConfiguration" + productKey = "FakeStringValue" + targetEdition = "windows10Enterprise" + license = "FakeStringValue" + licenseType = "productKey" + } + Description = "FakeStringValue" + DisplayName = "FakeStringValue" + Id = "FakeStringValue" + + } + } + } + It 'Should Reverse Engineer resource from the Export method' { + $result = Export-TargetResource @testParams + $result | Should -Not -BeNullOrEmpty + } + } + } +} + +Invoke-Command -ScriptBlock $Global:DscHelper.CleanupScript -NoNewScope From 6ef29dbf66209e172f677a162dc0fd65553269b8 Mon Sep 17 00:00:00 2001 From: William-francillette Date: Sun, 30 Apr 2023 12:47:58 +0100 Subject: [PATCH 2/2] changelog --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f12f59262f..ca8cf5786b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Change log for Microsoft365DSC +# UNRELEASED + + * IntuneDeviceConfigurationEditionUpgradePolicyWindows10 + * Initial release + # 1.23.426.3 * DEPENDENCIES