private/CreateOrSetGroup.ps1

function CreateOrSetGroup {
    [CmdletBinding(SupportsShouldProcess=$true)]
    Param
    (
        [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
        [String]$Name,

        [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
        [String]$Description,

        [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
        [String]$Path,

        [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
        [String]$GroupScope,

        [Parameter(ValueFromPipelineByPropertyName)]
        [String]$Info,

        [Parameter(ValueFromPipelineByPropertyName)]
        [String[]]$MemberOf=$null,

        [Parameter(ValueFromPipelineByPropertyName)]
        [String[]]$Members=$null,

        # Clears the 'MemberOf' attribute of the target group by removing it from other groups.
        # Typically used to remove rights that a role participates in.
        [Switch]$ResetMembership,

        # Removes all (right/role) members from this group. This only targets groups and filters by right/role names.
        # Typically used to remove all roles from a given right without disrupting e.g. service accounts.
        [Switch]$ResetMembers,
        [Microsoft.ActiveDirectory.Management.ADDirectoryServer]$Server = (get-addomainController -Writable -Discover)
    )
    Begin{
        $CreatedGroups = [System.Collections.Generic.List[String]]::new()
        $MembershipChanges = [System.Collections.Generic.List[System.collections.hashtable]]::new()
        write-loghandler -level "Verbose" -message "Initializing OU/Container Processing (DC: $server)"
    }
    PROCESS {
        write-loghandler -level "Debug" -message "Started processing '$name'" -indentLevel 1
        $myOut = [ordered]@{
            Status = "Pending"
            Name = $Name
            Description = $Description
        }
        $GroupParams = @{
            Description = $Description
            GroupScope = $groupScope
            confirm = $false
            SAMAccountName = $name
        }
        $GroupDN = "CN=$name,$path"
        $PSShouldProcessMsg = $(write-logHandler -passthru -target $GroupDN -message "Set Description and metadata")
        $Results = if ($PSCmdlet.ShouldProcess.invoke($PSShouldProcessMsg)) {
            try {
                Set-ADGroup -server $server -Identity $GroupDN @GroupParams -replace @{info=$info}
                $myOut['status'] = "..Set"
                if ($resetMembership) {
                    write-loghandler -level "warning" -message "Resetting membership $GroupDN"
                    get-adgroup -identity $groupDN -properties memberOf -server $server | select-object -expand memberOf | remove-adgroupmember -member $groupDN -confirm:$false -server $server
                }
                $myOut['status'] = "-membership"
                if ($resetMembers) {
                    # TODO: This filter's a bit nasty-- it doesn't account well for the rightsprefix.
                    $removals = @(get-adgroupmember -identity $groupDN -server $server   | where-object {$_.objectClass -eq 'group' -and ($_.name -like "*$($settings.Names.RightsName)-*" -or $_.name -like "*$($settings.Names.RolesName)-*")})
                    if ($removals.count -gt 0) {
                        write-loghandler -level "warning" -message "Resetting members for $GroupDN. $($removals.count) groups to be removed."
                        remove-adgroupMember -server $server -identity $groupDN -Members $Removals
                    }
                }
                $myOut['status'] = "-members"


                if ($members) {
                    add-adgroupMember -server $server -identity $GroupDN -members $members
                    $myOut['status'] = "+members"
                }

                $myOut['status'] = "Updated"
            } Catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException] {
                write-loghandler -level "Verbose" -message " Didn't exist; creating"
                try {
                    New-ADGroup -server $server -name $name -path $path @GroupParams -groupCategory "Security" -passthru
                    $myOut['status'] = "NEW"
                    $CreatedGroups.add($GroupDN)
                } catch {
                    write-warning $_.exception.getType().fullname
                    write-loghandler -level "warning" -message ("Error creating {0} at {1}" -f $name,$path)
                    #throw $_
                }

            }
        }
        if ($members) {
            if ($null -eq $groupDN) {
                write-loghandler -level "Debug" -message "you have null members for $groupDN"
            } else {
                $MembershipChanges.add(@{
                    Identity = $GroupDN
                    Members = $members
                }) | out-null
            }
        }
        if ($memberOf) {
            foreach ($g in $memberOf) {
                if ($null -eq $g) {
                    write-loghandler -level "Debug" -message "you have null memberofs for $groupDN"
                } else {
                    $MembershipChanges.add(@{
                        Identity = $g
                        Members = $groupDN
                    }) | out-null
                }
            }
        }
        [pscustomobject]$myOut
    }
    END{
        Write-loghandler -level "Debug" -message "Waiting for creation of new Groups"
        for ($i = 0; $i -lt $CreatedGroups.count; $i++) {
            $ProgressActivity = "Waiting for creation of new Groups ({0} / {1})" -f $($i+1), $Createdgroups.count
            $item = $CreatedGroups[$i]
            $name = $item.split(",")[0].split("=")[1]
            $status = $name
            write-Progress -id 1 -Activity $ProgressActivity -status $status  -PercentComplete (($i/$createdGroups.count) * 100)   -SecondsRemaining $Settings.AppSettings.SleepTimeout
            for ($j = 0; $j -lt $Settings.AppSettings.SleepTimeout/$Settings.AppSettings.SleepLength; $j+=$Settings.AppSettings.SleepLength) {
                $itemExists = [bool](Get-ADGroup -server $server -filter "distinguishedName -eq '$item'")
                Write-Progress -id 1 -Activity $ProgressActivity  -Status $status  -SecondsRemaining $($Settings.AppSettings.SleepTimeout - $j) -PercentComplete (($i/$createdGroups.count) * 100)
                if ($itemExists) {
                    break
                }
                start-sleep -seconds $Settings.AppSettings.SleepLength
            }
        }
        write-Progress -id 1 $progressActivity -Completed
        if ($MembershipChanges.count -gt 0) {
            write-loghandler -level "Verbose" -message "Updating memberships"
            foreach ($line in $MembershipChanges) {
                if ($PSCmdlet.ShouldProcess($line.identity,"Add child membership")) {
                    try {
                        add-adgroupMember -server $server @line
                    } catch {
                        write-warning $_.exception.getType().fullname
                        write-loghandler -level "warning" -message ("Error adding {0} to {1}" -f $line.members,$line.identity)
                        #write-loghandler -level "warning" -message "Name: $Name; Description: $Description; Path: $Path; Parent: $g"
                        throw $_
                    }
                }
            }
        }
    }
}