diff --git a/BestPracticeAnalyser_List/function.json b/BestPracticeAnalyser_List/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/BestPracticeAnalyser_List/function.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "bindings": [ - { - "authLevel": "anonymous", - "type": "httpTrigger", - "direction": "in", - "name": "Request", - "methods": [ - "get", - "post" - ] - }, - { - "type": "http", - "direction": "out", - "name": "Response" - } - ] -} \ No newline at end of file diff --git a/BestPracticeAnalyser_List/run.ps1 b/BestPracticeAnalyser_List/run.ps1 deleted file mode 100644 index dd27bc04a93b..000000000000 --- a/BestPracticeAnalyser_List/run.ps1 +++ /dev/null @@ -1,26 +0,0 @@ -using namespace System.Net - -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) - -$APIName = $TriggerMetadata.FunctionName -Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Accessed this API" -Sev "Debug" - -$Tenants = Get-Tenants -$Table = get-cipptable 'cachebpa' -$Results = (Get-CIPPAzDataTableEntity @Table) | ForEach-Object { - $_.UnusedLicenseList = @(ConvertFrom-Json -ErrorAction silentlycontinue -InputObject $_.UnusedLicenseList) - $_ -} - -if (!$Results) { - $Results = @{ - Tenant = "The BPA has not yet run." - } -} -Write-Host ($Tenants | ConvertTo-Json) -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @(($Results | Where-Object -Property RowKey -In $Tenants.customerId)) - }) \ No newline at end of file diff --git a/Config/7547f73c-3cb0-460c-a4bd-391944908007.IntuneTemplate.json b/Config/7547f73c-3cb0-460c-a4bd-391944908007.IntuneTemplate.json index fde8371a4af5..46b4483e224a 100644 --- a/Config/7547f73c-3cb0-460c-a4bd-391944908007.IntuneTemplate.json +++ b/Config/7547f73c-3cb0-460c-a4bd-391944908007.IntuneTemplate.json @@ -1,5 +1,5 @@ { - "Displayname": "CIPP Default: Skip Autopilot User Setup Page", + "Displayname": "CIPP: Skip Autopilot User Setup Page", "Description": "Skips the autopilot user setup page", "RAWJson": "{\"id\":\"00000000-0000-0000-0000-000000000000\",\"displayName\":\"Skip Autopilot User Setup Page\",\"roleScopeTagIds\":[\"0\"],\"@odata.type\":\"#microsoft.graph.windows10CustomConfiguration\",\"omaSettings\":[{\"displayName\":\"SkipUserSetupPage\",\"omaUri\":\"./Device/Vendor/MSFT/DMClient/Provider/MS DM Server/FirstSyncStatus/SkipUserStatusPage\",\"@odata.type\":\"#microsoft.graph.omaSettingBoolean\",\"value\":\"true\"}]}", "Type": "Device", diff --git a/Config/CIPPDefaultTable.BPATemplate.json b/Config/CIPPDefaultTable.BPATemplate.json index 2f7f31ac326c..735012b4bd77 100644 --- a/Config/CIPPDefaultTable.BPATemplate.json +++ b/Config/CIPPDefaultTable.BPATemplate.json @@ -1,5 +1,5 @@ { - "name": "CIPP Best Practices v1.0 - Table view", + "name": "CIPP Best Practices v1.5 - Table view", "style": "Table", "Fields": [ { @@ -172,19 +172,21 @@ "FrontendFields": [ { "name": "Current Secure Score", - "value": "CurrentSecureScore.currentScore" - }, - { - "name": "Max Secure Score", - "value": "CurrentSecureScore.maxScore" + "value": "CurrentSecureScore.currentScore / CurrentSecureScore.maxScore * 100", + "formatter": "math", + "showAs": "percentage" }, { "name": "Average Comparative Score (All Tenants)", - "value": "CurrentSecureScore.averageComparativeScores[0].averageScore" + "value": "CurrentSecureScore.averageComparativeScores[0].averageScore / CurrentSecureScore.maxScore * 100", + "formatter": "math", + "showAs": "percentage" }, { "name": "Average Comparative Score (Similiar Size Tenants)", - "value": "CurrentSecureScore.averageComparativeScores[1].averageScore" + "value": "CurrentSecureScore.averageComparativeScores[1].averageScore / CurrentSecureScore.maxScore * 100", + "formatter": "math", + "showAs": "percentage" } ] } diff --git a/Config/CyberEssentials.BPATemplate.json b/Config/CyberEssentials.BPATemplate.json new file mode 100644 index 000000000000..31d25321dc88 --- /dev/null +++ b/Config/CyberEssentials.BPATemplate.json @@ -0,0 +1,98 @@ +{ + "name": "CIPP Cyber Essentials Helper - Tenant view", + "style": "Tenant", + "Fields": [ + { + "name": "deviceregister", + "UseExistingInfo": false, + "FrontendFields": [ + { + "name": "Device Register", + "value": "deviceregister", + "desc": "These are all devices found in M365 to add to your CE Device Register.", + "formatter": "table" + } + ], + "StoreAs": "JSON", + "API": "Graph", + "ExtractFields": [ + "deviceName", + "lastSyncDateTime", + "osVersion", + "userPrincipalName", + "complianceState" + ], + "URL": "https://graph.microsoft.com/beta/deviceManagement/managedDevices" + }, + { + "name": "adminsTable", + "UseExistingInfo": false, + "FrontendFields": [ + { + "name": "Admins Table", + "value": "adminsTable", + "desc": "The list of admin accounts in your M365 environment. These must all be named and attached to actual users.", + "formatter": "table" + } + ], + "StoreAs": "JSON", + "API": "Graph", + "ExtractFields": ["displayName", "userPrincipalName"], + "URL": "https://graph.microsoft.com/beta/directoryRoles/roleTemplateId=62e90394-69f5-4237-9190-012177145e10/members" + }, + { + "name": "windowsProtectionState", + "UseExistingInfo": false, + "FrontendFields": [ + { + "name": "Defender List", + "value": "windowsProtectionState", + "formatter": "table", + "desc": "List of Defender protected workstations. Add this to your Malware Protection Audit List" + } + ], + "StoreAs": "JSON", + "API": "Graph", + "ExtractFields": ["windowsProtectionState"], + "parameters": {}, + "URL": "https://graph.microsoft.com/beta/deviceManagement/managedDevices?$expand=windowsProtectionState" + }, + { + "name": "detectedApps", + "UseExistingInfo": false, + "FrontendFields": [ + { + "name": "Detected Apps", + "value": "detectedApps", + "desc": "All Detected Software and their version. Add this to your software audit list", + "formatter": "table" + } + ], + "StoreAs": "JSON", + "API": "Graph", + "ExtractFields": ["displayName", "version", "platform", "publisher"], + "URL": "https://graph.microsoft.com/beta/deviceManagement/detectedApps" + }, + { + "name": "userRegistrationDetails", + "UseExistingInfo": false, + "FrontendFields": [ + { + "name": "User Registration Details", + "desc": "All MFA settings (Requires a P1 Subscription)", + "value": "userRegistrationDetails", + "formatter": "table" + } + ], + "StoreAs": "JSON", + "API": "Graph", + "ExtractFields": [ + "userDisplayName", + "isAdmin", + "isMFARegistered", + "defaultMFAMethod" + ], + "URL": "https://graph.microsoft.com/beta/reports/authenticationMethods/userRegistrationDetails" + } + ] +} diff --git a/DomainAnalyser_List/function.json b/DomainAnalyser_List/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/DomainAnalyser_List/function.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "bindings": [ - { - "authLevel": "anonymous", - "type": "httpTrigger", - "direction": "in", - "name": "Request", - "methods": [ - "get", - "post" - ] - }, - { - "type": "http", - "direction": "out", - "name": "Response" - } - ] -} \ No newline at end of file diff --git a/DomainAnalyser_List/run.ps1 b/DomainAnalyser_List/run.ps1 deleted file mode 100644 index 65a72671901f..000000000000 --- a/DomainAnalyser_List/run.ps1 +++ /dev/null @@ -1,42 +0,0 @@ -using namespace System.Net - -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) -$APIName = $TriggerMetadata.FunctionName -Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - -# Write to the Azure Functions log stream. -Write-Host 'PowerShell HTTP trigger function processed a request.' - -$DomainTable = Get-CIPPTable -Table 'Domains' - -# Get all the things - -if ($Request.Query.tenantFilter -ne 'AllTenants') { - $DomainTable.Filter = "TenantId eq '{0}'" -f $Request.Query.tenantFilter -} - -try { - # Extract json from table results - $Results = foreach ($DomainAnalyserResult in (Get-CIPPAzDataTableEntity @DomainTable).DomainAnalyser) { - try { - if (![string]::IsNullOrEmpty($DomainAnalyserResult)) { - $Object = $DomainAnalyserResult | ConvertFrom-Json - - if (($Request.Query.tenantFilter -eq 'AllTenants' -and $Object.Tenant -notin $Skiplist.Name) -or $Request.Query.tenantFilter -ne 'AllTenants') { - $Object.GUID = $Object.GUID -replace '[^a-zA-Z-]', '' - $Object - } - } - } catch {} - } -} catch { - $Results = @() -} - - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @($Results) - }) \ No newline at end of file diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecAddTrustedIP.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecAddTrustedIP.ps1 new file mode 100644 index 000000000000..db587ae67959 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecAddTrustedIP.ps1 @@ -0,0 +1,22 @@ +using namespace System.Net + +Function Invoke-ExecAddTrustedIP { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $Table = Get-CippTable -tablename 'trustedIps' + Add-CIPPAzDataTableEntity @Table -Entity @{ + PartitionKey = $request.query.tenantfilter + RowKey = $Request.query.ip + state = $request.query.State + } -Force + + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @{ results = "Added $($Request.query.ip) to database with state $($Request.query.state) for $($Request.query.tenantfilter)" } + }) +} \ No newline at end of file diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecCAExclusion.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecCAExclusion.ps1 new file mode 100644 index 000000000000..4dafed5af25a --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecCAExclusion.ps1 @@ -0,0 +1,51 @@ +using namespace System.Net + +Function Invoke-ExecCAExclusion { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $TriggerMetadata.FunctionName + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' + #If UserId is a guid, get the user's UPN + if ($Request.body.UserId -match '^[a-f0-9]{8}-([a-f0-9]{4}-){3}[a-f0-9]{12}$') { + $Username = (New-GraphGetRequest -uri "https://graph.microsoft.com/v1.0/users/$($Request.body.UserId)" -tenantid $Request.body.TenantFilter).userPrincipalName + } + if ($Request.body.vacation -eq 'true') { + $StartDate = $Request.body.StartDate + $TaskBody = @{ + TenantFilter = $Request.body.TenantFilter + Name = "Add CA Exclusion Vacation Mode: $Username - $($Request.body.TenantFilter)" + Command = @{ + value = 'Set-CIPPCAExclusion' + label = 'Set-CIPPCAExclusion' + } + Parameters = @{ + ExclusionType = 'Add' + UserID = $Request.body.UserID + PolicyId = $Request.body.PolicyId + UserName = $Username + } + ScheduledTime = $StartDate + } + Add-CIPPScheduledTask -Task $TaskBody -hidden $false + #Removal of the exclusion + $TaskBody.Parameters.ExclusionType = 'Remove' + $TaskBody.Name = "Remove CA Exclusion Vacation Mode: $username - $($Request.body.TenantFilter)" + $TaskBody.ScheduledTime = $Request.body.EndDate + Add-CIPPScheduledTask -Task $TaskBody -hidden $false + $body = @{ Results = "Successfully added vacation mode schedule for $Username." } + } else { + Set-CIPPCAExclusion -TenantFilter $Request.body.TenantFilter -ExclusionType $Request.body.ExclusionType -UserID $Request.body.UserID -PolicyId $Request.body.PolicyId -executingUser $request.headers.'x-ms-client-principal' -UserName $Username + } + + + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Body + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecGeoIPLookup.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecGeoIPLookup.ps1 index ebd5cab52f88..3410320f99a8 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecGeoIPLookup.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecGeoIPLookup.ps1 @@ -1,6 +1,6 @@ - using namespace System.Net +using namespace System.Net - Function Invoke-ExecGeoIPLookup { +Function Invoke-ExecGeoIPLookup { <# .FUNCTIONALITY Entrypoint @@ -8,24 +8,16 @@ [CmdletBinding()] param($Request, $TriggerMetadata) - $APIName = $TriggerMetadata.FunctionName -Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' -Write-Host $Request.Query.IP -$location = Get-CIPPGeoIPLocation -IP $Request.query.IP -$ARINInfo = Invoke-RestMethod -Uri "https://whois.arin.net/rest/ip/$($Request.Query.IP)" -Method Get -ContentType "application/json" -Headers @{Accept = "application/json" } -$LocationInfo = [pscustomobject]@{ - location = $location - arin = $ARINInfo - startaddress = $arininfo.net.startaddress.'$' - endAddress = $arininfo.net.endAddress.'$' - OrgRef = $arininfo.net.orgRef.'@NAME' - SubnetName = $arininfo.net.name.'$' -} + $APIName = $TriggerMetadata.FunctionName + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' + Write-Host $Request.Query.IP + $locationInfo = Get-CIPPGeoIPLocation -IP $Request.query.IP + -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $LocationInfo - }) + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $LocationInfo + }) - } +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecOffboardUser.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecOffboardUser.ps1 index 6e6e9970f39a..2391bd643995 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecOffboardUser.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecOffboardUser.ps1 @@ -8,6 +8,7 @@ Function Invoke-ExecOffboardUser { [CmdletBinding()] param($Request, $TriggerMetadata) try { + $APIName = 'ExecOffboardUser' Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' $Username = $request.body.user $Tenantfilter = $request.body.tenantfilter diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDomainAnalyser.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDomainAnalyser.ps1 new file mode 100644 index 000000000000..ef10d6a3505d --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDomainAnalyser.ps1 @@ -0,0 +1,39 @@ + +using namespace System.Net + +Function Invoke-ListDomainAnalyser { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + $DomainTable = Get-CIPPTable -Table 'Domains' + + # Get all the things + + if ($Request.Query.tenantFilter -ne 'AllTenants') { + $DomainTable.Filter = "TenantId eq '{0}'" -f $Request.Query.tenantFilter + } + + try { + # Extract json from table results + $Results = foreach ($DomainAnalyserResult in (Get-CIPPAzDataTableEntity @DomainTable).DomainAnalyser) { + try { + if (![string]::IsNullOrEmpty($DomainAnalyserResult)) { + $Object = $DomainAnalyserResult | ConvertFrom-Json -ErrorAction SilentlyContinue + $Object + } + } catch {} + } + } catch { + $Results = @() + } + + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @($Results) + }) +} \ No newline at end of file diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDomainHealth.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDomainHealth.ps1 index 695fb64ffa29..6d2d1d1106ef 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDomainHealth.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDomainHealth.ps1 @@ -142,6 +142,7 @@ Function Invoke-ListDomainHealth { } catch { Write-LogMessage -API $APINAME -tenant $($name) -user $request.headers.'x-ms-client-principal' -message "DNS Helper API failed. $($_.Exception.Message)" -Sev 'Error' $body = [pscustomobject]@{'Results' = "Failed. $($_.Exception.Message)" } + $StatusCode = [HttpStatusCode]::InternalServerError } # Associate values to output bindings by calling 'Push-OutputBinding'. diff --git a/Modules/CIPPCore/Public/Entrypoints/Push-ExecOnboardTenantQueue.ps1 b/Modules/CIPPCore/Public/Entrypoints/Push-ExecOnboardTenantQueue.ps1 index 1ed88b340cc4..6c12ad723332 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Push-ExecOnboardTenantQueue.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Push-ExecOnboardTenantQueue.ps1 @@ -224,35 +224,32 @@ Function Push-ExecOnboardTenantQueue { if ($AccessAssignments.status -notcontains 'pending') { $OnboardingSteps.Step3.Message = 'Group check: Access assignments are mapped and active' $OnboardingSteps.Step3.Status = 'succeeded' + if ($QueueItem.AddMissingGroups -eq $true) { + $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = 'Checking for missing groups for SAM user' }) + $SamUserId = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/me?`$select=id").id + $CurrentMemberships = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/me/transitiveMemberOf?`$select=id,displayName" + foreach ($Role in $QueueItem.Roles) { + if ($CurrentMemberships.id -notcontains $Role.GroupId) { + $PostBody = @{ + '@odata.id' = 'https://graph.microsoft.com/v1.0/directoryObjects/{0}' -f $SamUserId + } | ConvertTo-Json -Compress + try { + New-GraphPostRequest -uri "https://graph.microsoft.com/beta/groups/$($Role.GroupId)/members/`$ref" -body $PostBody -AsApp $true -NoAuthCheck $true + $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = "Added SAM user to $($Role.GroupName)" }) + } catch { + $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = "Failed to add SAM user to $($Role.GroupName) - $($_.Exception.Message)" }) + } + } + } + $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = 'SAM user group check completed' }) + } } else { $OnboardingSteps.Step3.Message = 'Group check: Access assignments are still pending, try again later' $OnboardingSteps.Step3.Status = 'failed' $TenantOnboarding.Status = 'failed' - $TenantOnboarding.OnboardingSteps = [string](ConvertTo-Json -InputObject $OnboardingSteps -Compress) - $TenantOnboarding.Logs = [string](ConvertTo-Json -InputObject @($Logs) -Compress) - Add-CIPPAzDataTableEntity @OnboardTable -Entity $TenantOnboarding -Force -ErrorAction Stop - return - } - } - if ($QueueItem.AddMissingGroups -eq $true) { - $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = 'Checking for missing groups for SAM user' }) - $SamUserId = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/me?`$select=id").id - $CurrentMemberships = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/me/transitiveMemberOf?`$select=id,displayName" - foreach ($Role in $QueueItem.Roles) { - if ($CurrentMemberships.id -notcontains $Role.GroupId) { - $PostBody = @{ - '@odata.id' = 'https://graph.microsoft.com/v1.0/directoryObjects/{0}' -f $SamUserId - } | ConvertTo-Json -Compress - try { - New-GraphPostRequest -uri "https://graph.microsoft.com/beta/groups/$($Role.GroupId)/members/`$ref" -body $PostBody -AsApp $true -NoAuthCheck $true - $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = "Added SAM user to $($Role.GroupName)" }) - } catch { - $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = "Failed to add SAM user to $($Role.GroupName) - $($_.Exception.Message)" }) - } - } } - $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = 'SAM user group check completed' }) } + $TenantOnboarding.OnboardingSteps = [string](ConvertTo-Json -InputObject $OnboardingSteps -Compress) $TenantOnboarding.Logs = [string](ConvertTo-Json -InputObject @($Logs) -Compress) Add-CIPPAzDataTableEntity @OnboardTable -Entity $TenantOnboarding -Force -ErrorAction Stop diff --git a/Modules/CIPPCore/Public/Invoke-CIPPWebhookProcessing.ps1 b/Modules/CIPPCore/Public/Invoke-CIPPWebhookProcessing.ps1 index 9e05e5f92bb5..1f698dc9f475 100644 --- a/Modules/CIPPCore/Public/Invoke-CIPPWebhookProcessing.ps1 +++ b/Modules/CIPPCore/Public/Invoke-CIPPWebhookProcessing.ps1 @@ -11,6 +11,7 @@ function Invoke-CippWebhookProcessing { ) $ConfigTable = get-cipptable -TableName 'SchedulerConfig' $LocationTable = Get-CIPPTable -TableName 'knownlocationdb' + $TrustedIPsTable = Get-CIPPTable -TableName 'trustedIps' $Alertconfig = Get-CIPPAzDataTableEntity @ConfigTable -Filter "Tenant eq '$tenantfilter'" if (!$Alertconfig) { $Alertconfig = Get-CIPPAzDataTableEntity @ConfigTable -Filter "Tenant eq 'AllTenants'" @@ -19,6 +20,8 @@ function Invoke-CippWebhookProcessing { if ($data.userId -eq 'Not Available') { $data.userId = $data.userKey } if ($data.Userkey -eq 'Not Available') { $data.Userkey = $data.userId } if ($data.clientip) { + $TrustedIps = Get-CIPPAzDataTableEntity @TrustedIPsTable -Filter "PartitionKey eq '$($TenantFilter)' and RowKey eq '$($data.clientip)' and state eq 'Trusted'" + Write-Host "TrustedIPs: $($TrustedIps | ConvertTo-Json -Depth 15 -Compress)" #First we perform a lookup in the knownlocationdb table to see if we have a location for this IP address. $Location = Get-CIPPAzDataTableEntity @LocationTable -Filter "RowKey eq '$($data.clientip)'" | Select-Object -Last 1 #If we have a location, we use that. If not, we perform a lookup in the GeoIP database. @@ -57,12 +60,12 @@ function Invoke-CippWebhookProcessing { return '' } - $AllowedLocations = ($Alertconfig.if | ConvertFrom-Json).allowedcountries.value + $AllowedLocations = ($Alertconfig.if | ConvertFrom-Json -ErrorAction SilentlyContinue).allowedcountries.value Write-Host "These are the allowed locations: $($AllowedLocations)" Write-Host "Operation: $($data.operation)" switch ($data.operation) { - { 'UserLoggedIn' -eq $data.operation -and $proxy -eq $true } { $data.operation = 'BadRepIP' } - { 'UserLoggedIn' -eq $data.operation -and $hosting -eq $true } { $data.operation = 'HostedIP' } + { 'UserLoggedIn' -eq $data.operation -and $proxy -eq $true -and !$TrustedIps } { $data.operation = 'BadRepIP' } + { 'UserLoggedIn' -eq $data.operation -and $hosting -eq $true -and !$TrustedIps } { $data.operation = 'HostedIP' } { 'UserLoggedIn' -eq $data.operation -and $Country -notin $AllowedLocations -and $data.ResultStatus -eq 'Success' -and $TableObj.ResultStatusDetail -eq 'Success' } { Write-Host "$($country) is not in $($AllowedLocations)" $data.operation = 'UserLoggedInFromUnknownLocation' @@ -75,7 +78,7 @@ function Invoke-CippWebhookProcessing { foreach ($AlertSetting in $Alertconfig) { $ifs = $AlertSetting.If | ConvertFrom-Json $Dos = $AlertSetting.execution | ConvertFrom-Json - if ($data.operation -notin $Ifs.selection -and $ifs.selection -ne 'AnyAlert' -and ($ifs.count -le 1 -and $ifs.selection -ne 'customField')) { + if ($data.operation -notin $Ifs.selection -and 'AnyAlert' -notin $ifs.selection -and ($ifs.count -le 1 -and $ifs.selection -ne 'customField')) { Write-Host 'Not an operation to do anything for. storing IP info' if ($data.ClientIP -and $data.operation -like '*LoggedIn*') { Write-Host 'Add IP and potential location to knownlocation db for this specific user.' @@ -192,11 +195,16 @@ function Invoke-CippWebhookProcessing { } } } + Write-Host 'Going to create the content' foreach ($action in $dos) { switch ($action.execute) { 'generatemail' { + Write-Host 'Going to create the email' $GenerateEmail = New-CIPPAlertTemplate -format 'html' -data $Data -LocationInfo $Location -ActionResults $ActionResults + Write-Host 'Going to send the mail' Send-CIPPAlert -Type 'email' -Title $GenerateEmail.title -HTMLContent $GenerateEmail.htmlcontent -TenantFilter $TenantFilter + Write-Host 'email should be sent' + } 'generatePSA' { $GenerateEmail = New-CIPPAlertTemplate -format 'html'-data $Data -LocationInfo $Location -ActionResults $ActionResults diff --git a/Modules/CIPPCore/Public/New-CIPPAlertTemplate.ps1 b/Modules/CIPPCore/Public/New-CIPPAlertTemplate.ps1 index 1eaeeda79a70..442d149133a9 100644 --- a/Modules/CIPPCore/Public/New-CIPPAlertTemplate.ps1 +++ b/Modules/CIPPCore/Public/New-CIPPAlertTemplate.ps1 @@ -3,12 +3,10 @@ function New-CIPPAlertTemplate { [Parameter(Mandatory = $true)] $Data, [Parameter(Mandatory = $true)] - [ValidateSet('html', 'json')] $Format, $LocationInfo, $ActionResults ) - $Appname = '[{"Application Name":"ACOM Azure Website","Application IDs":"23523755-3a2b-41ca-9315-f81f3f566a95"},{"Application Name":"AEM-DualAuth","Application IDs":"69893ee3-dd10-4b1c-832d-4870354be3d8"},{"Application Name":"ASM Campaign Servicing","Application IDs":"0cb7b9ec-5336-483b-bc31-b15b5788de71"},{"Application Name":"Azure Advanced Threat Protection","Application IDs":"7b7531ad-5926-4f2d-8a1d-38495ad33e17"},{"Application Name":"Azure Data Lake","Application IDs":"e9f49c6b-5ce5-44c8-925d-015017e9f7ad"},{"Application Name":"Azure Lab Services Portal","Application IDs":"835b2a73-6e10-4aa5-a979-21dfda45231c"},{"Application Name":"Azure Portal","Application IDs":"c44b4083-3bb0-49c1-b47d-974e53cbdf3c"},{"Application Name":"AzureSupportCenter","Application IDs":"37182072-3c9c-4f6a-a4b3-b3f91cacffce"},{"Application Name":"Bing","Application IDs":"9ea1ad79-fdb6-4f9a-8bc3-2b70f96e34c7"},{"Application Name":"CPIM Service","Application IDs":"bb2a2e3a-c5e7-4f0a-88e0-8e01fd3fc1f4"},{"Application Name":"CRM Power BI Integration","Application IDs":"e64aa8bc-8eb4-40e2-898b-cf261a25954f"},{"Application Name":"Dataverse","Application IDs":"00000007-0000-0000-c000-000000000000"},{"Application Name":"Enterprise Roaming and Backup","Application IDs":"60c8bde5-3167-4f92-8fdb-059f6176dc0f"},{"Application Name":"IAM Supportability","Application IDs":"a57aca87-cbc0-4f3c-8b9e-dc095fdc8978"},{"Application Name":"IrisSelectionFrontDoor","Application IDs":"16aeb910-ce68-41d1-9ac3-9e1673ac9575"},{"Application Name":"MCAPI Authorization Prod","Application IDs":"d73f4b35-55c9-48c7-8b10-651f6f2acb2e"},{"Application Name":"Media Analysis and Transformation Service","Application IDs":"944f0bd1-117b-4b1c-af26-804ed95e767e
0cd196ee-71bf-4fd6-a57c-b491ffd4fb1e"},{"Application Name":"Microsoft 365 Support Service","Application IDs":"ee272b19-4411-433f-8f28-5c13cb6fd407"},{"Application Name":"Microsoft App Access Panel","Application IDs":"0000000c-0000-0000-c000-000000000000"},{"Application Name":"Microsoft Approval Management","Application IDs":"65d91a3d-ab74-42e6-8a2f-0add61688c74
38049638-cc2c-4cde-abe4-4479d721ed44"},{"Application Name":"Microsoft Authentication Broker","Application IDs":"29d9ed98-a469-4536-ade2-f981bc1d605e"},{"Application Name":"Microsoft Azure CLI","Application IDs":"04b07795-8ddb-461a-bbee-02f9e1bf7b46"},{"Application Name":"Microsoft Azure PowerShell","Application IDs":"1950a258-227b-4e31-a9cf-717495945fc2"},{"Application Name":"Microsoft Bing Search","Application IDs":"cf36b471-5b44-428c-9ce7-313bf84528de"},{"Application Name":"Microsoft Bing Search for Microsoft Edge","Application IDs":"2d7f3606-b07d-41d1-b9d2-0d0c9296a6e8"},{"Application Name":"Microsoft Bing Default Search Engine","Application IDs":"1786c5ed-9644-47b2-8aa0-7201292175b6"},{"Application Name":"Microsoft Defender for Cloud Apps","Application IDs":"3090ab82-f1c1-4cdf-af2c-5d7a6f3e2cc7"},{"Application Name":"Microsoft Docs","Application IDs":"18fbca16-2224-45f6-85b0-f7bf2b39b3f3"},{"Application Name":"Microsoft Dynamics ERP","Application IDs":"00000015-0000-0000-c000-000000000000"},{"Application Name":"Microsoft Edge Insider Addons Prod","Application IDs":"6253bca8-faf2-4587-8f2f-b056d80998a7"},{"Application Name":"Microsoft Exchange Online Protection","Application IDs":"00000007-0000-0ff1-ce00-000000000000"},{"Application Name":"Microsoft Forms","Application IDs":"c9a559d2-7aab-4f13-a6ed-e7e9c52aec87"},{"Application Name":"Microsoft Graph","Application IDs":"00000003-0000-0000-c000-000000000000"},{"Application Name":"Microsoft Intune Web Company Portal","Application IDs":"74bcdadc-2fdc-4bb3-8459-76d06952a0e9"},{"Application Name":"Microsoft Intune Windows Agent","Application IDs":"fc0f3af4-6835-4174-b806-f7db311fd2f3"},{"Application Name":"Microsoft Learn","Application IDs":"18fbca16-2224-45f6-85b0-f7bf2b39b3f3"},{"Application Name":"Microsoft Office","Application IDs":"d3590ed6-52b3-4102-aeff-aad2292ab01c"},{"Application Name":"Microsoft Office 365 Portal","Application IDs":"00000006-0000-0ff1-ce00-000000000000"},{"Application Name":"Microsoft Office Web Apps Service","Application IDs":"67e3df25-268a-4324-a550-0de1c7f97287"},{"Application Name":"Microsoft Online Syndication Partner Portal","Application IDs":"d176f6e7-38e5-40c9-8a78-3998aab820e7"},{"Application Name":"Microsoft password reset service","Application IDs":"93625bc8-bfe2-437a-97e0-3d0060024faa"},{"Application Name":"Microsoft Power BI","Application IDs":"871c010f-5e61-4fb1-83ac-98610a7e9110"},{"Application Name":"Microsoft Storefronts","Application IDs":"28b567f6-162c-4f54-99a0-6887f387bbcc"},{"Application Name":"Microsoft Stream Portal","Application IDs":"cf53fce8-def6-4aeb-8d30-b158e7b1cf83"},{"Application Name":"Microsoft Substrate Management","Application IDs":"98db8bd6-0cc0-4e67-9de5-f187f1cd1b41"},{"Application Name":"Microsoft Support","Application IDs":"fdf9885b-dd37-42bf-82e5-c3129ef5a302"},{"Application Name":"Microsoft Teams","Application IDs":"1fec8e78-bce4-4aaf-ab1b-5451cc387264"},{"Application Name":"Microsoft Teams Services","Application IDs":"cc15fd57-2c6c-4117-a88c-83b1d56b4bbe"},{"Application Name":"Microsoft Teams Web Client","Application IDs":"5e3ce6c0-2b1f-4285-8d4b-75ee78787346"},{"Application Name":"Microsoft Whiteboard Services","Application IDs":"95de633a-083e-42f5-b444-a4295d8e9314"},{"Application Name":"O365 Suite UX","Application IDs":"4345a7b9-9a63-4910-a426-35363201d503"},{"Application Name":"Office 365 Exchange Online","Application IDs":"00000002-0000-0ff1-ce00-000000000000"},{"Application Name":"Office 365 Management","Application IDs":"00b41c95-dab0-4487-9791-b9d2c32c80f2"},{"Application Name":"Office 365 Search Service","Application IDs":"66a88757-258c-4c72-893c-3e8bed4d6899"},{"Application Name":"Office 365 SharePoint Online","Application IDs":"00000003-0000-0ff1-ce00-000000000000"},{"Application Name":"Office Delve","Application IDs":"94c63fef-13a3-47bc-8074-75af8c65887a"},{"Application Name":"Office Online Add-in SSO","Application IDs":"93d53678-613d-4013-afc1-62e9e444a0a5"},{"Application Name":"Office Online Client AAD- Augmentation Loop","Application IDs":"2abdc806-e091-4495-9b10-b04d93c3f040"},{"Application Name":"Office Online Client AAD- Loki","Application IDs":"b23dd4db-9142-4734-867f-3577f640ad0c"},{"Application Name":"Office Online Client AAD- Maker","Application IDs":"17d5e35f-655b-4fb0-8ae6-86356e9a49f5"},{"Application Name":"Office Online Client MSA- Loki","Application IDs":"b6e69c34-5f1f-4c34-8cdf-7fea120b8670"},{"Application Name":"Office Online Core SSO","Application IDs":"243c63a3-247d-41c5-9d83-7788c43f1c43"},{"Application Name":"Office Online Search","Application IDs":"a9b49b65-0a12-430b-9540-c80b3332c127"},{"Application Name":"Office.com","Application IDs":"4b233688-031c-404b-9a80-a4f3f2351f90"},{"Application Name":"Office365 Shell WCSS-Client","Application IDs":"89bee1f7-5e6e-4d8a-9f3d-ecd601259da7"},{"Application Name":"OfficeClientService","Application IDs":"0f698dd4-f011-4d23-a33e-b36416dcb1e6"},{"Application Name":"OfficeHome","Application IDs":"4765445b-32c6-49b0-83e6-1d93765276ca"},{"Application Name":"OfficeShredderWacClient","Application IDs":"4d5c2d63-cf83-4365-853c-925fd1a64357"},{"Application Name":"OMSOctopiPROD","Application IDs":"62256cef-54c0-4cb4-bcac-4c67989bdc40"},{"Application Name":"OneDrive SyncEngine","Application IDs":"ab9b8c07-8f02-4f72-87fa-80105867a763"},{"Application Name":"OneNote","Application IDs":"2d4d3d8e-2be3-4bef-9f87-7875a61c29de"},{"Application Name":"Outlook Mobile","Application IDs":"27922004-5251-4030-b22d-91ecd9a37ea4"},{"Application Name":"Partner Customer Delegated Admin Offline Processor","Application IDs":"a3475900-ccec-4a69-98f5-a65cd5dc5306"},{"Application Name":"Password Breach Authenticator","Application IDs":"bdd48c81-3a58-4ea9-849c-ebea7f6b6360"},{"Application Name":"Power BI Service","Application IDs":"00000009-0000-0000-c000-000000000000"},{"Application Name":"SharedWithMe","Application IDs":"ffcb16e8-f789-467c-8ce9-f826a080d987"},{"Application Name":"SharePoint Online Web Client Extensibility","Application IDs":"08e18876-6177-487e-b8b5-cf950c1e598c"},{"Application Name":"Signup","Application IDs":"b4bddae8-ab25-483e-8670-df09b9f1d0ea"},{"Application Name":"Skype for Business Online","Application IDs":"00000004-0000-0ff1-ce00-000000000000"},{"Application Name":"Sway","Application IDs":"905fcf26-4eb7-48a0-9ff0-8dcc7194b5ba"},{"Application Name":"Universal Store Native Client","Application IDs":"268761a2-03f3-40df-8a8b-c3db24145b6b"},{"Application Name":"Vortex [wsfed enabled]","Application IDs":"5572c4c0-d078-44ce-b81c-6cbf8d3ed39e"},{"Application Name":"Windows Azure Active Directory","Application IDs":"00000002-0000-0000-c000-000000000000"},{"Application Name":"Windows Azure Service Management API","Application IDs":"797f4846-ba00-4fd7-ba43-dac1f8f63013"},{"Application Name":"WindowsDefenderATP Portal","Application IDs":"a3b79187-70b2-4139-83f9-6016c58cd27b"},{"Application Name":"Windows Search","Application IDs":"26a7ee05-5602-4d76-a7ba-eae8b7b67941"},{"Application Name":"Windows Spotlight","Application IDs":"1b3c667f-cde3-4090-b60b-3d2abd0117f0"},{"Application Name":"Windows Store for Business","Application IDs":"45a330b1-b1ec-4cc1-9161-9f03992aa49f"},{"Application Name":"Yammer","Application IDs":"00000005-0000-0ff1-ce00-000000000000"},{"Application Name":"Yammer Web","Application IDs":"c1c74fed-04c9-4704-80dc-9f79a2e515cb"},{"Application Name":"Yammer Web Embed","Application IDs":"e1ef36fd-b883-4dbf-97f0-9ece4b576fc6"}]' | ConvertFrom-Json | Where-Object -Property 'Application IDs' -EQ $data.applicationId $HTMLTemplate = Get-Content 'TemplateEmail.HTML' -Raw | Out-String $Title = '' @@ -18,7 +16,7 @@ function New-CIPPAlertTemplate { $AfterButtonText = '' $RuleTable = '' $Table = '' - $LocationInfo = $LocationInfo | Select-Object *, -excludeproperty Etag, PartitionKey, RowKey, TimeStamp + $LocationInfo = $LocationInfo | Select-Object * -ExcludeProperty Etag, PartitionKey, RowKey, TimeStamp switch ($Data.Operation) { 'New-InboxRule' { $Title = "$($TenantFilter) - New Rule Detected for $($data.UserId)" @@ -177,9 +175,9 @@ function New-CIPPAlertTemplate { $LocationTable = ($LocationInfo | ConvertTo-Html -Fragment -As List | Out-String).Replace('', '
') $IntroText = $IntroText + "

The location information for this IP is as follows:

$LocationTable" } - $ButtonUrl = "$CIPPPURL/identity/administration/ViewBec?userId=$($data.ObjectId)&tenantDomain=$($data.OrganizationId)" - $ButtonText = 'User Management' - $AfterButtonText = '

If this is incorrect, use the user management screen to block the user and revoke the sessions

' + $ButtonUrl = "$CIPPPURL/tenant/tools/geoiplookup?ip=$($data.ClientIP)&SearchNow=true&customerId=$($data.OrganizationId)" + $ButtonText = 'Whitelist IP' + $AfterButtonText = '

If this is incorrect, you can whitelist the following IP.

' } 'HostedIP' { $Table = ($TableObj | ConvertTo-Html -Fragment -As List | Out-String).Replace('
', '
') @@ -191,9 +189,9 @@ function New-CIPPAlertTemplate { $LocationTable = ($LocationInfo | ConvertTo-Html -Fragment -As List | Out-String).Replace('
', '
') $IntroText = $IntroText + "

The location information for this IP is as follows:

$LocationTable" } - $ButtonUrl = "$CIPPPURL/identity/administration/ViewBec?userId=$($data.ObjectId)&tenantDomain=$($data.OrganizationId)" - $ButtonText = 'User Management' - $AfterButtonText = '

If this is incorrect, use the user management screen to block the user and revoke the sessions

' + $ButtonUrl = "$CIPPPURL/tenant/tools/geoiplookup?ip=$($data.ClientIP)&SearchNow=true&customerId=$($data.OrganizationId)" + $ButtonText = 'Whitelist IP' + $AfterButtonText = '

If this is incorrect, you can whitelist the following IP.

' } 'Add service principal.' { if ($Appname) { $AppName = $AppName.'Application Name' } else { $appName = $data.ApplicationId } diff --git a/Modules/CIPPCore/Public/New-CIPPCAPolicy.ps1 b/Modules/CIPPCore/Public/New-CIPPCAPolicy.ps1 index 345d5fa7af97..ee1a1002cc0b 100644 --- a/Modules/CIPPCore/Public/New-CIPPCAPolicy.ps1 +++ b/Modules/CIPPCore/Public/New-CIPPCAPolicy.ps1 @@ -6,30 +6,25 @@ function New-CIPPCAPolicy { $TenantFilter, $State, $Overwrite, - $APIName = "Create CA Policy", + $APIName = 'Create CA Policy', $ExecutingUser ) function Remove-EmptyArrays ($Object) { if ($Object -is [Array]) { foreach ($Item in $Object) { Remove-EmptyArrays $Item } - } - elseif ($Object -is [HashTable]) { + } elseif ($Object -is [HashTable]) { foreach ($Key in @($Object.get_Keys())) { if ($Object[$Key] -is [Array] -and $Object[$Key].get_Count() -eq 0) { $Object.Remove($Key) - } - else { Remove-EmptyArrays $Object[$Key] } + } else { Remove-EmptyArrays $Object[$Key] } } - } - elseif ($Object -is [PSCustomObject]) { + } elseif ($Object -is [PSCustomObject]) { foreach ($Name in @($Object.psobject.properties.Name)) { if ($Object.$Name -is [Array] -and $Object.$Name.get_Count() -eq 0) { $Object.PSObject.Properties.Remove($Name) - } - elseif ($object.$name -eq $null) { + } elseif ($object.$name -eq $null) { $Object.PSObject.Properties.Remove($Name) - } - else { Remove-EmptyArrays $Object.$Name } + } else { Remove-EmptyArrays $Object.$Name } } } } @@ -46,8 +41,7 @@ function New-CIPPCAPolicy { if ($State -and $State -ne 'donotchange') { $Jsonobj.state = $State } - } - catch { + } catch { # no issues here. } @@ -55,19 +49,18 @@ function New-CIPPCAPolicy { $LocationLookupTable = foreach ($locations in $jsonobj.LocationInfo) { foreach ($location in $locations) { if (!$location.displayName) { continue } - $CheckExististing = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/identity/conditionalAccess/namedLocations" -tenantid $TenantFilter + $CheckExististing = New-GraphGETRequest -uri 'https://graph.microsoft.com/beta/identity/conditionalAccess/namedLocations' -tenantid $TenantFilter if ($Location.displayName -in $CheckExististing.displayName) { [pscustomobject]@{ id = ($CheckExististing | Where-Object -Property displayName -EQ $Location.displayName).id name = ($CheckExististing | Where-Object -Property displayName -EQ $Location.displayName).displayName } - 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" + 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 { + } else { $Body = ConvertTo-Json -InputObject $Location - $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" + $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]@{ id = $GraphRequest.id name = $GraphRequest.displayName @@ -75,7 +68,7 @@ function New-CIPPCAPolicy { } } } - Write-Host "here5" + Write-Host 'here5' foreach ($location in $JSONObj.conditions.locations.includeLocations) { Write-Host "Replacting $location" @@ -97,29 +90,26 @@ function New-CIPPCAPolicy { $RawJSON = $JSONObj | ConvertTo-Json -Depth 10 Write-Host $RawJSON try { - Write-Host "Checking" - $CheckExististing = New-GraphGETRequest -uri "https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies" -tenantid $TenantFilter + Write-Host 'Checking' + $CheckExististing = New-GraphGETRequest -uri 'https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies' -tenantid $TenantFilter if ($displayname -in $CheckExististing.displayName) { if ($Overwrite -ne $true) { Throw "Conditional Access Policy with Display Name $($Displayname) Already exists" return $false - } - else { - Write-Host "overwriting" + } else { + Write-Host 'overwriting' $PatchRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/identity/conditionalAccess/policies/$($CheckExististing.id)" -tenantid $tenantfilter -type PATCH -body $RawJSON - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($Tenant) -message "Updated Conditional Access Policy $($JSONObj.Displayname) to the template standard." -Sev "Info" + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($Tenant) -message "Updated Conditional Access Policy $($JSONObj.Displayname) to the template standard." -Sev 'Info' return "Updated policy $displayname for $tenantfilter" } - } - else { - Write-Host "Creating" - $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/identity/conditionalAccess/policies" -tenantid $tenantfilter -type POST -body $RawJSON - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($Tenant) -message "Added Conditional Access Policy $($JSONObj.Displayname)" -Sev "Info" + } else { + Write-Host 'Creating' + $CreateRequest = New-GraphPOSTRequest -uri 'https://graph.microsoft.com/beta/identity/conditionalAccess/policies' -tenantid $tenantfilter -type POST -body $RawJSON + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($Tenant) -message "Added Conditional Access Policy $($JSONObj.Displayname)" -Sev 'Info' return "Created policy $displayname for $tenantfilter" } - } - catch { + } catch { throw "Failed to create or update conditional access rule $($JSONObj.displayName): $($_.exception.message)" - Write-LogMessage -API "Standards" -tenant $tenant -message "Failed to create or update conditional access rule $($JSONObj.displayName): $($_.exception.message) " -sev "Error" + Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to create or update conditional access rule $($JSONObj.displayName): $($_.exception.message) " -sev 'Error' } } diff --git a/Modules/CIPPCore/Public/Set-CIPPCAExclusion.ps1 b/Modules/CIPPCore/Public/Set-CIPPCAExclusion.ps1 new file mode 100644 index 000000000000..888a90749cd8 --- /dev/null +++ b/Modules/CIPPCore/Public/Set-CIPPCAExclusion.ps1 @@ -0,0 +1,41 @@ +function Set-CIPPCAExclusion { + [CmdletBinding()] + param( + $TenantFilter, + $ExclusionType, + $UserID, + $PolicyId, + $Username, + $executingUser + ) + try { + $CheckExististing = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/identity/conditionalAccess/policies/$($PolicyId)" -tenantid $TenantFilter + if ($ExclusionType -eq 'add') { + $NewExclusions = [pscustomobject]@{ + conditions = [pscustomobject]@{ users = [pscustomobject]@{ + excludeUsers = @($CheckExististing.conditions.users.excludeUsers + $UserID) + } + } + } + $RawJson = ConvertTo-Json -Depth 10 -InputObject $NewExclusions + New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/identity/conditionalAccess/policies/$($CheckExististing.id)" -tenantid $tenantfilter -type PATCH -body $RawJSON + + } + + if ($ExclusionType -eq 'remove') { + $NewExclusions = [pscustomobject]@{ + conditions = [pscustomobject]@{ users = [pscustomobject]@{ + excludeUsers = @($CheckExististing.conditions.users.excludeUsers | Where-Object { $_ -ne $UserID }) + } + } + } + $RawJson = ConvertTo-Json -Depth 10 -InputObject $NewExclusions + New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/identity/conditionalAccess/policies/$($CheckExististing.id)" -tenantid $tenantfilter -type PATCH -body $RawJSON + } + "Successfully performed $($ExclusionType) exclusion for $username from policy $($PolicyId)" + Write-LogMessage -user $executingUser -API 'Set-CIPPConditionalAccessExclusion' -message "Successfully performed $($ExclusionType) exclusion for $username from policy $($PolicyId)" -Sev 'Info' -tenant $TenantFilter + } catch { + "Failed to $($ExclusionType) user exclusion for $username from policy $($PolicyId): $_" + Write-LogMessage -user $executingUser -API 'Set-CIPPConditionalAccessExclusion' -message "Failed to $($ExclusionType) user exclusion for $username from policy $($PolicyId): $_" -Sev 'Error' -tenant $TenantFilter + } +} \ No newline at end of file diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableMailTips.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableMailTips.ps1 new file mode 100644 index 000000000000..51991bf57f9e --- /dev/null +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableMailTips.ps1 @@ -0,0 +1,42 @@ +function Invoke-CIPPStandardEnableMailTips { + <# + .FUNCTIONALITY + Internal + #> + + param($Tenant, $Settings) + + if ($Settings.remediate) { + + + try { + New-ExoRequest -tenantid $Tenant -cmdlet 'Set-OrganizationConfig' -cmdparams @{ MailTipsAllTipsEnabled = $true; MailTipsExternalRecipientsTipsEnabled = $true; MailTipsGroupMetricsEnabled = $true; MailTipsLargeAudienceThreshold = $Settings.MailTipsLargeAudienceThreshold } + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Enabled all MailTips' -sev Info + } catch { + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to enable all MailTips: $($_.exception.message)" -sev Error + } + } + + + if ($Settings.alert -or $Settings.report) { + $MailTipsState = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-OrganizationConfig' | Select-Object MailTipsAllTipsEnabled, MailTipsExternalRecipientsTipsEnabled, MailTipsGroupMetricsEnabled, MailTipsLargeAudienceThreshold + + if ($Settings.alert) { + if ($MailTipsState.MailTipsAllTipsEnabled -and $MailTipsState.MailTipsExternalRecipientsTipsEnabled -and $MailTipsState.MailTipsGroupMetricsEnabled -and $MailTipsState.MailTipsLargeAudienceThreshold -eq $Settings.MailTipsLargeAudienceThreshold) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'All MailTips are enabled' -sev Info + } else { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Not all MailTips are enabled' -sev Alert + } + } + + if ($Settings.report) { + + if ($MailTipsState.MailTipsAllTipsEnabled -and $MailTipsState.MailTipsExternalRecipientsTipsEnabled -and $MailTipsState.MailTipsGroupMetricsEnabled -and $MailTipsState.MailTipsLargeAudienceThreshold -eq $Settings.MailTipsLargeAudienceThreshold) { + $MailTipsState = $true + } else { + $MailTipsState = $false + } + Add-CIPPBPAField -FieldName 'MailTipsEnabled' -FieldValue [bool]$MailTipsState -StoreAs bool -Tenant $tenant + } + } +} \ No newline at end of file diff --git a/Modules/CippExtensions/Private/Get-HaloMapping.ps1 b/Modules/CippExtensions/Private/Get-HaloMapping.ps1 index d86753f29306..adfdd8e72102 100644 --- a/Modules/CippExtensions/Private/Get-HaloMapping.ps1 +++ b/Modules/CippExtensions/Private/Get-HaloMapping.ps1 @@ -24,8 +24,10 @@ function Get-HaloMapping { $i++ $pagecount = [Math]::Ceiling($Result.record_count / 999) } while ($i -le $pagecount) + } catch { + Write-LogMessage -Message "Could not get HaloPSA Clients, error: $($_.Exception.Message)" -Level Error -tenant 'CIPP' -API 'HaloMapping' + $RawHaloClients = @(@{name = "Could not get HaloPSA Clients, error: $($_.Exception.Message)" }) } - catch { $RawHaloClients = @() } $HaloClients = $RawHaloClients | ForEach-Object { [PSCustomObject]@{ name = $_.name diff --git a/Modules/CippExtensions/Private/New-HaloPSATicket.ps1 b/Modules/CippExtensions/Private/New-HaloPSATicket.ps1 index 2b1b18486d7b..3dd96ee6eb28 100644 --- a/Modules/CippExtensions/Private/New-HaloPSATicket.ps1 +++ b/Modules/CippExtensions/Private/New-HaloPSATicket.ps1 @@ -15,7 +15,7 @@ function New-HaloPSATicket { usertype = 1 userlookup = @{ id = -1 - lookupdisplay = "Enter Details Manually" + lookupdisplay = 'Enter Details Manually' } client_id = $client site_id = $null @@ -28,20 +28,19 @@ function New-HaloPSATicket { } if ($Configuration.TicketType) { - $object | Add-Member -MemberType NoteProperty -Name "tickettype_id" -Value $Configuration.TicketType + $object | Add-Member -MemberType NoteProperty -Name 'tickettype_id' -Value $Configuration.TicketType } #use the token to create a new ticket in HaloPSA $body = ConvertTo-Json -Compress -Depth 10 -InputObject @($Object) - Write-Host "Sending ticket to HaloPSA" + Write-Host 'Sending ticket to HaloPSA' Write-Host $body try { $Ticket = Invoke-RestMethod -Uri "$($Configuration.ResourceURL)/Tickets" -ContentType 'application/json; charset=utf-8' -Method Post -Body $body -Headers @{Authorization = "Bearer $($token.access_token)" } - } - catch { - Write-Host "Failed to send ticket to HaloPSA" - Write-Host $_.Exception.Message + } catch { + Write-LogMessage -message "Failed to send ticket to HaloPSA: $($_.Exception.Message)" -API 'HaloPSATicket' -sev Error + Write-Host "Failed to send ticket to HaloPSA: $($_.Exception.Message)" } } \ No newline at end of file diff --git a/PublicWebhooks/run.ps1 b/PublicWebhooks/run.ps1 index 124f05bd761a..2a44861c59c9 100644 --- a/PublicWebhooks/run.ps1 +++ b/PublicWebhooks/run.ps1 @@ -3,7 +3,7 @@ using namespace System.Net # Input bindings are passed in via param block. param($Request, $TriggerMetadata) - +Set-Location (Get-Item $PSScriptRoot).Parent.FullName $WebhookTable = Get-CIPPTable -TableName webhookTable $Webhooks = Get-CIPPAzDataTableEntity @WebhookTable Write-Host 'Received request' diff --git a/PublicWebhooksProcess/run.ps1 b/PublicWebhooksProcess/run.ps1 index 69e153f60e01..50bbde87cfb2 100644 --- a/PublicWebhooksProcess/run.ps1 +++ b/PublicWebhooksProcess/run.ps1 @@ -30,7 +30,7 @@ if ($Request.query.CIPPID -in $Webhooks.RowKey) { Write-Host "Webhook TenantFilter: $TenantFilter" $ConfigTable = get-cipptable -TableName 'SchedulerConfig' $Alertconfig = Get-CIPPAzDataTableEntity @ConfigTable | Where-Object { $_.Tenant -eq $TenantFilter -or $_.Tenant -eq 'AllTenants' } - $Operations = ($AlertConfig.if | ConvertFrom-Json -ErrorAction SilentlyContinue).selection, 'UserLoggedIn' + $Operations = ($AlertConfig.if | ConvertFrom-Json -ErrorAction SilentlyContinue).selection + 'UserLoggedIn' $Webhookinfo = $Webhooks | Where-Object -Property RowKey -EQ $Request.query.CIPPID #Increased download efficiency: only download the data we need for processing. Todo: Change this to load from table or dynamic source. $MappingTable = [pscustomobject]@{ @@ -53,14 +53,16 @@ if ($Request.query.CIPPID -in $Webhooks.RowKey) { #Compare $Operations to $MappingTable. If there is a match, we make a new variable called $LogsToDownload #Example: $Operations = 'UserLoggedIn', 'Set-InboxRule' makes : $LogsToDownload = @('Audit.AzureActiveDirectory',Audit.Exchange) $LogsToDownload = $Operations | Where-Object { $MappingTable.$_ } | ForEach-Object { $MappingTable.$_ } - if ($ReceivedItem.ContentType -in $LogsToDownload -or $LogsToDownload -contains 'AnyLog') { + Write-Host "Our operations: $Operations" + Write-Host "Logs to download: $LogsToDownload" + if ($ReceivedItem.ContentType -in $LogsToDownload -or 'AnyLog' -in $LogsToDownload) { $Data = New-GraphPostRequest -type GET -uri "https://manage.office.com/api/v1.0/$($ReceivedItem.tenantId)/activity/feed/audit/$($ReceivedItem.contentid)" -tenantid $TenantFilter -scope 'https://manage.office.com/.default' } else { Write-Host "No data to download for $($ReceivedItem.ContentType)" continue } Write-Host "Data found: $($data.count) items" - $DataToProcess = $Data | Where-Object -Property Operation -In $Operations + $DataToProcess = if ('anylog' -NotIn $LogsToDownload) { $Data | Where-Object -Property Operation -In $Operations } else { $Data } Write-Host "Data to process found: $($DataToProcess.count) items" foreach ($Item in $DataToProcess) { Write-Host "Processing $($item.operation)" @@ -68,7 +70,7 @@ if ($Request.query.CIPPID -in $Webhooks.RowKey) { } } } catch { - Write-Host "Webhook Failed: $($_.Exception.Message)" + Write-Host "Webhook Failed: $($_.Exception.Message). Line number $($_.InvocationInfo.ScriptLineNumber)" } } diff --git a/version_latest.txt b/version_latest.txt index 14d8a90bcd7a..ec4595317e77 100644 --- a/version_latest.txt +++ b/version_latest.txt @@ -1 +1 @@ -4.9.6 \ No newline at end of file +4.9.8 \ No newline at end of file