From 02be28dc0c040c959da155b27ac584cc6e6b2b47 Mon Sep 17 00:00:00 2001 From: Johan Ljunggren Date: Tue, 30 Jul 2019 14:45:03 +0200 Subject: [PATCH] Changes to WaitForADDomain - BREAKING CHANGE: Refactored the resource to handle timeout better and more correctly wait for a specific amount, and at the same time make the resource more intuitive to use. This change has replaced parameters in the resource (issue #343). - Now the resource can use built-in `PsDscRunAsCredential` instead of specifying the `Credential` parameter (issue #367). - New parameter `SiteName` can be used to wait for a domain controller in a specific site in the domain. --- CHANGELOG.md | 12 +- .../MSFT_WaitForADDomain.psm1 | 303 +++++++++++------- .../MSFT_WaitForADDomain.schema.mof | 11 +- .../en-US/MSFT_WaitForADDomain.strings.psd1 | 10 +- .../en-US/about_WaitForADDomain.help.txt | 22 +- Tests/Unit/MSFT_WaitForADDomain.Tests.ps1 | 136 ++++++-- 6 files changed, 327 insertions(+), 167 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e377310cd..5981fd9f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,8 @@ `Credential` in the function `Restore-ADCommonObject` - Removed the alias `DomainAdministratorCredential` from the parameter `Credential` in the function `Get-ADCommonParameters` + - Added function `Find-DomainController`. + - Added function `Get-CurrentUser` (moved from the resource ADKDSKey). - Updated all the examples files to be prefixed with the resource name so they are more easily discovered in PowerShell Gallery and Azure Automation ([issue #416](https://github.com/PowerShell/ActiveDirectoryDsc/issues/416)). @@ -105,7 +107,15 @@ - Added comment-based help ([issue #337](https://github.com/PowerShell/ActiveDirectoryDsc/issues/337)). - Added integration tests ([issue #348](https://github.com/PowerShell/ActiveDirectoryDsc/issues/348)). - Changes to WaitForADDomain - - Added comment-based help ([issue #341](https://github.com/PowerShell/ActiveDirectoryDsc/issues/341)) + - BREAKING CHANGE: Refactored the resource to handle timeout better and + more correctly wait for a specific amount, and at the same time make + the resource more intuitive to use. This change has replaced parameters + in the resource ([issue #343](https://github.com/PowerShell/ActiveDirectoryDsc/issues/343)). + - Now the resource can use built-in `PsDscRunAsCredential` instead of + specifying the `Credential` parameter ([issue #367](https://github.com/PowerShell/ActiveDirectoryDsc/issues/367)). + - New parameter `SiteName` can be used to wait for a domain controller + in a specific site in the domain. + - Added comment-based help ([issue #341](https://github.com/PowerShell/ActiveDirectoryDsc/issues/341)). - Changes to ADDomainController - BREAKING CHANGE: Renamed the parameter `DomainAdministratorCredential` to `Credential` to better indicate that it is possible to impersonate diff --git a/DSCResources/MSFT_WaitForADDomain/MSFT_WaitForADDomain.psm1 b/DSCResources/MSFT_WaitForADDomain/MSFT_WaitForADDomain.psm1 index 730bb3122..6a9f99343 100644 --- a/DSCResources/MSFT_WaitForADDomain/MSFT_WaitForADDomain.psm1 +++ b/DSCResources/MSFT_WaitForADDomain/MSFT_WaitForADDomain.psm1 @@ -6,99 +6,144 @@ Import-Module -Name (Join-Path -Path $script:localizationModulePath -ChildPath ' $script:localizedData = Get-LocalizedData -ResourceName 'MSFT_WaitForADDomain' +# This file is used to remember the number of times the node has been rebooted. +$script:rebootLogFile = Join-Path $env:temp -ChildPath 'WaitForADDomain_Reboot.tmp' + <# .SYNOPSIS - Gets the current state of the specified Active Directory to see if it - is available. + Returns the current state of the specified Active Directory domain. .PARAMETER DomainName - The name of the Active Directory domain to wait for. + Specifies the fully qualified domain name to wait for. - .PARAMETER DomainUserCredential - The user account credentials to use to perform this task. + .PARAMETER SiteName + Specifies the site in the domain where to look for a domain controller. - .PARAMETER RetryIntervalSec - The interval in seconds between retry attempts. Default value is 60. + .PARAMETER Credential + Specifies the credentials that are used when accessing the domain, + unless the built-in PsDscRunAsCredential is used. - .PARAMETER RetryCount - The number of retries before failing. Default value is 10. + .PARAMETER WaitTimeout + Specifies the timeout in seconds that the resource will wait for the + domain to be accessible. Default value is 300 seconds. - .PARAMETER RebootRetryCount - The number of times to reboot after failing and then restart retrying. - Default value is 0 (zero). + .PARAMETER RebootCount + Specifies the number of times the node will be reboot in an effort to + connect to the domain. #> function Get-TargetResource { [OutputType([System.Collections.Hashtable])] param ( - [Parameter(Mandatory = $true)] [System.String] $DomainName, [Parameter()] - [System.Management.Automation.PSCredential] - $DomainUserCredential, + [System.String] + $SiteName, [Parameter()] - [System.UInt64] - $RetryIntervalSec = 60, + [System.Management.Automation.PSCredential] + $Credential, [Parameter()] - [System.UInt32] - $RetryCount = 10, + [System.UInt64] + $WaitTimeout = 300, [Parameter()] [System.UInt32] - $RebootRetryCount = 0 + $RebootCount ) - if ($DomainUserCredential) + $findDomainControllerParameters = @{ + DomainName = $DomainName + } + + Write-Verbose -Message ($script:localizedData.SearchDomainController -f $DomainName) + + if ($PSBoundParameters.ContainsKey('SiteName')) { - $convertToCimCredential = New-CimInstance -ClassName MSFT_Credential -Namespace 'root/microsoft/windows/desiredstateconfiguration' -ClientOnly -Property @{ - Username = [System.String] $DomainUserCredential.UserName - Password = [System.String] $null - } + $findDomainControllerParameters['SiteName'] = $SiteName + + Write-Verbose -Message ($script:localizedData.SearchInSiteOnly -f $SiteName) + } + + if ($PSBoundParameters.ContainsKey('Credential')) + { + $cimCredentialInstance = New-CimCredentialInstance -Credential $Credential + + $findDomainControllerParameters['Credential'] = $Credential + + Write-Verbose -Message ($script:localizedData.ImpersonatingCredentials -f $Credential.UserName) } else { - $convertToCimCredential = $null + if ($null -ne $PsDscContext.RunAsUser) + { + # Running using PsDscRunAsCredential + Write-Verbose -Message ($script:localizedData.ImpersonatingCredentials -f $PsDscContext.RunAsUser) + } + else + { + # Running as SYSTEM or current user. + Write-Verbose -Message ($script:localizedData.ImpersonatingCredentials -f (Get-CurrentUser).Name) + } + + $cimCredentialInstance = $null } - Write-Verbose -Message ($script:localizedData.GetDomain -f $DomainName) + $currentDomainController = Find-DomainController @findDomainControllerParameters + + if ($currentDomainController) + { + $domainFound = $true + $domainControllerSiteName = $currentDomainController.SiteName - $domain = Get-Domain -DomainName $DomainName -DomainUserCredential $DomainUserCredential + Write-Verbose -Message $script:localizedData.FoundDomainController + + } + else + { + $domainFound = $false + $domainControllerSiteName = $null + + Write-Verbose -Message $script:localizedData.NoFoundDomainController + } return @{ - DomainName = $domain.Name - DomainUserCredential = $convertToCimCredential - RetryIntervalSec = $RetryIntervalSec - RetryCount = $RetryCount - RebootRetryCount = $RebootRetryCount + DomainName = $DomainName + SiteName = $domainControllerSiteName + Credential = $cimCredentialInstance + WaitTimeout = $WaitTimeout + RebootCount = $RebootCount + IsAvailable = $domainFound } } <# .SYNOPSIS - Sets the current state of the specified Active Directory to see if a - reboot is required. + Waits for the specified Active Directory domain to have a domain + controller that can serve connections. .PARAMETER DomainName - The name of the Active Directory domain to wait for. + Specifies the fully qualified domain name to wait for. - .PARAMETER DomainUserCredential - The user account credentials to use to perform this task. + .PARAMETER SiteName + Specifies the site in the domain where to look for a domain controller. - .PARAMETER RetryIntervalSec - The interval in seconds between retry attempts. Default value is 60. + .PARAMETER Credential + Specifies the credentials that are used when accessing the domain, + unless the built-in PsDscRunAsCredential is used. - .PARAMETER RetryCount - The number of retries before failing. Default value is 10. + .PARAMETER WaitTimeout + Specifies the timeout in seconds that the resource will wait for the + domain to be accessible. Default value is 300 seconds. - .PARAMETER RebootRetryCount - The number of times to reboot after failing and then restart retrying. - Default value is 0 (zero). + .PARAMETER RebootCount + Specifies the number of times the node will be reboot in an effort to + connect to the domain. #> function Set-TargetResource { @@ -120,25 +165,22 @@ function Set-TargetResource $DomainName, [Parameter()] - [System.Management.Automation.PSCredential] - $DomainUserCredential, + [System.String] + $SiteName, [Parameter()] - [System.UInt64] - $RetryIntervalSec = 60, + [System.Management.Automation.PSCredential] + $Credential, [Parameter()] - [System.UInt32] - $RetryCount = 10, + [System.UInt64] + $WaitTimeout = 300, [Parameter()] [System.UInt32] - $RebootRetryCount = 0 - + $RebootCount ) - $rebootLogFile = "$env:temp\WaitForADDomain_Reboot.tmp" - for ($count = 0; $count -lt $RetryCount; $count++) { $domain = Get-Domain -DomainName $DomainName -DomainUserCredential $DomainUserCredential @@ -192,24 +234,26 @@ function Set-TargetResource <# .SYNOPSIS - Tests the current state of the specified Active Directory to see if it - is available. + Determines if the specified Active Directory domain have a domain controller + that can serve connections. .PARAMETER DomainName - The name of the Active Directory domain to wait for. + Specifies the fully qualified domain name to wait for. - .PARAMETER DomainUserCredential - The user account credentials to use to perform this task. + .PARAMETER SiteName + Specifies the site in the domain where to look for a domain controller. - .PARAMETER RetryIntervalSec - The interval in seconds between retry attempts. Default value is 60. + .PARAMETER Credential + Specifies the credentials that are used when accessing the domain, + unless the built-in PsDscRunAsCredential is used. - .PARAMETER RetryCount - The number of retries before failing. Default value is 10. + .PARAMETER WaitTimeout + Specifies the timeout in seconds that the resource will wait for the + domain to be accessible. Default value is 300 seconds. - .PARAMETER RebootRetryCount - The number of times to reboot after failing and then restart retrying. - Default value is 0 (zero). + .PARAMETER RebootCount + Specifies the number of times the node will be reboot in an effort to + connect to the domain. #> function Test-TargetResource { @@ -221,92 +265,127 @@ function Test-TargetResource $DomainName, [Parameter()] - [System.Management.Automation.PSCredential] - $DomainUserCredential, + [System.String] + $SiteName, [Parameter()] - [System.UInt64] - $RetryIntervalSec = 60, + [System.Management.Automation.PSCredential] + $Credential, [Parameter()] - [System.UInt32] - $RetryCount = 10, + [System.UInt64] + $WaitTimeout = 300, [Parameter()] [System.UInt32] - $RebootRetryCount = 0 + $RebootCount + ) + Write-Verbose -Message ( + $script:localizedData.TestConfiguration -f $DomainName ) - $rebootLogFile = "$env:temp\WaitForADDomain_Reboot.tmp" + # Only pass properties that could be used when fetching the domain controller. + $compareTargetResourceStateParameters = @{ + DomainName = $DomainName + SiteName = $SiteName + Credential = $Credential + } - $domain = Get-Domain -DomainName $DomainName -DomainUserCredential $DomainUserCredential + <# + This returns array of hashtables which contain the properties ParameterName, + Expected, Actual, and InDesiredState. In this case only the property + 'IsAvailable' will be returned. + #> + $compareTargetResourceStateResult = Compare-TargetResourceState @compareTargetResourceStateParameters - if ($domain) + if ($false -in $compareTargetResourceStateResult.InDesiredState) { - if ($RebootRetryCount -gt 0) - { - Remove-Item $rebootLogFile -ErrorAction SilentlyContinue - } - - Write-Verbose -Message ($script:localizedData.DomainInDesiredState -f $DomainName) + $testTargetResourceReturnValue = $false - return $true + Write-Verbose -Message ($script:localizedData.DomainNotInDesiredState -f $DomainName) } else { - Write-Verbose -Message ($script:localizedData.DomainNotInDesiredState -f $DomainName) - return $false + $testTargetResourceReturnValue = $true + + if ($PSBoundParameters.ContainsKey('RebootCount') -and $RebootCount -gt 0 ) + { + if (Test-Path -Path $script:rebootLogFile) + { + Remove-Item $script:rebootLogFile -Force -ErrorAction SilentlyContinue + } + } + + Write-Verbose -Message ($script:localizedData.DomainInDesiredState -f $DomainName) } + + return $testTargetResourceReturnValue } <# .SYNOPSIS - Gets the specified Active Directory domain + Compares the properties in the current state with the properties of the + desired state and returns a hashtable with the comparison result. .PARAMETER DomainName - The name of the Active Directory domain to wait for. + Specifies the fully qualified domain name to wait for. - .PARAMETER DomainUserCredential - The user account credentials to use to perform this task. + .PARAMETER SiteName + Specifies the site in the domain where to look for a domain controller. + + .PARAMETER Credential + Specifies the credentials that are used when accessing the domain, + unless the built-in PsDscRunAsCredential is used. #> -function Get-Domain +function Compare-TargetResourceState { - [OutputType([PSObject])] + [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [System.String] $DomainName, + [Parameter()] + [System.String] + $SiteName, + [Parameter()] [System.Management.Automation.PSCredential] - $DomainUserCredential + $Credential ) - Write-Verbose -Message ($script:localizedData.CheckDomain -f $DomainName) - - if ($DomainUserCredential) - { - $context = New-Object -TypeName 'System.DirectoryServices.ActiveDirectory.DirectoryContext' -ArgumentList @('Domain', $DomainName, $DomainUserCredential.UserName, $DomainUserCredential.GetNetworkCredential().Password) - } - else - { - $context = New-Object -TypeName 'System.DirectoryServices.ActiveDirectory.DirectoryContext' -ArgumentList @('Domain', $DomainName) + $getTargetResourceParameters = @{ + DomainName = $DomainName + SiteName = $SiteName + Credential = $Credential } - try - { - $domain = ([System.DirectoryServices.ActiveDirectory.DomainController]::FindOne($context)).domain.ToString() + <# + Removes any keys not bound to $PSBoundParameters. + Need the @() around this to get a new array to enumerate. + #> + @($getTargetResourceParameters.Keys) | ForEach-Object { + if (-not $PSBoundParameters.ContainsKey($_)) + { + $getTargetResourceParameters.Remove($_) + } + } - Write-Verbose -Message ($script:localizedData.FoundDomain -f $DomainName) + $getTargetResourceResult = Get-TargetResource @getTargetResourceParameters - return @{ - Name = $domain + <# + Only interested in the read-only property IsAvailable, which + should always be compared to the value $true. + #> + $compareResourcePropertyStateParameters = @{ + CurrentValues = $getTargetResourceResult + DesiredValues = @{ + IsAvailable = $true } + Properties = 'IsAvailable' } - catch - { - Write-Verbose -Message ($script:localizedData.DomainNotFound -f $DomainName) - } + + return Compare-ResourcePropertyState @compareResourcePropertyStateParameters } diff --git a/DSCResources/MSFT_WaitForADDomain/MSFT_WaitForADDomain.schema.mof b/DSCResources/MSFT_WaitForADDomain/MSFT_WaitForADDomain.schema.mof index 03674d3b8..9f39cbb19 100644 --- a/DSCResources/MSFT_WaitForADDomain/MSFT_WaitForADDomain.schema.mof +++ b/DSCResources/MSFT_WaitForADDomain/MSFT_WaitForADDomain.schema.mof @@ -1,9 +1,10 @@ [ClassVersion("1.0.1.0"), FriendlyName("WaitForADDomain")] class MSFT_WaitForADDomain : OMI_BaseResource { - [Key, Description("The name of the Active Directory domain to wait for.")] String DomainName; - [Write, Description("The user account credentials to use to perform this task."), EmbeddedInstance("MSFT_Credential")] String DomainUserCredential; - [Write, Description("The interval in seconds between retry attempts. Default value is 60.")] UInt64 RetryIntervalSec; - [Write, Description("The number of retries before failing. Default value is 10.")] UInt32 RetryCount; - [Write, Description("The number of times to reboot after failing and then restart retrying. Default value is 0 (zero).")] UInt32 RebootRetryCount; + [Key, Description("Specifies the fully qualified domain name to wait for.")] String DomainName; + [Write, Description("Specifies the site in the domain where to look for a domain controller.")] String SiteName; + [Write, Description("Specifies the credentials that are used when accessing the domain, unless the built-in PsDscRunAsCredential is used."), EmbeddedInstance("MSFT_Credential")] String Credential; + [Write, Description("Specifies the timeout in seconds that the resource will wait for the domain to be accessible. Default value is 300 seconds.")] UInt64 WaitTimeout; + [Write, Description("Specifies the number of times the node will be reboot in an effort to connect to the domain.")] UInt32 RebootCount; + [Read, Description("Returns a value indicating if a domain controller was found.")] Boolean IsAvailable; }; diff --git a/DSCResources/MSFT_WaitForADDomain/en-US/MSFT_WaitForADDomain.strings.psd1 b/DSCResources/MSFT_WaitForADDomain/en-US/MSFT_WaitForADDomain.strings.psd1 index 30c594028..f4d1d4a64 100644 --- a/DSCResources/MSFT_WaitForADDomain/en-US/MSFT_WaitForADDomain.strings.psd1 +++ b/DSCResources/MSFT_WaitForADDomain/en-US/MSFT_WaitForADDomain.strings.psd1 @@ -1,13 +1,15 @@ # culture='en-US' ConvertFrom-StringData @' - GetDomain = Getting Domain '{0}'. (WFADD0001) + SearchDomainController = Searching for a domain controller in the domain '{0}'. (WFADD0001) DomainNotFoundRetrying = Domain '{0}' not found. Will retry again after {1} seconds. (WFADD0002) DomainNotFoundRebooting = Domain '{0}' not found after {1} attempts with {2} sec interval. Rebooting. Reboot attempt number {3} of {4}. (WFADD0003) DomainNotFoundAfterReboot = Domain '{0}' NOT found after {1} Reboot attempts. (WFADD0004) DomainNotFoundAfterRetry = Domain '{0}' NOT found after {1} attempts. (WFADD0005) DomainInDesiredState = Domain '{0}' is in the desired state. (WFADD0006) DomainNotInDesiredState = Domain '{0}' is not in the desired state. (WFADD0007) - CheckDomain = Checking for domain '{0}'. (WFADD0008) - FoundDomain = Found domain '{0}'. (WFADD0009) - DomainNotFound = Domain '{0}' not found. (WFADD0010) + FoundDomainController = Found domain controller. (WFADD0009) + NoFoundDomainController = No domain controller was found. (WFADD0010) + ImpersonatingCredentials = Impersonating the credentials '{0}' when looking for a domain controller. (WFADD0011) + SearchInSiteOnly = Limiting the search scope for a domain controller to the site '{0}'. (WFADD0012) + TestConfiguration = Determining the current state of the Active Directory domain '{0}'. (WFADD0013) '@ diff --git a/DSCResources/MSFT_WaitForADDomain/en-US/about_WaitForADDomain.help.txt b/DSCResources/MSFT_WaitForADDomain/en-US/about_WaitForADDomain.help.txt index 84b091723..6945f010d 100644 --- a/DSCResources/MSFT_WaitForADDomain/en-US/about_WaitForADDomain.help.txt +++ b/DSCResources/MSFT_WaitForADDomain/en-US/about_WaitForADDomain.help.txt @@ -10,23 +10,23 @@ .PARAMETER DomainName Key - String - The name of the Active Directory domain to wait for. + Specifies the fully qualified domain name to wait for. -.PARAMETER DomainUserCredential +.PARAMETER SiteName Write - String - The user account credentials to use to perform this task. + Specifies the site in the domain where to look for a domain controller. -.PARAMETER RetryIntervalSec - Write - UInt64 - The interval in seconds between retry attempts. Default value is 60. +.PARAMETER Credential + Write - String + Specifies the credentials that are used when accessing the domain, unless the built-in PsDscRunAsCredential is used. -.PARAMETER RetryCount - Write - UInt32 - The number of retries before failing. Default value is 10. +.PARAMETER WaitTimeout + Write - UInt64 + Specifies the timeout in seconds that the resource will wait for the domain to be accessible. Default value is 300 seconds. -.PARAMETER RebootRetryCount +.PARAMETER RebootCount Write - UInt32 - The number of times to reboot after failing and then restart retrying. Default value is 0 (zero). + Specifies the number of times the node will be reboot in an effort to connect to the domain. .EXAMPLE 1 diff --git a/Tests/Unit/MSFT_WaitForADDomain.Tests.ps1 b/Tests/Unit/MSFT_WaitForADDomain.Tests.ps1 index acd031149..902c8ca68 100644 --- a/Tests/Unit/MSFT_WaitForADDomain.Tests.ps1 +++ b/Tests/Unit/MSFT_WaitForADDomain.Tests.ps1 @@ -36,47 +36,115 @@ try Invoke-TestSetup InModuleScope $script:dscResourceName { - $domainUserCredential = New-Object -TypeName 'System.Management.Automation.PSCredential' -ArgumentList @( - 'Username', - $(ConvertTo-SecureString -String 'Password' -AsPlainText -Force) + $mockUserName = 'User1' + $mockDomainUserCredential = New-Object -TypeName 'System.Management.Automation.PSCredential' -ArgumentList @( + $mockUserName, + (ConvertTo-SecureString -String 'Password' -AsPlainText -Force) ) - $domainName = 'example.com' - $testParams = @{ - DomainName = $domainName - DomainUserCredential = $domainUserCredential - RetryIntervalSec = 10 - RetryCount = 5 - } + $mockDomainName = 'example.com' + $mockSiteName = 'Europe' - $rebootTestParams = @{ - DomainName = $domainName - DomainUserCredential = $domainUserCredential - RetryIntervalSec = 10 - RetryCount = 5 - RebootRetryCount = 3 + $mockDefaultParameters = @{ + DomainName = $mockDomainName + Verbose = $true } - $fakeDomainObject = @{Name = $domainName} - #region Function Get-TargetResource Describe 'WaitForADDomain\Get-TargetResource' { - It 'Returns a "System.Collections.Hashtable" object type' { - Mock -CommandName Get-Domain -MockWith {return $fakeDomainObject} - $targetResource = Get-TargetResource @testParams - $targetResource -is [System.Collections.Hashtable] | Should -Be $true - } - - It "Returns DomainName = $($testParams.DomainName) when domain is found" { - Mock -CommandName Get-Domain -MockWith {return $fakeDomainObject} - $targetResource = Get-TargetResource @testParams - $targetResource.DomainName | Should -Be $testParams.DomainName - } - - It "Returns an empty DomainName when domain is not found" { - Mock -CommandName Get-Domain - $targetResource = Get-TargetResource @testParams - $targetResource.DomainName | Should -Be $null + Context 'When the system is in the desired state' { + Context 'When no domain controller is found in the domain' { + BeforeAll { + Mock -CommandName Find-DomainController -MockWith { + return $null + } + + $getTargetResourceParameters = $mockDefaultParameters.Clone() + } + + It 'Should return the same values as passed as parameters' { + $result = Get-TargetResource @getTargetResourceParameters + $result.DomainName | Should -Be $mockDomainName + } + + It 'Should return default value for property WaitTimeout' { + $getTargetResourceResult = Get-TargetResource @getTargetResourceParameters + $getTargetResourceResult.WaitTimeout | Should -Be 300 + } + + It 'Should return $null for the rest of the properties' { + $getTargetResourceResult = Get-TargetResource @getTargetResourceParameters + $getTargetResourceResult.SiteName | Should -BeNullOrEmpty + $getTargetResourceResult.Credential | Should -BeNullOrEmpty + $getTargetResourceResult.RebootCount | Should -Be 0 + } + } + + Context 'When a domain controller is found in the domain' { + Context 'When using the default parameters' { + BeforeAll { + Mock -CommandName Find-DomainController -MockWith { + return New-Object -TypeName PSObject | + Add-Member -MemberType ScriptProperty -Name 'Domain' -Value { + New-Object -TypeName PSObject | + Add-Member -MemberType ScriptMethod -Name 'ToString' -Value { + return $mockDomainName + } -PassThru -Force + } -PassThru | + Add-Member -MemberType NoteProperty -Name 'SiteName' -Value $mockSiteName -PassThru -Force + } + + $getTargetResourceParameters = $mockDefaultParameters.Clone() + } + + It 'Should return the same values as passed as parameters' { + $result = Get-TargetResource @getTargetResourceParameters + $result.DomainName | Should -Be $mockDomainName + } + + It 'Should return default value for property WaitTimeout' { + $getTargetResourceResult = Get-TargetResource @getTargetResourceParameters + $getTargetResourceResult.WaitTimeout | Should -Be 300 + } + + It 'Should return $null for the rest of the properties' { + $getTargetResourceResult = Get-TargetResource @getTargetResourceParameters + $getTargetResourceResult.SiteName | Should -Be 'Europe' + $getTargetResourceResult.Credential | Should -BeNullOrEmpty + $getTargetResourceResult.RebootCount | Should -Be 0 + } + } + + Context 'When using all available parameters' { + BeforeAll { + Mock -CommandName Find-DomainController -MockWith { + return New-Object -TypeName PSObject | + Add-Member -MemberType ScriptProperty -Name 'Domain' -Value { + New-Object -TypeName PSObject | + Add-Member -MemberType ScriptMethod -Name 'ToString' -Value { + return $mockDomainName + } -PassThru -Force + } -PassThru | + Add-Member -MemberType NoteProperty -Name 'SiteName' -Value $mockSiteName -PassThru -Force + } + + $getTargetResourceParameters = $mockDefaultParameters.Clone() + $getTargetResourceParameters['Credential'] = $mockDomainUserCredential + $getTargetResourceParameters['SiteName'] = 'Europe' + $getTargetResourceParameters['WaitTimeout'] = 600 + $getTargetResourceParameters['RebootCount'] = 2 + } + + It 'Should return the same values as passed as parameters' { + $result = Get-TargetResource @getTargetResourceParameters + $result.DomainName | Should -Be $mockDomainName + $result.SiteName | Should -Be 'Europe' + $result.WaitTimeout | Should -Be 600 + $result.RebootCount | Should -Be 2 + $result.Credential.UserName | Should -Be $mockUserName + } + } + } } } #endregion