Skip to content

Commit c214da4

Browse files
authored
Merge pull request #432 from KelvinTegelaar/dev
[pull] dev from KelvinTegelaar:dev
2 parents 5d4ed1d + 850af4f commit c214da4

File tree

61 files changed

+489
-67
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+489
-67
lines changed
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
function Push-ExecMdoAlertsListAllTenants {
2+
<#
3+
.FUNCTIONALITY
4+
Entrypoint
5+
#>
6+
param($Item)
7+
8+
$Tenant = Get-Tenants -TenantFilter $Item.customerId
9+
$domainName = $Tenant.defaultDomainName
10+
$Table = Get-CIPPTable -TableName 'cachealertsandincidents'
11+
12+
try {
13+
# Get MDO alerts using the specific endpoint and filter
14+
$Alerts = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/security/alerts_v2?`$filter=serviceSource eq 'microsoftDefenderForOffice365'" -tenantid $domainName
15+
16+
foreach ($Alert in $Alerts) {
17+
$GUID = (New-Guid).Guid
18+
$GraphRequest = @{
19+
MdoAlert = [string]($Alert | ConvertTo-Json -Depth 10)
20+
RowKey = [string]$GUID
21+
PartitionKey = 'MdoAlert'
22+
Tenant = [string]$domainName
23+
}
24+
Add-CIPPAzDataTableEntity @Table -Entity $GraphRequest -Force | Out-Null
25+
}
26+
27+
} catch {
28+
$GUID = (New-Guid).Guid
29+
$AlertText = ConvertTo-Json -InputObject @{
30+
Tenant = $domainName
31+
displayName = "Could not connect to Tenant: $($_.Exception.Message)"
32+
id = ''
33+
severity = 'CIPP'
34+
status = 'Failed'
35+
createdDateTime = (Get-Date).ToString('s')
36+
category = 'Unknown'
37+
description = 'Could not connect'
38+
serviceSource = 'microsoftDefenderForOffice365'
39+
}
40+
$GraphRequest = @{
41+
MdoAlert = [string]$AlertText
42+
RowKey = [string]$GUID
43+
PartitionKey = 'MdoAlert'
44+
Tenant = [string]$domainName
45+
}
46+
Add-CIPPAzDataTableEntity @Table -Entity $GraphRequest -Force | Out-Null
47+
}
48+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
using namespace System.Net
2+
3+
function Invoke-ExecSyncVPP {
4+
<#
5+
.FUNCTIONALITY
6+
Entrypoint
7+
.ROLE
8+
Endpoint.Application.ReadWrite
9+
#>
10+
[CmdletBinding()]
11+
param($Request, $TriggerMetadata)
12+
$APIName = $Request.Params.CIPPEndpoint
13+
$Headers = $Request.Headers
14+
Write-LogMessage -Headers $Headers -API $APIName -message 'Accessed this API' -Sev Debug
15+
16+
$TenantFilter = $Request.Body.tenantFilter ?? $Request.Query.tenantFilter
17+
try {
18+
# Get all VPP tokens and sync them
19+
$VppTokens = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/deviceAppManagement/vppTokens' -tenantid $TenantFilter | Where-Object { $_.state -eq 'valid' }
20+
21+
if ($null -eq $VppTokens -or $VppTokens.Count -eq 0) {
22+
$Result = 'No VPP tokens found'
23+
Write-LogMessage -Headers $Headers -API $APIName -tenant $TenantFilter -message $Result -Sev Info
24+
} else {
25+
$SyncCount = 0
26+
foreach ($Token in $VppTokens) {
27+
$null = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceAppManagement/vppTokens/$($Token.id)/syncLicenses" -tenantid $TenantFilter
28+
$SyncCount++
29+
}
30+
$Result = "Successfully started VPP sync for $SyncCount tokens"
31+
Write-LogMessage -Headers $Headers -API $APIName -tenant $TenantFilter -message $Result -Sev Info
32+
}
33+
$StatusCode = [HttpStatusCode]::OK
34+
} catch {
35+
$ErrorMessage = Get-CippException -Exception $_
36+
$Result = 'Failed to start VPP sync'
37+
Write-LogMessage -Headers $Headers -API $APIName -tenant $TenantFilter -message $Result -Sev Error -LogData $ErrorMessage
38+
$StatusCode = [HttpStatusCode]::Forbidden
39+
}
40+
41+
# Associate values to output bindings by calling 'Push-OutputBinding'.
42+
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
43+
StatusCode = $StatusCode
44+
Body = @{ Results = $Result }
45+
})
46+
47+
}

Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ExecGetRecoveryKey.ps1

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

3-
Function Invoke-ExecGetRecoveryKey {
3+
function Invoke-ExecGetRecoveryKey {
44
<#
55
.FUNCTIONALITY
66
Entrypoint
@@ -19,7 +19,7 @@ Function Invoke-ExecGetRecoveryKey {
1919
$GUID = $Request.Query.GUID ?? $Request.Body.GUID
2020

2121
try {
22-
$Result = Get-CIPPBitLockerKey -device $GUID -tenantFilter $TenantFilter -APIName $APIName -Headers $Headers
22+
$Result = Get-CIPPBitLockerKey -Device $GUID -TenantFilter $TenantFilter -APIName $APIName -Headers $Headers
2323
$StatusCode = [HttpStatusCode]::OK
2424
} catch {
2525
$Result = $_.Exception.Message
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
using namespace System.Net
2+
3+
function Invoke-ExecMDOAlertsList {
4+
<#
5+
.FUNCTIONALITY
6+
Entrypoint
7+
.ROLE
8+
Security.Alert.Read
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.Query.tenantFilter
19+
20+
try {
21+
$GraphRequest = if ($TenantFilter -ne 'AllTenants') {
22+
# Single tenant functionality
23+
New-GraphGetRequest -uri "https://graph.microsoft.com/beta/security/alerts_v2?`$filter=serviceSource eq 'microsoftDefenderForOffice365'" -tenantid $TenantFilter
24+
} else {
25+
# AllTenants functionality
26+
$Table = Get-CIPPTable -TableName cachealertsandincidents
27+
$PartitionKey = 'MdoAlert'
28+
$Filter = "PartitionKey eq '$PartitionKey'"
29+
$Rows = Get-CIPPAzDataTableEntity @Table -filter $Filter | Where-Object -Property Timestamp -GT (Get-Date).AddMinutes(-30)
30+
$QueueReference = '{0}-{1}' -f $TenantFilter, $PartitionKey
31+
$RunningQueue = Invoke-ListCippQueue -Reference $QueueReference | Where-Object { $_.Status -notmatch 'Completed' -and $_.Status -notmatch 'Failed' }
32+
# If a queue is running, we will not start a new one
33+
if ($RunningQueue) {
34+
$Metadata = [PSCustomObject]@{
35+
QueueMessage = 'Still loading data for all tenants. Please check back in a few more minutes'
36+
QueueId = $RunningQueue.RowKey
37+
}
38+
} elseif (!$Rows -and !$RunningQueue) {
39+
# If no rows are found and no queue is running, we will start a new one
40+
$TenantList = Get-Tenants -IncludeErrors
41+
$Queue = New-CippQueueEntry -Name 'MDO Alerts - All Tenants' -Link '/security/reports/mdo-alerts?customerId=AllTenants' -Reference $QueueReference -TotalTasks ($TenantList | Measure-Object).Count
42+
$Metadata = [PSCustomObject]@{
43+
QueueMessage = 'Loading data for all tenants. Please check back in a few minutes'
44+
QueueId = $Queue.RowKey
45+
}
46+
$InputObject = [PSCustomObject]@{
47+
OrchestratorName = 'MdoAlertsOrchestrator'
48+
QueueFunction = @{
49+
FunctionName = 'GetTenants'
50+
QueueId = $Queue.RowKey
51+
TenantParams = @{
52+
IncludeErrors = $true
53+
}
54+
DurableName = 'ExecMdoAlertsListAllTenants'
55+
}
56+
SkipLog = $true
57+
}
58+
Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Depth 5 -Compress) | Out-Null
59+
} else {
60+
$Metadata = [PSCustomObject]@{
61+
QueueId = $RunningQueue.RowKey ?? $null
62+
}
63+
$Alerts = $Rows
64+
foreach ($alert in $Alerts) {
65+
ConvertFrom-Json -InputObject $alert.MdoAlert -Depth 10
66+
}
67+
}
68+
}
69+
} catch {
70+
$Body = Get-NormalizedError -Message $_.Exception.Message
71+
$StatusCode = [HttpStatusCode]::Forbidden
72+
}
73+
if (!$Body) {
74+
$StatusCode = [HttpStatusCode]::OK
75+
$Body = [PSCustomObject]@{
76+
Results = @($GraphRequest)
77+
Metadata = $Metadata
78+
}
79+
}
80+
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
81+
StatusCode = $StatusCode
82+
Body = $Body
83+
})
84+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
using namespace System.Net
2+
3+
function Invoke-ExecSetMdoAlert {
4+
<#
5+
.FUNCTIONALITY
6+
Entrypoint
7+
.ROLE
8+
Security.Incident.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.Query.tenantFilter ?? $Request.Body.tenantFilter
19+
$AlertId = $Request.Query.GUID ?? $Request.Body.GUID
20+
$Status = $Request.Query.Status ?? $Request.Body.Status
21+
$Assigned = $Request.Query.Assigned ?? $Request.Body.Assigned ?? ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($Headers.'x-ms-client-principal')) | ConvertFrom-Json).userDetails
22+
$Classification = $Request.Query.Classification ?? $Request.Body.Classification
23+
$Determination = $Request.Query.Determination ?? $Request.Body.Determination
24+
$Result = ''
25+
$AssignBody = @{}
26+
27+
try {
28+
# Set received status
29+
if ($null -ne $Status) {
30+
$AssignBody.status = $Status
31+
$Result += 'Set status for incident ' + $AlertId + ' to ' + $Status
32+
}
33+
34+
# Set received classification and determination
35+
if ($null -ne $Classification) {
36+
if ($null -eq $Determination) {
37+
# Maybe some poindexter tries to send a classification without a determination
38+
throw
39+
}
40+
41+
$AssignBody.classification = $Classification
42+
$AssignBody.determination = $Determination
43+
$Result += 'Set classification & determination for incident ' + $AlertId + ' to ' + $Classification + ' ' + $Determination
44+
}
45+
46+
# Set received assignee
47+
if ($null -ne $Assigned) {
48+
$AssignBody.assignedTo = $Assigned
49+
if ($null -eq $Status) {
50+
$Result += 'Set assigned for incident ' + $AlertId + ' to ' + $Assigned
51+
}
52+
}
53+
54+
# Convert hashtable to JSON
55+
$AssignBodyJson = $AssignBody | ConvertTo-Json -Compress
56+
57+
$null = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/security/alerts_v2/$AlertId" -type PATCH -tenantid $TenantFilter -body $AssignBodyJson -asApp $true
58+
Write-LogMessage -headers $Headers -API $APIName -tenant $TenantFilter -message $Result -Sev 'Info'
59+
60+
$StatusCode = [HttpStatusCode]::OK
61+
} catch {
62+
$ErrorMessage = Get-CippException -Exception $_
63+
$Result = "Failed to update incident $AlertId : $($ErrorMessage.NormalizedError)"
64+
Write-LogMessage -headers $Headers -API $APIName -tenant $TenantFilter -message $Result -Sev 'Error' -LogData $ErrorMessage
65+
$StatusCode = [HttpStatusCode]::InternalServerError
66+
}
67+
68+
# Associate values to output bindings by calling 'Push-OutputBinding'.
69+
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
70+
StatusCode = $StatusCode
71+
Body = @{'Results' = $Result }
72+
})
73+
74+
}
Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,34 @@
11

2-
function Get-CIPPBitlockerKey {
2+
function Get-CIPPBitLockerKey {
33
[CmdletBinding()]
44
param (
5-
$device,
5+
$Device,
66
$TenantFilter,
77
$APIName = 'Get BitLocker key',
88
$Headers
99
)
1010

1111
try {
12-
$GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/informationProtection/bitlocker/recoveryKeys?`$filter=deviceId eq '$($device)'" -tenantid $TenantFilter | ForEach-Object {
13-
(New-GraphGetRequest -uri "https://graph.microsoft.com/beta/informationProtection/bitlocker/recoveryKeys/$($_.id)?`$select=key" -tenantid $TenantFilter).key
12+
$GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/v1.0/informationProtection/bitlocker/recoveryKeys?`$filter=deviceId eq '$($Device)'" -tenantid $TenantFilter |
13+
ForEach-Object {
14+
$BitLockerKeyObject = (New-GraphGetRequest -uri "https://graph.microsoft.com/v1.0/informationProtection/bitlocker/recoveryKeys/$($_.id)?`$select=key" -tenantid $TenantFilter)
15+
[PSCustomObject]@{
16+
resultText = "Id: $($_.id) Key: $($BitLockerKeyObject.key)"
17+
copyField = $BitLockerKeyObject.key
18+
state = 'success'
19+
}
20+
}
21+
22+
if ($GraphRequest.Count -eq 0) {
23+
Write-LogMessage -headers $Headers -API $APIName -message "No BitLocker recovery keys found for $($Device)" -Sev Info -tenant $TenantFilter
24+
return "No BitLocker recovery keys found for $($Device)"
1425
}
26+
Write-LogMessage -headers $Headers -API $APIName -message "Retrieved BitLocker recovery keys for $($Device)" -Sev Info -tenant $TenantFilter
1527
return $GraphRequest
1628
} catch {
1729
$ErrorMessage = Get-CippException -Exception $_
18-
$Result = "Could not retrieve BitLocker recovery key for $($device). Error: $($ErrorMessage.NormalizedError)"
19-
Write-LogMessage -headers $Headers -API $APIName -message $Result -Sev 'Error' -tenant $TenantFilter -LogData $ErrorMessage
30+
$Result = "Could not retrieve BitLocker recovery key for $($Device). Error: $($ErrorMessage.NormalizedError)"
31+
Write-LogMessage -headers $Headers -API $APIName -message $Result -Sev Error -tenant $TenantFilter -LogData $ErrorMessage
2032
throw $Result
2133
}
2234
}

Modules/CIPPCore/Public/Set-CIPPOutOfoffice.ps1

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,9 @@ function Set-CIPPOutOfOffice {
1818
try {
1919

2020
$CmdParams = @{
21-
Identity = $UserID
22-
AutoReplyState = $State
21+
Identity = $UserID
22+
AutoReplyState = $State
23+
ExternalAudience = 'None'
2324
}
2425

2526
if ($PSBoundParameters.ContainsKey('InternalMessage')) {
@@ -28,6 +29,7 @@ function Set-CIPPOutOfOffice {
2829

2930
if ($PSBoundParameters.ContainsKey('ExternalMessage')) {
3031
$CmdParams.ExternalMessage = $ExternalMessage
32+
$CmdParams.ExternalAudience = 'All'
3133
}
3234

3335
if ($State -eq 'Scheduled') {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ function Invoke-CIPPStandardAddDKIM {
3232

3333
param($Tenant, $Settings)
3434
#$Rerun -Type Standard -Tenant $Tenant -API 'AddDKIM' -Settings $Settings
35-
$TestResult = Test-CIPPStandardLicense -StandardName 'AddDKIM' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access
35+
$TestResult = Test-CIPPStandardLicense -StandardName 'AddDKIM' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access
3636

3737
if ($TestResult -eq $false) {
3838
Write-Host "We're exiting as the correct license is not present for this standard."

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ function Invoke-CIPPStandardAntiPhishPolicy {
5050
#>
5151

5252
param($Tenant, $Settings)
53-
$TestResult = Test-CIPPStandardLicense -StandardName 'AntiPhishPolicy' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access
53+
$TestResult = Test-CIPPStandardLicense -StandardName 'AntiPhishPolicy' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access
5454

5555
if ($TestResult -eq $false) {
5656
Write-Host "We're exiting as the correct license is not present for this standard."

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ function Invoke-CIPPStandardAntiSpamSafeList {
2929
#>
3030

3131
param($Tenant, $Settings)
32-
$TestResult = Test-CIPPStandardLicense -StandardName 'AntiSpamSafeList' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access
32+
$TestResult = Test-CIPPStandardLicense -StandardName 'AntiSpamSafeList' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access
3333

3434
if ($TestResult -eq $false) {
3535
Write-Host "We're exiting as the correct license is not present for this standard."
@@ -41,15 +41,15 @@ function Invoke-CIPPStandardAntiSpamSafeList {
4141
$State = [System.Convert]::ToBoolean($Settings.EnableSafeList)
4242
} catch {
4343
Write-LogMessage -API 'Standards' -tenant $Tenant -message 'AntiSpamSafeList: Failed to convert the EnableSafeList parameter to a boolean' -sev Error
44-
Return
44+
return
4545
}
4646

4747
try {
4848
$CurrentState = (New-ExoRequest -tenantid $Tenant -cmdlet 'Get-HostedConnectionFilterPolicy' -cmdParams @{Identity = 'Default' }).EnableSafeList
4949
} catch {
5050
$ErrorMessage = Get-CippException -Exception $_
5151
Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to get the Anti-Spam Connection Filter Safe List. Error: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage
52-
Return
52+
return
5353
}
5454
$WantedState = $State -eq $true ? $true : $false
5555
$StateIsCorrect = if ($CurrentState -eq $WantedState) { $true } else { $false }

0 commit comments

Comments
 (0)