diff --git a/CHANGELOG.md b/CHANGELOG.md index 8907bc9..8cd0497 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,8 @@ version of DSCResource.Common - Added CMClientSettingsComputerRestart resource +- Added CMHierarchySetting resource + ## [3.0.0] - 2022-01-03 ### Added diff --git a/README.md b/README.md index ffa3284..3705be3 100644 --- a/README.md +++ b/README.md @@ -175,6 +175,7 @@ Please check out common DSC Community [contributing guidelines](https://dsccommu client policy settings for User Device Affinity settings. - **CMSiteConfiguration**: Provides a resource for modifying the site settings. +- **CMHierarchySetting**: Provides a resource to modify hierarchy settings for a site. ### xSccmPreReqs @@ -2201,6 +2202,32 @@ you are using apply and auto correct. - [CMSiteConfiguration_Cas](Source\Examples\Resources\CMSiteConfiguration\CMSiteConfiguration_Cas.ps1) - [CMSiteConfiguration_Primary](Source\Examples\Resources\CMSiteConfiguration\CMSiteConfiguration_Primary.ps1) +### CMHierarchySetting + +- **[string] SiteCode** _(Key)_: Specifies the SiteCode for the Configuration Manager site. +- **[boolean] AllowPrestage** _(Write)_: Indicates that prestaging should be allowed. +- **[string] ApprovalMethod** _(Write)_: Approval method to use. + - Values include: {ManuallyApproveEachComputer | AutomaticallyApproveComputersInTrustedDomains | AutomaticallyApproveAllComputers} +- **[boolean] AutoResolveClientConflict** _(Write)_: Indicates that client conflicts should automatically be resolved. +- **[boolean] EnableAutoClientUpgrade** _(Write)_: Indicates that automatic client upgrades should be enabled. +- **[boolean] EnableExclusionCollection** _(Write)_: Indicates that an exclusion collection should be enabled. Requires use of ExclusionCollectionName parameter. +- **[boolean] EnablePreProduction** _(Write)_: Indicates that a preproduction collection should be enabled. Requires use of TargetCollectionName parameter. +- **[boolean] EnablePrereleaseFeature** _(Write)_: Indicates that pre-release features should be enabled. This is an operation that cannot be reverted. +- **[boolean] ExcludeServer** _(Write)_: Indicates that servers are excluded from auto upgrade. Skipped if EnableAutoClientUpgrade is not used. +- **[boolean] PreferBoundaryGroupManagementPoint** _(Write)_: Indicates that the boundary group management point should be preferred. +- **[boolean] UseFallbackSite** _(Write)_: Indicates that fallback site should be used. Requires use of FallbackSiteCode parameter. +- **[type] AutoUpgradeDays** _(Write)_: Days for Auto Upgrade advertisement. +- **[string] ExclusionCollectionName** _(Write)_: Exclusion collection name. Requires use of EnableExclusionCollection parameter. +- **[string] FallbackSiteCode** _(Write)_: Site code of fallback site. Requires use of UseFallbackSite parameter. +- **[string] TargetCollectionName** _(Write)_: Target preproduction collection name. Requires use of EnablePreProduction parameter. +- **[string] TelemetryLevel** _(Write)_: Level of telemetry to send. + - Values include: { Basic | Enhanced | Full } + +### CMHierarchySetting Examples + +- [CMHierarchySettingAutoUpgrade](source\Examples\Resources\CMHierarchySetting\CMHierarchySettingAutoUpgrade.ps1) +- [CMHierarchySettingFallbackSite](source\Examples\Resources\CMHierarchySetting\CMHierarchySettingFallbackSite.ps1) + ## ReverseDsc Most organizations using this module already have an existing Configuration Manager @@ -2279,6 +2306,7 @@ all of the modules and specify if it is currently supported by ReverseDSC. - DSC_CMForestDiscovery: Fully Supported - DSC_CMGroupDiscovery: Fully Supported - DSC_CMHeartbeatDiscovery: Fully Supported +- DSC_CMHierarchySetting: Fully Supported - DSC_CMIniFile: Not Supported - DSC_CMMaintenanceWindows: Fully Supported - DSC_CMManagementPoint: Fully Supported diff --git a/source/DSCResources/DSC_CMHierarchySetting/DSC_CMHierarchySetting.psm1 b/source/DSCResources/DSC_CMHierarchySetting/DSC_CMHierarchySetting.psm1 new file mode 100644 index 0000000..6bcad81 --- /dev/null +++ b/source/DSCResources/DSC_CMHierarchySetting/DSC_CMHierarchySetting.psm1 @@ -0,0 +1,358 @@ +$script:dscResourceCommonPath = Join-Path -Path $PSScriptRoot -ChildPath '..\..\Modules\DscResource.Common' +$script:configMgrResourcehelper = Join-Path -Path $PSScriptRoot -ChildPath '..\..\Modules\ConfigMgrCBDsc.ResourceHelper' + +Import-Module -Name $script:dscResourceCommonPath +Import-Module -Name $script:configMgrResourcehelper + +$script:localizedData = Get-LocalizedData -DefaultUICulture 'en-US' + +<# + .SYNOPSIS + This will return a hashtable of results. + + .PARAMETER SiteCode + Specifies the site code for Configuration Manager site. +#> +function Get-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + param + ( + [Parameter(Mandatory = $true)] + [String] + $SiteCode + ) + + Write-Verbose -Message $script:localizedData.RetrieveSettingValue + Import-ConfigMgrPowerShellModule -SiteCode $SiteCode + Set-Location -Path "$($SiteCode):\" + + $currentSetting = Get-CMHierarchySetting + $preprodSetting = $currentSetting | Where-Object PropertyNames -contains TargetCollectionID + $upgradeSetting = $currentSetting | Where-Object PropertyNames -contains AdvertisementDuration + $allProperties = Get-CimInstance -Namespace "ROOT\SMS\Site_$SiteCode" -ClassName SMS_SCI_SCProperty + [string] $excludeCollectionId = $upgradeSetting.ExcludedCollectionID + [string] $targetCollectionId = $preprodSetting.TargetCollectionID + + if (-not [string]::IsNullOrWhiteSpace($excludeCollectionId)) + { + $excludeCollectionName = (Get-CMCollection -Id $excludeCollectionId -ErrorAction SilentlyContinue).Name + } + + if (-not [string]::IsNullOrWhiteSpace($targetCollectionId)) + { + $targetCollectionName = (Get-CMCollection -Id $targetCollectionId -ErrorAction SilentlyContinue).Name + } + + return @{ + SiteCode = $SiteCode + AllowPrestage = $upgradeSetting.AllowPrestage + ApprovalMethod = @("ManuallyApproveEachComputer", "AutomaticallyApproveComputersInTrustedDomains", "AutomaticallyApproveAllComputers")[$allProperties.Where({ $_.PropertyName -eq 'Auto Approval' }).Value] + AutoResolveClientConflict = -not ($allProperties.Where({ $_.PropertyName -eq 'Registration HardwareID Conflict Resolution' }).Value -as [bool]) + EnableAutoClientUpgrade = $upgradeSetting.IsProgramEnabled + EnableExclusionCollection = $upgradeSetting.IsUpgradeExclusionEnabled + EnablePreProduction = $preprodSetting.IsAccepted -and $preprodSetting.IsEnabled + EnablePrereleaseFeature = $allProperties.Where({ $_.PropertyName -eq 'AcceptedBeta' }).Value -as [bool] + ExcludeServer = $upgradeSetting.ExcludeServers + PreferBoundaryGroupManagementPoint = $allProperties.Where({ $_.PropertyName -eq 'PreferMPInBoundaryWithFastNetwork' }).Value -as [bool] + UseFallbackSite = -not [string]::IsNullOrWhiteSpace($allProperties.Where({ $_.PropertyName -eq 'SiteAssignmentSiteCode' }).Value1) + AutoUpgradeDays = $upgradeSetting.AdvertisementDuration + ExclusionCollectionName = $excludeCollectionName + FallbackSiteCode = $allProperties.Where({ $_.PropertyName -eq 'SiteAssignmentSiteCode' }).Value1 + TargetCollectionName = $targetCollectionName + TelemetryLevel = @("Basic", "Enhanced", "Full")[$allProperties.Where({ $_.PropertyName -eq 'TelemetryLevel' }).Value - 1] + } +} + +<# + .SYNOPSIS + This will set the desired state. + + .PARAMETER SiteCode + Specifies the site code for Configuration Manager site. + .PARAMETER AllowPrestage + Indicates that prestaging should be allowed. + .PARAMETER ApprovalMethod + Approval method to use. + .PARAMETER AutoResolveClientConflict + Indicates that client conflicts should automatically be resolved. + .PARAMETER EnableAutoClientUpgrade + Indicates that automatic client upgrades should be enabled. + .PARAMETER EnableExclusionCollection + Indicates that an exclusion collection should be enabled. + .PARAMETER EnablePreProduction + Indicates that a preproduction collection should be enabled. + .PARAMETER EnablePrereleaseFeature + Indicates that pre-release features should be enabled. + .PARAMETER ExcludeServer + Indicates that servers are excluded from auto upgrade. + .PARAMETER PreferBoundaryGroupManagementPoint + Indicates that the boundary group management point should be preferred. + .PARAMETER UseFallbackSite + Indicates that fallback site should be used, which needs to be added using the FallbackSiteCode property. + .PARAMETER AutoUpgradeDays + Days interval for Auto Upgrade. + .PARAMETER ExclusionCollectionName + Exclusion collection name. + .PARAMETER FallbackSiteCode + Site code of fallback site. + .PARAMETER TargetCollectionName + Target collection name. + .PARAMETER TelemetryLevel + Level of telemetry to send. +#> +function Set-TargetResource +{ + [CmdletBinding()] + param + ( + [Parameter(Mandatory = $true)] + [String] + $SiteCode, + + [Parameter()] + [bool] + $AllowPrestage, + + [Parameter()] + [ValidateSet( "ManuallyApproveEachComputer", "AutomaticallyApproveComputersInTrustedDomains", "AutomaticallyApproveAllComputers")] + [string] + $ApprovalMethod, + + [Parameter()] + [bool] + $AutoResolveClientConflict, + + [Parameter()] + [bool] + $EnableAutoClientUpgrade, + + [Parameter()] + [bool] + $EnableExclusionCollection, + + [Parameter()] + [bool] + $EnablePreProduction, + + [Parameter()] + [bool] + $EnablePrereleaseFeature, + + [Parameter()] + [bool] + $ExcludeServer, + + [Parameter()] + [bool] + $PreferBoundaryGroupManagementPoint, + + [Parameter()] + [bool] + $UseFallbackSite, + + [Parameter()] + [uint32] + $AutoUpgradeDays, + + [Parameter()] + [string] + $ExclusionCollectionName, + + [Parameter()] + [string] + $FallbackSiteCode, + + [Parameter()] + [string] + $TargetCollectionName, + + [Parameter()] + [ValidateSet("Basic", "Enhanced", "Full")] + [string] + $TelemetryLevel + ) + + Import-ConfigMgrPowerShellModule -SiteCode $SiteCode + Set-Location -Path "$($SiteCode):\" + $PSBoundParameters.Remove('SiteCode') + + try + { + if ($UseFallbackSite -xor -not [string]::IsNullOrWhiteSpace($FallbackSiteCode)) + { + throw ($script:localizedData.SettingPairMismatch -f 'UseFallbackSite', 'FallbackSiteCode') + } + + if ($EnablePreProduction -xor -not [string]::IsNullOrWhiteSpace( $TargetCollectionName)) + { + throw ($script:localizedData.SettingPairMismatch -f 'EnablePreProduction', 'TargetCollectionName') + } + + if ($EnableExclusionCollection -xor -not [string]::IsNullOrWhiteSpace($ExclusionCollectionName)) + { + throw ($script:localizedData.SettingPairMismatch -f 'EnableExclusionCollection', 'ExclusionCollectionName') + } + + if ($ExcludeServer -and -not $EnableAutoClientUpgrade) + { + $PSBoundParameters.Remove('ExcludeServer') + Write-Verbose -Message ($script:localizedData.IgnoreAutoUpgrade -f 'ExcludeServer') + } + + if ($AutoUpgradeDays -gt 0 -and -not $EnableAutoClientUpgrade) + { + $PSBoundParameters.Remove('AutoUpgradeDays') + Write-Verbose -Message ($script:localizedData.IgnoreAutoUpgrade -f 'AutoUpgradeDays') + } + + Set-CMHierarchySetting @PSBoundParameters + } + catch + { + throw $_ + } + finally + { + Set-Location -Path "$env:temp" + } +} + +<# + .SYNOPSIS + This will test the desired state. + + .PARAMETER SiteCode + Specifies the site code for Configuration Manager site. + .PARAMETER AllowPrestage + Indicates that prestaging should be allowed. + .PARAMETER ApprovalMethod + Approval method to use. + .PARAMETER AutoResolveClientConflict + Indicates that client conflicts should automatically be resolved. + .PARAMETER EnableAutoClientUpgrade + Indicates that automatic client upgrades should be enabled. + .PARAMETER EnableExclusionCollection + Indicates that an exclusion collection should be enabled. + .PARAMETER EnablePreProduction + Indicates that a preproduction collection should be enabled. + .PARAMETER EnablePrereleaseFeature + Indicates that pre-release features should be enabled. + .PARAMETER ExcludeServer + Indicates that servers are excluded from auto upgrade. + .PARAMETER PreferBoundaryGroupManagementPoint + Indicates that the boundary group management point should be preferred. + .PARAMETER UseFallbackSite + Indicates that fallback site should be used, which needs to be added using the FallbackSiteCode property. + .PARAMETER AutoUpgradeDays + Days interval for Auto Upgrade. + .PARAMETER ExclusionCollectionName + Exclusion collection name. + .PARAMETER FallbackSiteCode + Site code of fallback site. + .PARAMETER TargetCollectionName + Target collection name. + .PARAMETER TelemetryLevel + Level of telemetry to send. +#> +function Test-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Boolean])] + param + ( + [Parameter(Mandatory = $true)] + [String] + $SiteCode, + + [Parameter()] + [bool] + $AllowPrestage, + + [Parameter()] + [ValidateSet( "ManuallyApproveEachComputer", "AutomaticallyApproveComputersInTrustedDomains", "AutomaticallyApproveAllComputers")] + [string] + $ApprovalMethod, + + [Parameter()] + [bool] + $AutoResolveClientConflict, + + [Parameter()] + [bool] + $EnableAutoClientUpgrade, + + [Parameter()] + [bool] + $EnableExclusionCollection, + + [Parameter()] + [bool] + $EnablePreProduction, + + [Parameter()] + [bool] + $EnablePrereleaseFeature, + + [Parameter()] + [bool] + $ExcludeServer, + + [Parameter()] + [bool] + $PreferBoundaryGroupManagementPoint, + + [Parameter()] + [bool] + $UseFallbackSite, + + [Parameter()] + [uint32] + $AutoUpgradeDays, + + [Parameter()] + [string] + $ExclusionCollectionName, + + [Parameter()] + [string] + $FallbackSiteCode, + + [Parameter()] + [string] + $TargetCollectionName, + + [Parameter()] + [ValidateSet("Basic", "Enhanced", "Full")] + [string] + $TelemetryLevel + ) + + Import-ConfigMgrPowerShellModule -SiteCode $SiteCode + Set-Location -Path "$($SiteCode):\" + $state = Get-TargetResource -SiteCode $SiteCode + $eval = 'AllowPrestage', 'ApprovalMethod', 'AutoResolveClientConflict', 'EnableAutoClientUpgrade', 'EnableExclusionCollection', 'EnablePreProduction', 'EnablePrereleaseFeature', 'ExcludeServer', 'PreferBoundaryGroupManagementPoint', 'UseFallbackSite', 'AutoUpgradeDays', 'ExclusionCollectionName', 'FallbackSiteCode', 'TargetCollectionName', 'TelemetryLevel' + $result = $true + + foreach ($property in $PSBoundParameters.GetEnumerator()) + { + if ($eval -notcontains $property.Key) + { + continue + } + + if ($property.Value -ne $state[$property.Key]) + { + Write-Verbose -Message ($script:localizedData.TestSetting ` + -f $property.Key, $property.Value, $state[$property.key]) + $result = $false + } + } + + Write-Verbose -Message ($script:localizedData.TestState -f $result) + return $result +} + +Export-ModuleMember -Function *-TargetResource + diff --git a/source/DSCResources/DSC_CMHierarchySetting/DSC_CMHierarchySetting.schema.mof b/source/DSCResources/DSC_CMHierarchySetting/DSC_CMHierarchySetting.schema.mof new file mode 100644 index 0000000..e424a82 --- /dev/null +++ b/source/DSCResources/DSC_CMHierarchySetting/DSC_CMHierarchySetting.schema.mof @@ -0,0 +1,21 @@ +[ClassVersion("1.0.0.0"), FriendlyName("CMHierarchySetting")] +class DSC_CMHierarchySetting : OMI_BaseResource +{ + [Key, Description("Specifies the SiteCode for the Configuration Manager site.")] String SiteCode; + [Write, Description("Indicates that prestaging should be allowed.")] Boolean AllowPrestage; + [Write, Description("Approval method to use."), ValueMap{"AutomaticallyApproveComputersInTrustedDomains","ManuallyApproveEachComputer","AutomaticallyApproveAllComputers"}, Values{"AutomaticallyApproveComputersInTrustedDomains","ManuallyApproveEachComputer","AutomaticallyApproveAllComputers"}] String ApprovalMethod; + [Write, Description("Indicates that client conflicts should automatically be resolved.")] Boolean AutoResolveClientConflict; + [Write, Description("Indicates that automatic client upgrades should be enabled.")] Boolean EnableAutoClientUpgrade; + [Write, Description("Indicates that an exclusion collection should be enabled. Requires use of ExclusionCollectionName parameter.")] Boolean EnableExclusionCollection; + [Write, Description("Indicates that a preproduction collection should be enabled. Requires use of TargetCollectionName parameter.")] Boolean EnablePreProduction; + [Write, Description("Indicates that pre-release features should be enabled. This is an operation that cannot be reverted.")] Boolean EnablePrereleaseFeature; + [Write, Description("Indicates that servers are excluded from auto upgrade. Skipped if EnableAutoClientUpgrade is not used.")] Boolean ExcludeServer; + [Write, Description("Indicates that the boundary group management point should be preferred.")] Boolean PreferBoundaryGroupManagementPoint; + [Write, Description("Indicates that fallback site should be used. Requires use of FallbackSiteCode parameter.")] Boolean UseFallbackSite; + [Write, Description("Days for Auto-Upgrade advertisement")] Uint32 AutoUpgradeDays; + [Write, Description("Exclusion collection name. Requires use of EnableExclusionCollection parameter.")] String ExclusionCollectionName; + [Write, Description("Site code of fallback site. Requires use of UseFallbackSite parameter.")] String FallbackSiteCode; + [Write, Description("Target preproduction collection name. Requires use of EnablePreProduction parameter.")] String TargetCollectionName; + [Write, Description("Level of telemetry to send."), ValueMap{"Basic","Enhanced","Full"}, Values{"Basic","Enhanced","Full"}] String TelemetryLevel; +}; + diff --git a/source/DSCResources/DSC_CMHierarchySetting/en-US/DSC_CMHierarchySetting.strings.psd1 b/source/DSCResources/DSC_CMHierarchySetting/en-US/DSC_CMHierarchySetting.strings.psd1 new file mode 100644 index 0000000..6bd115c --- /dev/null +++ b/source/DSCResources/DSC_CMHierarchySetting/en-US/DSC_CMHierarchySetting.strings.psd1 @@ -0,0 +1,7 @@ +ConvertFrom-StringData @' +RetrieveSettingValue = Getting current hierarchy settings. +TestState = Testing current resource state. In desired state: {0}. +TestSetting = {0} expected value: {1} returned {2}. +SettingPairMismatch = If {0} or {1} are used, both properties need to be specified. +IgnoreAutoUpgrade = {0} is configured, but client auto upgrade is not configured. Skipping setting. +'@ diff --git a/source/Examples/Resources/CMHierarchySetting/CMHierarchySettingAutoUpgrade.ps1 b/source/Examples/Resources/CMHierarchySetting/CMHierarchySettingAutoUpgrade.ps1 new file mode 100644 index 0000000..04c2e6c --- /dev/null +++ b/source/Examples/Resources/CMHierarchySetting/CMHierarchySettingAutoUpgrade.ps1 @@ -0,0 +1,22 @@ +<# + .SYNOPSIS + A DSC configuration script to enable automatic client upgrade while + excluding servers and all machines in the collection called 'NoAutoUpgrade'. +#> +Configuration Example +{ + Import-DscResource -ModuleName ConfigMgrCBDsc + + Node localhost + { + CMHierarchySetting ExampleSettings + { + SiteCode = 'Lab' + EnableAutoClientUpgrade = $true + EnableExclusionCollection = $true + ExcludeServer = $true + ExclusionCollectionName = 'NoAutoUpgrade' + AutoUpgradeDays = 7 + } + } +} diff --git a/source/Examples/Resources/CMHierarchySetting/CMHierarchySettingFallbackSite.ps1 b/source/Examples/Resources/CMHierarchySetting/CMHierarchySettingFallbackSite.ps1 new file mode 100644 index 0000000..9142ab2 --- /dev/null +++ b/source/Examples/Resources/CMHierarchySetting/CMHierarchySettingFallbackSite.ps1 @@ -0,0 +1,18 @@ +<# + .SYNOPSIS + A DSC configuration script to enable usage of a fallback site called FB1. +#> +Configuration Example +{ + Import-DscResource -ModuleName ConfigMgrCBDsc + + Node localhost + { + CMHierarchySetting ExampleSettings + { + SiteCode = 'Lab' + UseFallbackSite = $true + FallbackSiteCode = 'FB1' + } + } +} diff --git a/source/Modules/ConfigMgrCBDsc.ReverseDsc/ConfigMgrCBDsc.ReverseDsc.psm1 b/source/Modules/ConfigMgrCBDsc.ReverseDsc/ConfigMgrCBDsc.ReverseDsc.psm1 index b240ddd..74cca4c 100644 --- a/source/Modules/ConfigMgrCBDsc.ReverseDsc/ConfigMgrCBDsc.ReverseDsc.psm1 +++ b/source/Modules/ConfigMgrCBDsc.ReverseDsc/ConfigMgrCBDsc.ReverseDsc.psm1 @@ -4906,6 +4906,29 @@ Configuration ConfigureSccm } } + if (`$CMHierarchySetting) + { + CMHierarchySetting `$SiteCode + { + SiteCode = `$SiteCode + AllowPrestage = `$CMHierarchySetting.AllowPrestage + ApprovalMethod = `$CMHierarchySetting.ApprovalMethod + AutoResolveClientConflict = `$CMHierarchySetting.AutoResolveClientConflict + EnableAutoClientUpgrade = `$CMHierarchySetting.EnableAutoClientUpgrade + EnableExclusionCollection = `$CMHierarchySetting.EnableExclusionCollection + EnablePreProduction = `$CMHierarchySetting.EnablePreProduction + EnablePrereleaseFeature = `$CMHierarchySetting.EnablePrereleaseFeature + ExcludeServer = `$CMHierarchySetting.ExcludeServer + PreferBoundaryGroupManagementPoint = `$CMHierarchySetting.PreferBoundaryGroupManagementPoint + UseFallbackSite = `$CMHierarchySetting.UseFallbackSite + AutoUpgradeDays = `$CMHierarchySetting.AutoUpgradeDays + ExclusionCollectionName = `$CMHierarchySetting.ExclusionCollectionName + FallbackSiteCode = `$CMHierarchySetting.FallbackSiteCode + TargetCollectionName = `$CMHierarchySetting.TargetCollectionName + TelemetryLevel = `$CMHierarchySetting.TelemetryLevel + } + } + if (`$CMServiceConnectionPoint) { CMServiceConnectionPoint `$(`$CMServiceConnectionPoint.SiteServerName) @@ -11182,7 +11205,7 @@ function Set-ConfigMgrCBDscReverse 'DistributionGroups','DistributionPoint','DistributionPointGroupMembers', 'EmailNotificationComponent','FallbackPoints','ForestDiscovery','HeartbeatDiscovery', 'MaintenanceWindow','ManagementPoint','NetworkDiscovery','PullDistributionPoint', - 'PxeDistributionPoint','ReportingServicesPoint','SecurityScopes','ServiceConnection', + 'PxeDistributionPoint','ReportingServicesPoint','HierarchySetting','SecurityScopes','ServiceConnection', 'SiteMaintenance','SiteSystemServer','SoftwareDistributionComponent','SoftwareupdatePoint', 'StatusReportingComponent','SystemDiscovery','UserDiscovery','ConfigFileOnly','GroupDiscovery', 'SoftwareUpdatePointComponent','ClientSettings','ClientSettingsBits', @@ -11201,7 +11224,7 @@ function Set-ConfigMgrCBDscReverse 'DistributionGroups','DistributionPoint','DistributionPointGroupMembers', 'EmailNotificationComponent','FallbackPoints','ForestDiscovery','HeartbeatDiscovery', 'MaintenanceWindow','ManagementPoint','NetworkDiscovery','PullDistributionPoint', - 'PxeDistributionPoint','ReportingServicesPoint','SecurityScopes','ServiceConnection', + 'PxeDistributionPoint','ReportingServicesPoint', 'HierarchySetting','SecurityScopes','ServiceConnection', 'SiteMaintenance','SiteSystemServer','SoftwareDistributionComponent','SoftwareupdatePoint', 'StatusReportingComponent','SystemDiscovery','UserDiscovery','GroupDiscovery', 'SoftwareUpdatePointComponent','ClientSettings','ClientSettingsBits', @@ -12732,6 +12755,24 @@ function Set-ConfigMgrCBDscReverse } } + if (($Include -eq 'All' -and $Exclude -notcontains 'HierarchySetting') -or ($Include -contains 'HierarchySetting')) + { + $resourceName = 'CMHierarchySetting' + Write-Verbose -Message $script:localizedData.Hierarchy -Verbose + $params = @{ + ResourceName = $resourceName + SiteCode = $SiteCode + Indent = 2 + MultiEntry = $false + Resources = $resources + } + + $hierarchySettings = "$resourceName = @{`r`n" + $testThing = Set-OutFile @params + $hierarchySettings += "$testThing" + $fileOut += "$hierarchySettings`r`n" + } + if (($Include -eq 'All' -and $Exclude -notcontains 'SecurityScopes') -or ($Include -contains 'SecurityScopes')) { $resourceName = 'CMSecurityScopes' diff --git a/source/Modules/ConfigMgrCBDsc.ReverseDsc/en-US/ConfigMgrCBDsc.ReverseDsc.strings.psd1 b/source/Modules/ConfigMgrCBDsc.ReverseDsc/en-US/ConfigMgrCBDsc.ReverseDsc.strings.psd1 index 1ab4ec5..1071772 100644 --- a/source/Modules/ConfigMgrCBDsc.ReverseDsc/en-US/ConfigMgrCBDsc.ReverseDsc.strings.psd1 +++ b/source/Modules/ConfigMgrCBDsc.ReverseDsc/en-US/ConfigMgrCBDsc.ReverseDsc.strings.psd1 @@ -45,4 +45,5 @@ ConvertFrom-StringData @' ClientSoftUp = Processing CMClientSettingsSoftwareUpdate for client policy: {0}. ClientStateMessage = Processing CMClientSettingsStateMessaging for client policy: {0}. ClientAffinity = Processing CMClientSettingsUserDeviceAffinity for client policy: {0}. + Hierarchy = Processing CMHierarchySetting. '@ diff --git a/tests/Unit/CMHierarchySetting.tests.ps1 b/tests/Unit/CMHierarchySetting.tests.ps1 new file mode 100644 index 0000000..fe2d0fa --- /dev/null +++ b/tests/Unit/CMHierarchySetting.tests.ps1 @@ -0,0 +1,285 @@ +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '')] +param () + +$script:dscModuleName = 'ConfigMgrCBDsc' +$script:dscResourceName = 'DSC_CMHierarchySetting' + +function Invoke-TestSetup +{ + try + { + Import-Module -Name DscResource.Test -Force -ErrorAction 'Stop' + } + catch [System.IO.FileNotFoundException] + { + throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -Tasks build" first.' + } + + $script:testEnvironment = Initialize-TestEnvironment ` + -DSCModuleName $script:dscModuleName ` + -DSCResourceName $script:dscResourceName ` + -ResourceType 'Mof' ` + -TestType 'Unit' + + # Import Stub function + $script:moduleRoot = Split-Path -Parent (Split-Path -Parent $PSScriptRoot) + Import-Module (Join-Path -Path $PSScriptRoot -ChildPath 'Stubs\ConfigMgrCBDscStub.psm1') -Force -WarningAction SilentlyContinue +} + +function Invoke-TestCleanup +{ + Restore-TestEnvironment -TestEnvironment $script:testEnvironment +} + +Invoke-TestSetup + +# Begin Testing +try +{ + InModuleScope $script:dscResourceName { + + Describe 'ConfigMgrCBDsc - DSC_CMHierarchySetting\Get-TargetResource' -Tag 'GetHier' { + BeforeAll { + $hierarchyReturn = @( + [pscustomobject]@{ + PropertyNames = @('AdvertisementDuration') + AdvertisementDuration = 10 + AllowPrestage = $true + ExcludedCollectionID = 'ExclusionId' + ExcludeServers = $false + IsProgramEnabled = $true + IsUpgradeExclusionEnabled = $true + } + [pscustomobject]@{ + PropertyNames = @('TargetCollectionID') + IsAccepted = $true + IsEnabled = $true + TargetCollectionID = 'PreprodId' + } + ) + + $cimInstanceReturn = @( + [pscustomobject]@{ + PropertyName = 'Auto Approval' + Value = 1 + } + [pscustomobject]@{ + PropertyName = 'Registration HardwareID Conflict Resolution' + Value = 0 + } + [pscustomobject]@{ + PropertyName = 'AcceptedBeta' + Value = 0 + } + [pscustomobject]@{ + PropertyName = 'PreferMPInBoundaryWithFastNetwork' + Value = 0 + } + [pscustomobject]@{ + PropertyName = 'SiteAssignmentSiteCode' + Value1 = 'SI2' + } + [pscustomobject]@{ + PropertyName = 'TelemetryLevel' + Value = 2 + } + ) + + $preprodCollection = @{ + Name = 'Preprod Collection' + } + + $excludedCollection = @{ + Name = 'Exclusion Collection' + } + + Mock -CommandName Import-ConfigMgrPowerShellModule + Mock -CommandName Set-Location + Mock -CommandName Get-CimInstance -MockWith { $cimInstanceReturn } -ParameterFilter { $ClassName -eq 'SMS_SCI_SCProperty' } + } + + Context 'When retrieving Hierarchy Settings' { + + It 'Should return current hierarchy settings' { + Mock -CommandName Get-CMHierarchySetting -MockWith { $hierarchyReturn } + Mock -CommandName Get-CMCollection -MockWith { $preprodCollection } -ParameterFilter { $Id -eq 'PreprodId' } + Mock -CommandName Get-CMCollection -MockWith { $excludedCollection } -ParameterFilter { $Id -eq 'ExclusionId' } + + + $result = Get-TargetResource -SiteCode Lab + $result | Should -BeOfType System.Collections.HashTable + $result.SiteCode | Should -Be -ExpectedValue 'Lab' + $result.AllowPrestage | Should -Be -ExpectedValue $true + $result.ApprovalMethod | Should -Be -ExpectedValue 'AutomaticallyApproveComputersInTrustedDomains' + $result.AutoResolveClientConflict | Should -Be -ExpectedValue $true + $result.EnableAutoClientUpgrade | Should -Be -ExpectedValue $true + $result.EnableExclusionCollection | Should -Be -ExpectedValue $true + $result.EnablePreProduction | Should -Be -ExpectedValue $true + $result.EnablePrereleaseFeature | Should -Be -ExpectedValue $false + $result.ExcludeServer | Should -Be -ExpectedValue $false + $result.PreferBoundaryGroupManagementPoint | Should -Be -ExpectedValue $false + $result.UseFallbackSite | Should -Be -ExpectedValue $true + $result.AutoUpgradeDays | Should -Be -ExpectedValue 10 + $result.ExclusionCollectionName | Should -Be -ExpectedValue 'Exclusion Collection' + $result.FallbackSiteCode | Should -Be -ExpectedValue 'SI2' + $result.TargetCollectionName | Should -Be -ExpectedValue 'Preprod Collection' + $result.TelemetryLevel | Should -Be -ExpectedValue 'Enhanced' + } + + It 'Should call expected commands when reading the hierarchy setting' { + + Get-TargetResource -SiteCode Lab + Assert-MockCalled Import-ConfigMgrPowerShellModule -Exactly -Times 1 -Scope It + Assert-MockCalled Set-Location -Exactly -Times 1 -Scope It + Assert-MockCalled Get-CimInstance -Exactly -Times 1 -Scope It + Assert-MockCalled Get-CMHierarchySetting -Exactly -Times 1 -Scope It + } + } + } + + Describe 'ConfigMgrCBDsc - DSC_CMHierarchySetting\Set-TargetResource' -Tag 'Set' { + BeforeAll { + $correctInput = @{ + SiteCode = 'Lab' + AllowPrestage = $true + ApprovalMethod = 'AutomaticallyApproveComputersInTrustedDomains' + AutoResolveClientConflict = $true + EnableAutoClientUpgrade = $true + EnableExclusionCollection = $true + EnablePreProduction = $true + EnablePrereleaseFeature = $true + ExcludeServer = $true + PreferBoundaryGroupManagementPoint = $true + UseFallbackSite = $true + AutoUpgradeDays = 10 + ExclusionCollectionName = 'Exclusions' + FallbackSiteCode = 'FB1' + TargetCollectionName = 'Preprod' + TelemetryLevel = 'Enhanced' + } + + $fallbackMismatch = $correctInput.Clone() + $fallbackMismatch.UseFallbackSite = $false + $exclusionMismatch = $correctInput.Clone() + $exclusionMismatch.Remove('ExclusionCollectionName') + $preprodMismatch = $correctInput.Clone() + $preprodMismatch.Remove('TargetCollectionName') + $ignoreAutoUpgrade = $correctInput.Clone() + $ignoreAutoUpgrade.EnableAutoClientUpgrade = $false + + Mock -CommandName Set-CMHierarchySetting + Mock -CommandName Import-ConfigMgrPowerShellModule + Mock -CommandName Set-Location + Mock -CommandName Write-Verbose -MockWith {} -ParameterFilter { $Message -eq 'ExcludeServer is configured, but client auto upgrade is not configured. Skipping setting.' } + Mock -CommandName Write-Verbose -MockWith {} -ParameterFilter { $Message -eq 'AutoUpgradeDays is configured, but client auto upgrade is not configured. Skipping setting.' } + } + + Context 'When Set-TargetResource runs successfully' { + It 'Should call expected commands during configuration' { + Set-TargetResource @correctInput + Assert-MockCalled Import-ConfigMgrPowerShellModule -Exactly -Times 1 -Scope It + Assert-MockCalled Set-Location -Exactly -Times 2 -Scope It + Assert-MockCalled Set-CMHierarchySetting -Exactly -Times 1 -Scope It + } + It 'Should call expected commands during configuration with mismatched auto upgrade settings' { + Set-TargetResource @ignoreAutoUpgrade + Assert-MockCalled Import-ConfigMgrPowerShellModule -Exactly -Times 1 -Scope It + Assert-MockCalled Set-Location -Exactly -Times 2 -Scope It + Assert-MockCalled Write-Verbose -Exactly -Times 1 -ParameterFilter { $Message -eq 'ExcludeServer is configured, but client auto upgrade is not configured. Skipping setting.' } + Assert-MockCalled Write-Verbose -Exactly -Times 1 -ParameterFilter { $Message -eq 'AutoUpgradeDays is configured, but client auto upgrade is not configured. Skipping setting.' } + Assert-MockCalled Set-CMHierarchySetting -Exactly -Times 1 -Scope It + } + } + + Context 'When running Set-TargetResource should throw' { + BeforeEach { + $fallbackMismatchMessage = 'If UseFallbackSite or FallbackSiteCode are used, both properties need to be specified.' + $preprodMismatchMessage = 'If EnablePreProduction or TargetCollectionName are used, both properties need to be specified.' + $exclusionMismatchMessage = 'If EnableExclusionCollection or ExclusionCollectionName are used, both properties need to be specified.' + } + + It 'Should throw and call expected commands when setting with mismatched fallback settings' { + { Set-TargetResource @fallbackMismatch } | Should -Throw -ExpectedMessage $fallbackMismatchMessage + Assert-MockCalled Import-ConfigMgrPowerShellModule -Exactly -Times 1 -Scope It + Assert-MockCalled Set-Location -Exactly -Times 2 -Scope It + Assert-MockCalled Set-CMHierarchySetting -Exactly -Times 0 -Scope It + } + + It 'Should throw and call expected commands when setting with mismatched exclusion settings' { + { Set-TargetResource @exclusionMismatch } | Should -Throw -ExpectedMessage $exclusionMismatchMessage + Assert-MockCalled Import-ConfigMgrPowerShellModule -Exactly -Times 1 -Scope It + Assert-MockCalled Set-Location -Exactly -Times 2 -Scope It + Assert-MockCalled Set-CMHierarchySetting -Exactly -Times 0 -Scope It + } + + It 'Should throw and call expected commands when setting with mismatched preprod settings' { + { Set-TargetResource @preprodMismatch } | Should -Throw -ExpectedMessage $preprodMismatchMessage + Assert-MockCalled Import-ConfigMgrPowerShellModule -Exactly -Times 1 -Scope It + Assert-MockCalled Set-Location -Exactly -Times 2 -Scope It + Assert-MockCalled Set-CMHierarchySetting -Exactly -Times 0 -Scope It + } + } + } + + Describe 'ConfigMgrCBDsc - DSC_CMHierarchySetting\Test-TargetResource' -Tag 'Test' { + BeforeAll { + $returnPresentDefault = @{ + SiteCode = 'Lab' + AllowPrestage = $true + ApprovalMethod = 'AutomaticallyApproveComputersInTrustedDomains' + AutoResolveClientConflict = $true + EnableAutoClientUpgrade = $true + EnableExclusionCollection = $true + EnablePreProduction = $true + EnablePrereleaseFeature = $true + ExcludeServer = $true + PreferBoundaryGroupManagementPoint = $true + UseFallbackSite = $true + AutoUpgradeDays = 10 + ExclusionCollectionName = 'Exclusions' + FallbackSiteCode = 'FB1' + TargetCollectionName = 'Preprod' + TelemetryLevel = 'Enhanced' + } + + $inputPresent = $returnPresentDefault.Clone() + $inputMismatch = @{ + SiteCode = 'Lab' + AllowPrestage = $false + ApprovalMethod = 'AutomaticallyApproveAllComputers' + AutoResolveClientConflict = $false + EnableAutoClientUpgrade = $false + EnableExclusionCollection = $false + EnablePreProduction = $false + EnablePrereleaseFeature = $false + ExcludeServer = $false + PreferBoundaryGroupManagementPoint = $false + UseFallbackSite = $false + AutoUpgradeDays = 42 + ExclusionCollectionName = 'NoExclusions' + TargetCollectionName = 'NoPreprod' + TelemetryLevel = 'Full' + } + + Mock -CommandName Set-Location + Mock -CommandName Import-ConfigMgrPowerShellModule + Mock -CommandName Get-TargetResource -MockWith { $returnPresentDefault } + } + + Context 'When running Test-TargetResource' { + + It 'Should return desired result true settings match' { + Test-TargetResource @inputPresent | Should -Be $true + } + + It 'Should return desired result false when there is a settings mismatch' { + Test-TargetResource @inputMismatch | Should -Be $false + } + } + } + } +} +finally +{ + Invoke-TestCleanup +} diff --git a/tests/Unit/ConfigMgrCBDsc.ReverseDsc.tests.ps1 b/tests/Unit/ConfigMgrCBDsc.ReverseDsc.tests.ps1 index b51d14f..9d5600b 100644 --- a/tests/Unit/ConfigMgrCBDsc.ReverseDsc.tests.ps1 +++ b/tests/Unit/ConfigMgrCBDsc.ReverseDsc.tests.ps1 @@ -4291,6 +4291,122 @@ InModuleScope $script:subModuleName { } ) } + @{ + ImplementedAs = 'PowerShell' + Name = 'CMHierarchySetting' + ModuleName = 'ConfigMgrCBDsc' + Version = '1.0.1' + Properties = @( + @{ + Name = 'SiteCode' + PropertyType = '[string]' + IsMandatory = $true + Values = '{}' + } + @{ + Name = 'AllowPrestage' + PropertyType = '[bool]' + IsMandatory = $false + Values = '{}' + } + @{ + Name = 'ApprovalMethod' + PropertyType = '[string]' + IsMandatory = $false + Values = '{}' + } + @{ + Name = 'AutoResolveClientConflict' + PropertyType = '[bool]' + IsMandatory = $false + Values = '{}' + } + @{ + Name = 'EnableAutoClientUpgrade' + PropertyType = '[bool]' + IsMandatory = $false + Values = '{}' + } + @{ + Name = 'EnableExclusionCollection' + PropertyType = '[bool]' + IsMandatory = $false + Values = '{}' + } + @{ + Name = 'EnablePreProduction' + PropertyType = '[bool]' + IsMandatory = $false + Values = '{}' + } + @{ + Name = 'EnablePrereleaseFeature' + PropertyType = '[bool]' + IsMandatory = $false + Values = '{}' + } + @{ + Name = 'ExcludeServer' + PropertyType = '[bool]' + IsMandatory = $false + Values = '{}' + } + @{ + Name = 'PreferBoundaryGroupManagementPoint' + PropertyType = '[bool]' + IsMandatory = $false + Values = '{}' + } + @{ + Name = 'UseFallbackSite' + PropertyType = '[bool]' + IsMandatory = $false + Values = '{}' + } + @{ + Name = 'AutoUpgradeDays' + PropertyType = '[UInt32]' + IsMandatory = $false + Values = '{}' + } + @{ + Name = 'ExclusionCollectionName' + PropertyType = '[string]' + IsMandatory = $false + Values = '{}' + } + @{ + Name = 'FallbackSiteCode' + PropertyType = '[string]' + IsMandatory = $false + Values = '{}' + } + @{ + Name = 'TargetCollectionName' + PropertyType = '[string]' + IsMandatory = $false + Values = '{}' + } + @{ + Name = 'TelemetryLevel' + PropertyType = '[string]' + IsMandatory = $false + Values = '{}' + } + @{ + Name = 'DependsOn' + PropertyType = '[string[]]' + IsMandatory = $false + Values = '{}' + } + @{ + Name = 'PsDscRunAsCredential' + PropertyType = '[PSCredential]' + IsMandatory = $false + Values = '{}' + } + ) + } ) $invokeCMAccounts = @{ @@ -6253,6 +6369,33 @@ InModuleScope $script:subModuleName { SiteSystemCollectionBehavior = 'Block' PSComputerName = 'localhost' } + + $invokeHierarchySetting = @{ + ConfigurationName = $null + DependsOn = $null + ModuleName = 'ConfigMgrCBDsc' + ModuleVersion = 1.0.1 + PsDscRunAsCredential = $null + ResourceId = $null + SourceInfo = $null + AllowPrestage = $true + ApprovalMethod = 'AutomaticallyApproveComputersInTrustedDomains' + AutoResolveClientConflict = $true + EnableAutoClientUpgrade = $true + EnableExclusionCollection = $true + EnablePreProduction = $true + EnablePrereleaseFeature = $true + ExcludeServer = $true + PreferBoundaryGroupManagementPoint = $true + UseFallbackSite = $true + AutoUpgradeDays = 10 + ExclusionCollectionName = 'Exclusions' + FallbackSiteCode = 'FB1' + TargetCollectionName = 'Preprod' + TelemetryLevel = 'Enhanced' + SiteCode = 'LAB' + PSComputerName = 'localhost' + } } Context 'When running the Set-ConfigMgrCBDscReverse' { @@ -6352,11 +6495,12 @@ InModuleScope $script:subModuleName { Mock -CommandName Invoke-DscResource -MockWith { $invokeCMClientSettingsStateMessaging } -ParameterFilter { $Name -eq 'CMClientSettingsStateMessaging' } Mock -CommandName Invoke-DscResource -MockWith { $invokeCMClientSettingsUserDeviceAffinity } -ParameterFilter { $Name -eq 'CMClientSettingsUserDeviceAffinity' } Mock -CommandName Invoke-DscResource -MockWith { $invokeSiteConfigurationCas } -ParameterFilter { $Name -eq 'CMSiteConfiguration' } + Mock -CommandName Invoke-DscResource -MockWith { $invokeHierarchySetting } -ParameterFilter { $Name -eq 'CMHierarchySetting' } $result = Set-ConfigMgrCBDscReverse @testAll $result | Should -BeOfType System.String Assert-MockCalled Get-CMAccount -Exactly -Times 1 -Scope It - Assert-MockCalled Invoke-DscResource -Exactly -Times 48 -Scope It + Assert-MockCalled Invoke-DscResource -Exactly -Times 49 -Scope It Assert-MockCalled Get-CMAdministrativeUser -Exactly -Times 1 -Scope It Assert-MockCalled Get-CMAssetIntelligenceSynchronizationPoint -Exactly -Times 1 -Scope It Assert-MockCalled Get-CMClientSetting -Exactly -Times 20 -Scope It