diff --git a/DSCResources/MSFT_xADDomain/MSFT_xADDomain.psm1 b/DSCResources/MSFT_xADDomain/MSFT_xADDomain.psm1 index 96f62f01c..29fc8cf8c 100644 --- a/DSCResources/MSFT_xADDomain/MSFT_xADDomain.psm1 +++ b/DSCResources/MSFT_xADDomain/MSFT_xADDomain.psm1 @@ -3,25 +3,66 @@ 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. + 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... '@ } +<# + .SYNOPSIS + Retrieves the name of the file that tracks the status of the xADDomain resource with the + specified domain name. + + .PARAMETER DomainName + The domain name of the xADDomain resource to retrieve the tracking file name of. + + .NOTES + The tracking file is currently output to the environment's temp directory. + + This file is NOT removed when a configuration completes, so if another call to a xADDomain + resource with the same domain name occurs in the same environment, this file will already + be present. + + This is so that when another call is made to the same resource, the resource will not + attempt to promote the machine to a domain controller again (which would cause an error). + + If the resource should be promoted to a domain controller once again, you must first remove + this file from the environment's temp directory (usually C:\Temp). + + If in the future this functionality needs to change so that future configurations are not + affected, $env:temp should be changed to the resource's cache location which is removed + after each configuration. + ($env:systemRoot\system32\Configuration\BuiltinProvCache\MSFT_xADDomain) +#> +function Get-TrackingFilename { + [OutputType([String])] + [CmdletBinding()] + param( + [Parameter(Mandatory = $true)] + [String] + $DomainName + ) + + return Join-Path -Path ($env:temp) -ChildPath ('{0}.xADDomain.completed' -f $DomainName) +} + function Get-TargetResource { [OutputType([System.Collections.Hashtable])] @@ -59,6 +100,11 @@ function Get-TargetResource $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) { @@ -93,6 +139,7 @@ function Get-TargetResource { Write-Verbose ($localizedData.DomainNotFound -f $domainFQDN) $domain = @{ }; + # will fall into retry mechanism } catch [System.Security.Authentication.AuthenticationException] { @@ -101,10 +148,27 @@ function Get-TargetResource } catch { - ## Not sure what's gone on here! - throw $_ + $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) + Start-Sleep -Seconds ($retries * $retryIntervalInSeconds) + } + + } while ($domainShouldExist -and ($retries -le $maxRetries) ) + } #end function Get-TargetResource function Test-TargetResource @@ -265,9 +329,11 @@ function Set-TargetResource $installADDSParams['DomainNetbiosName'] = $DomainNetBIOSName; } Install-ADDSForest @installADDSParams; - Write-Verbose -Message ($localizedData.CreatedForest); + 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 diff --git a/DSCResources/MSFT_xADDomainController/MSFT_xADDomainController.psm1 b/DSCResources/MSFT_xADDomainController/MSFT_xADDomainController.psm1 index 59f920cd6..1d6dd83be 100644 --- a/DSCResources/MSFT_xADDomainController/MSFT_xADDomainController.psm1 +++ b/DSCResources/MSFT_xADDomainController/MSFT_xADDomainController.psm1 @@ -132,7 +132,7 @@ function Set-TargetResource { $params.Add("SysvolPath", $SysvolPath) } - if ($SiteName -ne $null) + if ($SiteName -ne $null -and $SiteName -ne "") { $params.Add("SiteName", $SiteName) } diff --git a/README.md b/README.md index f9109e0a7..b0be46e73 100644 --- a/README.md +++ b/README.md @@ -244,6 +244,11 @@ Setting an ODJ Request file path for a configuration that creates a computer acc ### Unreleased +### 2.16.0.0 + +* xAdDomainController: Update to complete fix for SiteName being required field. +* xADDomain: Added retry logic to prevent FaultException to crash in Get-TargetResource on subsequent reboots after a domain is created because the service is not yet running. This error is mostly occur when the resource is used with the DSCExtension on Azure. + ### 2.15.0.0 * xAdDomainController: Fixes SiteName being required field. diff --git a/appveyor.yml b/appveyor.yml index f406fc820..eb95fbf93 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,7 +1,7 @@ #---------------------------------# # environment configuration # #---------------------------------# -version: 2.15.{build}.0 +version: 2.16.{build}.0 install: - git clone https://github.com/PowerShell/DscResource.Tests - ps: | @@ -47,7 +47,7 @@ deploy_script: # Creating project artifact $stagingDirectory = (Resolve-Path ..).Path $manifest = Join-Path $pwd "xActiveDirectory.psd1" - (Get-Content $manifest -Raw).Replace("2.15.0.0", $env:APPVEYOR_BUILD_VERSION) | Out-File $manifest + (Get-Content $manifest -Raw).Replace("2.16.0.0", $env:APPVEYOR_BUILD_VERSION) | Out-File $manifest $zipFilePath = Join-Path $stagingDirectory "$(Split-Path $pwd -Leaf).zip" Add-Type -assemblyname System.IO.Compression.FileSystem [System.IO.Compression.ZipFile]::CreateFromDirectory($pwd, $zipFilePath) diff --git a/xActiveDirectory.psd1 b/xActiveDirectory.psd1 index 591cecdd7..1809222d7 100644 --- a/xActiveDirectory.psd1 +++ b/xActiveDirectory.psd1 @@ -1,6 +1,6 @@ @{ # Version number of this module. -ModuleVersion = '2.15.0.0' +ModuleVersion = '2.16.0.0' # ID used to uniquely identify this module GUID = '9FECD4F6-8F02-4707-99B3-539E940E9FF5' @@ -49,7 +49,8 @@ PrivateData = @{ # IconUri = '' # ReleaseNotes of this module - ReleaseNotes = '* xAdDomainController: Fixes SiteName being required field. + ReleaseNotes = '* xAdDomainController: Update to complete fix for SiteName being required field. +* xADDomain: Added retry logic to prevent FaultException to crash in Get-TargetResource on subsequent reboots after a domain is created because the service is not yet running. This error is mostly occur when the resource is used with the DSCExtension on Azure. ' @@ -62,3 +63,4 @@ PrivateData = @{ +