Skip to content

Commit b347c11

Browse files
authored
Merge pull request #223 from KelvinTegelaar/dev
[pull] dev from KelvinTegelaar:dev
2 parents 996d20f + f901470 commit b347c11

File tree

10 files changed

+199
-40
lines changed

10 files changed

+199
-40
lines changed

Modules/CIPPCore/Public/Alerts/Get-CIPPAlertNewAppApproval.ps1

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,25 @@ function Get-CIPPAlertNewAppApproval {
1313
$Headers
1414
)
1515
try {
16-
$Approvals = New-GraphGetRequest -Uri "https://graph.microsoft.com/v1.0/identityGovernance/appConsent/appConsentRequests?`$filter=userConsentRequests/any (u:u/status eq 'InProgress')" -tenantid $TenantFilter
16+
$Approvals = New-GraphGetRequest -Uri "https://graph.microsoft.com/beta/identityGovernance/appConsent/appConsentRequests?`$filter=userConsentRequests/any (u:u/status eq 'InProgress')" -tenantid $TenantFilter
1717
if ($Approvals.count -gt 0) {
18-
$AlertData = "There are $($Approvals.count) App Approval(s) pending."
18+
$AlertData = [System.Collections.Generic.List[string]]::new()
19+
foreach ($App in $Approvals) {
20+
$userConsentRequests = New-GraphGetRequest -Uri "https://graph.microsoft.com/v1.0/identityGovernance/appConsent/appConsentRequests/$($App.id)/userConsentRequests" -tenantid $TenantFilter
21+
$userConsentRequests | ForEach-Object {
22+
$consentUrl = if ($App.consentType -eq 'Static') {
23+
# if something is going wrong here you've probably stumbled on a fourth variation - rvdwegen
24+
"https://login.microsoftonline.com/$($TenantFilter)/adminConsent?client_id=$($App.appId)&bf_id=$($App.id)&redirect_uri=https://entra.microsoft.com/TokenAuthorize"
25+
} elseif ($App.pendingScopes.displayName) {
26+
"https://login.microsoftonline.com/$($TenantFilter)/v2.0/adminConsent?client_id=$($App.appId)&scope=$($App.pendingScopes.displayName -Join(' '))&bf_id=$($App.id)&redirect_uri=https://entra.microsoft.com/TokenAuthorize"
27+
} else {
28+
"https://login.microsoftonline.com/$($TenantFilter)/adminConsent?client_id=$($App.appId)&bf_id=$($App.id)&redirect_uri=https://entra.microsoft.com/TokenAuthorize"
29+
}
30+
31+
$Message = "App name: $($App.appDisplayName) - Request user: $($_.createdBy.user.userPrincipalName) - Reason: $($_.reason)`nApp Id: $($App.appId) - Scopes: $($App.pendingScopes.displayName)`nConsent URL: $consentUrl"
32+
$AlertData.Add($Message)
33+
}
34+
}
1935
Write-AlertTrace -cmdletName $MyInvocation.MyCommand -tenantFilter $TenantFilter -data $AlertData
2036
}
2137
} catch {
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
function Invoke-ExecSetRecipientLimits {
2+
<#
3+
.FUNCTIONALITY
4+
Entrypoint
5+
.ROLE
6+
Exchange.Mailbox.ReadWrite
7+
#>
8+
[CmdletBinding()]
9+
param($Request, $TriggerMetadata)
10+
11+
$APIName = $Request.Params.CIPPEndpoint
12+
$Headers = $Request.Headers
13+
Write-LogMessage -Headers $Headers -API $APIName -tenant $TenantFilter -message 'Accessed this API' -Sev 'Debug'
14+
15+
# Interact with the query or body of the request
16+
$TenantFilter = $Request.Body.tenantFilter
17+
$recipientLimit = $Request.Body.recipientLimit
18+
$Identity = $Request.Body.Identity
19+
$UserPrincipalName = $Request.Body.userid
20+
21+
# Set the parameters for the EXO request
22+
$ExoRequest = @{
23+
tenantid = $TenantFilter
24+
cmdlet = 'Set-Mailbox'
25+
cmdParams = @{
26+
Identity = $Identity
27+
RecipientLimits = $recipientLimit
28+
}
29+
}
30+
31+
# Execute the EXO request
32+
try {
33+
$null = New-ExoRequest @ExoRequest
34+
$Results = "Recipient limit for $UserPrincipalName has been set to $recipientLimit"
35+
36+
Write-LogMessage -API $APIName -tenant $TenantFilter -message $Results -sev Info
37+
$StatusCode = [HttpStatusCode]::OK
38+
} catch {
39+
$ErrorMessage = Get-CippException -Exception $_
40+
$Results = "Could not set recipient limit for $UserPrincipalName to $recipientLimit. Error: $($ErrorMessage.NormalizedError)"
41+
Write-LogMessage -API $APIName -tenant $TenantFilter -message $Results -sev Error -LogData $ErrorMessage
42+
$StatusCode = [HttpStatusCode]::InternalServerError
43+
}
44+
45+
# Associate values to output bindings by calling 'Push-OutputBinding'.
46+
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
47+
StatusCode = $StatusCode
48+
Body = @{ Results = $Results }
49+
})
50+
}

Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ListMailboxes.ps1

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,8 @@ Function Invoke-ListMailboxes {
6363
@{ Name = 'recipientType'; Expression = { $_.'RecipientType' } },
6464
@{ Name = 'recipientTypeDetails'; Expression = { $_.'RecipientTypeDetails' } },
6565
@{ Name = 'AdditionalEmailAddresses'; Expression = { ($_.'EmailAddresses' | Where-Object { $_ -clike 'smtp:*' }).Replace('smtp:', '') -join ', ' } },
66-
@{Name = 'ForwardingSmtpAddress'; Expression = { $_.'ForwardingSmtpAddress' -replace 'smtp:', '' } },
67-
@{Name = 'InternalForwardingAddress'; Expression = { $_.'ForwardingAddress' } },
66+
@{ Name = 'ForwardingSmtpAddress'; Expression = { $_.'ForwardingSmtpAddress' -replace 'smtp:', '' } },
67+
@{ Name = 'InternalForwardingAddress'; Expression = { $_.'ForwardingAddress' } },
6868
DeliverToMailboxAndForward,
6969
HiddenFromAddressListsEnabled,
7070
ExternalDirectoryObjectId,
@@ -77,6 +77,8 @@ Function Invoke-ListMailboxes {
7777
ComplianceTagHoldApplied,
7878
RetentionHoldEnabled,
7979
InPlaceHolds
80+
# This select also exists in ListUserMailboxDetails and should be updated if this is changed here
81+
8082

8183
$StatusCode = [HttpStatusCode]::OK
8284
} catch {

Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-ExecAssignApp.ps1

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,10 @@ Function Invoke-ExecAssignApp {
1414
$Headers = $Request.Headers
1515
Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug'
1616

17-
18-
19-
2017
# Interact with query parameters or the body of the request.
21-
$tenantfilter = $Request.Query.TenantFilter
22-
$appFilter = $Request.Query.ID
23-
$AssignTo = $Request.Query.AssignTo
18+
$TenantFilter = $Request.Query.tenantFilter ?? $Request.Body.tenantFilter
19+
$appFilter = $Request.Query.ID ?? $Request.Body.ID
20+
$AssignTo = $Request.Query.AssignTo ?? $Request.Body.AssignTo
2421
$AssignBody = switch ($AssignTo) {
2522

2623
'AllUsers' {
@@ -42,20 +39,23 @@ Function Invoke-ExecAssignApp {
4239
}
4340

4441
}
45-
$body = [pscustomobject]@{'Results' = "$($TenantFilter): Assigned app to $assignTo" }
4642
try {
47-
$GraphRequest = New-Graphpostrequest -uri "https://graph.microsoft.com/beta/deviceAppManagement/mobileApps/$appFilter/assign" -tenantid $TenantFilter -body $Assignbody
48-
Write-LogMessage -headers $Request.Headers -API $APINAME -tenant $($tenantfilter) -message "Assigned $($appFilter) to $assignTo" -Sev 'Info'
43+
$null = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceAppManagement/mobileApps/$appFilter/assign" -tenantid $TenantFilter -body $AssignBody
44+
$Result = "Successfully assigned app $($appFilter) to $($AssignTo)"
45+
Write-LogMessage -headers $Headers -API $APIName -tenant $($TenantFilter) -message $Result -Sev Info
46+
$StatusCode = [HttpStatusCode]::OK
4947

5048
} catch {
51-
Write-LogMessage -headers $Request.Headers -API $APINAME -tenant $($tenantfilter) -message "Failed to assign app $($appFilter): $($_.Exception.Message)" -Sev 'Error'
52-
$body = [pscustomobject]@{'Results' = "Failed to assign. $($_.Exception.Message)" }
49+
$ErrorMessage = Get-CippException -Exception $_
50+
$Result = "Failed to assign app $($appFilter) to $($AssignTo). Error: $($ErrorMessage.NormalizedError)"
51+
Write-LogMessage -headers $Headers -API $APIName -tenant $TenantFilter -message $Result -Sev 'Error' -LogData $ErrorMessage
52+
$StatusCode = [HttpStatusCode]::InternalServerError
5353
}
5454

5555
# Associate values to output bindings by calling 'Push-OutputBinding'.
5656
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
57-
StatusCode = [HttpStatusCode]::OK
58-
Body = $body
57+
StatusCode = $StatusCode
58+
Body = @{ Results = $Result }
5959
})
6060

6161
}

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

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,20 @@ Function Invoke-AddUser {
3838
} else {
3939
$CreationResults = New-CIPPUserTask -userobj $UserObj -APIName $APINAME -Headers $Request.Headers
4040
$body = [pscustomobject] @{
41-
'Results' = $CreationResults.Results
42-
'Username' = $CreationResults.username
43-
'Password' = $CreationResults.password
41+
'Results' = @(
42+
$CreationResults.Results[0],
43+
$CreationResults.Results[1],
44+
@{
45+
'resultText' = $CreationResults.Results[2]
46+
'copyField' = $CreationResults.password
47+
'state' = 'success'
48+
}
49+
)
4450
'CopyFrom' = @{
4551
'Success' = $CreationResults.CopyFrom.Success
4652
'Error' = $CreationResults.CopyFrom.Error
4753
}
4854
}
49-
5055
}
5156
# Associate values to output bindings by calling 'Push-OutputBinding'.
5257
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{

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

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -178,9 +178,9 @@ function Invoke-ListUserMailboxDetails {
178178
}
179179

180180
# Parse InPlaceHolds to determine hold types if avaliable
181-
$InPlaceHold = $false
182-
$EDiscoveryHold = $false
183-
$PurviewRetentionHold = $false
181+
$InPlaceHold = $false
182+
$EDiscoveryHold = $false
183+
$PurviewRetentionHold = $false
184184
$ExcludedFromOrgWideHold = $false
185185

186186
# Check if InPlaceHolds property exists and has values
@@ -192,10 +192,10 @@ function Invoke-ListUserMailboxDetails {
192192
}
193193
# In-Place Hold - no prefix or starts with cld
194194
# Check if it doesn't match any of the other known prefixes
195-
elseif (($hold -like 'cld*' -or
196-
($hold -notlike 'UniH*' -and
197-
$hold -notlike 'mbx*' -and
198-
$hold -notlike 'skp*' -and
195+
elseif (($hold -like 'cld*' -or
196+
($hold -notlike 'UniH*' -and
197+
$hold -notlike 'mbx*' -and
198+
$hold -notlike 'skp*' -and
199199
$hold -notlike '-mbx*'))) {
200200
$InPlaceHold = $true
201201
}
@@ -240,20 +240,28 @@ function Invoke-ListUserMailboxDetails {
240240
AutoExpandingArchive = $AutoExpandingArchiveEnabled
241241
RecipientTypeDetails = $MailboxDetailedRequest.RecipientTypeDetails
242242
Mailbox = $MailboxDetailedRequest
243-
MailboxActionsData = ($MailboxDetailedRequest | Select-Object id, ExchangeGuid, ArchiveGuid, WhenSoftDeleted, @{ Name = 'UPN'; Expression = { $_.'UserPrincipalName' } },
243+
MailboxActionsData = ($MailboxDetailedRequest | Select-Object id, ExchangeGuid, ArchiveGuid, WhenSoftDeleted,
244+
@{ Name = 'UPN'; Expression = { $_.'UserPrincipalName' } },
244245
@{ Name = 'displayName'; Expression = { $_.'DisplayName' } },
245246
@{ Name = 'primarySmtpAddress'; Expression = { $_.'PrimarySMTPAddress' } },
246247
@{ Name = 'recipientType'; Expression = { $_.'RecipientType' } },
247248
@{ Name = 'recipientTypeDetails'; Expression = { $_.'RecipientTypeDetails' } },
248249
@{ Name = 'AdditionalEmailAddresses'; Expression = { ($_.'EmailAddresses' | Where-Object { $_ -clike 'smtp:*' }).Replace('smtp:', '') -join ', ' } },
249-
@{Name = 'ForwardingSmtpAddress'; Expression = { $_.'ForwardingSmtpAddress' -replace 'smtp:', '' } },
250-
@{Name = 'InternalForwardingAddress'; Expression = { $_.'ForwardingAddress' } },
250+
@{ Name = 'ForwardingSmtpAddress'; Expression = { $_.'ForwardingSmtpAddress' -replace 'smtp:', '' } },
251+
@{ Name = 'InternalForwardingAddress'; Expression = { $_.'ForwardingAddress' } },
251252
DeliverToMailboxAndForward,
252253
HiddenFromAddressListsEnabled,
253254
ExternalDirectoryObjectId,
254255
MessageCopyForSendOnBehalfEnabled,
255-
MessageCopyForSentAsEnabled)
256-
} # Select statement taken from ListMailboxes to save a EXO request
256+
MessageCopyForSentAsEnabled,
257+
LitigationHoldEnabled,
258+
LitigationHoldDate,
259+
LitigationHoldDuration,
260+
@{ Name = 'LicensedForLitigationHold'; Expression = { ($_.PersistedCapabilities -contains 'BPOS_S_DlpAddOn' -or $_.PersistedCapabilities -contains 'BPOS_S_Enterprise') } },
261+
ComplianceTagHoldApplied,
262+
RetentionHoldEnabled,
263+
InPlaceHolds)
264+
} # Select statement taken from ListMailboxes to save a EXO request. If updated here, update in ListMailboxes as well.
257265

258266
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
259267
StatusCode = [HttpStatusCode]::OK

Modules/CIPPCore/Public/New-CIPPUserTask.ps1

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ function New-CIPPUserTask {
1313
$Results.Add('Created New User.')
1414
$Results.Add("Username: $($CreationResults.Username)")
1515
$Results.Add("Password: $($CreationResults.Password)")
16-
$Results.Add("$($CreationResults.Password)")
1716
} catch {
1817
$Results.Add("Failed to create user. $($_.Exception.Message)" )
1918
return @{'Results' = $Results }

Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardStaleEntraDevices.ps1

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ function Invoke-CIPPStandardStaleEntraDevices {
77
.SYNOPSIS
88
(Label) Cleanup stale Entra devices
99
.DESCRIPTION
10-
(Helptext) Cleans up Entra devices that have not connected/signed in for the specified number of days.
11-
(DocsDescription) Cleans up Entra devices that have not connected/signed in for the specified number of days. First disables and later deletes the devices. More info can be found in the [Microsoft documentation](https://learn.microsoft.com/en-us/entra/identity/devices/manage-stale-devices)
10+
(Helptext) Remediate is currently not available. Cleans up Entra devices that have not connected/signed in for the specified number of days.
11+
(DocsDescription) Remediate is currently not available. Cleans up Entra devices that have not connected/signed in for the specified number of days. First disables and later deletes the devices. More info can be found in the [Microsoft documentation](https://learn.microsoft.com/en-us/entra/identity/devices/manage-stale-devices)
1212
.NOTES
1313
CAT
1414
Entra (AAD) Standards
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
function Invoke-CIPPStandardTeamsMeetingRecordingExpiration {
2+
<#
3+
.FUNCTIONALITY
4+
Internal
5+
.COMPONENT
6+
(APIName) TeamsMeetingRecordingExpiration
7+
.SYNOPSIS
8+
(Label) Set Teams Meeting Recording Expiration
9+
.DESCRIPTION
10+
(Helptext) Sets the default number of days after which Teams meeting recordings automatically expire. Valid values are -1 (Never Expire) or between 1 and 99999. The default value is 120 days.
11+
(DocsDescription) Allows administrators to configure a default expiration period (in days) for Teams meeting recordings. Recordings older than this period will be automatically moved to the recycle bin. This setting helps manage storage consumption and enforce data retention policies.
12+
.NOTES
13+
CAT
14+
Teams Standards
15+
TAG
16+
ADDEDCOMPONENT
17+
{"type":"number","name":"standards.TeamsMeetingRecordingExpiration.ExpirationDays","label":"Recording Expiration Days (e.g., 365)","required":true}
18+
IMPACT
19+
Medium Impact
20+
ADDEDDATE
21+
2025-04-17
22+
POWERSHELLEQUIVALENT
23+
Set-CsTeamsMeetingPolicy -Identity Global -MeetingRecordingExpirationDays \<days\>
24+
RECOMMENDEDBY
25+
UPDATECOMMENTBLOCK
26+
Run the Tools\Update-StandardsComments.ps1 script to update this comment block
27+
.LINK
28+
https://docs.cipp.app/user-documentation/tenant/standards/list-standards/teams-standards#medium-impact
29+
#>
30+
##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'TeamsMeetingRecordingExpiration'
31+
32+
param($Tenant, $Settings)
33+
34+
# Input validation
35+
$ExpirationDays = try { [int64]$Settings.ExpirationDays } catch { Write-Warning "Invalid ExpirationDays value provided: $($Settings.ExpirationDays)"; return }
36+
if (($ExpirationDays -ne -1) -and ($ExpirationDays -lt 1 -or $ExpirationDays -gt 99999)) {
37+
Write-LogMessage -API 'Standards' -tenant $Tenant -message "Invalid ExpirationDays value: $ExpirationDays. Must be -1 (Never Expire) or between 1 and 99999." -sev Error
38+
return
39+
}
40+
41+
$CurrentExpirationDays = (New-TeamsRequest -TenantFilter $Tenant -Cmdlet 'Get-CsTeamsMeetingPolicy' -CmdParams @{Identity = 'Global' }).NewMeetingRecordingExpirationDays
42+
$StateIsCorrect = if ($CurrentExpirationDays -eq $ExpirationDays) { $true } else { $false }
43+
44+
if ($Settings.remediate -eq $true) {
45+
Write-Host 'Time to remediate'
46+
if ($StateIsCorrect -eq $true) {
47+
Write-LogMessage -API 'Standards' -tenant $Tenant -message "Teams Meeting Recording Expiration Policy already set to $ExpirationDays days." -sev Info
48+
} else {
49+
$cmdParams = @{
50+
Identity = 'Global'
51+
NewMeetingRecordingExpirationDays = $ExpirationDays
52+
}
53+
54+
try {
55+
New-TeamsRequest -TenantFilter $Tenant -Cmdlet 'Set-CsTeamsMeetingPolicy' -CmdParams $cmdParams
56+
Write-LogMessage -API 'Standards' -tenant $Tenant -message "Successfully updated Teams Meeting Recording Expiration Policy to $ExpirationDays days." -sev Info
57+
} catch {
58+
$ErrorMessage = Get-CippException -Exception $_
59+
Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to set Teams Meeting Recording Expiration Policy. Error: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage
60+
}
61+
}
62+
}
63+
64+
if ($Settings.alert -eq $true) {
65+
if ($StateIsCorrect -eq $true) {
66+
Write-LogMessage -API 'Standards' -tenant $Tenant -message "Teams Meeting Recording Expiration Policy is set correctly ($($CurrentExpirationDays) days)." -sev Info
67+
} else {
68+
Write-StandardsAlert -message "Teams Meeting Recording Expiration Policy is not set correctly. Current: $CurrentExpirationDays days, Desired: $ExpirationDays days." -object $CurrentExpirationDays -tenant $Tenant -standardName 'TeamsMeetingRecordingExpiration' -standardId $Settings.standardId
69+
Write-LogMessage -API 'Standards' -tenant $Tenant -message "Teams Meeting Recording Expiration Policy is not set correctly (Current: $CurrentExpirationDays, Desired: $ExpirationDays)." -sev Info
70+
}
71+
}
72+
73+
if ($Settings.report -eq $true) {
74+
Add-CIPPBPAField -FieldName 'TeamsMeetingRecordingExpiration' -FieldValue $CurrentExpirationDays -StoreAs string -Tenant $Tenant
75+
76+
$CurrentExpirationDays = [PSCustomObject]@{
77+
ExpirationDays = [string]$CurrentExpirationDays
78+
}
79+
Set-CIPPStandardsCompareField -FieldName 'standards.TeamsMeetingRecordingExpiration' -FieldValue $CurrentExpirationDays -Tenant $Tenant
80+
}
81+
}

Tools/Update-StandardsComments.ps1

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -106,12 +106,10 @@ foreach ($Standard in $StandardsInfo) {
106106
$NewComment.Add(" $(ConvertTo-Json -InputObject $Value -Depth 5 -Compress)`n")
107107
}
108108
continue
109-
}
110-
elseif ($Property.Value -is [System.Management.Automation.PSCustomObject]) {
109+
} elseif ($Property.Value -is [System.Management.Automation.PSCustomObject]) {
111110
$NewComment.Add(" $(ConvertTo-Json -InputObject $Property.Value -Depth 5 -Compress)`n")
112111
continue
113-
}
114-
else {
112+
} else {
115113
if ($null -ne $Property.Value) {
116114
$NewComment.Add(" $(EscapeMarkdown($Property.Value.ToString()))`n")
117115
}

0 commit comments

Comments
 (0)