DSCResources/MSFT_xADGroup/MSFT_xADGroup.psm1
# Localized messages data LocalizedData { # culture="en-US" ConvertFrom-StringData @' RoleNotFoundError = Please ensure that the PowerShell module for role '{0}' is installed AddingGroup = Adding AD Group '{0}' UpdatingGroup = Updating AD Group '{0}' RemovingGroup = Removing AD Group '{0}' MovingGroup = Moving AD Group '{0}' to '{1}' GroupNotFound = AD Group '{0}' was not found NotDesiredPropertyState = AD Group '{0}' is not correct. Expected '{1}', actual '{2}' UpdatingGroupProperty = Updating AD Group property '{0}' to '{1}' '@ } function Get-TargetResource { [CmdletBinding()] [OutputType([System.Collections.Hashtable])] param ( [parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [System.String] $GroupName, [ValidateSet('DomainLocal','Global','Universal')] [System.String] $GroupScope = 'Global', [ValidateSet('Security','Distribution')] [System.String] $Category = 'Security', [ValidateNotNullOrEmpty()] [System.String] $Path, [ValidateSet("Present", "Absent")] [System.String] $Ensure = "Present", [ValidateNotNullOrEmpty()] [System.String] $Description, [ValidateNotNullOrEmpty()] [System.String] $DisplayName, [ValidateNotNullOrEmpty()] [System.Management.Automation.PSCredential] $Credential, [ValidateNotNullOrEmpty()] [System.String] $DomainController ) Assert-Module -ModuleName 'ActiveDirectory'; $adGroupParams = Get-ADCommonParameters @PSBoundParameters; try { $adGroup = Get-ADGroup @adGroupParams -Property Name,GroupScope,GroupCategory,DistinguishedName,Description,DisplayName; $targetResource = @{ GroupName = $adGroup.Name; GroupScope = $adGroup.GroupScope; Category = $adGroup.GroupCategory; Path = Get-ADObjectParentDN -DN $adGroup.DistinguishedName; Description = $adGroup.Description; DisplayName = $adGroup.DisplayName; Ensure = 'Present'; } } catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException] { Write-Verbose ($LocalizedData.GroupNotFound -f $GroupName); $targetResource = @{ GroupName = $GroupName; GroupScope = $GroupScope; Category = $Category; Path = $Path; Description = $Description; DisplayName = $DisplayName; Ensure = 'Absent'; } } return $targetResource; } #end function Get-TargetResource function Test-TargetResource { [CmdletBinding()] [OutputType([System.Boolean])] param ( [parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [System.String] $GroupName, [ValidateSet('DomainLocal','Global','Universal')] [System.String] $GroupScope = 'Global', [ValidateSet('Security','Distribution')] [System.String] $Category = 'Security', [ValidateNotNullOrEmpty()] [System.String] $Path, [ValidateSet("Present", "Absent")] [System.String] $Ensure = "Present", [ValidateNotNullOrEmpty()] [System.String] $Description, [ValidateNotNullOrEmpty()] [System.String] $DisplayName, [ValidateNotNullOrEmpty()] [System.Management.Automation.PSCredential] $Credential, [ValidateNotNullOrEmpty()] [System.String] $DomainController ) $adGroup = Get-TargetResource @PSBoundParameters; $targetResourceInCompliance = $true; if ($adGroup.GroupScope -ne $GroupScope) { Write-Verbose ($LocalizedData.NotDesiredPropertyState -f 'GroupScope', $GroupScope, $adGroup.GroupScope); $targetResourceInCompliance = $false; } elseif ($adGroup.Category -ne $Category) { Write-Verbose ($LocalizedData.NotDesiredPropertyState -f 'Category', $Category, $adGroup.Category); $targetResourceInCompliance = $false; } elseif ($Path -and ($adGroup.Path -ne $Path)) { Write-Verbose ($LocalizedData.NotDesiredPropertyState -f 'Path', $Path, $adGroup.Path); $targetResourceInCompliance = $false; } elseif ($Description -and ($adGroup.Description -ne $Description)) { Write-Verbose ($LocalizedData.NotDesiredPropertyState -f 'Description', $Description, $adGroup.Description); $targetResourceInCompliance = $false; } elseif ($DisplayName -and ($adGroup.DisplayName -ne $DisplayName)) { Write-Verbose ($LocalizedData.NotDesiredPropertyState -f 'DisplayName', $DisplayName, $adGroup.DisplayName); $targetResourceInCompliance = $false; } elseif ($adGroup.Ensure -ne $Ensure) { Write-Verbose ($LocalizedData.NotDesiredPropertyState -f 'Ensure', $Ensure, $adGroup.Ensure); $targetResourceInCompliance = $false; } return $targetResourceInCompliance; } #end function Test-TargetResource function Set-TargetResource { [CmdletBinding()] param ( [parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [System.String] $GroupName, [ValidateSet('DomainLocal','Global','Universal')] [System.String] $GroupScope = 'Global', [ValidateSet('Security','Distribution')] [System.String] $Category = 'Security', [ValidateNotNullOrEmpty()] [System.String] $Path, [ValidateSet("Present", "Absent")] [System.String] $Ensure = "Present", [ValidateNotNullOrEmpty()] [System.String] $Description, [ValidateNotNullOrEmpty()] [System.String] $DisplayName, [ValidateNotNullOrEmpty()] [System.Management.Automation.PSCredential] $Credential, [ValidateNotNullOrEmpty()] [System.String] $DomainController ) Assert-Module -ModuleName 'ActiveDirectory'; $adGroupParams = Get-ADCommonParameters @PSBoundParameters; try { $adGroup = Get-ADGroup @adGroupParams -Property Name,GroupScope,GroupCategory,DistinguishedName,Description,DisplayName; if ($Ensure -eq 'Present') { $setADGroupParams = @{}; # Update existing group properties if ($Category -ne $adGroup.GroupCategory) { Write-Verbose ($LocalizedData.UpdatingGroupProperty -f 'Category', $Category); $setADGroupParams['Category'] = $Categrory; } if ($GroupScope -ne $adGroup.GroupScope) { ## Cannot change DomainLocal to Global or vice versa. Need to change them to Universal groups first! Set-ADGroup -Identity $adGroup.DistinguishedName -GroupScope Universal; Write-Verbose ($LocalizedData.UpdatingGroupProperty -f 'GroupScope', $GroupScope); $setADGroupParams['GroupScope'] = $GroupScope; } if ($Description -and ($Description -ne $adGroup.Description)) { Write-Verbose ($LocalizedData.UpdatingGroupProperty -f 'Description', $Description); $setADGroupParams['Description'] = $Description; } if ($DisplayName -and ($DisplayName -ne $adGroup.DisplayName)) { Write-Verbose ($LocalizedData.UpdatingGroupProperty -f 'DisplayName', $DisplayName); $setADGroupParams['DisplayName'] = $DisplayName; } Write-Verbose ($LocalizedData.UpdatingGroup -f $GroupName); Set-ADGroup -Identity $adGroup.DistinguishedName @setADGroupParams; # Move group if the path is not correct if ($Path -and ($Path -ne (Get-ADObjectParentDN -DN $adGroup.DistinguishedName))) { Write-Verbose ($LocalizedData.MovingGroup -f $GroupName, $Path); Move-ADObject -Identity $adGroup.DistinguishedName -TargetPath $Path; } } elseif ($Ensure -eq 'Absent') { # Remove existing group Write-Verbose ($LocalizedData.RemovingGroup -f $GroupName); Remove-ADGroup @adGroupParams -Confirm:$false; } } catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException] { ## The AD group doesn't exist if ($Ensure -eq 'Present') { Write-Verbose ($LocalizedData.GroupNotFound -f $GroupName); Write-Verbose ($LocalizedData.AddingGroup -f $GroupName); $adGroupParams = Get-ADCommonParameters @PSBoundParameters -UseNameParameter; if ($Description) { $adGroupParams['Description'] = $Description; } if ($DisplayName) { $adGroupParams['DisplayName'] = $DisplayName; } if ($Path) { $adGroupParams['Path'] = $Path; } ## Create group New-ADGroup @adGroupParams -GroupCategory $Category -GroupScope $GroupScope; } } #end catch } #end function Set-TargetResource # Internal function to assert if the role specific module is installed or not function Assert-Module { [CmdletBinding()] param ( [System.String] $ModuleName = 'ActiveDirectory' ) if (-not (Get-Module -Name $ModuleName -ListAvailable)) { $errorMsg = $($LocalizedData.RoleNotFoundError) -f $moduleName; $exception = New-Object System.InvalidOperationException $errorMessage; $errorRecord = New-Object System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $null; throw $errorRecord; } } #end function Assert-Module # Internal function to get an Active Directory object's parent Distinguished Name function Get-ADObjectParentDN { # https://www.uvm.edu/~gcd/2012/07/listing-parent-of-ad-object-in-powershell/ [CmdletBinding()] param ( [Parameter(Mandatory)] [System.String] $DN ) $distinguishedNameParts = $DN -split '(?<![\\]),'; $distinguishedNameParts[1..$($distinguishedNameParts.Count-1)] -join ','; } # Internal function to build common parameters for the Active Directory cmdlets function Get-ADCommonParameters { [CmdletBinding()] [OutputType([System.Collections.Hashtable])] param ( [parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [System.String] $GroupName, [ValidateSet('DomainLocal','Global','Universal')] [System.String] $GroupScope = 'Global', [ValidateSet('Security','Distribution')] [System.String] $Category = 'Security', [ValidateNotNullOrEmpty()] [System.String] $Path, [ValidateSet("Present", "Absent")] [System.String] $Ensure = "Present", [ValidateNotNullOrEmpty()] [System.String] $Description, [ValidateNotNullOrEmpty()] [System.String] $DisplayName, [ValidateNotNullOrEmpty()] [System.Management.Automation.PSCredential] $Credential, [ValidateNotNullOrEmpty()] [System.String] $DomainController, [Switch] $UseNameParameter ) ## The Get-ADGroup and Set-ADGroup parameters take an -Identity parameter, but the New-ADGroup cmdlet uses the -Name parameter if ($UseNameParameter) { $adGroupCommonParameters = @{ Name = $GroupName; } } else { $adGroupCommonParameters = @{ Identity = $GroupName; } } if ($Credential) { $adGroupCommonParameters['Credential'] = $Credential; } if ($DomainController) { $adGroupCommonParameters['Server'] = $DomainController; } return $adGroupCommonParameters; } #end function Get-ADCommonParameters Export-ModuleMember -Function *-TargetResource; |