DSCResources/DSC_DFSNamespaceRoot/DSC_DFSNamespaceRoot.psm1
$modulePath = Join-Path -Path (Split-Path -Path (Split-Path -Path $PSScriptRoot -Parent) -Parent) -ChildPath 'Modules' # Import the DFSDsc.Common Module Import-Module -Name (Join-Path -Path $modulePath -ChildPath 'DscResource.Common') # Import Localization Strings $script:localizedData = Get-LocalizedData -DefaultUICulture 'en-US' <# .SYNOPSIS Returns the current state of a DFS Namespace Root. .PARAMETER Path Specifies a path for the root of a DFS namespace. .PARAMETER TargetPath Specifies a path for a root target of the DFS namespace. .PARAMETER Ensure Specifies if the DFS Namespace root should exist. .PARAMETER Type Specifies the type of a DFS namespace as a Type object. #> function Get-TargetResource { [CmdletBinding()] [OutputType([System.Collections.Hashtable])] param ( [Parameter(Mandatory = $true)] [System.String] $Path, [Parameter(Mandatory = $true)] [System.String] $TargetPath, [Parameter(Mandatory = $true)] [ValidateSet('Present','Absent')] [System.String] $Ensure, [Parameter(Mandatory = $true)] [ValidateSet('Standalone','DomainV1','DomainV2')] [System.String] $Type ) Write-Verbose -Message ( @( "$($MyInvocation.MyCommand): " $($script:localizedData.GettingNamespaceRootMessage) ` -f $Type,$Path,$TargetPath ) -join '' ) # Generate the return object assuming absent. $returnValue = @{ Path = $Path TargetPath = $TargetPath Ensure = 'Absent' Type = $Type } # Lookup the existing Namespace root $root = Get-Root ` -Path $Path if ($root) { # The namespace exists Write-Verbose -Message ( @( "$($MyInvocation.MyCommand): " $($script:localizedData.NamespaceRootExistsMessage) ` -f $Type,$Path ) -join '' ) } else { # The namespace does not exist Write-Verbose -Message ( @( "$($MyInvocation.MyCommand): " $($script:localizedData.NamespaceRootDoesNotExistMessage) ` -f $Type,$Path ) -join '' ) return $returnValue } # if $returnValue += @{ TimeToLiveSec = $root.TimeToLiveSec State = $root.State Description = $root.Description EnableSiteCosting = ($root.Flags -contains 'Site Costing') EnableInsiteReferrals = ($root.Flags -contains 'Insite Referrals') EnableAccessBasedEnumeration = ($root.Flags -contains 'AccessBased Enumeration') EnableRootScalability = ($root.Flags -contains 'Root Scalability') EnableTargetFailback = ($root.Flags -contains 'Target Failback') } # DFS Root exists but does target exist? $target = Get-RootTarget ` -Path $Path ` -TargetPath $TargetPath if ($target) { # The target exists in this namespace $returnValue.Ensure = 'Present' $returnValue += @{ ReferralPriorityClass = $target.ReferralPriorityClass ReferralPriorityRank = $target.ReferralPriorityRank } Write-Verbose -Message ( @( "$($MyInvocation.MyCommand): " $($script:localizedData.NamespaceRootTargetExistsMessage) ` -f $Type,$Path,$TargetPath ) -join '' ) } else { # The target does not exist in this namespace Write-Verbose -Message ( @( "$($MyInvocation.MyCommand): " $($script:localizedData.NamespaceRootTargetDoesNotExistMessage) ` -f $Type,$Path,$TargetPath ) -join '' ) } # if return $returnValue } # Get-TargetResource <# .SYNOPSIS Sets the current state of a DFS Namespace Folder. .PARAMETER Path Specifies a path for the root of a DFS namespace. .PARAMETER TargetPath Specifies a path for a root target of the DFS namespace. .PARAMETER Ensure Specifies if the DFS Namespace root should exist. .PARAMETER Type Specifies the type of a DFS namespace as a Type object. .PARAMETER Description The description of the DFS Namespace. .PARAMETER TimeToLiveSec Specifies a TTL interval, in seconds, for referrals. .PARAMETER EnableSiteCosting Indicates whether a DFS namespace uses cost-based selection. .PARAMETER EnableInsiteReferrals Indicates whether a DFS namespace server provides a client only with referrals that are in the same site as the client. .PARAMETER EnableAccessBasedEnumeration Indicates whether a DFS namespace uses access-based enumeration. .PARAMETER EnableRootScalability Indicates whether a DFS namespace uses root scalability mode. .PARAMETER EnableTargetFailback Indicates whether a DFS namespace uses target failback. .PARAMETER ReferralPriorityClass Specifies the target priority class for a DFS namespace root. .PARAMETER ReferralPriorityRank Specifies the priority rank, as an integer, for a root target of the DFS namespace. #> function Set-TargetResource { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [System.String] $Path, [Parameter(Mandatory = $true)] [System.String] $TargetPath, [Parameter(Mandatory = $true)] [ValidateSet('Present','Absent')] [System.String] $Ensure, [Parameter(Mandatory = $true)] [ValidateSet('Standalone','DomainV1','DomainV2')] [System.String] $Type, [Parameter()] [System.String] $Description, [Parameter()] [System.UInt32] $TimeToLiveSec, [Parameter()] [System.Boolean] $EnableSiteCosting, [Parameter()] [System.Boolean] $EnableInsiteReferrals, [Parameter()] [System.Boolean] $EnableAccessBasedEnumeration, [Parameter()] [System.Boolean] $EnableRootScalability, [Parameter()] [System.Boolean] $EnableTargetFailback, [Parameter()] [ValidateSet('Global-High','SiteCost-High','SiteCost-Normal','SiteCost-Low','Global-Low')] [System.String] $ReferralPriorityClass, [Parameter()] [System.UInt32] $ReferralPriorityRank ) Write-Verbose -Message ( @( "$($MyInvocation.MyCommand): " $($script:localizedData.SettingNamespaceRootMessage) ` -f $Type,$Path,$TargetPath ) -join '' ) # Lookup the existing Namespace root $root = Get-Root ` -Path $Path if ($Ensure -eq 'Present') { # Set desired Configuration if ($root) { # Does the root need to be updated? [System.Boolean] $rootChange = $false # The root properties that will be updated $rootProperties = @{ State = 'online' } if (($Description) ` -and ($root.Description -ne $Description)) { $rootProperties += @{ Description = $Description } $rootChange = $true } # if if (($TimeToLiveSec) ` -and ($root.TimeToLiveSec -ne $TimeToLiveSec)) { $rootProperties += @{ TimeToLiveSec = $TimeToLiveSec } $rootChange = $true } # if if (($null -ne $EnableSiteCosting) ` -and (($root.Flags -contains 'Site Costing') -ne $EnableSiteCosting)) { $rootProperties += @{ EnableSiteCosting = $EnableSiteCosting } $rootChange = $true } # if if (($null -ne $EnableInsiteReferrals) ` -and (($root.Flags -contains 'Insite Referrals') -ne $EnableInsiteReferrals)) { $rootProperties += @{ EnableInsiteReferrals = $EnableInsiteReferrals } $rootChange = $true } # if if (($null -ne $EnableAccessBasedEnumeration) ` -and (($root.Flags -contains 'AccessBased Enumeration') -ne $EnableAccessBasedEnumeration)) { $rootProperties += @{ EnableAccessBasedEnumeration = $EnableAccessBasedEnumeration } $rootChange = $true } # if if (($null -ne $EnableRootScalability) ` -and (($root.Flags -contains 'Root Scalability') -ne $EnableRootScalability)) { $rootProperties += @{ EnableRootScalability = $EnableRootScalability } $rootChange = $true } # if if (($null -ne $EnableTargetFailback) ` -and (($root.Flags -contains 'Target Failback') -ne $EnableTargetFailback)) { $rootProperties += @{ EnableTargetFailback = $EnableTargetFailback } $rootChange = $true } # if if ($rootChange) { # Update root settings $null = Set-DfsnRoot ` -Path $Path ` @RootProperties ` -ErrorAction Stop $rootProperties.GetEnumerator() | ForEach-Object -Process { Write-Verbose -Message ( @( "$($MyInvocation.MyCommand): " $($script:localizedData.NamespaceRootUpdateParameterMessage) ` -f $Type,$Path,$_.name, $_.value ) -join '' ) } } # if # Get target $target = Get-RootTarget ` -Path $Path ` -TargetPath $TargetPath # Does the target need to be updated? [System.Boolean] $targetChange = $false # The Target properties that will be updated $targetProperties = @{} # Check the target properties if (($ReferralPriorityClass) ` -and ($target.ReferralPriorityClass -ne $ReferralPriorityClass)) { $targetProperties += @{ ReferralPriorityClass = ($ReferralPriorityClass -replace '-','') } $targetChange = $true } # if if (($ReferralPriorityRank) ` -and ($target.ReferralPriorityRank -ne $ReferralPriorityRank)) { $targetProperties += @{ ReferralPriorityRank = $ReferralPriorityRank } $targetChange = $true } # if # Is the target a member of the namespace? if ($target) { # Does the target need to be changed? if ($targetChange) { # Update target settings $null = Set-DfsnRootTarget ` -Path $Path ` -TargetPath $TargetPath ` @TargetProperties ` -ErrorAction Stop } } else { # Add target to Namespace $null = New-DfsnRootTarget ` -Path $Path ` -TargetPath $TargetPath ` @TargetProperties ` -ErrorAction Stop } # if # Output the target parameters that were changed/set $targetProperties.GetEnumerator() | ForEach-Object -Process { Write-Verbose -Message ( @( "$($MyInvocation.MyCommand): " $($script:localizedData.NamespaceRootTargetUpdateParameterMessage) ` -f $Type,$Path,$TargetPath,$_.name, $_.value ) -join '' ) } } else { <# Prepare to use the PSBoundParameters as a splat to created The new DFS Namespace root. #> $null = $PSBoundParameters.Remove('Ensure') # Correct the ReferralPriorityClass field if ($ReferralPriorityClass) { $PSBoundParameters.ReferralPriorityClass = ($ReferralPriorityClass -replace '-','') } # if # Create New-DfsnRoot $null = New-DfsnRoot ` @PSBoundParameters ` -ErrorAction Stop $PSBoundParameters.GetEnumerator() | ForEach-Object -Process { Write-Verbose -Message ( @( "$($MyInvocation.MyCommand): " $($script:localizedData.NamespaceRootUpdateParameterMessage) ` -f $Type,$Path,$_.name, $_.value ) -join '' ) } } # if } else { <# The Namespace Target should not exist Get root target #> $target = Get-RootTarget ` -Path $Path ` -TargetPath $TargetPath if ($target) { # Remove the target from the namespace $null = Remove-DfsnRootTarget ` -Path $Path ` -TargetPath $TargetPath ` -Confirm:$false ` -ErrorAction Stop Write-Verbose -Message ( @( "$($MyInvocation.MyCommand): " $($script:localizedData.NamespaceRootTargetRemovedMessage) ` -f $Type,$Path,$TargetPath ) -join '' ) } # if } # if } # Set-TargetResource <# .SYNOPSIS Tests the current state of a DFS Namespace Folder. .PARAMETER Path Specifies a path for the root of a DFS namespace. .PARAMETER TargetPath Specifies a path for a root target of the DFS namespace. .PARAMETER Ensure Specifies if the DFS Namespace root should exist. .PARAMETER Type Specifies the type of a DFS namespace as a Type object. .PARAMETER Description The description of the DFS Namespace. .PARAMETER TimeToLiveSec Specifies a TTL interval, in seconds, for referrals. .PARAMETER EnableSiteCosting Indicates whether a DFS namespace uses cost-based selection. .PARAMETER EnableInsiteReferrals Indicates whether a DFS namespace server provides a client only with referrals that are in the same site as the client. .PARAMETER EnableAccessBasedEnumeration Indicates whether a DFS namespace uses access-based enumeration. .PARAMETER EnableRootScalability Indicates whether a DFS namespace uses root scalability mode. .PARAMETER EnableTargetFailback Indicates whether a DFS namespace uses target failback. .PARAMETER ReferralPriorityClass Specifies the target priority class for a DFS namespace root. .PARAMETER ReferralPriorityRank Specifies the priority rank, as an integer, for a root target of the DFS namespace. #> function Test-TargetResource { [CmdletBinding()] [OutputType([System.Boolean])] param ( [Parameter(Mandatory = $true)] [System.String] $Path, [Parameter(Mandatory = $true)] [System.String] $TargetPath, [Parameter(Mandatory = $true)] [ValidateSet('Present','Absent')] [System.String] $Ensure, [Parameter(Mandatory = $true)] [ValidateSet('Standalone','DomainV1','DomainV2')] [System.String] $Type, [Parameter()] [System.String] $Description, [Parameter()] [System.UInt32] $TimeToLiveSec, [Parameter()] [System.Boolean] $EnableSiteCosting, [Parameter()] [System.Boolean] $EnableInsiteReferrals, [Parameter()] [System.Boolean] $EnableAccessBasedEnumeration, [Parameter()] [System.Boolean] $EnableRootScalability, [Parameter()] [System.Boolean] $EnableTargetFailback, [Parameter()] [ValidateSet('Global-High','SiteCost-High','SiteCost-Normal','SiteCost-Low','Global-Low')] [System.String] $ReferralPriorityClass, [Parameter()] [System.UInt32] $ReferralPriorityRank ) Write-Verbose -Message ( @( "$($MyInvocation.MyCommand): " $($script:localizedData.TestingNamespaceRootMessage) ` -f $Type,$Path,$TargetPath ) -join '' ) # Flag to signal whether settings are correct [System.Boolean] $desiredConfigurationMatch = $true # Lookup the existing Namespace root $root = Get-Root ` -Path $Path if ($Ensure -eq 'Present') { # The Namespace root should exist if ($root) { <# The Namespace root exists and should Changing the namespace type is not possible - the namespace can only be recreated if the type should change. #> if (($root.Type -replace ' ','') -ne $Type) { New-InvalidOperationException ` -Message ($($script:localizedData.NamespaceRootTypeConversionError) ` -f $Type,($root.Type -replace ' ','')) } # if # Check the Namespace parameters if (($Description) ` -and ($root.Description -ne $Description)) { Write-Verbose -Message ( @( "$($MyInvocation.MyCommand): " $($script:localizedData.NamespaceRootParameterNeedsUpdateMessage) ` -f $Type,$Path,'Description' ) -join '' ) $desiredConfigurationMatch = $false } # if if (($TimeToLiveSec) ` -and ($root.TimeToLiveSec -ne $TimeToLiveSec)) { Write-Verbose -Message ( @( "$($MyInvocation.MyCommand): " $($script:localizedData.NamespaceRootParameterNeedsUpdateMessage) ` -f $Type,$Path,'TimeToLiveSec' ) -join '' ) $desiredConfigurationMatch = $false } # if if (($null -ne $EnableSiteCosting) ` -and (($root.Flags -contains 'Site Costing') -ne $EnableSiteCosting)) { Write-Verbose -Message ( @( "$($MyInvocation.MyCommand): " $($script:localizedData.NamespaceRootParameterNeedsUpdateMessage) ` -f $Type,$Path,'EnableSiteCosting' ) -join '' ) $desiredConfigurationMatch = $false } # if if (($null -ne $EnableInsiteReferrals) ` -and (($root.Flags -contains 'Insite Referrals') -ne $EnableInsiteReferrals)) { Write-Verbose -Message ( @( "$($MyInvocation.MyCommand): " $($script:localizedData.NamespaceRootParameterNeedsUpdateMessage) ` -f $Type,$Path,'EnableInsiteReferrals' ) -join '' ) $desiredConfigurationMatch = $false } # if if (($null -ne $EnableAccessBasedEnumeration) ` -and (($root.Flags -contains 'AccessBased Enumeration') -ne $EnableAccessBasedEnumeration)) { Write-Verbose -Message ( @( "$($MyInvocation.MyCommand): " $($script:localizedData.NamespaceRootParameterNeedsUpdateMessage) ` -f $Type,$Path,'EnableAccessBasedEnumeration' ) -join '' ) $desiredConfigurationMatch = $false } # if if (($null -ne $EnableRootScalability) ` -and (($root.Flags -contains 'Root Scalability') -ne $EnableRootScalability)) { Write-Verbose -Message ( @( "$($MyInvocation.MyCommand): " $($script:localizedData.NamespaceRootParameterNeedsUpdateMessage) ` -f $Type,$Path,'EnableRootScalability' ) -join '' ) $desiredConfigurationMatch = $false } # if if (($null -ne $EnableTargetFailback) ` -and (($root.Flags -contains 'Target Failback') -ne $EnableTargetFailback)) { Write-Verbose -Message ( @( "$($MyInvocation.MyCommand): " $($script:localizedData.NamespaceRootParameterNeedsUpdateMessage) ` -f $Type,$Path,'EnableTargetFailback' ) -join '' ) $desiredConfigurationMatch = $false } # if $target = Get-RootTarget ` -Path $Path ` -TargetPath $TargetPath if ($target) { if (($ReferralPriorityClass) ` -and ($target.ReferralPriorityClass -ne $ReferralPriorityClass)) { Write-Verbose -Message ( @( "$($MyInvocation.MyCommand): " $($script:localizedData.NamespaceRootTargetParameterNeedsUpdateMessage) ` -f $Type,$Path,$TargetPath,'ReferralPriorityClass' ) -join '' ) $desiredConfigurationMatch = $false } # if if (($ReferralPriorityRank) ` -and ($target.ReferralPriorityRank -ne $ReferralPriorityRank)) { Write-Verbose -Message ( @( "$($MyInvocation.MyCommand): " $($script:localizedData.NamespaceRootTargetParameterNeedsUpdateMessage) ` -f $Type,$Path,$TargetPath,'ReferralPriorityRank' ) -join '' ) $desiredConfigurationMatch = $false } # if } else { # The Root target does not exist but should - change required Write-Verbose -Message ( @( "$($MyInvocation.MyCommand): " $($script:localizedData.NamespaceRootTargetDoesNotExistButShouldMessage) ` -f $Type,$Path,$TargetPath ) -join '' ) $desiredConfigurationMatch = $false } # if } else { # Ths Namespace root doesn't exist but should - change required Write-Verbose -Message ( @( "$($MyInvocation.MyCommand): " $($script:localizedData.NamespaceRootDoesNotExistButShouldMessage) ` -f $Type,$Path ) -join '' ) $desiredConfigurationMatch = $false } # if } else { # The Namespace target should not exist if ($root) { $target = Get-RootTarget ` -Path $Path ` -TargetPath $TargetPath if ($target) { # The Root target exists but should not - change required Write-Verbose -Message ( @( "$($MyInvocation.MyCommand): " $($script:localizedData.NamespaceRootTargetExistsButShouldNotMessage) ` -f $Type,$Path,$TargetPath ) -join '' ) $desiredConfigurationMatch = $false } else { # The Namespace exists but the target doesn't - change not required Write-Verbose -Message ( @( "$($MyInvocation.MyCommand): " $($script:localizedData.NamespaceRootTargetDoesNotExistAndShouldNotMessage) ` -f $Type,$Path,$TargetPath ) -join '' ) } # if } else { # The Namespace does not exist (so neither does the target) - change not required Write-Verbose -Message ( @( "$($MyInvocation.MyCommand): " $($script:localizedData.NamespaceRootDoesNotExistAndShouldNotMessage) ` -f $Type,$Path ) -join '' ) } # if } # if return $desiredConfigurationMatch } # Test-TargetResource <# .SYNOPSIS Lookup the DFSN Root. .PARAMETER Path Specifies a path for the root of a DFS namespace. #> function Get-Root { param ( [Parameter(Mandatory = $true)] [System.String] $Path ) try { $dfsnRoot = Get-DfsnRoot ` -Path $Path ` -ErrorAction Stop } catch [Microsoft.Management.Infrastructure.CimException] { $dfsnRoot = $null } catch { throw $_ } return $dfsnRoot } <# .SYNOPSIS Lookup the DFSN Root Target in a namespace. .PARAMETER Path Specifies a path for the root of a DFS namespace. .PARAMETER TargetPath Specifies a path for a root target of the DFS namespace. #> function Get-RootTarget { param ( [Parameter(Mandatory = $true)] [System.String] $Path, [Parameter(Mandatory = $true)] [System.String] $TargetPath ) try { $dfsnTarget = Get-DfsnRootTarget ` -Path $Path ` -TargetPath $TargetPath ` -ErrorAction Stop } catch [Microsoft.Management.Infrastructure.CimException] { $dfsnTarget = $null } catch { throw $_ } return $dfsnTarget } Export-ModuleMember -Function *-TargetResource |