Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
…into Issue27

Conflicts:
	README.md
  • Loading branch information
iainbrighton committed Feb 15, 2016
2 parents c4a8d9f + ea3d03d commit 1f9b865
Show file tree
Hide file tree
Showing 4 changed files with 225 additions and 17 deletions.
37 changes: 34 additions & 3 deletions DSCResources/MSFT_xADCommon/MSFT_xADCommon.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@ data localizedString
IncludeAndExcludeConflictError = The member '{0}' is included in both '{1}' and '{2}' parameter values. The same member must not be included in both '{1}' and '{2}' parameter values.
IncludeAndExcludeAreEmptyError = The '{0}' and '{1}' parameters are either both null or empty. At least one member must be specified in one of these parameters.
CheckingMembers = Checking for '{0}' members.
CheckingMembers = Checking for '{0}' members.
MembershipCountMismatch = Membership count is not correct. Expected '{0}' members, actual '{1}' members.
MemberNotInDesiredState = Member '{0}' is not in the desired state.
RemovingDuplicateMember = Removing duplicate member '{0}' definition.
MembershipInDesiredState = Membership is in the desired state.
MembershipNotDesiredState = Membership is NOT in the desired state.
MembershipNotDesiredState = Membership is NOT in the desired state.
CheckingDomain = Checking for domain '{0}'.
'@
}

Expand All @@ -38,15 +39,18 @@ function Assert-Module
# Internal function to test whether computer is a member of a domain
function Test-DomainMember {
[CmdletBinding()]
[OutputType([System.Boolean])]
param ( )
$isDomainMember = [System.Boolean] (Get-CimInstance -ClassName Win32_ComputerSystem -Verbose:$false).PartOfDomain;
$isDomainMember = [System.Boolean] (Get-CimInstance -ClassName Win32_ComputerSystem -Verbose:$false).PartOfDomain;
return $isDomainMember;
}

# Internal function to build domain FQDN
function Resolve-DomainFQDN {
[CmdletBinding()]
param (
[Parameter(Mandatory)]
[OutputType([System.String])]
[System.String] $DomainName,

[Parameter()] [AllowNull()]
Expand All @@ -60,6 +64,32 @@ function Resolve-DomainFQDN {
return $domainFQDN
}

## Internal function to test/ domain availability
function Test-ADDomain
{
[CmdletBinding()]
[OutputType([System.Boolean])]
param
(
[Parameter(Mandatory)]
[String] $DomainName,

[Parameter()]
[PSCredential] $Credential
)
Write-Verbose -Message ($localizedString.CheckingDomain -f $DomainName);
$ldapDomain = 'LDAP://{0}' -f $DomainName;
if ($PSBoundParameters.ContainsKey('Credential'))
{
$domain = New-Object DirectoryServices.DirectoryEntry($ldapDomain, $Credential.UserName, $Credential.GetNetworkCredential().Password);
}
else
{
$domain = New-Object DirectoryServices.DirectoryEntry($ldapDomain);
}
return ($null -ne $domain);
}

# Internal function to get an Active Directory object's parent Distinguished Name
function Get-ADObjectParentDN
{
Expand Down Expand Up @@ -88,6 +118,7 @@ function Get-ADObjectParentDN
http://www.uvm.edu/~gcd/code-license/
#>
[CmdletBinding()]
[OutputType([System.String])]
param
(
[Parameter(Mandatory)]
Expand Down
53 changes: 39 additions & 14 deletions DSCResources/MSFT_xWaitForADDomain/MSFT_xWaitForADDomain.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,16 @@ function Get-TargetResource

[UInt32]$RetryCount = 5
)

$convertToCimCredential = New-CimInstance -ClassName MSFT_Credential -Property @{Username=[string]$DomainUserCredential.UserName; Password=[string]$null} -Namespace root/microsoft/windows/desiredstateconfiguration -ClientOnly

$cimInstanceParams = @{
ClassName = 'MSFT_Credential'
Property = @{Username=[string]$DomainUserCredential.UserName; Password=[string]$null}
Namespace = 'root/microsoft/windows/desiredstateconfiguration'
ClientOnly = $true
}
$convertToCimCredential = New-CimInstance @cimInstanceParams
$domain = Get-Domain @PSBoundParameters
$returnValue = @{
DomainName = $DomainName
DomainName = $domain.name
DomainUserCredential = $convertToCimCredential
RetryIntervalSec = $RetryIntervalSec
RetryCount = $RetryCount
Expand All @@ -42,18 +47,17 @@ function Set-TargetResource
)

$domainFound = $false
Write-Verbose -Message "Checking for domain $DomainName ..."


for($count = 0; $count -lt $RetryCount; $count++)
{
try
$domain = Get-Domain @PSBoundParameters
if ($domain.name)
{
$domain = Get-ADDomain -Identity $DomainName -Credential $DomainUserCredential
Write-Verbose -Message "Found domain $DomainName"
$domainFound = $true
break;
break
}
Catch
else
{
Write-Verbose -Message "Domain $DomainName not found. Will retry again after $RetryIntervalSec sec"
Start-Sleep -Seconds $RetryIntervalSec
Expand All @@ -80,17 +84,38 @@ function Test-TargetResource
[UInt32]$RetryCount = 5
)

Write-Verbose -Message "Checking for domain $DomainName ..."
try
$domain = Get-Domain @PSBoundParameters
if ($domain.name)
{
$domain = Get-ADDomain -Identity $DomainName -Credential $DomainUserCredential
Write-Verbose -Message "Found domain $DomainName"
$true
}
Catch
else
{
Write-Verbose -Message "Domain $DomainName not found"
$false
}
}

function Get-Domain
{
[OutputType([System.Boolean])]
param
(
[Parameter(Mandatory)]
[String]$DomainName,

[Parameter(Mandatory)]
[PSCredential]$DomainUserCredential,

[UInt64]$RetryIntervalSec = 10,

[UInt32]$RetryCount = 5
)
Write-Verbose -Message "Checking for domain $DomainName ..."
New-Object DirectoryServices.DirectoryEntry(
"LDAP://$DomainName",
$DomainUserCredential.UserName,
$DomainUserCredential.GetNetworkCredential().Password
)
}
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ The xADOrganizational Unit DSC resource will manage OUs within Active Directory.

### Unreleased

* xWaitForADDomain: Updated to make it compatible with systems that don't have the ActiveDirectory module installed, and to allow it to function with domains/forests that don't have a domain controller with Active Directory Web Services running.
* xADDomain: Added check for Active Directory cmdlets.
* xADDomain: Added additional error trapping, verbose and diagnostic information.
* xADDomain: Added unit test coverage.
Expand Down
151 changes: 151 additions & 0 deletions Tests/Unit/MSFT_xWaitForADDomain.Tests.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
$Global:DSCModuleName = 'xActiveDirectory'
$Global:DSCResourceName = 'MSFT_xWaitForADDomain'

#region HEADER
[String] $moduleRoot = Split-Path -Parent (Split-Path -Parent (Split-Path -Parent $Script:MyInvocation.MyCommand.Path))
if ( (-not (Test-Path -Path (Join-Path -Path $moduleRoot -ChildPath 'DSCResource.Tests'))) -or `
(-not (Test-Path -Path (Join-Path -Path $moduleRoot -ChildPath 'DSCResource.Tests\TestHelper.psm1'))) )
{
& git @('clone','https://github.com/PowerShell/DscResource.Tests.git',(Join-Path -Path $moduleRoot -ChildPath '\DSCResource.Tests\'))
}
else
{
& git @('-C',(Join-Path -Path $moduleRoot -ChildPath '\DSCResource.Tests\'),'pull')
}
Import-Module (Join-Path -Path $moduleRoot -ChildPath 'DSCResource.Tests\TestHelper.psm1') -Force
$TestEnvironment = Initialize-TestEnvironment `
-DSCModuleName $Global:DSCModuleName `
-DSCResourceName $Global:DSCResourceName `
-TestType Unit
#endregion

# Begin Testing
try
{

#region Pester Tests

# The InModuleScope command allows you to perform white-box unit testing on the internal
# (non-exported) code of a Script Module.
InModuleScope $Global:DSCResourceName {

#region Pester Test Initialization
$password = 'Password' | ConvertTo-SecureString -AsPlainText -Force
$DomainUserCredential = New-Object pscredential('Username', $password)
$domainName = 'example.com'
$testParams = @{
DomainName = $domainName
DomainUserCredential = $DomainUserCredential
RetryIntervalSec = 10
RetryCount = 5
}
$fakeDomainObject = @{Name = $domainName}
#endregion


#region Function Get-TargetResource
Describe "$($Global:DSCResourceName)\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 -MockWith {}
$targetResource = Get-TargetResource @testParams
$targetResource.DomainName | Should Be $null
}
}
#endregion


#region Function Test-TargetResource
Describe "$($Global:DSCResourceName)\Test-TargetResource" {
It 'Returns a "System.Boolean" object type' {
Mock -CommandName Get-Domain -MockWith {return $fakeDomainObject}
$targetResource = Test-TargetResource @testParams
$targetResource -is [System.Boolean] | Should Be $true
}

It 'Passes when domain found' {
Mock -CommandName Get-Domain -MockWith {return $fakeDomainObject}
Test-TargetResource @testParams | Should Be $true
}

It 'Fails when domain not found' {
Mock -CommandName Get-Domain -MockWith {}
Test-TargetResource @testParams | Should Be $false
}
}
#endregion


#region Function Set-TargetResource
Describe "$($Global:DSCResourceName)\Set-TargetResource" {
It "Doesn't throw exception and doesn't call Start-Sleep and Clear-DnsClientCache when domain found" {
Mock -CommandName Get-Domain -MockWith {return $fakeDomainObject}
Mock -CommandName Start-Sleep -MockWith {}
Mock -CommandName Clear-DnsClientCache -MockWith {}
{Set-TargetResource @testParams} | Should Not Throw
Assert-MockCalled -CommandName Get-Domain -Times 1 -Exactly -Scope It
Assert-MockCalled -CommandName Start-Sleep -Times 0 -Scope It
Assert-MockCalled -CommandName Clear-DnsClientCache -Times 0 -Scope It
}

It "Doesn't call Start-Sleep and Clear-DnsClientCache when domain found" {
Mock -CommandName Get-Domain -MockWith {return $fakeDomainObject}
Mock -CommandName Start-Sleep -MockWith {}
Mock -CommandName Clear-DnsClientCache -MockWith {}
{Set-TargetResource @testParams} | Should Not Throw
Assert-MockCalled -CommandName Start-Sleep -Times 0 -Scope It
Assert-MockCalled -CommandName Clear-DnsClientCache -Times 0 -Scope It
}

It "Throws exception when domain not found after $($testParams.RetryCount) retries" {
Mock -CommandName Get-Domain -MockWith {}
Mock -CommandName Start-Sleep -MockWith {}
Mock -CommandName Clear-DnsClientCache -MockWith {}
{Set-TargetResource @testParams} | Should Throw
}

It "Calls Get-Domain exactly $($testParams.RetryCount) times when domain not found" {
Mock -CommandName Get-Domain -MockWith {}
Mock -CommandName Start-Sleep -MockWith {}
Mock -CommandName Clear-DnsClientCache -MockWith {}
{Set-TargetResource @testParams} | Should Throw
Assert-MockCalled -CommandName Get-Domain -Times $testParams.RetryCount -Exactly -Scope It
}

It "Calls Start-Sleep exactly $($testParams.RetryCount) times when domain not found" {
Mock -CommandName Get-Domain -MockWith {}
Mock -CommandName Start-Sleep -MockWith {}
Mock -CommandName Clear-DnsClientCache -MockWith {}
{Set-TargetResource @testParams} | Should Throw
Assert-MockCalled -CommandName Start-Sleep -Times $testParams.RetryCount -Exactly -Scope It
}

It "Calls Clear-DnsClientCache exactly $($testParams.RetryCount) times when domain not found" {
Mock -CommandName Get-Domain -MockWith {}
Mock -CommandName Start-Sleep -MockWith {}
Mock -CommandName Clear-DnsClientCache -MockWith {}
{Set-TargetResource @testParams} | Should Throw
Assert-MockCalled -CommandName Clear-DnsClientCache -Times $testParams.RetryCount -Exactly -Scope It
}
}
#endregion
}
#endregion
}
finally
{
#region FOOTER
Restore-TestEnvironment -TestEnvironment $TestEnvironment
#endregion
}

0 comments on commit 1f9b865

Please sign in to comment.