From b454dc391ec542efa9e9391abad5126fac44609a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Wed, 24 Jan 2024 22:13:15 +0100 Subject: [PATCH 01/50] Progress --- .../Public/Entrypoints/Invoke-EditUser.ps1 | 29 +++++++++++++++---- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-EditUser.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-EditUser.ps1 index 132ccd3af8af..9e5e7600a8d0 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-EditUser.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-EditUser.ps1 @@ -55,8 +55,7 @@ Function Invoke-EditUser { $results.add("Success. The password has been set to $($userobj.password)") Write-LogMessage -API $APINAME -tenant ($UserObj.tenantid) -user $request.headers.'x-ms-client-principal' -message "Reset $($userobj.displayname)'s Password" -Sev 'Info' } - } - catch { + } catch { Write-LogMessage -API $APINAME -tenant ($UserObj.tenantid) -user $request.headers.'x-ms-client-principal' -message "User edit API failed. $($_.Exception.Message)" -Sev 'Error' $results.add( "Failed to edit user. $($_.Exception.Message)") } @@ -81,8 +80,7 @@ Function Invoke-EditUser { $results.add( 'Success. User license has been edited.' ) } - } - catch { + } catch { Write-LogMessage -API $APINAME -tenant ($UserObj.tenantid) -user $request.headers.'x-ms-client-principal' -message "License assign API failed. $($_.Exception.Message)" -Sev 'Error' $results.add( "We've failed to assign the license. $($_.Exception.Message)") } @@ -98,8 +96,7 @@ Function Invoke-EditUser { $results.add( 'Success. added aliasses to user.') } - } - catch { + } catch { Write-LogMessage -API $APINAME -tenant ($UserObj.tenantid) -user $request.headers.'x-ms-client-principal' -message "Alias API failed. $($_.Exception.Message)" -Sev 'Error' $results.add( "Successfully edited user. The password is $password. We've failed to create the Aliases: $($_.Exception.Message)") } @@ -108,6 +105,26 @@ Function Invoke-EditUser { $CopyFrom = Set-CIPPCopyGroupMembers -ExecutingUser $request.headers.'x-ms-client-principal' -tenantid $Userobj.tenantid -CopyFromId $Request.body.CopyFrom -UserID $UserprincipalName -TenantFilter $Userobj.tenantid $results.AddRange($CopyFrom) } + + if ($Request.body.AddToGroups -ne '') { + $Request.body.AddToGroups | ForEach-Object { + + try { + Write-Host 'Adding to groups IM IN HERE' + Write-Host $_.groupType + $UserBody = [PSCustomObject]@{ + '@odata.id' = "https://graph.microsoft.com/beta/directoryObjects/$($UserObj.Userid)" + } + $UserBodyJSON = ConvertTo-Json -Compress -Depth 10 -InputObject $UserBody + New-GraphPostRequest -uri "https://graph.microsoft.com/beta/groups/$($_.value)/members/`$ref" -tenantid $Userobj.tenantid -type POST -body $UserBodyJSON -Verbose + } catch { + Write-Host $_.Exception.Message + } + } + + + } + $body = @{'Results' = @($results) } # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ From c12073841975ba9323406f8f9ba81b3ffa484991 Mon Sep 17 00:00:00 2001 From: Jr7468 Date: Mon, 29 Jan 2024 13:31:00 +0000 Subject: [PATCH 02/50] Changing API Name --- Modules/CIPPCore/Public/Entrypoints/Invoke-AddUser.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-AddUser.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddUser.ps1 index 1e6888622537..119bbcd532da 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-AddUser.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddUser.ps1 @@ -8,7 +8,7 @@ Function Invoke-AddUser { [CmdletBinding()] param($Request, $TriggerMetadata) - $APIName = $TriggerMetadata.FunctionName + $APIName = "AddUser" Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' $Results = [System.Collections.ArrayList]@() From 74a73d48a8a801b63e79e5a8b210d7031fbc9d1b Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Mon, 29 Jan 2024 17:35:49 +0100 Subject: [PATCH 03/50] try catch improvements --- .../Push-CIPPAlertAppSecretExpiry.ps1 | 2 +- .../Push-CIPPAlertMFAAlertUsers.ps1 | 20 ++++++------------- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertAppSecretExpiry.ps1 b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertAppSecretExpiry.ps1 index 65501b405c16..581c56ebd962 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertAppSecretExpiry.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertAppSecretExpiry.ps1 @@ -33,7 +33,7 @@ function Push-CIPPAlertAppSecretExpiry { Add-CIPPAzDataTableEntity @LastRunTable -Entity $LastRun -Force } } catch { - throw $_ + } } diff --git a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertMFAAlertUsers.ps1 b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertMFAAlertUsers.ps1 index 520c84be33c5..2537b9a30a38 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertMFAAlertUsers.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertMFAAlertUsers.ps1 @@ -6,22 +6,14 @@ function Push-CIPPAlertMFAAlertUsers { $TriggerMetadata ) try { - $LastRunTable = Get-CIPPTable -Table AlertLastRun - $Filter = "RowKey eq 'MFAAllUsers' and PartitionKey eq '{0}'" -f $QueueItem.tenantid - $LastRun = Get-CIPPAzDataTableEntity @LastRunTable -Filter $Filter - $Yesterday = (Get-Date).AddDays(-1) - if (-not $LastRun.Timestamp.DateTime -or ($LastRun.Timestamp.DateTime -le $Yesterday)) { - $users = New-GraphGETRequest -uri 'https://graph.microsoft.com/beta/reports/authenticationMethods/userRegistrationDetails?$filter=isMfaRegistered eq false' -tenantid $($QueueItem.tenant) - if ($users) { - Write-AlertMessage -tenant $QueueItem.tenant -message "The following users do not have MFA registered: $($users.UserPrincipalName -join ', ')" - } + + $users = New-GraphGETRequest -uri 'https://graph.microsoft.com/beta/reports/authenticationMethods/userRegistrationDetails?$filter=isMfaRegistered eq false' -tenantid $($QueueItem.tenant) + if ($users) { + Write-AlertMessage -tenant $QueueItem.tenant -message "The following users do not have MFA registered: $($users.UserPrincipalName -join ', ')" } + } catch { Write-LogMessage -message "Failed to check MFA status for all users: $($_.exception.message)" -API 'MFA Alerts - Informational' -tenant $QueueItem.tenant -sev Info } - $LastRun = @{ - RowKey = 'MFAAllUsers' - PartitionKey = $QueueItem.tenantid - } - Add-CIPPAzDataTableEntity @LastRunTable -Entity $LastRun -Force + } From baa4e9e22cf0b8e991e499b679bd38ce5cde8a33 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Mon, 29 Jan 2024 17:50:17 +0100 Subject: [PATCH 04/50] cleanup sam manifest --- Modules/CIPPCore/Public/SAMManifest.json | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/Modules/CIPPCore/Public/SAMManifest.json b/Modules/CIPPCore/Public/SAMManifest.json index fc887aed506b..f4ee6e523f9a 100644 --- a/Modules/CIPPCore/Public/SAMManifest.json +++ b/Modules/CIPPCore/Public/SAMManifest.json @@ -154,14 +154,7 @@ { "id": "b27a61ec-b99c-4d6a-b126-c4375d08ae30", "type": "Scope" }, { "id": "84bccea3-f856-4a8a-967b-dbe0a3d53a64", "type": "Scope" }, { "id": "280b3b69-0437-44b1-bc20-3b2fca1ee3e9", "type": "Scope" }, - { - "id": "885f682f-a990-4bad-a642-36736a74b0c7", - "type": "Scope" - }, - { - "id": "c2d95988-7604-4ba1-aaed-38a5f82a51c7", - "type": "Scope" - } + { "id": "885f682f-a990-4bad-a642-36736a74b0c7", "type": "Scope" } ] }, { From 783112ee5558f1f134249f4b78775e4d3a040277 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Mon, 29 Jan 2024 17:56:12 +0100 Subject: [PATCH 05/50] update error messages --- Modules/CIPPCore/Public/GraphHelper/Get-NormalizedError.ps1 | 1 + 1 file changed, 1 insertion(+) diff --git a/Modules/CIPPCore/Public/GraphHelper/Get-NormalizedError.ps1 b/Modules/CIPPCore/Public/GraphHelper/Get-NormalizedError.ps1 index 88fb8492350e..42bdbfcd5356 100644 --- a/Modules/CIPPCore/Public/GraphHelper/Get-NormalizedError.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/Get-NormalizedError.ps1 @@ -56,6 +56,7 @@ function Get-NormalizedError { '*The property value exceeds the maximum allowed size (64KB)*' { 'One of the values exceeds the maximum allowed size (64KB).' } '*Unable to initialize the authorization context*' { 'Your GDAP configuration does not allow us to write to this tenant, please check your group mappings and tenant onboarding.' } '*Providers.Common.V1.CoreException*' { '403 (Access Denied) - We cannot connect to this tenant.' } + '*Authentication failed. MFA required*' { 'Authentication failed. MFA required' } Default { $message } } From a778a0ef060c3fb33a705fe11b1456d5455c61a8 Mon Sep 17 00:00:00 2001 From: CHRIS-BRANNON <99292551+CHRIS-BRANNON@users.noreply.github.com> Date: Mon, 29 Jan 2024 14:26:45 -0500 Subject: [PATCH 06/50] Fix Outbound Spam Alert Passing NULL var into EXO Request and failing to remediate. --- .../Standards/Invoke-CIPPStandardOutBoundSpamAlert.ps1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOutBoundSpamAlert.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOutBoundSpamAlert.ps1 index 307ebdfada1c..1816a15ca998 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOutBoundSpamAlert.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOutBoundSpamAlert.ps1 @@ -7,10 +7,10 @@ function Invoke-CIPPStandardOutBoundSpamAlert { If ($Settings.remediate) { $Contacts = $settings.OutboundSpamContact try { - New-ExoRequest -tenantid $tenant -cmdlet 'Set-HostedOutboundSpamFilterPolicy' -cmdparams @{ Identity = 'Default'; NotifyOutboundSpam = $true; NotifyOutboundSpamRecipients = $Contacts.OutboundSpamContact } -useSystemMailbox $true - Write-LogMessage -API 'Standards' -tenant $tenant -message "Set outbound spam filter alert to $($Contacts.OutboundSpamContact)" -sev Info + New-ExoRequest -tenantid $tenant -cmdlet 'Set-HostedOutboundSpamFilterPolicy' -cmdparams @{ Identity = 'Default'; NotifyOutboundSpam = $true; NotifyOutboundSpamRecipients = $Contacts } -useSystemMailbox $true + Write-LogMessage -API 'Standards' -tenant $tenant -message "Set outbound spam filter alert to $($Contacts)" -sev Info } catch { - Write-LogMessage -API 'Standards' -tenant $tenant -message "Could not set outbound spam contact to $($Contacts.OutboundSpamContact). $($_.exception.message)" -sev Error + Write-LogMessage -API 'Standards' -tenant $tenant -message "Could not set outbound spam contact to $($Contacts). $($_.exception.message)" -sev Error } } if ($Settings.alert) { From 050c2bcecd3d66aa26103327043dbde9dd0b7844 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Mon, 29 Jan 2024 22:39:23 +0100 Subject: [PATCH 07/50] Redesign AddDKIM --- .../Standards/Invoke-CIPPStandardAddDKIM.ps1 | 49 ++++++++++++++----- 1 file changed, 38 insertions(+), 11 deletions(-) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAddDKIM.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAddDKIM.ps1 index ecf181d8497a..9b6eb9012710 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAddDKIM.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAddDKIM.ps1 @@ -4,28 +4,55 @@ function Invoke-CIPPStandardAddDKIM { Internal #> param($Tenant, $Settings) - $DKIM = (New-ExoRequest -tenantid $tenant -cmdlet 'Get-DkimSigningConfig') | Where-Object -Property Enabled -EQ $false + + $AllDomains = (New-GraphGetRequest -uri 'https://graph.microsoft.com/v1.0/domains' -tenantid $Tenant | Where-Object { $_.supportedServices -contains 'Email' }).id + $DKIM = (New-ExoRequest -tenantid $tenant -cmdlet 'Get-DkimSigningConfig') | Select-Object Domain, Enabled, Status + + # List of domains for each way to enable DKIM + $NewDomains = $AllDomains | Where-Object { $DKIM.Domain -notcontains $_ } + $SetDomains = $DKIM | Where-Object { $AllDomains -contains $_.Domain -and $_.Enabled -eq $false } + If ($Settings.remediate) { - try { - $DKIM | ForEach-Object { - (New-ExoRequest -tenantid $tenant -cmdlet 'New-DkimSigningConfig' -cmdparams @{ KeySize = 2048; DomainName = $_.Identity; Enabled = $true } -useSystemMailbox $true) + $ErrorCounter = 0 + # New-domains + foreach ($Domain in $NewDomains) { + try { + (New-ExoRequest -tenantid $tenant -cmdlet 'New-DkimSigningConfig' -cmdparams @{ KeySize = 2048; DomainName = $Domain; Enabled = $true } -useSystemMailbox $true) + Write-LogMessage -API 'Standards' -tenant $tenant -message "Enabled DKIM for $Domain" -sev Info + } catch { + Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to enable DKIM. Error: $($_.Exception.Message)" -sev Error + $ErrorCounter++ + } + } + + # Set-domains + foreach ($Domain in $SetDomains) { + try { + (New-ExoRequest -tenantid $tenant -cmdlet 'Set-DkimSigningConfig' -cmdparams @{ Identity = $Domain.Domain; Enabled = $true } -useSystemMailbox $true) + Write-LogMessage -API 'Standards' -tenant $tenant -message "Enabled DKIM for $($Domain.Domain)" -sev Info + } catch { + Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to enable DKIM. Error: $($_.Exception.Message)" -sev Error + $ErrorCounter++ } - Write-LogMessage -API 'Standards' -tenant $tenant -message 'Enabled DKIM Setup' -sev Info - - } catch { - Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to enable DKIM. Error: $($_.exception.message)" -sev Error + } + if ($ErrorCounter -eq 0) { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'Enabled DKIM for all domains in tenant' -sev Info + } else { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'Failed to enable DKIM for all domains in tenant' -sev Error } } if ($Settings.alert) { - if ($DKIM) { + if ($null -eq $NewDomains -and $null -eq $SetDomains) { Write-LogMessage -API 'Standards' -tenant $tenant -message 'DKIM is enabled for all available domains' -sev Info } else { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'DKIM is not enabled for all available domains' -sev Alert + $NoDKIM = ($NewDomains + $SetDomains.Domain) -join ';' + Write-LogMessage -API 'Standards' -tenant $tenant -message "DKIM is not enabled for: $NoDKIM" -sev Alert } } if ($Settings.report) { - Add-CIPPBPAField -FieldName 'DKIM' -FieldValue [bool]$DKIM -StoreAs bool -Tenant $tenant + if ($null -eq $NewDomains -and $null -eq $SetDomains) { $DKIMState = $true } else { $DKIMState = $false } + Add-CIPPBPAField -FieldName 'DKIM' -FieldValue [bool]$DKIMState -StoreAs bool -Tenant $tenant } } From 4a2e412de1e49bff3d0abc5fdc8f20091f89ab2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Mon, 29 Jan 2024 22:40:03 +0100 Subject: [PATCH 08/50] Rearrange try catch and improve alert --- .../Invoke-CIPPStandardRotateDKIM.ps1 | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardRotateDKIM.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardRotateDKIM.ps1 index 2ce2937ab173..5246d658f5de 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardRotateDKIM.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardRotateDKIM.ps1 @@ -4,24 +4,29 @@ function Invoke-CIPPStandardRotateDKIM { Internal #> param($Tenant, $Settings) - $DKIM = (New-ExoRequest -tenantid $tenant -cmdlet 'Get-DkimSigningConfig') | Where-Object { $_.Selector1KeySize -EQ 1024 -and $_.Enabled -eq $true } + $DKIM = (New-ExoRequest -tenantid $tenant -cmdlet 'Get-DkimSigningConfig') | Where-Object { $_.Selector1KeySize -Eq 1024 -and $_.Enabled -eq $true } + If ($Settings.remediate) { - try { - $DKIM | ForEach-Object { - (New-ExoRequest -tenantid $tenant -cmdlet 'Rotate-DkimSigningConfig' -cmdparams @{ KeySize = 2048; Identity = $_.Identity } -useSystemMailbox $true) + + $DKIM | ForEach-Object { + try { + (New-ExoRequest -tenantid $tenant -cmdlet 'Rotate-DkimSigningConfig' -cmdparams @{ KeySize = 2048; Identity = $_.Identity } -useSystemMailbox $true) + Write-LogMessage -API 'Standards' -tenant $tenant -message "Rotated DKIM for $($_.Identity)" -sev Info + } catch { + Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to rotate DKIM Error: $($_.exception.message)" -sev Error } - Write-LogMessage -API 'Standards' -tenant $tenant -message 'Rotated DKIM' -sev Info - - } catch { - Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to rotate DKIM Error: $($_.exception.message)" -sev Error } + Write-LogMessage -API 'Standards' -tenant $tenant -message 'Rotated DKIM' -sev Info } - if ($Settings.alert) { - $DKIM | ForEach-Object { - Write-LogMessage -API 'Standards' -tenant $tenant -message "DKIM is not rotated for $($_.Identity)" -sev Alert + if ($Settings.alert) { + if ($null -eq $DKIM) { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'DKIM is rotated for all domains' -sev Info + } else { + Write-LogMessage -API 'Standards' -tenant $tenant -message "DKIM is not rotated for $($DKIM.Identity -join ';')" -sev Alert } } + if ($Settings.report) { Add-CIPPBPAField -FieldName 'DKIM' -FieldValue $DKIM -StoreAs json -Tenant $tenant } From 7a27eb1d8ed404b2a50976e2ea9fdea922bd80a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Mon, 29 Jan 2024 23:34:38 +0100 Subject: [PATCH 09/50] Fix old typo --- DomainAnalyser_All/run.ps1 | 53 +++++++++++++------------------------- 1 file changed, 18 insertions(+), 35 deletions(-) diff --git a/DomainAnalyser_All/run.ps1 b/DomainAnalyser_All/run.ps1 index 0317848a5a23..6f11a3e4856b 100644 --- a/DomainAnalyser_All/run.ps1 +++ b/DomainAnalyser_All/run.ps1 @@ -10,8 +10,7 @@ try { $ValidResolvers = @('Google', 'CloudFlare', 'Quad9') if ($ValidResolvers -contains $Config.Resolver) { $Resolver = $Config.Resolver - } - else { + } else { $Resolver = 'Google' $Config = @{ PartitionKey = 'Domains' @@ -20,8 +19,7 @@ try { } Add-CIPPAzDataTableEntity @ConfigTable -Entity $Config -Force } -} -catch { +} catch { $Resolver = 'Google' } Set-DnsResolver -Resolver $Resolver @@ -30,8 +28,7 @@ $Domain = $DomainObject.rowKey try { $Tenant = $DomainObject.TenantDetails | ConvertFrom-Json -ErrorAction Stop -} -catch { +} catch { $Tenant = @{Tenant = 'None' } } @@ -90,15 +87,13 @@ $MXFailCount = $MXRecord.ValidationFails | Measure-Object | Select-Object -Expan if ($MXFailCount -eq 0) { $Result.MXPassTest = $true $ScoreDomain += $Scores.MXRecommended -} -else { +} else { $ScoreExplanation.Add('MX record did not pass validation') | Out-Null } if ([string]::IsNullOrEmpty($MXRecord.MailProvider)) { $Result.MailProvider = 'Unknown' -} -else { +} else { $Result.MailProvider = $MXRecord.MailProvider.Name } @@ -109,17 +104,14 @@ try { $Result.ActualSPFRecord = $SPFRecord.Record if ($SPFRecord.RecordCount -eq 1) { $ScoreDomain += $Scores.SPFPresent - } - else { + } else { $ScoreExplanation.Add('Multiple SPF records detected') | Out-Null } - } - else { + } else { $Result.ActualSPFRecord = 'No SPF Record' $ScoreExplanation.Add('No SPF Record Found') | Out-Null } -} -catch { +} catch { $Message = 'SPF Exception: {0} line {1} - {2}' -f $_.InvocationInfo.ScriptName, $_.InvocationInfo.ScriptLineNumber, $_.Exception.Message Write-LogMessage -API 'DomainAnalyser' -tenant $tenant.tenant -message $Message -sev Error throw $Message @@ -135,8 +127,7 @@ $SPFFailCount = $SPFRecord.ValidationFails | Measure-Object | Select-Object -Exp if ($SPFFailCount -eq 0) { $ScoreDomain += $Scores.SPFCorrectAll $Result.SPFPassAll = $true -} -else { +} else { $ScoreExplanation.Add('SPF record did not pass validation') | Out-Null } @@ -147,12 +138,11 @@ try { If ([string]::IsNullOrEmpty($DMARCPolicy.Record)) { $Result.DMARCPresent = $false $ScoreExplanation.Add('No DMARC Records Found') | Out-Null - } - else { + } else { $Result.DMARCPresent = $true $ScoreDomain += $Scores.DMARCPresent - $Result.DMARCFullPolicy = $DMARCResults.Record + $Result.DMARCFullPolicy = $DMARCPolicy.Record if ($DMARCPolicy.Policy -eq 'reject' -and $DMARCPolicy.SubdomainPolicy -eq 'reject') { $Result.DMARCActionPolicy = 'Reject' $ScoreDomain += $Scores.DMARCSetReject @@ -171,8 +161,7 @@ try { if ($ReportEmailCount -gt 0) { $Result.DMARCReportingActive = $true $ScoreDomain += $Scores.DMARCReportingActive - } - else { + } else { $Result.DMARCReportingActive = $False $ScoreExplanation.Add('DMARC Reporting not Configured') | Out-Null } @@ -180,14 +169,12 @@ try { if ($DMARCPolicy.Percent -eq 100) { $Result.DMARCPercentagePass = $true $ScoreDomain += $Scores.DMARCPercentageGood - } - else { + } else { $Result.DMARCPercentagePass = $false $ScoreExplanation.Add('DMARC Not Checking All Messages') | Out-Null } } -} -catch { +} catch { $Message = 'DMARC Exception: {0} line {1} - {2}' -f $_.InvocationInfo.ScriptName, $_.InvocationInfo.ScriptLineNumber, $_.Exception.Message Write-LogMessage -API 'DomainAnalyser' -tenant $tenant.tenant -message $Message -sev Error throw $Message @@ -201,13 +188,11 @@ try { if (($DNSSECFailCount + $DNSSECWarnCount) -eq 0) { $Result.DNSSECPresent = $true $ScoreDomain += $Scores.DNSSECPresent - } - else { + } else { $Result.DNSSECPresent = $false $ScoreExplanation.Add('DNSSEC Not Configured or Enabled') | Out-Null } -} -catch { +} catch { $Message = 'DNSSEC Exception: {0} line {1} - {2}' -f $_.InvocationInfo.ScriptName, $_.InvocationInfo.ScriptLineNumber, $_.Exception.Message Write-LogMessage -API 'DomainAnalyser' -tenant $tenant.tenant -message $Message -sev Error throw $Message @@ -230,13 +215,11 @@ try { if ($DkimRecordCount -gt 0 -and $DkimFailCount -eq 0) { $Result.DKIMEnabled = $true $ScoreDomain += $Scores.DKIMActiveAndWorking - } - else { + } else { $Result.DKIMEnabled = $false $ScoreExplanation.Add('DKIM Not Configured') | Out-Null } -} -catch { +} catch { $Message = 'DKIM Exception: {0} line {1} - {2}' -f $_.InvocationInfo.ScriptName, $_.InvocationInfo.ScriptLineNumber, $_.Exception.Message Write-LogMessage -API 'DomainAnalyser' -tenant $tenant.tenant -message $Message -sev Error throw $Message From 4cc516a845571b19628a4b0b5d03cfe2af252e5d Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Tue, 30 Jan 2024 09:45:34 +0100 Subject: [PATCH 10/50] add oauth2 token to ignore list --- Modules/CIPPCore/Public/Invoke-CIPPWebhookProcessing.ps1 | 1 + 1 file changed, 1 insertion(+) diff --git a/Modules/CIPPCore/Public/Invoke-CIPPWebhookProcessing.ps1 b/Modules/CIPPCore/Public/Invoke-CIPPWebhookProcessing.ps1 index 1f698dc9f475..fee8af4c24be 100644 --- a/Modules/CIPPCore/Public/Invoke-CIPPWebhookProcessing.ps1 +++ b/Modules/CIPPCore/Public/Invoke-CIPPWebhookProcessing.ps1 @@ -52,6 +52,7 @@ function Invoke-CippWebhookProcessing { $ExtendedPropertiesIgnoreList = @( 'OAuth2:Authorize' + 'OAuth2:Token' 'SAS:EndAuth' 'SAS:ProcessAuth' ) From 3c269274a77457900eacbcd13d248a8b0baee29f Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Tue, 30 Jan 2024 14:33:19 +0100 Subject: [PATCH 11/50] fixes nesting issue --- .../Public/Entrypoints/Invoke-AddCATemplate.ps1 | 14 ++++++-------- Modules/CIPPCore/Public/New-CIPPCAPolicy.ps1 | 5 +++-- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-AddCATemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddCATemplate.ps1 index 9c5d7ee1261e..7fc95e0d7af1 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-AddCATemplate.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddCATemplate.ps1 @@ -15,9 +15,8 @@ Function Invoke-AddCATemplate { try { $GUID = (New-Guid).GUID $JSON = if ($request.body.rawjson) { - ([pscustomobject]$request.body.rawjson) | ConvertFrom-Json - } - else { + ConvertFrom-Json -InputObject ([pscustomobject]$request.body.rawjson) + } else { ([pscustomobject]$Request.body) | ForEach-Object { $NonEmptyProperties = $_.psobject.Properties | Where-Object { $null -ne $_.Value } | Select-Object -ExpandProperty Name $_ | Select-Object -Property $NonEmptyProperties @@ -44,7 +43,7 @@ Function Invoke-AddCATemplate { $JSON | Add-Member -NotePropertyName 'LocationInfo' -NotePropertyValue @($IncludeJSON, $ExcludeJSON) - $JSON = ($JSON | ConvertTo-Json -Depth 100) + $JSON = (ConvertTo-Json -Depth 100 -InputObject $JSON ) $Table = Get-CippTable -tablename 'templates' $Table.Force = $true Add-CIPPAzDataTableEntity @Table -Entity @{ @@ -53,12 +52,11 @@ Function Invoke-AddCATemplate { PartitionKey = 'CATemplate' GUID = "$GUID" } - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Created Transport Rule Template $($Request.body.name) with GUID $GUID" -Sev 'Debug' + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Created CA Template $($Request.body.name) with GUID $GUID" -Sev 'Debug' $body = [pscustomobject]@{'Results' = 'Successfully added template' } - } - catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to create Transport Rule Template: $($_.Exception.Message)" -Sev 'Error' + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to create CA Template: $($_.Exception.Message)" -Sev 'Error' $body = [pscustomobject]@{'Results' = "Intune Template Deployment failed: $($_.Exception.Message)" } } diff --git a/Modules/CIPPCore/Public/New-CIPPCAPolicy.ps1 b/Modules/CIPPCore/Public/New-CIPPCAPolicy.ps1 index d4af47d3325a..5fd635238470 100644 --- a/Modules/CIPPCore/Public/New-CIPPCAPolicy.ps1 +++ b/Modules/CIPPCore/Public/New-CIPPCAPolicy.ps1 @@ -73,7 +73,9 @@ function New-CIPPCAPolicy { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Matched a CA policy with the existing Named Location: $($location.displayName)" -Sev 'Info' } else { + if ($location.countriesAndRegions) { $location.countriesAndRegions = @($location.countriesAndRegions) } $Body = ConvertTo-Json -InputObject $Location + Write-Host "Trying to create named location with: $body" $GraphRequest = New-GraphPOSTRequest -uri 'https://graph.microsoft.com/beta/identity/conditionalAccess/namedLocations' -body $body -Type POST -tenantid $tenantfilter Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Created new Named Location: $($location.displayName)" -Sev 'Info' [pscustomobject]@{ @@ -83,10 +85,9 @@ function New-CIPPCAPolicy { } } } - Write-Host 'here5' foreach ($location in $JSONObj.conditions.locations.includeLocations) { - Write-Host "Replacting $location" + Write-Host "Replacing $location" $lookup = $LocationLookupTable | Where-Object -Property name -EQ $location Write-Host "Found $lookup" if (!$lookup) { continue } From c5cf3f2048e334caaa02a6febc7242b9108fd2ef Mon Sep 17 00:00:00 2001 From: Roel van der Wegen Date: Tue, 30 Jan 2024 21:24:38 +0100 Subject: [PATCH 12/50] Add logging error to log --- Modules/CIPPCore/Public/Entrypoints/Invoke-ExecGDAPInvite.ps1 | 1 + 1 file changed, 1 insertion(+) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecGDAPInvite.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecGDAPInvite.ps1 index ff9a8d856843..d6a5965f2055 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecGDAPInvite.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecGDAPInvite.ps1 @@ -68,6 +68,7 @@ Function Invoke-ExecGDAPInvite { } catch { $Message = 'Error creating GDAP relationship' Write-Host "GDAP ERROR: $($_.Exception.Message)" + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $env:TenantID -message "$($Message): $($_.Exception.Message)" -Sev 'Error' } Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Created GDAP Invite - $InviteUrl" -Sev 'Info' From 7d17010039bd0777cc3ae194d4366fa2cd479b6d Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Tue, 30 Jan 2024 22:00:30 +0100 Subject: [PATCH 13/50] changes to scheduler --- .../Entrypoints/Push-SchedulerAlert.ps1 | 43 +++++ .../Push-SchedulerCIPPNotifications.ps1 | 164 ++++++++++++++++++ .../Push-Schedulerwebhookcreation.ps1 | 7 + Scheduler_Alert/function.json | 15 -- Scheduler_Alert/run.ps1 | 46 ----- Scheduler_CIPPNotifications/function.json | 9 - Scheduler_CIPPNotifications/run.ps1 | 164 ------------------ Scheduler_Extensions/run.ps1 | 12 +- Scheduler_GetQueue/function.json | 15 +- Scheduler_GetQueue/run.ps1 | 21 ++- Scheduler_Orchestration/function.json | 9 - Scheduler_Orchestration/run.ps1 | 32 ---- Scheduler_Timer/function.json | 15 -- Scheduler_Timer/run.ps1 | 8 - Z_CIPPQueueTrigger/function.json | 6 + 15 files changed, 254 insertions(+), 312 deletions(-) create mode 100644 Modules/CIPPCore/Public/Entrypoints/Push-SchedulerAlert.ps1 create mode 100644 Modules/CIPPCore/Public/Entrypoints/Push-SchedulerCIPPNotifications.ps1 create mode 100644 Modules/CIPPCore/Public/Entrypoints/Push-Schedulerwebhookcreation.ps1 delete mode 100644 Scheduler_Alert/function.json delete mode 100644 Scheduler_Alert/run.ps1 delete mode 100644 Scheduler_CIPPNotifications/function.json delete mode 100644 Scheduler_CIPPNotifications/run.ps1 delete mode 100644 Scheduler_Orchestration/function.json delete mode 100644 Scheduler_Orchestration/run.ps1 delete mode 100644 Scheduler_Timer/function.json delete mode 100644 Scheduler_Timer/run.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/Push-SchedulerAlert.ps1 b/Modules/CIPPCore/Public/Entrypoints/Push-SchedulerAlert.ps1 new file mode 100644 index 000000000000..d9800f40a34a --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Push-SchedulerAlert.ps1 @@ -0,0 +1,43 @@ +function Push-SchedulerAlert { + param ( + $QueueItem, $TriggerMetadata + ) + $Tenant = $QueueItem + try { + $Table = Get-CIPPTable -Table SchedulerConfig + if ($Tenant.tag -eq 'AllTenants') { + $Filter = "RowKey eq 'AllTenants' and PartitionKey eq 'Alert'" + } else { + $Filter = "RowKey eq '{0}' and PartitionKey eq 'Alert'" -f $Tenant.tenantid + } + $Alerts = Get-CIPPAzDataTableEntity @Table -Filter $Filter + + + $IgnoreList = @('Etag', 'PartitionKey', 'Timestamp', 'RowKey', 'tenantid', 'tenant', 'type') + $alertList = $Alerts | Select-Object * -ExcludeProperty $IgnoreList + foreach ($task in ($AlertList.psobject.members | Where-Object { $_.MemberType -EQ 'NoteProperty' -and $_.value -eq $True }).name) { + $QueueItem = [pscustomobject]@{ + tenant = $tenant.tenant + tenantid = $tenant.tenantid + FunctionName = "CIPPAlert$($Task)" + } + Push-OutputBinding -Name QueueItemOut -Value $QueueItem + } + + $Table = Get-CIPPTable + $PartitionKey = Get-Date -UFormat '%Y%m%d' + $Filter = "PartitionKey eq '{0}' and Tenant eq '{1}'" -f $PartitionKey, $tenant.tenant + $currentlog = Get-CIPPAzDataTableEntity @Table -Filter $Filter + + $AlertsTable = Get-CIPPTable -Table cachealerts + $CurrentAlerts = (Get-CIPPAzDataTableEntity @AlertsTable -Filter $Filter) + $CurrentAlerts | ForEach-Object { + if ($_.Message -notin $currentlog.Message) { Write-LogMessage -message $_.Message -API 'Alerts' -tenant $tenant.tenant -sev Alert -tenantid $Tenant.tenantid } + Remove-AzDataTableEntity @AlertsTable -Entity $_ | Out-Null + } + + } catch { + $Message = 'Exception on line {0} - {1}' -f $_.InvocationInfo.ScriptLineNumber, $_.Exception.Message + Write-LogMessage -message $Message -API 'Alerts' -tenant $tenant.tenant -sev Error + } +} \ No newline at end of file diff --git a/Modules/CIPPCore/Public/Entrypoints/Push-SchedulerCIPPNotifications.ps1 b/Modules/CIPPCore/Public/Entrypoints/Push-SchedulerCIPPNotifications.ps1 new file mode 100644 index 000000000000..3ec9e8b7d9a2 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Push-SchedulerCIPPNotifications.ps1 @@ -0,0 +1,164 @@ +function Push-SchedulerCIPPNotifications { + param ( + $QueueItem, $TriggerMetadata + ) + + $Table = Get-CIPPTable -TableName SchedulerConfig + $Filter = "RowKey eq 'CippNotifications' and PartitionKey eq 'CippNotifications'" + $Config = [pscustomobject](Get-CIPPAzDataTableEntity @Table -Filter $Filter) + + $Settings = [System.Collections.ArrayList]@('Alerts') + $Config.psobject.properties.name | ForEach-Object { $settings.add($_) } + $severity = $Config.Severity -split ',' + Write-Host "Our Severity table is: $severity" + if (!$severity) { + $severity = [System.Collections.ArrayList]@('Info', 'Error', 'Warning', 'Critical', 'Alert') + } + Write-Host "Our Severity table is: $severity" + $Table = Get-CIPPTable + $PartitionKey = Get-Date -UFormat '%Y%m%d' + $Filter = "PartitionKey eq '{0}'" -f $PartitionKey + $Currentlog = Get-CIPPAzDataTableEntity @Table -Filter $Filter | Where-Object { + $_.API -In $Settings -and $_.SentAsAlert -ne $true -and $_.Severity -In $severity + } + Write-Host ($Currentlog).count + #email try + try { + if ($config.onePerTenant) { + if ($Config.email -like '*@*' -and $null -ne $CurrentLog) { + $JSONRecipients = $Config.email.split(',').trim() | ForEach-Object { if ($_ -like '*@*') { '{ "EmailAddress": { "Address": "' + $_ + '" } }, ' } } + $JSONRecipients = ([string]$JSONRecipients).Substring(0, ([string]$JSONRecipients).Length - 1) + foreach ($tenant in ($CurrentLog.Tenant | Sort-Object -Unique)) { + $HTMLLog = ($CurrentLog | Select-Object Message, API, Tenant, Username, Severity | Where-Object -Property tenant -EQ $tenant | ConvertTo-Html -frag) -replace '', '
' | Out-String + $JSONBody = @" + { + "message": { + "subject": "$($Tenant): CIPP Alert: Alerts found starting at $((Get-Date).AddMinutes(-15))", + "body": { + "contentType": "HTML", + "content": "You've setup your alert policies to be alerted whenever specific events happen. We've found some of these events in the log:

+ + + $($HTMLLog) + + " + }, + "toRecipients": [ + $($JSONRecipients) + ] + }, + "saveToSentItems": "false" + } +"@ + New-GraphPostRequest -uri 'https://graph.microsoft.com/v1.0/me/sendMail' -tenantid $env:TenantID -type POST -body ($JSONBody) + Write-LogMessage -API 'Alerts' -message "Sent alerts to: $($JSONRecipients)" -tenant $Tenant -sev Debug + } + } + } else { + if ($Config.email -like '*@*' -and $null -ne $CurrentLog) { + $JSONRecipients = $Config.email.split(',').trim() | ForEach-Object { if ($_ -like '*@*') { '{ "EmailAddress": { "Address": "' + $_ + '" } }, ' } } + $JSONRecipients = ([string]$JSONRecipients).Substring(0, ([string]$JSONRecipients).Length - 1) + $HTMLLog = ($CurrentLog | Select-Object Message, API, Tenant, Username, Severity | ConvertTo-Html -frag) -replace '
', '
' | Out-String + $JSONBody = @" + { + "message": { + "subject": "CIPP Alert: Alerts found starting at $((Get-Date).AddMinutes(-15))", + "body": { + "contentType": "HTML", + "content": "You've setup your alert policies to be alerted whenever specific events happen. We've found some of these events in the log:

+ + + $($HTMLLog) + + " + }, + "toRecipients": [ + $($JSONRecipients) + ] + }, + "saveToSentItems": "false" + } +"@ + New-GraphPostRequest -uri 'https://graph.microsoft.com/v1.0/me/sendMail' -tenantid $env:TenantID -type POST -body ($JSONBody) + Write-LogMessage -API 'Alerts' -message "Sent alerts to: $($Config.email)" -tenant 'All Tenants' -sev Debug + } + } + } catch { + Write-Host "Could not send alerts to email: $($_.Exception.message)" + Write-LogMessage -API 'Alerts' -message "Could not send alerts to: $($_.Exception.message)" -tenant 'All Tenants' -sev error + } + + + try { + Write-Host $($config | ConvertTo-Json) + Write-Host $config.webhook + if ($Config.webhook -ne '' -and $null -ne $CurrentLog) { + switch -wildcard ($config.webhook) { + + '*webhook.office.com*' { + $Log = $Currentlog | ConvertTo-Html -frag | Out-String + $JSonBody = "{`"text`": `"You've setup your alert policies to be alerted whenever specific events happen. We've found some of these events in the log.

$Log`"}" + Invoke-RestMethod -Uri $config.webhook -Method POST -ContentType 'Application/json' -Body $JSONBody + } + + '*slack.com*' { + $Log = $Currentlog | ForEach-Object { + $JSonBody = @" + {"blocks":[{"type":"header","text":{"type":"plain_text","text":"New Alert from CIPP","emoji":true}},{"type":"section","fields":[{"type":"mrkdwn","text":"*DateTime:*\n$($_.Timestamp)"},{"type":"mrkdwn","text":"*Tenant:*\n$($_.Tenant)"},{"type":"mrkdwn","text":"*API:*\n$($_.API)"},{"type":"mrkdwn","text":"*User:*\n$($_.Username)."}]},{"type":"section","text":{"type":"mrkdwn","text":"*Message:*\n$($_.Message)"}}]} +"@ + Invoke-RestMethod -Uri $config.webhook -Method POST -ContentType 'Application/json' -Body $JSONBody + } + } + + '*discord.com*' { + $Log = $Currentlog | ConvertTo-Html -frag | Out-String + $JSonBody = "{`"content`": `"You've setup your alert policies to be alerted whenever specific events happen. We've found some of these events in the log. $Log`"}" + Invoke-RestMethod -Uri $config.webhook -Method POST -ContentType 'Application/json' -Body $JSONBody + } + default { + $Log = $Currentlog | ConvertTo-Json -Compress + $JSonBody = $Log + Invoke-RestMethod -Uri $config.webhook -Method POST -ContentType 'Application/json' -Body $JSONBody + } + } + Write-LogMessage -API 'Alerts' -tenant $Tenant -message "Sent Webhook to $($config.webhook)" -sev Debug + } + + $UpdateLogs = $CurrentLog | ForEach-Object { + $_.SentAsAlert = $true + $_ + } + if ($UpdateLogs) { + Add-CIPPAzDataTableEntity @Table -Entity $UpdateLogs -Force + } + } catch { + Write-Host "Could not send alerts to webhook: $($_.Exception.message)" + Write-LogMessage -API 'Alerts' -message "Could not send alerts to : $($_.Exception.message)" -tenant $Tenant -sev error + } + + if ($config.sendtoIntegration) { + try { + foreach ($tenant in ($CurrentLog.Tenant | Sort-Object -Unique)) { + $HTMLLog = ($CurrentLog | Select-Object Message, API, Tenant, Username, Severity | Where-Object -Property tenant -EQ $tenant | ConvertTo-Html -frag) -replace '
', '
' | Out-String + $Alert = @{ + TenantId = $Tenant + AlertText = " $($htmllog)" + AlertTitle = "$tenant CIPP Alert: Alerts found starting at $((Get-Date).AddMinutes(-15))" + } + New-CippExtAlert -Alert $Alert + $UpdateLogs = $CurrentLog | ForEach-Object { + $_.SentAsAlert = $true + $_ + } + if ($UpdateLogs) { + Add-CIPPAzDataTableEntity @Table -Entity $UpdateLogs -Force + } + } + } catch { + Write-Host "Could not send alerts to ticketing system: $($_.Exception.message)" + Write-LogMessage -API 'Alerts' -tenant $Tenant -message "Could not send alerts to ticketing system: $($_.Exception.message)" -sev Error + } + } + + +} \ No newline at end of file diff --git a/Modules/CIPPCore/Public/Entrypoints/Push-Schedulerwebhookcreation.ps1 b/Modules/CIPPCore/Public/Entrypoints/Push-Schedulerwebhookcreation.ps1 new file mode 100644 index 000000000000..82e1a47d55c5 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Push-Schedulerwebhookcreation.ps1 @@ -0,0 +1,7 @@ +function Push-Schedulerwebhookcreation + { + param ( + $QueueItem, $TriggerMetadata + ) + +} \ No newline at end of file diff --git a/Scheduler_Alert/function.json b/Scheduler_Alert/function.json deleted file mode 100644 index b8758df62b9d..000000000000 --- a/Scheduler_Alert/function.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "bindings": [ - { - "name": "tenant", - "direction": "in", - "type": "activityTrigger" - }, - { - "type": "queue", - "direction": "out", - "name": "QueueItem", - "queueName": "CIPPGenericQueue" - } - ] -} diff --git a/Scheduler_Alert/run.ps1 b/Scheduler_Alert/run.ps1 deleted file mode 100644 index 1a7cca3527e3..000000000000 --- a/Scheduler_Alert/run.ps1 +++ /dev/null @@ -1,46 +0,0 @@ -param($tenant) - -try { - - $Table = Get-CIPPTable -Table SchedulerConfig - if ($Tenant.tag -eq 'AllTenants') { - $Filter = "RowKey eq 'AllTenants' and PartitionKey eq 'Alert'" - } else { - $Filter = "RowKey eq '{0}' and PartitionKey eq 'Alert'" -f $Tenant.tenantid - } - $Alerts = Get-CIPPAzDataTableEntity @Table -Filter $Filter - - - $IgnoreList = @('Etag', 'PartitionKey', 'Timestamp', 'RowKey', 'tenantid', 'tenant', 'type') - $alertList = $Alerts | Select-Object * -ExcludeProperty $IgnoreList - foreach ($task in ($AlertList.psobject.members | Where-Object { $_.MemberType -EQ 'NoteProperty' -and $_.value -eq $True }).name) { - $QueueItem = [pscustomobject]@{ - tenant = $tenant.tenant - tenantid = $tenant.tenantid - FunctionName = "CIPPAlert$($Task)" - } - Push-OutputBinding -Name QueueItem -Value $QueueItem - } - - $Table = Get-CIPPTable - $PartitionKey = Get-Date -UFormat '%Y%m%d' - $Filter = "PartitionKey eq '{0}' and Tenant eq '{1}'" -f $PartitionKey, $tenant.tenant - $currentlog = Get-CIPPAzDataTableEntity @Table -Filter $Filter - - $AlertsTable = Get-CIPPTable -Table cachealerts - $CurrentAlerts = (Get-CIPPAzDataTableEntity @AlertsTable -Filter $Filter) - $CurrentAlerts | ForEach-Object { - if ($_.Message -notin $currentlog.Message) { Write-LogMessage -message $_.Message -API 'Alerts' -tenant $tenant.tenant -sev Alert -tenantid $Tenant.tenantid } - Remove-AzDataTableEntity @AlertsTable -Entity $_ | Out-Null - } - - [PSCustomObject]@{ - ReturnedValues = $true - } -} catch { - $Message = 'Exception on line {0} - {1}' -f $_.InvocationInfo.ScriptLineNumber, $_.Exception.Message - Write-LogMessage -message $Message -API 'Alerts' -tenant $tenant.tenant -sev Error - [PSCustomObject]@{ - ReturnedValues = $false - } -} diff --git a/Scheduler_CIPPNotifications/function.json b/Scheduler_CIPPNotifications/function.json deleted file mode 100644 index 2d4ea9094b24..000000000000 --- a/Scheduler_CIPPNotifications/function.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "bindings": [ - { - "name": "tenant", - "direction": "in", - "type": "activityTrigger" - } - ] -} \ No newline at end of file diff --git a/Scheduler_CIPPNotifications/run.ps1 b/Scheduler_CIPPNotifications/run.ps1 deleted file mode 100644 index 512f015f0fc9..000000000000 --- a/Scheduler_CIPPNotifications/run.ps1 +++ /dev/null @@ -1,164 +0,0 @@ -param($tenant) - - -$Table = Get-CIPPTable -TableName SchedulerConfig -$Filter = "RowKey eq 'CippNotifications' and PartitionKey eq 'CippNotifications'" -$Config = [pscustomobject](Get-CIPPAzDataTableEntity @Table -Filter $Filter) - -$Settings = [System.Collections.ArrayList]@('Alerts') -$Config.psobject.properties.name | ForEach-Object { $settings.add($_) } -$severity = $Config.Severity -split ',' -Write-Host "Our Severity table is: $severity" -if (!$severity) { - $severity = [System.Collections.ArrayList]@('Info', 'Error', 'Warning', 'Critical', 'Alert') -} -Write-Host "Our Severity table is: $severity" -$Table = Get-CIPPTable -$PartitionKey = Get-Date -UFormat '%Y%m%d' -$Filter = "PartitionKey eq '{0}'" -f $PartitionKey -$Currentlog = Get-CIPPAzDataTableEntity @Table -Filter $Filter | Where-Object { - $_.API -In $Settings -and $_.SentAsAlert -ne $true -and $_.Severity -In $severity -} -Write-Host ($Currentlog).count -#email try -try { - if ($config.onePerTenant) { - if ($Config.email -like '*@*' -and $null -ne $CurrentLog) { - $JSONRecipients = $Config.email.split(',').trim() | ForEach-Object { if ($_ -like '*@*') { '{ "EmailAddress": { "Address": "' + $_ + '" } }, ' } } - $JSONRecipients = ([string]$JSONRecipients).Substring(0, ([string]$JSONRecipients).Length - 1) - foreach ($tenant in ($CurrentLog.Tenant | Sort-Object -Unique)) { - $HTMLLog = ($CurrentLog | Select-Object Message, API, Tenant, Username, Severity | Where-Object -Property tenant -EQ $tenant | ConvertTo-Html -frag) -replace '
', '
' | Out-String - $JSONBody = @" - { - "message": { - "subject": "$($Tenant): CIPP Alert: Alerts found starting at $((Get-Date).AddMinutes(-15))", - "body": { - "contentType": "HTML", - "content": "You've setup your alert policies to be alerted whenever specific events happen. We've found some of these events in the log:

- - - $($HTMLLog) - - " - }, - "toRecipients": [ - $($JSONRecipients) - ] - }, - "saveToSentItems": "false" - } -"@ - New-GraphPostRequest -uri 'https://graph.microsoft.com/v1.0/me/sendMail' -tenantid $env:TenantID -type POST -body ($JSONBody) - Write-LogMessage -API 'Alerts' -message "Sent alerts to: $($JSONRecipients)" -tenant $Tenant -sev Debug - } - } - } else { - if ($Config.email -like '*@*' -and $null -ne $CurrentLog) { - $JSONRecipients = $Config.email.split(',').trim() | ForEach-Object { if ($_ -like '*@*') { '{ "EmailAddress": { "Address": "' + $_ + '" } }, ' } } - $JSONRecipients = ([string]$JSONRecipients).Substring(0, ([string]$JSONRecipients).Length - 1) - $HTMLLog = ($CurrentLog | Select-Object Message, API, Tenant, Username, Severity | ConvertTo-Html -frag) -replace '
', '
' | Out-String - $JSONBody = @" - { - "message": { - "subject": "CIPP Alert: Alerts found starting at $((Get-Date).AddMinutes(-15))", - "body": { - "contentType": "HTML", - "content": "You've setup your alert policies to be alerted whenever specific events happen. We've found some of these events in the log:

- - - $($HTMLLog) - - " - }, - "toRecipients": [ - $($JSONRecipients) - ] - }, - "saveToSentItems": "false" - } -"@ - New-GraphPostRequest -uri 'https://graph.microsoft.com/v1.0/me/sendMail' -tenantid $env:TenantID -type POST -body ($JSONBody) - Write-LogMessage -API 'Alerts' -message "Sent alerts to: $($Config.email)" -tenant 'All Tenants' -sev Debug - } - } -} catch { - Write-Host "Could not send alerts to email: $($_.Exception.message)" - Write-LogMessage -API 'Alerts' -message "Could not send alerts to: $($_.Exception.message)" -tenant 'All Tenants' -sev error -} - - -try { - Write-Host $($config | ConvertTo-Json) - Write-Host $config.webhook - if ($Config.webhook -ne '' -and $null -ne $CurrentLog) { - switch -wildcard ($config.webhook) { - - '*webhook.office.com*' { - $Log = $Currentlog | ConvertTo-Html -frag | Out-String - $JSonBody = "{`"text`": `"You've setup your alert policies to be alerted whenever specific events happen. We've found some of these events in the log.

$Log`"}" - Invoke-RestMethod -Uri $config.webhook -Method POST -ContentType 'Application/json' -Body $JSONBody - } - - '*slack.com*' { - $Log = $Currentlog | ForEach-Object { - $JSonBody = @" - {"blocks":[{"type":"header","text":{"type":"plain_text","text":"New Alert from CIPP","emoji":true}},{"type":"section","fields":[{"type":"mrkdwn","text":"*DateTime:*\n$($_.Timestamp)"},{"type":"mrkdwn","text":"*Tenant:*\n$($_.Tenant)"},{"type":"mrkdwn","text":"*API:*\n$($_.API)"},{"type":"mrkdwn","text":"*User:*\n$($_.Username)."}]},{"type":"section","text":{"type":"mrkdwn","text":"*Message:*\n$($_.Message)"}}]} -"@ - Invoke-RestMethod -Uri $config.webhook -Method POST -ContentType 'Application/json' -Body $JSONBody - } - } - - '*discord.com*' { - $Log = $Currentlog | ConvertTo-Html -frag | Out-String - $JSonBody = "{`"content`": `"You've setup your alert policies to be alerted whenever specific events happen. We've found some of these events in the log. $Log`"}" - Invoke-RestMethod -Uri $config.webhook -Method POST -ContentType 'Application/json' -Body $JSONBody - } - default { - $Log = $Currentlog | ConvertTo-Json -Compress - $JSonBody = $Log - Invoke-RestMethod -Uri $config.webhook -Method POST -ContentType 'Application/json' -Body $JSONBody - } - } - Write-LogMessage -API 'Alerts' -tenant $Tenant -message "Sent Webhook to $($config.webhook)" -sev Debug - } - - $UpdateLogs = $CurrentLog | ForEach-Object { - $_.SentAsAlert = $true - $_ - } - if ($UpdateLogs) { - Add-CIPPAzDataTableEntity @Table -Entity $UpdateLogs -Force - } -} catch { - Write-Host "Could not send alerts to webhook: $($_.Exception.message)" - Write-LogMessage -API 'Alerts' -message "Could not send alerts to : $($_.Exception.message)" -tenant $Tenant -sev error -} - -if ($config.sendtoIntegration) { - try { - foreach ($tenant in ($CurrentLog.Tenant | Sort-Object -Unique)) { - $HTMLLog = ($CurrentLog | Select-Object Message, API, Tenant, Username, Severity | Where-Object -Property tenant -EQ $tenant | ConvertTo-Html -frag) -replace '
', '
' | Out-String - $Alert = @{ - TenantId = $Tenant - AlertText = " $($htmllog)" - AlertTitle = "$tenant CIPP Alert: Alerts found starting at $((Get-Date).AddMinutes(-15))" - } - New-CippExtAlert -Alert $Alert - $UpdateLogs = $CurrentLog | ForEach-Object { - $_.SentAsAlert = $true - $_ - } - if ($UpdateLogs) { - Add-CIPPAzDataTableEntity @Table -Entity $UpdateLogs -Force - } - } - } catch { - Write-Host "Could not send alerts to ticketing system: $($_.Exception.message)" - Write-LogMessage -API 'Alerts' -tenant $Tenant -message "Could not send alerts to ticketing system: $($_.Exception.message)" -sev Error - } -} - - -[PSCustomObject]@{ - ReturnedValues = $true -} diff --git a/Scheduler_Extensions/run.ps1 b/Scheduler_Extensions/run.ps1 index c6ce09744cbd..66af8649ebf7 100644 --- a/Scheduler_Extensions/run.ps1 +++ b/Scheduler_Extensions/run.ps1 @@ -6,7 +6,7 @@ $Table = Get-CIPPTable -TableName Extensionsconfig $Configuration = ((Get-AzDataTableEntity @Table).config | ConvertFrom-Json) -Write-Host "Started Scheduler for Extensions" +Write-Host 'Started Scheduler for Extensions' # NinjaOne Extension if ($Configuration.NinjaOne.Enabled -eq $True) { @@ -42,7 +42,7 @@ if ($Configuration.NinjaOne.Enabled -eq $True) { $TenantsToProcess = Get-AzDataTableEntity @CIPPMapping -Filter $Filter | Where-Object { $Null -ne $_.NinjaOne -and $_.NinjaOne -ne '' } if ($Null -eq $LastRunTime -or $LastRunTime -le (Get-Date).addhours(-25) -or $TimeSetting -eq $CurrentInterval) { - Write-Host "Executing" + Write-Host 'Executing' foreach ($Tenant in $TenantsToProcess | Sort-Object lastEndTime) { Push-OutputBinding -Name NinjaProcess -Value @{ 'NinjaAction' = 'SyncTenant' @@ -55,7 +55,7 @@ if ($Configuration.NinjaOne.Enabled -eq $True) { $AddObject = @{ PartitionKey = 'NinjaConfig' RowKey = 'NinjaLastRunTime' - 'SettingValue' = (Get-Date).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffK") + 'SettingValue' = (Get-Date).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ss.fffK') } Add-AzDataTableEntity @Table -Entity $AddObject -Force @@ -76,7 +76,7 @@ if ($Configuration.NinjaOne.Enabled -eq $True) { $_ | Add-Member -NotePropertyName lastStartTime -NotePropertyValue $Null -Force } } - $CatchupTenants = $TenantsToProcess | where-object { (((($_.lastEndTime -eq $Null) -or ($_.lastStartTime -gt $_.lastEndTime)) -and ($_.lastStartTime -lt (Get-Date).AddMinutes(-30)))) -or ($_.lastStartTime -lt $LastRunTime) } + $CatchupTenants = $TenantsToProcess | Where-Object { (((($_.lastEndTime -eq $Null) -or ($_.lastStartTime -gt $_.lastEndTime)) -and ($_.lastStartTime -lt (Get-Date).AddMinutes(-30)))) -or ($_.lastStartTime -lt $LastRunTime) } foreach ($Tenant in $CatchupTenants) { Push-OutputBinding -Name NinjaProcess -Value @{ 'NinjaAction' = 'SyncTenant' @@ -84,8 +84,8 @@ if ($Configuration.NinjaOne.Enabled -eq $True) { } Start-Sleep -Seconds 1 } - if (($CatchupTenants | Measure-Object).count -gt 0){ - Write-LogMessage -API 'NinjaOneSync' -user 'CIPP' -message "NinjaOne Synchronization Catchup Queued for $(($CatchupTenants | Measure-Object).count) Tenants" -Sev 'Info' + if (($CatchupTenants | Measure-Object).count -gt 0) { + Write-LogMessage -API 'NinjaOneSync' -user 'CIPP' -message "NinjaOne Synchronization Catchup Queued for $(($CatchupTenants | Measure-Object).count) Tenants" -Sev 'Info' } } diff --git a/Scheduler_GetQueue/function.json b/Scheduler_GetQueue/function.json index b31f1ad21352..f9f3ccb2d877 100644 --- a/Scheduler_GetQueue/function.json +++ b/Scheduler_GetQueue/function.json @@ -1,9 +1,16 @@ { "bindings": [ { - "name": "name", - "type": "activityTrigger", - "direction": "in" + "name": "Timer", + "schedule": "0 */1 * * * *", + "direction": "in", + "type": "timerTrigger" + }, + { + "type": "queue", + "direction": "out", + "name": "QueueItem", + "queueName": "CIPPGenericQueue" } ] -} \ No newline at end of file +} diff --git a/Scheduler_GetQueue/run.ps1 b/Scheduler_GetQueue/run.ps1 index 3d495bd85264..f14ccc274dd4 100644 --- a/Scheduler_GetQueue/run.ps1 +++ b/Scheduler_GetQueue/run.ps1 @@ -1,9 +1,9 @@ -param($name) +param($Timer) $Table = Get-CIPPTable -TableName SchedulerConfig $Tenants = Get-CIPPAzDataTableEntity @Table | Where-Object -Property PartitionKey -NE 'WebhookAlert' -$object = foreach ($Tenant in $Tenants) { +$Tasks = foreach ($Tenant in $Tenants) { if ($Tenant.tenant -ne 'AllTenants') { [pscustomobject]@{ Tenant = $Tenant.tenant @@ -23,6 +23,19 @@ $object = foreach ($Tenant in $Tenants) { } } } -} +} -$object \ No newline at end of file +foreach ($Task in $Tasks) { + $QueueItem = [pscustomobject]@{ + Tenant = $task.tenant + Tenantid = $task.tenantid + Tag = $task.tag + Type = $task.type + FunctionName = "Scheduler$($Task.Type)" + } + try { + Push-OutputBinding -Name QueueItem -Value $QueueItem + } catch { + Write-Host "Could not launch queue item for $($Task.tenant): $($_.Exception.Message)" + } +} \ No newline at end of file diff --git a/Scheduler_Orchestration/function.json b/Scheduler_Orchestration/function.json deleted file mode 100644 index 7326b39c184d..000000000000 --- a/Scheduler_Orchestration/function.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "bindings": [ - { - "name": "Context", - "type": "orchestrationTrigger", - "direction": "in" - } - ] -} \ No newline at end of file diff --git a/Scheduler_Orchestration/run.ps1 b/Scheduler_Orchestration/run.ps1 deleted file mode 100644 index 0014b630fe38..000000000000 --- a/Scheduler_Orchestration/run.ps1 +++ /dev/null @@ -1,32 +0,0 @@ -param($Context) - -$DurableRetryOptions = @{ - FirstRetryInterval = (New-TimeSpan -Seconds 5) - MaxNumberOfAttempts = 3 - BackoffCoefficient = 2 -} -$RetryOptions = New-DurableRetryOptions @DurableRetryOptions - -try { - $Batch = Invoke-ActivityFunction -FunctionName 'Scheduler_GetQueue' -Input 'LetsGo' - if (($Batch | Measure-Object).Count -gt 0) { - - $ParallelTasks = foreach ($Item in $Batch) { - try { - Invoke-DurableActivity -FunctionName "Scheduler_$($item['Type'])" -Input $item -NoWait -RetryOptions $RetryOptions -ErrorAction Stop - } - catch { - Write-Host 'Could not start:' - Write-Host ($item | ConvertTo-Json) - } - } - $Outputs = Wait-ActivityFunction -Task $ParallelTasks - if (-not $Outputs['DataReturned']) { - Write-Host 'Errors detected' - } - } -} -catch {} -finally { - Write-LogMessage -API 'Scheduler' -tenant $tenant -message 'Scheduler Ran.' -sev Debug -} \ No newline at end of file diff --git a/Scheduler_Timer/function.json b/Scheduler_Timer/function.json deleted file mode 100644 index 56e4cf0cfda1..000000000000 --- a/Scheduler_Timer/function.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "bindings": [ - { - "name": "Timer", - "schedule": "0 0 * * * *", - "direction": "in", - "type": "timerTrigger" - }, - { - "name": "starter", - "type": "durableClient", - "direction": "in" - } - ] -} diff --git a/Scheduler_Timer/run.ps1 b/Scheduler_Timer/run.ps1 deleted file mode 100644 index f62c2909b58d..000000000000 --- a/Scheduler_Timer/run.ps1 +++ /dev/null @@ -1,8 +0,0 @@ -using namespace System.Net - -param($Timer) - -$InstanceId = Start-NewOrchestration -FunctionName 'Scheduler_Orchestration' -Write-Host "Started orchestration with ID = '$InstanceId'" -New-OrchestrationCheckStatusResponse -Request $timer -InstanceId $InstanceId - diff --git a/Z_CIPPQueueTrigger/function.json b/Z_CIPPQueueTrigger/function.json index c048325fc313..4d818463ea75 100644 --- a/Z_CIPPQueueTrigger/function.json +++ b/Z_CIPPQueueTrigger/function.json @@ -7,6 +7,12 @@ "type": "queueTrigger", "direction": "in", "queueName": "CIPPGenericQueue" + }, + { + "type": "queue", + "direction": "out", + "name": "QueueItemOut", + "queueName": "CIPPGenericQueue" } ] } From 6c2c5579a305e79da35cd08109ac4ee898a02f08 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Tue, 30 Jan 2024 22:05:31 +0100 Subject: [PATCH 14/50] timing --- Scheduler_GetQueue/function.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scheduler_GetQueue/function.json b/Scheduler_GetQueue/function.json index f9f3ccb2d877..73fa51771c60 100644 --- a/Scheduler_GetQueue/function.json +++ b/Scheduler_GetQueue/function.json @@ -2,7 +2,7 @@ "bindings": [ { "name": "Timer", - "schedule": "0 */1 * * * *", + "schedule": "0 */15 * * * *", "direction": "in", "type": "timerTrigger" }, From fd56e576eae05e8115c7461e1eccfde9e336be08 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Tue, 30 Jan 2024 22:07:07 +0100 Subject: [PATCH 15/50] decreased amount of syncs --- Scheduler_Extensions/function.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scheduler_Extensions/function.json b/Scheduler_Extensions/function.json index a0b7faadd73d..f3e5317f409a 100644 --- a/Scheduler_Extensions/function.json +++ b/Scheduler_Extensions/function.json @@ -2,7 +2,7 @@ "bindings": [ { "name": "Timer", - "schedule": "0 */15 * * * *", + "schedule": "0 0 */2 * * *", "direction": "in", "type": "timerTrigger" }, From 37d4679a0c09d1f6b87d899ccca2ce09b4baed92 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Tue, 30 Jan 2024 22:14:37 +0100 Subject: [PATCH 16/50] set to 1 hour again --- Scheduler_GetQueue/function.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scheduler_GetQueue/function.json b/Scheduler_GetQueue/function.json index 73fa51771c60..d0f59a682e3c 100644 --- a/Scheduler_GetQueue/function.json +++ b/Scheduler_GetQueue/function.json @@ -2,7 +2,7 @@ "bindings": [ { "name": "Timer", - "schedule": "0 */15 * * * *", + "schedule": "0 0 * * * *", "direction": "in", "type": "timerTrigger" }, From 60442434a29666270c7542e6c06bc7095eb84088 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Tue, 30 Jan 2024 22:43:10 +0100 Subject: [PATCH 17/50] updates to webhook creation --- .../Public/Entrypoints/Invoke-AddAlert.ps1 | 4 ++-- .../Public/New-CIPPGraphSubscription.ps1 | 24 ++++++++++++++++--- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-AddAlert.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddAlert.ps1 index b2ac6be60384..9bc6df14e424 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-AddAlert.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddAlert.ps1 @@ -56,7 +56,7 @@ Function Invoke-AddAlert { $params = @{ TenantFilter = $_.defaultDomainName auditLogAPI = $true - operations = 'Audit.AzureActiveDirectory,Audit.Exchange,Audit.SharePoint,Audit.General' + operations = $Request.body.ifs.selection BaseURL = $URL ExecutingUser = $Request.headers.'x-ms-client-principal' } @@ -73,7 +73,7 @@ Function Invoke-AddAlert { $params = @{ TenantFilter = $tenant auditLogAPI = $true - operations = 'Audit.AzureActiveDirectory,Audit.Exchange,Audit.SharePoint,Audit.General' + operations = $Request.body.ifs.selection BaseURL = $URL ExecutingUser = $Request.headers.'x-ms-client-principal' } diff --git a/Modules/CIPPCore/Public/New-CIPPGraphSubscription.ps1 b/Modules/CIPPCore/Public/New-CIPPGraphSubscription.ps1 index 16877c1e6524..6eac507448ec 100644 --- a/Modules/CIPPCore/Public/New-CIPPGraphSubscription.ps1 +++ b/Modules/CIPPCore/Public/New-CIPPGraphSubscription.ps1 @@ -15,10 +15,28 @@ function New-CIPPGraphSubscription { ) $CIPPID = (New-Guid).GUID $WebhookTable = Get-CIPPTable -TableName webhookTable - + Write-Host "Operations are: $operations" try { if ($auditLogAPI) { - $EventTypes = @('Audit.AzureActiveDirectory', 'Audit.Exchange', 'Audit.SharePoint', 'Audit.General') + $MappingTable = [pscustomobject]@{ + 'UserLoggedIn' = 'Audit.AzureActiveDirectory' + 'Add member to role.' = 'Audit.AzureActiveDirectory' + 'Disable account.' = 'Audit.AzureActiveDirectory' + 'Update StsRefreshTokenValidFrom Timestamp.' = 'Audit.AzureActiveDirectory' + 'Enable account.' = 'Audit.AzureActiveDirectory' + 'Disable Strong Authentication.' = 'Audit.AzureActiveDirectory' + 'Reset user password.' = 'Audit.AzureActiveDirectory' + 'Add service principal.' = 'Audit.AzureActiveDirectory' + 'HostedIP' = 'Audit.AzureActiveDirectory' + 'badRepIP' = 'Audit.AzureActiveDirectory' + 'UserLoggedInFromUnknownLocation' = 'Audit.AzureActiveDirectory' + 'customfield' = 'AnyLog' + 'anyAlert' = 'AnyLog' + 'New-InboxRule' = 'Audit.Exchange' + 'Set-InboxRule' = 'Audit.Exchange' + } + $EventTypes = $operations | Where-Object { $MappingTable.$_ } | ForEach-Object { $MappingTable.$_ } + if ('anyLog' -in $EventTypes) { $EventTypes = @('Audit.AzureActiveDirectory', 'Audit.Exchange', 'Audit.SharePoint', 'Audit.General') } foreach ($EventType in $EventTypes) { $CIPPID = (New-Guid).GUID $Resource = $EventType @@ -42,7 +60,7 @@ function New-CIPPGraphSubscription { WebhookNotificationUrl = [string]$CIPPAuditURL } Add-CIPPAzDataTableEntity @WebhookTable -Entity $WebhookRow - + Write-Host "Creating webhook subscription for $EventType" $AuditLog = New-GraphPOSTRequest -uri "https://manage.office.com/api/v1.0/$($TenantFilter)/activity/feed/subscriptions/start?contentType=$EventType&PublisherIdentifier=$($TenantFilter)" -tenantid $TenantFilter -type POST -scope 'https://manage.office.com/.default' -body $AuditLogparams -verbose Write-LogMessage -user $ExecutingUser -API $APIName -message "Created Webhook subscription for $($TenantFilter) for the log $($EventType)" -Sev 'Info' -tenant $TenantFilter From dcf1a040a15d1bdc1877726e18c80246b19e7792 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Wed, 31 Jan 2024 09:56:03 +0100 Subject: [PATCH 18/50] breakout from loop --- .../Entrypoints/Push-CIPPAlertMFAAdmins.ps1 | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertMFAAdmins.ps1 b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertMFAAdmins.ps1 index 26baebfccf93..b0c8056e1f03 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertMFAAdmins.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertMFAAdmins.ps1 @@ -6,19 +6,19 @@ function Push-CIPPAlertMFAAdmins { $TriggerMetadata ) try { - $CAPolicies = (New-GraphGetRequest -Uri 'https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies' -tenantid $QueueItem.tenant -ErrorAction Stop) + $CAPolicies = (New-GraphGetRequest -Uri 'https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies?$top=999' -tenantid $QueueItem.tenant -ErrorAction Stop) foreach ($Policy in $CAPolicies) { if ($policy.grantControls.customAuthenticationFactors -eq 'RequireDuoMfa') { $DuoActive = $true } - if (!$DuoActive) { - $users = New-GraphGETRequest -uri 'https://graph.microsoft.com/beta/reports/authenticationMethods/userRegistrationDetails?$filter=IsAdmin eq true' -tenantid $($QueueItem.tenant) | Where-Object -Property 'isMfaRegistered' -EQ $false - if ($users) { - Write-AlertMessage -tenant $QueueItem.tenant -message "The following admins do not have MFA registered: $($users.UserPrincipalName -join ', ')" - } - } else { - Write-LogMessage -message 'Potentially using Duo for MFA, could not check MFA status for Admins with 100% accuracy' -API 'MFA Alerts - Informational' -tenant $QueueItem.tenant -sev Info + } + if (!$DuoActive) { + $users = New-GraphGETRequest -uri 'https://graph.microsoft.com/beta/reports/authenticationMethods/userRegistrationDetails?$top=999&$filter=IsAdmin eq true' -tenantid $($QueueItem.tenant) | Where-Object -Property 'isMfaRegistered' -EQ $false + if ($users) { + Write-AlertMessage -tenant $QueueItem.tenant -message "The following admins do not have MFA registered: $($users.UserPrincipalName -join ', ')" } + } else { + Write-LogMessage -message 'Potentially using Duo for MFA, could not check MFA status for Admins with 100% accuracy' -API 'MFA Alerts - Informational' -tenant $QueueItem.tenant -sev Info } } catch { Write-LogMessage -message "Failed to check MFA status for Admins: $($_.exception.message)" -API 'MFA Alerts - Informational' -tenant $QueueItem.tenant -sev Error From 9be36b667bdd7c3166fb8e073b9de2ac443d95b3 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Wed, 31 Jan 2024 20:58:05 +0100 Subject: [PATCH 19/50] cleaned --- .../Standards/Invoke-CIPPStandardDisableM365GroupUsers.ps1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableM365GroupUsers.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableM365GroupUsers.ps1 index 125025a40b83..f9beff174010 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableM365GroupUsers.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableM365GroupUsers.ps1 @@ -11,12 +11,12 @@ function Invoke-CIPPStandardDisableM365GroupUsers { if (!$CurrentState) { #if no current configuration is found, we set it to the default template supplied by MS. $CurrentState = '{"id":"","displayName":"Group.Unified","templateId":"62375ab9-6b52-47ed-826b-58e47e0e304b","values":[{"name":"NewUnifiedGroupWritebackDefault","value":"true"},{"name":"EnableMIPLabels","value":"false"},{"name":"CustomBlockedWordsList","value":""},{"name":"EnableMSStandardBlockedWords","value":"false"},{"name":"ClassificationDescriptions","value":""},{"name":"DefaultClassification","value":""},{"name":"PrefixSuffixNamingRequirement","value":""},{"name":"AllowGuestsToBeGroupOwner","value":"false"},{"name":"AllowGuestsToAccessGroups","value":"true"},{"name":"GuestUsageGuidelinesUrl","value":""},{"name":"GroupCreationAllowedGroupId","value":""},{"name":"AllowToAddGuests","value":"true"},{"name":"UsageGuidelinesUrl","value":""},{"name":"ClassificationList","value":""},{"name":"EnableGroupCreation","value":"true"}]}' - (New-GraphPostRequest -tenantid $tenant -Uri "https://graph.microsoft.com/beta/settings/$($CurrentState.id)" -Type POST -Body $CurrentState -ContentType 'application/json') + New-GraphPostRequest -tenantid $tenant -Uri "https://graph.microsoft.com/beta/settings/$($CurrentState.id)" -Type POST -Body $CurrentState -ContentType 'application/json' $CurrentState = (New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/settings' -tenantid $tenant) | Where-Object -Property displayname -EQ 'Group.unified' } - ($CurrentState.values | Where-Object { $_.name -eq 'EnableGroupCreation' }).value = 'false' + ($CurrentState.values | Where-Object { $_.name -eq 'EnableGroupCreation' }).value = 'false' $body = "{values : $($CurrentState.values | ConvertTo-Json -Compress)}" - (New-GraphPostRequest -tenantid $tenant -Uri "https://graph.microsoft.com/beta/settings/$($CurrentState.id)" -Type patch -Body $body -ContentType 'application/json') + New-GraphPostRequest -tenantid $tenant -asApp $true-Uri "https://graph.microsoft.com/beta/settings/$($CurrentState.id)" -Type patch -Body $body -ContentType 'application/json' Write-LogMessage -API 'Standards' -tenant $tenant -message 'Standards API: Disabled users from creating M365 Groups.' -sev Info } catch { Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to disable users from creating M365 Groups: $($_.exception.message)" -sev 'Error' From 929a20cc80ed9c12a8c3d57bbe100187546958e5 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Wed, 31 Jan 2024 21:40:15 +0100 Subject: [PATCH 20/50] technical and compliance have become the same entry. --- .../Public/Standards/Invoke-CIPPStandardMailContacts.ps1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMailContacts.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMailContacts.ps1 index 738420ebe73a..fc2b34dda7b1 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMailContacts.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMailContacts.ps1 @@ -13,13 +13,13 @@ function Invoke-CIPPStandardMailContacts { $Body = [pscustomobject]@{} switch ($Contacts) { { $Contacts.MarketingContact } { $body | Add-Member -NotePropertyName marketingNotificationEmails -NotePropertyValue @($Contacts.MarketingContact) } - { $Contacts.SecurityContact } { $body | Add-Member -NotePropertyName securityComplianceNotificationMails -NotePropertyValue @($Contacts.SecurityContact) } + { $Contacts.SecurityContact } { $body | Add-Member -NotePropertyName technicalNotificationMails -NotePropertyValue @($Contacts.SecurityContact) } { $Contacts.TechContact } { $body | Add-Member -NotePropertyName technicalNotificationMails -NotePropertyValue @($Contacts.TechContact) } { $Contacts.GeneralContact } { $body | Add-Member -NotePropertyName privacyProfile -NotePropertyValue @{contactEmail = $Contacts.GeneralContact } } } Write-Host (ConvertTo-Json -InputObject $body) - New-GraphPostRequest -tenantid $tenant -Uri "https://graph.microsoft.com/beta/organization/$($TenantID.id)" -asApp $true -Type patch -Body (ConvertTo-Json -InputObject $body) -ContentType 'application/json' - Write-LogMessage -API 'Standards' -tenant $tenant -message "Contact email's set." -sev Info + New-GraphPostRequest -tenantid $tenant -Uri "https://graph.microsoft.com/v1.0/organization/$($TenantID.id)" -asApp $true -Type patch -Body (ConvertTo-Json -InputObject $body) -ContentType 'application/json' + Write-LogMessage -API 'Standards' -tenant $tenant -message 'Contact emails set.' -sev Info } catch { Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to set contact emails: $($_.exception.message)" -sev Error } From 5ee2bcb3cca7fe1493c6907050711e3daa1e77b7 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Wed, 31 Jan 2024 23:11:15 +0100 Subject: [PATCH 21/50] spacing issue --- .../Standards/Invoke-CIPPStandardDisableM365GroupUsers.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableM365GroupUsers.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableM365GroupUsers.ps1 index f9beff174010..bbb62f9b0b92 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableM365GroupUsers.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableM365GroupUsers.ps1 @@ -11,12 +11,12 @@ function Invoke-CIPPStandardDisableM365GroupUsers { if (!$CurrentState) { #if no current configuration is found, we set it to the default template supplied by MS. $CurrentState = '{"id":"","displayName":"Group.Unified","templateId":"62375ab9-6b52-47ed-826b-58e47e0e304b","values":[{"name":"NewUnifiedGroupWritebackDefault","value":"true"},{"name":"EnableMIPLabels","value":"false"},{"name":"CustomBlockedWordsList","value":""},{"name":"EnableMSStandardBlockedWords","value":"false"},{"name":"ClassificationDescriptions","value":""},{"name":"DefaultClassification","value":""},{"name":"PrefixSuffixNamingRequirement","value":""},{"name":"AllowGuestsToBeGroupOwner","value":"false"},{"name":"AllowGuestsToAccessGroups","value":"true"},{"name":"GuestUsageGuidelinesUrl","value":""},{"name":"GroupCreationAllowedGroupId","value":""},{"name":"AllowToAddGuests","value":"true"},{"name":"UsageGuidelinesUrl","value":""},{"name":"ClassificationList","value":""},{"name":"EnableGroupCreation","value":"true"}]}' - New-GraphPostRequest -tenantid $tenant -Uri "https://graph.microsoft.com/beta/settings/$($CurrentState.id)" -Type POST -Body $CurrentState -ContentType 'application/json' + New-GraphPostRequest -tenantid $tenant -Uri "https://graph.microsoft.com/beta/settings/$($CurrentState.id)" -AsApp $true -Type POST -Body $CurrentState -ContentType 'application/json' $CurrentState = (New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/settings' -tenantid $tenant) | Where-Object -Property displayname -EQ 'Group.unified' } ($CurrentState.values | Where-Object { $_.name -eq 'EnableGroupCreation' }).value = 'false' $body = "{values : $($CurrentState.values | ConvertTo-Json -Compress)}" - New-GraphPostRequest -tenantid $tenant -asApp $true-Uri "https://graph.microsoft.com/beta/settings/$($CurrentState.id)" -Type patch -Body $body -ContentType 'application/json' + New-GraphPostRequest -tenantid $tenant -asApp $true -Uri "https://graph.microsoft.com/beta/settings/$($CurrentState.id)" -Type patch -Body $body -ContentType 'application/json' Write-LogMessage -API 'Standards' -tenant $tenant -message 'Standards API: Disabled users from creating M365 Groups.' -sev Info } catch { Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to disable users from creating M365 Groups: $($_.exception.message)" -sev 'Error' From a1a09c5c80babd8c79fd0f2e00eee2208c260582 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Wed, 31 Jan 2024 23:26:44 +0100 Subject: [PATCH 22/50] typo correctly --- .../Standards/Invoke-CIPPStandardsharingCapability.ps1 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardsharingCapability.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardsharingCapability.ps1 index e7e177a3cdce..0003bddc0be4 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardsharingCapability.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardsharingCapability.ps1 @@ -9,17 +9,17 @@ function Invoke-CIPPStandardsharingCapability { If ($Settings.remediate) { try { New-GraphPostRequest -tenantid $tenant -Uri 'https://graph.microsoft.com/beta/admin/sharepoint/settings' -AsApp $true -Type patch -Body "{`"sharingCapability`":`"$($Settings.Level)`"}" -ContentType 'application/json' - Write-LogMessage -API 'Standards' -tenant $tenant -message "Set sharing level to $($Settings.level)" -sev Info + Write-LogMessage -API 'Standards' -tenant $tenant -message "Set sharing level to $($Settings.Level)" -sev Info } catch { - Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to set sharing level to $($Settings.level): $($_.exception.message)" -sev Error + Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to set sharing level to $($Settings.Level): $($_.exception.message)" -sev Error } } if ($Settings.alert) { if ($CurrentInfo.sharingCapability -eq $Settings.level) { - Write-LogMessage -API 'Standards' -tenant $tenant -message "Sharing level is set to $($Settings.level)" -sev Info + Write-LogMessage -API 'Standards' -tenant $tenant -message "Sharing level is set to $($Settings.Level)" -sev Info } else { - Write-LogMessage -API 'Standards' -tenant $tenant -message "Sharing level is not set to $($Settings.level)" -sev Alert + Write-LogMessage -API 'Standards' -tenant $tenant -message "Sharing level is not set to $($Settings.Level)" -sev Alert } } if ($Settings.report) { From f5c23e5798149ed0625bd4d18befe47dd4812ce0 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 31 Jan 2024 17:35:45 -0500 Subject: [PATCH 23/50] Fix cache table name length --- .../CIPPCore/Public/Entrypoints/Push-ListGraphRequestQueue.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Push-ListGraphRequestQueue.ps1 b/Modules/CIPPCore/Public/Entrypoints/Push-ListGraphRequestQueue.ps1 index 126e8d14335d..82f12e1df665 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Push-ListGraphRequestQueue.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Push-ListGraphRequestQueue.ps1 @@ -19,7 +19,7 @@ function Push-ListGraphRequestQueue { $PartitionKey = $QueueItem.PartitionKey - $TableName = ('cache{0}' -f ($QueueItem.Endpoint -replace '[^A-Za-z0-9]'))[0..63] -join '' + $TableName = ('cache{0}' -f ($QueueItem.Endpoint -replace '[^A-Za-z0-9]'))[0..62] -join '' Write-Host $TableName $Table = Get-CIPPTable -TableName $TableName From 60b76be8ad1aaac1e9c614cea3ea2ed6eac188db Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Thu, 1 Feb 2024 12:33:35 +0100 Subject: [PATCH 24/50] added attributes to edit user --- .../Public/Entrypoints/Invoke-EditUser.ps1 | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-EditUser.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-EditUser.ps1 index 132ccd3af8af..9f7ba18ed39a 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-EditUser.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-EditUser.ps1 @@ -44,8 +44,17 @@ Function Invoke-EditUser { } } | ForEach-Object { $NonEmptyProperties = $_.psobject.Properties | Select-Object -ExpandProperty Name - $_ | Select-Object -Property $NonEmptyProperties | ConvertTo-Json + $_ | Select-Object -Property $NonEmptyProperties } + if ($userobj.addedAttributes) { + Write-Host 'Found added attribute' + Write-Host "Added attributes: $($userobj.addedAttributes | ConvertTo-Json)" + $userobj.addedAttributes.getenumerator() | ForEach-Object { + $results.add("Edited property $($_.Key) with value $($_.Value)") + $bodytoShip | Add-Member -NotePropertyName $_.Key -NotePropertyValue $_.Value -Force + } + } + $bodyToShip = ConvertTo-Json -Depth 10 -InputObject $BodyToship -Compress $GraphRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($userobj.Userid)" -tenantid $Userobj.tenantid -type PATCH -body $BodyToship -verbose $results.add( 'Success. The user has been edited.' ) Write-LogMessage -API $APINAME -tenant ($UserObj.tenantid) -user $request.headers.'x-ms-client-principal' -message "Edited user $($userobj.displayname) with id $($userobj.Userid)" -Sev 'Info' @@ -55,8 +64,7 @@ Function Invoke-EditUser { $results.add("Success. The password has been set to $($userobj.password)") Write-LogMessage -API $APINAME -tenant ($UserObj.tenantid) -user $request.headers.'x-ms-client-principal' -message "Reset $($userobj.displayname)'s Password" -Sev 'Info' } - } - catch { + } catch { Write-LogMessage -API $APINAME -tenant ($UserObj.tenantid) -user $request.headers.'x-ms-client-principal' -message "User edit API failed. $($_.Exception.Message)" -Sev 'Error' $results.add( "Failed to edit user. $($_.Exception.Message)") } @@ -81,8 +89,7 @@ Function Invoke-EditUser { $results.add( 'Success. User license has been edited.' ) } - } - catch { + } catch { Write-LogMessage -API $APINAME -tenant ($UserObj.tenantid) -user $request.headers.'x-ms-client-principal' -message "License assign API failed. $($_.Exception.Message)" -Sev 'Error' $results.add( "We've failed to assign the license. $($_.Exception.Message)") } @@ -98,8 +105,7 @@ Function Invoke-EditUser { $results.add( 'Success. added aliasses to user.') } - } - catch { + } catch { Write-LogMessage -API $APINAME -tenant ($UserObj.tenantid) -user $request.headers.'x-ms-client-principal' -message "Alias API failed. $($_.Exception.Message)" -Sev 'Error' $results.add( "Successfully edited user. The password is $password. We've failed to create the Aliases: $($_.Exception.Message)") } From 5dc69165d915d949ff8fbab3fca73488efb18a33 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Thu, 1 Feb 2024 13:52:34 +0100 Subject: [PATCH 25/50] added text --- .../Entrypoints/Push-CIPPAlertNoCAConfig.ps1 | 2 +- .../Push-CIPPAlertOverusedLicenses.ps1 | 2 +- .../Entrypoints/Push-CIPPAlertQuotaUsed.ps1 | 3 +- .../Push-CIPPAlertUnusedLicenses.ps1 | 30 +++++++++---------- 4 files changed, 19 insertions(+), 18 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertNoCAConfig.ps1 b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertNoCAConfig.ps1 index 72bd6d90b151..17b5363a1c54 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertNoCAConfig.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertNoCAConfig.ps1 @@ -15,7 +15,7 @@ function Push-CIPPAlertNoCAConfig { } } } catch { - Write-AlertMessage -tenant $($QueueItem.tenant) -message "Error occurred: $(Get-NormalizedError -message $_.Exception.message)" + Write-AlertMessage -tenant $($QueueItem.tenant) -message "Conditional Access Config Alert: Error occurred: $(Get-NormalizedError -message $_.Exception.message)" } } diff --git a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertOverusedLicenses.ps1 b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertOverusedLicenses.ps1 index bd96b03266cd..af90000fa4d0 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertOverusedLicenses.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertOverusedLicenses.ps1 @@ -22,6 +22,6 @@ function Push-CIPPAlertOverusedLicenses { } } } catch { - Write-AlertMessage -tenant $($QueueItem.tenant) -message "Error occurred: $(Get-NormalizedError -message $_.Exception.message)" + Write-AlertMessage -tenant $($QueueItem.tenant) -message "Overused Licenses Alert Error occurred: $(Get-NormalizedError -message $_.Exception.message)" } } diff --git a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertQuotaUsed.ps1 b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertQuotaUsed.ps1 index 9adaa80ceca6..1e5f94064479 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertQuotaUsed.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertQuotaUsed.ps1 @@ -9,12 +9,13 @@ function Push-CIPPAlertQuotaUsed { try { New-GraphGetRequest -uri "https://graph.microsoft.com/beta/reports/getMailboxUsageDetail(period='D7')?`$format=application/json" -tenantid $QueueItem.tenant | ForEach-Object { + if ($_.StorageUsedInBytes -eq 0) { continue } $PercentLeft = [math]::round($_.StorageUsedInBytes / $_.prohibitSendReceiveQuotaInBytes * 100) if ($PercentLeft -gt 90) { Write-AlertMessage -tenant $($QueueItem.tenant) -message "$($_.UserPrincipalName): Mailbox has less than 10% space left. Mailbox is $PercentLeft% full" } } } catch { - Write-AlertMessage -tenant $($QueueItem.tenant) -message "Error occurred: $(Get-NormalizedError -message $_.Exception.message)" + Write-AlertMessage -tenant $($QueueItem.tenant) -message "Mailbox Quota Alert Error occurred: $(Get-NormalizedError -message $_.Exception.message)" } } diff --git a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertUnusedLicenses.ps1 b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertUnusedLicenses.ps1 index c2e7beeb6522..2bd58f8b6178 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertUnusedLicenses.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertUnusedLicenses.ps1 @@ -7,21 +7,21 @@ function Push-CIPPAlertUnusedLicenses { ) - try { - $LicenseTable = Get-CIPPTable -TableName ExcludedLicenses - $ExcludedSkuList = Get-CIPPAzDataTableEntity @LicenseTable - New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/subscribedSkus' -tenantid $QueueItem.tenant | ForEach-Object { - $skuid = $_ - foreach ($sku in $skuid) { - if ($sku.skuId -in $ExcludedSkuList.GUID) { continue } - $PrettyName = ($ConvertTable | Where-Object { $_.GUID -eq $sku.skuid }).'Product_Display_Name' | Select-Object -Last 1 - if (!$PrettyName) { $PrettyName = $sku.skuPartNumber } - if ($sku.prepaidUnits.enabled - $sku.consumedUnits -gt 0) { - Write-AlertMessage -tenant $($QueueItem.tenant) -message "$PrettyName has unused licenses. Using $($_.consumedUnits) of $($_.prepaidUnits.enabled)." - } - } + try { + $LicenseTable = Get-CIPPTable -TableName ExcludedLicenses + $ExcludedSkuList = Get-CIPPAzDataTableEntity @LicenseTable + New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/subscribedSkus' -tenantid $QueueItem.tenant | ForEach-Object { + $skuid = $_ + foreach ($sku in $skuid) { + if ($sku.skuId -in $ExcludedSkuList.GUID) { continue } + $PrettyName = ($ConvertTable | Where-Object { $_.GUID -eq $sku.skuid }).'Product_Display_Name' | Select-Object -Last 1 + if (!$PrettyName) { $PrettyName = $sku.skuPartNumber } + if ($sku.prepaidUnits.enabled - $sku.consumedUnits -gt 0) { + Write-AlertMessage -tenant $($QueueItem.tenant) -message "$PrettyName has unused licenses. Using $($_.consumedUnits) of $($_.prepaidUnits.enabled)." } - } catch { - Write-AlertMessage -tenant $($QueueItem.tenant) -message "Error occurred: $(Get-NormalizedError -message $_.Exception.message)" } } + } catch { + Write-AlertMessage -tenant $($QueueItem.tenant) -message "Unused Licenses Alert Error occurred: $(Get-NormalizedError -message $_.Exception.message)" + } +} From 09fee64579019bc2361026de6626105046dbd818 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Thu, 1 Feb 2024 18:06:05 +0100 Subject: [PATCH 26/50] Update selectlist ordering and add onpremimmutableid --- Modules/CIPPCore/Public/Entrypoints/Invoke-ListUsers.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListUsers.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListUsers.ps1 index 961117510a0e..50c2d13f4525 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListUsers.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListUsers.ps1 @@ -10,7 +10,7 @@ Function Invoke-ListUsers { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - $selectlist = 'id', 'accountEnabled', 'businessPhones', 'city', 'createdDateTime', 'companyName', 'country', 'department', 'displayName', 'faxNumber', 'givenName', 'isResourceAccount', 'jobTitle', 'mail', 'mailNickname', 'mobilePhone', 'onPremisesDistinguishedName', 'officeLocation', 'onPremisesLastSyncDateTime', 'otherMails', 'postalCode', 'preferredDataLocation', 'preferredLanguage', 'proxyAddresses', 'showInAddressList', 'state', 'streetAddress', 'surname', 'usageLocation', 'userPrincipalName', 'userType', 'assignedLicenses', 'onPremisesSyncEnabled', 'LicJoined', 'Aliases', 'primDomain', 'Tenant', 'CippStatus' + $selectlist = 'id', 'accountEnabled', 'displayName', 'userPrincipalName', 'userType', 'createdDateTime', 'companyName', 'country', 'department', 'businessPhones', 'city', 'faxNumber', 'givenName', 'isResourceAccount', 'jobTitle', 'mobilePhone', 'officeLocation', 'postalCode', 'preferredDataLocation', 'preferredLanguage', 'mail', 'mailNickname', 'proxyAddresses', 'Aliases', 'otherMails', 'showInAddressList', 'state', 'streetAddress', 'surname', 'usageLocation', 'LicJoined', 'assignedLicenses', 'onPremisesSyncEnabled', 'OnPremisesImmutableId', 'onPremisesDistinguishedName', 'onPremisesLastSyncDateTime', 'primDomain', 'Tenant', 'CippStatus' # Write to the Azure Functions log stream. Write-Host 'PowerShell HTTP trigger function processed a request.' $ConvertTable = Import-Csv Conversiontable.csv | Sort-Object -Property 'guid' -Unique From 7fa9f10e97208ee15fd34202675fb135eb86f372 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Thu, 1 Feb 2024 18:56:11 +0100 Subject: [PATCH 27/50] fixes userid --- .../Public/Entrypoints/Invoke-ListUserMailboxDetails.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListUserMailboxDetails.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListUserMailboxDetails.ps1 index 6a043ace73b2..22f5665696c4 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListUserMailboxDetails.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListUserMailboxDetails.ps1 @@ -94,7 +94,7 @@ Function Invoke-ListUserMailboxDetails { } $forwardingaddress = if ($MailboxDetailedRequest.ForwardingAddress) { - $MailboxDetailedRequest.ForwardingAddress + (New-GraphGetRequest -tenantid $TenantFilter -uri "https://graph.microsoft.com/beta/users/$($MailboxDetailedRequest.ForwardingAddress)").UserPrincipalName } elseif ($MailboxDetailedRequest.ForwardingSmtpAddress -and $MailboxDetailedRequest.ForwardingAddress) { $MailboxDetailedRequest.ForwardingAddress + ' ' + $MailboxDetailedRequest.ForwardingSmtpAddress } else { From 053f8d82a179b67d8525adebf1daad060e418e11 Mon Sep 17 00:00:00 2001 From: Jr7468 Date: Fri, 2 Feb 2024 17:20:45 +0000 Subject: [PATCH 28/50] Changed how copyFrom outputs --- Modules/CIPPCore/Public/Entrypoints/Invoke-AddUser.ps1 | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-AddUser.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddUser.ps1 index 119bbcd532da..8845a0a8987c 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-AddUser.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddUser.ps1 @@ -107,11 +107,17 @@ Function Invoke-AddUser { $results.Add($CopyFrom.Success -join ', ') $results.Add($CopyFrom.Error -join ', ') } + + $copyFromResults = @{ + 'Success' = $CopyFrom.Success + 'Error' = $CopyFrom.Error + } + $body = [pscustomobject] @{ 'Results' = @($results) 'Username' = $UserprincipalName 'Password' = $password - 'CopyFrom' = $CopyFrom + 'CopyFrom' = $copyFromResults } # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ From 2014f50649ebe6ae2c1888b1eb7d1d4df7f300d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Fri, 2 Feb 2024 19:28:06 +0100 Subject: [PATCH 29/50] IT WOOOOOOORKS --- .../Public/Entrypoints/Invoke-EditUser.ps1 | 73 ++++++++++++++++--- 1 file changed, 63 insertions(+), 10 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-EditUser.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-EditUser.ps1 index 774d37738762..8df8768c74be 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-EditUser.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-EditUser.ps1 @@ -15,6 +15,8 @@ Function Invoke-EditUser { $Results = [System.Collections.ArrayList]@() $licenses = ($userobj | Select-Object 'License_*').psobject.properties.value $Aliases = if ($userobj.AddedAliases) { ($userobj.AddedAliases).Split([Environment]::NewLine) } + $AddToGroups = $Request.body.AddToGroups + $RemoveFromGroups = $Request.body.RemoveFromGroups # Write to the Azure Functions log stream. Write-Host 'PowerShell HTTP trigger function processed a request.' @@ -115,23 +117,74 @@ Function Invoke-EditUser { $results.AddRange($CopyFrom) } - if ($Request.body.AddToGroups -ne '') { - $Request.body.AddToGroups | ForEach-Object { + if ($AddToGroups) { + $AddToGroups | ForEach-Object { + $GroupType = $_.value.groupType -join ',' + $GroupID = $_.value.groupid + $GroupName = $_.value.groupName + Write-Host "About to add $($UserObj.userPrincipalName) to $GroupName. Group ID is: $GroupID and type is: $GroupType" + try { - Write-Host 'Adding to groups IM IN HERE' - Write-Host $_.groupType - $UserBody = [PSCustomObject]@{ - '@odata.id' = "https://graph.microsoft.com/beta/directoryObjects/$($UserObj.Userid)" + + if ($GroupType -eq 'Distribution list' -or $GroupType -eq 'Mail-Enabled Security') { + + Write-Host 'Adding to group via Add-DistributionGroupMember ' + $Params = @{ Identity = $GroupID; Member = $UserObj.Userid; BypassSecurityGroupManagerCheck = $true } + New-ExoRequest -tenantid $Userobj.tenantid -cmdlet 'Add-DistributionGroupMember' -cmdParams $params -UseSystemMailbox $true + + } else { + + Write-Host 'Adding to group via Graph' + $UserBody = [PSCustomObject]@{ + '@odata.id' = "https://graph.microsoft.com/beta/directoryObjects/$($UserObj.Userid)" + } + $UserBodyJSON = ConvertTo-Json -Compress -Depth 10 -InputObject $UserBody + New-GraphPostRequest -uri "https://graph.microsoft.com/beta/groups/$GroupID/members/`$ref" -tenantid $Userobj.tenantid -type POST -body $UserBodyJSON -Verbose + } - $UserBodyJSON = ConvertTo-Json -Compress -Depth 10 -InputObject $UserBody - New-GraphPostRequest -uri "https://graph.microsoft.com/beta/groups/$($_.value)/members/`$ref" -tenantid $Userobj.tenantid -type POST -body $UserBodyJSON -Verbose + + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $Userobj.tenantid -message "Added $($UserObj.DisplayName) to $GroupName group" -Sev 'Info' + $null = $results.add("Success. $($UserObj.DisplayName) has been added to $GroupName") } catch { - Write-Host $_.Exception.Message + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $Userobj.tenantid -message "Failed to add member $($UserObj.DisplayName) to $GroupName. Error:$($_.Exception.Message)" -Sev 'Error' + $null = $results.add("Failed to add member $($UserObj.DisplayName) to $GroupName : $($_.Exception.Message)") } - } + } + } + + if ($RemoveFromGroups) { + $RemoveFromGroups | ForEach-Object { + + $GroupType = $_.value.groupType -join ',' + $GroupID = $_.value.groupid + $GroupName = $_.value.groupName + Write-Host "About to remove $($UserObj.userPrincipalName) from $GroupName. Group ID is: $GroupID and type is: $GroupType" + try { + + if ($GroupType -eq 'Distribution list' -or $GroupType -eq 'Mail-Enabled Security') { + + Write-Host 'Removing From group via Remove-DistributionGroupMember ' + $Params = @{ Identity = $GroupID; Member = $UserObj.Userid; BypassSecurityGroupManagerCheck = $true } + New-ExoRequest -tenantid $Userobj.tenantid -cmdlet 'Remove-DistributionGroupMember' -cmdParams $params -UseSystemMailbox $true + + } else { + + Write-Host 'Removing From group via Graph' + New-GraphPostRequest -uri "https://graph.microsoft.com/beta/groups/$GroupID/members/$($UserObj.Userid)/`$ref" -tenantid $Userobj.tenantid -type DELETE + + } + + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $Userobj.tenantid -message "Removed $($UserObj.DisplayName) from $GroupName group" -Sev 'Info' + $null = $results.add("Success. $($UserObj.DisplayName) has been removed from $GroupName") + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $Userobj.tenantid -message "Failed to remove member $($UserObj.DisplayName) from $GroupName. Error:$($_.Exception.Message)" -Sev 'Error' + $null = $results.add("Failed to remove member $($UserObj.DisplayName) from $GroupName : $($_.Exception.Message)") + } + + } } $body = @{'Results' = @($results) } From 0c5588cfcc0bb39d91933ef634763bc0ef3267bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Fri, 2 Feb 2024 19:30:19 +0100 Subject: [PATCH 30/50] Make some calls = null to make psanalyser stop complaining --- Modules/CIPPCore/Public/Entrypoints/Invoke-EditUser.ps1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-EditUser.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-EditUser.ps1 index 8df8768c74be..e869d8829311 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-EditUser.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-EditUser.ps1 @@ -57,12 +57,12 @@ Function Invoke-EditUser { } } $bodyToShip = ConvertTo-Json -Depth 10 -InputObject $BodyToship -Compress - $GraphRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($userobj.Userid)" -tenantid $Userobj.tenantid -type PATCH -body $BodyToship -verbose + $null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($userobj.Userid)" -tenantid $Userobj.tenantid -type PATCH -body $BodyToship -verbose $results.add( 'Success. The user has been edited.' ) Write-LogMessage -API $APINAME -tenant ($UserObj.tenantid) -user $request.headers.'x-ms-client-principal' -message "Edited user $($userobj.displayname) with id $($userobj.Userid)" -Sev 'Info' if ($userobj.password) { $passwordProfile = [pscustomobject]@{'passwordProfile' = @{ 'password' = $userobj.password; 'forceChangePasswordNextSignIn' = [boolean]$UserObj.mustchangepass } } | ConvertTo-Json - $GraphRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($userobj.Userid)" -tenantid $Userobj.tenantid -type PATCH -body $PasswordProfile -verbose + $null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($userobj.Userid)" -tenantid $Userobj.tenantid -type PATCH -body $PasswordProfile -verbose $results.add("Success. The password has been set to $($userobj.password)") Write-LogMessage -API $APINAME -tenant ($UserObj.tenantid) -user $request.headers.'x-ms-client-principal' -message "Reset $($userobj.displayname)'s Password" -Sev 'Info' } @@ -85,7 +85,7 @@ Function Invoke-EditUser { $LicenseBody = '{"addLicenses": [' + $LicList + '], "removeLicenses": ' + $LicensesToRemove + '}' if ($userobj.RemoveAllLicenses) { $LicenseBody = '{"addLicenses": [], "removeLicenses": ' + $LicensesToRemove + '}' } Write-Host $LicenseBody - $LicRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($userobj.Userid)/assignlicense" -tenantid $Userobj.tenantid -type POST -body $LicenseBody -verbose + $null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($userobj.Userid)/assignlicense" -tenantid $Userobj.tenantid -type POST -body $LicenseBody -verbose Write-LogMessage -API $APINAME -tenant ($UserObj.tenantid) -user $request.headers.'x-ms-client-principal' -message "Changed user $($userobj.displayname) license. Sent info: $licensebody" -Sev 'Info' $results.add( 'Success. User license has been edited.' ) From a0adfede3ee951b182c9c09da762b68770f9b38e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Fri, 2 Feb 2024 20:28:57 +0100 Subject: [PATCH 31/50] Fix buttons not being able add to M365 groups sometimes --- .../Public/Entrypoints/Invoke-EditGroup.ps1 | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-EditGroup.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-EditGroup.ps1 index 7e002adccdfe..135ddf5a44ba 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-EditGroup.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-EditGroup.ps1 @@ -13,6 +13,7 @@ Function Invoke-EditGroup { $Results = [System.Collections.ArrayList]@() $userobj = $Request.body + $GroupType = $userobj.groupType -join ',' # Write to the Azure Functions log stream. Write-Host 'PowerShell HTTP trigger function processed a request.' @@ -22,20 +23,21 @@ Function Invoke-EditGroup { $AddMembers | ForEach-Object { try { $member = $_ + if ($member -like '*#EXT#*') { $member = [System.Web.HttpUtility]::UrlEncode($member) } $MemberIDs = 'https://graph.microsoft.com/v1.0/directoryObjects/' + (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($member)" -tenantid $Userobj.tenantid).id $addmemberbody = "{ `"members@odata.bind`": $(ConvertTo-Json @($MemberIDs)) }" - if ($userobj.groupType -eq 'Distribution list' -or $userobj.groupType -eq 'Mail-Enabled Security') { + if ($GroupType -eq 'Distribution list' -or $GroupType -eq 'Mail-Enabled Security') { $Params = @{ Identity = $userobj.groupid; Member = $member; BypassSecurityGroupManagerCheck = $true } New-ExoRequest -tenantid $Userobj.tenantid -cmdlet 'Add-DistributionGroupMember' -cmdParams $params -UseSystemMailbox $true } else { New-GraphPostRequest -uri "https://graph.microsoft.com/beta/groups/$($userobj.groupid)" -tenantid $Userobj.tenantid -type patch -body $addmemberbody -Verbose } Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $Userobj.tenantid -message "Added $member to $($userobj.groupName) group" -Sev 'Info' - $body = $results.add("Success. $member has been added") + $null = $results.add("Success. $member has been added to $($userobj.groupName)") } catch { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $Userobj.tenantid -message "Failed to add member $member to $($userobj.groupName). Error:$($_.Exception.Message)" -Sev 'Error' - $body = $results.add("Failed to add member $member to $($userobj.groupName): $($_.Exception.Message)") + $null = $results.add("Failed to add member $member to $($userobj.groupName): $($_.Exception.Message)") } } @@ -50,13 +52,13 @@ Function Invoke-EditGroup { $Params = @{ Identity = $userobj.groupid; Member = $member; BypassSecurityGroupManagerCheck = $true } New-ExoRequest -tenantid $Userobj.tenantid -cmdlet 'Add-DistributionGroupMember' -cmdParams $params -UseSystemMailbox $true Write-LogMessage -API $APINAME -tenant $Userobj.tenantid -user $request.headers.'x-ms-client-principal' -message "Added $member to $($userobj.groupName) group" -Sev 'Info' - $body = $results.add("Success. $member has been added") + $null = $results.add("Success. $member has been added to $($userobj.groupName)") } else { Write-LogMessage -API $APINAME -tenant $Userobj.tenantid -user $request.headers.'x-ms-client-principal' -message 'You cannot add a contact to a security group' -Sev 'Error' - $body = $results.add('You cannot add a contact to a security group') + $null = $results.add('You cannot add a contact to a security group') } } catch { - $body = $results.add("Failed to add member $member to $($userobj.groupName): $($_.Exception.Message)") + $null = $results.add("Failed to add member $member to $($userobj.groupName): $($_.Exception.Message)") } } @@ -67,7 +69,7 @@ Function Invoke-EditGroup { if ($RemoveMembers) { $RemoveMembers | ForEach-Object { $member = $_ - if ($userobj.groupType -eq 'Distribution list' -or $userobj.groupType -eq 'Mail-Enabled Security') { + if ($GroupType -eq 'Distribution list' -or $GroupType -eq 'Mail-Enabled Security') { $Params = @{ Identity = $userobj.groupid; Member = $member ; BypassSecurityGroupManagerCheck = $true } New-ExoRequest -tenantid $Userobj.tenantid -cmdlet 'Remove-DistributionGroupMember' -cmdParams $params -UseSystemMailbox $true } else { @@ -75,12 +77,12 @@ Function Invoke-EditGroup { New-GraphPostRequest -uri "https://graph.microsoft.com/beta/groups/$($userobj.groupid)/members/$($MemberInfo.id)/`$ref" -tenantid $Userobj.tenantid -type DELETE } Write-LogMessage -API $APINAME -tenant $Userobj.tenantid -user $request.headers.'x-ms-client-principal' -message "Removed $member from $($userobj.groupName) group" -Sev 'Info' - $body = $results.add("Success. Member $member has been removed") + $null = $results.add("Success. Member $member has been removed from $($userobj.groupName)") } } } catch { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $Userobj.tenantid -message "Failed to remove $RemoveMembers from $($userobj.groupName). Error:$($_.Exception.Message)" -Sev 'Error' - $body = $results.add("Could not remove $RemoveMembers from $($userobj.groupName). $($_.Exception.Message)") + $null = $results.add("Could not remove $RemoveMembers from $($userobj.groupName). $($_.Exception.Message)") } $AddOwners = $userobj.Addowner.value @@ -90,11 +92,11 @@ Function Invoke-EditGroup { try { $ID = 'https://graph.microsoft.com/beta/users/' + (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($_)" -tenantid $Userobj.tenantid).id Write-Host $ID - $AddOwner = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/groups/$($userobj.groupid)/owners/`$ref" -tenantid $Userobj.tenantid -type POST -body ('{"@odata.id": "' + $ID + '"}') + $null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/groups/$($userobj.groupid)/owners/`$ref" -tenantid $Userobj.tenantid -type POST -body ('{"@odata.id": "' + $ID + '"}') Write-LogMessage -API $APINAME -tenant $Userobj.tenantid -user $request.headers.'x-ms-client-principal' -message "Added owner $_ to $($userobj.groupName) group" -Sev 'Info' - $body = $results.add("Success. $_ has been added") + $null = $results.add("Success. $_ has been added $($userobj.groupName)") } catch { - $body = $results.add("Failed to add owner $_ to $($userobj.groupName): Error:$($_.Exception.Message)") + $null = $results.add("Failed to add owner $_ to $($userobj.groupName): Error:$($_.Exception.Message)") } } @@ -112,9 +114,9 @@ Function Invoke-EditGroup { $MemberInfo = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($_)" -tenantid $Userobj.tenantid) New-GraphPostRequest -uri "https://graph.microsoft.com/beta/groups/$($userobj.groupid)/owners/$($MemberInfo.id)/`$ref" -tenantid $Userobj.tenantid -type DELETE Write-LogMessage -API $APINAME -tenant $Userobj.tenantid -user $request.headers.'x-ms-client-principal' -message "Removed $($MemberInfo.UserPrincipalname) from $($userobj.displayname) group" -Sev 'Info' - $body = $results.add("Success. Member $_ has been removed from $($userobj.groupName)") + $null = $results.add("Success. Member $_ has been removed from $($userobj.groupName)") } catch { - $body = $results.add("Failed to remove $_ from $($userobj.groupName): $($_.Exception.Message)") + $null = $results.add("Failed to remove $_ from $($userobj.groupName): $($_.Exception.Message)") } } } From 6311d86ab70d119e8bd9dd0a01907a52dbc607b3 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Fri, 2 Feb 2024 17:15:10 -0500 Subject: [PATCH 32/50] Update DNSHealth Add Microsoft DKIM fallback for Domain Analyser and Individual Domain Check --- DomainAnalyser_All/run.ps1 | 19 +-- .../Entrypoints/Invoke-ListDomainHealth.ps1 | 3 +- .../Public/Set-CIPPCopyGroupMembers.ps1 | 8 +- Modules/DNSHealth/1.0.6/DNSHealth.psd1 | 137 ------------------ Modules/DNSHealth/1.0.7/DNSHealth.psd1 | 131 +++++++++++++++++ .../DNSHealth/{1.0.6 => 1.0.7}/DNSHealth.psm1 | 87 +++++++---- .../MailProviders/AppRiver.json | 0 .../MailProviders/BarracudaESS.json | 0 .../MailProviders/Google.json | 0 .../MailProviders/Intermedia.json | 0 .../MailProviders/Microsoft365.json | 0 .../MailProviders/Mimecast.json | 0 .../{1.0.6 => 1.0.7}/MailProviders/Null.json | 0 .../MailProviders/Proofpoint.json | 0 .../MailProviders/Reflexion.json | 0 .../MailProviders/Sophos.json | 0 .../MailProviders/SpamTitan.json | 0 .../MailProviders/_template.json | 0 .../{1.0.6 => 1.0.7}/PSGetModuleInfo.xml | 53 ++++--- 19 files changed, 230 insertions(+), 208 deletions(-) delete mode 100644 Modules/DNSHealth/1.0.6/DNSHealth.psd1 create mode 100644 Modules/DNSHealth/1.0.7/DNSHealth.psd1 rename Modules/DNSHealth/{1.0.6 => 1.0.7}/DNSHealth.psm1 (98%) rename Modules/DNSHealth/{1.0.6 => 1.0.7}/MailProviders/AppRiver.json (100%) rename Modules/DNSHealth/{1.0.6 => 1.0.7}/MailProviders/BarracudaESS.json (100%) rename Modules/DNSHealth/{1.0.6 => 1.0.7}/MailProviders/Google.json (100%) rename Modules/DNSHealth/{1.0.6 => 1.0.7}/MailProviders/Intermedia.json (100%) rename Modules/DNSHealth/{1.0.6 => 1.0.7}/MailProviders/Microsoft365.json (100%) rename Modules/DNSHealth/{1.0.6 => 1.0.7}/MailProviders/Mimecast.json (100%) rename Modules/DNSHealth/{1.0.6 => 1.0.7}/MailProviders/Null.json (100%) rename Modules/DNSHealth/{1.0.6 => 1.0.7}/MailProviders/Proofpoint.json (100%) rename Modules/DNSHealth/{1.0.6 => 1.0.7}/MailProviders/Reflexion.json (100%) rename Modules/DNSHealth/{1.0.6 => 1.0.7}/MailProviders/Sophos.json (100%) rename Modules/DNSHealth/{1.0.6 => 1.0.7}/MailProviders/SpamTitan.json (100%) rename Modules/DNSHealth/{1.0.6 => 1.0.7}/MailProviders/_template.json (100%) rename Modules/DNSHealth/{1.0.6 => 1.0.7}/PSGetModuleInfo.xml (82%) diff --git a/DomainAnalyser_All/run.ps1 b/DomainAnalyser_All/run.ps1 index 6f11a3e4856b..81678cbe8c98 100644 --- a/DomainAnalyser_All/run.ps1 +++ b/DomainAnalyser_All/run.ps1 @@ -116,7 +116,7 @@ try { Write-LogMessage -API 'DomainAnalyser' -tenant $tenant.tenant -message $Message -sev Error throw $Message } - + # Check SPF Record $Result.SPFPassAll = $false @@ -143,13 +143,13 @@ try { $ScoreDomain += $Scores.DMARCPresent $Result.DMARCFullPolicy = $DMARCPolicy.Record - if ($DMARCPolicy.Policy -eq 'reject' -and $DMARCPolicy.SubdomainPolicy -eq 'reject') { + if ($DMARCPolicy.Policy -eq 'reject' -and $DMARCPolicy.SubdomainPolicy -eq 'reject') { $Result.DMARCActionPolicy = 'Reject' $ScoreDomain += $Scores.DMARCSetReject } - if ($DMARCPolicy.Policy -eq 'none') { + if ($DMARCPolicy.Policy -eq 'none') { $Result.DMARCActionPolicy = 'None' - $ScoreExplanation.Add('DMARC is not being enforced') | Out-Null + $ScoreExplanation.Add('DMARC is not being enforced') | Out-Null } if ($DMARCPolicy.Policy -eq 'quarantine') { $Result.DMARCActionPolicy = 'Quarantine' @@ -171,7 +171,7 @@ try { $ScoreDomain += $Scores.DMARCPercentageGood } else { $Result.DMARCPercentagePass = $false - $ScoreExplanation.Add('DMARC Not Checking All Messages') | Out-Null + $ScoreExplanation.Add('DMARC Not Checking All Messages') | Out-Null } } } catch { @@ -190,7 +190,7 @@ try { $ScoreDomain += $Scores.DNSSECPresent } else { $Result.DNSSECPresent = $false - $ScoreExplanation.Add('DNSSEC Not Configured or Enabled') | Out-Null + $ScoreExplanation.Add('DNSSEC Not Configured or Enabled') | Out-Null } } catch { $Message = 'DNSSEC Exception: {0} line {1} - {2}' -f $_.InvocationInfo.ScriptName, $_.InvocationInfo.ScriptLineNumber, $_.Exception.Message @@ -201,14 +201,15 @@ try { # DKIM Check try { $DkimParams = @{ - Domain = $Domain + Domain = $Domain + FallbackToMicrosoftSelectors = $true } if (![string]::IsNullOrEmpty($DomainObject.DkimSelectors)) { $DkimParams.Selectors = $DomainObject.DkimSelectors | ConvertFrom-Json } $DkimRecord = Read-DkimRecord @DkimParams -ErrorAction Stop - + $DkimRecordCount = $DkimRecord.Records | Measure-Object | Select-Object -ExpandProperty Count $DkimFailCount = $DkimRecord.ValidationFails | Measure-Object | Select-Object -ExpandProperty Count #$DkimWarnCount = $DkimRecord.ValidationWarns | Measure-Object | Select-Object -ExpandProperty Count @@ -217,7 +218,7 @@ try { $ScoreDomain += $Scores.DKIMActiveAndWorking } else { $Result.DKIMEnabled = $false - $ScoreExplanation.Add('DKIM Not Configured') | Out-Null + $ScoreExplanation.Add('DKIM Not Configured') | Out-Null } } catch { $Message = 'DKIM Exception: {0} line {1} - {2}' -f $_.InvocationInfo.ScriptName, $_.InvocationInfo.ScriptLineNumber, $_.Exception.Message diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDomainHealth.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDomainHealth.ps1 index 6d2d1d1106ef..dfbd46514448 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDomainHealth.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDomainHealth.ps1 @@ -75,7 +75,8 @@ Function Invoke-ListDomainHealth { } 'ReadDkimRecord' { $DkimQuery = @{ - Domain = $Request.Query.Domain + Domain = $Request.Query.Domain + FallbackToMicrosoftSelectors = $true } if ($Request.Query.Selector) { $DkimQuery.Selectors = ($Request.Query.Selector).trim() -split '\s*,\s*' diff --git a/Modules/CIPPCore/Public/Set-CIPPCopyGroupMembers.ps1 b/Modules/CIPPCore/Public/Set-CIPPCopyGroupMembers.ps1 index 098c0fc41b94..cfd851f589eb 100644 --- a/Modules/CIPPCore/Public/Set-CIPPCopyGroupMembers.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPCopyGroupMembers.ps1 @@ -5,17 +5,17 @@ function Set-CIPPCopyGroupMembers( [string]$TenantFilter, [string]$APIName = "Copy User Groups" ) { - $MemberIDs = "https://graph.microsoft.com/v1.0/directoryObjects/" + (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$UserId" -tenantid $TenantFilter).id + $MemberIDs = "https://graph.microsoft.com/v1.0/directoryObjects/" + (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$UserId" -tenantid $TenantFilter).id $AddMemberBody = "{ `"members@odata.bind`": $(ConvertTo-Json @($MemberIDs)) }" - + $Success = New-Object System.Collections.ArrayList $Errors = New-Object System.Collections.ArrayList - (New-GraphGETRequest -uri "https://graph.microsoft.com/beta/users/$CopyFromId/memberOf" -tenantid $TenantFilter) | Where-Object { $_.GroupTypes -notin "DynamicMemberShip" } | ForEach-Object { + (New-GraphGETRequest -uri "https://graph.microsoft.com/beta/users/$CopyFromId/memberOf" -tenantid $TenantFilter) | Where-Object { $_.GroupTypes -notin "herohero" } | ForEach-Object { try { $MailGroup = $_ if ($MailGroup.MailEnabled -and $Mailgroup.ResourceProvisioningOptions -notin "Team") { $Params = @{ Identity = $MailGroup.mail; Member = $UserId; BypassSecurityGroupManagerCheck = $true } - New-ExoRequest -tenantid $TenantFilter -cmdlet "Add-DistributionGroupMember" -cmdParams $params -UseSystemMailbox $true + New-ExoRequest -tenantid $TenantFilter -cmdlet "Add-DistributionGroupMember" -cmdParams $params -UseSystemMailbox $true } else { $GroupResult = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/groups/$($_.id)" -tenantid $TenantFilter -type patch -body $AddMemberBody -Verbose diff --git a/Modules/DNSHealth/1.0.6/DNSHealth.psd1 b/Modules/DNSHealth/1.0.6/DNSHealth.psd1 deleted file mode 100644 index 257d08264fb1..000000000000 --- a/Modules/DNSHealth/1.0.6/DNSHealth.psd1 +++ /dev/null @@ -1,137 +0,0 @@ -# -# Module manifest for module 'DNSHealth' -# -# Generated by: John Duprey -# -# Generated on: 06/15/2023 -# - -@{ - -# Script module or binary module file associated with this manifest. -RootModule = 'DNSHealth.psm1' - -# Version number of this module. -ModuleVersion = '1.0.6' - -# Supported PSEditions -# CompatiblePSEditions = @() - -# ID used to uniquely identify this module -GUID = 'a300d2b0-d468-46d1-88a3-e442a76b655b' - -# Author of this module -Author = 'John Duprey' - -# Company or vendor of this module -CompanyName = 'Unknown' - -# Copyright statement for this module -Copyright = '2023 John Duprey' - -# Description of the functionality provided by this module -Description = 'CIPP DNS Health Check Module' - -# Minimum version of the PowerShell engine required by this module -PowerShellVersion = '7.0' - -# Name of the PowerShell host required by this module -# PowerShellHostName = '' - -# Minimum version of the PowerShell host required by this module -# PowerShellHostVersion = '' - -# Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only. -# DotNetFrameworkVersion = '' - -# Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only. -# ClrVersion = '' - -# Processor architecture (None, X86, Amd64) required by this module -# ProcessorArchitecture = '' - -# Modules that must be imported into the global environment prior to importing this module -# RequiredModules = @() - -# Assemblies that must be loaded prior to importing this module -# RequiredAssemblies = @() - -# Script files (.ps1) that are run in the caller's environment prior to importing this module. -ScriptsToProcess = @() - -# Type files (.ps1xml) to be loaded when importing this module -# TypesToProcess = @() - -# Format files (.ps1xml) to be loaded when importing this module -# FormatsToProcess = @() - -# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess -# NestedModules = @() - -# Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. -FunctionsToExport = 'Read-DmarcPolicy', 'Read-MtaStsPolicy', 'Read-DkimRecord', - 'Read-MtaStsRecord', 'Read-MXRecord', 'Read-NSRecord', 'Read-SPFRecord', - 'Read-TlsRptRecord', 'Read-WhoisRecord', 'Resolve-DnsHttpsQuery', - 'Set-DnsResolver', 'Test-DNSSEC', 'Test-HttpsCertificate', - 'Test-MtaSts' - -# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. -CmdletsToExport = '*' - -# Variables to export from this module -VariablesToExport = '*' - -# Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export. -AliasesToExport = '*' - -# DSC resources to export from this module -# DscResourcesToExport = @() - -# List of all modules packaged with this module -# ModuleList = @() - -# List of all files packaged with this module -# FileList = @() - -# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. -PrivateData = @{ - - PSData = @{ - - # Tags applied to this module. These help with module discovery in online galleries. - # Tags = @() - - # A URL to the license for this module. - # LicenseUri = '' - - # A URL to the main website for this project. - ProjectUri = 'https://github.com/johnduprey/DNSHealth' - - # A URL to an icon representing this module. - # IconUri = '' - - # ReleaseNotes of this module - # ReleaseNotes = '' - - # Prerelease string of this module - # Prerelease = '' - - # Flag to indicate whether the module requires explicit user acceptance for install/update/save - # RequireLicenseAcceptance = $false - - # External dependent modules of this module - # ExternalModuleDependencies = @() - - } # End of PSData hashtable - - -} # End of PrivateData hashtable - -# HelpInfo URI of this module -# HelpInfoURI = '' - -# Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. -# DefaultCommandPrefix = '' - -} - diff --git a/Modules/DNSHealth/1.0.7/DNSHealth.psd1 b/Modules/DNSHealth/1.0.7/DNSHealth.psd1 new file mode 100644 index 000000000000..56383a3e37f3 --- /dev/null +++ b/Modules/DNSHealth/1.0.7/DNSHealth.psd1 @@ -0,0 +1,131 @@ +# +# Module manifest for module 'DNSHealth' +# +# Generated by: John Duprey +# +# Generated on: 2023-02-03 +# + +@{ + + # Script module or binary module file associated with this manifest. + RootModule = 'DNSHealth.psm1' + + # Version number of this module. + ModuleVersion = '1.0.7' + + # Supported PSEditions + # CompatiblePSEditions = @() + + # ID used to uniquely identify this module + GUID = 'a300d2b0-d468-46d1-88a3-e442a76b655b' + + # Author of this module + Author = 'John Duprey' + + # Company or vendor of this module + CompanyName = '' + + # Copyright statement for this module + Copyright = '2023 John Duprey' + + # Description of the functionality provided by this module + Description = 'CIPP DNS Health Check Module' + + # Minimum version of the PowerShell engine required by this module + PowerShellVersion = '7.0' + + # Name of the PowerShell host required by this module + # PowerShellHostName = '' + + # Minimum version of the PowerShell host required by this module + # PowerShellHostVersion = '' + + # Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only. + # DotNetFrameworkVersion = '' + + # Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only. + # ClrVersion = '' + + # Processor architecture (None, X86, Amd64) required by this module + # ProcessorArchitecture = '' + + # Modules that must be imported into the global environment prior to importing this module + #RequiredModules = @('') + + # Assemblies that must be loaded prior to importing this module + # RequiredAssemblies = @() + + # Script files (.ps1) that are run in the caller's environment prior to importing this module. + ScriptsToProcess = @() + + # Type files (.ps1xml) to be loaded when importing this module + # TypesToProcess = @() + + # Format files (.ps1xml) to be loaded when importing this module + # FormatsToProcess = @() + + # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess + # NestedModules = @() + + # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. + FunctionsToExport = @('Read-DmarcPolicy','Read-MtaStsPolicy','Read-DkimRecord','Read-MtaStsRecord','Read-MXRecord','Read-NSRecord','Read-SPFRecord','Read-TlsRptRecord','Read-WhoisRecord','Resolve-DnsHttpsQuery','Set-DnsResolver','Test-DNSSEC','Test-HttpsCertificate','Test-MtaSts') + + # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. + #CmdletsToExport = '*' + + # Variables to export from this module + #VariablesToExport = '*' + + # Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export. + #AliasesToExport = '*' + + # DSC resources to export from this module + # DscResourcesToExport = @() + + # List of all modules packaged with this module + # ModuleList = @() + + # List of all files packaged with this module + # FileList = @() + + # Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. + PrivateData = @{ + + PSData = @{ + + # Tags applied to this module. These help with module discovery in online galleries. + # Tags = @() + + # A URL to the license for this module. + # LicenseUri = '' + + # A URL to the main website for this project. + ProjectUri = 'https://github.com/johnduprey/DNSHealth' + + # A URL to an icon representing this module. + # IconUri = '' + + # ReleaseNotes of this module + # ReleaseNotes = '' + + # Prerelease string of this module + # Prerelease = '' + + # Flag to indicate whether the module requires explicit user acceptance for install/update/save + # RequireLicenseAcceptance = $false + + # External dependent modules of this module + #ExternalModuleDependencies = @() + + } # End of PSData hashtable + + } # End of PrivateData hashtable + + # HelpInfo URI of this module + # HelpInfoURI = '' + + # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. + #DefaultCommandPrefix = '' + +} diff --git a/Modules/DNSHealth/1.0.6/DNSHealth.psm1 b/Modules/DNSHealth/1.0.7/DNSHealth.psm1 similarity index 98% rename from Modules/DNSHealth/1.0.6/DNSHealth.psm1 rename to Modules/DNSHealth/1.0.7/DNSHealth.psm1 index 253a66b1d0be..b69e40274c16 100644 --- a/Modules/DNSHealth/1.0.6/DNSHealth.psm1 +++ b/Modules/DNSHealth/1.0.7/DNSHealth.psm1 @@ -1,4 +1,5 @@ -#Region './Private/Get-DomainMacros.ps1' 0 +#Region './Private/Get-DomainMacros.ps1' -1 + function Get-DomainMacros { [CmdletBinding()] Param( @@ -25,7 +26,8 @@ function Get-DomainMacros { $MacroExpand } #EndRegion './Private/Get-DomainMacros.ps1' 26 -#Region './Private/Get-RsaPublicKeyInfo.ps1' 0 +#Region './Private/Get-RsaPublicKeyInfo.ps1' -1 + function Get-RsaPublicKeyInfo { <# .SYNOPSIS @@ -192,7 +194,8 @@ namespace SevenTiny.Bantina.Security { [SevenTiny.Bantina.Security.RSACommon]::CreateRsaProviderFromPublicKey($EncodedString) } #EndRegion './Private/Get-RsaPublicKeyInfo.ps1' 166 -#Region './Private/Get-ServerCertificateValidation.ps1' 0 +#Region './Private/Get-ServerCertificateValidation.ps1' -1 + function Get-ServerCertificateValidation { <# .SYNOPSIS @@ -274,7 +277,8 @@ namespace CyberDrain.CIPP { [CyberDrain.CIPP.CertificateCheck]::GetServerCertificate($Url, $FollowRedirect) } #EndRegion './Private/Get-ServerCertificateValidation.ps1' 81 -#Region './Public/Policies/Read-DmarcPolicy.ps1' 0 +#Region './Public/Policies/Read-DmarcPolicy.ps1' -1 + function Read-DmarcPolicy { <# .SYNOPSIS @@ -549,7 +553,8 @@ function Read-DmarcPolicy { $DmarcAnalysis } #EndRegion './Public/Policies/Read-DmarcPolicy.ps1' 274 -#Region './Public/Policies/Read-MtaStsPolicy.ps1' 0 +#Region './Public/Policies/Read-MtaStsPolicy.ps1' -1 + function Read-MtaStsPolicy { <# .SYNOPSIS @@ -676,7 +681,8 @@ function Read-MtaStsPolicy { $StsPolicyAnalysis } #EndRegion './Public/Policies/Read-MtaStsPolicy.ps1' 126 -#Region './Public/Records/Read-DkimRecord.ps1' 0 +#Region './Public/Records/Read-DkimRecord.ps1' -1 + function Read-DkimRecord { <# .SYNOPSIS @@ -704,7 +710,10 @@ function Read-DkimRecord { [string]$Domain, [Parameter()] - [System.Collections.Generic.List[string]]$Selectors = @() + [System.Collections.Generic.List[string]]$Selectors = @(), + + [Parameter()] + [switch]$FallbackToMicrosoftSelectors ) $MXRecord = $null @@ -728,21 +737,28 @@ function Read-DkimRecord { # MX lookup, check for defined selectors try { $MXRecord = Read-MXRecord -Domain $Domain - foreach ($Selector in $MXRecord.Selectors) { - try { - $Selectors.Add($Selector) | Out-Null + if ($MXRecord.Selectors) { + foreach ($Selector in $MXRecord.Selectors) { + try { + $Selectors.Add($Selector) | Out-Null + } catch { Write-Verbose $_.Exception.Message } } - - catch { Write-Verbose $_.Exception.Message } } - $DkimAnalysis.MailProvider = $MXRecord.MailProvider - if ($MXRecord.MailProvider.PSObject.Properties.Name -contains 'MinimumSelectorPass') { - $MinimumSelectorPass = $MXRecord.MailProvider.MinimumSelectorPass + if ($MXRecord.MailProvider) { + $DkimAnalysis.MailProvider = $MXRecord.MailProvider + if ($MXRecord.MailProvider.PSObject.Properties.Name -contains 'MinimumSelectorPass') { + $MinimumSelectorPass = $MXRecord.MailProvider.MinimumSelectorPass + } + $DkimAnalysis.Selectors = $Selectors } - $DkimAnalysis.Selectors = $Selectors - } + } catch { Write-Verbose $_.Exception.Message } - catch { Write-Verbose $_.Exception.Message } + # Fallback to Microsoft DKIM selectors + if ($FallbackToMicrosoftSelectors.IsPresent -and ($Selectors | Measure-Object | Select-Object -ExpandProperty Count) -eq 0) { + $MinimumSelectorPass = 1 + $Selectors.Add('selector1') + $Selectors.Add('selector2') + } # Get unique selectors $Selectors = $Selectors | Sort-Object -Unique @@ -936,8 +952,9 @@ function Read-DkimRecord { # Return analysis $DkimAnalysis } -#EndRegion './Public/Records/Read-DkimRecord.ps1' 260 -#Region './Public/Records/Read-MtaStsRecord.ps1' 0 +#EndRegion './Public/Records/Read-DkimRecord.ps1' 270 +#Region './Public/Records/Read-MtaStsRecord.ps1' -1 + function Read-MtaStsRecord { <# .SYNOPSIS @@ -1074,7 +1091,8 @@ function Read-MtaStsRecord { $StsAnalysis } #EndRegion './Public/Records/Read-MtaStsRecord.ps1' 136 -#Region './Public/Records/Read-MXRecord.ps1' 0 +#Region './Public/Records/Read-MXRecord.ps1' -1 + function Read-MXRecord { <# .SYNOPSIS @@ -1228,7 +1246,8 @@ function Read-MXRecord { $MXResults } #EndRegion './Public/Records/Read-MXRecord.ps1' 153 -#Region './Public/Records/Read-NSRecord.ps1' 0 +#Region './Public/Records/Read-NSRecord.ps1' -1 + function Read-NSRecord { <# .SYNOPSIS @@ -1292,7 +1311,8 @@ function Read-NSRecord { $NSResults } #EndRegion './Public/Records/Read-NSRecord.ps1' 63 -#Region './Public/Records/Read-SPFRecord.ps1' 0 +#Region './Public/Records/Read-SPFRecord.ps1' -1 + function Read-SpfRecord { <# .SYNOPSIS @@ -1846,7 +1866,8 @@ function Read-SpfRecord { $SpfResults } #EndRegion './Public/Records/Read-SPFRecord.ps1' 553 -#Region './Public/Records/Read-TlsRptRecord.ps1' 0 +#Region './Public/Records/Read-TlsRptRecord.ps1' -1 + function Read-TlsRptRecord { <# .SYNOPSIS @@ -1998,7 +2019,8 @@ function Read-TlsRptRecord { $TlsRptAnalysis } #EndRegion './Public/Records/Read-TlsRptRecord.ps1' 151 -#Region './Public/Records/Read-WhoisRecord.ps1' 0 +#Region './Public/Records/Read-WhoisRecord.ps1' -1 + function Read-WhoisRecord { <# .SYNOPSIS @@ -2174,7 +2196,8 @@ function Read-WhoisRecord { $WhoisResults } #EndRegion './Public/Records/Read-WhoisRecord.ps1' 175 -#Region './Public/Resolver/Resolve-DnsHttpsQuery.ps1' 0 +#Region './Public/Resolver/Resolve-DnsHttpsQuery.ps1' -1 + function Resolve-DnsHttpsQuery { <# .SYNOPSIS @@ -2253,7 +2276,8 @@ function Resolve-DnsHttpsQuery { return $Results } #EndRegion './Public/Resolver/Resolve-DnsHttpsQuery.ps1' 78 -#Region './Public/Resolver/Set-DnsResolver.ps1' 0 +#Region './Public/Resolver/Set-DnsResolver.ps1' -1 + function Set-DnsResolver { [CmdletBinding(SupportsShouldProcess)] Param( @@ -2289,7 +2313,8 @@ function Set-DnsResolver { } } #EndRegion './Public/Resolver/Set-DnsResolver.ps1' 35 -#Region './Public/Tests/Test-DNSSEC.ps1' 0 +#Region './Public/Tests/Test-DNSSEC.ps1' -1 + function Test-DNSSEC { <# .SYNOPSIS @@ -2368,7 +2393,8 @@ function Test-DNSSEC { $DSResults } #EndRegion './Public/Tests/Test-DNSSEC.ps1' 78 -#Region './Public/Tests/Test-HttpsCertificate.ps1' 0 +#Region './Public/Tests/Test-HttpsCertificate.ps1' -1 + function Test-HttpsCertificate { <# .SYNOPSIS @@ -2529,7 +2555,8 @@ function Test-HttpsCertificate { $CertificateTests } #EndRegion './Public/Tests/Test-HttpsCertificate.ps1' 160 -#Region './Public/Tests/Test-MtaSts.ps1' 0 +#Region './Public/Tests/Test-MtaSts.ps1' -1 + function Test-MtaSts { <# .SYNOPSIS diff --git a/Modules/DNSHealth/1.0.6/MailProviders/AppRiver.json b/Modules/DNSHealth/1.0.7/MailProviders/AppRiver.json similarity index 100% rename from Modules/DNSHealth/1.0.6/MailProviders/AppRiver.json rename to Modules/DNSHealth/1.0.7/MailProviders/AppRiver.json diff --git a/Modules/DNSHealth/1.0.6/MailProviders/BarracudaESS.json b/Modules/DNSHealth/1.0.7/MailProviders/BarracudaESS.json similarity index 100% rename from Modules/DNSHealth/1.0.6/MailProviders/BarracudaESS.json rename to Modules/DNSHealth/1.0.7/MailProviders/BarracudaESS.json diff --git a/Modules/DNSHealth/1.0.6/MailProviders/Google.json b/Modules/DNSHealth/1.0.7/MailProviders/Google.json similarity index 100% rename from Modules/DNSHealth/1.0.6/MailProviders/Google.json rename to Modules/DNSHealth/1.0.7/MailProviders/Google.json diff --git a/Modules/DNSHealth/1.0.6/MailProviders/Intermedia.json b/Modules/DNSHealth/1.0.7/MailProviders/Intermedia.json similarity index 100% rename from Modules/DNSHealth/1.0.6/MailProviders/Intermedia.json rename to Modules/DNSHealth/1.0.7/MailProviders/Intermedia.json diff --git a/Modules/DNSHealth/1.0.6/MailProviders/Microsoft365.json b/Modules/DNSHealth/1.0.7/MailProviders/Microsoft365.json similarity index 100% rename from Modules/DNSHealth/1.0.6/MailProviders/Microsoft365.json rename to Modules/DNSHealth/1.0.7/MailProviders/Microsoft365.json diff --git a/Modules/DNSHealth/1.0.6/MailProviders/Mimecast.json b/Modules/DNSHealth/1.0.7/MailProviders/Mimecast.json similarity index 100% rename from Modules/DNSHealth/1.0.6/MailProviders/Mimecast.json rename to Modules/DNSHealth/1.0.7/MailProviders/Mimecast.json diff --git a/Modules/DNSHealth/1.0.6/MailProviders/Null.json b/Modules/DNSHealth/1.0.7/MailProviders/Null.json similarity index 100% rename from Modules/DNSHealth/1.0.6/MailProviders/Null.json rename to Modules/DNSHealth/1.0.7/MailProviders/Null.json diff --git a/Modules/DNSHealth/1.0.6/MailProviders/Proofpoint.json b/Modules/DNSHealth/1.0.7/MailProviders/Proofpoint.json similarity index 100% rename from Modules/DNSHealth/1.0.6/MailProviders/Proofpoint.json rename to Modules/DNSHealth/1.0.7/MailProviders/Proofpoint.json diff --git a/Modules/DNSHealth/1.0.6/MailProviders/Reflexion.json b/Modules/DNSHealth/1.0.7/MailProviders/Reflexion.json similarity index 100% rename from Modules/DNSHealth/1.0.6/MailProviders/Reflexion.json rename to Modules/DNSHealth/1.0.7/MailProviders/Reflexion.json diff --git a/Modules/DNSHealth/1.0.6/MailProviders/Sophos.json b/Modules/DNSHealth/1.0.7/MailProviders/Sophos.json similarity index 100% rename from Modules/DNSHealth/1.0.6/MailProviders/Sophos.json rename to Modules/DNSHealth/1.0.7/MailProviders/Sophos.json diff --git a/Modules/DNSHealth/1.0.6/MailProviders/SpamTitan.json b/Modules/DNSHealth/1.0.7/MailProviders/SpamTitan.json similarity index 100% rename from Modules/DNSHealth/1.0.6/MailProviders/SpamTitan.json rename to Modules/DNSHealth/1.0.7/MailProviders/SpamTitan.json diff --git a/Modules/DNSHealth/1.0.6/MailProviders/_template.json b/Modules/DNSHealth/1.0.7/MailProviders/_template.json similarity index 100% rename from Modules/DNSHealth/1.0.6/MailProviders/_template.json rename to Modules/DNSHealth/1.0.7/MailProviders/_template.json diff --git a/Modules/DNSHealth/1.0.6/PSGetModuleInfo.xml b/Modules/DNSHealth/1.0.7/PSGetModuleInfo.xml similarity index 82% rename from Modules/DNSHealth/1.0.6/PSGetModuleInfo.xml rename to Modules/DNSHealth/1.0.7/PSGetModuleInfo.xml index 3ef782dbd75c..baad9e9643b8 100644 --- a/Modules/DNSHealth/1.0.6/PSGetModuleInfo.xml +++ b/Modules/DNSHealth/1.0.7/PSGetModuleInfo.xml @@ -7,13 +7,13 @@ DNSHealth - 1.0.6 + 1.0.7 Module CIPP DNS Health Check Module John Duprey johnduprey 2023 John Duprey -
2023-06-15T12:02:08-04:00
+
2024-02-02T21:41:51-05:00
@@ -36,7 +36,7 @@ - Function + Command @@ -58,8 +58,15 @@ - Command + Cmdlet + + + + + + Function + Read-DmarcPolicy @@ -80,23 +87,16 @@ - Workflow - - - - - - - RoleCapability - + DscResource + - Cmdlet - + Workflow + - DscResource - + RoleCapability + @@ -121,25 +121,24 @@ True True 0 - 39 - 27746 - 6/15/2023 12:02:08 PM -04:00 - 6/15/2023 12:02:08 PM -04:00 - 6/15/2023 12:02:08 PM -04:00 + 78 + 27851 + 2/2/2024 9:41:51 PM -05:00 + 2/2/2024 9:41:51 PM -05:00 + 2/2/2024 9:41:51 PM -05:00 PSModule PSFunction_Read-DmarcPolicy PSCommand_Read-DmarcPolicy PSFunction_Read-MtaStsPolicy PSCommand_Read-MtaStsPolicy PSFunction_Read-DkimRecord PSCommand_Read-DkimRecord PSFunction_Read-MtaStsRecord PSCommand_Read-MtaStsRecord PSFunction_Read-MXRecord PSCommand_Read-MXRecord PSFunction_Read-NSRecord PSCommand_Read-NSRecord PSFunction_Read-SPFRecord PSCommand_Read-SPFRecord PSFunction_Read-TlsRptRecord PSCommand_Read-TlsRptRecord PSFunction_Read-WhoisRecord PSCommand_Read-WhoisRecord PSFunction_Resolve-DnsHttpsQuery PSCommand_Resolve-DnsHttpsQuery PSFunction_Set-DnsResolver PSCommand_Set-DnsResolver PSFunction_Test-DNSSEC PSCommand_Test-DNSSEC PSFunction_Test-HttpsCertificate PSCommand_Test-HttpsCertificate PSFunction_Test-MtaSts PSCommand_Test-MtaSts PSIncludes_Function False - 2023-06-15T12:02:08Z - 1.0.6 + 2024-02-02T21:41:51Z + 1.0.7 John Duprey false Module - DNSHealth.nuspec|MailProviders\SpamTitan.json|DNSHealth.psd1|MailProviders\Null.json|DNSHealth.psm1|MailProviders\BarracudaESS.json|MailProviders\Microsoft365.json|MailProviders\AppRiver.json|MailProviders\Google.json|MailProviders\Sophos.json|MailProviders\_template.json|MailProviders\Reflexion.json|MailProviders\Intermedia.json|MailProviders\Proofpoint.json|MailProviders\Mimecast.json + DNSHealth.nuspec|MailProviders\BarracudaESS.json|MailProviders\Reflexion.json|MailProviders\Null.json|MailProviders\SpamTitan.json|DNSHealth.psd1|MailProviders\Microsoft365.json|MailProviders\Sophos.json|MailProviders\Proofpoint.json|DNSHealth.psm1|MailProviders\_template.json|MailProviders\Google.json|MailProviders\Intermedia.json|MailProviders\AppRiver.json|MailProviders\Mimecast.json a300d2b0-d468-46d1-88a3-e442a76b655b 7.0 - Unknown
- C:\Users\JDDoS\Documents\GitHub\CIPP-API\Modules\DNSHealth\1.0.6 + C:\GitHub\CIPP Workspace\CIPP-API\Modules\DNSHealth\1.0.7 From 8f860c229d4de4b1522e87b54cce7e58a75269a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Sat, 3 Feb 2024 13:24:53 +0100 Subject: [PATCH 33/50] Exclude guests, add count of users in alert and add select statement --- .../Public/Entrypoints/Push-CIPPAlertMFAAlertUsers.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertMFAAlertUsers.ps1 b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertMFAAlertUsers.ps1 index 2537b9a30a38..3537616d02ed 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertMFAAlertUsers.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertMFAAlertUsers.ps1 @@ -7,9 +7,9 @@ function Push-CIPPAlertMFAAlertUsers { ) try { - $users = New-GraphGETRequest -uri 'https://graph.microsoft.com/beta/reports/authenticationMethods/userRegistrationDetails?$filter=isMfaRegistered eq false' -tenantid $($QueueItem.tenant) + $users = New-GraphGETRequest -uri 'https://graph.microsoft.com/beta/reports/authenticationMethods/userRegistrationDetails?$filter=isMfaRegistered eq false and userType eq ''member''&$select=userPrincipalName,lastUpdatedDateTime,isMfaRegistered' -tenantid $($QueueItem.tenant) if ($users) { - Write-AlertMessage -tenant $QueueItem.tenant -message "The following users do not have MFA registered: $($users.UserPrincipalName -join ', ')" + Write-AlertMessage -tenant $QueueItem.tenant -message "The following $($users.Count) users do not have MFA registered: $($users.UserPrincipalName -join ', ')" } } catch { From 43ce71c2ec2ddf138792a8fdbbeac5528dc3663f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Sat, 3 Feb 2024 17:28:43 +0100 Subject: [PATCH 34/50] Add alias handling part --- .../Entrypoints/Invoke-AddSharedMailbox.ps1 | 49 +++++++++++++++---- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-AddSharedMailbox.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddSharedMailbox.ps1 index 5426ea863112..4aeb1ed59621 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-AddSharedMailbox.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddSharedMailbox.ps1 @@ -9,32 +9,61 @@ Function Invoke-AddSharedMailbox { param($Request, $TriggerMetadata) $APIName = $TriggerMetadata.FunctionName - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $User = $request.headers.'x-ms-client-principal' + Write-LogMessage -user $User -API $APINAME -message 'Accessed this API' -Sev 'Debug' + + $Results = [System.Collections.ArrayList]@() $groupobj = $Request.body + $Aliases = $groupobj.addedAliases -Split '\n' # Write to the Azure Functions log stream. Write-Host 'PowerShell HTTP trigger function processed a request.' try { - $email = "$($groupobj.username)@$($groupobj.domain)" + $Email = "$($groupobj.username)@$($groupobj.domain)" + Write-Host "Email object is: $Email" + # Write-Host 'Group object is:' + # $groupobj + Write-Host "Aliases are: $($Aliases.Count)" + $Aliases | ForEach-Object { + Write-Host "Alias: $_" + } $BodyToship = [pscustomobject] @{ 'displayName' = $groupobj.Displayname 'name' = $groupobj.username - 'primarySMTPAddress' = $email + 'primarySMTPAddress' = $Email Shared = $true - } - New-ExoRequest -tenantid $Request.body.tenantid -cmdlet 'New-Mailbox' -cmdparams $BodyToship + $AddSharedRequest = New-ExoRequest -tenantid $groupobj.tenantid -cmdlet 'New-Mailbox' -cmdparams $BodyToship + $Body = $Results.add("Successfully created shared mailbox: $Email.") + Write-LogMessage -user $User -API $APINAME -tenant $($groupobj.tenantid) -message "Created shared mailbox $($groupobj.displayname) with email $Email" -Sev 'Info' - $body = [pscustomobject]@{'Results' = 'Successfully created shared mailbox.' } - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($groupobj.tenantid) -message "Created group $($groupobj.displayname) with id $($GraphRequest.id) for " -Sev 'Info' + } catch { + Write-LogMessage -user $User -API $APINAME -tenant $($groupobj.tenantid) -message "Failed to create shared mailbox. Error: $($_.Exception.Message)" -Sev 'Error' + $Body = $Results.add("Failed to create Shared Mailbox. $($_.Exception.Message)") } - catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($groupobj.tenantid) -message "Group creation API failed. $($_.Exception.Message)" -Sev 'Error' - $body = [pscustomobject]@{'Results' = "Failed to create Shared Mailbox. $($_.Exception.Message)" } + try { + if ($Aliases) { + + $AliasBodyToShip = [pscustomobject] @{ + 'Identity' = $Email + 'EmailAddresses' = @{Add = $Aliases } + } + $AliasBodyToShip + New-ExoRequest -tenantid $groupobj.tenantid -cmdlet 'Set-Mailbox' -cmdparams $AliasBodyToShip + Write-LogMessage -user $User -API $APINAME -tenant $($groupobj.tenantid) -message "Added aliases to $Email : $($Aliases -join ',')" -Sev 'Info' + $Body = $results.add("Added Aliases to $Email : $($Aliases -join ',')") + } + } catch { + Write-LogMessage -user $User -API $APINAME -tenant $($groupobj.tenantid) -message "Failed to add aliases to $Email : $($_.Exception.Message)" -Sev 'Error' + $Body = $results.add("Failed to add aliases to $Email : $($_.Exception.Message)") + } + + $Body = [pscustomobject] @{ + 'Results' = @($results) } # Associate values to output bindings by calling 'Push-OutputBinding'. From 77f22f76fcc017cf27bf49764f7c1aba7ad15795 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Sat, 3 Feb 2024 19:06:57 +0100 Subject: [PATCH 35/50] thanks john --- .../Entrypoints/Invoke-AddSharedMailbox.ps1 | 23 ++++++------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-AddSharedMailbox.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddSharedMailbox.ps1 index 4aeb1ed59621..c3017c7cf881 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-AddSharedMailbox.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddSharedMailbox.ps1 @@ -22,13 +22,6 @@ Function Invoke-AddSharedMailbox { try { $Email = "$($groupobj.username)@$($groupobj.domain)" - Write-Host "Email object is: $Email" - # Write-Host 'Group object is:' - # $groupobj - Write-Host "Aliases are: $($Aliases.Count)" - $Aliases | ForEach-Object { - Write-Host "Alias: $_" - } $BodyToship = [pscustomobject] @{ 'displayName' = $groupobj.Displayname 'name' = $groupobj.username @@ -47,25 +40,23 @@ Function Invoke-AddSharedMailbox { try { if ($Aliases) { - + + Start-Sleep 3 # Sleep since there is apparently a race condition with the mailbox creation if we don't delay for a lil bit $AliasBodyToShip = [pscustomobject] @{ - 'Identity' = $Email - 'EmailAddresses' = @{Add = $Aliases } + 'Identity' = $AddSharedRequest.Guid + 'EmailAddresses' = @{'@odata.type' = '#Exchange.GenericHashTable'; Add = $Aliases } } $AliasBodyToShip - New-ExoRequest -tenantid $groupobj.tenantid -cmdlet 'Set-Mailbox' -cmdparams $AliasBodyToShip + New-ExoRequest -tenantid $groupobj.tenantid -cmdlet 'Set-Mailbox' -cmdparams $AliasBodyToShip -UseSystemMailbox $true Write-LogMessage -user $User -API $APINAME -tenant $($groupobj.tenantid) -message "Added aliases to $Email : $($Aliases -join ',')" -Sev 'Info' $Body = $results.add("Added Aliases to $Email : $($Aliases -join ',')") } } catch { Write-LogMessage -user $User -API $APINAME -tenant $($groupobj.tenantid) -message "Failed to add aliases to $Email : $($_.Exception.Message)" -Sev 'Error' - $Body = $results.add("Failed to add aliases to $Email : $($_.Exception.Message)") - } - - $Body = [pscustomobject] @{ - 'Results' = @($results) + $Body = $results.add("ERROR: Failed to add aliases to $Email : $($_.Exception.Message)") } + $Body = [pscustomobject] @{ 'Results' = @($results) } # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK From cff3a4038541d626549f0fc6187a62ba19dc7bf7 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Sat, 3 Feb 2024 19:33:56 -0500 Subject: [PATCH 36/50] Fix mailbox rules --- ListMailboxRulesAllTenants/run.ps1 | 60 +++++++++++-------- .../Entrypoints/Invoke-ListMailboxRules.ps1 | 22 +++---- 2 files changed, 42 insertions(+), 40 deletions(-) diff --git a/ListMailboxRulesAllTenants/run.ps1 b/ListMailboxRulesAllTenants/run.ps1 index 28782db5e6cb..36b671ad11f6 100644 --- a/ListMailboxRulesAllTenants/run.ps1 +++ b/ListMailboxRulesAllTenants/run.ps1 @@ -3,51 +3,59 @@ param([string] $QueueItem, $TriggerMetadata) # Write out the queue message and metadata to the information log. Write-Host "PowerShell queue trigger function processed work item: $QueueItem" -$Tenants = if ($QueueItem -ne "AllTenants") { + +$Tenants = if ($QueueItem -ne 'AllTenants') { [PSCustomObject]@{ defaultDomainName = $QueueItem } -} -else { +} else { Get-Tenants } -$Tenants | ForEach-Object -Parallel { +$Tenants | ForEach-Object -Parallel { $domainName = $_.defaultDomainName - Import-Module '.\Modules\CIPPcore' + Import-Module CippCore + Import-Module AzBobbyTables + $Table = Get-CIPPTable -TableName cachembxrules try { - - $Rules = New-ExoRequest -tenantid $domainName -cmdlet "Get-Mailbox" | ForEach-Object -Parallel { - New-ExoRequest -Anchor $_.UserPrincipalName -tenantid $domainName -cmdlet "Get-InboxRule" -cmdParams @{Mailbox = $_.GUID } + $Rules = New-ExoRequest -tenantid $domainName -cmdlet 'Get-Mailbox' -Select 'userPrincipalName,GUID' | ForEach-Object -Parallel { + Import-Module CippCore + $MbxRules = New-ExoRequest -Anchor $_.UserPrincipalName -tenantid $using:domainName -cmdlet 'Get-InboxRule' -cmdParams @{Mailbox = $_.GUID } + foreach ($Rule in $MbxRules) { + $Rule | Add-Member -NotePropertyName 'UserPrincipalName' -NotePropertyValue $_.userPrincipalName + $Rule + } } - foreach ($Rule in $Rules) { - $GraphRequest = @{ - Rules = [string]($Rule | ConvertTo-Json) - RowKey = [string](New-Guid).guid + if (($Rules | Measure-Object).Count -gt 0) { + foreach ($Rule in $Rules) { + $GraphRequest = [PSCustomObject]@{ + Rules = [string]($Rule | ConvertTo-Json) + RowKey = [string](New-Guid).guid + Tenant = [string]$domainName + PartitionKey = 'mailboxrules' + } + + } + } else { + $Rules = @{ + Name = 'No rules found' + } | ConvertTo-Json + $GraphRequest = [PSCustomObject]@{ + Rules = [string]$Rules + RowKey = [string]$domainName Tenant = [string]$domainName PartitionKey = 'mailboxrules' } - $Table = Get-CIPPTable -TableName cachembxrules - Add-CIPPAzDataTableEntity @Table -Entity $GraphRequest -Force | Out-Null } - } - catch { + } catch { $Rules = @{ Name = "Could not connect to tenant $($_.Exception.message)" } | ConvertTo-Json - $GraphRequest = @{ + $GraphRequest = [PSCustomObject]@{ Rules = [string]$Rules RowKey = [string]$domainName Tenant = [string]$domainName - PartitionKey = 'mailboxrules' } - $Table = Get-CIPPTable -TableName cachembxrules - Add-CIPPAzDataTableEntity @Table -Entity $GraphRequest -Force | Out-Null } + Add-CIPPAzDataTableEntity @Table -Entity $GraphRequest -Force | Out-Null } - - - -$Table = Get-CIPPTable -TableName cachembxrules -Write-Host "$($GraphRequest.RowKey) - $($GraphRequest.tenant)" -Add-CIPPAzDataTableEntity @Table -Entity $GraphRequest -Force | Out-Null diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxRules.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxRules.ps1 index b65dba4fdd09..a4ca980ba7d3 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxRules.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxRules.ps1 @@ -18,6 +18,8 @@ Function Invoke-ListMailboxRules { # Interact with query parameters or the body of the request. $TenantFilter = $Request.Query.TenantFilter + $Table = Get-CIPPTable -TableName cachembxrules + $Rows = Get-CIPPAzDataTableEntity @Table | Where-Object -Property Timestamp -GT (Get-Date).Addhours(-1) if (!$Rows) { Push-OutputBinding -Name mbxrulequeue -Value $TenantFilter @@ -27,22 +29,14 @@ Function Invoke-ListMailboxRules { } } else { if ($TenantFilter -ne 'AllTenants') { - $Table = Get-CIPPTable -TableName cachembxrules - $Rows = Get-CIPPAzDataTableEntity @Table | Where-Object -Property Timestamp -GT (Get-Date).Addhours(-1) - $GraphRequest = $Rows | Where-Object -Property Tenant -EQ $TenantFilter | ForEach-Object { - $NewObj = $_.Rules | ConvertFrom-Json - $NewObj | Add-Member -NotePropertyName 'Tenant' -NotePropertyValue $TenantFilter - $NewObj - } - } else { - $GraphRequest = New-ExoRequest -tenantid $tenantFilter -cmdlet 'Get-Mailbox' -Select 'userPrincipalName,GUID' | ForEach-Object { - New-ExoRequest -Anchor $_.UserPrincipalName -tenantid $tenantFilter -cmdlet 'Get-InboxRule' -cmdParams @{Mailbox = $_.GUID } - } + $Rows = $Rows | Where-Object -Property Tenant -EQ $TenantFilter + } + $GraphRequest = $Rows | ForEach-Object { + $NewObj = $_.Rules | ConvertFrom-Json + $NewObj | Add-Member -NotePropertyName 'Tenant' -NotePropertyValue $_.Tenant + $NewObj } } - #Remove all old cache - #Remove-AzDataTableEntity @Table -Entity (Get-CIPPAzDataTableEntity @Table -Property PartitionKey, RowKey, Timestamp | Where-Object -Property Timestamp -LT (Get-Date).AddMinutes(-15)) - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK From b3bd33fa72c9264f42d92d9b1a8916c756173137 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Mon, 5 Feb 2024 09:51:02 +0100 Subject: [PATCH 37/50] alphabetical sort --- Modules/CIPPCore/Public/Entrypoints/Invoke-ListGroups.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGroups.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGroups.ps1 index c2196b1a4e4a..d25ccd2c6d9f 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGroups.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGroups.ps1 @@ -71,7 +71,7 @@ Function Invoke-ListGroups { # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = $StatusCode - Body = @($GraphRequest) + Body = @($GraphRequest | Sort-Object displayName) }) } From f929cf762633cd40d9110356b7c95f09709054b7 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Mon, 5 Feb 2024 09:52:13 +0100 Subject: [PATCH 38/50] temporary move back to 1 for dequeue --- host.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/host.json b/host.json index 00c49cbf2490..f4f1896a0272 100644 --- a/host.json +++ b/host.json @@ -10,7 +10,7 @@ }, "extensions": { "queues": { - "maxDequeueCount": 3 + "maxDequeueCount": 1 } }, "logging": { From 37e52bf47b2d73d213b9c70b9568d474ffb1cb7f Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Mon, 5 Feb 2024 09:52:37 +0100 Subject: [PATCH 39/50] remove filelogging mode disablement --- host.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/host.json b/host.json index f4f1896a0272..b1667f1e9bbb 100644 --- a/host.json +++ b/host.json @@ -12,8 +12,5 @@ "queues": { "maxDequeueCount": 1 } - }, - "logging": { - "fileLoggingMode": "never" } } From b5bde28ee00a71871b84ed8158be36fdd6b2e775 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Mon, 5 Feb 2024 11:15:00 +0100 Subject: [PATCH 40/50] add setting of onedrive permission --- .../Invoke-ExecOneDrivePermission.ps1 | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 Modules/CIPPCore/Public/Entrypoints/Invoke-ExecOneDrivePermission.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecOneDrivePermission.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecOneDrivePermission.ps1 new file mode 100644 index 000000000000..154bc731d07e --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecOneDrivePermission.ps1 @@ -0,0 +1,26 @@ +using namespace System.Net + +Function Invoke-ExecOneDrivePermission { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $TriggerMetadata.FunctionName + $tenantFilter = $Request.Body.TenantFilter + try { + $State = Set-CIPPOnedriveAccess -tenantFilter $tenantFilter -userid $request.body.UPN -OnedriveAccessUser $request.body.input -ExecutingUser $ExecutingUser -APIName $APIName + $Results = [pscustomobject]@{'Results' = "$State" } + } catch { + $Results = [pscustomobject]@{'Results' = "Failed. $($_.Exception.Message)" } + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Results + }) + +} From 0b283b955c957a6b33865d91a0711d4d66c9b0b3 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Mon, 5 Feb 2024 11:38:14 +0100 Subject: [PATCH 41/50] add remove option --- .../Invoke-ExecOneDrivePermission.ps1 | 2 +- .../CIPPCore/Public/Set-CIPPOneDriveAccess.ps1 | 18 +++++++++++++----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecOneDrivePermission.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecOneDrivePermission.ps1 index 154bc731d07e..4951c1ae45af 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecOneDrivePermission.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecOneDrivePermission.ps1 @@ -11,7 +11,7 @@ Function Invoke-ExecOneDrivePermission { $APIName = $TriggerMetadata.FunctionName $tenantFilter = $Request.Body.TenantFilter try { - $State = Set-CIPPOnedriveAccess -tenantFilter $tenantFilter -userid $request.body.UPN -OnedriveAccessUser $request.body.input -ExecutingUser $ExecutingUser -APIName $APIName + $State = Set-CIPPOnedriveAccess -tenantFilter $tenantFilter -userid $request.body.UPN -OnedriveAccessUser $request.body.input -ExecutingUser $ExecutingUser -APIName $APIName -RemovePermission $request.body.RemovePermission $Results = [pscustomobject]@{'Results' = "$State" } } catch { $Results = [pscustomobject]@{'Results' = "Failed. $($_.Exception.Message)" } diff --git a/Modules/CIPPCore/Public/Set-CIPPOneDriveAccess.ps1 b/Modules/CIPPCore/Public/Set-CIPPOneDriveAccess.ps1 index 53cdaf9def8e..4a032ddcf062 100644 --- a/Modules/CIPPCore/Public/Set-CIPPOneDriveAccess.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPOneDriveAccess.ps1 @@ -5,8 +5,14 @@ function Set-CIPPOnedriveAccess { $OnedriveAccessUser, $TenantFilter, $APIName = 'Manage OneDrive Access', + $RemovePermission, $ExecutingUser ) + if ($RemovePermission -eq $true) { + $SiteAdmin = 'false' + } else { + $SiteAdmin = 'true' + } try { $URL = (New-GraphGetRequest -uri "https://graph.microsoft.com/v1.0/users/$($UserId)/Drives" -asapp $true -tenantid $TenantFilter).WebUrl @@ -22,7 +28,7 @@ function Set-CIPPOnedriveAccess { $URL $OnedriveAccessUser - true + $SiteAdmin @@ -31,11 +37,13 @@ function Set-CIPPOnedriveAccess { "@ $request = New-GraphPostRequest -scope "$AdminURL/.default" -tenantid $TenantFilter -Uri "$AdminURL/_vti_bin/client.svc/ProcessQuery" -Type POST -Body $XML -ContentType 'text/xml' if (!$request.ErrorInfo.ErrorMessage) { - Write-LogMessage -user $ExecutingUser -API $APIName -message "Gave $($OnedriveAccessUser) access to $($userid) OneDrive" -Sev 'Info' -tenant $TenantFilter - return "User's OneDrive URL is $URL. Access has been given to $($OnedriveAccessUser)" + $Message = "$($OnedriveAccessUser) has been $($RemovePermission ? 'removed from' : 'given') access to $URL" + Write-LogMessage -user $ExecutingUser -API $APIName -message $Message -Sev 'Info' -tenant $TenantFilter + return $Message } else { - Write-LogMessage -user $ExecutingUser -API $APIName -message "Failed to give OneDrive Access: $($request.ErrorInfo.ErrorMessage)" -Sev 'Info' -tenant $TenantFilter - return "Failed to give OneDrive Access: $($request.ErrorInfo.ErrorMessage)" + $message = "Failed to change OneDrive Access: $($request.ErrorInfo.ErrorMessage)" + Write-LogMessage -user $ExecutingUser -API $APIName -message $message -Sev 'Info' -tenant $TenantFilter + return $message } } catch { Write-LogMessage -user $ExecutingUser -API $APIName -message "Could not add new owner to OneDrive $($OnedriveAccessUser) on $($userid)" -Sev 'Error' -tenant $TenantFilter From d3651a918e650cec036d616d104f21d773a3f377 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Mon, 5 Feb 2024 12:07:26 +0100 Subject: [PATCH 42/50] Renamed cmdlet --- .../Public/Entrypoints/Invoke-ExecOneDrivePermission.ps1 | 2 +- Modules/CIPPCore/Public/Invoke-CIPPOffboardingJob.ps1 | 2 +- .../{Set-CIPPOneDriveAccess.ps1 => Set-CIPPSharePointOwner.ps1} | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename Modules/CIPPCore/Public/{Set-CIPPOneDriveAccess.ps1 => Set-CIPPSharePointOwner.ps1} (98%) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecOneDrivePermission.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecOneDrivePermission.ps1 index 4951c1ae45af..5254899559de 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecOneDrivePermission.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecOneDrivePermission.ps1 @@ -11,7 +11,7 @@ Function Invoke-ExecOneDrivePermission { $APIName = $TriggerMetadata.FunctionName $tenantFilter = $Request.Body.TenantFilter try { - $State = Set-CIPPOnedriveAccess -tenantFilter $tenantFilter -userid $request.body.UPN -OnedriveAccessUser $request.body.input -ExecutingUser $ExecutingUser -APIName $APIName -RemovePermission $request.body.RemovePermission + $State = Set-CIPPSharePointOwner -tenantFilter $tenantFilter -userid $request.body.UPN -OnedriveAccessUser $request.body.input -ExecutingUser $ExecutingUser -APIName $APIName -RemovePermission $request.body.RemovePermission $Results = [pscustomobject]@{'Results' = "$State" } } catch { $Results = [pscustomobject]@{'Results' = "Failed. $($_.Exception.Message)" } diff --git a/Modules/CIPPCore/Public/Invoke-CIPPOffboardingJob.ps1 b/Modules/CIPPCore/Public/Invoke-CIPPOffboardingJob.ps1 index 7da2b800b3c9..0d45ac6311df 100644 --- a/Modules/CIPPCore/Public/Invoke-CIPPOffboardingJob.ps1 +++ b/Modules/CIPPCore/Public/Invoke-CIPPOffboardingJob.ps1 @@ -35,7 +35,7 @@ function Invoke-CIPPOffboardingJob { } { $_.'OnedriveAccess' -ne '' } { - $Options.OnedriveAccess | ForEach-Object { Set-CIPPOnedriveAccess -tenantFilter $tenantFilter -userid $username -OnedriveAccessUser $_.value -ExecutingUser $ExecutingUser -APIName $APIName } + $Options.OnedriveAccess | ForEach-Object { Set-CIPPSharePointOwner -tenantFilter $tenantFilter -userid $username -OnedriveAccessUser $_.value -ExecutingUser $ExecutingUser -APIName $APIName } } { $_.'AccessNoAutomap' -ne '' } { diff --git a/Modules/CIPPCore/Public/Set-CIPPOneDriveAccess.ps1 b/Modules/CIPPCore/Public/Set-CIPPSharePointOwner.ps1 similarity index 98% rename from Modules/CIPPCore/Public/Set-CIPPOneDriveAccess.ps1 rename to Modules/CIPPCore/Public/Set-CIPPSharePointOwner.ps1 index 4a032ddcf062..068a8b383731 100644 --- a/Modules/CIPPCore/Public/Set-CIPPOneDriveAccess.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPSharePointOwner.ps1 @@ -1,4 +1,4 @@ -function Set-CIPPOnedriveAccess { +function Set-CIPPSharePointOwner { [CmdletBinding()] param ( $userid, From a725204848bd7ab2884e592ee865e28f469d96ec Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Mon, 5 Feb 2024 12:33:42 +0100 Subject: [PATCH 43/50] add setting sharepoint owner --- ...ission.ps1 => Invoke-ExecSharePointOwner.ps1} | 4 ++-- .../CIPPCore/Public/Set-CIPPSharePointOwner.ps1 | 16 ++++++++++------ 2 files changed, 12 insertions(+), 8 deletions(-) rename Modules/CIPPCore/Public/Entrypoints/{Invoke-ExecOneDrivePermission.ps1 => Invoke-ExecSharePointOwner.ps1} (89%) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecOneDrivePermission.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecSharePointOwner.ps1 similarity index 89% rename from Modules/CIPPCore/Public/Entrypoints/Invoke-ExecOneDrivePermission.ps1 rename to Modules/CIPPCore/Public/Entrypoints/Invoke-ExecSharePointOwner.ps1 index 5254899559de..398f070db9ee 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecOneDrivePermission.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecSharePointOwner.ps1 @@ -1,6 +1,6 @@ using namespace System.Net -Function Invoke-ExecOneDrivePermission { +Function Invoke-ExecSharePointOwner { <# .FUNCTIONALITY Entrypoint @@ -11,7 +11,7 @@ Function Invoke-ExecOneDrivePermission { $APIName = $TriggerMetadata.FunctionName $tenantFilter = $Request.Body.TenantFilter try { - $State = Set-CIPPSharePointOwner -tenantFilter $tenantFilter -userid $request.body.UPN -OnedriveAccessUser $request.body.input -ExecutingUser $ExecutingUser -APIName $APIName -RemovePermission $request.body.RemovePermission + $State = Set-CIPPSharePointOwner -tenantFilter $tenantFilter -userid $request.body.UPN -OnedriveAccessUser $request.body.input -ExecutingUser $ExecutingUser -APIName $APIName -RemovePermission $request.body.RemovePermission -URL $Request.Body.URL $Results = [pscustomobject]@{'Results' = "$State" } } catch { $Results = [pscustomobject]@{'Results' = "Failed. $($_.Exception.Message)" } diff --git a/Modules/CIPPCore/Public/Set-CIPPSharePointOwner.ps1 b/Modules/CIPPCore/Public/Set-CIPPSharePointOwner.ps1 index 068a8b383731..3acdfc3d314f 100644 --- a/Modules/CIPPCore/Public/Set-CIPPSharePointOwner.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPSharePointOwner.ps1 @@ -4,9 +4,10 @@ function Set-CIPPSharePointOwner { $userid, $OnedriveAccessUser, $TenantFilter, - $APIName = 'Manage OneDrive Access', + $APIName = 'Manage SharePoint Owner', $RemovePermission, - $ExecutingUser + $ExecutingUser, + $URL ) if ($RemovePermission -eq $true) { $SiteAdmin = 'false' @@ -15,7 +16,9 @@ function Set-CIPPSharePointOwner { } try { - $URL = (New-GraphGetRequest -uri "https://graph.microsoft.com/v1.0/users/$($UserId)/Drives" -asapp $true -tenantid $TenantFilter).WebUrl + if (!$URL) { + $URL = (New-GraphGetRequest -uri "https://graph.microsoft.com/v1.0/users/$($UserId)/Drives" -asapp $true -tenantid $TenantFilter).WebUrl + } $OnMicrosoft = (New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/domains?$top=999' -tenantid $TenantFilter | Where-Object -Property isInitial -EQ $true).id.split('.') | Select-Object -First 1 $AdminUrl = "https://$($OnMicrosoft)-admin.sharepoint.com" $XML = @" @@ -36,17 +39,18 @@ function Set-CIPPSharePointOwner { "@ $request = New-GraphPostRequest -scope "$AdminURL/.default" -tenantid $TenantFilter -Uri "$AdminURL/_vti_bin/client.svc/ProcessQuery" -Type POST -Body $XML -ContentType 'text/xml' + Write-Host $($request) if (!$request.ErrorInfo.ErrorMessage) { $Message = "$($OnedriveAccessUser) has been $($RemovePermission ? 'removed from' : 'given') access to $URL" Write-LogMessage -user $ExecutingUser -API $APIName -message $Message -Sev 'Info' -tenant $TenantFilter return $Message } else { - $message = "Failed to change OneDrive Access: $($request.ErrorInfo.ErrorMessage)" + $message = "Failed to change access: $($request.ErrorInfo.ErrorMessage)" Write-LogMessage -user $ExecutingUser -API $APIName -message $message -Sev 'Info' -tenant $TenantFilter return $message } } catch { - Write-LogMessage -user $ExecutingUser -API $APIName -message "Could not add new owner to OneDrive $($OnedriveAccessUser) on $($userid)" -Sev 'Error' -tenant $TenantFilter - return "Could not add owner to OneDrive for $($userid). Error: $($_.Exception.Message)" + Write-LogMessage -user $ExecutingUser -API $APIName -message "Could not add new owner to $($OnedriveAccessUser) on $URL" -Sev 'Error' -tenant $TenantFilter + return "Could not add owner for $($URL). Error: $($_.Exception.Message)" } } From cb3129232f26279b7ba37a24057214bcf9df426d Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Mon, 5 Feb 2024 14:23:04 +0100 Subject: [PATCH 44/50] add remove member --- .../CIPPCore/Public/Add-CIPPGroupMember.ps1 | 29 +++++++++++++++++++ .../Invoke-ExecSetSharePointMember.ps1 | 29 +++++++++++++++++++ .../Public/Remove-CIPPGroupMember.ps1 | 29 +++++++++++++++++++ 3 files changed, 87 insertions(+) create mode 100644 Modules/CIPPCore/Public/Add-CIPPGroupMember.ps1 create mode 100644 Modules/CIPPCore/Public/Entrypoints/Invoke-ExecSetSharePointMember.ps1 create mode 100644 Modules/CIPPCore/Public/Remove-CIPPGroupMember.ps1 diff --git a/Modules/CIPPCore/Public/Add-CIPPGroupMember.ps1 b/Modules/CIPPCore/Public/Add-CIPPGroupMember.ps1 new file mode 100644 index 000000000000..2ff3c406102b --- /dev/null +++ b/Modules/CIPPCore/Public/Add-CIPPGroupMember.ps1 @@ -0,0 +1,29 @@ +function Add-CIPPGroupMember( + [string]$ExecutingUser, + [string]$GroupType, + [string]$GroupId, + [string]$Member, + [string]$TenantFilter, + [string]$APIName = 'Add Group Member' +) { + try { + if ($member -like '*#EXT#*') { $member = [System.Web.HttpUtility]::UrlEncode($member) } + $MemberIDs = 'https://graph.microsoft.com/v1.0/directoryObjects/' + (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($member)" -tenantid $TenantFilter).id + $addmemberbody = "{ `"members@odata.bind`": $(ConvertTo-Json @($MemberIDs)) }" + if ($GroupType -eq 'Distribution list' -or $GroupType -eq 'Mail-Enabled Security') { + $Params = @{ Identity = $GroupId; Member = $member; BypassSecurityGroupManagerCheck = $true } + New-ExoRequest -tenantid $TenantFilter -cmdlet 'Add-DistributionGroupMember' -cmdParams $params -UseSystemMailbox $true + } else { + New-GraphPostRequest -uri "https://graph.microsoft.com/beta/groups/$($GroupId)" -tenantid $TenantFilter -type patch -body $addmemberbody -Verbose + } + $Message = "Successfully added user $($Member) to $GroupId." + Write-LogMessage -user $ExecutingUser -API $APIName -tenant $TenantFilter -message $Message -Sev 'Info' + return $message + return + } catch { + $message = "Failed to add user $($Member) to $($GroupId): $($_.Exception.Message)" + Write-LogMessage -user $ExecutingUser -API $APIName -tenant $TenantFilter -message $message -Sev 'error' + return $message + } + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecSetSharePointMember.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecSetSharePointMember.ps1 new file mode 100644 index 000000000000..0a031a0af5d3 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecSetSharePointMember.ps1 @@ -0,0 +1,29 @@ +using namespace System.Net + +Function Invoke-ExecSetSharePointMember { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + $GroupId = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/groups?`$filter=mail eq '$($Request.Body.GroupID)'" -tenantid $Request.Body.TenantFilter).id + if ($Request.body.SharePointType -eq 'Group') { + if ($Request.body.Add -eq $true) { + $Results = Add-CIPPGroupMember -GroupType 'Team' -GroupID $GroupID -Member $Request.Body.input -TenantFilter $Request.Body.TenantFilter -ExecutingUser $request.headers.'x-ms-client-principal' + } else { + $UserID = (New-GraphGetRequest -uri "https://graph.microsoft.com/v1.0/users/$($Request.Body.input)" -tenantid $Request.Body.TenantFilter).id + $Results = Remove-CIPPGroupMember -GroupType 'Team' -GroupID $GroupID -Member $UserID -TenantFilter $Request.Body.TenantFilter -ExecutingUser $request.headers.'x-ms-client-principal' + } + } else { + $Results = 'This type of SharePoint site is not supported.' + } + $body = [pscustomobject]@{'Results' = $Results } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $body + }) + +} diff --git a/Modules/CIPPCore/Public/Remove-CIPPGroupMember.ps1 b/Modules/CIPPCore/Public/Remove-CIPPGroupMember.ps1 new file mode 100644 index 000000000000..d47e79878fd4 --- /dev/null +++ b/Modules/CIPPCore/Public/Remove-CIPPGroupMember.ps1 @@ -0,0 +1,29 @@ +function Remove-CIPPGroupMember( + [string]$ExecutingUser, + [string]$GroupType, + [string]$GroupId, + [string]$Member, + [string]$TenantFilter, + [string]$APIName = 'Remove Group Member' +) { + try { + if ($member -like '*#EXT#*') { $member = [System.Web.HttpUtility]::UrlEncode($member) } + $MemberIDs = 'https://graph.microsoft.com/v1.0/directoryObjects/' + (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($member)" -tenantid $TenantFilter).id + $addmemberbody = "{ `"members@odata.bind`": $(ConvertTo-Json @($MemberIDs)) }" + if ($GroupType -eq 'Distribution list' -or $GroupType -eq 'Mail-Enabled Security') { + $Params = @{ Identity = $GroupId; Member = $member; BypassSecurityGroupManagerCheck = $true } + New-ExoRequest -tenantid $TenantFilter -cmdlet 'Remove-DistributionGroupMember' -cmdParams $params -UseSystemMailbox $true + } else { + New-GraphPostRequest -uri "https://graph.microsoft.com/beta/groups/$($GroupId)/members/$($Member)/`$ref" -tenantid $TenantFilter -type DELETE -body '{}' -Verbose + } + $Message = "Successfully removed user $($Member) from $GroupId." + Write-LogMessage -user $ExecutingUser -API $APIName -tenant $TenantFilter -message $Message -Sev 'Info' + return $message + return + } catch { + $message = "Failed to remove user $($Member) from $($GroupId): $($_.Exception.Message)" + Write-LogMessage -user $ExecutingUser -API $APIName -tenant $TenantFilter -message $message -Sev 'error' + return $message + } + +} From 6b24163265e9e69ba5fb0a72c8d475db8df6b13b Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Mon, 5 Feb 2024 14:28:27 +0100 Subject: [PATCH 45/50] up version --- version_latest.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version_latest.txt b/version_latest.txt index 25b08bbc78f0..acf69b48b843 100644 --- a/version_latest.txt +++ b/version_latest.txt @@ -1 +1 @@ -5.0.5 \ No newline at end of file +5.1.0 \ No newline at end of file From aea997a4d292344ef765987562514a8bb29464c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Mon, 5 Feb 2024 19:57:17 +0100 Subject: [PATCH 46/50] Add disable sp legacy auth standard --- ...IPPStandardDisableSharePointLegacyAuth.ps1 | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSharePointLegacyAuth.ps1 diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSharePointLegacyAuth.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSharePointLegacyAuth.ps1 new file mode 100644 index 000000000000..87178367ab5c --- /dev/null +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSharePointLegacyAuth.ps1 @@ -0,0 +1,37 @@ +function Invoke-CIPPStandardDisableSharePointLegacyAuth { + <# + .FUNCTIONALITY + Internal + #> + param($Tenant, $Settings) + + $CurrentInfo = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/admin/sharepoint/settings?$select=isLegacyAuthProtocolsEnabled' -tenantid $Tenant -AsApp $true + + If ($Settings.remediate) { + + if ($CurrentInfo.isLegacyAuthProtocolsEnabled) { + try { + $body = '{"isLegacyAuthProtocolsEnabled": "false"}' + $null = New-GraphPostRequest -tenantid $tenant -Uri 'https://graph.microsoft.com/beta/admin/sharepoint/settings' -AsApp $true -Type patch -Body $body -ContentType 'application/json' + Write-LogMessage -API 'Standards' -tenant $tenant -message 'Disabled SharePoint basic authentication' -sev Info + $CurrentInfo.isLegacyAuthProtocolsEnabled = $false + } catch { + Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to disable SharePoint basic authentication. Error: $($_.exception.message)" -sev Error + } + } else { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'SharePoint basic authentication is already disabled' -sev Info + } + } + if ($Settings.alert) { + + if ($CurrentInfo.isLegacyAuthProtocolsEnabled) { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'SharePoint basic authentication is enabled' -sev Alert + } else { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'SharePoint basic authentication is disabled' -sev Info + } + } + if ($Settings.report) { + + Add-CIPPBPAField -FieldName 'SharePointLegacyAuthEnabled' -FieldValue [bool]$CurrentInfo.isLegacyAuthProtocolsEnabled -StoreAs bool -Tenant $tenant + } +} From 7d61b934b58492414eb2a3b2973e71136ea894e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Mon, 5 Feb 2024 22:40:02 +0100 Subject: [PATCH 47/50] Add disable users from installing add-ins in Outlook standard --- ...nvoke-CIPPStandardDisableOutlookAddins.ps1 | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableOutlookAddins.ps1 diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableOutlookAddins.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableOutlookAddins.ps1 new file mode 100644 index 000000000000..d352fd8b33f0 --- /dev/null +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableOutlookAddins.ps1 @@ -0,0 +1,54 @@ +function Invoke-CIPPStandardDisableOutlookAddins { + <# + .FUNCTIONALITY + Internal + #> + param($Tenant, $Settings) + + $CurrentInfo = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-RoleAssignmentPolicy' | Where-Object { $_.IsDefault -eq $true } + $Roles = @('My Custom Apps', 'My Marketplace Apps', 'My ReadWriteMailbox Apps') + $RolesToRemove = foreach ($Role in $Roles) { + if ($CurrentInfo.AssignedRoles -contains $Role) { + $Role + } + } + + if ($Settings.remediate) { + if ($RolesToRemove) { + $Errors = [System.Collections.Generic.List[string]]::new() + + foreach ($Role in $RolesToRemove) { + try { + New-ExoRequest -tenantid $Tenant -cmdlet 'Get-ManagementRoleAssignment' -cmdparams @{ RoleAssignee = $CurrentInfo.Identity; Role = $Role } | ForEach-Object { + New-ExoRequest -tenantid $Tenant -cmdlet 'Remove-ManagementRoleAssignment' -cmdparams @{ Identity = $_.Guid; Confirm = $false } -UseSystemMailbox $true + Write-LogMessage -API 'Standards' -tenant $tenant -message "Disabled Outlook add-in role: $Role" -sev Debug + } + } catch { + Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to disable Outlook add-in role: $Role Error: $($_.exception.message)" -sev Error + $Errors.Add($Role) + } + } + + if ($Errors.Count -gt 0) { + Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to disable users from installing Outlook add-ins. Roles: $($Errors -join ', ')" -sev Error + } else { + Write-LogMessage -API 'Standards' -tenant $tenant -message "Disabled users from installing Outlook add-ins. Roles removed: $($RolesToRemove -join ', ')" -sev Info + $RolesToRemove = $null + } + } else { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'Users installing Outlook add-ins already disabled' -sev Info + } + } + + if ($Settings.alert) { + if ($RolesToRemove) { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'Users are not disabled from installing Outlook add-ins.' -sev Alert + } else { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'Users are disabled from installing Outlook add-ins.' -sev Info + } + } + if ($Settings.report) { + if ($RolesToRemove) { $State = $false } else { $State = $true } + Add-CIPPBPAField -FieldName 'DisabledOutlookAddins' -FieldValue [bool]$State -StoreAs bool -Tenant $tenant + } +} \ No newline at end of file From f316a983660bd7ff0c0cc94507639b1b92e4f9bc Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Tue, 6 Feb 2024 17:40:45 +0100 Subject: [PATCH 48/50] update --- Modules/CIPPCore/Public/Remove-CIPPGroupMember.ps1 | 1 - 1 file changed, 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Remove-CIPPGroupMember.ps1 b/Modules/CIPPCore/Public/Remove-CIPPGroupMember.ps1 index d47e79878fd4..9567039fe8e4 100644 --- a/Modules/CIPPCore/Public/Remove-CIPPGroupMember.ps1 +++ b/Modules/CIPPCore/Public/Remove-CIPPGroupMember.ps1 @@ -19,7 +19,6 @@ function Remove-CIPPGroupMember( $Message = "Successfully removed user $($Member) from $GroupId." Write-LogMessage -user $ExecutingUser -API $APIName -tenant $TenantFilter -message $Message -Sev 'Info' return $message - return } catch { $message = "Failed to remove user $($Member) from $($GroupId): $($_.Exception.Message)" Write-LogMessage -user $ExecutingUser -API $APIName -tenant $TenantFilter -message $message -Sev 'error' From 13d85539dcef9869c7b449694e17b300f9a70367 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Tue, 6 Feb 2024 18:54:33 +0100 Subject: [PATCH 49/50] Fixes bec issue --- Durable_BECRun/run.ps1 | 79 ++++++++++++++++++++---------------------- 1 file changed, 37 insertions(+), 42 deletions(-) diff --git a/Durable_BECRun/run.ps1 b/Durable_BECRun/run.ps1 index 49d358ff3fca..377ca2c5533b 100644 --- a/Durable_BECRun/run.ps1 +++ b/Durable_BECRun/run.ps1 @@ -2,7 +2,7 @@ param($Context) #$Context does not allow itself to be cast to a pscustomobject for some reason, so we convert $context = $Context | ConvertTo-Json | ConvertFrom-Json $APIName = $TriggerMetadata.FunctionName -Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Accessed this API" -Sev "Debug" +Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' $TenantFilter = $Context.input.tenantfilter $SuspectUser = $Context.input.userid $UserName = $Context.input.username @@ -10,38 +10,37 @@ Write-Host "Working on $UserName" try { $startDate = (Get-Date).AddDays(-7) $endDate = (Get-Date) - $auditLog = (New-ExoRequest -tenantid $Tenantfilter -cmdlet "Get-AdminAuditLogConfig").UnifiedAuditLogIngestionEnabled + $auditLog = (New-ExoRequest -tenantid $Tenantfilter -cmdlet 'Get-AdminAuditLogConfig').UnifiedAuditLogIngestionEnabled $7dayslog = if ($auditLog -eq $false) { - $ExtractResult = "AuditLog is disabled. Cannot perform full analysis" - } - else { + $ExtractResult = 'AuditLog is disabled. Cannot perform full analysis' + } else { $sessionid = Get-Random -Minimum 10000 -Maximum 99999 $operations = @( - "New-InboxRule", - "Set-InboxRule", - "UpdateInboxRules", - "Remove-MailboxPermission", - "Add-MailboxPermission", - "UpdateCalendarDelegation", - "AddFolderPermissions", - "MailboxLogin", - "UserLoggedIn" + 'New-InboxRule', + 'Set-InboxRule', + 'UpdateInboxRules', + 'Remove-MailboxPermission', + 'Add-MailboxPermission', + 'UpdateCalendarDelegation', + 'AddFolderPermissions', + 'MailboxLogin', + 'UserLoggedIn' ) $startDate = (Get-Date).AddDays(-7) $endDate = (Get-Date) $SearchParam = @{ - SessionCommand = "ReturnLargeSet" + SessionCommand = 'ReturnLargeSet' Operations = $operations sessionid = $sessionid startDate = $startDate endDate = $endDate } do { - New-ExoRequest -tenantid $Tenantfilter -cmdlet "Search-unifiedAuditLog" -cmdParams $SearchParam -Anchor $Username + New-ExoRequest -tenantid $Tenantfilter -cmdlet 'Search-unifiedAuditLog' -cmdParams $SearchParam -Anchor $Username Write-Host "Retrieved $($logsTenant.count) logs" -ForegroundColor Yellow $logsTenant } while ($LogsTenant.count % 5000 -eq 0 -and $LogsTenant.count -ne 0) - $ExtractResult = "Succesfully extracted logs from auditlog" + $ExtractResult = 'Succesfully extracted logs from auditlog' } Try { $URI = "https://graph.microsoft.com/beta/auditLogs/signIns?`$filter=(userId eq '$SuspectUser')&`$top=1&`$orderby=createdDateTime desc" @@ -50,13 +49,12 @@ try { @{ Name = 'AppDisplayName'; Expression = { $_.resourceDisplayName } }, @{ Name = 'Status'; Expression = { if (($_.conditionalAccessStatus -eq 'Success' -or 'Not Applied') -and $_.status.errorCode -eq 0) { 'Success' } else { 'Failed' } } }, @{ Name = 'IPAddress'; Expression = { $_.ipAddress } } - } - catch { + } catch { $LastSignIn = [PSCustomObject]@{ - AppDisplayName = "Unknown - could not retrieve information. No access to sign-in logs" - CreatedDateTime = "Unknown" - Id = "0" - Status = "Could not retrieve additional details" + AppDisplayName = 'Unknown - could not retrieve information. No access to sign-in logs' + CreatedDateTime = 'Unknown' + Id = '0' + Status = 'Could not retrieve additional details' } } #List all users devices @@ -64,15 +62,13 @@ try { $base64IdentityParam = [Convert]::ToBase64String($Bytes) Try { $Devices = New-GraphGetRequest -uri "https://outlook.office365.com:443/adminapi/beta/$($TenantFilter)/mailbox('$($base64IdentityParam)')/MobileDevice/Exchange.GetMobileDeviceStatistics()/?IsEncoded=True" -Tenantid $tenantfilter -scope ExchangeOnline - } - catch { + } catch { $Devices = $null } - $PermissionsLog = ($7dayslog | Where-Object -Property Operations -In "Remove-MailboxPermission", "Add-MailboxPermission", "UpdateCalendarDelegation", "AddFolderPermissions" ).AuditData | ConvertFrom-Json -Depth 100 | ForEach-Object { + $PermissionsLog = ($7dayslog | Where-Object -Property Operations -In 'Remove-MailboxPermission', 'Add-MailboxPermission', 'UpdateCalendarDelegation', 'AddFolderPermissions' ).AuditData | ConvertFrom-Json -Depth 100 | ForEach-Object { $perms = if ($_.Parameters) { - $_.Parameters | ForEach-Object { if ($_.Name -eq "AccessRights") { $_.Value } } - } - else + $_.Parameters | ForEach-Object { if ($_.Name -eq 'AccessRights') { $_.Value } } + } else { $_.item.ParentFolder.MemberRights } $objectID = if ($_.ObjectID) { $_.ObjectID } else { $($_.MailboxOwnerUPN) + $_.item.ParentFolder.Path } [pscustomobject]@{ @@ -83,43 +79,42 @@ try { } } - $RulesLog = @(($7dayslog | Where-Object -Property Operations -In "New-InboxRule", "Set-InboxRule", "UpdateInboxRules").AuditData | ConvertFrom-Json) | ForEach-Object { + $RulesLog = @(($7dayslog | Where-Object -Property Operations -In 'New-InboxRule', 'Set-InboxRule', 'UpdateInboxRules').AuditData | ConvertFrom-Json) | ForEach-Object { Write-Host ($_ | ConvertTo-Json) [pscustomobject]@{ ClientIP = $_.ClientIP CreationTime = $_.CreationTime UserId = $_.UserId - RuleName = ($_.OperationProperties | ForEach-Object { if ($_.Name -eq "RuleName") { $_.Value } }) - RuleCondition = ($_.OperationProperties | ForEach-Object { if ($_.Name -eq "RuleCondition") { $_.Value } }) + RuleName = ($_.OperationProperties | ForEach-Object { if ($_.Name -eq 'RuleName') { $_.Value } }) + RuleCondition = ($_.OperationProperties | ForEach-Object { if ($_.Name -eq 'RuleCondition') { $_.Value } }) } } $PasswordChanges = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users?`select=lastPasswordChangeDateTime,displayname,UserPrincipalName" -Tenantid $tenantfilter | Where-Object { $_.lastPasswordChangeDateTime -gt $startDate } - $NewUsers = New-GraphGetRequest -uri "https://graph.microsoft.com/v1.0/users?`$select=displayname,UserPrincipalName,CreatedDateTime" -Tenantid $tenantfilter | Where-Object { $_.CreatedDateTime -gt $startDate } + $NewUsers = New-GraphGetRequest -uri "https://graph.microsoft.com/v1.0/users?`$select=displayname,UserPrincipalName,CreatedDateTime" -Tenantid $tenantfilter | Where-Object { $_.CreatedDateTime -gt $startDate } $MFADevices = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($SuspectUser)/authentication/methods" -Tenantid $tenantfilter $NewSPs = New-GraphGetRequest -uri "https://graph.microsoft.com/v1.0/servicePrincipals?`$select=displayName,createdDateTime,id,AppDisplayName&`$filter=createdDateTime ge $($startDate.ToString('yyyy-MM-ddTHH:mm:ssZ'))" -Tenantid $tenantfilter - $Last50Logons = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/auditLogs/signIns?`$top=50&`$orderby=createdDateTime desc" -tenantid $TenantFilter -noPagination $true -verbose | Select-Object @{ Name = 'CreatedDateTime'; Expression = { $(($_.createdDateTime | Out-String) -replace '\r\n') } }, + $Last50Logons = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/auditLogs/signIns?`$top=50&`$orderby=createdDateTime desc" -tenantid $TenantFilter -noPagination $true -verbose | Select-Object @{ Name = 'CreatedDateTime'; Expression = { $(($_.createdDateTime | Out-String) -replace '\r\n') } }, id, @{ Name = 'AppDisplayName'; Expression = { $_.resourceDisplayName } }, @{ Name = 'Status'; Expression = { if (($_.conditionalAccessStatus -eq 'Success' -or 'Not Applied') -and $_.status.errorCode -eq 0) { 'Success' } else { 'Failed' } } }, @{ Name = 'IPAddress'; Expression = { $_.ipAddress } }, UserPrincipalName $Results = [PSCustomObject]@{ - AddedApps = $NewSPs - SuspectUserMailboxLogons = $Last50Logons + AddedApps = @($NewSPs) + SuspectUserMailboxLogons = @($Last50Logons) LastSuspectUserLogon = @($LastSignIn) SuspectUserDevices = @($Devices) NewRules = @($RulesLog) MailboxPermissionChanges = @($PermissionsLog) NewUsers = @($NewUsers) - MFADevices = $MFADevices - ChangedPasswords = $PasswordChanges + MFADevices = @($MFADevices) + ChangedPasswords = @($PasswordChanges) ExtractedAt = (Get-Date).ToString('s') ExtractResult = $ExtractResult } -} -catch { +} catch { $errMessage = Get-NormalizedError -message $_.Exception.Message - $results = [pscustomobject]@{"Results" = "$errMessage" } + $results = [pscustomobject]@{'Results' = "$errMessage" } } $Table = Get-CippTable -tablename 'cachebec' @@ -128,5 +123,5 @@ Add-CIPPAzDataTableEntity @Table -Entity @{ UserId = $Context.input.userid Results = "$($results | ConvertTo-Json -Depth 10)" RowKey = $Context.input.userid - PartitionKey = "bec" + PartitionKey = 'bec' } \ No newline at end of file From 0e16005548df88ba69faa21cf04609ce769569c9 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Tue, 6 Feb 2024 19:01:34 +0100 Subject: [PATCH 50/50] up version --- version_latest.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version_latest.txt b/version_latest.txt index acf69b48b843..3bff059174b8 100644 --- a/version_latest.txt +++ b/version_latest.txt @@ -1 +1 @@ -5.1.0 \ No newline at end of file +5.1.1 \ No newline at end of file