DSCResources/xActiveDirectory/2.14.0.0/DSCResources/MSFT_xADDomain/MSFT_xADDomain.psm1
# Localized messages data localizedData { # culture="en-US" ConvertFrom-StringData @' RoleNotFoundError = Please ensure that the PowerShell module for role '{0}' is installed. InvalidDomainError = Computer is a member of the wrong domain?! ExistingDomainMemberError = Computer is already a domain member. Cannot create a new '{0}' domain? InvalidCredentialError = Domain '{0}' is available, but invalid credentials were supplied. QueryDomainWithLocalCredential = Computer is a domain member; querying domain '{0}' using local credential ... QueryDomainWithCredential = Computer is a workgroup member; querying for domain '{0}' using supplied credential ... DomainFound = Active Directory domain '{0}' found. DomainNotFound = Active Directory domain '{0}' cannot be found. CreatingChildDomain = Creating domain '{0}' as a child of domain '{1}' ... CreatedChildDomain = Child domain '{0}' created. CreatingForest = Creating AD forest '{0}' ... CreatedForest = AD forest '{0}' created. ResourcePropertyValueIncorrect = Property '{0}' value is incorrect; expected '{1}', actual '{2}'. ResourceInDesiredState = Resource '{0}' is in the desired state. ResourceNotInDesiredState = Resource '{0}' is NOT in the desired state. RetryingGetADDomain = Attempt {0} of {1} to call Get-ADDomain failed, retrying in {2} seconds. UnhandledError = Unhandled error occured, detail here: {0} FaultExceptionAndDomainShouldExist = ServiceModel FaultException detected and domain should exist, performing retry... '@ } function Get-TrackingFilename { param( [Parameter(Mandatory)] [String] $DomainName ) Join-Path $Env:TEMP ('{0}.xADDomain.completed' -f $DomainName) } function Get-TargetResource { [OutputType([System.Collections.Hashtable])] param ( [Parameter(Mandatory)] [String] $DomainName, [Parameter(Mandatory)] [PSCredential] $DomainAdministratorCredential, [Parameter(Mandatory)] [PSCredential] $SafemodeAdministratorPassword, [Parameter()] [ValidateNotNullOrEmpty()] [String] $ParentDomainName, [Parameter()] [ValidateNotNullOrEmpty()] [String] $DomainNetBIOSName, [Parameter()] [ValidateNotNullOrEmpty()] [PSCredential] $DnsDelegationCredential, [Parameter()] [ValidateNotNullOrEmpty()] [String] $DatabasePath, [Parameter()] [ValidateNotNullOrEmpty()] [String] $LogPath, [Parameter()] [ValidateNotNullOrEmpty()] [String] $SysvolPath ) Assert-Module -ModuleName 'ADDSDeployment'; $domainFQDN = Resolve-DomainFQDN -DomainName $DomainName -ParentDomainName $ParentDomainName; $isDomainMember = Test-DomainMember; $retries = 0 $maxRetries = 5 $retryIntervalInSeconds = 30 $domainShouldExist = (Test-Path (Get-TrackingFilename -DomainName $DomainName)) do { try { if ($isDomainMember) { ## We're already a domain member, so take the credentials out of the equation Write-Verbose ($localizedData.QueryDomainADWithLocalCredentials -f $domainFQDN); $domain = Get-ADDomain -Identity $domainFQDN -ErrorAction Stop; } else { Write-Verbose ($localizedData.QueryDomainWithCredential -f $domainFQDN); $domain = Get-ADDomain -Identity $domainFQDN -Credential $DomainAdministratorCredential -ErrorAction Stop; } ## No need to check whether the node is actually a domain controller. If we don't throw an exception, ## the domain is already UP - and this resource shouldn't run. Domain controller functionality ## should be checked by the xADDomainController resource? Write-Verbose ($localizedData.DomainFound -f $domain.DnsRoot); $targetResource = @{ DomainName = $domain.DnsRoot; ParentDomainName = $domain.ParentDomain; DomainNetBIOSName = $domain.NetBIOSName; } return $targetResource; } catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException] { $errorMessage = $localizedData.ExistingDomainMemberError -f $DomainName; ThrowInvalidOperationError -ErrorId 'xADDomain_DomainMember' -ErrorMessage $errorMessage; } catch [Microsoft.ActiveDirectory.Management.ADServerDownException] { Write-Verbose ($localizedData.DomainNotFound -f $domainFQDN) $domain = @{ }; # will fall into retry mechanism } catch [System.Security.Authentication.AuthenticationException] { $errorMessage = $localizedData.InvalidCredentialError -f $DomainName; ThrowInvalidOperationError -ErrorId 'xADDomain_InvalidCredential' -ErrorMessage $errorMessage; } catch { $errorMessage = $localizedData.UnhandledError -f ($_.Exception | Format-List -Force | Out-String) Write-Verbose $errorMessage if ($domainShouldExist -and ($_.Exception.InnerException -is [System.ServiceModel.FaultException])) { Write-Verbose $localizedData.FaultExceptionAndDomainShouldExist # will fall into retry mechanism } else { ## Not sure what's gone on here! throw $_ } } if($domainShouldExist) { $retries++ Write-Verbose ($localizedData.RetryingGetADDomain -f $retries, $maxRetries, $retryIntervalInSeconds) Sleep -Seconds ($retries * $retryIntervalInSeconds) } } while ($domainShouldExist -and ($retries -le $maxRetries) ) } #end function Get-TargetResource function Test-TargetResource { [OutputType([System.Boolean])] param ( [Parameter(Mandatory)] [String] $DomainName, [Parameter(Mandatory)] [PSCredential] $DomainAdministratorCredential, [Parameter(Mandatory)] [PSCredential] $SafemodeAdministratorPassword, [Parameter()] [ValidateNotNullOrEmpty()] [String] $ParentDomainName, [Parameter()] [ValidateNotNullOrEmpty()] [String] $DomainNetBIOSName, [Parameter()] [ValidateNotNullOrEmpty()] [PSCredential] $DnsDelegationCredential, [Parameter()] [ValidateNotNullOrEmpty()] [String] $DatabasePath, [Parameter()] [ValidateNotNullOrEmpty()] [String] $LogPath, [Parameter()] [ValidateNotNullOrEmpty()] [String] $SysvolPath ) $targetResource = Get-TargetResource @PSBoundParameters $isCompliant = $true; ## The Get-Target resource returns .DomainName as the domain's FQDN. Therefore, we ## need to resolve this before comparison. $domainFQDN = Resolve-DomainFQDN -DomainName $DomainName -ParentDomainName $ParentDomainName if ($domainFQDN -ne $targetResource.DomainName) { $message = $localizedData.ResourcePropertyValueIncorrect -f 'DomainName', $domainFQDN, $targetResource.DomainName; Write-Verbose -Message $message; $isCompliant = $false; } $propertyNames = @('ParentDomainName','DomainNetBIOSName'); foreach ($propertyName in $propertyNames) { if ($PSBoundParameters.ContainsKey($propertyName)) { $propertyValue = (Get-Variable -Name $propertyName).Value; if ($targetResource.$propertyName -ne $propertyValue) { $message = $localizedData.ResourcePropertyValueIncorrect -f $propertyName, $propertyValue, $targetResource.$propertyName; Write-Verbose -Message $message; $isCompliant = $false; } } } if ($isCompliant) { Write-Verbose -Message ($localizedData.ResourceInDesiredState -f $domainFQDN); return $true; } else { Write-Verbose -Message ($localizedData.ResourceNotInDesiredState -f $domainFQDN); return $false; } } #end function Test-TargetResource function Set-TargetResource { param ( [Parameter(Mandatory)] [String] $DomainName, [Parameter(Mandatory)] [PSCredential] $DomainAdministratorCredential, [Parameter(Mandatory)] [PSCredential] $SafemodeAdministratorPassword, [Parameter()] [ValidateNotNullOrEmpty()] [String] $ParentDomainName, [Parameter()] [ValidateNotNullOrEmpty()] [String] $DomainNetBIOSName, [Parameter()] [ValidateNotNullOrEmpty()] [PSCredential] $DnsDelegationCredential, [Parameter()] [ValidateNotNullOrEmpty()] [String] $DatabasePath, [Parameter()] [ValidateNotNullOrEmpty()] [String] $LogPath, [Parameter()] [ValidateNotNullOrEmpty()] [String] $SysvolPath ) # Debug can pause Install-ADDSForest/Install-ADDSDomain, so we remove it. [ref] $null = $PSBoundParameters.Remove("Debug"); ## Not entirely necessary, but run Get-TargetResouece to ensure we raise any pre-flight errors. $targetResource = Get-TargetResource @PSBoundParameters; $installADDSParams = @{ SafeModeAdministratorPassword = $SafemodeAdministratorPassword.Password; NoRebootOnCompletion = $true; Force = $true; } if ($PSBoundParameters.ContainsKey('DnsDelegationCredential')) { $installADDSParams['DnsDelegationCredential'] = $DnsDelegationCredential; $installADDSParams['CreateDnsDelegation'] = $true; } if ($PSBoundParameters.ContainsKey('DatabasePath')) { $installADDSParams['DatabasePath'] = $DatabasePath; } if ($PSBoundParameters.ContainsKey('LogPath')) { $installADDSParams['LogPath'] = $LogPath; } if ($PSBoundParameters.ContainsKey('SysvolPath')) { $installADDSParams['SysvolPath'] = $SysvolPath; } if ($PSBoundParameters.ContainsKey('ParentDomainName')) { Write-Verbose -Message ($localizedData.CreatingChildDomain -f $DomainName, $ParentDomainName); $installADDSParams['Credential'] = $DomainAdministratorCredential $installADDSParams['NewDomainName'] = $DomainName $installADDSParams['ParentDomainName'] = $ParentDomainName $installADDSParams['DomainType'] = 'ChildDomain'; if ($PSBoundParameters.ContainsKey('DomainNetBIOSName')) { $installADDSParams['NewDomainNetbiosName'] = $DomainNetBIOSName; } Install-ADDSDomain @installADDSParams; Write-Verbose -Message ($localizedData.CreatedChildDomain); } else { Write-Verbose -Message ($localizedData.CreatingForest -f $DomainName); $installADDSParams['DomainName'] = $DomainName; if ($PSBoundParameters.ContainsKey('DomainNetbiosName')) { $installADDSParams['DomainNetbiosName'] = $DomainNetBIOSName; } Install-ADDSForest @installADDSParams; Write-Verbose -Message ($localizedData.CreatedForest -f $DomainName); } "Finished" | Out-File -FilePath (Get-TrackingFilename -DomainName $DomainName) -Force # Signal to the LCM to reboot the node to compensate for the one we # suppressed from Install-ADDSForest/Install-ADDSDomain $global:DSCMachineStatus = 1 } #end function Set-TargetResource ## Import the common AD functions $adCommonFunctions = Join-Path -Path (Split-Path -Path $PSScriptRoot -Parent) -ChildPath '\MSFT_xADCommon\MSFT_xADCommon.ps1'; . $adCommonFunctions; Export-ModuleMember -Function *-TargetResource; |