Skip to content

Commit

Permalink
Merge pull request #222 from X-Guardian/RenameComputer-Fix
Browse files Browse the repository at this point in the history
xComputer: Fix for Error When Joining a Domain and Renaming a Computer when JoinOU is specified
  • Loading branch information
PlagueHO authored Jun 27, 2019
2 parents 6ec8840 + 1955672 commit 75152fc
Show file tree
Hide file tree
Showing 4 changed files with 169 additions and 2 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

- xComputer:
- Fix for 'directory service is busy' error when joining a domain and renaming
a computer when JoinOU is specified - Fixes [Issue #221](https://github.com/PowerShell/ComputerManagementDsc/issues/221).

## 6.4.0.0

- ScheduledTask:
Expand Down
29 changes: 28 additions & 1 deletion DSCResources/MSFT_Computer/MSFT_Computer.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ $script:localizedData = Get-LocalizedData `
-ResourceName 'MSFT_Computer' `
-ResourcePath (Split-Path -Parent $Script:MyInvocation.MyCommand.Path)

$FailToRenameAfterJoinDomainErrorId = 'FailToRenameAfterJoinDomain,Microsoft.PowerShell.Commands.AddComputerCommand'

<#
.SYNOPSIS
Gets the current state of the computer.
Expand Down Expand Up @@ -251,7 +253,32 @@ function Set-TargetResource
}

# Rename the computer, and join it to the domain.
Add-Computer @addComputerParameters
try
{
Add-Computer @addComputerParameters
}
catch [System.InvalidOperationException]
{
<#
If the rename failed during the domain join, re-try the rename.
References to this issue:
https://social.technet.microsoft.com/Forums/windowsserver/en-US/81105b18-b1ff-4fcc-ae5c-2c1a7cf7bf3d/addcomputer-to-domain-with-new-name-returns-error
https://powershell.org/forums/topic/the-directory-service-is-busy/
#>
if ($_.FullyQualifiedErrorId -eq $failToRenameAfterJoinDomainErrorId)
{
Write-Verbose -Message $script:localizedData.FailToRenameAfterJoinDomainMessage
Rename-Computer -NewName $Name -DomainCredential $Credential
}
else
{
New-InvalidOperationException -ErrorRecord $_
}
}
catch
{
throw $_
}

if ($rename)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ ConvertFrom-StringData @'
RenamedComputerMessage = Renamed computer to '{0}'.
RenamedComputerAndJoinedDomainMessage = Renamed computer to '{0}' and added to the domain '{1}'.
JoinedDomainMessage = Added computer to domain '{0}'.
FailToRenameAfterJoinDomainMessage = Failed to rename the computer during the domain join. Re-trying the rename.
RenamedComputerAndJoinedWorkgroupMessage = Renamed computer to '{0}' and addded to workgroup '{1}'.
JoinedWorkgroupMessage = Added computer to workgroup '{0}'.
CredentialsNotSpecifiedError = Must to specify credentials with domain.
Expand Down
137 changes: 136 additions & 1 deletion Tests/Unit/MSFT_Computer.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -481,13 +481,14 @@ try

Context "$($script:dscResourceName)\Set-TargetResource" {
Mock -CommandName Rename-Computer
Mock -CommandName Add-Computer
Mock -CommandName Set-CimInstance

It 'Throws if both DomainName and WorkGroupName are specified' {
$errorRecord = Get-InvalidOperationRecord `
-Message ($LocalizedData.DomainNameAndWorkgroupNameError)

Mock -CommandName Add-Computer

{
Set-TargetResource `
-Name $env:COMPUTERNAME `
Expand All @@ -505,6 +506,8 @@ try
-Message ($LocalizedData.CredentialsNotSpecifiedError) `
-ArgumentName 'Credentials'

Mock -CommandName Add-Computer

{
Set-TargetResource `
-Name $env:COMPUTERNAME `
Expand All @@ -529,6 +532,8 @@ try
'contoso.com'
}

Mock -CommandName Add-Computer

Set-TargetResource `
-Name $notComputerName `
-DomainName 'adventure-works.com' `
Expand All @@ -554,6 +559,8 @@ try
'contoso.com'
}

Mock -CommandName Add-Computer

Set-TargetResource `
-Name $notComputerName `
-DomainName 'adventure-works.com' `
Expand All @@ -580,6 +587,8 @@ try
'contoso.com'
}

Mock -CommandName Add-Computer

Set-TargetResource `
-Name $notComputerName `
-WorkGroupName 'contoso' `
Expand All @@ -604,6 +613,8 @@ try
''
}

Mock -CommandName Add-Computer

Set-TargetResource `
-Name $notComputerName `
-DomainName 'Contoso.com' `
Expand All @@ -628,6 +639,8 @@ try
''
}

Mock -CommandName Add-Computer

Set-TargetResource `
-Name $notComputerName `
-DomainName 'Contoso.com' `
Expand All @@ -653,6 +666,8 @@ try
''
}

Mock -CommandName Add-Computer

Set-TargetResource `
-Name $notComputerName `
-DomainName 'Contoso.com' `
Expand All @@ -665,6 +680,110 @@ try
Assert-MockCalled -CommandName Add-Computer -Exactly -Times 0 -Scope It -ParameterFilter { $WorkGroupName }
}

It 'Should try a separate rename if ''FailToRenameAfterJoinDomain'' occured during domain join' {
$message = "Computer '' was successfully joined to the new domain '', but renaming it to '' failed with the following error message: The directory service is busy."
$exception = [System.InvalidOperationException]::new($message)
$errorID = $failToRenameAfterJoinDomainErrorId
$errorCategory = [Management.Automation.ErrorCategory]::InvalidOperation
$errorRecord = [System.Management.Automation.ErrorRecord]::new($exception, $errorID, $errorCategory, $null)

Mock -CommandName Get-WMIObject -MockWith {
[PSCustomObject] @{
Domain = 'Contoso'
Workgroup = 'Contoso'
PartOfDomain = $false
}
}

Mock -CommandName Get-ComputerDomain -MockWith {
''
}

Mock -CommandName Add-Computer -MockWith {
Throw $errorRecord
}

Set-TargetResource `
-Name $notComputerName `
-DomainName 'Contoso.com' `
-JoinOU 'OU=Computers,DC=contoso,DC=com' `
-Credential $credential | Should -BeNullOrEmpty

Assert-MockCalled -CommandName Rename-Computer -Exactly -Times 1 -Scope It
Assert-MockCalled -CommandName Add-Computer -Exactly -Times 1 -Scope It -ParameterFilter { $DomainName -and $NewName }
Assert-MockCalled -CommandName Add-Computer -Exactly -Times 0 -Scope It -ParameterFilter { $WorkGroupName }
}

It 'Should Throw the correct error if Add-Computer errors with an unknown InvalidOperationException' {
$error = 'Unknown Error'
$errorRecord = [System.InvalidOperationException]::new($error)

Mock -CommandName Get-WMIObject -MockWith {
[PSCustomObject] @{
Domain = 'Contoso'
Workgroup = 'Contoso'
PartOfDomain = $false
}
}

Mock -CommandName Get-ComputerDomain -MockWith {
''
}

Mock -CommandName Add-Computer -MockWith {
Throw $errorRecord
}

Mock -CommandName New-InvalidOperationException -MockWith {
Throw $errorRecord
}

{ Set-TargetResource `
-Name $notComputerName `
-DomainName 'Contoso.com' `
-JoinOU 'OU=Computers,DC=contoso,DC=com' `
-Credential $credential
} | Should -Throw $error

Assert-MockCalled -CommandName Rename-Computer -Exactly -Times 0 -Scope It
Assert-MockCalled -CommandName Add-Computer -Exactly -Times 1 -Scope It -ParameterFilter { $DomainName -and $NewName }
Assert-MockCalled -CommandName Add-Computer -Exactly -Times 0 -Scope It -ParameterFilter { $WorkGroupName }
}

It 'Should Throw the correct error if Add-Computer errors with an unknown error' {
$errorRecord = 'Unknown Error'
Mock -CommandName Get-WMIObject -MockWith {
[PSCustomObject] @{
Domain = 'Contoso'
Workgroup = 'Contoso'
PartOfDomain = $false
}
}

Mock -CommandName Get-ComputerDomain -MockWith {
''
}

Mock -CommandName Add-Computer -MockWith {
Throw $errorRecord
}

Mock -CommandName New-InvalidOperationException -MockWith {
Throw $errorRecord
}

{ Set-TargetResource `
-Name $notComputerName `
-DomainName 'Contoso.com' `
-JoinOU 'OU=Computers,DC=contoso,DC=com' `
-Credential $credential
} | Should -Throw $errorRecord

Assert-MockCalled -CommandName Rename-Computer -Exactly -Times 0 -Scope It
Assert-MockCalled -CommandName Add-Computer -Exactly -Times 1 -Scope It -ParameterFilter { $DomainName -and $NewName }
Assert-MockCalled -CommandName Add-Computer -Exactly -Times 0 -Scope It -ParameterFilter { $WorkGroupName }
}

It 'Changes ComputerName and changes Workgroup to new Workgroup' {
Mock -CommandName Get-WMIObject -MockWith {
[PSCustomObject] @{
Expand All @@ -678,6 +797,8 @@ try
''
}

Mock -CommandName Add-Computer

Set-TargetResource `
-Name $notComputerName `
-WorkGroupName 'adventure-works' `
Expand All @@ -701,6 +822,8 @@ try
'contoso.com'
}

Mock -CommandName Add-Computer

Set-TargetResource `
-Name $env:COMPUTERNAME `
-DomainName 'adventure-works.com' `
Expand All @@ -727,6 +850,8 @@ try
'contoso.com'
}

Mock -CommandName Add-Computer

Set-TargetResource `
-Name 'localhost' `
-DomainName 'adventure-works.com' `
Expand All @@ -753,6 +878,8 @@ try
'contoso.com'
}

Mock -CommandName Add-Computer

Set-TargetResource `
-Name $env:COMPUTERNAME `
-DomainName 'adventure-works.com' `
Expand Down Expand Up @@ -780,6 +907,8 @@ try
'contoso.com'
}

Mock -CommandName Add-Computer

Set-TargetResource `
-Name 'localhost' `
-DomainName 'adventure-works.com' `
Expand Down Expand Up @@ -807,6 +936,8 @@ try
''
}

Mock -CommandName Add-Computer

Set-TargetResource `
-Name $env:COMPUTERNAME `
-WorkGroupName 'Contoso' `
Expand All @@ -832,6 +963,8 @@ try
''
}

Mock -CommandName Add-Computer

Set-TargetResource `
-Name 'localhost' `
-WorkGroupName 'Contoso' `
Expand All @@ -857,6 +990,8 @@ try
'contoso.com'
}

Mock -CommandName Add-Computer

Set-TargetResource `
-Name $notComputerName `
-Credential $credential `
Expand Down

0 comments on commit 75152fc

Please sign in to comment.