Skip to content

Commit

Permalink
ADGroup: Add Support for Managed Service Accounts (#578)
Browse files Browse the repository at this point in the history
- ADGroup
  - Added support for Managed Service Accounts (issue #532).
  • Loading branch information
X-Guardian authored Mar 11, 2020
1 parent 811eef5 commit 4cbeae1
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 63 deletions.
24 changes: 13 additions & 11 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ For older change log history see the [historic changelog](HISTORIC_CHANGELOG.md)
- Added Strict-Mode v1.0 to all unit tests.
- ADDomain
- Added integration tests
([issue #302](https://github.com/dsccommunity/ActiveDirectoryDsc/issues/302)).
([issue #345](https://github.com/dsccommunity/ActiveDirectoryDsc/issues/345)).
- ADGroup
- Added support for Managed Service Accounts
([issue #532](https://github.com/dsccommunity/ActiveDirectoryDsc/issues/532)).
- ADForestProperties
- Added TombstoneLifetime property
([issue #302](https://github.com/dsccommunity/ActiveDirectoryDsc/issues/302)).
Expand All @@ -25,25 +28,24 @@ For older change log history see the [historic changelog](HISTORIC_CHANGELOG.md)
### Fixed

- ADForestProperties
- Fixed ability to clear `ServicePrincipalNameSuffix` and `UserPrincipalNameSuffix` ([issue #548](https://github.com/PowerShell/ActiveDirectoryDsc/issues/548)).
- WaitForADDomain
- Fixed `Find-DomainController` to correctly handle an exception thrown when a domain controller is not ready ([issue #530](https://github.com/dsccommunity/ActiveDirectoryDsc/issues/530)).
- Fixed ability to clear `ServicePrincipalNameSuffix` and `UserPrincipalNameSuffix` ([issue #548](https://github.com/dsccommunity/ActiveDirectoryDsc/issues/548)).
- Fixed ability to clear `ServicePrincipalNameSuffix` and `UserPrincipalNameSuffix`
([issue #548](https://github.com/dsccommunity/ActiveDirectoryDsc/issues/548)).
([issue #548](https://github.com/PowerShell/ActiveDirectoryDsc/issues/548)).
- WaitForADDomain
- Fixed `Find-DomainController` to correctly handle an exception thrown when a domain controller is not ready
([issue #530](https://github.com/dsccommunity/ActiveDirectoryDsc/issues/530)).
- ADObjectPermissionEntry
- Fixed issue where Get-DscConfiguration / Test-DscConfiguration throw an exception when target object path does not
yet exist
([issue #552](https://github.com/dsccommunity/ActiveDirectoryDsc/issues/552))
([issue #552](https://github.com/dsccommunity/ActiveDirectoryDsc/issues/552)).
- Fixed issue where Get-TargetResource throw an exception, `Cannot find drive. A drive with the name 'AD' does not
exist`, when running soon after domain controller restart
([issue #547](https://github.com/dsccommunity/ActiveDirectoryDsc/issues/547))
([issue #547](https://github.com/dsccommunity/ActiveDirectoryDsc/issues/547)).
- ADOrganizationalUnit
- Fixed issue where Get-DscConfiguration / Test-DscConfiguration throw an exception when parent path does not yet exist
([issue #553](https://github.com/dsccommunity/ActiveDirectoryDsc/issues/553))
- Fixed issue where Get-DscConfiguration/Test-DscConfiguration throws an exception when parent path does not yet exist
([issue #553](https://github.com/dsccommunity/ActiveDirectoryDsc/issues/553)).
- ADReplicationSiteLink
- Fixed issue creating a Site Link with options specified
([issue #571](https://github.com/dsccommunity/ActiveDirectoryDsc/issues/571))
([issue #571](https://github.com/dsccommunity/ActiveDirectoryDsc/issues/571)).
- ADDomain
- Added additional Get-ADDomain retry exceptions
([issue #574](https://github.com/dsccommunity/ActiveDirectoryDsc/issues/574)).
Expand Down
154 changes: 102 additions & 52 deletions Tests/Unit/ActiveDirectoryDsc.Common.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -1006,6 +1006,14 @@ InModuleScope 'ActiveDirectoryDsc.Common' {
Name = 'CN=Computer1,DC=contoso,DC=com'
Domain = 'contoso.com'
}
[PSCustomObject] @{
Name = 'CN=Msa1,DC=contoso,DC=com'
Domain = 'contoso.com'
}
[PSCustomObject] @{
Name = 'CN=Gmsa1,DC=contoso,DC=com'
Domain = 'contoso.com'
}
[PSCustomObject] @{
Name = 'CN=Account1,DC=a,DC=contoso,DC=com'
Domain = 'a.contoso.com'
Expand All @@ -1018,6 +1026,14 @@ InModuleScope 'ActiveDirectoryDsc.Common' {
Name = 'CN=Computer1,DC=a,DC=contoso,DC=com'
Domain = 'a.contoso.com'
}
[PSCustomObject] @{
Name = 'CN=Msa1,DC=a,DC=contoso,DC=com'
Domain = 'a.contoso.com'
}
[PSCustomObject] @{
Name = 'CN=Gmsa1,DC=a,DC=contoso,DC=com'
Domain = 'a.contoso.com'
}
[PSCustomObject] @{
Name = 'CN=Account1,DC=b,DC=contoso,DC=com'
Domain = 'b.contoso.com'
Expand All @@ -1030,6 +1046,14 @@ InModuleScope 'ActiveDirectoryDsc.Common' {
Name = 'CN=Computer1,DC=b,DC=contoso,DC=com'
Domain = 'b.contoso.com'
}
[PSCustomObject] @{
Name = 'CN=Msa1,DC=b,DC=contoso,DC=com'
Domain = 'b.contoso.com'
}
[PSCustomObject] @{
Name = 'CN=Gmsa1,DC=b,DC=contoso,DC=com'
Domain = 'b.contoso.com'
}
)

$invalidMemberData = @(
Expand All @@ -1043,13 +1067,17 @@ InModuleScope 'ActiveDirectoryDsc.Common' {
}

Context 'When all members are in the same domain' {
Mock -CommandName Add-ADGroupMember
$groupCount = 0
BeforeAll {
Mock -CommandName Add-ADGroupMember
$groupCount = 0
}

foreach ($domainGroup in ($memberData | Group-Object -Property Domain))
{
$groupCount ++
It 'Should not throw an error when calling Add-ADCommonGroupMember' {
Add-ADCommonGroupMember -Members $domainGroup.Group.Name -Parameters $fakeParameters
It "Should not throw an error for $($domainGroup.Name)" {
{ Add-ADCommonGroupMember -Members $domainGroup.Group.Name -Parameters $fakeParameters } |
Should -Not -Throw
}
}

Expand All @@ -1059,67 +1087,89 @@ InModuleScope 'ActiveDirectoryDsc.Common' {
}

Context 'When members are in different domains' {
Mock -CommandName Add-ADGroupMember
Mock -CommandName Get-ADObject -MockWith {
param
(
[Parameter()]
[System.String]
$Identity,

[Parameter()]
[System.String]
$Server,

[Parameter()]
[System.String[]]
$Properties
)
BeforeAll {
Mock -CommandName Add-ADGroupMember
Mock -CommandName Get-ADObject -MockWith {
param
(
[Parameter()]
[System.String]
$Identity,

[Parameter()]
[System.String]
$Server,

[Parameter()]
[System.String[]]
$Properties
)

$objectClass = switch ($Identity)
{
{ $Identity -match 'Group' }
$objectClass = switch ($Identity)
{
'group'
{ $Identity -match 'Group' }
{
'group'
}
{ $Identity -match 'Account' }
{
'user'
}
{ $Identity -match 'Computer' }
{
'computer'
}
{ $Identity -match 'msa' }
{
'msDS-ManagedServiceAccount'
}
{ $Identity -match 'gmsa' }
{
'msDS-GroupManagedServiceAccount'
}
}
{ $Identity -match 'Account' }
{
'user'
}
{ $Identity -match 'Computer' }
{
'computer'
}
}

return (
[PSCustomObject] @{
objectClass = $objectClass
}
)
return (
@{
objectClass = $objectClass
}
)
}
# Mocks should return something that is used with Add-ADGroupMember
Mock -CommandName Get-ADComputer -MockWith { 'placeholder' }
Mock -CommandName Get-ADGroup -MockWith { 'placeholder' }
Mock -CommandName Get-ADUser -MockWith { 'placeholder' }
Mock -CommandName Get-ADServiceAccount -MockWith { 'placeholder' }
}
# Mocks should return something that is used with Add-ADGroupMember
Mock -CommandName Get-ADComputer -MockWith { return 'placeholder' }
Mock -CommandName Get-ADGroup -MockWith { return 'placeholder' }
Mock -CommandName Get-ADUser -MockWith { return 'placeholder' }

It 'Should not throw an error' {
{ Add-ADCommonGroupMember -Members $memberData.Name -Parameters $fakeParameters -MembersInMultipleDomains } | Should -Not -Throw
{ Add-ADCommonGroupMember -Members $memberData.Name -Parameters $fakeParameters `
-MembersInMultipleDomains } | Should -Not -Throw
}

It 'Should have called all mocked cmdlets' {
Assert-MockCalled -CommandName Get-ADComputer -Exactly -Times $memberData.Where( { $_.Name -like '*Computer*' }).Count
Assert-MockCalled -CommandName Get-ADUser -Exactly -Times $memberData.Where( { $_.Name -like '*Account*' }).Count
Assert-MockCalled -CommandName Get-ADGroup -Exactly -Times $memberData.Where( { $_.Name -like '*Group*' }).Count
Assert-MockCalled -CommandName Add-ADGroupMember -Exactly -Times $memberData.Count
It 'Should have called the expected mocks' {
Assert-MockCalled -CommandName Get-ADComputer `
-Exactly -Times $memberData.Where( { $_.Name -like '*Computer*' }).Count
Assert-MockCalled -CommandName Get-ADUser `
-Exactly -Times $memberData.Where( { $_.Name -like '*Account*' }).Count
Assert-MockCalled -CommandName Get-ADGroup `
-Exactly -Times $memberData.Where( { $_.Name -like '*Group*' }).Count
Assert-MockCalled -CommandName Get-ADServiceAccount `
-Exactly -Times $memberData.Where( { $_.Name -like '*msa*' }).Count
Assert-MockCalled -CommandName Add-ADGroupMember `
-Exactly -Times $memberData.Count
}
}

Context 'When the domain name cannot be determined' {
BeforeAll {
$emptyDomainError = ($script:localizedData.EmptyDomainError -f
$invalidMemberData[0], $fakeParameters.Identity)
}

It 'Should throw the correct error' {
{
Add-ADCommonGroupMember -Members $invalidMemberData -Parameters $fakeParameters -MembersInMultipleDomains
} | Should -Throw ($script:localizedData.EmptyDomainError -f $invalidMemberData[0], $fakeParameters.Identity)
{ Add-ADCommonGroupMember -Members $invalidMemberData -Parameters $fakeParameters `
-MembersInMultipleDomains } | Should -Throw $emptyDomainError
}
}
}
Expand Down Expand Up @@ -2315,7 +2365,7 @@ InModuleScope 'ActiveDirectoryDsc.Common' {
Describe 'ActiveDirectoryDsc.Common\Test-Password' {
BeforeAll {
$mockDomainName = 'contoso.com'
$mockFQDN = 'DC=' + $mockDomainName.replace('.',',DC=')
$mockFQDN = 'DC=' + $mockDomainName.replace('.', ',DC=')
$mockUserName = 'JohnDoe'
$mockPassword = 'mockpassword'
$mockPasswordCredential = [System.Management.Automation.PSCredential]::new(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1316,6 +1316,14 @@ function Add-ADCommonGroupMember
{
$memberObject = Get-ADUser @commonParameters
}
elseif ($memberObjectClass -eq 'msDS-ManagedServiceAccount')
{
$memberObject = Get-ADServiceAccount @commonParameters
}
elseif ($memberObjectClass -eq 'msDS-GroupManagedServiceAccount')
{
$memberObject = Get-ADServiceAccount @commonParameters
}

Add-ADGroupMember @Parameters -Members $memberObject -ErrorAction 'Stop'
}
Expand Down

0 comments on commit 4cbeae1

Please sign in to comment.