Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add User Sponsor command #1348

Open
wants to merge 26 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
7339fc6
add user sponsor tests
Feb 11, 2025
520dd75
Merge branch 'main' into dbutoyi/user_sponsor
Feb 11, 2025
3a5a50c
refactor Get entra user sponsor functions
Feb 12, 2025
7d5d535
refactor tests
Feb 12, 2025
7bfaefb
refactor and fix unit tests
Feb 12, 2025
f3e8c21
import the correct module Entra Beta Users
Feb 12, 2025
56e7854
refactor user sponsor beta tests
Feb 12, 2025
0d46e96
refactor user sponsor beta test
Feb 12, 2025
abbe5c6
Merge branch 'main' into dbutoyi/user_sponsor
Feb 12, 2025
b27551e
add documentation for usersponsor command
Feb 12, 2025
2a58b06
remove empty doc
Feb 12, 2025
c301c74
Merge branch 'main' into dbutoyi/user_sponsor
SteveMutungi254 Feb 17, 2025
79c863b
add aliases help messages and refactor
Feb 19, 2025
c531c12
Docs enhancements suggestions (#1363)
SteveMutungi254 Feb 19, 2025
6542057
refactors remove unsupported search query
Feb 19, 2025
74ab937
doc add get by sponsor Id
Feb 21, 2025
45a4d0d
Merge branch 'main' into dbutoyi/user_sponsor
SteveMutungi254 Feb 21, 2025
c4033f7
Update module/Entra/Microsoft.Entra/Users/Get-EntraUserSponsor.ps1
DButoyez Feb 21, 2025
fdb44be
Update module/Entra/Microsoft.Entra/Users/Get-EntraUserSponsor.ps1
DButoyez Feb 21, 2025
0032b1b
Update module/EntraBeta/Microsoft.Entra.Beta/Users/Get-EntraBetaUserS…
DButoyez Feb 21, 2025
1f370a5
Update module/EntraBeta/Microsoft.Entra.Beta/Users/Get-EntraBetaUserS…
DButoyez Feb 21, 2025
f3b3fd1
Update module/EntraBeta/Microsoft.Entra.Beta/Users/Get-EntraBetaUserS…
DButoyez Feb 21, 2025
09b141c
Update module/EntraBeta/Microsoft.Entra.Beta/Users/Get-EntraBetaUserS…
DButoyez Feb 21, 2025
a7870a7
Update module/docs/entra-powershell-beta/Users/Get-EntraBetaUserSpons…
DButoyez Feb 21, 2025
5e8ec48
Update module/docs/entra-powershell-v1.0/Users/Get-EntraUserSponsor.md
DButoyez Feb 21, 2025
40f2c0c
Update module/docs/entra-powershell-v1.0/Users/Get-EntraUserSponsor.md
SteveMutungi254 Feb 21, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 104 additions & 0 deletions module/Entra/Microsoft.Entra/Users/Get-EntraUserSponsor.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
function Get-EntraUserSponsor {
[CmdletBinding(DefaultParameterSetName = 'GetQuery')]
param (
[Parameter(ParameterSetName = "GetQuery", ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Filter to apply to the query.")]
[System.String] $Filter,

[Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "The unique identifier (User ID) of the user whose sponsor information you want to retrieve.")]
[System.String] $UserId,

[Alias('Limit')]
[Parameter(ParameterSetName = "GetQuery", ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Maximum number of results to return.")]
[System.Nullable`1[System.Int32]] $Top,

[Parameter(ParameterSetName = "GetQuery", ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Retrieve all user's sponsors.")]
[switch] $All,

[Alias('DirectoryObjectId')]
[Parameter(ParameterSetName = "GetById", Mandatory = $false, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "The User Sponsor ID to retrieve.")]
[System.String] $SponsorId,

[Alias('Select')]
[Parameter(Mandatory = $false, ValueFromPipeline = $false, ValueFromPipelineByPropertyName = $true, HelpMessage = "Properties to include in the results.")]
[System.String[]] $Property
)

PROCESS {
$customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand
$params = @{}
$topCount = $null
$baseUri = "https://graph.microsoft.com/v1.0/users/$UserId/sponsors"
$properties = '$select=*'
$params["Method"] = "GET"
$params["Uri"] = "$baseUri/?$properties"
if ($null -ne $PSBoundParameters["Property"]) {
$selectProperties = $PSBoundParameters["Property"]
$selectProperties = $selectProperties -Join ','
$properties = "`$select=$($selectProperties)"
$params["Uri"] = "$baseUri/?$properties"
}
if ($PSBoundParameters.ContainsKey("Top")) {
$topCount = $PSBoundParameters["Top"]
if ($topCount -gt 999) {
$params["Uri"] += "&`$top=999"
}
else {
$params["Uri"] += "&`$top=$topCount"
}
}
if ($null -ne $PSBoundParameters["SponsorId"]) {
$params["Uri"] += "&`$filter=id eq '$SponsorId'"
}
if ($null -ne $PSBoundParameters["Filter"]) {
$Filter = $PSBoundParameters["Filter"]
$f = '$' + 'Filter'
$params["Uri"] += "&$f=$Filter"
}
Write-Debug("============================ TRANSFORMATIONS ============================")
$params.Keys | ForEach-Object {"$_ : $($params[$_])" } | Write-Debug
Write-Debug("=========================================================================`n")
$response = Invoke-GraphRequest -Headers $customHeaders -Uri $($params.Uri) -Method GET | ConvertTo-Json -Depth 10 | ConvertFrom-Json
try {
$data = $response.value | ConvertTo-Json -Depth 10 | ConvertFrom-Json
$directoryObjectList = @()
$all = $All.IsPresent
$increment = $topCount - $data.Count

while ($response.'@odata.nextLink' -and (($all -and ($increment -lt 0)) -or $increment -gt 0)) {
$params["Uri"] = $response.'@odata.nextLink'
if ($increment -gt 0) {
$topValue = [Math]::Min($increment, 999)
$params["Uri"] = $params["Uri"].Replace('$top=999', "`$top=$topValue")
$increment -= $topValue
}
$response = Invoke-GraphRequest -Headers $customHeaders -Uri $URI -Method $Method | ConvertTo-Json -Depth 10 | ConvertFrom-Json
$data += $response.value | ConvertTo-Json -Depth 10 | ConvertFrom-Json
}
} catch {}

foreach ($item in $data) {
if ($null -ne $item) {
# Determine the type based on @odata.type
switch ($item.'@odata.type') {
'#microsoft.graph.user' {
$directoryObject = [Microsoft.Graph.PowerShell.Models.MicrosoftGraphUser]::new()
}
'#microsoft.graph.group' {
$directoryObject = [Microsoft.Graph.PowerShell.Models.MicrosoftGraphGroup]::new()
}
default {
Write-Warning "Unknown type: $($item.'@odata.type')"
continue
}
}
$item.PSObject.Properties | ForEach-Object {
$propertyName = $_.Name
$propertyValue = $_.Value
$directoryObject | Add-Member -MemberType NoteProperty -Name $propertyName -Value $propertyValue -Force
}
$directoryObjectList += $directoryObject
}
}
$directoryObjectList
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
function Get-EntraBetaUserSponsor {
[CmdletBinding(DefaultParameterSetName = 'GetQuery')]
param (
[Parameter(ParameterSetName = "GetQuery", ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Filter to apply to the query.")]
[System.String] $Filter,

[Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "The unique identifier (User ID) of the user whose sponsor information you want to retrieve.")]
[System.String] $UserId,

[Alias('Limit')]
[Parameter(ParameterSetName = "GetQuery", ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Maximum number of results to return.")]
[System.Nullable`1[System.Int32]] $Top,

[Parameter(ParameterSetName = "GetQuery", ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Retrieve all user's sponsors.")]
[switch] $All,

[Alias('DirectoryObjectId')]
[Parameter(ParameterSetName = "GetById", Mandatory = $false, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "The User Sponsor ID to retrieve.")]
[System.String] $SponsorId,

[Alias('Select')]
[Parameter(Mandatory = $false, ValueFromPipeline = $false, ValueFromPipelineByPropertyName = $true, HelpMessage = "Properties to include in the results.")]
[System.String[]] $Property
)

PROCESS {
$customHeaders = New-EntraBetaCustomHeaders -Command $MyInvocation.MyCommand
$params = @{}
$topCount = $null
$baseUri = "https://graph.microsoft.com/beta/users/$UserId/sponsors"
$properties = '$select=*'
$params["Method"] = "GET"
$params["Uri"] = "$baseUri/?$properties"
if ($null -ne $PSBoundParameters["Property"]) {
$selectProperties = $PSBoundParameters["Property"]
$selectProperties = $selectProperties -Join ','
$properties = "`$select=$($selectProperties)"
$params["Uri"] = "$baseUri/?$properties"
}
if ($PSBoundParameters.ContainsKey("Top")) {
$topCount = $PSBoundParameters["Top"]
if ($topCount -gt 999) {
$params["Uri"] += "&`$top=999"
}
else {
$params["Uri"] += "&`$top=$topCount"
}
}
if ($null -ne $PSBoundParameters["SponsorId"]) {
$params["Uri"] += "&`$filter=id eq '$SponsorId'"
}
if ($null -ne $PSBoundParameters["Filter"]) {
$Filter = $PSBoundParameters["Filter"]
$f = '$' + 'Filter'
$params["Uri"] += "&$f=$Filter"
}
Write-Debug("============================ TRANSFORMATIONS ============================")
$params.Keys | ForEach-Object {"$_ : $($params[$_])" } | Write-Debug
Write-Debug("=========================================================================`n")
$response = Invoke-GraphRequest -Headers $customHeaders -Uri $($params.Uri) -Method GET | ConvertTo-Json -Depth 10 | ConvertFrom-Json
try {
$data = $response.value | ConvertTo-Json -Depth 10 | ConvertFrom-Json
$directoryObjectList = @()
$all = $All.IsPresent
$increment = $topCount - $data.Count

while ($response.'@odata.nextLink' -and (($all -and ($increment -lt 0)) -or $increment -gt 0)) {
$params["Uri"] = $response.'@odata.nextLink'
if ($increment -gt 0) {
$topValue = [Math]::Min($increment, 999)
$params["Uri"] = $params["Uri"].Replace('$top=999', "`$top=$topValue")
$increment -= $topValue
}
$response = Invoke-GraphRequest -Headers $customHeaders -Uri $URI -Method $Method | ConvertTo-Json -Depth 10 | ConvertFrom-Json
$data += $response.value | ConvertTo-Json -Depth 10 | ConvertFrom-Json
}
} catch {}

foreach ($item in $data) {
if ($null -ne $item) {
# Determine the type based on @odata.type
switch ($item.'@odata.type') {
'#microsoft.graph.user' {
$directoryObject = [Microsoft.Graph.PowerShell.Models.MicrosoftGraphUser]::new()
}
'#microsoft.graph.group' {
$directoryObject = [Microsoft.Graph.PowerShell.Models.MicrosoftGraphGroup]::new()
}
default {
Write-Warning "Unknown type: $($item.'@odata.type')"
continue
}
}
$item.PSObject.Properties | ForEach-Object {
$propertyName = $_.Name
$propertyValue = $_.Value
$directoryObject | Add-Member -MemberType NoteProperty -Name $propertyName -Value $propertyValue -Force
}
$directoryObjectList += $directoryObject
}
}
$directoryObjectList
}
}
185 changes: 185 additions & 0 deletions module/docs/entra-powershell-beta/Users/Get-EntraBetaUserSponsor.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
---
title: Get-EntraBetaUserSponsor
description: This article provides details on the Get-EntraBetaUserSponsor command.

ms.topic: reference
ms.date: 02/10/2025
ms.author: eunicewaweru
ms.reviewer: stevemutungi
manager: CelesteDG
author: msewaweru

schema: 2.0.0
---

# Get-EntraBetaUserSponsor

## Synopsis

Retrieve a user's sponsors (users or groups).

## Syntax

```powershell
Get-EntraBetaUserSponsor
-UserId <String>
[-All]
[-Property <String[]>]
[<CommonParameters>]
```

### GetById

```powershell
Get-EntraBetaUserSponsor
-UserId <String>
-SponsorId <String>
[-Property <String[]>]
[<CommonParameters>]
```

## Description

The `Get-EntraBetaUserSponsor` cmdlet retrieve a user's sponsors (users or groups). The sponsor feature tracks who is responsible for each guest user by assigning a person or group, ensuring accountability.

In delegated scenarios with work or school accounts, the signed-in user needs a supported Microsoft Entra role or a custom role with `microsoft.directory/users/sponsors/read permission`. The least privileged supported roles are:

- Guest Inviter
- Directory Readers
- Directory Writers
- User Administrator

## Examples

### Example 1: Get the user sponsors

```powershell
Connect-Entra -Scopes 'User.Read', 'User.Read.All' # User.Read.All is application-only permission (non-interactive login)
Get-EntraBetaUserSponsor -UserId '[email protected]' |
Select-Object Id, displayName, userPrincipalName, createdDateTime, accountEnabled, userType |
Format-Table -AutoSize
```

```Output
id displayName userPrincipalName createdDateTime accountEnabled userType
-- ----------- ----------------- --------------- -------------- --------
c0c97c58-1895-4910-b1bb-58f96db771df Adele Vance [email protected] 28/10/2024 09:50:43 True Member
79984fce-9e33-497a-a5a2-b3c85e3fedcb Alex Wilber [email protected] 28/10/2024 09:50:46 True Member
406e3c9f-7a2d-4ef0-b1d4-69ddbd2719bb Diego Siciliani [email protected] 28/10/2024 09:50:46 True Member
Comment on lines +64 to +68
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
id displayName userPrincipalName createdDateTime accountEnabled userType
-- ----------- ----------------- --------------- -------------- --------
c0c97c58-1895-4910-b1bb-58f96db771df Adele Vance [email protected].com 28/10/2024 09:50:43 True Member
79984fce-9e33-497a-a5a2-b3c85e3fedcb Alex Wilber [email protected].com 28/10/2024 09:50:46 True Member
406e3c9f-7a2d-4ef0-b1d4-69ddbd2719bb Diego Siciliani [email protected].com 28/10/2024 09:50:46 True Member
id displayName userPrincipalName createdDateTime accountEnabled userType
-- ----------- ----------------- --------------- -------------- --------
cccccccc-2222-3333-4444-dddddddddddd Angel Brown AngelB@contoso.com 28/10/2024 09:50:43 True Member
dddddddd-3333-4444-5555-eeeeeeeeeeee Avery Smith AveryS@contoso.com 28/10/2024 09:50:46 True Member
eeeeeeee-4444-5555-6666-ffffffffffff Sawyer Miller SawyerM@contoso.com 28/10/2024 09:50:46 True Member

```

This example shows how to list user sponsors.

- The `-UserId` parameter specifies the User ID or User Principal Name.

### Example 2: Get top one sponsor

```powershell
Connect-Entra -Scopes 'User.Read', 'User.Read.All' # User.Read.All is application-only permission (non-interactive login)
Get-EntraBetaUserSponsor -UserId '[email protected]' -Top 1 | Select-Object Id, DisplayName, '@odata.type'
```

```Output
Id displayName @odata.type
-- ----------- -----------
cccccccc-2222-3333-4444-dddddddddddd Contoso Group #microsoft.graph.group
```

This example retrieves the top sponsor for the specified user.

- The `-UserId` parameter specifies the User ID or User Principal Name.

### Example 3: Retrieve the assigned sponsor for a specific user by their SponsorId

```powershell
Connect-Entra -Scopes 'User.Read', 'User.Read.All' # User.Read.All is application-only permission (non-interactive login)
Get-EntraBetaUserSponsor -UserId '[email protected]' -SponsorId c0c97c58-1895-4910-b1bb-58f96db771df | Select-Object Id, DisplayName, '@odata.type'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Get-EntraBetaUserSponsor -UserId '[email protected]' -SponsorId c0c97c58-1895-4910-b1bb-58f96db771df | Select-Object Id, DisplayName, '@odata.type'
Get-EntraBetaUserSponsor -UserId '[email protected]' -SponsorId cccccccc-2222-3333-4444-dddddddddddd | Select-Object Id, DisplayName, '@odata.type'

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, @alexandair for the catch!

```

```Output
Id displayName @odata.type
-- ----------- -----------
cccccccc-2222-3333-4444-dddddddddddd Contoso Group #microsoft.graph.group
```

This example retrieves the assigned sponsor for the specified user.

- The `-UserId` parameter specifies the User ID or User Principal Name.
- The `-SponsorId` parameter specifies the specific user's sponsor ID to retrieve.

## Parameters

### -All

List all pages.

```yaml
Type: System.Management.Automation.SwitchParameter
Parameter Sets: (All)
Aliases:

Required: False
Position: Named
Default value: False
Accept pipeline input: False
Accept wildcard characters: False
```

### -UserId

Specifies the ID (as a UserPrincipalName or UserId) of a user in Microsoft Entra ID.

```yaml
Type: System.String
Parameter Sets: (All)

Required: True
Position: Named
Default value: None
Accept pipeline input: True (ByPropertyName, ByValue)
Accept wildcard characters: False
```

### -Top

Specifies the maximum number of records to return.

```yaml
Type: System.Int32
Parameter Sets: (All)
Aliases: Limit

Required: False
Position: Named
Default value: None
Accept pipeline input: True (ByPropertyName, ByValue)
Accept wildcard characters: False
```

### -Property

Specifies properties to be returned.

```yaml
Type: System.String[]
Parameter Sets: (All)
Aliases: Select

Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```

### CommonParameters

This cmdlet supports the common parameters: `-Debug`, `-ErrorAction`, `-ErrorVariable`, `-InformationAction`, `-InformationVariable`, `-OutVariable`, `-OutBuffer`, `-PipelineVariable`, `-Verbose`, `-WarningAction`, and `-WarningVariable`. For more information, see [about_CommonParameters](https://go.microsoft.com/fwlink/?LinkID=113216).

## Inputs

## Outputs

## Notes

## Related Links
Loading