---
title: Manage group membership
summary: Adds or removes a target user from a named Active Directory security group, operating either on the currently loaded user or a user resolved by ID.
status: draft
owner: SAIF
last_reviewed: 2026-07-30
library: SAIF.Business.Security.SystemUser
reference_type: package
operation_id: OP-SU-07
trigger: Caller calls clsSystemUser.AddUserToRole(...) or RemoveUserFromRole(...)
---

# Manage group membership

The library exposes matching add/remove pairs for AD group membership: each has an overload that acts on the currently loaded `m_DirUser` and an overload that first resolves a named user by ID. Both operations share the same private helper pattern — resolve the named security group, then delegate to `clsUser.AddToGroup` or `clsUser.RemoveFromGroup` — so they are documented together.

| Field | Value |
| --- | --- |
| **Operation ID** | OP-SU-07 |
| **Trigger** | `AddUserToRole(inRoleName)`, `AddUserToRole(inUserId, inRoleName)`, `RemoveUserFromRole(inRoleName)`, or `RemoveUserFromRole(inUserId, inRoleName)` |
| **Inputs** | Target group name (`inRoleName`); optionally a target user ID (`inUserId`) when not operating on the currently loaded user |
| **Outputs** | `Boolean` result reflecting whether the group membership change succeeded |
| **Primary components** | `clsSystemUser.AddUserToRole(...)` (public, two overloads), `clsSystemUser.RemoveUserFromRole(...)` (public, two overloads), private `AddUserToRole(inUserObject, inRoleName)`, private `RemoveUserFromRole(inUserObject, inRoleName)` |
| **Entry point** | `Business\SAIF.Business.Security.SystemUser\clsSystemUser.vb` |

## Steps

1. **Select the target user.**
   - The single-argument overloads (`AddUserToRole(inRoleName)`, `RemoveUserFromRole(inRoleName)`) operate on the currently loaded `m_DirUser` context — the account established at construction or by [Switch active user context](switch-active-user-context.md).
   - The two-argument overloads (`AddUserToRole(inUserId, inRoleName)`, `RemoveUserFromRole(inUserId, inRoleName)`) call `m_DirServer.GetUser(inUserId)` to resolve the target user first.
     - If that lookup returns `Nothing`: the method returns `False` immediately and no group operation is attempted.
2. **Resolve the security group.** The shared private helper (`AddUserToRole(inUserObject, inRoleName)` or `RemoveUserFromRole(inUserObject, inRoleName)`) calls `m_DirServer.GetGroup(inRoleName)` to locate the target AD group.
   - If the group is not found: the helper returns `False` without attempting the membership change.
3. **Apply the membership change.** If the group is found, the helper calls `inUserObject.AddToGroup(securityRole)` or `inUserObject.RemoveFromGroup(securityRole)` and returns that call's Boolean result directly.
4. **Return the outcome.** The public method returns whatever the private helper (or the not-found short-circuit) produced.

## Process flow

The following diagram visualizes this operation's control flow across the add and remove entry points.

```mermaid
flowchart TD
	Start([Caller calls AddUserToRole or RemoveUserFromRole]) --> Which{Which overload?}
	Which -->|Single-arg| UseCurrent[Use current m_DirUser]
	Which -->|Two-arg| Resolve[m_DirServer.GetUser inUserId]
	Resolve --> UserFound{User found?}
	UserFound -->|No| FailUser([Return False])
	UserFound -->|Yes| UseCurrent
	UseCurrent --> Group[m_DirServer.GetGroup inRoleName]
	Group --> GroupFound{Group found?}
	GroupFound -->|No| FailGroup([Return False])
	GroupFound -->|Yes| Action{Add or Remove?}
	Action -->|Add| AddCall[AddToGroup]
	Action -->|Remove| RemoveCall[RemoveFromGroup]
	AddCall --> Return([Return Boolean result])
	RemoveCall --> Return
```

## Failure and edge-case behavior

- Both a missing target user and a missing target group produce an indistinguishable `False` return — the caller cannot tell from the result alone which precondition failed.
- Neither entry point verifies that the user is not already a member (for add) or is currently a member (for remove) before delegating to `AddToGroup`/`RemoveFromGroup`; that behavior is owned entirely by the directory-service layer.*
- The single-argument overloads depend on `m_DirUser` already being correctly loaded; if construction or a prior [Switch active user context](switch-active-user-context.md) call failed silently, the group operation acts on a stale or unintended user context.*

## Related documentation

- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)

> **Note:** Statements marked with `*` were inferred from code structure, naming
> conventions, or contextual evidence where direct confirmation was not available
> in source artifacts.

## Sources

- `Business\SAIF.Business.Security.SystemUser\clsSystemUser.vb`
