Skip to content

[Request]: New Add-AdoMembership Cmdlet #97

@msc365admin

Description

@msc365admin

Is there an existing issue for this?

  • I have searched the existing issues

Azure.DevOps.PSModule version

0.2.2

Related function

Get-AdoMembership, Add-AdoGroupMember, Remove-AdoMembership (proposed)

Use case

As a DevOps Engineer managing Azure DevOps organization identity and access management

I want a generic Add-AdoMembership cmdlet that directly uses subject and container descriptors to create membership relationships

So that I can have a consistent, descriptor-based API surface that aligns with Get-AdoMembership and Remove-AdoMembership, enabling more flexible membership management workflows without needing to know origin IDs

Notes

  • Currently, Add-AdoGroupMember exists but uses a different API endpoint (/graph/groups) and requires an OriginId parameter
  • The Memberships API (/graph/memberships/{subjectDescriptor}/{containerDescriptor}) provides a more direct approach using descriptors
  • Having Get-AdoMembership, Add-AdoMembership, and Remove-AdoMembership creates a consistent, intuitive cmdlet family
  • The descriptor-based approach is more flexible as it works with any subject/container relationship
  • Users already have descriptors from Get-AdoGroup, Get-AdoDescriptor, or other cmdlets - no need to track origin IDs
  • Enables symmetrical operations: if you can GET and REMOVE memberships by descriptor, you should be able to ADD them the same way

Proposed solution

Create an Add-AdoMembership cmdlet that complements the existing membership management cmdlets:

Cmdlet Signature

function Add-AdoMembership {
    [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Medium')]
    param (
        [Parameter(ValueFromPipelineByPropertyName)]
        [ValidateScript({ Confirm-CollectionUri -Uri $_ })]
        [string]$CollectionUri = ($env:DefaultAdoCollectionUri -replace 'https://', 'https://vssps.'),

        [Parameter(Mandatory, ValueFromPipelineByPropertyName, ValueFromPipeline)]
        [string[]]$SubjectDescriptor,

        [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
        [string]$ContainerDescriptor,

        [Parameter()]
        [Alias('ApiVersion')]
        [ValidateSet('7.1-preview.1', '7.2-preview.1')]
        [string]$Version = '7.1-preview.1'
    )
}

Key Features

  1. PUT HTTP Method: Calls the Azure DevOps Graph API using PUT method
  2. Descriptor-Based: Works directly with subject and container descriptors (no origin ID needed)
  3. Pipeline Support: Accept SubjectDescriptor from pipeline for bulk operations
  4. Confirmation Prompts: Include -WhatIf and -Confirm support for safe operations
  5. Descriptor Validation: Validate descriptor format before API calls
  6. Error Handling: Clear error messages for invalid descriptors or existing memberships
  7. Consistency: Matches parameter patterns with Get-AdoMembership and Remove-AdoMembership
  8. Idempotency: Handle cases where membership already exists gracefully

API Endpoint

PUT https://vssps.dev.azure.com/{organization}/_apis/graph/memberships/{subjectDescriptor}/{containerDescriptor}?api-version=7.1-preview.1

Example Usage

# Add a single membership using descriptors
$params = @{
    CollectionUri       = 'https://vssps.dev.azure.com/my-org'
    SubjectDescriptor   = 'aadgp.00000000-0000-0000-0000-000000000000'
    ContainerDescriptor = 'vssgp.00000000-0000-0000-0000-000000000001'
}
Add-AdoMembership @params

# Add multiple users to a group via pipeline
$userDescriptors = @(
    'aad.MDAwMDAwMDAtMDAwMC0wMDAwLTAwMDAtMDAwMDAwMDAwMDAy',
    'aad.MDAwMDAwMDAtMDAwMC0wMDAwLTAwMDAtMDAwMDAwMDAwMDAz'
)
$userDescriptors | Add-AdoMembership @params

# Retrieve group members and add them to another group
$params = @{
    CollectionUri       = 'https://vssps.dev.azure.com/my-org'
}
$sourceGroup = Get-AdoGroup @params -GroupName 'Developers'
$targetGroup = Get-AdoGroup @params -GroupName 'Contributors'

Get-AdoMembership @params -ContainerDescriptor $sourceGroup.descriptor |
    Add-AdoMembership @params -ContainerDescriptor $targetGroup.descriptor

# Preview changes without executing
Add-AdoMembership @params -WhatIf

# Add without confirmation prompt (automation scenarios)
Add-AdoMembership @params -Confirm:$false

Comparison: Add-AdoGroupMember vs Add-AdoMembership

Aspect Add-AdoGroupMember Add-AdoMembership
API Endpoint /graph/groups /graph/memberships
HTTP Method POST PUT
Primary Parameter OriginId (GUID) SubjectDescriptor (string)
Use Case Add Entra ID groups by origin ID Add any subject by descriptor
Requires Knowledge of origin ID Only descriptor (from Get cmdlets)
Naming Pattern Group-specific operation Generic membership operation
Consistency Different from Get/Remove Matches Get-AdoMembership pattern

Implementation Checklist

  • Create Add-AdoMembership.ps1 in src/Azure.DevOps.PSModule/Public/Graph/Memberships/
  • Implement comprehensive Pester tests in src/Azure.DevOps.PSModule/Tests/Graph/Memberships/Add-AdoMembership.Tests.ps1
  • Generate PlatyPS documentation in docs/Add-AdoMembership.md
  • Update module manifest to export the new cmdlet
  • Add usage examples to README
  • Update CHANGELOG with new feature
  • Document relationship with existing Add-AdoGroupMember cmdlet

Benefits

  • Consistency: Creates a unified membership management API surface (Get, Add, Remove)
  • Flexibility: Works with descriptors from any source, not just origin IDs
  • Discoverability: Intuitive naming - users looking for membership operations find all related cmdlets
  • Simplicity: Simpler workflows when descriptors are already available from other cmdlets
  • Pipeline-Friendly: Enables chaining operations with other descriptor-based cmdlets
  • Completeness: Provides full CRUD operations for membership management

Relationship with Add-AdoGroupMember

  • Add-AdoGroupMember remains valuable for specific Entra ID group scenarios where origin ID is readily available
  • Add-AdoMembership provides a more generic, descriptor-based alternative
  • Both cmdlets can coexist, serving different use cases
  • Consider Add-AdoGroupMember as a specialized convenience wrapper
  • Add-AdoMembership aligns better with the Get/Remove cmdlet patterns

Testing Scenarios

  1. Successfully add a valid membership relationship
  2. Handle existing membership gracefully (idempotency)
  3. Validate proper error handling for invalid descriptors
  4. Confirm pipeline input processing for bulk operations
  5. Verify -WhatIf and -Confirm behavior
  6. Test with AAD, AADGP, and VSSGP descriptor types
  7. Validate API version parameter functionality
  8. Test subject-to-subject and subject-to-container relationships
  9. Verify error handling for insufficient permissions
  10. Test edge cases (self-referencing, circular dependencies)

Migration Path

For users currently using Add-AdoGroupMember, provide guidance:

# Old pattern (using Add-AdoGroupMember with OriginId)
Add-AdoGroupMember -GroupDescriptor $groupDesc -OriginId $originId

# New pattern (using Add-AdoMembership with SubjectDescriptor)
# First get the descriptor from origin ID if needed
$subject = Get-AdoGroup -OriginId $originId
Add-AdoMembership -SubjectDescriptor $subject.descriptor -ContainerDescriptor $groupDesc

# Or even better - pipe directly
Get-AdoGroup -OriginId $originId |
    Add-AdoMembership -ContainerDescriptor $groupDesc

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

Status

Backlog

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions