Skip to content

Commit f0e0d46

Browse files
authored
Merge pull request #1615 from KelvinTegelaar/dev
Dev to hotfix
2 parents 567c049 + 818f33b commit f0e0d46

File tree

10 files changed

+257
-14
lines changed

10 files changed

+257
-14
lines changed

CIPP-Permissions.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,11 @@
425425
"Name": "UserAuthenticationMethod.ReadWrite",
426426
"Description": "Allows the app to read and write your authentication methods, including phone numbers and Authenticator app settings.This does not allow the app to see secret information like your passwords, or to sign-in or otherwise use your authentication methods."
427427
},
428+
{
429+
"Id": "424b07a8-1209-4d17-9fe4-9018a93a1024",
430+
"Name": "TeamsTelephoneNumber.ReadWrite.All",
431+
"Description": "Allows the app to read and modify your tenant's acquired telephone number details on behalf of the signed-in admin user. Acquired telephone numbers may include attributes related to assigned object, emergency location, network site, etc."
432+
},
428433
{
429434
"Id": "b7887744-6746-4312-813d-72daeaee7e2d",
430435
"Name": "UserAuthenticationMethod.ReadWrite.All",
@@ -697,6 +702,11 @@
697702
"Name": "User.ReadWrite.All",
698703
"Description": "Allows the app to read and update user profiles without a signed in user."
699704
},
705+
{
706+
"Id": "0a42382f-155c-4eb1-9bdc-21548ccaa387",
707+
"Name": "TeamsTelephoneNumber.ReadWrite.All",
708+
"Description": "Allows the app to read your tenant's acquired telephone number details, without a signed-in user. Acquired telephone numbers may include attributes related to assigned object, emergency location, network site, etc."
709+
},
700710
{
701711
"Id": "50483e42-d915-4231-9639-7fdb7fd190e5",
702712
"Name": "UserAuthenticationMethod.ReadWrite.All",

Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Tools/Invoke-ListMessageTrace.ps1

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using namespace System.Net
22

3-
Function Invoke-ListMessageTrace {
3+
function Invoke-ListMessageTrace {
44
<#
55
.FUNCTIONALITY
66
Entrypoint
@@ -65,11 +65,11 @@ Function Invoke-ListMessageTrace {
6565
MessageTraceId = $Request.Body.ID
6666
RecipientAddress = $Request.Body.recipient
6767
}
68-
New-ExoRequest -TenantId $TenantFilter -Cmdlet 'Get-MessageTraceDetail' -CmdParams $CmdParams | Select-Object @{ Name = 'Date'; Expression = { $_.Date.ToString('u') } }, Event, Action, Detail
68+
New-ExoRequest -TenantId $TenantFilter -Cmdlet 'Get-MessageTraceDetailV2' -CmdParams $CmdParams | Select-Object @{ Name = 'Date'; Expression = { $_.Date.ToString('u') } }, Event, Action, Detail
6969
} else {
7070
Write-Information ($SearchParams | ConvertTo-Json)
7171

72-
New-ExoRequest -TenantId $TenantFilter -Cmdlet 'Get-MessageTrace' -CmdParams $SearchParams | Select-Object MessageTraceId, Status, Subject, RecipientAddress, SenderAddress, @{ Name = 'Received'; Expression = { $_.Received.ToString('u') } }, FromIP, ToIP
72+
New-ExoRequest -TenantId $TenantFilter -Cmdlet 'Get-MessageTraceV2' -CmdParams $SearchParams | Select-Object MessageTraceId, Status, Subject, RecipientAddress, SenderAddress, @{ Name = 'Received'; Expression = { $_.Received.ToString('u') } }, FromIP, ToIP
7373
Write-LogMessage -headers $Request.Headers -API $APIName -tenant $($TenantFilter) -message 'Executed message trace' -Sev 'Info'
7474

7575
}

Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-CIPPOffboardingJob.ps1

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,13 @@ function Invoke-CIPPOffboardingJob {
111111
$_.Exception.Message
112112
}
113113
}
114+
{ $_.RemoveTeamsPhoneDID } {
115+
try {
116+
Remove-CIPPUserTeamsPhoneDIDs -userid $userid -username $username -tenantFilter $TenantFilter -Headers $Headers -APIName $APIName
117+
} catch {
118+
$_.Exception.Message
119+
}
120+
}
114121
{ $_.RemoveLicenses -eq $true } {
115122
Remove-CIPPLicense -userid $userid -username $Username -tenantFilter $TenantFilter -Headers $Headers -APIName $APIName -Schedule
116123
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
using namespace System.Net
2+
3+
function Invoke-DeleteSharepointSite {
4+
<#
5+
.FUNCTIONALITY
6+
Entrypoint
7+
.ROLE
8+
Sharepoint.Site.ReadWrite
9+
#>
10+
[CmdletBinding()]
11+
param($Request, $TriggerMetadata)
12+
13+
$APIName = $Request.Params.CIPPEndpoint
14+
$Headers = $Request.Headers
15+
Write-LogMessage -Headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug'
16+
17+
# Interact with query parameters or the body of the request.
18+
$TenantFilter = $Request.Body.tenantFilter
19+
$SiteId = $Request.Body.SiteId
20+
21+
try {
22+
# Validate required parameters
23+
if (-not $SiteId) {
24+
throw "SiteId is required"
25+
}
26+
if (-not $TenantFilter) {
27+
throw "TenantFilter is required"
28+
}
29+
30+
# Validate SiteId format (GUID)
31+
if ($SiteId -notmatch '^(\{)?[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}(\})?$') {
32+
throw "SiteId must be a valid GUID"
33+
}
34+
35+
$SharePointInfo = Get-SharePointAdminLink -Public $false -tenantFilter $TenantFilter
36+
37+
# Get site information using SharePoint admin API
38+
$SiteInfoUri = "$($SharePointInfo.AdminUrl)/_api/SPO.Tenant/sites('$SiteId')"
39+
40+
# Add the headers that SharePoint REST API expects
41+
$ExtraHeaders = @{
42+
'accept' = 'application/json'
43+
'content-type' = 'application/json'
44+
'odata-version' = '4.0'
45+
}
46+
47+
$SiteInfo = New-GraphGETRequest -scope "$($SharePointInfo.AdminUrl)/.default" -uri $SiteInfoUri -tenantid $TenantFilter -extraHeaders $ExtraHeaders
48+
49+
if (-not $SiteInfo) {
50+
throw "Could not retrieve site information from SharePoint Admin API"
51+
}
52+
53+
# Determine if site is group-connected based on GroupId
54+
$IsGroupConnected = $SiteInfo.GroupId -and $SiteInfo.GroupId -ne "00000000-0000-0000-0000-000000000000"
55+
56+
if ($IsGroupConnected) {
57+
# Use GroupSiteManager/Delete for group-connected sites
58+
$body = @{
59+
siteUrl = $SiteInfo.Url
60+
}
61+
$DeleteUri = "$($SharePointInfo.AdminUrl)/_api/GroupSiteManager/Delete"
62+
} else {
63+
# Use SPSiteManager/delete for regular sites
64+
$body = @{
65+
siteId = $SiteId
66+
}
67+
$DeleteUri = "$($SharePointInfo.AdminUrl)/_api/SPSiteManager/delete"
68+
}
69+
70+
# Execute the deletion
71+
$DeleteResult = New-GraphPOSTRequest -scope "$($SharePointInfo.AdminUrl)/.default" -uri $DeleteUri -body (ConvertTo-Json -Depth 10 -InputObject $body) -tenantid $TenantFilter -extraHeaders $ExtraHeaders
72+
73+
$SiteTypeMsg = if ($IsGroupConnected) { "group-connected" } else { "regular" }
74+
$Results = "Successfully initiated deletion of $SiteTypeMsg SharePoint site with ID $SiteId, this process can take some time to complete in the background"
75+
76+
Write-LogMessage -headers $Headers -API $APIName -tenant $TenantFilter -message $Results -sev Info
77+
$StatusCode = [HttpStatusCode]::OK
78+
79+
} catch {
80+
$ErrorMessage = Get-CippException -Exception $_
81+
$Results = "Failed to delete SharePoint site with ID $SiteId. Error: $($ErrorMessage.NormalizedError)"
82+
Write-LogMessage -headers $Headers -API $APIName -tenant $TenantFilter -message $Results -sev Error -LogData $ErrorMessage
83+
$StatusCode = [HttpStatusCode]::InternalServerError
84+
}
85+
86+
# Associate values to output bindings
87+
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
88+
StatusCode = $StatusCode
89+
Body = @{ 'Results' = $Results }
90+
})
91+
}

Modules/CIPPCore/Public/GraphHelper/New-GraphGetRequest.ps1

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ function New-GraphGetRequest {
5959
$RetryCount = 0
6060
$MaxRetries = 3
6161
$RequestSuccessful = $false
62-
Write-Host "This is attempt $($RetryCount + 1) of $MaxRetries"
62+
Write-Information "GET [ $nextURL ] | tenant: $tenantid | attempt: $($RetryCount + 1) of $MaxRetries"
6363
do {
6464
try {
6565
$GraphRequest = @{
@@ -117,11 +117,24 @@ function New-GraphGetRequest {
117117
} catch {
118118
$ShouldRetry = $false
119119
$WaitTime = 0
120-
121120
try {
122-
$Message = ($_.ErrorDetails.Message | ConvertFrom-Json -ErrorAction SilentlyContinue).error.message
121+
$MessageObj = $_.ErrorDetails.Message | ConvertFrom-Json -ErrorAction SilentlyContinue
122+
if ($MessageObj.error) {
123+
$MessageObj | Add-Member -NotePropertyName 'url' -NotePropertyValue $nextURL -Force
124+
$Message = $MessageObj.error.message -ne '' ? $MessageObj.error.message : $MessageObj.error.code
125+
}
123126
} catch { $Message = $null }
124-
if ($Message -eq $null) { $Message = $($_.Exception.Message) }
127+
128+
if ([string]::IsNullOrEmpty($Message)) {
129+
$Message = $($_.Exception.Message)
130+
$MessageObj = @{
131+
error = @{
132+
code = $_.Exception.GetType().FullName
133+
message = $Message
134+
url = $nextURL
135+
}
136+
}
137+
}
125138

126139
# Check for 429 Too Many Requests
127140
if ($_.Exception.Response.StatusCode -eq 429) {
@@ -147,7 +160,7 @@ function New-GraphGetRequest {
147160
} else {
148161
# Final failure - update tenant error tracking and throw
149162
if ($Message -ne 'Request not applicable to target tenant.' -and $Tenant) {
150-
$Tenant.LastGraphError = $Message
163+
$Tenant.LastGraphError = [string]($MessageObj | ConvertTo-Json -Compress)
151164
if ($Tenant.PSObject.Properties.Name -notcontains 'GraphErrorCount') {
152165
$Tenant | Add-Member -MemberType NoteProperty -Name 'GraphErrorCount' -Value 0 -Force
153166
}

Modules/CIPPCore/Public/GraphRequests/Get-GraphRequestList.ps1

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,6 @@ function Get-GraphRequestList {
8686
$SingleTenantThreshold = 8000
8787
Write-Information "Tenant: $TenantFilter"
8888
$TableName = ('cache{0}' -f ($Endpoint -replace '[^A-Za-z0-9]'))[0..62] -join ''
89-
Write-Information "Table: $TableName"
9089
$Endpoint = $Endpoint -replace '^/', ''
9190
$DisplayName = ($Endpoint -split '/')[0]
9291

@@ -123,7 +122,6 @@ function Get-GraphRequestList {
123122
}
124123
$GraphQuery.Query = $ParamCollection.ToString()
125124
$PartitionKey = Get-StringHash -String (@($Endpoint, $ParamCollection.ToString(), 'v2') -join '-')
126-
Write-Information "PK: $PartitionKey"
127125

128126
# Perform $count check before caching
129127
$Count = 0
@@ -174,7 +172,7 @@ function Get-GraphRequestList {
174172
Write-Information "Total results (`$count): $Count"
175173
}
176174
}
177-
Write-Information ( 'GET [ {0} ]' -f $GraphQuery.ToString())
175+
#Write-Information ( 'GET [ {0} ]' -f $GraphQuery.ToString())
178176

179177
try {
180178
if ($QueueId) {
@@ -196,7 +194,7 @@ function Get-GraphRequestList {
196194
}
197195
$Rows = Get-CIPPAzDataTableEntity @Table -Filter $Filter
198196
$Type = 'Cache'
199-
Write-Information "Cached: $(($Rows | Measure-Object).Count) rows (Type: $($Type))"
197+
Write-Information "Table: $TableName | PK: $PartitionKey | Cached: $(($Rows | Measure-Object).Count) rows (Type: $($Type))"
200198
$QueueReference = '{0}-{1}' -f $TenantFilter, $PartitionKey
201199
$RunningQueue = Invoke-ListCippQueue -Reference $QueueReference | Where-Object { $_.Status -notmatch 'Completed' -and $_.Status -notmatch 'Failed' }
202200
}

Modules/CIPPCore/Public/PermissionsTranslator.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5353,5 +5353,23 @@
53535353
"userConsentDescription": "Access Microsoft Teams and Skype for Business data as the signed in user",
53545354
"userConsentDisplayName": "Access Microsoft Teams and Skype for Business data based on the user's role membership",
53555355
"value": "OnPremDirectorySynchronization.ReadWrite.All"
5356+
},
5357+
{
5358+
"description": "Read and Modify Tenant-Acquired Telephone Number Details",
5359+
"displayName": "Read and Modify Tenant-Acquired Telephone Number Details",
5360+
"id": "424b07a8-1209-4d17-9fe4-9018a93a1024",
5361+
"Origin": "Delegated",
5362+
"userConsentDescription": "Allows the app to read and modify your tenant's acquired telephone number details on behalf of the signed-in admin user. Acquired telephone numbers may include attributes related to assigned object, emergency location, network site, etc.",
5363+
"userConsentDisplayName": "Allows the app to read and modify your tenant's acquired telephone number details on behalf of the signed-in admin user. Acquired telephone numbers may include attributes related to assigned object, emergency location, network site, etc.",
5364+
"value": "TeamsTelephoneNumber.ReadWrite.All"
5365+
},
5366+
{
5367+
"description": "Read and Modify Tenant-Acquired Telephone Number Details",
5368+
"displayName": "Read and Modify Tenant-Acquired Telephone Number Details",
5369+
"id": "0a42382f-155c-4eb1-9bdc-21548ccaa387",
5370+
"Origin": "Application",
5371+
"userConsentDescription": "Allows the app to read your tenant's acquired telephone number details, without a signed-in user. Acquired telephone numbers may include attributes related to assigned object, emergency location, network site, etc.",
5372+
"userConsentDisplayName": "Allows the app to read your tenant's acquired telephone number details, without a signed-in user. Acquired telephone numbers may include attributes related to assigned object, emergency location, network site, etc.",
5373+
"value": "TeamsTelephoneNumber.ReadWrite.All"
53565374
}
53575375
]
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
using namespace System.Net
2+
using namespace System.Collections.Generic
3+
4+
function Remove-CIPPUserTeamsPhoneDIDs {
5+
[CmdletBinding()]
6+
param (
7+
$Headers,
8+
[parameter(Mandatory = $true)]
9+
[string]$UserID,
10+
[string]$Username,
11+
$APIName = 'Remove User Teams Phone DIDs',
12+
[parameter(Mandatory = $true)]
13+
$TenantFilter
14+
)
15+
16+
try {
17+
18+
# Set Username to UserID if not provided
19+
if ([string]::IsNullOrEmpty($Username)) {
20+
$Username = $UserID
21+
}
22+
23+
# Initialize collections for results
24+
$Results = [List[string]]::new()
25+
$SuccessCount = 0
26+
$ErrorCount = 0
27+
28+
# Get all tenant DIDs
29+
$TeamsPhoneDIDs = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/admin/teams/telephoneNumberManagement/numberAssignments" -tenant $TenantFilter
30+
31+
if (-not $TeamsPhoneDIDs -or $TeamsPhoneDIDs.Count -eq 0) {
32+
$Result = "No Teams Phone DIDs found in tenant"
33+
$Results.Add($Result)
34+
return $Results.ToArray()
35+
}
36+
37+
# Filter DIDs assigned to the specific user
38+
$UserDIDs = $TeamsPhoneDIDs | Where-Object { $_.assignmentTargetId -eq $UserID -and $_.assignmentStatus -ne 'unassigned' }
39+
40+
if (-not $UserDIDs -or $UserDIDs.Count -eq 0) {
41+
$Result = "No Teams Phone DIDs found assigned to user: '$Username' - '$UserID'"
42+
$Results.Add($Result)
43+
return $Results.ToArray()
44+
}
45+
46+
# Prepare bulk requests for all DIDs
47+
$RemoveRequests = foreach ($DID in $UserDIDs) {
48+
@{
49+
id = $DID.telephoneNumber
50+
method = 'POST'
51+
url = "admin/teams/telephoneNumberManagement/numberAssignments/unassignNumber"
52+
body = @{
53+
telephoneNumber = $DID.telephoneNumber
54+
numberType = $DID.numberType
55+
}
56+
}
57+
}
58+
59+
# Execute bulk request
60+
$RemoveResults = New-GraphBulkRequest -tenantid $TenantFilter -requests @($RemoveRequests)
61+
62+
# Process results
63+
$RemoveResults | ForEach-Object {
64+
$PhoneNumber = $_.id
65+
66+
if ($_.status -eq 204) {
67+
$SuccessResult = "Successfully removed Teams Phone DID: '$PhoneNumber' from: '$Username' - '$UserID'"
68+
Write-LogMessage -headers $Headers -API $APIName -message $SuccessResult -Sev 'Info' -tenant $TenantFilter
69+
$Results.Add($SuccessResult)
70+
$SuccessCount++
71+
} else {
72+
$ErrorMessage = if ($_.body.error.message) {
73+
$_.body.error.message
74+
} else {
75+
"HTTP Status: $($_.status)"
76+
}
77+
78+
$ErrorResult = "Failed to remove Teams Phone DID: '$PhoneNumber' from: '$Username' - '$UserID'. Error: $ErrorMessage"
79+
Write-LogMessage -headers $Headers -API $APIName -message $ErrorResult -Sev 'Error' -tenant $TenantFilter
80+
$Results.Add($ErrorResult)
81+
$ErrorCount++
82+
}
83+
}
84+
85+
# Add summary result
86+
$SummaryResult = "Completed processing $($UserDIDs.Count) DIDs for user '$Username': $SuccessCount successful, $ErrorCount failed"
87+
Write-LogMessage -headers $Headers -API $APIName -message $SummaryResult -Sev 'Info' -tenant $TenantFilter
88+
$Results.Add($SummaryResult)
89+
90+
return $Results.ToArray()
91+
92+
} catch {
93+
$ErrorMessage = Get-CippException -Exception $_
94+
$Result = "Failed to process Teams Phone DIDs removal for: '$Username' - '$UserID'. Error: $($ErrorMessage.NormalizedError)"
95+
Write-LogMessage -headers $Headers -API $APIName -message $Result -Sev 'Error' -tenant $TenantFilter -LogData $ErrorMessage
96+
throw $Result
97+
}
98+
}

Modules/CIPPCore/Public/SAMManifest.json

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,14 @@
570570
{
571571
"id": "b7887744-6746-4312-813d-72daeaee7e2d",
572572
"type": "Scope"
573+
},
574+
{
575+
"id": "424b07a8-1209-4d17-9fe4-9018a93a1024",
576+
"type": "Scope"
577+
},
578+
{
579+
"id": "0a42382f-155c-4eb1-9bdc-21548ccaa387",
580+
"type": "Role"
573581
}
574582
]
575583
},
@@ -643,4 +651,4 @@
643651
]
644652
}
645653
]
646-
}
654+
}

version_latest.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
8.4.0
1+
8.4.2

0 commit comments

Comments
 (0)