Skip to content

Commit a22892a

Browse files
authored
Merge pull request #312 from KelvinTegelaar/dev
[pull] dev from KelvinTegelaar:dev
2 parents bebccd9 + a82676d commit a22892a

File tree

8 files changed

+193
-27
lines changed

8 files changed

+193
-27
lines changed

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

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,22 @@ function Get-CIPPAlertAppSecretExpiry {
1818
return
1919
}
2020

21-
$AlertData = foreach ($App in $applist) {
21+
$AlertData = [System.Collections.Generic.List[PSCustomObject]]::new()
22+
23+
foreach ($App in $applist) {
2224
Write-Host "checking $($App.displayName)"
2325
if ($App.passwordCredentials) {
2426
foreach ($Credential in $App.passwordCredentials) {
2527
if ($Credential.endDateTime -lt (Get-Date).AddDays(30) -and $Credential.endDateTime -gt (Get-Date).AddDays(-7)) {
2628
Write-Host ("Application '{0}' has secrets expiring on {1}" -f $App.displayName, $Credential.endDateTime)
27-
@{ DisplayName = $App.displayName; Expires = $Credential.endDateTime }
29+
30+
$Message = [PSCustomObject]@{
31+
AppName = $App.displayName
32+
AppId = $App.appId
33+
Expires = $Credential.endDateTime
34+
Tenant = $TenantFilter
35+
}
36+
$AlertData.Add($Message)
2837
}
2938
}
3039
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
function Get-CIPPAlertNewRiskyUsers {
2+
<#
3+
.FUNCTIONALITY
4+
Entrypoint
5+
#>
6+
[CmdletBinding()]
7+
Param (
8+
[Parameter(Mandatory = $false)]
9+
[Alias('input')]
10+
$TenantFilter
11+
)
12+
$Deltatable = Get-CIPPTable -Table DeltaCompare
13+
try {
14+
# Check if tenant has P2 capabilities
15+
$Capabilities = Get-CIPPTenantCapabilities -TenantFilter $TenantFilter
16+
if (-not $Capabilities.AADPremiumService) {
17+
Write-AlertMessage -tenant $($TenantFilter) -message 'Tenant does not have Azure AD Premium P2 licensing required for risky users detection'
18+
return
19+
}
20+
21+
$Filter = "PartitionKey eq 'RiskyUsersDelta' and RowKey eq '{0}'" -f $TenantFilter
22+
$RiskyUsersDelta = (Get-CIPPAzDataTableEntity @Deltatable -Filter $Filter).delta | ConvertFrom-Json -ErrorAction SilentlyContinue
23+
24+
# Get current risky users with more detailed information
25+
$NewDelta = (New-GraphGetRequest -uri 'https://graph.microsoft.com/v1.0/identityProtection/riskyUsers' -tenantid $TenantFilter) | Select-Object userPrincipalName, riskLevel, riskState, riskDetail, riskLastUpdatedDateTime, isProcessing, history
26+
27+
$NewDeltatoSave = $NewDelta | ConvertTo-Json -Depth 10 -Compress -ErrorAction SilentlyContinue | Out-String
28+
$DeltaEntity = @{
29+
PartitionKey = 'RiskyUsersDelta'
30+
RowKey = [string]$TenantFilter
31+
delta = "$NewDeltatoSave"
32+
}
33+
Add-CIPPAzDataTableEntity @DeltaTable -Entity $DeltaEntity -Force
34+
35+
if ($RiskyUsersDelta) {
36+
$AlertData = $NewDelta | Where-Object {
37+
$_.userPrincipalName -notin $RiskyUsersDelta.userPrincipalName
38+
} | ForEach-Object {
39+
$riskHistory = if ($_.history) {
40+
$latestHistory = $_.history | Sort-Object -Property riskLastUpdatedDateTime -Descending | Select-Object -First 1
41+
"Previous Risk Level: $($latestHistory.riskLevel), Last Updated: $($latestHistory.riskLastUpdatedDateTime)"
42+
}
43+
else {
44+
'No previous risk history'
45+
}
46+
47+
# Map risk level to severity
48+
$severity = switch ($_.riskLevel) {
49+
'high' { 'Critical' }
50+
'medium' { 'Warning' }
51+
'low' { 'Info' }
52+
default { 'Info' }
53+
}
54+
55+
@{
56+
Message = "New risky user detected: $($_.userPrincipalName)"
57+
Details = @{
58+
RiskLevel = $_.riskLevel
59+
RiskState = $_.riskState
60+
RiskDetail = $_.riskDetail
61+
LastUpdated = $_.riskLastUpdatedDateTime
62+
IsProcessing = $_.isProcessing
63+
RiskHistory = $riskHistory
64+
Severity = $severity
65+
}
66+
}
67+
}
68+
69+
if ($AlertData) {
70+
Write-AlertTrace -cmdletName $MyInvocation.MyCommand -tenantFilter $TenantFilter -data $AlertData
71+
}
72+
}
73+
}
74+
catch {
75+
Write-AlertMessage -tenant $($TenantFilter) -message "Could not get risky users for $($TenantFilter): $(Get-NormalizedError -message $_.Exception.message)"
76+
}
77+
}

Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecCombinedSetup.ps1

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,25 @@
11
using namespace System.Net
22

3-
Function Invoke-ExecCombinedSetup {
3+
function Invoke-ExecCombinedSetup {
44
<#
55
.FUNCTIONALITY
66
Entrypoint,AnyTenant
77
.ROLE
88
CIPP.AppSettings.ReadWrite
99
#>
10+
[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '')]
1011
[CmdletBinding()]
1112
param($Request, $TriggerMetadata)
1213
#Make arraylist of Results
1314
$Results = [System.Collections.ArrayList]::new()
1415
try {
16+
# Set up Azure context if needed for Key Vault access
17+
if ($env:AzureWebJobsStorage -ne 'UseDevelopmentStorage=true' -and $env:MSI_SECRET) {
18+
Disable-AzContextAutosave -Scope Process | Out-Null
19+
$null = Connect-AzAccount -Identity
20+
$SubscriptionId = $env:WEBSITE_OWNER_NAME -split '\+' | Select-Object -First 1
21+
$null = Set-AzContext -SubscriptionId $SubscriptionId
22+
}
1523
if ($request.body.selectedBaselines -and $request.body.baselineOption -eq 'downloadBaselines') {
1624
#do a single download of the selected baselines.
1725
foreach ($template in $request.body.selectedBaselines) {
@@ -56,6 +64,47 @@ Function Invoke-ExecCombinedSetup {
5664
$notificationResults = Set-CIPPNotificationConfig @notificationConfig
5765
$Results.add($notificationResults)
5866
}
67+
if ($Request.Body.selectedOption -eq 'Manual') {
68+
$KV = $env:WEBSITE_DEPLOYMENT_ID
69+
70+
if ($env:AzureWebJobsStorage -eq 'UseDevelopmentStorage=true') {
71+
$DevSecretsTable = Get-CIPPTable -tablename 'DevSecrets'
72+
$Secret = Get-CIPPAzDataTableEntity @DevSecretsTable -Filter "PartitionKey eq 'Secret' and RowKey eq 'Secret'"
73+
if (!$Secret) {
74+
$Secret = [PSCustomObject]@{
75+
'PartitionKey' = 'Secret'
76+
'RowKey' = 'Secret'
77+
'TenantId' = ''
78+
'RefreshToken' = ''
79+
'ApplicationId' = ''
80+
'ApplicationSecret' = ''
81+
}
82+
Add-CIPPAzDataTableEntity @DevSecretsTable -Entity $Secret -Force
83+
}
84+
85+
if ($Request.Body.tenantId) { $Secret.TenantId = $Request.Body.tenantid }
86+
if ($Request.Body.applicationId) { $Secret.ApplicationId = $Request.Body.applicationId }
87+
if ($Request.Body.ApplicationSecret) { $Secret.ApplicationSecret = $Request.Body.ApplicationSecret }
88+
Add-CIPPAzDataTableEntity @DevSecretsTable -Entity $Secret -Force
89+
$Results.add('Manual credentials have been set in the DevSecrets table.')
90+
} else {
91+
if ($Request.Body.tenantId) {
92+
Set-AzKeyVaultSecret -VaultName $kv -Name 'tenantid' -SecretValue (ConvertTo-SecureString -String $Request.Body.tenantId -AsPlainText -Force)
93+
$Results.add('Set tenant ID in Key Vault.')
94+
}
95+
if ($Request.Body.applicationId) {
96+
Set-AzKeyVaultSecret -VaultName $kv -Name 'applicationid' -SecretValue (ConvertTo-SecureString -String $Request.Body.applicationId -AsPlainText -Force)
97+
$Results.add('Set application ID in Key Vault.')
98+
}
99+
if ($Request.Body.applicationSecret) {
100+
Set-AzKeyVaultSecret -VaultName $kv -Name 'applicationsecret' -SecretValue (ConvertTo-SecureString -String $Request.Body.applicationSecret -AsPlainText -Force)
101+
$Results.add('Set application secret in Key Vault.')
102+
}
103+
}
104+
105+
$Results.add('Manual credentials setup has been completed.')
106+
}
107+
59108
$Results.add('Setup is now complete. You may navigate away from this page and start using CIPP.')
60109
#one more force of reauth so env vars update.
61110
$auth = Get-CIPPAuthentication

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

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,19 @@ Function Invoke-ExecEmailForward {
1212

1313
$Tenantfilter = $request.body.tenantfilter
1414
$username = $request.body.userid
15-
$ForwardingAddress = $request.body.ForwardInternal.value
15+
if ($request.body.ForwardInternal -is [string]) {
16+
$ForwardingAddress = $request.body.ForwardInternal
17+
} else {($request.body.ForwardInternal.value)
18+
$ForwardingAddress = $request.body.ForwardInternal.value
19+
}
1620
$ForwardingSMTPAddress = $request.body.ForwardExternal
1721
$ForwardOption = $request.body.forwardOption
1822
$APIName = $Request.Params.CIPPEndpoint
19-
[bool]$KeepCopy = if ($request.body.keepCopy -eq 'true') { $true } else { $false }
23+
[bool]$KeepCopy = if ($request.body.KeepCopy -eq 'true') { $true } else { $false }
2024

2125
if ($ForwardOption -eq 'internalAddress') {
2226
try {
23-
Set-CIPPForwarding -userid $username -tenantFilter $TenantFilter -APIName $APINAME -Headers $Request.Headers -Forward $ForwardingAddress -keepCopy $KeepCopy
27+
Set-CIPPForwarding -userid $username -tenantFilter $TenantFilter -APIName $APINAME -Headers $Request.Headers -Forward $ForwardingAddress -KeepCopy $KeepCopy
2428
if (-not $request.body.KeepCopy) {
2529
$results = "Forwarding all email for $($username) to $($ForwardingAddress) and not keeping a copy"
2630
} else {
@@ -35,7 +39,7 @@ Function Invoke-ExecEmailForward {
3539

3640
if ($ForwardOption -eq 'ExternalAddress') {
3741
try {
38-
Set-CIPPForwarding -userid $username -tenantFilter $TenantFilter -APIName $APINAME -Headers $Request.Headers -forwardingSMTPAddress $ForwardingSMTPAddress -keepCopy $KeepCopy
42+
Set-CIPPForwarding -userid $username -tenantFilter $TenantFilter -APIName $APINAME -Headers $Request.Headers -forwardingSMTPAddress $ForwardingSMTPAddress -KeepCopy $KeepCopy
3943
if (-not $request.body.KeepCopy) {
4044
$results = "Forwarding all email for $($username) to $($ForwardingSMTPAddress) and not keeping a copy"
4145
} else {

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,10 @@ function Invoke-CIPPOffboardingJob {
4545
Set-CIPPOutOfOffice -tenantFilter $TenantFilter -userid $username -InternalMessage $Options.OOO -ExternalMessage $Options.OOO -Headers $Headers -APIName $APIName -state 'Enabled'
4646
}
4747
{ $_.forward } {
48-
if (!$Options.keepCopy) {
48+
if (!$Options.KeepCopy) {
4949
Set-CIPPForwarding -userid $userid -username $username -tenantFilter $TenantFilter -Forward $Options.forward.value -Headers $Headers -APIName $APIName
5050
} else {
51-
$KeepCopy = [boolean]$Options.keepCopy
51+
$KeepCopy = [boolean]$Options.KeepCopy
5252
Set-CIPPForwarding -userid $userid -username $username -tenantFilter $TenantFilter -Forward $Options.forward.value -KeepCopy $KeepCopy -Headers $Headers -APIName $APIName
5353
}
5454
}

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

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ function Invoke-ListUserMailboxDetails {
6464
}
6565
)
6666
Write-Host $UserID
67-
$usernames = New-GraphGetRequest -tenantid $TenantFilter -uri 'https://graph.microsoft.com/beta/users?$select=id,userPrincipalName&$top=999'
67+
$usernames = New-GraphGetRequest -tenantid $TenantFilter -uri 'https://graph.microsoft.com/beta/users?$select=id,userPrincipalName,displayName,mailNickname&$top=999'
6868
$Results = New-ExoBulkRequest -TenantId $TenantFilter -CmdletArray $Requests -returnWithCommand $true -Anchor $username
6969
Write-Host "First line of usernames is $($usernames[0] | ConvertTo-Json)"
7070

@@ -144,21 +144,48 @@ function Invoke-ListUserMailboxDetails {
144144
$ParsedPerms = @()
145145
}
146146

147-
# Get forwarding address
148-
$ForwardingAddress = if ($MailboxDetailedRequest.ForwardingAddress) {
149-
try {
150-
(New-GraphGetRequest -TenantId $TenantFilter -Uri "https://graph.microsoft.com/beta/users/$($MailboxDetailedRequest.ForwardingAddress)").UserPrincipalName
151-
} catch {
152-
try {
153-
'{0} ({1})' -f $MailboxDetailedRequest.ForwardingAddress, (($((New-GraphGetRequest -TenantId $TenantFilter -Uri "https://graph.microsoft.com/beta/users?`$filter=displayName eq '$($MailboxDetailedRequest.ForwardingAddress)'") | Select-Object -First 1 -ExpandProperty UserPrincipalName)))
154-
} catch {
155-
$MailboxDetailedRequest.ForwardingAddress
147+
# Get forwarding address - lazy load contacts only if needed
148+
$ForwardingAddress = $null
149+
if ($MailboxDetailedRequest.ForwardingSmtpAddress) {
150+
# External forwarding
151+
$ForwardingAddress = $MailboxDetailedRequest.ForwardingSmtpAddress -replace '^smtp:', ''
152+
} elseif ($MailboxDetailedRequest.ForwardingAddress) {
153+
# Internal forwarding
154+
$rawAddress = $MailboxDetailedRequest.ForwardingAddress
155+
156+
if ($rawAddress -match '@') {
157+
# Already an email address
158+
$ForwardingAddress = $rawAddress
159+
} else {
160+
# First try users array
161+
$matchedUser = $usernames | Where-Object {
162+
$_.id -eq $rawAddress -or
163+
$_.displayName -eq $rawAddress -or
164+
$_.mailNickname -eq $rawAddress
165+
}
166+
167+
if ($matchedUser) {
168+
$ForwardingAddress = $matchedUser.userPrincipalName
169+
} else {
170+
# Query for the specific contact only
171+
try {
172+
# Escape single quotes in the filter value
173+
$escapedAddress = $rawAddress -replace "'", "''"
174+
$filterQuery = "displayName eq '$escapedAddress' or mailNickname eq '$escapedAddress'"
175+
$contactUri = "https://graph.microsoft.com/beta/contacts?`$filter=$filterQuery&`$select=displayName,mail,mailNickname"
176+
177+
$matchedContacts = New-GraphGetRequest -tenantid $TenantFilter -uri $contactUri
178+
179+
if ($matchedContacts -and $matchedContacts.Count -gt 0) {
180+
$ForwardingAddress = $matchedContacts[0].mail
181+
} else {
182+
$ForwardingAddress = $rawAddress
183+
}
184+
} catch {
185+
$ForwardingAddress = $rawAddress
186+
}
156187
}
157188
}
158-
} elseif ($MailboxDetailedRequest.ForwardingSmtpAddress -and $MailboxDetailedRequest.ForwardingAddress) {
159-
"$($MailboxDetailedRequest.ForwardingAddress) $($MailboxDetailedRequest.ForwardingSmtpAddress)"
160-
} else {
161-
$MailboxDetailedRequest.ForwardingSmtpAddress
162189
}
163190

164191
$ProhibitSendQuotaString = $MailboxDetailedRequest.ProhibitSendQuota -split ' '

Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ListBPATemplates.ps1

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ Function Invoke-ListBPATemplates {
3434
foreach ($Template in $Templates) {
3535
$Template.JSON = $Template.JSON -replace '"parameters":', '"Parameters":'
3636
}
37-
$Templates = $Templates.JSON | ConvertFrom-Json
37+
$Templates = $Templates.JSON | ConvertFrom-Json | Sort-Object Name
3838
} else {
3939
$Templates = $Templates | ForEach-Object {
4040
$TemplateJson = $_.JSON -replace '"parameters":', '"Parameters":'
@@ -45,7 +45,7 @@ Function Invoke-ListBPATemplates {
4545
Name = $Template.Name
4646
Style = $Template.Style
4747
}
48-
}
48+
} | Sort-Object Name
4949
}
5050
# Associate values to output bindings by calling 'Push-OutputBinding'.
5151
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{

openapi.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2850,7 +2850,7 @@
28502850
"schema": {
28512851
"type": "string"
28522852
},
2853-
"name": "keepCopy",
2853+
"name": "KeepCopy",
28542854
"in": "body"
28552855
}
28562856
],
@@ -3829,7 +3829,7 @@
38293829
"schema": {
38303830
"type": "string"
38313831
},
3832-
"name": "keepCopy",
3832+
"name": "KeepCopy",
38333833
"in": "body"
38343834
},
38353835
{

0 commit comments

Comments
 (0)