diff --git a/.github/workflows/ninjaone_cipp426ns.yml b/.github/workflows/ninjaone_cipp426ns.yml new file mode 100644 index 000000000000..6df7b1bab0e9 --- /dev/null +++ b/.github/workflows/ninjaone_cipp426ns.yml @@ -0,0 +1,29 @@ +# Docs for the Azure Web Apps Deploy action: https://github.com/azure/functions-action +# More GitHub Actions for Azure: https://github.com/Azure/actions + +name: Build and deploy Powershell project to Azure Function App - cipp426ns + +on: + push: + branches: + - NinjaOne + workflow_dispatch: + +env: + AZURE_FUNCTIONAPP_PACKAGE_PATH: '.' # set this to the path to your web app project, defaults to the repository root + +jobs: + build-and-deploy: + runs-on: windows-latest + steps: + - name: 'Checkout GitHub Action' + uses: actions/checkout@v2 + + - name: 'Run Azure Functions Action' + uses: Azure/functions-action@v1 + id: fa + with: + app-name: 'cipp426ns' + slot-name: 'Production' + package: ${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }} + publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_198DAF92160A4302B5AA0C145DE72796 }} diff --git a/.gitignore b/.gitignore index e052ecc4c278..0311022a9306 100644 --- a/.gitignore +++ b/.gitignore @@ -7,5 +7,4 @@ chocoapps.cache Cache_* Logs ExcludedTenants -Config SendNotifications/config.json diff --git a/AddAPDevice/function.json b/AddAPDevice/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/AddAPDevice/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/AddAlert/function.json b/AddAlert/function.json deleted file mode 100644 index 1de186148741..000000000000 --- a/AddAlert/function.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "bindings": [ - { - "authLevel": "anonymous", - "type": "httpTrigger", - "direction": "in", - "name": "Request", - "methods": ["get", "post"] - }, - { - "type": "http", - "direction": "out", - "name": "Response" - }, - { - "type": "queue", - "direction": "out", - "name": "Subscription", - "queueName": "AlertSubscriptions" - } - ] -} diff --git a/AddAlert/run.ps1 b/AddAlert/run.ps1 deleted file mode 100644 index 13e890b456d7..000000000000 --- a/AddAlert/run.ps1 +++ /dev/null @@ -1,94 +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 = ($Request.body | Select-Object Select_*).psobject.properties.value -$Results = foreach ($Tenant in $tenants) { - try { - $TenantID = if ($tenant -ne 'AllTenants') { - (get-tenants | Where-Object -Property defaultDomainName -EQ $Tenant).customerId - } - else { - 'AllTenants' - } - if ($Request.body.SetAlerts) { - $CompleteObject = @{ - tenant = $tenant - tenantid = $TenantID - AdminPassword = [bool]$Request.body.AdminPassword - DefenderMalware = [bool]$Request.body.DefenderMalware - DefenderStatus = [bool]$Request.body.DefenderStatus - MFAAdmins = [bool]$Request.body.MFAAdmins - MFAAlertUsers = [bool]$Request.body.MFAAlertUsers - NewGA = [bool]$Request.body.NewGA - NewRole = [bool]$Request.body.NewRole - QuotaUsed = [bool]$Request.body.QuotaUsed - UnusedLicenses = [bool]$Request.body.UnusedLicenses - OverusedLicenses = [bool]$Request.body.OverusedLicenses - AppSecretExpiry = [bool]$Request.body.AppSecretExpiry - ApnCertExpiry = [bool]$Request.body.ApnCertExpiry - VppTokenExpiry = [bool]$Request.body.VppTokenExpiry - DepTokenExpiry = [bool]$Request.body.DepTokenExpiry - NoCAConfig = [bool]$Request.body.NoCAConfig - SecDefaultsUpsell = [bool]$Request.body.SecDefaultsUpsell - SharePointQuota = [bool]$Request.body.SharePointQuota - ExpiringLicenses = [bool]$Request.body.ExpiringLicenses - type = 'Alert' - RowKey = $TenantID - PartitionKey = 'Alert' - } - - $Table = get-cipptable -TableName 'SchedulerConfig' - Add-CIPPAzDataTableEntity @Table -Entity $CompleteObject -Force - } - $URL = ($request.headers.'x-ms-original-url').split('/api') | Select-Object -First 1 - if ($Tenant -eq 'AllTenants') { - Get-Tenants | ForEach-Object { - foreach ($eventType in $Request.body.EventTypes.value) { - $params = @{ - TenantFilter = $_.defaultDomainName - auditLogAPI = $true - operations = ($Request.body.Operations.value -join ',') - allowedLocations = ($Request.body.AllowedLocations.value -join ',') - BaseURL = $URL - EventType = $eventType - ExecutingUser = $Request.headers.'x-ms-client-principal' - } - Push-OutputBinding -Name Subscription -Value $Params - } - } - } - else { - foreach ($eventType in $Request.body.EventTypes.value) { - $params = @{ - TenantFilter = $tenant - auditLogAPI = $true - operations = ($Request.body.Operations.value -join ',') - allowedLocations = ($Request.body.AllowedLocations.value -join ',') - BaseURL = $URL - EventType = $eventType - ExecutingUser = $Request.headers.'x-ms-client-principal' - } - New-CIPPGraphSubscription @params - } - } - "Successfully added Alert for $($Tenant) to queue." - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $tenant -message "Successfully added Alert for $($Tenant) to queue." -Sev 'Info' - } - catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $tenant -message "Failed to add Alert for for $($Tenant) to queue" -Sev 'Error' - "Failed to add Alert for for $($Tenant) to queue $($_.Exception.message)" - } -} - -$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/AddAutopilotConfig/function.json b/AddAutopilotConfig/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/AddAutopilotConfig/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/AddCAPolicy/function.json b/AddCAPolicy/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/AddCAPolicy/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/AddCATemplate/function.json b/AddCATemplate/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/AddCATemplate/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/AddChocoApp/function.json b/AddChocoApp/function.json deleted file mode 100644 index 3bd167116eae..000000000000 --- a/AddChocoApp/function.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "bindings": [ - { - "authLevel": "anonymous", - "type": "httpTrigger", - "direction": "in", - "name": "Request", - "methods": [ - "get", - "post" - ] - }, - { - "type": "http", - "direction": "out", - "name": "Response" - }, - { - "name": "starter", - "direction": "in", - "type": "durableClient" - } - ] -} \ No newline at end of file diff --git a/AddContact/function.json b/AddContact/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/AddContact/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/AddDefenderDeployment/function.json b/AddDefenderDeployment/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/AddDefenderDeployment/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/AddEnrollment/function.json b/AddEnrollment/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/AddEnrollment/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/AddExConnector/function.json b/AddExConnector/function.json deleted file mode 100644 index bec6849b58ab..000000000000 --- a/AddExConnector/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/AddExConnectorTemplate/function.json b/AddExConnectorTemplate/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/AddExConnectorTemplate/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/AddGroup/function.json b/AddGroup/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/AddGroup/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/AddGroupTemplate/function.json b/AddGroupTemplate/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/AddGroupTemplate/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/AddGuest/function.json b/AddGuest/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/AddGuest/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/AddIntuneTemplate/function.json b/AddIntuneTemplate/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/AddIntuneTemplate/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/AddMSPApp/function.json b/AddMSPApp/function.json deleted file mode 100644 index 3bd167116eae..000000000000 --- a/AddMSPApp/function.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "bindings": [ - { - "authLevel": "anonymous", - "type": "httpTrigger", - "direction": "in", - "name": "Request", - "methods": [ - "get", - "post" - ] - }, - { - "type": "http", - "direction": "out", - "name": "Response" - }, - { - "name": "starter", - "direction": "in", - "type": "durableClient" - } - ] -} \ No newline at end of file diff --git a/AddNamedLocation/function.json b/AddNamedLocation/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/AddNamedLocation/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/AddOfficeApp/function.json b/AddOfficeApp/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/AddOfficeApp/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/AddPolicy/function.json b/AddPolicy/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/AddPolicy/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/AddScheduledItem/function.json b/AddScheduledItem/function.json deleted file mode 100644 index b0ca1676cc0b..000000000000 --- a/AddScheduledItem/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/AddScheduledItem/run.ps1 b/AddScheduledItem/run.ps1 deleted file mode 100644 index 6f64a255a725..000000000000 --- a/AddScheduledItem/run.ps1 +++ /dev/null @@ -1,9 +0,0 @@ -using namespace System.Net -param($Request, $TriggerMetadata) -$APIName = $TriggerMetadata.FunctionName -Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' -$Result = Add-CIPPScheduledTask -Task $Request.body -hidden $false -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @{ Results = $Result } - }) \ No newline at end of file diff --git a/AddSharedMailbox/function.json b/AddSharedMailbox/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/AddSharedMailbox/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/AddSpamFilter/function.json b/AddSpamFilter/function.json deleted file mode 100644 index bec6849b58ab..000000000000 --- a/AddSpamFilter/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/AddSpamFilterTemplate/function.json b/AddSpamFilterTemplate/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/AddSpamFilterTemplate/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/AddStandardsDeploy/function.json b/AddStandardsDeploy/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/AddStandardsDeploy/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/AddTeam/function.json b/AddTeam/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/AddTeam/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/AddTransportRule/function.json b/AddTransportRule/function.json deleted file mode 100644 index bec6849b58ab..000000000000 --- a/AddTransportRule/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/AddTransportTemplate/function.json b/AddTransportTemplate/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/AddTransportTemplate/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/AddUser/function.json b/AddUser/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/AddUser/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/AddWinGetApp/WinGetBody.json b/AddWinGetApp/WinGetBody.json deleted file mode 100644 index bc0552931ac6..000000000000 --- a/AddWinGetApp/WinGetBody.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "@odata.type": "#microsoft.graph.winGetApp", - "displayName": "Display Name value", - "description": "Description value", - "publisher": "Publisher value", - "isFeatured": true, - "uploadState": 11, - "publishingState": "processing", - "packageIdentifier": "", - "installExperience": { - "@odata.type": "microsoft.graph.winGetAppInstallExperience", - "runAsAccount": "user" - } -} diff --git a/AddWinGetApp/function.json b/AddWinGetApp/function.json deleted file mode 100644 index 3bd167116eae..000000000000 --- a/AddWinGetApp/function.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "bindings": [ - { - "authLevel": "anonymous", - "type": "httpTrigger", - "direction": "in", - "name": "Request", - "methods": [ - "get", - "post" - ] - }, - { - "type": "http", - "direction": "out", - "name": "Response" - }, - { - "name": "starter", - "direction": "in", - "type": "durableClient" - } - ] -} \ No newline at end of file diff --git a/Applications_Upload/run.ps1 b/Applications_Upload/run.ps1 index c5cabfdcc96e..a92637a42882 100644 --- a/Applications_Upload/run.ps1 +++ b/Applications_Upload/run.ps1 @@ -4,41 +4,38 @@ $Filter = "PartitionKey eq 'apps' and RowKey eq '$name'" Set-Location (Get-Item $PSScriptRoot).Parent.FullName $ChocoApp = (Get-CIPPAzDataTableEntity @Table -filter $Filter).JSON | ConvertFrom-Json $intuneBody = $ChocoApp.IntuneBody -$tenants = if ($chocoapp.Tenant -eq "AllTenants") { +$tenants = if ($chocoapp.Tenant -eq 'AllTenants') { (Get-tenants).defaultDomainName -} -else { +} else { $chocoapp.Tenant } -if ($chocoApp.type -eq "MSPApp") { +if ($chocoApp.type -eq 'MSPApp') { [xml]$Intunexml = Get-Content "AddMSPApp\$($ChocoApp.MSPAppName).app.xml" $intunewinFilesize = (Get-Item "AddMSPApp\$($ChocoApp.MSPAppName).intunewin") $Infile = "AddMSPApp\$($ChocoApp.MSPAppName).intunewin" -} -else { - [xml]$Intunexml = Get-Content "AddChocoApp\choco.app.xml" - $intunewinFilesize = (Get-Item "AddChocoApp\IntunePackage.intunewin") +} else { + [xml]$Intunexml = Get-Content 'AddChocoApp\choco.app.xml' + $intunewinFilesize = (Get-Item 'AddChocoApp\IntunePackage.intunewin') $Infile = "AddChocoApp\$($intunexml.ApplicationInfo.FileName)" } $assignTo = $ChocoApp.AssignTo $AssignToIntent = $ChocoApp.InstallationIntent -$Baseuri = "https://graph.microsoft.com/beta/deviceAppManagement/mobileApps" +$Baseuri = 'https://graph.microsoft.com/beta/deviceAppManagement/mobileApps' $ContentBody = ConvertTo-Json @{ name = $intunexml.ApplicationInfo.FileName size = [int64]$intunexml.ApplicationInfo.UnencryptedContentSize sizeEncrypted = [int64]($intunewinFilesize).length } $ClearRow = Get-CIPPAzDataTableEntity @Table -Filter $Filter -$RemoveCacheFile = if ($chocoapp.Tenant -ne "AllTenants") { +$RemoveCacheFile = if ($chocoapp.Tenant -ne 'AllTenants') { Remove-AzDataTableEntity @Table -Entity $clearRow -} -else { +} else { $Table.Force = $true Add-CIPPAzDataTableEntity @Table -Entity @{ JSON = "$($ChocoApp | ConvertTo-Json)" RowKey = "$($ClearRow.RowKey)" - PartitionKey = "apps" - status = "Deployed" + PartitionKey = 'apps' + status = 'Deployed' } } $EncBody = @{ @@ -58,62 +55,60 @@ foreach ($tenant in $tenants) { $ApplicationList = (New-graphGetRequest -Uri $baseuri -tenantid $Tenant) | Where-Object { $_.DisplayName -eq $ChocoApp.ApplicationName } if ($ApplicationList.displayname.count -ge 1) { - Write-LogMessage -api "AppUpload" -tenant $($Tenant) -message "$($ChocoApp.ApplicationName) exists. Skipping this application" -Sev "Info" + Write-LogMessage -api 'AppUpload' -tenant $($Tenant) -message "$($ChocoApp.ApplicationName) exists. Skipping this application" -Sev 'Info' continue } - if ($chocoApp.type -eq "WinGet") { - Write-Host "Winget!" + if ($chocoApp.type -eq 'WinGet') { + Write-Host 'Winget!' Write-Host ($intuneBody | ConvertTo-Json -Compress) $NewApp = New-GraphPostRequest -Uri $baseuri -Body ($intuneBody | ConvertTo-Json -Compress) -Type POST -tenantid $tenant Start-Sleep -Milliseconds 200 - Write-LogMessage -api "AppUpload" -tenant $($Tenant) -message "$($ChocoApp.ApplicationName) uploaded as WinGet app." -Sev "Info" - if ($AssignTo -ne "On") { + Write-LogMessage -api 'AppUpload' -tenant $($Tenant) -message "$($ChocoApp.ApplicationName) uploaded as WinGet app." -Sev 'Info' + if ($AssignTo -ne 'On') { $intent = if ($AssignToIntent) { 'Uninstall' } else { 'Required' } - Set-CIPPAssignedApplication -ApplicationId $NewApp.Id -Intent $intent -TenantFilter $tenant -groupName "$AssignTo" -AppType "WinGet" + Set-CIPPAssignedApplication -ApplicationId $NewApp.Id -Intent $intent -TenantFilter $tenant -groupName "$AssignTo" -AppType 'WinGet' } - Write-LogMessage -api "AppUpload" -tenant $($Tenant) -message "$($ChocoApp.ApplicationName) Successfully created" -Sev "Info" + Write-LogMessage -api 'AppUpload' -tenant $($Tenant) -message "$($ChocoApp.ApplicationName) Successfully created" -Sev 'Info' exit 0 - } - else { + } else { $NewApp = New-GraphPostRequest -Uri $baseuri -Body ($intuneBody | ConvertTo-Json) -Type POST -tenantid $tenant } $ContentReq = New-GraphPostRequest -Uri "$($BaseURI)/$($NewApp.id)/microsoft.graph.win32lobapp/contentVersions/1/files/" -Body $ContentBody -Type POST -tenantid $tenant do { - $AzFileUri = New-graphGetRequest -Uri "$($BaseURI)/$($NewApp.id)/microsoft.graph.win32lobapp/contentVersions/1/files/$($ContentReq.id)" -tenantid $tenant - if ($AZfileuri.uploadState -like "*fail*") { break } + $AzFileUri = New-graphGetRequest -Uri "$($BaseURI)/$($NewApp.id)/microsoft.graph.win32lobapp/contentVersions/1/files/$($ContentReq.id)" -tenantid $tenant + if ($AZfileuri.uploadState -like '*fail*') { break } Start-Sleep -Milliseconds 300 } while ($AzFileUri.AzureStorageUri -eq $null) $chunkSizeInBytes = 4mb [byte[]]$bytes = [System.IO.File]::ReadAllBytes($($intunewinFilesize.fullname)) - $chunks = [Math]::Ceiling($bytes.Length / $chunkSizeInBytes); - $id = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($chunks.ToString("0000"))) + $chunks = [Math]::Ceiling($bytes.Length / $chunkSizeInBytes) + $id = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($chunks.ToString('0000'))) #For anyone that reads this, The maximum chunk size is 100MB for blob storage, so we can upload it as one part and just give it the single ID. Easy :) - $Upload = Invoke-RestMethod -Uri "$($AzFileUri.azureStorageUri)&comp=block&blockid=$id" -Method Put -Headers @{'x-ms-blob-type' = 'BlockBlob' } -InFile $inFile -ContentType "application/octet-stream" + $Upload = Invoke-RestMethod -Uri "$($AzFileUri.azureStorageUri)&comp=block&blockid=$id" -Method Put -Headers @{'x-ms-blob-type' = 'BlockBlob' } -InFile $inFile -ContentType 'application/octet-stream' $ConfirmUpload = Invoke-RestMethod -Uri "$($AzFileUri.azureStorageUri)&comp=blocklist" -Method Put -Body "$id" - $CommitReq = New-graphPostRequest -Uri "$($BaseURI)/$($NewApp.id)/microsoft.graph.win32lobapp/contentVersions/1/files/$($ContentReq.id)/commit" -Body $EncBody -Type POST -tenantid $tenant + $CommitReq = New-graphPostRequest -Uri "$($BaseURI)/$($NewApp.id)/microsoft.graph.win32lobapp/contentVersions/1/files/$($ContentReq.id)/commit" -Body $EncBody -Type POST -tenantid $tenant do { $CommitStateReq = New-graphGetRequest -Uri "$($BaseURI)/$($NewApp.id)/microsoft.graph.win32lobapp/contentVersions/1/files/$($ContentReq.id)" -tenantid $tenant - if ($CommitStateReq.uploadState -like "*fail*") { - Write-LogMessage -api "AppUpload" -tenant $($Tenant) -message "$($ChocoApp.ApplicationName) Commit failed. Please check if app uploaded succesful" -Sev "Warning" + if ($CommitStateReq.uploadState -like '*fail*') { + Write-LogMessage -api 'AppUpload' -tenant $($Tenant) -message "$($ChocoApp.ApplicationName) Commit failed. Please check if app uploaded succesful" -Sev 'Warning' break } Start-Sleep -Milliseconds 300 - } while ($CommitStateReq.uploadState -eq "commitFilePending") + } while ($CommitStateReq.uploadState -eq 'commitFilePending') $CommitFinalizeReq = New-graphPostRequest -Uri "$($BaseURI)/$($NewApp.id)" -tenantid $tenant -Body '{"@odata.type":"#microsoft.graph.win32lobapp","committedContentVersion":"1"}' -type PATCH - Write-LogMessage -api "AppUpload" -tenant $($Tenant) -message "Added Application $($chocoApp.ApplicationName)" -Sev "Info" - if ($AssignTo -ne "On") { + Write-LogMessage -api 'AppUpload' -tenant $($Tenant) -message "Added Application $($chocoApp.ApplicationName)" -Sev 'Info' + if ($AssignTo -ne 'On') { $intent = if ($AssignToIntent) { 'Uninstall' } else { 'Required' } - Set-CIPPAssignedApplication -ApplicationId $NewApp.Id -Intent $intent -TenantFilter $tenant -groupName "$AssignTo" -AppType "Win32Lob" + Set-CIPPAssignedApplication -ApplicationId $NewApp.Id -Intent $intent -TenantFilter $tenant -groupName "$AssignTo" -AppType 'Win32Lob' } - Write-LogMessage -api "AppUpload" -tenant $($Tenant) -message "Successfully added Application" -Sev "Info" - } - catch { + Write-LogMessage -api 'AppUpload' -tenant $($Tenant) -message 'Successfully added Application' -Sev 'Info' + } catch { "Failed to add Application for $($Tenant): $($_.Exception.Message)" - Write-LogMessage -api "AppUpload" -tenant $($Tenant) -message "Failed adding Application $($ChocoApp.ApplicationName). Error: $($_.Exception.Message)" -Sev "Error" + Write-LogMessage -api 'AppUpload' -tenant $($Tenant) -message "Failed adding Application $($ChocoApp.ApplicationName). Error: $($_.Exception.Message)" -Sev 'Error' continue } diff --git a/BestPracticeAnalyser_All/run.ps1 b/BestPracticeAnalyser_All/run.ps1 index 71b679a9c66a..ddd92560ccda 100644 --- a/BestPracticeAnalyser_All/run.ps1 +++ b/BestPracticeAnalyser_All/run.ps1 @@ -92,6 +92,9 @@ $AddRow = foreach ($Template in $templates) { 'string' { $Result.Add($field.Name, [string]$FieldInfo) } + 'percentage' { + + } } } catch { Write-LogMessage -API 'BPA' -tenant $tenant -message "Error storing $($field.Name) for $($TenantName.displayName) with GUID $($TenantName.customerId). Error: $($_.Exception.Message)" -sev Error diff --git a/BestPracticeAnalyser_GetQueue/run.ps1 b/BestPracticeAnalyser_GetQueue/run.ps1 index baca4447eea1..0e2792c8075c 100644 --- a/BestPracticeAnalyser_GetQueue/run.ps1 +++ b/BestPracticeAnalyser_GetQueue/run.ps1 @@ -1,5 +1,4 @@ param($name) -Set-Location (Get-Item $PSScriptRoot).Parent.FullName #$Skiplist = (Get-Content ExcludedTenants -ErrorAction SilentlyContinue | ConvertFrom-Csv -Delimiter "|" -Header "name", "date", "user").name $Tenants = Get-Tenants #Get-Content ".\tenants.cache.json" | ConvertFrom-Json | Where-Object {$Skiplist -notcontains $_.defaultDomainName} diff --git a/Config/49a8069e-3b46-4680-a035-9250bc675446.CATemplate.json b/Config/49a8069e-3b46-4680-a035-9250bc675446.CATemplate.json index c3fda26a115a..5e9afa63f143 100644 --- a/Config/49a8069e-3b46-4680-a035-9250bc675446.CATemplate.json +++ b/Config/49a8069e-3b46-4680-a035-9250bc675446.CATemplate.json @@ -1,41 +1,41 @@ -{ - "state": "enabled", - "grantControls": { - "builtInControls": ["mfa"], - "operator": "OR", - "termsOfUse": [], - "customAuthenticationFactors": [] - }, - "conditions": { - "times": null, - "locations": null, - "signInRiskLevels": [], - "devices": null, - "deviceStates": null, - "users": { - "excludeRoles": [], - "excludeUsers": [], - "excludeGroups": [], - "includeUsers": ["All"], - "includeRoles": [], - "includeGroups": [] - }, - "servicePrincipalRiskLevels": [], - "userRiskLevels": [], - "clientAppTypes": [ - "exchangeActiveSync", - "browser", - "mobileAppsAndDesktopClients", - "other" - ], - "platforms": null, - "clientApplications": null, - "applications": { - "includeApplications": ["All"], - "includeUserActions": [], - "includeAuthenticationContextClassReferences": [], - "excludeApplications": [] - } - }, - "displayName": "Enforce Multi factor authentication for each application" -} +{ + "state": "enabled", + "grantControls": { + "builtInControls": ["mfa"], + "operator": "OR", + "termsOfUse": [], + "customAuthenticationFactors": [] + }, + "conditions": { + "times": null, + "locations": null, + "signInRiskLevels": [], + "devices": null, + "deviceStates": null, + "users": { + "excludeRoles": [], + "excludeUsers": [], + "excludeGroups": [], + "includeUsers": ["All"], + "includeRoles": [], + "includeGroups": [] + }, + "servicePrincipalRiskLevels": [], + "userRiskLevels": [], + "clientAppTypes": [ + "exchangeActiveSync", + "browser", + "mobileAppsAndDesktopClients", + "other" + ], + "platforms": null, + "clientApplications": null, + "applications": { + "includeApplications": ["All"], + "includeUserActions": [], + "includeAuthenticationContextClassReferences": [], + "excludeApplications": [] + } + }, + "displayName": "Enforce Multi factor authentication for each application" +} diff --git a/Config/4d9206b0-4f96-41e6-86a5-f78cdcff5069.IntuneTemplate.json b/Config/4d9206b0-4f96-41e6-86a5-f78cdcff5069.IntuneTemplate.json index 3fd6ff12fb5b..f5951d846e4c 100644 --- a/Config/4d9206b0-4f96-41e6-86a5-f78cdcff5069.IntuneTemplate.json +++ b/Config/4d9206b0-4f96-41e6-86a5-f78cdcff5069.IntuneTemplate.json @@ -1,7 +1,7 @@ -{ - "Displayname": "CIPP Default: Set screen lock time to 5 minutes", - "Description": "Sets the screen to lock after 5 minutes of inactivity.", - "RAWJson": "{\"name\":\"Set Screen Lockout to 5 minutes\",\"description\":\"\",\"platforms\":\"windows10\",\"technologies\":\"mdm\",\"roleScopeTagIds\":[\"0\"],\"settings\":[{\"@odata.type\":\"#microsoft.graph.deviceManagementConfigurationSetting\",\"settingInstance\":{\"@odata.type\":\"#microsoft.graph.deviceManagementConfigurationSimpleSettingInstance\",\"settingDefinitionId\":\"device_vendor_msft_policy_config_localpoliciessecurityoptions_interactivelogon_machineinactivitylimit_v2\",\"simpleSettingValue\":{\"@odata.type\":\"#microsoft.graph.deviceManagementConfigurationIntegerSettingValue\",\"value\":300}}}]}", - "Type": "Catalog", - "GUID": "4d9206b0-4f96-41e6-86a5-f78cdcff5069.IntuneTemplate.json" -} +{ + "Displayname": "CIPP Default: Set screen lock time to 5 minutes", + "Description": "Sets the screen to lock after 5 minutes of inactivity.", + "RAWJson": "{\"name\":\"Set Screen Lockout to 5 minutes\",\"description\":\"\",\"platforms\":\"windows10\",\"technologies\":\"mdm\",\"roleScopeTagIds\":[\"0\"],\"settings\":[{\"@odata.type\":\"#microsoft.graph.deviceManagementConfigurationSetting\",\"settingInstance\":{\"@odata.type\":\"#microsoft.graph.deviceManagementConfigurationSimpleSettingInstance\",\"settingDefinitionId\":\"device_vendor_msft_policy_config_localpoliciessecurityoptions_interactivelogon_machineinactivitylimit_v2\",\"simpleSettingValue\":{\"@odata.type\":\"#microsoft.graph.deviceManagementConfigurationIntegerSettingValue\",\"value\":300}}}]}", + "Type": "Catalog", + "GUID": "4d9206b0-4f96-41e6-86a5-f78cdcff5069.IntuneTemplate.json" +} diff --git a/Config/7547f73c-3cb0-460c-a4bd-391944908007.IntuneTemplate.json b/Config/7547f73c-3cb0-460c-a4bd-391944908007.IntuneTemplate.json index 9cf2094dae99..fde8371a4af5 100644 --- a/Config/7547f73c-3cb0-460c-a4bd-391944908007.IntuneTemplate.json +++ b/Config/7547f73c-3cb0-460c-a4bd-391944908007.IntuneTemplate.json @@ -1,7 +1,7 @@ -{ - "Displayname": "CIPP Default: 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", - "GUID": "7547f73c-3cb0-460c-a4bd-391944908007.IntuneTemplate.json" -} +{ + "Displayname": "CIPP Default: 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", + "GUID": "7547f73c-3cb0-460c-a4bd-391944908007.IntuneTemplate.json" +} diff --git a/Config/7b41924e-3051-4a23-b0d0-8cdeadc2c05a.IntuneTemplate.json b/Config/7b41924e-3051-4a23-b0d0-8cdeadc2c05a.IntuneTemplate.json index b7e696cc9b81..2dabd1a426af 100644 --- a/Config/7b41924e-3051-4a23-b0d0-8cdeadc2c05a.IntuneTemplate.json +++ b/Config/7b41924e-3051-4a23-b0d0-8cdeadc2c05a.IntuneTemplate.json @@ -1,7 +1,7 @@ -{ - "Displayname": "CIPP Default: Enable Onedrive Silent Logon and Known Folder Move", - "Description": "This policy enables Onedrive Silent Logon and Known Folder move", - "RAWJson": "{\n\"added\":[\n{\n\"enabled\":true,\n\"presentationValues\":[],\n\"definition@odata.bind\":\"https://graph.microsoft.com/beta/deviceManagement/groupPolicyDefinitions('9a4db949-29e4-4e31-a129-bf2b88d8fa1b')\"\n},\n{\n\"enabled\":true,\n\"presentationValues\":[\n{\n\"@odata.type\":\"#microsoft.graph.groupPolicyPresentationValueText\",\n\"value\":\"%tenantid%\",\n\"presentation@odata.bind\":\"https://graph.microsoft.com/beta/deviceManagement/groupPolicyDefinitions('39147fa2-6c5e-437b-8264-19b50b891709')/presentations('fbefbbdf-5382-477c-8b6c-71f4a06e2805')\"\n},\n{\n\"@odata.type\":\"#microsoft.graph.groupPolicyPresentationValueText\",\n\"value\":\"0\",\n\"presentation@odata.bind\":\"https://graph.microsoft.com/beta/deviceManagement/groupPolicyDefinitions('39147fa2-6c5e-437b-8264-19b50b891709')/presentations('35c82072-a93b-4022-be14-8684c2f6fcc2')\"\n}\n],\n\"definition@odata.bind\":\"https://graph.microsoft.com/beta/deviceManagement/groupPolicyDefinitions('39147fa2-6c5e-437b-8264-19b50b891709')\"\n},\n{\n\"enabled\":true,\n\"presentationValues\":[],\n\"definition@odata.bind\":\"https://graph.microsoft.com/beta/deviceManagement/groupPolicyDefinitions('81c07ba0-7512-402d-b1f6-00856975cfab')\"\n},\n{\n\"enabled\":true,\n\"presentationValues\":[],\n\"definition@odata.bind\":\"https://graph.microsoft.com/beta/deviceManagement/groupPolicyDefinitions('61b07a01-7e60-4127-b086-f6b32458a5c5')\"\n},\n],\n\"updated\":[],\n\"deletedIds\":[]\n}", - "Type": "Admin", - "GUID": "7b41924e-3051-4a23-b0d0-8cdeadc2c05a.IntuneTemplate.json" -} +{ + "Displayname": "CIPP Default: Enable Onedrive Silent Logon and Known Folder Move", + "Description": "This policy enables Onedrive Silent Logon and Known Folder move", + "RAWJson": "{\n\"added\":[\n{\n\"enabled\":true,\n\"presentationValues\":[],\n\"definition@odata.bind\":\"https://graph.microsoft.com/beta/deviceManagement/groupPolicyDefinitions('9a4db949-29e4-4e31-a129-bf2b88d8fa1b')\"\n},\n{\n\"enabled\":true,\n\"presentationValues\":[\n{\n\"@odata.type\":\"#microsoft.graph.groupPolicyPresentationValueText\",\n\"value\":\"%tenantid%\",\n\"presentation@odata.bind\":\"https://graph.microsoft.com/beta/deviceManagement/groupPolicyDefinitions('39147fa2-6c5e-437b-8264-19b50b891709')/presentations('fbefbbdf-5382-477c-8b6c-71f4a06e2805')\"\n},\n{\n\"@odata.type\":\"#microsoft.graph.groupPolicyPresentationValueText\",\n\"value\":\"0\",\n\"presentation@odata.bind\":\"https://graph.microsoft.com/beta/deviceManagement/groupPolicyDefinitions('39147fa2-6c5e-437b-8264-19b50b891709')/presentations('35c82072-a93b-4022-be14-8684c2f6fcc2')\"\n}\n],\n\"definition@odata.bind\":\"https://graph.microsoft.com/beta/deviceManagement/groupPolicyDefinitions('39147fa2-6c5e-437b-8264-19b50b891709')\"\n},\n{\n\"enabled\":true,\n\"presentationValues\":[],\n\"definition@odata.bind\":\"https://graph.microsoft.com/beta/deviceManagement/groupPolicyDefinitions('81c07ba0-7512-402d-b1f6-00856975cfab')\"\n},\n{\n\"enabled\":true,\n\"presentationValues\":[],\n\"definition@odata.bind\":\"https://graph.microsoft.com/beta/deviceManagement/groupPolicyDefinitions('61b07a01-7e60-4127-b086-f6b32458a5c5')\"\n},\n],\n\"updated\":[],\n\"deletedIds\":[]\n}", + "Type": "Admin", + "GUID": "7b41924e-3051-4a23-b0d0-8cdeadc2c05a.IntuneTemplate.json" +} diff --git a/Config/7e06b0de-0469-4aae-89be-d83c44b5799f.IntuneTemplate.json b/Config/7e06b0de-0469-4aae-89be-d83c44b5799f.IntuneTemplate.json index 3e7e82b550fb..cc0fa7def31d 100644 --- a/Config/7e06b0de-0469-4aae-89be-d83c44b5799f.IntuneTemplate.json +++ b/Config/7e06b0de-0469-4aae-89be-d83c44b5799f.IntuneTemplate.json @@ -1,7 +1,7 @@ -{ - "Displayname": "CIPP Default: Enable Bitlocker Encryption for OS drives", - "Description": "Enables Bitlocker and stores the key in Azure AD for system Drives", - "RAWJson": "{\"id\":\"00000000-0000-0000-0000-000000000000\",\"displayName\":\"CIPP: Enable Bitlocker Encryption\",\"roleScopeTagIds\":[\"0\"],\"@odata.type\":\"#microsoft.graph.windows10EndpointProtectionConfiguration\",\"applicationGuardEnabledOptions\":\"notConfigured\",\"firewallCertificateRevocationListCheckMethod\":\"deviceDefault\",\"firewallPacketQueueingMethod\":\"deviceDefault\",\"deviceGuardLocalSystemAuthorityCredentialGuardSettings\":\"notConfigured\",\"defenderSecurityCenterNotificationsFromApp\":\"notConfigured\",\"windowsDefenderTamperProtection\":\"notConfigured\",\"defenderSecurityCenterITContactDisplay\":\"notConfigured\",\"xboxServicesAccessoryManagementServiceStartupMode\":\"manual\",\"xboxServicesLiveAuthManagerServiceStartupMode\":\"manual\",\"xboxServicesLiveGameSaveServiceStartupMode\":\"manual\",\"xboxServicesLiveNetworkingServiceStartupMode\":\"manual\",\"applicationGuardBlockClipboardSharing\":\"notConfigured\",\"defenderPreventCredentialStealingType\":\"notConfigured\",\"defenderAdobeReaderLaunchChildProcess\":\"notConfigured\",\"defenderOfficeCommunicationAppsLaunchChildProcess\":\"notConfigured\",\"defenderAdvancedRansomewareProtectionType\":\"notConfigured\",\"defenderNetworkProtectionType\":\"notConfigured\",\"localSecurityOptionsFormatAndEjectOfRemovableMediaAllowedUser\":\"notConfigured\",\"localSecurityOptionsSmartCardRemovalBehavior\":\"lockWorkstation\",\"localSecurityOptionsInformationDisplayedOnLockScreen\":\"notConfigured\",\"localSecurityOptionsMinimumSessionSecurityForNtlmSspBasedClients\":\"none\",\"localSecurityOptionsMinimumSessionSecurityForNtlmSspBasedServers\":\"none\",\"lanManagerAuthenticationLevel\":\"lmAndNltm\",\"localSecurityOptionsAdministratorElevationPromptBehavior\":\"notConfigured\",\"localSecurityOptionsStandardUserElevationPromptBehavior\":\"notConfigured\",\"userRightsAccessCredentialManagerAsTrustedCaller\":null,\"userRightsLocalLogOn\":null,\"userRightsAllowAccessFromNetwork\":null,\"userRightsActAsPartOfTheOperatingSystem\":null,\"userRightsBackupData\":null,\"userRightsChangeSystemTime\":null,\"userRightsCreateGlobalObjects\":null,\"userRightsCreatePageFile\":null,\"userRightsCreatePermanentSharedObjects\":null,\"userRightsCreateSymbolicLinks\":null,\"userRightsCreateToken\":null,\"userRightsDebugPrograms\":null,\"userRightsBlockAccessFromNetwork\":null,\"userRightsDenyLocalLogOn\":null,\"userRightsRemoteDesktopServicesLogOn\":null,\"userRightsDelegation\":null,\"userRightsGenerateSecurityAudits\":null,\"userRightsImpersonateClient\":null,\"userRightsIncreaseSchedulingPriority\":null,\"userRightsLoadUnloadDrivers\":null,\"userRightsLockMemory\":null,\"userRightsManageAuditingAndSecurityLogs\":null,\"userRightsManageVolumes\":null,\"userRightsModifyFirmwareEnvironment\":null,\"userRightsModifyObjectLabels\":null,\"userRightsProfileSingleProcess\":null,\"userRightsRemoteShutdown\":null,\"userRightsRestoreData\":null,\"userRightsTakeOwnership\":null,\"bitLockerRecoveryPasswordRotation\":\"notConfigured\",\"bitLockerPrebootRecoveryMsgURLOption\":\"default\",\"bitLockerEncryptDevice\":true,\"bitLockerDisableWarningForOtherDiskEncryption\":true,\"bitLockerAllowStandardUserEncryption\":true,\"bitLockerSyntheticSystemDrivePolicybitLockerDriveRecovery\":true,\"applicationGuardAllowPrintToPDF\":false,\"applicationGuardAllowPrintToXPS\":false,\"applicationGuardAllowPrintToLocalPrinters\":false,\"applicationGuardAllowPrintToNetworkPrinters\":false,\"bitLockerFixedDrivePolicy\":{\"requireEncryptionForWriteAccess\":false,\"recoveryOptions\":null,\"encryptionMethod\":null},\"bitLockerRemovableDrivePolicy\":{\"requireEncryptionForWriteAccess\":false,\"encryptionMethod\":null},\"bitLockerSystemDrivePolicy\":{\"startupAuthenticationRequired\":true,\"startupAuthenticationTpmUsage\":\"allowed\",\"startupAuthenticationTpmPinUsage\":\"allowed\",\"startupAuthenticationTpmKeyUsage\":\"allowed\",\"startupAuthenticationTpmPinAndKeyUsage\":\"allowed\",\"startupAuthenticationBlockWithoutTpmChip\":false,\"minimumPinLength\":null,\"recoveryOptions\":{\"blockDataRecoveryAgent\":false,\"recoveryPasswordUsage\":\"allowed\",\"recoveryKeyUsage\":\"allowed\",\"enableRecoveryInformationSaveToStore\":true,\"recoveryInformationToStore\":\"passwordAndKey\",\"enableBitLockerAfterRecoveryInformationToStore\":true},\"prebootRecoveryEnableMessageAndUrl\":false,\"encryptionMethod\":null},\"firewallProfileDomain\":null,\"firewallProfilePrivate\":null,\"firewallProfilePublic\":null,\"deviceGuardEnableVirtualizationBasedSecurity\":false,\"deviceGuardEnableSecureBootWithDMA\":false}", - "Type": "Device", - "GUID": "7e06b0de-0469-4aae-89be-d83c44b5799f.IntuneTemplate.json" -} +{ + "Displayname": "CIPP Default: Enable Bitlocker Encryption for OS drives", + "Description": "Enables Bitlocker and stores the key in Azure AD for system Drives", + "RAWJson": "{\"id\":\"00000000-0000-0000-0000-000000000000\",\"displayName\":\"CIPP: Enable Bitlocker Encryption\",\"roleScopeTagIds\":[\"0\"],\"@odata.type\":\"#microsoft.graph.windows10EndpointProtectionConfiguration\",\"applicationGuardEnabledOptions\":\"notConfigured\",\"firewallCertificateRevocationListCheckMethod\":\"deviceDefault\",\"firewallPacketQueueingMethod\":\"deviceDefault\",\"deviceGuardLocalSystemAuthorityCredentialGuardSettings\":\"notConfigured\",\"defenderSecurityCenterNotificationsFromApp\":\"notConfigured\",\"windowsDefenderTamperProtection\":\"notConfigured\",\"defenderSecurityCenterITContactDisplay\":\"notConfigured\",\"xboxServicesAccessoryManagementServiceStartupMode\":\"manual\",\"xboxServicesLiveAuthManagerServiceStartupMode\":\"manual\",\"xboxServicesLiveGameSaveServiceStartupMode\":\"manual\",\"xboxServicesLiveNetworkingServiceStartupMode\":\"manual\",\"applicationGuardBlockClipboardSharing\":\"notConfigured\",\"defenderPreventCredentialStealingType\":\"notConfigured\",\"defenderAdobeReaderLaunchChildProcess\":\"notConfigured\",\"defenderOfficeCommunicationAppsLaunchChildProcess\":\"notConfigured\",\"defenderAdvancedRansomewareProtectionType\":\"notConfigured\",\"defenderNetworkProtectionType\":\"notConfigured\",\"localSecurityOptionsFormatAndEjectOfRemovableMediaAllowedUser\":\"notConfigured\",\"localSecurityOptionsSmartCardRemovalBehavior\":\"lockWorkstation\",\"localSecurityOptionsInformationDisplayedOnLockScreen\":\"notConfigured\",\"localSecurityOptionsMinimumSessionSecurityForNtlmSspBasedClients\":\"none\",\"localSecurityOptionsMinimumSessionSecurityForNtlmSspBasedServers\":\"none\",\"lanManagerAuthenticationLevel\":\"lmAndNltm\",\"localSecurityOptionsAdministratorElevationPromptBehavior\":\"notConfigured\",\"localSecurityOptionsStandardUserElevationPromptBehavior\":\"notConfigured\",\"userRightsAccessCredentialManagerAsTrustedCaller\":null,\"userRightsLocalLogOn\":null,\"userRightsAllowAccessFromNetwork\":null,\"userRightsActAsPartOfTheOperatingSystem\":null,\"userRightsBackupData\":null,\"userRightsChangeSystemTime\":null,\"userRightsCreateGlobalObjects\":null,\"userRightsCreatePageFile\":null,\"userRightsCreatePermanentSharedObjects\":null,\"userRightsCreateSymbolicLinks\":null,\"userRightsCreateToken\":null,\"userRightsDebugPrograms\":null,\"userRightsBlockAccessFromNetwork\":null,\"userRightsDenyLocalLogOn\":null,\"userRightsRemoteDesktopServicesLogOn\":null,\"userRightsDelegation\":null,\"userRightsGenerateSecurityAudits\":null,\"userRightsImpersonateClient\":null,\"userRightsIncreaseSchedulingPriority\":null,\"userRightsLoadUnloadDrivers\":null,\"userRightsLockMemory\":null,\"userRightsManageAuditingAndSecurityLogs\":null,\"userRightsManageVolumes\":null,\"userRightsModifyFirmwareEnvironment\":null,\"userRightsModifyObjectLabels\":null,\"userRightsProfileSingleProcess\":null,\"userRightsRemoteShutdown\":null,\"userRightsRestoreData\":null,\"userRightsTakeOwnership\":null,\"bitLockerRecoveryPasswordRotation\":\"notConfigured\",\"bitLockerPrebootRecoveryMsgURLOption\":\"default\",\"bitLockerEncryptDevice\":true,\"bitLockerDisableWarningForOtherDiskEncryption\":true,\"bitLockerAllowStandardUserEncryption\":true,\"bitLockerSyntheticSystemDrivePolicybitLockerDriveRecovery\":true,\"applicationGuardAllowPrintToPDF\":false,\"applicationGuardAllowPrintToXPS\":false,\"applicationGuardAllowPrintToLocalPrinters\":false,\"applicationGuardAllowPrintToNetworkPrinters\":false,\"bitLockerFixedDrivePolicy\":{\"requireEncryptionForWriteAccess\":false,\"recoveryOptions\":null,\"encryptionMethod\":null},\"bitLockerRemovableDrivePolicy\":{\"requireEncryptionForWriteAccess\":false,\"encryptionMethod\":null},\"bitLockerSystemDrivePolicy\":{\"startupAuthenticationRequired\":true,\"startupAuthenticationTpmUsage\":\"allowed\",\"startupAuthenticationTpmPinUsage\":\"allowed\",\"startupAuthenticationTpmKeyUsage\":\"allowed\",\"startupAuthenticationTpmPinAndKeyUsage\":\"allowed\",\"startupAuthenticationBlockWithoutTpmChip\":false,\"minimumPinLength\":null,\"recoveryOptions\":{\"blockDataRecoveryAgent\":false,\"recoveryPasswordUsage\":\"allowed\",\"recoveryKeyUsage\":\"allowed\",\"enableRecoveryInformationSaveToStore\":true,\"recoveryInformationToStore\":\"passwordAndKey\",\"enableBitLockerAfterRecoveryInformationToStore\":true},\"prebootRecoveryEnableMessageAndUrl\":false,\"encryptionMethod\":null},\"firewallProfileDomain\":null,\"firewallProfilePrivate\":null,\"firewallProfilePublic\":null,\"deviceGuardEnableVirtualizationBasedSecurity\":false,\"deviceGuardEnableSecureBootWithDMA\":false}", + "Type": "Device", + "GUID": "7e06b0de-0469-4aae-89be-d83c44b5799f.IntuneTemplate.json" +} diff --git a/Config/8d57edc3-071d-42e7-86b1-126720645ac6.TransportRuleTemplate.json b/Config/8d57edc3-071d-42e7-86b1-126720645ac6.TransportRuleTemplate.json index f6d9ccbac6ff..cb8508809c87 100644 --- a/Config/8d57edc3-071d-42e7-86b1-126720645ac6.TransportRuleTemplate.json +++ b/Config/8d57edc3-071d-42e7-86b1-126720645ac6.TransportRuleTemplate.json @@ -1,34 +1,34 @@ -{ - "name": "Block Specific email addresses with a hard rejection", - "applyome": false, - "attachmenthasexecutablecontent": false, - "attachmentispasswordprotected": false, - "attachmentisunsupported": false, - "attachmentprocessinglimitexceeded": false, - "comments": "\n", - "deletemessage": false, - "exceptifattachmenthasexecutablecontent": false, - "exceptifattachmentispasswordprotected": false, - "exceptifattachmentisunsupported": false, - "exceptifattachmentprocessinglimitexceeded": false, - "exceptifhasnoclassification": false, - "exceptifhassenderoverride": false, - "from": ["SomeSpammer@spam.com"], - "hasnoclassification": false, - "hassenderoverride": false, - "mode": "enforce", - "moderatemessagebymanager": false, - "quarantine": false, - "recipientaddresstype": "resolved", - "rejectmessageenhancedstatuscode": "5.7.1", - "rejectmessagereasontext": "Your email has been rejected.", - "removeome": false, - "removeomev2": false, - "removermsattachmentencryption": false, - "routemessageoutboundrequiretls": false, - "ruleerroraction": "ignore", - "rulesubtype": "none", - "senderaddresslocation": "header", - "stopruleprocessing": false, - "uselegacyregex": false -} +{ + "name": "Block Specific email addresses with a hard rejection", + "applyome": false, + "attachmenthasexecutablecontent": false, + "attachmentispasswordprotected": false, + "attachmentisunsupported": false, + "attachmentprocessinglimitexceeded": false, + "comments": "\n", + "deletemessage": false, + "exceptifattachmenthasexecutablecontent": false, + "exceptifattachmentispasswordprotected": false, + "exceptifattachmentisunsupported": false, + "exceptifattachmentprocessinglimitexceeded": false, + "exceptifhasnoclassification": false, + "exceptifhassenderoverride": false, + "from": ["SomeSpammer@spam.com"], + "hasnoclassification": false, + "hassenderoverride": false, + "mode": "enforce", + "moderatemessagebymanager": false, + "quarantine": false, + "recipientaddresstype": "resolved", + "rejectmessageenhancedstatuscode": "5.7.1", + "rejectmessagereasontext": "Your email has been rejected.", + "removeome": false, + "removeomev2": false, + "removermsattachmentencryption": false, + "routemessageoutboundrequiretls": false, + "ruleerroraction": "ignore", + "rulesubtype": "none", + "senderaddresslocation": "header", + "stopruleprocessing": false, + "uselegacyregex": false +} diff --git a/Config/CIPPDefaultTable.BPATemplate.json b/Config/CIPPDefaultTable.BPATemplate.json index 9cdf9c2f5f9d..2f7f31ac326c 100644 --- a/Config/CIPPDefaultTable.BPATemplate.json +++ b/Config/CIPPDefaultTable.BPATemplate.json @@ -1,192 +1,192 @@ -{ - "name": "CIPP Best Practices v1.0 - Table view", - "style": "Table", - "Fields": [ - { - "name": "PasswordNeverExpires", - "API": "Graph", - "URL": "https://graph.microsoft.com/beta/domains", - "ExtractFields": ["passwordValidityPeriodInDays"], - "where": "$_.passwordValidityPeriodInDays -eq 2147483647", - "StoreAs": "bool", - "FrontendFields": [ - { - "name": "Password Never Expires", - "value": "PasswordNeverExpires", - "formatter": "bool" - } - ] - }, - { - "name": "OAuthAppConsent", - "API": "Graph", - "URL": "https://graph.microsoft.com/v1.0/policies/authorizationPolicy?$select=defaultUserRolePermissions", - "ExtractFields": ["defaultuserrolepermissions"], - "where": "'ManagePermissionGrantsForSelf.microsoft-user-default-legacy' -notin $_.defaultuserrolepermissions.permissionGrantPoliciesAssigned", - "StoreAs": "bool", - "FrontendFields": [ - { - "name": "OAuth App Consent", - "value": "OAuthAppConsent", - "formatter": "bool" - } - ] - }, - { - "name": "UnifiedAuditLog", - "API": "Exchange", - "Command": "Get-AdminAuditLogConfig", - "ExtractFields": ["UnifiedAuditLogIngestionEnabled"], - "StoreAs": "bool", - "FrontendFields": [ - { - "name": "Unified Audit Log", - "value": "UnifiedAuditLog", - "formatter": "bool" - } - ] - }, - { - "name": "MFANudgeState", - "API": "Graph", - "URL": "https://graph.microsoft.com/beta/policies/authenticationMethodsPolicy", - "ExtractFields": ["registrationEnforcement"], - "StoreAs": "bool", - "where": "$_.registrationEnforcement.authenticationMethodsRegistrationCampaign.state -eq 'Enabled'", - "FrontendFields": [ - { - "name": "MFA Registration Campaign Enabled", - "value": "MFANudgeState", - "formatter": "bool" - } - ] - }, - { - "name": "TAPEnabled", - "API": "Graph", - "URL": "https://graph.microsoft.com/beta/policies/authenticationmethodspolicy/authenticationMethodConfigurations/TemporaryAccessPass", - "ExtractFields": ["State"], - "StoreAs": "bool", - "FrontendFields": [ - { - "name": "Temporary Access Pass Enabled", - "value": "TAPEnabled", - "formatter": "bool" - } - ] - }, - { - "name": "SecureDefaultState", - "API": "Graph", - "URL": "https://graph.microsoft.com/beta/policies/identitySecurityDefaultsEnforcementPolicy", - "ExtractFields": ["IsEnabled"], - "StoreAs": "bool", - "FrontendFields": [ - { - "name": "Secure Defaults State Enabled", - "value": "SecureDefaultState", - "formatter": "warnBool" - } - ] - }, - { - "name": "AnonymousPrivacyReports", - "API": "Graph", - "URL": "https://graph.microsoft.com/beta/admin/reportSettings", - "ExtractFields": ["displayConcealedNames"], - "StoreAs": "bool", - "where": "$_.displayConcealedNames -eq $false", - "FrontendFields": [ - { - "name": "Anonymous Privacy Reports", - "value": "AnonymousPrivacyReports", - "formatter": "reverseBool" - } - ] - }, - { - "name": "MessageCopyforSentAsDisabled", - "API": "Exchange", - "Command": "Get-Mailbox", - "Parameters": { - "RecipientTypeDetails": ["SharedMailbox", "UserMailbox"] - }, - "where": "$_.MessageCopyForSentAsEnabled -eq $false", - "ExtractFields": ["userprincipalname", "messageCopyForSentAsEnabled"], - "StoreAs": "JSON", - "FrontendFields": [ - { - "name": "Message Copy for Sent-As Disabled", - "formatter": "table", - "value": "MessageCopyforSentAsDisabled" - } - ] - }, - { - "name": "SharedMailboxeswithenabledusers", - "API": "Exchange", - "Command": "Get-Mailbox", - "Parameters": { - "RecipientTypeDetails": "SharedMailbox" - }, - "where": "$_.accountDisabled -eq $false", - "ExtractFields": ["userprincipalname", "accountDisabled"], - "StoreAs": "JSON", - "FrontendFields": [ - { - "name": "Shared Mailboxes with enabled users", - "formatter": "table", - "value": "SharedMailboxeswithenabledusers" - } - ] - }, - { - "name": "Unusedlicenses", - "API": "CIPPFunction", - "Command": "Get-CIPPLicenseOverview", - "ExtractFields": [ - "License", - "TotalLicenses", - "availableUnits", - "CountUsed" - ], - "StoreAs": "JSON", - "where": "$_.availableUnits -gt 0", - "FrontendFields": [ - { - "name": "Unused licenses", - "formatter": "table", - "value": "Unusedlicenses" - } - ] - }, - { - "name": "CurrentSecureScore", - "API": "Graph", - "URL": "https://graph.microsoft.com/beta/security/secureScores?$top=1", - "Parameters": { - "Nopagination": true - }, - "ExtractFields": ["currentScore", "maxScore", "averageComparativeScores"], - "StoreAs": "JSON", - "FrontendFields": [ - { - "name": "Current Secure Score", - "value": "CurrentSecureScore.currentScore" - }, - { - "name": "Max Secure Score", - "value": "CurrentSecureScore.maxScore" - }, - { - "name": "Average Comparative Score (All Tenants)", - "value": "CurrentSecureScore.averageComparativeScores[0].averageScore" - }, - { - "name": "Average Comparative Score (Similiar Size Tenants)", - "value": "CurrentSecureScore.averageComparativeScores[1].averageScore" - } - ] - } - ] -} +{ + "name": "CIPP Best Practices v1.0 - Table view", + "style": "Table", + "Fields": [ + { + "name": "PasswordNeverExpires", + "API": "Graph", + "URL": "https://graph.microsoft.com/beta/domains", + "ExtractFields": ["passwordValidityPeriodInDays"], + "where": "$_.passwordValidityPeriodInDays -eq 2147483647", + "StoreAs": "bool", + "FrontendFields": [ + { + "name": "Password Never Expires", + "value": "PasswordNeverExpires", + "formatter": "bool" + } + ] + }, + { + "name": "OAuthAppConsent", + "API": "Graph", + "URL": "https://graph.microsoft.com/v1.0/policies/authorizationPolicy?$select=defaultUserRolePermissions", + "ExtractFields": ["defaultuserrolepermissions"], + "where": "'ManagePermissionGrantsForSelf.microsoft-user-default-legacy' -notin $_.defaultuserrolepermissions.permissionGrantPoliciesAssigned", + "StoreAs": "bool", + "FrontendFields": [ + { + "name": "OAuth App Consent", + "value": "OAuthAppConsent", + "formatter": "bool" + } + ] + }, + { + "name": "UnifiedAuditLog", + "API": "Exchange", + "Command": "Get-AdminAuditLogConfig", + "ExtractFields": ["UnifiedAuditLogIngestionEnabled"], + "StoreAs": "bool", + "FrontendFields": [ + { + "name": "Unified Audit Log", + "value": "UnifiedAuditLog", + "formatter": "bool" + } + ] + }, + { + "name": "MFANudgeState", + "API": "Graph", + "URL": "https://graph.microsoft.com/beta/policies/authenticationMethodsPolicy", + "ExtractFields": ["registrationEnforcement"], + "StoreAs": "bool", + "where": "$_.registrationEnforcement.authenticationMethodsRegistrationCampaign.state -eq 'Enabled'", + "FrontendFields": [ + { + "name": "MFA Registration Campaign Enabled", + "value": "MFANudgeState", + "formatter": "bool" + } + ] + }, + { + "name": "TAPEnabled", + "API": "Graph", + "URL": "https://graph.microsoft.com/beta/policies/authenticationmethodspolicy/authenticationMethodConfigurations/TemporaryAccessPass", + "ExtractFields": ["State"], + "StoreAs": "bool", + "FrontendFields": [ + { + "name": "Temporary Access Pass Enabled", + "value": "TAPEnabled", + "formatter": "bool" + } + ] + }, + { + "name": "SecureDefaultState", + "API": "Graph", + "URL": "https://graph.microsoft.com/beta/policies/identitySecurityDefaultsEnforcementPolicy", + "ExtractFields": ["IsEnabled"], + "StoreAs": "bool", + "FrontendFields": [ + { + "name": "Secure Defaults State Enabled", + "value": "SecureDefaultState", + "formatter": "warnBool" + } + ] + }, + { + "name": "AnonymousPrivacyReports", + "API": "Graph", + "URL": "https://graph.microsoft.com/beta/admin/reportSettings", + "ExtractFields": ["displayConcealedNames"], + "StoreAs": "bool", + "where": "$_.displayConcealedNames -eq $false", + "FrontendFields": [ + { + "name": "Anonymous Privacy Reports", + "value": "AnonymousPrivacyReports", + "formatter": "reverseBool" + } + ] + }, + { + "name": "MessageCopyforSentAsDisabled", + "API": "Exchange", + "Command": "Get-Mailbox", + "Parameters": { + "RecipientTypeDetails": ["SharedMailbox", "UserMailbox"] + }, + "where": "$_.MessageCopyForSentAsEnabled -eq $false", + "ExtractFields": ["userprincipalname", "messageCopyForSentAsEnabled"], + "StoreAs": "JSON", + "FrontendFields": [ + { + "name": "Message Copy for Sent-As Disabled", + "formatter": "table", + "value": "MessageCopyforSentAsDisabled" + } + ] + }, + { + "name": "SharedMailboxeswithenabledusers", + "API": "Exchange", + "Command": "Get-Mailbox", + "Parameters": { + "RecipientTypeDetails": "SharedMailbox" + }, + "where": "$_.accountDisabled -eq $false", + "ExtractFields": ["userprincipalname", "accountDisabled"], + "StoreAs": "JSON", + "FrontendFields": [ + { + "name": "Shared Mailboxes with enabled users", + "formatter": "table", + "value": "SharedMailboxeswithenabledusers" + } + ] + }, + { + "name": "Unusedlicenses", + "API": "CIPPFunction", + "Command": "Get-CIPPLicenseOverview", + "ExtractFields": [ + "License", + "TotalLicenses", + "availableUnits", + "CountUsed" + ], + "StoreAs": "JSON", + "where": "$_.availableUnits -gt 0", + "FrontendFields": [ + { + "name": "Unused licenses", + "formatter": "table", + "value": "Unusedlicenses" + } + ] + }, + { + "name": "CurrentSecureScore", + "API": "Graph", + "URL": "https://graph.microsoft.com/beta/security/secureScores?$top=1", + "Parameters": { + "Nopagination": true + }, + "ExtractFields": ["currentScore", "maxScore", "averageComparativeScores"], + "StoreAs": "JSON", + "FrontendFields": [ + { + "name": "Current Secure Score", + "value": "CurrentSecureScore.currentScore" + }, + { + "name": "Max Secure Score", + "value": "CurrentSecureScore.maxScore" + }, + { + "name": "Average Comparative Score (All Tenants)", + "value": "CurrentSecureScore.averageComparativeScores[0].averageScore" + }, + { + "name": "Average Comparative Score (Similiar Size Tenants)", + "value": "CurrentSecureScore.averageComparativeScores[1].averageScore" + } + ] + } + ] +} diff --git a/Config/CIPPDefaultTenantPage.BPATemplate.json b/Config/CIPPDefaultTenantPage.BPATemplate.json index 48c62139c647..aa706369f119 100644 --- a/Config/CIPPDefaultTenantPage.BPATemplate.json +++ b/Config/CIPPDefaultTenantPage.BPATemplate.json @@ -1,155 +1,155 @@ -{ - "name": "CIPP Best Practices v1.0 - Tenant view", - "style": "Tenant", - "Fields": [ - { - "name": "PasswordNeverExpires", - "UseExistingInfo": true, - "StoreAs": "bool", - "FrontendFields": [ - { - "name": "Password Never Expires", - "value": "PasswordNeverExpires", - "formatter": "bool", - "desc": "This setting shows if your environment has enabled the password never expires setting. This setting is expected to be set to 'No'" - } - ] - }, - { - "name": "OAuthAppConsent", - "UseExistingInfo": true, - "StoreAs": "bool", - "FrontendFields": [ - { - "name": "OAuth App Consent", - "value": "OAuthAppConsent", - "formatter": "bool", - "desc": "This setting shows if your environment has enabled OAuth App Consent. This setting is expected to be set to 'Yes'" - } - ] - }, - { - "name": "UnifiedAuditLog", - "UseExistingInfo": true, - "StoreAs": "bool", - "FrontendFields": [ - { - "name": "Unified Audit Log", - "value": "UnifiedAuditLog", - "formatter": "bool", - "desc": "This setting shows if your environment has enabled the unified audit log. This setting is expected to be set to 'Yes'" - } - ] - }, - { - "name": "MFANudgeState", - "UseExistingInfo": true, - "StoreAs": "bool", - "FrontendFields": [ - { - "name": "MFA Registration Campaign Enabled", - "value": "MFANudgeState", - "formatter": "bool", - "desc": "This setting shows if your environment has enabled the MFA registration campaign, also known as the MFA Nudge. This setting is recommended to be set to 'Yes'" - } - ] - }, - { - "name": "TAPEnabled", - "UseExistingInfo": true, - "StoreAs": "bool", - "FrontendFields": [ - { - "name": "Temporary Access Pass Enabled", - "value": "TAPEnabled", - "formatter": "bool", - "desc": "This setting shows if your environment has enabled the temporary access pass feature." - } - ] - }, - { - "name": "SecureDefaultState", - "UseExistingInfo": true, - "StoreAs": "bool", - "FrontendFields": [ - { - "name": "Secure Defaults State Enabled", - "value": "SecureDefaultState", - "formatter": "warnBool", - "desc": "This setting shows if your environment has enabled the secure defaults state. If you are using Conditional Access this setting may be set to `No`" - } - ] - }, - { - "name": "AnonymousPrivacyReports", - "UseExistingInfo": true, - "StoreAs": "bool", - "FrontendFields": [ - { - "name": "Anonymous Privacy Reports", - "value": "AnonymousPrivacyReports", - "formatter": "reverseBool", - "desc": "This setting shows if your environment has enabled the anonymous privacy reports, these will need to be disabled to be able to view mailboxes and onedrive reports" - } - ] - }, - { - "name": "MessageCopyforSentAsDisabled", - "UseExistingInfo": true, - "StoreAs": "JSON", - "FrontendFields": [ - { - "name": "Message Copy for Sent-As Disabled", - "formatter": "table", - "value": "MessageCopyforSentAsDisabled", - "desc": "These are the mailboxes that have the MessageCopyForSentAsDisabled setting enabled." - } - ] - }, - { - "name": "SharedMailboxeswithenabledusers", - "UseExistingInfo": true, - "StoreAs": "JSON", - "FrontendFields": [ - { - "name": "Shared Mailboxes with enabled users", - "formatter": "table", - "value": "SharedMailboxeswithenabledusers", - "desc": "These are the shared mailboxes that have enabled users." - } - ] - }, - { - "name": "Unusedlicenses", - "UseExistingInfo": true, - "StoreAs": "JSON", - "FrontendFields": [ - { - "name": "Unused licenses", - "formatter": "table", - "value": "Unusedlicenses", - "desc": "These are the licenses that are not assigned to an user, but have been purchased." - } - ] - }, - { - "name": "CurrentSecureScore", - "UseExistingInfo": true, - "StoreAs": "JSON", - "FrontendFields": [ - { - "name": "Current Secure Score", - "value": "CurrentSecureScore.currentScore", - "desc": "The current Secure Score for this tenant. This is the sum of all the individual controls that have been implemented.", - "formatter": "number" - }, - { - "name": "Max Secure Score", - "value": "CurrentSecureScore.maxScore", - "desc": "The maximum Secure Score for this tenant. This is the sum of all the individual controls that can be implemented.", - "formatter": "number" - } - ] - } - ] -} +{ + "name": "CIPP Best Practices v1.0 - Tenant view", + "style": "Tenant", + "Fields": [ + { + "name": "PasswordNeverExpires", + "UseExistingInfo": true, + "StoreAs": "bool", + "FrontendFields": [ + { + "name": "Password Never Expires", + "value": "PasswordNeverExpires", + "formatter": "bool", + "desc": "This setting shows if your environment has enabled the password never expires setting. This setting is expected to be set to 'No'" + } + ] + }, + { + "name": "OAuthAppConsent", + "UseExistingInfo": true, + "StoreAs": "bool", + "FrontendFields": [ + { + "name": "OAuth App Consent", + "value": "OAuthAppConsent", + "formatter": "bool", + "desc": "This setting shows if your environment has enabled OAuth App Consent. This setting is expected to be set to 'Yes'" + } + ] + }, + { + "name": "UnifiedAuditLog", + "UseExistingInfo": true, + "StoreAs": "bool", + "FrontendFields": [ + { + "name": "Unified Audit Log", + "value": "UnifiedAuditLog", + "formatter": "bool", + "desc": "This setting shows if your environment has enabled the unified audit log. This setting is expected to be set to 'Yes'" + } + ] + }, + { + "name": "MFANudgeState", + "UseExistingInfo": true, + "StoreAs": "bool", + "FrontendFields": [ + { + "name": "MFA Registration Campaign Enabled", + "value": "MFANudgeState", + "formatter": "bool", + "desc": "This setting shows if your environment has enabled the MFA registration campaign, also known as the MFA Nudge. This setting is recommended to be set to 'Yes'" + } + ] + }, + { + "name": "TAPEnabled", + "UseExistingInfo": true, + "StoreAs": "bool", + "FrontendFields": [ + { + "name": "Temporary Access Pass Enabled", + "value": "TAPEnabled", + "formatter": "bool", + "desc": "This setting shows if your environment has enabled the temporary access pass feature." + } + ] + }, + { + "name": "SecureDefaultState", + "UseExistingInfo": true, + "StoreAs": "bool", + "FrontendFields": [ + { + "name": "Secure Defaults State Enabled", + "value": "SecureDefaultState", + "formatter": "warnBool", + "desc": "This setting shows if your environment has enabled the secure defaults state. If you are using Conditional Access this setting may be set to `No`" + } + ] + }, + { + "name": "AnonymousPrivacyReports", + "UseExistingInfo": true, + "StoreAs": "bool", + "FrontendFields": [ + { + "name": "Anonymous Privacy Reports", + "value": "AnonymousPrivacyReports", + "formatter": "reverseBool", + "desc": "This setting shows if your environment has enabled the anonymous privacy reports, these will need to be disabled to be able to view mailboxes and onedrive reports" + } + ] + }, + { + "name": "MessageCopyforSentAsDisabled", + "UseExistingInfo": true, + "StoreAs": "JSON", + "FrontendFields": [ + { + "name": "Message Copy for Sent-As Disabled", + "formatter": "table", + "value": "MessageCopyforSentAsDisabled", + "desc": "These are the mailboxes that have the MessageCopyForSentAsDisabled setting enabled." + } + ] + }, + { + "name": "SharedMailboxeswithenabledusers", + "UseExistingInfo": true, + "StoreAs": "JSON", + "FrontendFields": [ + { + "name": "Shared Mailboxes with enabled users", + "formatter": "table", + "value": "SharedMailboxeswithenabledusers", + "desc": "These are the shared mailboxes that have enabled users." + } + ] + }, + { + "name": "Unusedlicenses", + "UseExistingInfo": true, + "StoreAs": "JSON", + "FrontendFields": [ + { + "name": "Unused licenses", + "formatter": "table", + "value": "Unusedlicenses", + "desc": "These are the licenses that are not assigned to an user, but have been purchased." + } + ] + }, + { + "name": "CurrentSecureScore", + "UseExistingInfo": true, + "StoreAs": "JSON", + "FrontendFields": [ + { + "name": "Current Secure Score", + "value": "CurrentSecureScore.currentScore", + "desc": "The current Secure Score for this tenant. This is the sum of all the individual controls that have been implemented.", + "formatter": "number" + }, + { + "name": "Max Secure Score", + "value": "CurrentSecureScore.maxScore", + "desc": "The maximum Secure Score for this tenant. This is the sum of all the individual controls that can be implemented.", + "formatter": "number" + } + ] + } + ] +} diff --git a/Config/SharePoint.BPATemplate.json b/Config/SharePoint.BPATemplate.json index 99ba97e5caa7..da945a5d1f4f 100644 --- a/Config/SharePoint.BPATemplate.json +++ b/Config/SharePoint.BPATemplate.json @@ -1,70 +1,70 @@ -{ - "name": "CIPP SharePoint Report v1.0 - Table view", - "style": "Table", - "Fields": [ - { - "name": "SharepointSettings", - "API": "Graph", - "URL": "https://graph.microsoft.com/beta/admin/sharepoint/settings", - "Parameters": { - "asApp": "True" - }, - "ExtractFields": [ - "sharingCapability", - "isMacSyncAppEnabled", - "isResharingByExternalUsersEnabled", - "isUnmanagedSyncAppForTenantRestricted", - "isSiteCreationEnabled", - "deletedUserPersonalSiteRetentionPeriodInDays" - ], - "StoreAs": "JSON", - "FrontendFields": [ - { - "name": "Sharing capability", - "value": "SharepointSettings.sharingCapability", - "formatter": "string" - }, - { - "name": "Mac Sync Enabled", - "value": "SharepointSettings.isMacSyncAppEnabled", - "formatter": "warnBool" - }, - { - "name": "Resharing by external users", - "value": "isResharingByExternalUsersEnabled", - "formatter": "reverseBool" - }, - { - "name": "Allow users to sync from unmanaged devices", - "value": "SharepointSettings.isUnmanagedSyncAppForTenantRestricted", - "formatter": "bool" - }, - { - "name": "Site creation by standards users enabled", - "value": "SharepointSettings.isSiteCreationEnabled", - "formatter": "reverseBool" - }, - { - "name": "Deleted user data rention(days)", - "value": "SharepointSettings.deletedUserPersonalSiteRetentionPeriodInDays", - "formatter": "string" - } - ] - }, - { - "name": "WebtimeOut", - "API": "Graph", - "URL": "https://graph.microsoft.com/beta/policies/activityBasedTimeoutPolicies", - "ExtractFields": ["definition"], - "StoreAs": "bool", - "where": "$_.definition -like '*WebSessionIdleTimeout*'", - "FrontendFields": [ - { - "name": "Web Time-Out enabled", - "value": "WebtimeOut", - "formatter": "bool" - } - ] - } - ] -} +{ + "name": "CIPP SharePoint Report v1.0 - Table view", + "style": "Table", + "Fields": [ + { + "name": "SharepointSettings", + "API": "Graph", + "URL": "https://graph.microsoft.com/beta/admin/sharepoint/settings", + "Parameters": { + "asApp": "True" + }, + "ExtractFields": [ + "sharingCapability", + "isMacSyncAppEnabled", + "isResharingByExternalUsersEnabled", + "isUnmanagedSyncAppForTenantRestricted", + "isSiteCreationEnabled", + "deletedUserPersonalSiteRetentionPeriodInDays" + ], + "StoreAs": "JSON", + "FrontendFields": [ + { + "name": "Sharing capability", + "value": "SharepointSettings.sharingCapability", + "formatter": "string" + }, + { + "name": "Mac Sync Enabled", + "value": "SharepointSettings.isMacSyncAppEnabled", + "formatter": "warnBool" + }, + { + "name": "Resharing by external users", + "value": "isResharingByExternalUsersEnabled", + "formatter": "reverseBool" + }, + { + "name": "Allow users to sync from unmanaged devices", + "value": "SharepointSettings.isUnmanagedSyncAppForTenantRestricted", + "formatter": "bool" + }, + { + "name": "Site creation by standards users enabled", + "value": "SharepointSettings.isSiteCreationEnabled", + "formatter": "reverseBool" + }, + { + "name": "Deleted user data rention(days)", + "value": "SharepointSettings.deletedUserPersonalSiteRetentionPeriodInDays", + "formatter": "string" + } + ] + }, + { + "name": "WebtimeOut", + "API": "Graph", + "URL": "https://graph.microsoft.com/beta/policies/activityBasedTimeoutPolicies", + "ExtractFields": ["definition"], + "StoreAs": "bool", + "where": "$_.definition -like '*WebSessionIdleTimeout*'", + "FrontendFields": [ + { + "name": "Web Time-Out enabled", + "value": "WebtimeOut", + "formatter": "bool" + } + ] + } + ] +} diff --git a/Config/adf9f6d1-36fb-438b-a82b-71f3af402b6c.TransportRuleTemplate.json b/Config/adf9f6d1-36fb-438b-a82b-71f3af402b6c.TransportRuleTemplate.json index 42abed3204d2..a92d2ae442d0 100644 --- a/Config/adf9f6d1-36fb-438b-a82b-71f3af402b6c.TransportRuleTemplate.json +++ b/Config/adf9f6d1-36fb-438b-a82b-71f3af402b6c.TransportRuleTemplate.json @@ -1,35 +1,35 @@ -{ - "name": "Block External Auto-forwarding", - "applyome": false, - "attachmenthasexecutablecontent": false, - "attachmentispasswordprotected": false, - "attachmentisunsupported": false, - "attachmentprocessinglimitexceeded": false, - "deletemessage": false, - "exceptifattachmenthasexecutablecontent": false, - "exceptifattachmentispasswordprotected": false, - "exceptifattachmentisunsupported": false, - "exceptifattachmentprocessinglimitexceeded": false, - "exceptifhasnoclassification": false, - "exceptifhassenderoverride": false, - "fromscope": "inorganization", - "hasnoclassification": false, - "hassenderoverride": false, - "messagetypematches": "autoforward", - "mode": "enforce", - "moderatemessagebymanager": false, - "quarantine": false, - "recipientaddresstype": "resolved", - "rejectmessageenhancedstatuscode": "5.7.1", - "rejectmessagereasontext": "to improve security, auto-forwarding rules to external addresses has been disabled. please contact your Microsoft partner if you'd like to set up an exception.", - "removeome": false, - "removeomev2": false, - "removermsattachmentencryption": false, - "routemessageoutboundrequiretls": false, - "ruleerroraction": "ignore", - "rulesubtype": "none", - "senderaddresslocation": "header", - "senttoscope": "notinorganization", - "stopruleprocessing": false, - "uselegacyregex": false -} +{ + "name": "Block External Auto-forwarding", + "applyome": false, + "attachmenthasexecutablecontent": false, + "attachmentispasswordprotected": false, + "attachmentisunsupported": false, + "attachmentprocessinglimitexceeded": false, + "deletemessage": false, + "exceptifattachmenthasexecutablecontent": false, + "exceptifattachmentispasswordprotected": false, + "exceptifattachmentisunsupported": false, + "exceptifattachmentprocessinglimitexceeded": false, + "exceptifhasnoclassification": false, + "exceptifhassenderoverride": false, + "fromscope": "inorganization", + "hasnoclassification": false, + "hassenderoverride": false, + "messagetypematches": "autoforward", + "mode": "enforce", + "moderatemessagebymanager": false, + "quarantine": false, + "recipientaddresstype": "resolved", + "rejectmessageenhancedstatuscode": "5.7.1", + "rejectmessagereasontext": "to improve security, auto-forwarding rules to external addresses has been disabled. please contact your Microsoft partner if you'd like to set up an exception.", + "removeome": false, + "removeomev2": false, + "removermsattachmentencryption": false, + "routemessageoutboundrequiretls": false, + "ruleerroraction": "ignore", + "rulesubtype": "none", + "senderaddresslocation": "header", + "senttoscope": "notinorganization", + "stopruleprocessing": false, + "uselegacyregex": false +} diff --git a/Config/b39b8d85-1531-420e-baeb-b388f565418b.TransportRuleTemplate.json b/Config/b39b8d85-1531-420e-baeb-b388f565418b.TransportRuleTemplate.json index 73995dab2028..0f0541e25af9 100644 --- a/Config/b39b8d85-1531-420e-baeb-b388f565418b.TransportRuleTemplate.json +++ b/Config/b39b8d85-1531-420e-baeb-b388f565418b.TransportRuleTemplate.json @@ -1,33 +1,33 @@ -{ - "name": "if a message subject contains \"encrypt:\" encrypt message.", - "applyome": false, - "applyrightsprotectiontemplate": "encrypt", - "attachmenthasexecutablecontent": false, - "attachmentispasswordprotected": false, - "attachmentisunsupported": false, - "attachmentprocessinglimitexceeded": false, - "comments": "\n", - "deletemessage": false, - "exceptifattachmenthasexecutablecontent": false, - "exceptifattachmentispasswordprotected": false, - "exceptifattachmentisunsupported": false, - "exceptifattachmentprocessinglimitexceeded": false, - "exceptifhasnoclassification": false, - "exceptifhassenderoverride": false, - "hasnoclassification": false, - "hassenderoverride": false, - "mode": "enforce", - "moderatemessagebymanager": false, - "quarantine": false, - "recipientaddresstype": "resolved", - "removeome": false, - "removeomev2": false, - "removermsattachmentencryption": false, - "routemessageoutboundrequiretls": false, - "ruleerroraction": "ignore", - "rulesubtype": "none", - "senderaddresslocation": "header", - "stopruleprocessing": false, - "subjectcontainswords": ["encrypt:"], - "uselegacyregex": false -} +{ + "name": "if a message subject contains \"encrypt:\" encrypt message.", + "applyome": false, + "applyrightsprotectiontemplate": "encrypt", + "attachmenthasexecutablecontent": false, + "attachmentispasswordprotected": false, + "attachmentisunsupported": false, + "attachmentprocessinglimitexceeded": false, + "comments": "\n", + "deletemessage": false, + "exceptifattachmenthasexecutablecontent": false, + "exceptifattachmentispasswordprotected": false, + "exceptifattachmentisunsupported": false, + "exceptifattachmentprocessinglimitexceeded": false, + "exceptifhasnoclassification": false, + "exceptifhassenderoverride": false, + "hasnoclassification": false, + "hassenderoverride": false, + "mode": "enforce", + "moderatemessagebymanager": false, + "quarantine": false, + "recipientaddresstype": "resolved", + "removeome": false, + "removeomev2": false, + "removermsattachmentencryption": false, + "routemessageoutboundrequiretls": false, + "ruleerroraction": "ignore", + "rulesubtype": "none", + "senderaddresslocation": "header", + "stopruleprocessing": false, + "subjectcontainswords": ["encrypt:"], + "uselegacyregex": false +} diff --git a/Config/b79d0123-3105-4c5d-9f15-62cc7a7eb7e1.IntuneTemplate.json b/Config/b79d0123-3105-4c5d-9f15-62cc7a7eb7e1.IntuneTemplate.json index 987c08d764dc..8994b7867849 100644 --- a/Config/b79d0123-3105-4c5d-9f15-62cc7a7eb7e1.IntuneTemplate.json +++ b/Config/b79d0123-3105-4c5d-9f15-62cc7a7eb7e1.IntuneTemplate.json @@ -1,7 +1,7 @@ -{ - "Displayname": "CIPP Default: Automatic Configuration of Outlook", - "Description": "Configures the first profile on a device to always use the e-mail address of the currently logged on user.", - "RAWJson": "{\"name\":\"Automatic configuration of Outlook\",\"description\":\"\",\"platforms\":\"windows10\",\"technologies\":\"mdm\",\"roleScopeTagIds\":[\"0\"],\"settings\":[{\"@odata.type\":\"#microsoft.graph.deviceManagementConfigurationSetting\",\"settingInstance\":{\"@odata.type\":\"#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance\",\"settingDefinitionId\":\"user_vendor_msft_policy_config_outlk16v2~policy~l_microsoftofficeoutlook~l_toolsaccounts~l_exchangesettings_l_automaticallyconfigureprofilebasedonactiveonce\",\"choiceSettingValue\":{\"@odata.type\":\"#microsoft.graph.deviceManagementConfigurationChoiceSettingValue\",\"value\":\"user_vendor_msft_policy_config_outlk16v2~policy~l_microsoftofficeoutlook~l_toolsaccounts~l_exchangesettings_l_automaticallyconfigureprofilebasedonactiveonce_1\",\"children\":[]}}}]}", - "Type": "Catalog", - "GUID": "b79d0123-3105-4c5d-9f15-62cc7a7eb7e1" -} +{ + "Displayname": "CIPP Default: Automatic Configuration of Outlook", + "Description": "Configures the first profile on a device to always use the e-mail address of the currently logged on user.", + "RAWJson": "{\"name\":\"Automatic configuration of Outlook\",\"description\":\"\",\"platforms\":\"windows10\",\"technologies\":\"mdm\",\"roleScopeTagIds\":[\"0\"],\"settings\":[{\"@odata.type\":\"#microsoft.graph.deviceManagementConfigurationSetting\",\"settingInstance\":{\"@odata.type\":\"#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance\",\"settingDefinitionId\":\"user_vendor_msft_policy_config_outlk16v2~policy~l_microsoftofficeoutlook~l_toolsaccounts~l_exchangesettings_l_automaticallyconfigureprofilebasedonactiveonce\",\"choiceSettingValue\":{\"@odata.type\":\"#microsoft.graph.deviceManagementConfigurationChoiceSettingValue\",\"value\":\"user_vendor_msft_policy_config_outlk16v2~policy~l_microsoftofficeoutlook~l_toolsaccounts~l_exchangesettings_l_automaticallyconfigureprofilebasedonactiveonce_1\",\"children\":[]}}}]}", + "Type": "Catalog", + "GUID": "b79d0123-3105-4c5d-9f15-62cc7a7eb7e1" +} diff --git a/Config/cba836bb-33b7-4c50-88be-ee80f74cbeac.CATemplate.json b/Config/cba836bb-33b7-4c50-88be-ee80f74cbeac.CATemplate.json index 0bece075c9d2..a454eecc7793 100644 --- a/Config/cba836bb-33b7-4c50-88be-ee80f74cbeac.CATemplate.json +++ b/Config/cba836bb-33b7-4c50-88be-ee80f74cbeac.CATemplate.json @@ -1,36 +1,36 @@ -{ - "grantControls": { - "termsOfUse": [], - "builtInControls": ["mfa"], - "customAuthenticationFactors": [], - "operator": "OR" - }, - "state": "enabled", - "conditions": { - "servicePrincipalRiskLevels": [], - "userRiskLevels": [], - "deviceStates": null, - "signInRiskLevels": [], - "clientAppTypes": ["all"], - "devices": null, - "locations": null, - "applications": { - "includeApplications": ["d414ee2d-73e5-4e5b-bb16-03ef55fea597"], - "includeUserActions": [], - "includeAuthenticationContextClassReferences": [], - "excludeApplications": [] - }, - "users": { - "includeUsers": ["All"], - "excludeRoles": [], - "includeRoles": [], - "excludeUsers": [], - "includeGroups": [], - "excludeGroups": [] - }, - "platforms": null, - "times": null, - "clientApplications": null - }, - "displayName": "Enforce Multi-factor authentication for Static Web Apps" -} +{ + "grantControls": { + "termsOfUse": [], + "builtInControls": ["mfa"], + "customAuthenticationFactors": [], + "operator": "OR" + }, + "state": "enabled", + "conditions": { + "servicePrincipalRiskLevels": [], + "userRiskLevels": [], + "deviceStates": null, + "signInRiskLevels": [], + "clientAppTypes": ["all"], + "devices": null, + "locations": null, + "applications": { + "includeApplications": ["d414ee2d-73e5-4e5b-bb16-03ef55fea597"], + "includeUserActions": [], + "includeAuthenticationContextClassReferences": [], + "excludeApplications": [] + }, + "users": { + "includeUsers": ["All"], + "excludeRoles": [], + "includeRoles": [], + "excludeUsers": [], + "includeGroups": [], + "excludeGroups": [] + }, + "platforms": null, + "times": null, + "clientApplications": null + }, + "displayName": "Enforce Multi-factor authentication for Static Web Apps" +} diff --git a/Config/e82dd7d8-3f13-43cd-bdd4-896e0958493b.TransportRuleTemplate.json b/Config/e82dd7d8-3f13-43cd-bdd4-896e0958493b.TransportRuleTemplate.json index 4109bd25294e..a975c36fa432 100644 --- a/Config/e82dd7d8-3f13-43cd-bdd4-896e0958493b.TransportRuleTemplate.json +++ b/Config/e82dd7d8-3f13-43cd-bdd4-896e0958493b.TransportRuleTemplate.json @@ -1,32 +1,32 @@ -{ - "name": "Block emails silently based on their subject", - "applyome": false, - "attachmenthasexecutablecontent": false, - "attachmentispasswordprotected": false, - "attachmentisunsupported": false, - "attachmentprocessinglimitexceeded": false, - "comments": "\n", - "deletemessage": true, - "exceptifattachmenthasexecutablecontent": false, - "exceptifattachmentispasswordprotected": false, - "exceptifattachmentisunsupported": false, - "exceptifattachmentprocessinglimitexceeded": false, - "exceptifhasnoclassification": false, - "exceptifhassenderoverride": false, - "hasnoclassification": false, - "hassenderoverride": false, - "mode": "enforce", - "moderatemessagebymanager": false, - "quarantine": false, - "recipientaddresstype": "resolved", - "removeome": false, - "removeomev2": false, - "removermsattachmentencryption": false, - "routemessageoutboundrequiretls": false, - "ruleerroraction": "ignore", - "rulesubtype": "none", - "senderaddresslocation": "header", - "stopruleprocessing": false, - "subjectorbodycontainswords": ["This subject"], - "uselegacyregex": false -} +{ + "name": "Block emails silently based on their subject", + "applyome": false, + "attachmenthasexecutablecontent": false, + "attachmentispasswordprotected": false, + "attachmentisunsupported": false, + "attachmentprocessinglimitexceeded": false, + "comments": "\n", + "deletemessage": true, + "exceptifattachmenthasexecutablecontent": false, + "exceptifattachmentispasswordprotected": false, + "exceptifattachmentisunsupported": false, + "exceptifattachmentprocessinglimitexceeded": false, + "exceptifhasnoclassification": false, + "exceptifhassenderoverride": false, + "hasnoclassification": false, + "hassenderoverride": false, + "mode": "enforce", + "moderatemessagebymanager": false, + "quarantine": false, + "recipientaddresstype": "resolved", + "removeome": false, + "removeomev2": false, + "removermsattachmentencryption": false, + "routemessageoutboundrequiretls": false, + "ruleerroraction": "ignore", + "rulesubtype": "none", + "senderaddresslocation": "header", + "stopruleprocessing": false, + "subjectorbodycontainswords": ["This subject"], + "uselegacyregex": false +} diff --git a/Config/f8be7e58-2419-40a8-a739-714bf5deff90.CATemplate.json b/Config/f8be7e58-2419-40a8-a739-714bf5deff90.CATemplate.json index 966e83ecf3cb..392a69750b24 100644 --- a/Config/f8be7e58-2419-40a8-a739-714bf5deff90.CATemplate.json +++ b/Config/f8be7e58-2419-40a8-a739-714bf5deff90.CATemplate.json @@ -1,36 +1,36 @@ -{ - "state": "enabled", - "grantControls": { - "builtInControls": ["block"], - "operator": "OR", - "termsOfUse": [], - "customAuthenticationFactors": [] - }, - "conditions": { - "times": null, - "locations": null, - "signInRiskLevels": [], - "devices": null, - "deviceStates": null, - "users": { - "excludeRoles": [], - "excludeUsers": [], - "excludeGroups": [], - "includeUsers": ["All"], - "includeRoles": [], - "includeGroups": [] - }, - "servicePrincipalRiskLevels": [], - "userRiskLevels": [], - "clientAppTypes": ["exchangeActiveSync", "other"], - "platforms": null, - "clientApplications": null, - "applications": { - "includeApplications": ["None"], - "includeUserActions": [], - "includeAuthenticationContextClassReferences": [], - "excludeApplications": [] - } - }, - "displayName": "Block Legacy Authentication" -} +{ + "state": "enabled", + "grantControls": { + "builtInControls": ["block"], + "operator": "OR", + "termsOfUse": [], + "customAuthenticationFactors": [] + }, + "conditions": { + "times": null, + "locations": null, + "signInRiskLevels": [], + "devices": null, + "deviceStates": null, + "users": { + "excludeRoles": [], + "excludeUsers": [], + "excludeGroups": [], + "includeUsers": ["All"], + "includeRoles": [], + "includeGroups": [] + }, + "servicePrincipalRiskLevels": [], + "userRiskLevels": [], + "clientAppTypes": ["exchangeActiveSync", "other"], + "platforms": null, + "clientApplications": null, + "applications": { + "includeApplications": ["None"], + "includeUserActions": [], + "includeAuthenticationContextClassReferences": [], + "excludeApplications": [] + } + }, + "displayName": "Block Legacy Authentication" +} diff --git a/DomainAnalyser_GetTenantDomains/run.ps1 b/DomainAnalyser_GetTenantDomains/run.ps1 index 2c805c5a0046..4e0fd71f2be8 100644 --- a/DomainAnalyser_GetTenantDomains/run.ps1 +++ b/DomainAnalyser_GetTenantDomains/run.ps1 @@ -5,7 +5,7 @@ $ExcludedTenants = Get-Tenants -SkipList $DomainTable = Get-CippTable -tablename 'Domains' $TenantDomains = $Tenants | ForEach-Object -Parallel { - Import-Module '.\GraphHelper.psm1' + Import-Module CippCore $Tenant = $_ # Get Domains to Lookup try { diff --git a/DomainAnalyser_List/run.ps1 b/DomainAnalyser_List/run.ps1 index 70a5bd281942..65a72671901f 100644 --- a/DomainAnalyser_List/run.ps1 +++ b/DomainAnalyser_List/run.ps1 @@ -2,7 +2,6 @@ using namespace System.Net # Input bindings are passed in via param block. param($Request, $TriggerMetadata) -Set-Location (Get-Item $PSScriptRoot).Parent.FullName $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' @@ -29,11 +28,9 @@ try { $Object } } - } - catch {} + } catch {} } -} -catch { +} catch { $Results = @() } diff --git a/EditCAPolicy/function.json b/EditCAPolicy/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/EditCAPolicy/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/EditCAPolicy/run.ps1 b/EditCAPolicy/run.ps1 deleted file mode 100644 index 98856573fb0b..000000000000 --- a/EditCAPolicy/run.ps1 +++ /dev/null @@ -1,29 +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" - -$Tenant = $request.query.tenantFilter -$ID = $request.query.guid -$results = try { - $EditBody = "{`"state`": `"$($request.query.state)`"}" - $Request = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta//identity/conditionalAccess/policies/$($id)" -tenantid $tenant -type PATCH -body $EditBody - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($Tenant) -message "Edited CA policy $($ID)" -Sev "Error" - "Successfully edited CA policy" -} -catch { - "Failed to add CA policy: $($_.Exception.Message)" - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($Tenant) -message "Failed editing CA policy $($ID). Error: $($_.Exception.Message)" -Sev "Error" - continue -} - -$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/EditExConnector/function.json b/EditExConnector/function.json deleted file mode 100644 index bec6849b58ab..000000000000 --- a/EditExConnector/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/EditGroup/function.json b/EditGroup/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/EditGroup/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/EditPolicy/function.json b/EditPolicy/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/EditPolicy/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/EditSpamFilter/function.json b/EditSpamFilter/function.json deleted file mode 100644 index bec6849b58ab..000000000000 --- a/EditSpamFilter/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/EditTenant/function.json b/EditTenant/function.json deleted file mode 100644 index bec6849b58ab..000000000000 --- a/EditTenant/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/EditTenant/run.ps1 b/EditTenant/run.ps1 deleted file mode 100644 index 8a0427aaf662..000000000000 --- a/EditTenant/run.ps1 +++ /dev/null @@ -1,57 +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' - -$tenantDisplayName = $request.body.displayName -$tenantDefaultDomainName = $request.body.defaultDomainName -$Tenant = $request.body.tenantid -$customerContextId = $request.body.customerId - -$tokens = try { - $AADGraphtoken = (Get-GraphToken -scope 'https://graph.windows.net/.default') - $allTenantsDetails = (Invoke-RestMethod -Method GET -Uri 'https://graph.windows.net/myorganization/contracts?api-version=1.6' -ContentType 'application/json' -Headers $AADGraphtoken) - $tenantObjectId = $allTenantsDetails.value | Where-Object { $_.customerContextId -eq $customerContextId } | Select-Object 'objectId' -} -catch { - $Results = "Failed to retrieve list of tenants. Error: $($_.Exception.Message)" - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantDisplayName) -message "Failed to retrieve list of tenants. Error: $($_.Exception.Message)" -Sev 'Error' -} - - -if ($tenantObjectId) { - try { - $bodyToPatch = '{"displayName":"' + $tenantDisplayName + '","defaultDomainName":"' + $tenantDefaultDomainName + '"}' - $patchTenant = (Invoke-RestMethod -Method PATCH -Uri "https://graph.windows.net/myorganization/contracts/$($tenantObjectId.objectId)?api-version=1.6" -Body $bodyToPatch -ContentType 'application/json' -Headers $AADGraphtoken -ErrorAction Stop) - $Filter = "PartitionKey eq 'Tenants' and defaultDomainName eq '{0}'" -f $tenantDefaultDomainName - try { - $TenantsTable = Get-CippTable -tablename Tenants - $Tenant = Get-CIPPAzDataTableEntity @TenantsTable -Filter $Filter - $Tenant.displayName = $tenantDisplayName - Update-AzDataTableEntity @TenantsTable -Entity $Tenant - } - catch { - $AddedText = "but could not edit the tenant cache. Clear the tenant cache to display the updated details" - } - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $tenantDisplayName -message "Edited tenant $tenantDisplayName" -Sev 'Info' - $results = "Successfully amended details for $($Tenant.displayName) $AddedText" - } - catch { - $results = "Failed to amend details for $tenantDisplayName : $($_.Exception.Message)" - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $tenantDisplayName -message "Failed amending details $tenantDisplayName. Error: $($_.Exception.Message)" -Sev 'Error' - } -} -else { - $Results = "Could not find the tenant to edit in the contract endpoint. Please ensure you have a reseller relationship with the tenant you are trying to edit." -} - -$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/EditTransportRule/function.json b/EditTransportRule/function.json deleted file mode 100644 index bec6849b58ab..000000000000 --- a/EditTransportRule/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/EditTransportRule/run.ps1 b/EditTransportRule/run.ps1 deleted file mode 100644 index 9228d09212bd..000000000000 --- a/EditTransportRule/run.ps1 +++ /dev/null @@ -1,29 +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" -$Tenantfilter = $request.Query.tenantfilter - - -$Params = @{ - Identity = $request.query.guid -} - -try { - $cmdlet = if ($request.query.state -eq "enable") { "Enable-TransportRule" } else { "Disable-TransportRule" } - $GraphRequest = New-ExoRequest -tenantid $Tenantfilter -cmdlet $cmdlet -cmdParams $params -UseSystemMailbox $true - $Result = "Set transport rule $($Request.query.guid) to $($request.query.State)" - Write-LogMessage -API "TransportRules" -tenant $tenantfilter -message "Set transport rule $($Request.query.guid) to $($request.query.State)" -sev Debug -} -catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception - $Result = $ErrorMessage -} -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @{Results = $Result } - }) diff --git a/EditUser/function.json b/EditUser/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/EditUser/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/EditUser/run.ps1 b/EditUser/run.ps1 deleted file mode 100644 index 9c414e521610..000000000000 --- a/EditUser/run.ps1 +++ /dev/null @@ -1,110 +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" -$userobj = $Request.body -$Results = [System.Collections.ArrayList]@() -$licenses = ($userobj | Select-Object "License_*").psobject.properties.value -$Aliases = if ($userobj.AddedAliases) { ($userobj.AddedAliases).Split([Environment]::NewLine) } - -# Write to the Azure Functions log stream. -Write-Host "PowerShell HTTP trigger function processed a request." -#Edit the user -try { - Write-Host "$([boolean]$UserObj.mustchangepass)" - $Email = "$($UserObj.username)@$($UserObj.domain)" - $UserprincipalName = "$($UserObj.username)@$($UserObj.domain)" - $BodyToship = [pscustomobject] @{ - "givenName" = $userobj.firstname - "surname" = $userobj.lastname - "city" = $userobj.city - "country" = $userobj.country - "department" = $userobj.department - "displayName" = $UserObj.Displayname - "postalCode" = $userobj.postalCode - "companyName" = $userobj.companyName - "mailNickname" = $UserObj.username - "jobTitle" = $UserObj.JobTitle - "userPrincipalName" = $Email - "usageLocation" = $UserObj.usageLocation - "mobilePhone" = $userobj.mobilePhone - "streetAddress" = $userobj.streetAddress - "businessPhones" = @($userobj.businessPhone) - "passwordProfile" = @{ - "forceChangePasswordNextSignIn" = [boolean]$UserObj.mustchangepass - } - } | ForEach-Object { - $NonEmptyProperties = $_.psobject.Properties | Select-Object -ExpandProperty Name - $_ | Select-Object -Property $NonEmptyProperties | ConvertTo-Json - } - $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" - 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 - $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 { - 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)") -} - - -#Reassign the licenses -try { - - if ($licenses -or $userobj.RemoveAllLicenses) { - $licenses = (($userobj | Select-Object "License_*").psobject.properties | Where-Object { $_.value -EQ $true }).name -replace "License_", "" - $CurrentLicenses = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($userobj.Userid)" -tenantid $Userobj.tenantid - $RemovalList = ($CurrentLicenses.assignedLicenses | Where-Object -Property skuid -NotIn $licenses).skuid - $LicensesToRemove = if ($RemovalList) { ConvertTo-Json @( $RemovalList ) } else { "[]" } - - $liclist = foreach ($license in $Licenses) { '{"disabledPlans": [],"skuId": "' + $license + '" },' } - $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 - - 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." ) - } - -} -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)") -} - -#Add Aliases, removal currently not supported. -try { - if ($Aliases) { - foreach ($Alias in $Aliases) { - New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($userobj.Userid)" -tenantid $Userobj.tenantid -type "patch" -body "{`"mail`": `"$Alias`"}" -verbose - } - New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($userobj.Userid)" -tenantid $Userobj.tenantid -type "patch" -body "{`"mail`": `"$UserprincipalName`"}" -verbose - Write-LogMessage -API $APINAME -tenant ($UserObj.tenantid) -user $request.headers.'x-ms-client-principal' -message "Added Aliases to $($userobj.displayname)" -Sev "Info" - $results.add( "Success. added aliasses to user.") - } - -} -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)") -} - -if ($Request.body.CopyFrom -ne "") { - $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) -} -$body = @{"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/ExecAccessChecks/function.json b/ExecAccessChecks/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecAccessChecks/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/ExecAccessChecks/run.ps1 b/ExecAccessChecks/run.ps1 deleted file mode 100644 index 0cc71645208e..000000000000 --- a/ExecAccessChecks/run.ps1 +++ /dev/null @@ -1,29 +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.' -if ($Request.query.Permissions -eq 'true') { - $Results = Test-CIPPAccessPermissions -tenantfilter $ENV:tenantid -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' -} - -if ($Request.query.Tenants -eq 'true') { - $Results = Test-CIPPAccessTenant -Tenantcsv $Request.body.TenantId -} -if ($Request.query.GDAP -eq 'true') { - $Results = Test-CIPPGDAPRelationships -} - -$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/ExecAddGDAPRole/function.json b/ExecAddGDAPRole/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecAddGDAPRole/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/ExecAddGDAPRole/run.ps1 b/ExecAddGDAPRole/run.ps1 deleted file mode 100644 index a78d130486a7..000000000000 --- a/ExecAddGDAPRole/run.ps1 +++ /dev/null @@ -1,62 +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' -$Groups = $Request.body.gdapRoles -$CustomSuffix = $Request.body.customSuffix -$Table = Get-CIPPTable -TableName 'GDAPRoles' - -$Results = [System.Collections.Generic.List[string]]::new() -$ExistingGroups = New-GraphGetRequest -NoAuthCheck $True -uri 'https://graph.microsoft.com/beta/groups' -tenantid $env:TenantID - -$RoleMappings = foreach ($group in $Groups) { - if ($CustomSuffix) { - $GroupName = "M365 GDAP $($Group.Name) - $CustomSuffix" - $MailNickname = "M365GDAP$(($Group.Name).replace(' ',''))$($CustomSuffix)" - } - else { - $GroupName = "M365 GDAP $($Group.Name)" - $MailNickname = "M365GDAP$(($Group.Name).replace(' ',''))" - } - try { - if ($GroupName -in $ExistingGroups.displayName) { - @{ - PartitionKey = 'Roles' - RowKey = ($ExistingGroups | Where-Object -Property displayName -EQ $GroupName).id - RoleName = $Group.Name - GroupName = $GroupName - GroupId = ($ExistingGroups | Where-Object -Property displayName -EQ $GroupName).id - roleDefinitionId = $group.ObjectId - } - $Results.Add("M365 GDAP $($Group.Name) already exists") - } - else { - $BodyToship = [pscustomobject] @{'displayName' = $GroupName; 'description' = "This group is used to manage M365 partner tenants at the $($group.name) level."; securityEnabled = $true; mailEnabled = $false; mailNickname = $MailNickname } | ConvertTo-Json - $GraphRequest = New-GraphPostRequest -NoAuthCheck $True -uri 'https://graph.microsoft.com/beta/groups' -tenantid $env:TenantID -type POST -body $BodyToship -verbose - @{ - PartitionKey = 'Roles' - RowKey = $GraphRequest.Id - RoleName = $Group.Name - GroupName = $GroupName - GroupId = $GraphRequest.Id - roleDefinitionId = $group.ObjectId - } - $Results.Add("$GroupName added successfully") - } - } - catch { - $Results.Add("Could not create GDAP group $($GroupName): $($_.Exception.Message)") - } -} - -Add-CIPPAzDataTableEntity @Table -Entity $RoleMappings -Force - -$body = @{Results = @($Results) } -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $body - }) \ No newline at end of file diff --git a/ExecAddSPN/function.json b/ExecAddSPN/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecAddSPN/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/ExecAddSPN/run.ps1 b/ExecAddSPN/run.ps1 deleted file mode 100644 index c954af2de341..000000000000 --- a/ExecAddSPN/run.ps1 +++ /dev/null @@ -1,23 +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" - -# Interact with query parameters or the body of the request. -$Body = if ($Request.Query.Enable) { '{"accountEnabled":"true"}' } else { '{"accountEnabled":"false"}' } -try { - $GraphRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/v1.0/servicePrincipals" -tenantid $ENV:TenantID -type POST -Body "{ `"appId`": `"2832473f-ec63-45fb-976f-5d45a7d4bb91`" }" -NoAuthCheck $true - $Results = [pscustomobject]@{"Results" = "Successfully completed request. Add your GDAP migration permissions to your SAM application here: https://portal.azure.com/#view/Microsoft_AAD_RegisteredApps/ApplicationMenuBlade/~/CallAnAPI/appId/$($ENV:ApplicationID)/isMSAApp/ " } -} -catch { - $Results = [pscustomobject]@{"Results" = "Failed to add SPN. Please manually execute 'New-AzureADServicePrincipal -AppId 2832473f-ec63-45fb-976f-5d45a7d4bb91' The error was $($_.Exception.Message)" } -} - -# 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/ExecAlertsList/function.json b/ExecAlertsList/function.json deleted file mode 100644 index 6276e76c91b7..000000000000 --- a/ExecAlertsList/function.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "bindings": [ - { - "authLevel": "anonymous", - "type": "httpTrigger", - "direction": "in", - "name": "Request", - "methods": ["get", "post"] - }, - { - "type": "http", - "direction": "out", - "name": "Response" - }, - { - "type": "queue", - "direction": "out", - "name": "Msg", - "queueName": "alertqueue" - } - ] -} diff --git a/ExecAlertsList/run.ps1 b/ExecAlertsList/run.ps1 deleted file mode 100644 index 7fad1371efbf..000000000000 --- a/ExecAlertsList/run.ps1 +++ /dev/null @@ -1,105 +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.' - -function New-FlatArray ([Array]$arr) { - $arr | ForEach-Object { - if ($_ -is 'Array') { - New-FlatArray $_ - } - else { $_ } - } -} -try { - # Interact with query parameters or the body of the request. - $TenantFilter = $Request.Query.TenantFilter - $GraphRequest = if ($TenantFilter -ne 'AllTenants') { - $Alerts = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/security/alerts' -tenantid $TenantFilter - $AlertsObj = foreach ($Alert In $alerts) { - @{ - Tenant = $TenantFilter - GUID = $GUID - Id = $alert.Id - Title = $alert.Title - Category = $alert.category - EventDateTime = $alert.eventDateTime - Severity = $alert.Severity - Status = $alert.Status - RawResult = $($Alerts | Where-Object { $_.Id -eq $alert.Id }) - InvolvedUsers = $($Alerts | Where-Object { $_.Id -eq $alert.Id }).userStates - } - } - - $DisplayableAlerts = New-FlatArray $AlertsObj | Where-Object { $_.Id -ne $null } | Sort-Object -Property EventDateTime -Descending - - [PSCustomObject]@{ - NewAlertsCount = $DisplayableAlerts | Where-Object { $_.Status -eq 'newAlert' } | Measure-Object | Select-Object -ExpandProperty Count - InProgressAlertsCount = $DisplayableAlerts | Where-Object { $_.Status -eq 'inProgress' } | Measure-Object | Select-Object -ExpandProperty Count - SeverityHighAlertsCount = ($DisplayableAlerts | Where-Object { ($_.Status -eq 'inProgress') -or ($_.Status -eq 'newAlert') } | Where-Object { $_.Severity -eq 'high' } | Measure-Object | Select-Object -ExpandProperty Count) - SeverityMediumAlertsCount = $DisplayableAlerts | Where-Object { ($_.Status -eq 'inProgress') -or ($_.Status -eq 'newAlert') } | Where-Object { $_.Severity -eq 'medium' } | Measure-Object | Select-Object -ExpandProperty Count - SeverityLowAlertsCount = $DisplayableAlerts | Where-Object { ($_.Status -eq 'inProgress') -or ($_.Status -eq 'newAlert') } | Where-Object { $_.Severity -eq 'low' } | Measure-Object | Select-Object -ExpandProperty Count - SeverityInformationalCount = $DisplayableAlerts | Where-Object { ($_.Status -eq 'inProgress') -or ($_.Status -eq 'newAlert') } | Where-Object { $_.Severity -eq 'informational' } | Measure-Object | Select-Object -ExpandProperty Count - MSResults = $DisplayableAlerts - } - } - else { - $Table = Get-CIPPTable -TableName cachealertsandincidents - $Filter = "PartitionKey eq 'alert'" - $Rows = Get-CIPPAzDataTableEntity @Table -filter $Filter | Where-Object -Property Timestamp -GT (Get-Date).AddMinutes(-10) - if (!$Rows) { - Push-OutputBinding -Name Msg -Value (Get-Date).ToString() - [PSCustomObject]@{ - Waiting = $true - } - } - else { - $Alerts = $Rows - $AlertsObj = foreach ($Alert in $alerts) { - $AlertInfo = $Alert.Alert | ConvertFrom-Json - @{ - Tenant = $Alert.Tenant - GUID = $GUID - Id = $AlertInfo.Id - Title = $AlertInfo.Title - Category = $AlertInfo.category - EventDateTime = $AlertInfo.eventDateTime - Severity = $AlertInfo.Severity - Status = $AlertInfo.Status - RawResult = $AlertInfo - InvolvedUsers = $AlertInfo.userStates - } - } - $DisplayableAlerts = New-FlatArray $AlertsObj | Where-Object { $_.Id -ne $null } | Sort-Object -Property EventDateTime -Descending - [PSCustomObject]@{ - NewAlertsCount = $DisplayableAlerts | Where-Object { $_.Status -eq 'newAlert' } | Measure-Object | Select-Object -ExpandProperty Count - InProgressAlertsCount = $DisplayableAlerts | Where-Object { $_.Status -eq 'inProgress' } | Measure-Object | Select-Object -ExpandProperty Count - SeverityHighAlertsCount = ($DisplayableAlerts | Where-Object { ($_.Status -eq 'inProgress') -or ($_.Status -eq 'newAlert') } | Where-Object { $_.Severity -eq 'high' } | Measure-Object | Select-Object -ExpandProperty Count) - SeverityMediumAlertsCount = $DisplayableAlerts | Where-Object { ($_.Status -eq 'inProgress') -or ($_.Status -eq 'newAlert') } | Where-Object { $_.Severity -eq 'medium' } | Measure-Object | Select-Object -ExpandProperty Count - SeverityLowAlertsCount = $DisplayableAlerts | Where-Object { ($_.Status -eq 'inProgress') -or ($_.Status -eq 'newAlert') } | Where-Object { $_.Severity -eq 'low' } | Measure-Object | Select-Object -ExpandProperty Count - SeverityInformationalCount = $DisplayableAlerts | Where-Object { ($_.Status -eq 'inProgress') -or ($_.Status -eq 'newAlert') } | Where-Object { $_.Severity -eq 'informational' } | Measure-Object | Select-Object -ExpandProperty Count - MSResults = $DisplayableAlerts - } - } - } - -} -catch { - $StatusCode = [HttpStatusCode]::Forbidden - $body = $_.Exception.message -} -if (!$body) { - $StatusCode = [HttpStatusCode]::OK - $body = $GraphRequest -} -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = $Body - }) \ No newline at end of file diff --git a/ExecAlertsListAllTenants/run.ps1 b/ExecAlertsListAllTenants/run.ps1 index bf31544adb5d..4782d15619b9 100644 --- a/ExecAlertsListAllTenants/run.ps1 +++ b/ExecAlertsListAllTenants/run.ps1 @@ -6,7 +6,7 @@ Write-Host "PowerShell queue trigger function processed work item: $QueueItem" Get-Tenants | ForEach-Object -Parallel { $domainName = $_.defaultDomainName - Import-Module '.\GraphHelper.psm1' + Import-Module CippCore $Table = Get-CIPPTable -TableName 'cachealertsandincidents' try { @@ -24,8 +24,7 @@ Get-Tenants | ForEach-Object -Parallel { } - } - catch { + } catch { $GUID = (New-Guid).Guid $AlertText = ConvertTo-Json -InputObject @{ Title = "Could not connect to tenant to retrieve data: $($_.Exception.Message)" @@ -36,8 +35,8 @@ Get-Tenants | ForEach-Object -Parallel { Status = '' userStates = @('None') vendorInformation = @{ - vendor = "CIPP" - provider = "CIPP" + vendor = 'CIPP' + provider = 'CIPP' } } $GraphRequest = @{ diff --git a/ExecAppApproval/function.json b/ExecAppApproval/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecAppApproval/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/ExecAppApproval/run.ps1 b/ExecAppApproval/run.ps1 deleted file mode 100644 index 51fa478763e7..000000000000 --- a/ExecAppApproval/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" - -# Write to the Azure Functions log stream. -Write-Host "PowerShell HTTP trigger function processed a request." -Write-Host "$($Request.query.ID)" -# Interact with query parameters or the body of the request. - -$applicationid = if ($request.query.applicationid) { $request.query.applicationid } else { $env:ApplicationID } -$Results = get-tenants | ForEach-Object { - [PSCustomObject]@{ - defaultDomainName = $_.defaultDomainName - link = "https://login.microsoftonline.com/$($_.customerId)/v2.0/adminconsent?client_id=$applicationid&scope=$applicationid/.default" - } -} - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Results - }) diff --git a/ExecAssignApp/function.json b/ExecAssignApp/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecAssignApp/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/ExecAssignApp/run.ps1 b/ExecAssignApp/run.ps1 deleted file mode 100644 index 3c009b9386c0..000000000000 --- a/ExecAssignApp/run.ps1 +++ /dev/null @@ -1,53 +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." - -# Interact with query parameters or the body of the request. -$tenantfilter = $Request.Query.TenantFilter -$appFilter = $Request.Query.ID -$AssignTo = $Request.Query.AssignTo -$AssignBody = switch ($AssignTo) { - - 'AllUsers' { - @" -{"mobileAppAssignments":[{"@odata.type":"#microsoft.graph.mobileAppAssignment","target":{"@odata.type":"#microsoft.graph.allLicensedUsersAssignmentTarget"},"intent":"Required","settings":null}]} -"@ - } - - 'AllDevices' { - @" -{"mobileAppAssignments":[{"@odata.type":"#microsoft.graph.mobileAppAssignment","target":{"@odata.type":"#microsoft.graph.allDevicesAssignmentTarget"},"intent":"Required","settings":null}]} -"@ - } - - 'Both' { - @" -{"mobileAppAssignments":[{"@odata.type":"#microsoft.graph.mobileAppAssignment","target":{"@odata.type":"#microsoft.graph.allLicensedUsersAssignmentTarget"},"intent":"Required","settings":null},{"@odata.type":"#microsoft.graph.mobileAppAssignment","target":{"@odata.type":"#microsoft.graph.allDevicesAssignmentTarget"},"intent":"Required","settings":null}]} -"@ - } - -} -$body = [pscustomobject]@{"Results" = "$($TenantFilter): Assigned app to $assignTo" } -try { - $GraphRequest = New-Graphpostrequest -uri "https://graph.microsoft.com/beta/deviceAppManagement/mobileApps/$appFilter/assign" -tenantid $TenantFilter -body $Assignbody - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantfilter) -message "Assigned $($appFilter) to $assignTo" -Sev "Info" - -} -catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantfilter) -message "Failed to assign app $($appFilter): $($_.Exception.Message)" -Sev "Error" - $body = [pscustomobject]@{"Results" = "Failed to assign. $($_.Exception.Message)" } -} - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $body - }) diff --git a/ExecAutoExtendGDAP/function.json b/ExecAutoExtendGDAP/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecAutoExtendGDAP/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/ExecAutoExtendGDAP/run.ps1 b/ExecAutoExtendGDAP/run.ps1 deleted file mode 100644 index 8106ae4db6d1..000000000000 --- a/ExecAutoExtendGDAP/run.ps1 +++ /dev/null @@ -1,16 +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" - -# Interact with query parameters or the body of the request. -$Results = Set-CIPPGDAPAutoExtend -RelationShipid $Request.query.ID - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @{ Results = $Results } - }) \ No newline at end of file diff --git a/ExecBECCheck/function.json b/ExecBECCheck/function.json deleted file mode 100644 index 3de6affa2d01..000000000000 --- a/ExecBECCheck/function.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "bindings": [ - { - "authLevel": "anonymous", - "type": "httpTrigger", - "direction": "in", - "name": "Request", - "methods": [ - "get", - "post" - ] - }, - { - "type": "http", - "direction": "out", - "name": "Response" - }, - { - "name": "starter", - "type": "durableClient", - "direction": "in" - } - ] -} \ No newline at end of file diff --git a/ExecBECCheck/run.ps1 b/ExecBECCheck/run.ps1 deleted file mode 100644 index 6790917a0af7..000000000000 --- a/ExecBECCheck/run.ps1 +++ /dev/null @@ -1,31 +0,0 @@ -using namespace System.Net -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) - - -$body = if ($request.query.GUID) { - $Table = Get-CippTable -tablename 'cachebec' - $Filter = "PartitionKey eq 'bec' and RowKey eq '$($request.query.GUID)'" - $JSONOutput = Get-CIPPAzDataTableEntity @Table -Filter $Filter - if (!$JSONOutput) { - @{ Waiting = $true } - } - else { - $JSONOutput.Results - } -} -else { - $OrchRequest = [PSCustomObject]@{ - TenantFilter = $request.query.tenantfilter - UserID = $request.query.userid - userName = $request.query.userName - } - $InstanceId = Start-NewOrchestration -FunctionName 'Durable_BECRun' -InputObject $OrchRequest - @{ GUID = $request.query.userid } -} - - -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $body - }) \ No newline at end of file diff --git a/ExecBECRemediate/function.json b/ExecBECRemediate/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecBECRemediate/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/ExecBECRemediate/run.ps1 b/ExecBECRemediate/run.ps1 deleted file mode 100644 index 6f4a25eee516..000000000000 --- a/ExecBECRemediate/run.ps1 +++ /dev/null @@ -1,46 +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-Host "PowerShell HTTP trigger function processed a request." - -$TenantFilter = $request.body.tenantfilter -$SuspectUser = $request.body.userid -$username = $request.body.username -Write-Host $TenantFilter -Write-Host $SuspectUser -$Results = try { - Set-CIPPResetPassword -userid $username -tenantFilter $TenantFilter -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' - Set-CIPPSignInState -userid $username -AccountEnabled $false -tenantFilter $TenantFilter -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' - Revoke-CIPPSessions -userid $SuspectUser -username $request.body.username -ExecutingUser $request.headers.'x-ms-client-principal' -APIName $APINAME -tenantFilter $TenantFilter - $RuleDisabled = 0 - New-ExoRequest -anchor $username -tenantid $TenantFilter -cmdlet "get-inboxrule" -cmdParams @{Mailbox = $username } | ForEach-Object { - $null = New-ExoRequest -anchor $username -tenantid $TenantFilter -cmdlet "Disable-InboxRule" -cmdParams @{Confirm = $false; Identity = $_.Identity } - "Disabled Inbox Rule $($_.Identity) for $username" - $RuleDisabled ++ - } - if ($RuleDisabled) { - "Disabled $RuleDisabled Inbox Rules for $username" - } - else { - "No Inbox Rules found for $username. We have not disabled any rules." - } - - Write-LogMessage -API "BECRemediate" -tenant $tenantfilter -message "Executed Remediation for $SuspectUser" -sev "Info" - -} -catch { - #Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantfilter) -message "Failed to assign app $($appFilter): $($_.Exception.Message)" -Sev "Error" - $results = [pscustomobject]@{"Results" = "Failed to execute remediation. $($_.Exception.Message)" } - Write-LogMessage -API "BECRemediate" -tenant $tenantfilter -message "Executed Remediation for $SuspectUser failed" -sev "Error" -} -$results = [pscustomobject]@{"Results" = @($Results) } - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Results - }) diff --git a/ExecBackendURLs/function.json b/ExecBackendURLs/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecBackendURLs/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/ExecBackendURLs/run.ps1 b/ExecBackendURLs/run.ps1 deleted file mode 100644 index 3789d17af8f9..000000000000 --- a/ExecBackendURLs/run.ps1 +++ /dev/null @@ -1,35 +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' - -$Subscription = ($ENV:WEBSITE_OWNER_NAME).split('+') | Select-Object -First 1 -$SWAName = $ENV:Website_SITE_NAME -replace 'cipp', 'CIPP-SWA-' -# Write to the Azure Functions log stream. -Write-Host 'PowerShell HTTP trigger function processed a request.' - -$results = [PSCustomObject]@{ - ResourceGroup = "https://portal.azure.com/#@Go/resource/subscriptions/$Subscription/resourceGroups/$ENV:Website_Resource_Group/overview" - KeyVault = "https://portal.azure.com/#@Go/resource/subscriptions/$Subscription/resourceGroups/$ENV:Website_Resource_Group/providers/Microsoft.KeyVault/vaults/$($ENV:WEBSITE_SITE_NAME)/secrets" - FunctionApp = "https://portal.azure.com/#@Go/resource/subscriptions/$Subscription/resourceGroups/$ENV:Website_Resource_Group/providers/Microsoft.Web/sites/$($ENV:WEBSITE_SITE_NAME)/appServices" - FunctionConfig = "https://portal.azure.com/#@Go/resource/subscriptions/$Subscription/resourceGroups/$ENV:Website_Resource_Group/providers/Microsoft.Web/sites/$($ENV:WEBSITE_SITE_NAME)/configuration" - FunctionDeployment = "https://portal.azure.com/#@Go/resource/subscriptions/$Subscription/resourceGroups/$ENV:Website_Resource_Group/providers/Microsoft.Web/sites/$($ENV:WEBSITE_SITE_NAME)/vstscd" - SWADomains = "https://portal.azure.com/#@Go/resource/subscriptions/$Subscription/resourceGroups/$ENV:Website_Resource_Group/providers/Microsoft.Web/staticSites/$SWAName/customDomains" - SWARoles = "https://portal.azure.com/#@Go/resource/subscriptions/$Subscription/resourceGroups/$ENV:Website_Resource_Group/providers/Microsoft.Web/staticSites/$SWAName/roleManagement" - Subscription = $Subscription - RGName = $ENV:Website_Resource_Group - FunctionName = $ENV:WEBSITE_SITE_NAME - SWAName = $SWAName -} - - -$body = @{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/ExecCPVPermissions/function.json b/ExecCPVPermissions/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecCPVPermissions/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/ExecCPVPermissions/run.ps1 b/ExecCPVPermissions/run.ps1 deleted file mode 100644 index a015d769f4a2..000000000000 --- a/ExecCPVPermissions/run.ps1 +++ /dev/null @@ -1,44 +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.' -$TenantFilter = (get-tenants -IncludeAll -IncludeErrors | Where-Object -Property customerId -EQ $Request.query.Tenantfilter).defaultDomainName -Write-Host "Our Tenantfilter is $TenantFilter" - -$CPVConsentParams = @{ - Tenantfilter = $TenantFilter -} -if ($Request.Query.ResetSP -eq 'true') { - $CPVConsentParams.ResetSP = $true -} - -$GraphRequest = try { - Set-CIPPCPVConsent @CPVConsentParams - Add-CIPPApplicationPermission -RequiredResourceAccess 'CippDefaults' -ApplicationId $ENV:ApplicationID -tenantfilter $TenantFilter - Add-CIPPDelegatedPermission -RequiredResourceAccess 'CippDefaults' -ApplicationId $ENV:ApplicationID -tenantfilter $TenantFilter - $Success = $true -} catch { - "Failed to update permissions for $($TenantFilter): $($_.Exception.Message)" - $Success = $false -} - -$Tenant = Get-Tenants -IncludeAll -IncludeErrors | Where-Object -Property defaultDomainName -EQ $Tenantfilter - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @{ - Results = $GraphRequest - Metadata = @{ - Heading = 'CPV Permission - {0} ({1})' -f $Tenant.displayName, $Tenant.defaultDomainName - Success = $Success - } - } - }) diff --git a/ExecClrImmId/function.json b/ExecClrImmId/function.json deleted file mode 100644 index 68d371c20ff6..000000000000 --- a/ExecClrImmId/function.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "bindings": [ - { - "authLevel": "anonymous", - "type": "httpTrigger", - "direction": "in", - "name": "Request", - "methods": [ - "get" - ] - }, - { - "type": "http", - "direction": "out", - "name": "Response" - } - ] - } \ No newline at end of file diff --git a/ExecClrImmId/run.ps1 b/ExecClrImmId/run.ps1 deleted file mode 100644 index b4464b1d6fa6..000000000000 --- a/ExecClrImmId/run.ps1 +++ /dev/null @@ -1,31 +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." - -# Interact with query parameters or the body of the request. -Try { - $TenantFilter = $Request.Query.TenantFilter - $UserID = $Request.Query.ID - $Body = [pscustomobject] @{ - onPremisesImmutableId = $null - } | ConvertTo-Json - $GraphRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$UserID" -tenantid $TenantFilter -type PATCH -body $Body - $Results = [pscustomobject]@{"Results" = "Successfully Cleared ImmutableId" } -} -catch { - $Results = [pscustomobject]@{"Results" = "Failed. $_.Exception.Message"; colour = "danger" } - $_.Exception -} - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Results - }) diff --git a/ExecConverttoSharedMailbox/function.json b/ExecConverttoSharedMailbox/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecConverttoSharedMailbox/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/ExecConverttoSharedMailbox/run.ps1 b/ExecConverttoSharedMailbox/run.ps1 deleted file mode 100644 index 9ecbb30b2236..000000000000 --- a/ExecConverttoSharedMailbox/run.ps1 +++ /dev/null @@ -1,27 +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." - - -# Interact with query parameters or the body of the request. -Try { - $MailboxType = if ($request.query.ConvertToUser -eq 'true') { "Regular" } else { "Shared" } - $ConvertedMailbox = Set-CIPPMailboxType -userid $Request.query.id -tenantFilter $Request.query.TenantFilter -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' -MailboxType $MailboxType - $Results = [pscustomobject]@{"Results" = "$ConvertedMailbox" } -} -catch { - $Results = [pscustomobject]@{"Results" = "Failed to convert $($request.query.id) - $($_.Exception.Message)" } -} -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Results - }) diff --git a/ExecCopyForSent/function.json b/ExecCopyForSent/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecCopyForSent/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/ExecCopyForSent/run.ps1 b/ExecCopyForSent/run.ps1 deleted file mode 100644 index 2e318eca9042..000000000000 --- a/ExecCopyForSent/run.ps1 +++ /dev/null @@ -1,28 +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." - - -# Interact with query parameters or the body of the request. -Try { - $MessageCopyForSentAsEnabled = if ($request.query.MessageCopyForSentAsEnabled -eq 'false') { "false" } else { "true" } - $MessageResult = Set-CIPPMessageCopy -userid $Request.query.id -tenantFilter $Request.query.TenantFilter -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' -MessageCopyForSentAsEnabled $MessageCopyForSentAsEnabled - $Results = [pscustomobject]@{"Results" = "$MessageResult" } -} -catch { - $Results = [pscustomobject]@{"Results" = "set MessageCopyForSentAsEnabled to $MessageCopyForSentAsEnabled failed - $($_.Exception.Message)" } -} - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Results - }) diff --git a/ExecCreateTAP/function.json b/ExecCreateTAP/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecCreateTAP/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/ExecCreateTAP/run.ps1 b/ExecCreateTAP/run.ps1 deleted file mode 100644 index ef9ac68ca88d..000000000000 --- a/ExecCreateTAP/run.ps1 +++ /dev/null @@ -1,22 +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" - -# Interact with query parameters or the body of the request. -try { - $TAP = New-CIPPTAP -userid $Request.query.ID -TenantFilter $Request.query.tenantfilter -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' - $Results = [pscustomobject]@{"Results" = "$TAP" } -} -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 - }) \ No newline at end of file diff --git a/ExecDeleteGDAPRelationship/function.json b/ExecDeleteGDAPRelationship/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecDeleteGDAPRelationship/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/ExecDeleteGDAPRelationship/run.ps1 b/ExecDeleteGDAPRelationship/run.ps1 deleted file mode 100644 index 63d65434147a..000000000000 --- a/ExecDeleteGDAPRelationship/run.ps1 +++ /dev/null @@ -1,25 +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" - -# Interact with query parameters or the body of the request. -$GDAPID = $request.query.GDAPId -try { - $DELETE = New-GraphPostRequest -NoAuthCheck $True -uri "https://traf-pcsvcadmin-prod.trafficmanager.net/CustomerServiceAdminApi/Web/v1/delegatedAdminRelationships/$($GDAPID)/requests" -type POST -body '{"action":"terminate"}' -tenantid $env:TenantID -scope 'https://api.partnercustomeradministration.microsoft.com/.default' - $Results = [pscustomobject]@{"Results" = "Success. GDAP relationship for $($GDAPID) been revoked" } - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Success. GDAP relationship for $($GDAPID) been revoked" -Sev "Info" - -} -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 - }) \ No newline at end of file diff --git a/ExecDeleteGDAPRoleMapping/function.json b/ExecDeleteGDAPRoleMapping/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecDeleteGDAPRoleMapping/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/ExecDeleteGDAPRoleMapping/run.ps1 b/ExecDeleteGDAPRoleMapping/run.ps1 deleted file mode 100644 index d94e2964a3a4..000000000000 --- a/ExecDeleteGDAPRoleMapping/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' -$Table = Get-CIPPTable -TableName 'GDAPRoles' - -Write-Host $Table -try { - $Filter = "PartitionKey eq 'Roles' and RowKey eq '{0}'" -f $Request.Query.GroupId - $Entity = Get-CIPPAzDataTableEntity @Table -Filter $Filter - Remove-AzDataTableEntity @Table -Entity $Entity - $Results = [pscustomobject]@{'Results' = 'Success. GDAP relationship mapping deleted' } - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "GDAP relationship mapping deleted for $($Request.Query.GroupId)" -Sev 'Info' - -} 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 - }) diff --git a/ExecDeviceAction/function.json b/ExecDeviceAction/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecDeviceAction/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/ExecDeviceAction/run.ps1 b/ExecDeviceAction/run.ps1 deleted file mode 100644 index d74c194d37dc..000000000000 --- a/ExecDeviceAction/run.ps1 +++ /dev/null @@ -1,28 +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" - -# Interact with query parameters or the body of the request. - - -try { - if ($Request.Query.Action -eq "setDeviceName") { - $ActionBody = @{ deviceName = $Request.Body.input } | ConvertTo-Json -Compress - } - $ActionResult = New-CIPPDeviceAction -Action $Request.Query.Action -ActionBody $ActionBody -DeviceFilter $Request.Query.GUID -TenantFilter $Request.Query.TenantFilter -ExecutingUser $request.headers.'x-ms-client-principal' -APINAME $APINAME - $body = [pscustomobject]@{"Results" = "$ActionResult" } - -} -catch { - $body = [pscustomobject]@{"Results" = "Failed to queue action $action on $DeviceFilter $($_.Exception.Message)" } -} - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $body - }) diff --git a/ExecDisableEmailForward/function.json b/ExecDisableEmailForward/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecDisableEmailForward/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/ExecDisableEmailForward/run.ps1 b/ExecDisableEmailForward/run.ps1 deleted file mode 100644 index 117c1715a92c..000000000000 --- a/ExecDisableEmailForward/run.ps1 +++ /dev/null @@ -1,27 +0,0 @@ -using namespace System.Net - -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) -try { - $APIName = $TriggerMetadata.FunctionName - 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 - $Results = try { - Set-CIPPForwarding -userid $Request.body.user -tenantFilter $TenantFilter -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' -Forward $null -keepCopy $false -ForwardingSMTPAddress $null -Disable $true - } - catch { - "Could not disable forwarding message for $($username). Error: $($_.Exception.Message)" - } - - $body = [pscustomobject]@{"Results" = @($results) } -} -catch { - $body = [pscustomobject]@{"Results" = @("Could not disable forwarding user: $($_.Exception.message)") } -} - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Body - }) diff --git a/ExecDisableUser/function.json b/ExecDisableUser/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecDisableUser/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/ExecDisableUser/run.ps1 b/ExecDisableUser/run.ps1 deleted file mode 100644 index 428e12d454cc..000000000000 --- a/ExecDisableUser/run.ps1 +++ /dev/null @@ -1,20 +0,0 @@ -using namespace System.Net - -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) - -$APIName = $TriggerMetadata.FunctionName -try { - ([System.Convert]::ToBoolean($Request.Query.Enable)) - $State = Set-CIPPSignInState -userid $Request.query.ID -TenantFilter $Request.Query.TenantFilter -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' -AccountEnabled ([System.Convert]::ToBoolean($Request.Query.Enable)) - $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 - }) \ No newline at end of file diff --git a/ExecDnsConfig/function.json b/ExecDnsConfig/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecDnsConfig/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/ExecDnsConfig/run.ps1 b/ExecDnsConfig/run.ps1 deleted file mode 100644 index f224d28c1e9e..000000000000 --- a/ExecDnsConfig/run.ps1 +++ /dev/null @@ -1,106 +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' - -# List of supported resolvers -$ValidResolvers = @( - 'Google' - 'Cloudflare' - 'Quad9' -) - -# Write to the Azure Functions log stream. -Write-Host 'PowerShell HTTP trigger function processed a request.' - -$StatusCode = [HttpStatusCode]::OK -try { - $ConfigTable = Get-CippTable -tablename Config - $Filter = "PartitionKey eq 'Domains' and RowKey eq 'Domains'" - $Config = Get-CIPPAzDataTableEntity @ConfigTable -Filter $Filter - - $DomainTable = Get-CippTable -tablename 'Domains' - - if ($ValidResolvers -notcontains $Config.Resolver) { - $Config = @{ - PartitionKey = 'Domains' - RowKey = 'Domains' - Resolver = 'Google' - } - Add-CIPPAzDataTableEntity @ConfigTable -Entity $Config -Force - } - - $updated = $false - - switch ($Request.Query.Action) { - 'SetConfig' { - if ($Request.Query.Resolver) { - $Resolver = $Request.Query.Resolver - if ($ValidResolvers -contains $Resolver) { - try { - $Config.Resolver = $Resolver - } catch { - $Config = @{ - Resolver = $Resolver - } - } - $updated = $true - } - } - if ($updated) { - Add-CIPPAzDataTableEntity @ConfigTable -Entity $Config -Force - Write-LogMessage -API $APINAME -tenant 'Global' -user $request.headers.'x-ms-client-principal' -message 'DNS configuration updated' -Sev 'Info' - $body = [pscustomobject]@{'Results' = 'Success: DNS configuration updated.' } - } else { - $StatusCode = [HttpStatusCode]::BadRequest - $body = [pscustomobject]@{'Results' = 'Error: No DNS resolver provided.' } - } - } - 'SetDkimConfig' { - $Domain = $Request.Query.Domain - $Selector = ($Request.Query.Selector).trim() -split '\s*,\s*' - $DomainTable = Get-CIPPTable -Table 'Domains' - $Filter = "RowKey eq '{0}'" -f $Domain - $DomainInfo = Get-CIPPAzDataTableEntity @DomainTable -Filter $Filter - $DkimSelectors = [string]($Selector | ConvertTo-Json -Compress) - if ($DomainInfo) { - $DomainInfo.DkimSelectors = $DkimSelectors - } else { - $DomainInfo = @{ - 'RowKey' = $Request.Query.Domain - 'PartitionKey' = 'ManualEntry' - 'TenantId' = 'NoTenant' - 'MailProviders' = '' - 'TenantDetails' = '' - 'DomainAnalyser' = '' - 'DkimSelectors' = $DkimSelectors - } - } - Add-CIPPAzDataTableEntity @DomainTable -Entity $DomainInfo -Force - } - 'GetConfig' { - $body = [pscustomobject]$Config - Write-LogMessage -API $APINAME -tenant 'Global' -user $request.headers.'x-ms-client-principal' -message 'Retrieved DNS configuration' -Sev 'Info' - } - 'RemoveDomain' { - $Filter = "RowKey eq '{0}'" -f $Request.Query.Domain - $DomainRow = Get-CIPPAzDataTableEntity @DomainTable -Filter $Filter -Property PartitionKey, RowKey - Remove-AzDataTableEntity @DomainTable -Entity $DomainRow - Write-LogMessage -API $APINAME -tenant 'Global' -user $request.headers.'x-ms-client-principal' -message "Removed Domain - $($Request.Query.Domain) " -Sev 'Info' - $body = [pscustomobject]@{ 'Results' = "Domain removed - $($Request.Query.Domain)" } - } - } -} catch { - Write-LogMessage -API $APINAME -tenant $($name) -user $request.headers.'x-ms-client-principal' -message "DNS Config API failed. $($_.Exception.Message)" -Sev 'Error' - $body = [pscustomobject]@{'Results' = "Failed. $($_.Exception.Message)" } - $StatusCode = [HttpStatusCode]::BadRequest -} - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = $body - }) diff --git a/ExecEditCalendarPermissions/function.json b/ExecEditCalendarPermissions/function.json deleted file mode 100644 index bec6849b58ab..000000000000 --- a/ExecEditCalendarPermissions/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/ExecEditCalendarPermissions/run.ps1 b/ExecEditCalendarPermissions/run.ps1 deleted file mode 100644 index 9f1e96ee80c0..000000000000 --- a/ExecEditCalendarPermissions/run.ps1 +++ /dev/null @@ -1,32 +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" -$UserID = ($request.query.UserID) -$UserToGetPermissions = $Request.query.UserToGetPermissions -$Tenantfilter = $request.Query.tenantfilter -$Permissions = @($Request.query.permissions) -$folderName = $Request.query.folderName - - -try { - if ($Request.query.removeaccess) { - $result = Set-CIPPCalenderPermission -UserID $UserID -folderName $folderName -RemoveAccess $Request.query.removeaccess -TenantFilter $TenantFilter - } - else { - $result = Set-CIPPCalenderPermission -UserID $UserID -folderName $folderName -TenantFilter $Tenantfilter -UserToGetPermissions $UserToGetPermissions -Permissions $Permissions - $Result = "Successfully set permissions on folder $($CalParam.Identity). The user $UserToGetPermissions now has $Permissions permissions on this folder." - } -} -catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception - $Result = $ErrorMessage -} -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @{Results = $Result } - }) diff --git a/ExecEditMailboxPermissions/function.json b/ExecEditMailboxPermissions/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecEditMailboxPermissions/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/ExecEditMailboxPermissions/run.ps1 b/ExecEditMailboxPermissions/run.ps1 deleted file mode 100644 index 0b72530ce29a..000000000000 --- a/ExecEditMailboxPermissions/run.ps1 +++ /dev/null @@ -1,116 +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" -$Username = $request.body.userID -$Tenantfilter = $request.body.tenantfilter -if ($username -eq $null) { exit } -$userid = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($username)" -tenantid $Tenantfilter).id -$Results = [System.Collections.ArrayList]@() - -$RemoveFullAccess = ($Request.body.RemoveFullAccess).value -foreach ($RemoveUser in $RemoveFullAccess) { - try { - $MailboxPerms = New-ExoRequest -Anchor $username -tenantid $Tenantfilter -cmdlet "Remove-mailboxpermission" -cmdParams @{Identity = $userid; user = $RemoveUser; accessRights = @("FullAccess"); } - $results.add("Removed $($removeuser) from $($username) Shared Mailbox permissions") - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME-message "Removed $($RemoveUser) from $($username) Shared Mailbox permission" -Sev "Info" -tenant $TenantFilter - } - catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME-message "Could not remove mailbox permissions for $($removeuser) on $($username)" -Sev "Error" -tenant $TenantFilter - $results.add("Could not remove $($removeuser) shared mailbox permissions for $($username). Error: $($_.Exception.Message)") - } -} -$AddFullAccess = ($Request.body.AddFullAccess).value - -foreach ($UserAutomap in $AddFullAccess) { - try { - $MailboxPerms = New-ExoRequest -Anchor $username -tenantid $Tenantfilter -cmdlet "Add-MailboxPermission" -cmdParams @{Identity = $userid; user = $UserAutomap; accessRights = @("FullAccess"); automapping = $true } - $results.add( "Granted $($UserAutomap) access to $($username) Mailbox with automapping") - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME-message "Granted $($UserAutomap) access to $($username) Mailbox with automapping" -Sev "Info" -tenant $TenantFilter - - } - catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME-message "Could not add mailbox permissions for $($UserAutomap) on $($username)" -Sev "Error" -tenant $TenantFilter - $results.add( "Could not add $($UserAutomap) shared mailbox permissions for $($username). Error: $($_.Exception.Message)") - } -} -$AddFullAccessNoAutoMap = ($Request.body.AddFullAccessNoAutoMap).value - -foreach ($UserNoAutomap in $AddFullAccessNoAutoMap) { - try { - $MailboxPerms = New-ExoRequest -Anchor $username -tenantid $Tenantfilter -cmdlet "Add-MailboxPermission" -cmdParams @{Identity = $userid; user = $UserNoAutomap; accessRights = @("FullAccess"); automapping = $false } - $results.add( "Granted $UserNoAutomap access to $($username) Mailbox without automapping") - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME-message "Granted $UserNoAutomap access to $($username) Mailbox without automapping" -Sev "Info" -tenant $TenantFilter - } - catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME-message "Could not add mailbox permissions for $($UserNoAutomap) on $($username)" -Sev "Error" -tenant $TenantFilter - $results.add("Could not add $($UserNoAutomap) shared mailbox permissions for $($username). Error: $($_.Exception.Message)") - } -} - -$AddSendAS = ($Request.body.AddSendAs).value - -foreach ($UserSendAs in $AddSendAS) { - try { - $MailboxPerms = New-ExoRequest -Anchor $username -tenantid $Tenantfilter -cmdlet "Add-RecipientPermission" -cmdParams @{Identity = $userid; Trustee = $UserSendAs; accessRights = @("SendAs") } - $results.add( "Granted $UserSendAs access to $($username) with Send As permissions") - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME-message "Granted $UserSendAs access to $($username) with Send As permissions" -Sev "Info" -tenant $TenantFilter - } - catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME-message "Could not add mailbox permissions for $($UserSendAs) on $($username)" -Sev "Error" -tenant $TenantFilter - $results.add("Could not add $($UserSendAs) send-as permissions for $($username). Error: $($_.Exception.Message)") - } -} - -$RemoveSendAs = ($Request.body.RemoveSendAs).value - -foreach ($UserSendAs in $RemoveSendAs) { - try { - $MailboxPerms = New-ExoRequest -Anchor $username -tenantid $Tenantfilter -cmdlet "Remove-RecipientPermission" -cmdParams @{Identity = $userid; Trustee = $UserSendAs; accessRights = @("SendAs") } - $results.add( "Removed $UserSendAs from $($username) with Send As permissions") - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME-message "Removed $UserSendAs from $($username) with Send As permissions" -Sev "Info" -tenant $TenantFilter - } - catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME-message "Could not remove mailbox permissions for $($UserSendAs) on $($username)" -Sev "Error" -tenant $TenantFilter - $results.add("Could not remove $($UserSendAs) send-as permissions for $($username). Error: $($_.Exception.Message)") - } -} - -$AddSendOnBehalf = ($Request.body.AddSendOnBehalf).value - -foreach ($UserSendOnBehalf in $AddSendOnBehalf) { - try { - $MailboxPerms = New-ExoRequest -Anchor $username -tenantid $Tenantfilter -cmdlet "Set-Mailbox" -cmdParams @{Identity = $userid; GrantSendonBehalfTo = @{'@odata.type' = '#Exchange.GenericHashTable'; add = $UserSendOnBehalf}; } - $results.add( "Granted $UserSendOnBehalf access to $($username) with Send On Behalf Permissions") - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME-message "Granted $UserSendOnBehalf access to $($username) with Send On Behalf Permissions" -Sev "Info" -tenant $TenantFilter - } - catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME-message "Could not add send on behalf permissions for $($UserSendOnBehalf) on $($username)" -Sev "Error" -tenant $TenantFilter - $results.add("Could not add $($UserSendOnBehalf) send on behalf permissions for $($username). Error: $($_.Exception.Message)") - } -} - -$RemoveSendOnBehalf = ($Request.body.RemoveSendOnBehalf).value - -foreach ($UserSendOnBehalf in $RemoveSendOnBehalf) { - try { - $MailboxPerms = New-ExoRequest -Anchor $username -tenantid $Tenantfilter -cmdlet "Set-Mailbox" -cmdParams @{Identity = $userid; GrantSendonBehalfTo = @{'@odata.type' = '#Exchange.GenericHashTable'; remove = $UserSendOnBehalf}; } - $results.add( "Removed $UserSendOnBehalf from $($username) Send on Behalf Permissions") - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME-message "Removed $UserSendOnBehalf from $($username) Send on Behalf Permissions" -Sev "Info" -tenant $TenantFilter - } - catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME-message "Could not Remove send on behalf permissions for $($UserSendOnBehalf) on $($username)" -Sev "Error" -tenant $TenantFilter - $results.add("Could not remove $($UserSendOnBehalf) send on behalf permissions for $($username). Error: $($_.Exception.Message)") - } -} - -$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/ExecEditTemplate/function.json b/ExecEditTemplate/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecEditTemplate/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/ExecEditTemplate/run.ps1 b/ExecEditTemplate/run.ps1 deleted file mode 100644 index fe8139e089e4..000000000000 --- a/ExecEditTemplate/run.ps1 +++ /dev/null @@ -1,44 +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" - -try { - $Table = Get-CippTable -tablename 'templates' - $Table.Force = $true - $guid = $request.body.guid - $JSON = $request.body | Select-Object * -ExcludeProperty GUID | ConvertTo-Json - $Type = $request.Query.Type - - if ($Type -eq "IntuneTemplate") { - write-host "Intune Template" - write-host "" - $RawJSON = $request.body | Select-Object * -ExcludeProperty displayName, description, type, GUID | ConvertTo-Json -Depth 10 -Compress - Set-CIPPIntuneTemplate -RawJSON $RawJSON -GUID $GUID -DisplayName $Request.body.displayName -Description $Request.body.description -templateType $Request.body.type - } - else { - Add-CIPPAzDataTableEntity @Table -Entity @{ - JSON = "$JSON" - RowKey = "$GUID" - PartitionKey = "$Type" - GUID = "$GUID" - } - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Edited template $($Request.body.name) with GUID $GUID" -Sev "Debug" - } - $body = [pscustomobject]@{ "Results" = "Successfully saved the template" } - -} -catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to edit template: $($_.Exception.Message)" -Sev "Error" - $body = [pscustomobject]@{"Results" = "Editing template failed: $($_.Exception.Message)" } -} - - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $body - }) diff --git a/ExecEmailForward/function.json b/ExecEmailForward/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecEmailForward/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/ExecEmailForward/run.ps1 b/ExecEmailForward/run.ps1 deleted file mode 100644 index d0586980fb7e..000000000000 --- a/ExecEmailForward/run.ps1 +++ /dev/null @@ -1,70 +0,0 @@ -using namespace System.Net - -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) -$Username = $request.body.userID -$Tenantfilter = $request.body.tenantfilter -$ForwardingAddress = $request.body.ForwardInternal.value -$ForwardingSMTPAddress = $request.body.ForwardExternal -$DisableForwarding = $request.body.disableForwarding -$APIName = $TriggerMetadata.FunctionName - -if ($ForwardingAddress) { - try { - New-ExoRequest -tenantid $TenantFilter -cmdlet "Set-mailbox" -cmdParams @{Identity = $Username; ForwardingAddress = $ForwardingAddress ; DeliverToMailboxAndForward = [bool]$request.body.keepCopy } -Anchor $username - if (-not $request.body.KeepCopy) { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Set Forwarding for $($username) to $($ForwardingAddress) and not keeping a copy" -Sev "Info" -tenant $TenantFilter - $results = "Forwarding all email for $($username) to $($ForwardingAddress) and not keeping a copy" - } - elseif ($request.body.KeepCopy) { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Set Forwarding for $($username) to $($ForwardingAddress) and keeping a copy" -Sev "Info" -tenant $TenantFilter - $results = "Forwarding all email for $($username) to $($ForwardingAddress) and keeping a copy" - } - } - catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Could not add forwarding for $($username)" -Sev "Error" -tenant $TenantFilter - $results = "Could not add forwarding for $($username). Error: $($_.Exception.Message)" - - } -} - -elseif ($ForwardingSMTPAddress) { - try { - New-ExoRequest -tenantid $TenantFilter -cmdlet "Set-mailbox" -cmdParams @{Identity = $Username; ForwardingSMTPAddress = $ForwardingSMTPAddress ; DeliverToMailboxAndForward = [bool]$request.body.keepCopy } -Anchor $username - if (-not $request.body.KeepCopy) { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Set forwarding for $($username) to $($ForwardingSMTPAddress) and not keeping a copy" -Sev "Info" -tenant $TenantFilter - $results = "Forwarding all email for $($username) to $($ForwardingSMTPAddress) and not keeping a copy" - } - elseif ($request.body.KeepCopy) { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Set forwarding for $($username) to $($ForwardingSMTPAddress) and keeping a copy" -Sev "Info" -tenant $TenantFilter - $results = "Forwarding all email for $($username) to $($ForwardingSMTPAddress) and keeping a copy" - } - } - catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Could not add forwarding for $($username)" -Sev "Error" -tenant $TenantFilter - $results = "Could not add forwarding for $($username). Error: $($_.Exception.Message)" - - } - -} - -elseif ($DisableForwarding -eq "True") { - try { - New-ExoRequest -tenantid $TenantFilter -cmdlet "Set-Mailbox" -cmdParams @{Identity = $Username; ForwardingAddress = $null; ForwardingSMTPAddress = $null; DeliverToMailboxAndForward = $false } - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Disabled Email forwarding for $($username)" -Sev "Info" -tenant $TenantFilter - $results = "Disabled Email Forwarding for $($username)" -} -catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Could not disable Email forwarding for $($username)" -Sev "Error" -tenant $TenantFilter - $results = "Could not disable Email forwarding for $($username). Error: $($_.Exception.Message)" - -} -} - -$Body = @{"Results" = @($results) } - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Body - }) \ No newline at end of file diff --git a/ExecEnableArchive/function.json b/ExecEnableArchive/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecEnableArchive/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/ExecEnableArchive/run.ps1 b/ExecEnableArchive/run.ps1 deleted file mode 100644 index e11202af39cb..000000000000 --- a/ExecEnableArchive/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" - - -# Write to the Azure Functions log stream. -Write-Host "PowerShell HTTP trigger function processed a request." - - -# Interact with query parameters or the body of the request. -Try { - $ResultsArch = Set-CIPPMailboxArchive -userid $Request.query.id -tenantFilter $Request.query.TenantFilter -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' -ArchiveEnabled $true - $Results = [pscustomobject]@{"Results" = "$ResultsArch" } -} -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 - }) diff --git a/ExecExcludeLicenses/function.json b/ExecExcludeLicenses/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecExcludeLicenses/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/ExecExcludeLicenses/run.ps1 b/ExecExcludeLicenses/run.ps1 deleted file mode 100644 index 1ecedd09c706..000000000000 --- a/ExecExcludeLicenses/run.ps1 +++ /dev/null @@ -1,65 +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.' -$Table = Get-CIPPTable -TableName ExcludedLicenses -try { - - if ($Request.Query.List) { - $Rows = Get-CIPPAzDataTableEntity @Table - if ($Rows.Count -lt 1) { - $TableBaseData = '[{"GUID":"16ddbbfc-09ea-4de2-b1d7-312db6112d70","Product_Display_Name":"MICROSOFT TEAMS (FREE)"},{"GUID":"1f2f344a-700d-42c9-9427-5cea1d5d7ba6","Product_Display_Name":"MICROSOFT STREAM"},{"GUID":"338148b6-1b11-4102-afb9-f92b6cdc0f8d","Product_Display_Name":"DYNAMICS 365 P1 TRIAL FOR INFORMATION WORKERS"},{"GUID":"606b54a9-78d8-4298-ad8b-df6ef4481c80","Product_Display_Name":"Power Virtual Agents Viral Trial"},{"GUID":"61e6bd70-fbdb-4deb-82ea-912842f39431","Product_Display_Name":"Dynamics 365 Customer Service Insights Trial"},{"GUID":"6470687e-a428-4b7a-bef2-8a291ad947c9","Product_Display_Name":"WINDOWS STORE FOR BUSINESS"},{"GUID":"710779e8-3d4a-4c88-adb9-386c958d1fdf","Product_Display_Name":"MICROSOFT TEAMS EXPLORATORY"},{"GUID":"74fbf1bb-47c6-4796-9623-77dc7371723b","Product_Display_Name":"Microsoft Teams Trial"},{"GUID":"90d8b3f8-712e-4f7b-aa1e-62e7ae6cbe96","Product_Display_Name":"Business Apps (free)"},{"GUID":"a403ebcc-fae0-4ca2-8c8c-7a907fd6c235","Product_Display_Name":"Power BI (free)"},{"GUID":"bc946dac-7877-4271-b2f7-99d2db13cd2c","Product_Display_Name":"Dynamics 365 Customer Voice Trial"},{"GUID":"dcb1a3ae-b33f-4487-846a-a640262fadf4","Product_Display_Name":"Microsoft Power Apps Plan 2 Trial"},{"GUID":"f30db892-07e9-47e9-837c-80727f46fd3d","Product_Display_Name":"MICROSOFT FLOW FREE"},{"GUID":"fcecd1f9-a91e-488d-a918-a96cdb6ce2b0","Product_Display_Name":"Microsoft Dynamics AX7 User Trial"}]' | ConvertFrom-Json -AsHashtable -Depth 10 - $TableRows = foreach ($Row in $TableBaseData) { - $Row.PartitionKey = 'License' - $Row.RowKey = $Row.GUID - - Add-CIPPAzDataTableEntity @Table -Entity ([pscustomobject]$Row) -Force | Out-Null - } - - $Rows = Get-CIPPAzDataTableEntity @Table - - Write-LogMessage -API $APINAME -user $request.headers.'x-ms-client-principal' -message 'got excluded licenses list' -Sev 'Info' - } - $body = @($Rows) - } - - # Interact with query parameters or the body of the request. - $name = $Request.Query.TenantFilter - if ($Request.Query.AddExclusion) { - $AddObject = @{ - PartitionKey = 'License' - RowKey = $Request.body.GUID - 'GUID' = $Request.body.GUID - 'Product_Display_Name' = $request.body.SKUName - } - Add-CIPPAzDataTableEntity @Table -Entity $AddObject -Force - - Write-LogMessage -API $APINAME -user $request.headers.'x-ms-client-principal' -message "Added exclusion $($request.body.SKUName)" -Sev 'Info' - $body = [pscustomobject]@{'Results' = "Success. We've added $($request.body.SKUName) to the excluded list." } - } - - if ($Request.Query.RemoveExclusion) { - $Filter = "RowKey eq '{0}' and PartitionKey eq 'License'" -f $Request.Query.Guid - $Entity = Get-CIPPAzDataTableEntity @Table -Filter $Filter -Property PartitionKey, RowKey - Remove-AzDataTableEntity @Table -Entity $Entity - Write-LogMessage -API $APINAME -user $request.headers.'x-ms-client-principal' -message "Removed exclusion $($Request.Query.GUID)" -Sev 'Info' - $body = [pscustomobject]@{'Results' = "Success. We've removed $($Request.query.guid) from the excluded list." } - } -} -catch { - Write-LogMessage -API $APINAME -user $request.headers.'x-ms-client-principal' -message "Exclusion API failed. $($_.Exception.Message)" -Sev 'Error' - $body = [pscustomobject]@{'Results' = "Failed. $($_.Exception.Message)" } -} - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $body - }) diff --git a/ExecExcludeTenant/function.json b/ExecExcludeTenant/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecExcludeTenant/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/ExecExcludeTenant/run.ps1 b/ExecExcludeTenant/run.ps1 deleted file mode 100644 index f01c0873bd8d..000000000000 --- a/ExecExcludeTenant/run.ps1 +++ /dev/null @@ -1,66 +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.' -$user = $request.headers.'x-ms-client-principal' -$username = ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($user)) | ConvertFrom-Json).userDetails -$date = (Get-Date).tostring('yyyy-MM-dd') -$TenantsTable = Get-CippTable -tablename Tenants - -if ($Request.Query.List) { - $ExcludedFilter = "PartitionKey eq 'Tenants' and Excluded eq true" - $ExcludedTenants = Get-CIPPAzDataTableEntity @TenantsTable -Filter $ExcludedFilter - Write-LogMessage -API $APINAME -user $request.headers.'x-ms-client-principal' -message 'got excluded tenants list' -Sev 'Info' - $body = @($ExcludedTenants) -} -elseif ($Request.query.ListAll) { - $ExcludedTenants = Get-CIPPAzDataTableEntity @TenantsTable -filter "PartitionKey eq 'Tenants'" - Write-LogMessage -API $APINAME -user $request.headers.'x-ms-client-principal' -message 'got excluded tenants list' -Sev 'Info' - $body = @($ExcludedTenants) -} -try { - # Interact with query parameters or the body of the request. - $name = $Request.Query.TenantFilter - if ($Request.Query.AddExclusion) { - $Tenants = Get-Tenants -IncludeAll | Where-Object { $Request.body.value -contains $_.customerId } - - $Excluded = foreach ($Tenant in $Tenants) { - $Tenant.Excluded = $true - $Tenant.ExcludeUser = $username - $Tenant.ExcludeDate = $date - $Tenant - } - Write-Host ($Excluded | ConvertTo-Json) - Update-AzDataTableEntity @TenantsTable -Entity ([pscustomobject]$Excluded) - #Remove-CIPPCache - Write-LogMessage -API $APINAME -tenant $($name) -user $request.headers.'x-ms-client-principal' -message "Added exclusion for customer(s): $($Excluded.defaultDomainName -join ',')" -Sev 'Info' - $body = [pscustomobject]@{'Results' = "Success. Added exclusions for customer(s): $($Excluded.defaultDomainName -join ',')" } - } - - if ($Request.Query.RemoveExclusion) { - $Filter = "PartitionKey eq 'Tenants' and defaultDomainName eq '{0}'" -f $name - $Tenant = Get-CIPPAzDataTableEntity @TenantsTable -Filter $Filter - $Tenant.Excluded = $false - $Tenant.ExcludeUser = '' - $Tenant.ExcludeDate = '' - Update-AzDataTableEntity @TenantsTable -Entity $Tenant - #Remove-CIPPCache - Write-LogMessage -API $APINAME -tenant $($name) -user $request.headers.'x-ms-client-principal' -message "Removed exclusion for customer $($name)" -Sev 'Info' - $body = [pscustomobject]@{'Results' = "Success. We've removed $name from the excluded tenants." } - } -} -catch { - Write-LogMessage -API $APINAME -tenant $($name) -user $request.headers.'x-ms-client-principal' -message "Exclusion API failed. $($_.Exception.Message)" -Sev 'Error' - $body = [pscustomobject]@{'Results' = "Failed. $($_.Exception.Message)" } -} -if (!$body) { $body = @() } - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $body - }) diff --git a/ExecExtensionMapping/function.json b/ExecExtensionMapping/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecExtensionMapping/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/ExecExtensionMapping/run.ps1 b/ExecExtensionMapping/run.ps1 deleted file mode 100644 index b120dd08a090..000000000000 --- a/ExecExtensionMapping/run.ps1 +++ /dev/null @@ -1,38 +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.' -$Table = Get-CIPPTable -TableName CippMapping - -if ($Request.Query.List) { - switch ($Request.Query.List) { - 'Halo' { - $body = Get-HaloMapping -CIPPMapping $Table - } - } -} -try { - if ($Request.Query.AddMapping) { - switch ($Request.Query.AddMapping) { - 'Halo' { - $body = Set-HaloMapping -CIPPMapping $Table -APIName $APIName -Request $Request - } - } - } -} catch { - Write-LogMessage -API $APINAME -user $request.headers.'x-ms-client-principal' -message "mapping API failed. $($_.Exception.Message)" -Sev 'Error' - $body = [pscustomobject]@{'Results' = "Failed. $($_.Exception.Message)" } -} - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $body - }) diff --git a/ExecExtensionNinjaOneQueue/function.json b/ExecExtensionNinjaOneQueue/function.json new file mode 100644 index 000000000000..058a42bd6db9 --- /dev/null +++ b/ExecExtensionNinjaOneQueue/function.json @@ -0,0 +1,16 @@ +{ + "bindings": [ + { + "name": "QueueItem", + "type": "queueTrigger", + "direction": "in", + "queueName": "NinjaOneQueue" + }, + { + "type": "queue", + "direction": "out", + "name": "NinjaProcess", + "queueName": "NinjaOneQueue" + } + ] +} diff --git a/ExecExtensionNinjaOneQueue/run.ps1 b/ExecExtensionNinjaOneQueue/run.ps1 new file mode 100644 index 000000000000..bcb1695ae15b --- /dev/null +++ b/ExecExtensionNinjaOneQueue/run.ps1 @@ -0,0 +1,12 @@ +# Input bindings are passed in via param block. +param($QueueItem, $TriggerMetadata) + +# Write out the queue message and metadata to the information log. +Write-Host "PowerShell NinjaOne queue trigger function processed work item: $($QueueItem.NinjaAction)" + + +Switch ($QueueItem.NinjaAction) { + 'StartAutoMapping' { Invoke-NinjaOneOrgMapping } + 'AutoMapTenant' { Invoke-NinjaOneOrgMappingTenant -QueueItem $QueueItem } + 'SyncTenant' { Invoke-NinjaOneTenantSync -QueueItem $QueueItem } +} diff --git a/ExecExtensionSync/function.json b/ExecExtensionSync/function.json deleted file mode 100644 index c0b29a163b2a..000000000000 --- a/ExecExtensionSync/function.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "bindings": [ - { - "authLevel": "anonymous", - "type": "httpTrigger", - "direction": "in", - "name": "Request", - "methods": ["get", "post"] - }, - { - "type": "http", - "direction": "out", - "name": "Response" - }, - { - "type": "queue", - "direction": "out", - "name": "Msg", - "queueName": "billqueue" - } - ] -} diff --git a/ExecExtensionSync/run.ps1 b/ExecExtensionSync/run.ps1 deleted file mode 100644 index 215298a5d488..000000000000 --- a/ExecExtensionSync/run.ps1 +++ /dev/null @@ -1,34 +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' - - -try { - Write-LogMessage -API "Scheduler_Billing" -tenant "none" -message "Starting billing processing." -sev Info - $Table = Get-CIPPTable -TableName Extensionsconfig - $Configuration = (Get-CIPPAzDataTableEntity @Table).config | ConvertFrom-Json -Depth 10 - foreach ($ConfigItem in $Configuration.psobject.properties.name) { - switch ($ConfigItem) { - "Gradient" { - If ($Configuration.Gradient.enabled -and $Configuration.Gradient.BillingEnabled) { - Push-OutputBinding -Name msg -Value "LetsGo" - $Results = [pscustomobject]@{"Results" = "Succesfully started Gradient Sync" } - } - } - } - } -} -catch { - $Results = [pscustomobject]@{"Results" = "Could not start Gradient Sync: $($_.Exception.Message)" } - - Write-LogMessage -API "Scheduler_Billing" -tenant "none" -message "Could not start billing processing $($_.Exception.Message)" -sev Error -} - -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Results - }) -clobber \ No newline at end of file diff --git a/ExecExtensionTest/function.json b/ExecExtensionTest/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecExtensionTest/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/ExecExtensionsConfig/function.json b/ExecExtensionsConfig/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecExtensionsConfig/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/ExecGDAPInvite/function.json b/ExecGDAPInvite/function.json deleted file mode 100644 index 4ee273331c44..000000000000 --- a/ExecGDAPInvite/function.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "bindings": [ - { - "authLevel": "anonymous", - "type": "httpTrigger", - "direction": "in", - "name": "Request", - "methods": ["get", "post"] - }, - { - "type": "http", - "direction": "out", - "name": "Response" - } - ] -} diff --git a/ExecGDAPInviteApproved/function.json b/ExecGDAPInviteApproved/function.json deleted file mode 100644 index 7f36cd5bb076..000000000000 --- a/ExecGDAPInviteApproved/function.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "bindings": [ - { - "authLevel": "anonymous", - "type": "httpTrigger", - "direction": "in", - "name": "Request", - "methods": ["get", "post"] - }, - { - "type": "queue", - "direction": "out", - "name": "Msg", - "queueName": "gdapinvitequeue" - }, - { - "type": "http", - "direction": "out", - "name": "Response" - } - ] -} diff --git a/ExecGDAPInviteApproved/run.ps1 b/ExecGDAPInviteApproved/run.ps1 deleted file mode 100644 index 911927e6a6b2..000000000000 --- a/ExecGDAPInviteApproved/run.ps1 +++ /dev/null @@ -1,15 +0,0 @@ -using namespace System.Net - -param($Request, $TriggerMetadata) - -$APIName = $TriggerMetadata.FunctionName -Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - -Set-CIPPGDAPInviteGroups - -$body = @{Results = @('Processing recently activated GDAP relationships') } - -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $body - }) diff --git a/ExecGDAPMigration/function.json b/ExecGDAPMigration/function.json deleted file mode 100644 index 9ed224fecfec..000000000000 --- a/ExecGDAPMigration/function.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "bindings": [ - { - "authLevel": "anonymous", - "type": "httpTrigger", - "direction": "in", - "name": "Request", - "methods": ["get", "post"] - }, - { - "type": "http", - "direction": "out", - "name": "Response" - }, - { - "type": "queue", - "direction": "out", - "name": "Msg", - "queueName": "gdapqueue" - } - ] -} diff --git a/ExecGDAPMigration/run.ps1 b/ExecGDAPMigration/run.ps1 deleted file mode 100644 index 16a2353c166a..000000000000 --- a/ExecGDAPMigration/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" - -$Groups = $Request.body.gdapRoles -$Tenants = $Request.body.selectedTenants -$Results = [System.Collections.ArrayList]@() - -foreach ($Tenant in $Tenants) { - $obj = [PSCustomObject]@{ - tenant = $Tenant - gdapRoles = $Groups - } - Push-OutputBinding -Name Msg -Value $obj - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Started GDAP Migration for $($tenant.displayName)" -Sev "Debug" - $results.add("Started GDAP Migration for $($tenant.displayName)") | Out-Null -} -$body = @{Results = @($Results) } -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $body - }) \ No newline at end of file diff --git a/ExecGeoIPLookup/function.json b/ExecGeoIPLookup/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecGeoIPLookup/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/ExecGetLocalAdminPassword/function.json b/ExecGetLocalAdminPassword/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecGetLocalAdminPassword/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/ExecGetRecoveryKey/function.json b/ExecGetRecoveryKey/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecGetRecoveryKey/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/ExecGetRecoveryKey/run.ps1 b/ExecGetRecoveryKey/run.ps1 deleted file mode 100644 index c8374209d683..000000000000 --- a/ExecGetRecoveryKey/run.ps1 +++ /dev/null @@ -1,30 +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." - -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter -try { - $GraphRequest = Get-CIPPBitlockerKey -device $Request.query.GUID -tenantFilter $TenantFilter -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' - $Body = [pscustomobject]@{"Results" = $GraphRequest } - -} -catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $Body = [pscustomobject]@{"Results" = "Failed. $ErrorMessage" } - -} - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Body - }) diff --git a/ExecGraphRequest/function.json b/ExecGraphRequest/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecGraphRequest/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/ExecGraphRequest/run.ps1 b/ExecGraphRequest/run.ps1 deleted file mode 100644 index a8cd2c301a2c..000000000000 --- a/ExecGraphRequest/run.ps1 +++ /dev/null @@ -1,112 +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' - -Function ConvertTo-FlatObject { - # https://evotec.xyz/powershell-converting-advanced-object-to-flat-object/ - MIT License - [CmdletBinding()] - Param ( - [Parameter(ValueFromPipeLine)][Object[]]$Objects, - [String]$Separator = '.', - [ValidateSet('', 0, 1)]$Base = 1, - [int]$Depth = 5, - [Parameter(DontShow)][String[]]$Path, - [Parameter(DontShow)][System.Collections.IDictionary] $OutputObject - ) - Begin { - $InputObjects = [System.Collections.Generic.List[Object]]::new() - } - Process { - foreach ($O in $Objects) { - $InputObjects.Add($O) - } - } - End { - If ($PSBoundParameters.ContainsKey('OutputObject')) { - $Object = $InputObjects[0] - $Iterate = [ordered] @{} - if ($null -eq $Object) { - #Write-Verbose -Message "ConvertTo-FlatObject - Object is null" - } - elseif ($Object.GetType().Name -in 'String', 'DateTime', 'TimeSpan', 'Version', 'Enum') { - $Object = $Object.ToString() - } - elseif ($Depth) { - $Depth-- - If ($Object -is [System.Collections.IDictionary]) { - $Iterate = $Object - } - elseif ($Object -is [Array] -or $Object -is [System.Collections.IEnumerable]) { - $i = $Base - foreach ($Item in $Object.GetEnumerator()) { - $Iterate["$i"] = $Item - $i += 1 - } - } - else { - foreach ($Prop in $Object.PSObject.Properties) { - if ($Prop.IsGettable) { - $Iterate["$($Prop.Name)"] = $Object.$($Prop.Name) - } - } - } - } - If ($Iterate.Keys.Count) { - foreach ($Key in $Iterate.Keys) { - ConvertTo-FlatObject -Objects @(, $Iterate["$Key"]) -Separator $Separator -Base $Base -Depth $Depth -Path ($Path + $Key) -OutputObject $OutputObject - } - } - else { - $Property = $Path -Join $Separator - $OutputObject[$Property] = $Object - } - } - elseif ($InputObjects.Count -gt 0) { - foreach ($ItemObject in $InputObjects) { - $OutputObject = [ordered]@{} - ConvertTo-FlatObject -Objects @(, $ItemObject) -Separator $Separator -Base $Base -Depth $Depth -Path $Path -OutputObject $OutputObject - [PSCustomObject] $OutputObject - } - } - } -} -$TenantFilter = $Request.Query.TenantFilter -try { - if ($TenantFilter -ne 'AllTenants') { - $RawGraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/$($Request.Query.Endpoint)" -tenantid $TenantFilter -NoPagination [boolean]$Request.query.DisablePagination -ComplexFilter - } - else { - $RawGraphRequest = Get-Tenants | ForEach-Object -Parallel { - Import-Module .\GraphHelper.psm1 - try { - $DefaultDomainName = $_.defaultDomainName - $TenantName = $_.displayName - New-GraphGetRequest -uri "https://graph.microsoft.com/beta/$($using:Request.Query.Endpoint)" -tenantid $DefaultDomainName -NoPagination [boolean]$using:Request.query.DisablePagination -ComplexFilter | Select-Object @{ - label = 'Tenant' - expression = { $TenantName } - }, * - } - catch { - continue - } - } - - } - $GraphRequest = $RawGraphRequest | Where-Object -Property '@odata.context' -EQ $null | ConvertTo-FlatObject - $StatusCode = [HttpStatusCode]::OK -} -catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $StatusCode = [HttpStatusCode]::Forbidden - $GraphRequest = $ErrorMessage -} - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = @($GraphRequest) - }) diff --git a/ExecGroupsDelete/function.json b/ExecGroupsDelete/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecGroupsDelete/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/ExecGroupsDelete/run.ps1 b/ExecGroupsDelete/run.ps1 deleted file mode 100644 index 723d1256e9a6..000000000000 --- a/ExecGroupsDelete/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" - - -# Write to the Azure Functions log stream. -Write-Host "PowerShell HTTP trigger function processed a request." - - -# Interact with query parameters or the body of the request. -Try { - $RemoveResults = Remove-CIPPGroup -ID $Request.query.id -GroupType $Request.query.GroupType -tenantFilter $Request.query.TenantFilter -displayName $Request.query.displayName -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' - $Results = [pscustomobject]@{"Results" = $RemoveResults } -} -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 - }) diff --git a/ExecGroupsDeliveryManagement/function.json b/ExecGroupsDeliveryManagement/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecGroupsDeliveryManagement/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/ExecGroupsDeliveryManagement/run.ps1 b/ExecGroupsDeliveryManagement/run.ps1 deleted file mode 100644 index fdba10a56243..000000000000 --- a/ExecGroupsDeliveryManagement/run.ps1 +++ /dev/null @@ -1,27 +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." - - -# Interact with query parameters or the body of the request. -Try { - $SetResults = Set-CIPPGroupAuthentication -ID $Request.query.id -GroupType $Request.query.GroupType -OnlyAllowInternalString $Request.query.OnlyAllowInternal -tenantFilter $Request.query.TenantFilter -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' - $Results = [pscustomobject]@{"Results" = $SetResults } -} -catch { - $Results = [pscustomobject]@{"Results" = "Failed. $($_.Exception.Message)" } - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantfilter) -message "Delivery Management failed: $($_.Exception.Message)" -Sev "Error" -} -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Results - }) diff --git a/ExecGroupsHideFromGAL/function.json b/ExecGroupsHideFromGAL/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecGroupsHideFromGAL/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/ExecGroupsHideFromGAL/run.ps1 b/ExecGroupsHideFromGAL/run.ps1 deleted file mode 100644 index de8517b7abd4..000000000000 --- a/ExecGroupsHideFromGAL/run.ps1 +++ /dev/null @@ -1,22 +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" - -# Interact with query parameters or the body of the request. -Try { - $GroupStatus = Set-CIPPGroupGAL -Id $Request.query.id -tenantFilter $Request.query.TenantFilter -GroupType $Request.query.groupType -HiddenString $Request.query.HidefromGAL -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' - $Results = [pscustomobject]@{"Results" = $GroupStatus } -} -catch { - $Results = [pscustomobject]@{"Results" = "Failed. $($_.Exception.Message)" } - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantfilter) -message "Hide/UnHide from GAL failed: $($_.Exception.Message)" -Sev "Error" -} -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Results - }) diff --git a/ExecHideFromGAL/function.json b/ExecHideFromGAL/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecHideFromGAL/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/ExecHideFromGAL/run.ps1 b/ExecHideFromGAL/run.ps1 deleted file mode 100644 index f5dbe73a12de..000000000000 --- a/ExecHideFromGAL/run.ps1 +++ /dev/null @@ -1,25 +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" - - -$TenantFilter = $request.query.tenantfilter -Try { - $Hidden = [System.Convert]::ToBoolean($Request.query.HideFromGal) - $HideResults = Set-CIPPHideFromGAL -tenantFilter $tenantFilter -userid $Request.query.ID -HideFromGAL $Hidden -ExecutingUser $request.headers.'x-ms-client-principal' -APIName "ExecOffboardUser" - $Results = [pscustomobject]@{"Results" = $HideResults } - -} -catch { - $Results = [pscustomobject]@{"Results" = "Failed. $($_.Exception.Message)" } - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantfilter) -message "Hide/UnHide from GAL failed: $($_.Exception.Message)" -Sev "Error" -} -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Results - }) diff --git a/ExecIncidentsList/function.json b/ExecIncidentsList/function.json deleted file mode 100644 index c4fbb02afdb9..000000000000 --- a/ExecIncidentsList/function.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "bindings": [ - { - "authLevel": "anonymous", - "type": "httpTrigger", - "direction": "in", - "name": "Request", - "methods": ["get", "post"] - }, - { - "type": "http", - "direction": "out", - "name": "Response" - }, - { - "type": "queue", - "direction": "out", - "name": "Msg", - "queueName": "incidentqueue" - } - ] -} diff --git a/ExecIncidentsList/run.ps1 b/ExecIncidentsList/run.ps1 deleted file mode 100644 index 0a043bba2d03..000000000000 --- a/ExecIncidentsList/run.ps1 +++ /dev/null @@ -1,80 +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' -try { - # Interact with query parameters or the body of the request. - $TenantFilter = $Request.Query.TenantFilter - $GraphRequest = if ($TenantFilter -ne 'AllTenants') { - $incidents = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/security/incidents' -tenantid $Request.Query.TenantFilter -AsApp $true - - foreach ($incident in $incidents) { - [PSCustomObject]@{ - Tenant = $Request.Query.TenantFilter - Id = $incident.id - Status = $incident.status - IncidentUrl = $incident.incidentWebUrl - RedirectId = $incident.redirectIncidentId - DisplayName = $incident.displayName - Created = $incident.createdDateTime - Updated = $incident.lastUpdateDateTime - AssignedTo = $incident.assignedTo - Classification = $incident.classification - Determination = $incident.determination - Severity = $incident.severity - Tags = ($IncidentObj.tags -join ', ') - Comments = $incident.comments - } - } - } - else { - $Table = Get-CIPPTable -TableName cachealertsandincidents - $Filter = "PartitionKey eq 'Incident'" - $Rows = Get-CIPPAzDataTableEntity @Table -filter $Filter | Where-Object -Property Timestamp -GT (Get-Date).AddMinutes(-10) - if (!$Rows) { - Push-OutputBinding -Name Msg -Value (Get-Date).ToString() - [PSCustomObject]@{ - Waiting = $true - } - } - else { - $incidents = $Rows - foreach ($incident in $incidents) { - $IncidentObj = $incident.Incident | ConvertFrom-Json - [PSCustomObject]@{ - Tenant = $incident.Tenant - Id = $IncidentObj.id - Status = $IncidentObj.status - IncidentUrl = $IncidentObj.incidentWebUrl - RedirectId = $IncidentObj.redirectIncidentId - DisplayName = $IncidentObj.displayName - Created = $IncidentObj.createdDateTime - Updated = $IncidentObj.lastUpdateDateTime - AssignedTo = $IncidentObj.assignedTo - Classification = $IncidentObj.classification - Determination = $IncidentObj.determination - Severity = $IncidentObj.severity - Tags = ($IncidentObj.tags -join ', ') - Comments = @($IncidentObj.comments) - } - } - } - } -} -catch { - $StatusCode = [HttpStatusCode]::Forbidden - $body = $_.Exception.message -} -if (!$body) { - $StatusCode = [HttpStatusCode]::OK - $body = [PSCustomObject]@{ - MSResults = ($GraphRequest | Where-Object -Property id -NE $null) - } -} -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = $Body - }) \ No newline at end of file diff --git a/ExecIncidentsListAllTenants/run.ps1 b/ExecIncidentsListAllTenants/run.ps1 index c7222556a39b..480b27d643d9 100644 --- a/ExecIncidentsListAllTenants/run.ps1 +++ b/ExecIncidentsListAllTenants/run.ps1 @@ -6,7 +6,7 @@ Write-Host "PowerShell queue trigger function processed work item: $QueueItem" Get-Tenants | ForEach-Object -Parallel { $domainName = $_.defaultDomainName - Import-Module '.\GraphHelper.psm1' + Import-Module CippCore $Table = Get-CIPPTable -TableName 'cachealertsandincidents' try { @@ -16,26 +16,25 @@ Get-Tenants | ForEach-Object -Parallel { $GraphRequest = @{ Incident = [string]($incident | ConvertTo-Json -Depth 10) RowKey = [string]$GUID - PartitionKey = "Incident" + PartitionKey = 'Incident' Tenant = [string]$domainName } Add-CIPPAzDataTableEntity @Table -Entity $GraphRequest -Force | Out-Null } - } - catch { + } catch { $GUID = (New-Guid).Guid $AlertText = ConvertTo-Json -InputObject @{ Tenant = $domainName displayName = "Could not connect to Tenant: $($_.Exception.Message)" comments = @{ createdDateTime = (Get-Date).ToString('s') - createdbyDisplayName = "CIPP" - comment = "Could not connect" + createdbyDisplayName = 'CIPP' + comment = 'Could not connect' } - classification = "Unknown" - determination = "Unknown" - severity = "CIPP" + classification = 'Unknown' + determination = 'Unknown' + severity = 'CIPP' } $GraphRequest = @{ Incident = [string]$AlertText diff --git a/ExecListAppId/function.json b/ExecListAppId/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecListAppId/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/ExecListAppId/run.ps1 b/ExecListAppId/run.ps1 deleted file mode 100644 index d9683adb458a..000000000000 --- a/ExecListAppId/run.ps1 +++ /dev/null @@ -1,19 +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" -$ResponseURL = "$(($Request.headers.'x-ms-original-url').replace('/api/ExecListAppId','/api/ExecSAMSetup'))" - -$Results = @{ - applicationId = $ENV:ApplicationID - tenantId = $ENV:TenantID - refreshUrl = "https://login.microsoftonline.com/$ENV:TenantID/oauth2/v2.0/authorize?client_id=$ENV:ApplicationID&response_type=code&redirect_uri=$ResponseURL&response_mode=query&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default+offline_access+profile+openid&state=1&prompt=select_account" -} -# 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/ExecMailboxMobileDevices/function.json b/ExecMailboxMobileDevices/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecMailboxMobileDevices/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/ExecMailboxMobileDevices/run.ps1 b/ExecMailboxMobileDevices/run.ps1 deleted file mode 100644 index 5d14c16a87c1..000000000000 --- a/ExecMailboxMobileDevices/run.ps1 +++ /dev/null @@ -1,27 +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." - - -# Interact with query parameters or the body of the request. -Try { - $MobileResults = Set-CIPPMobileDevice -UserId $request.query.Userid -DeviceId $request.query.deviceid -Quarantine $request.query.Quarantine -tenantFilter $request.query.tenantfilter -APIName $APINAME -Delete $Request.query.Delete -ExecutingUser $request.headers.'x-ms-client-principal' - $Results = [pscustomobject]@{"Results" = $MobileResults } -} -catch { - $Results = [pscustomobject]@{"Results" = "Failed $($request.query.Userid): $($_.Exception.Message)" } -} - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Results - }) diff --git a/ExecMailboxRestore/function.json b/ExecMailboxRestore/function.json deleted file mode 100644 index bf6c3ef0c49a..000000000000 --- a/ExecMailboxRestore/function.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "scriptFile": "../Modules/CippEntryPoints/CippEntryPoints.psm1", - "entryPoint": "Receive-CippHttpTrigger", - "bindings": [ - { - "authLevel": "anonymous", - "type": "httpTrigger", - "direction": "in", - "name": "Request", - "methods": ["get", "post"] - }, - { - "type": "http", - "direction": "out", - "name": "Response" - } - ] -} diff --git a/ExecMaintenanceScripts/function.json b/ExecMaintenanceScripts/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecMaintenanceScripts/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/ExecMaintenanceScripts/run.ps1 b/ExecMaintenanceScripts/run.ps1 deleted file mode 100644 index e83bd46c96b1..000000000000 --- a/ExecMaintenanceScripts/run.ps1 +++ /dev/null @@ -1,78 +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' -Set-Location (Get-Item $PSScriptRoot).Parent.FullName -try { - $GraphToken = Get-GraphToken -returnRefresh $true - $AccessTokenDetails = Read-JwtAccessDetails -Token $GraphToken.access_token - - $ReplacementStrings = @{ - '##TENANTID##' = $env:TenantID - '##RESOURCEGROUP##' = $env:WEBSITE_RESOURCE_GROUP - '##FUNCTIONAPP##' = $env:WEBSITE_SITE_NAME - '##SUBSCRIPTION##' = (($env:WEBSITE_OWNER_NAME).split('+') | Select-Object -First 1) - '##TOKENIP##' = $AccessTokenDetails.IPAddress - } -} -catch { Write-Host $_.Exception.Message } -#$ReplacementStrings | Format-Table - -try { - $ScriptFile = $Request.Query.ScriptFile - - try { - $Filename = Split-Path -Leaf $ScriptFile - } - catch {} - - if (!$ScriptFile -or [string]::IsNullOrEmpty($ScriptFile)) { - $ScriptFiles = Get-ChildItem .\ExecMaintenanceScripts\Scripts | Select-Object -ExpandProperty PSChildName - - $ScriptOptions = foreach ($ScriptFile in $ScriptFiles) { - @{label = $ScriptFile; value = $ScriptFile } - } - $Body = @{ ScriptFiles = @($ScriptOptions) } - } - elseif (!(Get-ChildItem .\ExecMaintenanceScripts\Scripts\$Filename -ErrorAction SilentlyContinue)) { - $Body = @{ Status = 'Script does not exist' } - } - else { - $Script = Get-Content -Raw .\ExecMaintenanceScripts\Scripts\$Filename - foreach ($i in $ReplacementStrings.Keys) { - $Script = $Script -replace $i, $ReplacementStrings.$i - } - - $ScriptContent = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($Script)) - - if ($Request.Query.MakeLink) { - $Table = Get-CippTable -TableName 'MaintenanceScripts' - $LinkGuid = ([guid]::NewGuid()).ToString() - - $MaintenanceScriptRow = @{ - 'RowKey' = $LinkGuid - 'PartitionKey' = 'Maintenance' - 'ScriptContent' = $ScriptContent - } - Add-CIPPAzDataTableEntity @Table -Entity $MaintenanceScriptRow -Force - - $Body = @{ Link = "/api/PublicScripts?guid=$LinkGuid" } - } - else { - $Body = @{ ScriptContent = $ScriptContent } - } - } -} -catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantfilter) -message "Failed to retrieve maintenance scripts. Error: $($_.Exception.Message)" -Sev 'Error' - $Body = @{Status = "Failed to retrieve maintenance scripts $($_.Exception.Message)" } -} - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Body - }) diff --git a/ExecNotificationConfig/function.json b/ExecNotificationConfig/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecNotificationConfig/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/ExecNotificationConfig/run.ps1 b/ExecNotificationConfig/run.ps1 deleted file mode 100644 index 1d5238a72c59..000000000000 --- a/ExecNotificationConfig/run.ps1 +++ /dev/null @@ -1,47 +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.' -$sev = ([pscustomobject]$Request.body.Severity).value -join (',') -$results = try { - $Table = Get-CIPPTable -TableName SchedulerConfig - $SchedulerConfig = @{ - 'tenant' = 'Any' - 'tenantid' = 'TenantId' - 'type' = 'CIPPNotifications' - 'schedule' = 'Every 15 minutes' - 'Severity' = [string]$sev - 'email' = "$($Request.Body.Email)" - 'webhook' = "$($Request.Body.Webhook)" - 'onePerTenant' = [boolean]$Request.Body.onePerTenant - 'sendtoIntegration' = [boolean]$Request.Body.sendtoIntegration - 'includeTenantId' = [boolean]$Request.Body.includeTenantId - 'PartitionKey' = 'CippNotifications' - 'RowKey' = 'CippNotifications' - } - foreach ($logvalue in [pscustomobject]$Request.body.logsToInclude) { - $SchedulerConfig[([pscustomobject]$logvalue.value)] = $true - } - - Add-CIPPAzDataTableEntity @Table -Entity $SchedulerConfig -Force | Out-Null - 'Successfully set the configuration' -} -catch { - "Failed to set configuration: $($_.Exception.message)" -} - - -$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/ExecOffboardTenant/function.json b/ExecOffboardTenant/function.json deleted file mode 100644 index 4ee273331c44..000000000000 --- a/ExecOffboardTenant/function.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "bindings": [ - { - "authLevel": "anonymous", - "type": "httpTrigger", - "direction": "in", - "name": "Request", - "methods": ["get", "post"] - }, - { - "type": "http", - "direction": "out", - "name": "Response" - } - ] -} diff --git a/ExecOffboardTenant/run.ps1 b/ExecOffboardTenant/run.ps1 deleted file mode 100644 index a8be1ff1d1b5..000000000000 --- a/ExecOffboardTenant/run.ps1 +++ /dev/null @@ -1,108 +0,0 @@ -using namespace System.Net -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) -try { - $APIName = $TriggerMetadata.FunctionName - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Accessed this API" -Sev "Debug" - - $Tenantfilter = $request.body.tenantfilter - - $results = [System.Collections.ArrayList]@() - $errors = [System.Collections.ArrayList]@() - - if ($request.body.RemoveCSPGuestUsers) { - # Delete guest users who's domains match the CSP tenants - try { - try { - $domains = (New-GraphGETRequest -Uri "https://graph.microsoft.com/v1.0/domains?`$select=id" -tenantid $env:TenantID -NoAuthCheck:$true).id - $CSPGuestUsers = (New-GraphGETRequest -Uri "https://graph.microsoft.com/v1.0/users?`$select=id,mail&`$filter=userType eq 'Guest' and $(($domains | ForEach-Object { "endswith(mail, '$_')" }) -join " or ")&`$count=true" -tenantid $Tenantfilter -ComplexFilter) - } catch { - $errors.Add("Failed to retrieve guest users: $($_.Exception.message)") - } - - if ($CSPGuestUsers) { - [System.Collections.Generic.List[PSCustomObject]]$BulkRequests = @($CSPGuestUsers | ForEach-Object { - @{ - id = $($_.id) - method = "DELETE" - url = "/users/$($_.id)" - } - }) - - $BulkResults = New-GraphBulkRequest -Requests $BulkRequests -tenantid $TenantFilter - - $results.Add("Succesfully removed guest users") - } else { - $results.Add("No guest users found to remove") - } - } catch { - $errors.Add("Something went wrong while deleting guest users: $($_.Exception.message)") - } - } - - # All customer tenant specific actions ALWAYS have to be completed before this action! - if ($request.body.RemoveMultitenantApps) { - # Remove multi-tenant apps with the CSP tenant as origin - try { - $multitenantCSPApps = (New-GraphGETRequest -Uri "https://graph.microsoft.com/v1.0/servicePrincipals?`$count=true&`$select=displayName,appId,id,appOwnerOrganizationId&`$filter=appOwnerOrganizationId eq $($env:TenantID)" -tenantid $Tenantfilter -ComplexFilter) - $sortedArray = $multitenantCSPApps | Sort-Object @{Expression = { if ($_.appId -eq $env:applicationid) { 1 } else { 0 } }; Ascending = $true } - $sortedArray | ForEach-Object { - try { - $delete = (New-GraphPostRequest -type "DELETE" -Uri "https://graph.microsoft.com/v1.0/serviceprincipals/$($_.id)" -tenantid $Tenantfilter) - $results.Add("Succesfully removed app $($_.displayName)") - } catch { - #$results.Add("Failed to removed app $($_.displayName)") - $errors.Add("Failed to removed app $($_.displayName)") - } - } - } catch { - #$results.Add("Failed to retrieve multitenant apps, no apps have been removed: $($_.Exception.message)") - $errors.Add("Failed to retrieve multitenant apps, no apps have been removed: $($_.Exception.message)") - } - } - - if ($request.body.TerminateGDAP) { - # Terminate GDAP relationships - try { - $delegatedAdminRelationships = (New-GraphGETRequest -Uri "https://graph.microsoft.com/v1.0/tenantRelationships/delegatedAdminRelationships?`$filter=(status eq 'active') AND (customer/tenantId eq '$TenantFilter')" -tenantid $env:TenantID) - $delegatedAdminRelationships | ForEach-Object { - try { - $terminate = (New-GraphPostRequest -type "POST" -Uri "https://graph.microsoft.com/v1.0/tenantRelationships/delegatedAdminRelationships/$($_.id)/requests" -body '{"action":"terminate"}' -ContentType "application/json" -tenantid $env:TenantID) - $results.Add("Succesfully terminated GDAP relationship $($_.displayName) from tenant $TenantFilter") - } catch { - #$results.Add("Failed to terminate GDAP relationship $($_.displayName): $($_.Exception.message)") - $errors.Add("Failed to terminate GDAP relationship $($_.displayName): $($_.Exception.message)") - } - } - } catch { - #$results.Add("Failed to retrieve GDAP relationships, no relationships have been terminated: $($_.Exception.message)") - $errors.Add("Failed to retrieve GDAP relationships, no relationships have been terminated: $($_.Exception.message)") - } - } - - if ($request.body.TerminateContract) { - # Terminate contract relationship - try { - $terminate = (New-GraphPostRequest -type "PATCH" -body '{ "relationshipToPartner": "none" }' -Uri "https://api.partnercenter.microsoft.com/v1/customers/$TenantFilter" -ContentType "application/json" -scope "https://api.partnercenter.microsoft.com/user_impersonation" -tenantid $env:TenantID) - $results.Add("Succesfully terminated contract relationship") - } - catch { - #$results.Add("Failed to terminate contract relationship: $($_.Exception.message)") - $errors.Add("Failed to terminate contract relationship: $($_.Exception.message)") - } - } - - $StatusCode = [HttpStatusCode]::OK - $body = [pscustomobject]@{ - "Results" = @($results) - "Errors" = @($errors) - } -} -catch { - $StatusCode = [HttpStatusCode]::OK - $body = $_.Exception.message -} -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = $Body - }) \ No newline at end of file diff --git a/ExecOffboardUser/function.json b/ExecOffboardUser/function.json deleted file mode 100644 index f7988840965c..000000000000 --- a/ExecOffboardUser/function.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "bindings": [ - { - "authLevel": "anonymous", - "type": "httpTrigger", - "direction": "in", - "name": "Request", - "methods": ["get", "post"] - }, - { - "type": "http", - "direction": "out", - "name": "Response" - }, - { - "type": "queue", - "direction": "out", - "name": "Msg", - "queueName": "offboardingmailbox" - } - ] -} diff --git a/ExecOffboardUser/run.ps1 b/ExecOffboardUser/run.ps1 deleted file mode 100644 index 53afa5424071..000000000000 --- a/ExecOffboardUser/run.ps1 +++ /dev/null @@ -1,45 +0,0 @@ -using namespace System.Net -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) -try { - $APIName = $TriggerMetadata.FunctionName - 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 - $Results = if ($Request.body.Scheduled.enabled) { - $taskObject = [PSCustomObject]@{ - TenantFilter = $Tenantfilter - Name = "Offboarding: $Username" - Command = @{ - value = "Invoke-CIPPOffboardingJob" - } - Parameters = @{ - Username = $Username - APIName = "Scheduled Offboarding" - options = $request.body - } - ScheduledTime = $Request.body.scheduled.date - PostExecution = @{ - Webhook = [bool]$Request.Body.PostExecution.webhook - Email = [bool]$Request.Body.PostExecution.email - PSA = [bool]$Request.Body.PostExecution.psa - } - } - - Add-CIPPScheduledTask -Task $taskObject -hidden $false - } - else { - Invoke-CIPPOffboardingJob -Username $Username -TenantFilter $Tenantfilter -Options $Request.body -APIName $APIName -ExecutingUser $request.headers.'x-ms-client-principal' - } - $StatusCode = [HttpStatusCode]::OK - $body = [pscustomobject]@{"Results" = @($results) } -} -catch { - $StatusCode = [HttpStatusCode]::Forbidden - $body = $_.Exception.message -} -$Request.Body.PostExecution -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = $Body - }) diff --git a/ExecOneDriveShortCut/function.json b/ExecOneDriveShortCut/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecOneDriveShortCut/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/ExecOneDriveShortCut/run.ps1 b/ExecOneDriveShortCut/run.ps1 deleted file mode 100644 index ddb4566d600a..000000000000 --- a/ExecOneDriveShortCut/run.ps1 +++ /dev/null @@ -1,21 +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" - -Try { - $MessageResult = New-CIPPOneDriveShortCut -username $Request.body.username -userid $Request.body.userid -TenantFilter $Request.Body.TenantFilter -URL $Request.body.input -ExecutingUser $request.headers.'x-ms-client-principal' - $Results = [pscustomobject]@{ "Results" = "$MessageResult" } -} -catch { - $Results = [pscustomobject]@{"Results" = "Onedrive Shortcut creation failed: $($_.Exception.Message)" } -} - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Results - }) diff --git a/ExecPasswordConfig/function.json b/ExecPasswordConfig/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecPasswordConfig/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/ExecPasswordConfig/run.ps1 b/ExecPasswordConfig/run.ps1 deleted file mode 100644 index 104b9eaf1f7f..000000000000 --- a/ExecPasswordConfig/run.ps1 +++ /dev/null @@ -1,41 +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' - -$Table = Get-CIPPTable -TableName Settings -$PasswordType = (Get-CIPPAzDataTableEntity @Table) - -# Write to the Azure Functions log stream. -Write-Host 'PowerShell HTTP trigger function processed a request.' -$results = try { - if ($Request.Query.List) { - @{ passwordType = $PasswordType.passwordType } - } - else { - $SchedulerConfig = @{ - 'passwordType' = "$($Request.Body.passwordType)" - 'passwordCount' = "12" - 'PartitionKey' = 'settings' - 'RowKey' = 'settings' - } - - Add-CIPPAzDataTableEntity @Table -Entity $SchedulerConfig -Force | Out-Null - 'Successfully set the configuration' - } -} -catch { - "Failed to set configuration: $($_.Exception.message)" -} - - -$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/ExecQuarantineManagement/function.json b/ExecQuarantineManagement/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecQuarantineManagement/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/ExecQuarantineManagement/run.ps1 b/ExecQuarantineManagement/run.ps1 deleted file mode 100644 index aa1bdb83a53d..000000000000 --- a/ExecQuarantineManagement/run.ps1 +++ /dev/null @@ -1,36 +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." - - -# Interact with query parameters or the body of the request. -Try { - $tenantfilter = $Request.Query.TenantFilter - $params = @{ - Identity = $request.query.ID; - AllowSender = [boolean]$Request.query.AllowSender - ReleasetoAll = [boolean]$Request.query.type - ActionType = $Request.query.type - } - Write-Host $params - New-ExoRequest -tenantid $TenantFilter -cmdlet "Release-QuarantineMessage" -cmdParams $Params - $Results = [pscustomobject]@{"Results" = "Successfully processed $($request.query.ID)" } - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantfilter) -message "$($request.query.id)" -Sev "Info" -} -catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantfilter) -message "Quarantine Management failed: $($_.Exception.Message)" -Sev "Error" - $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 - }) diff --git a/ExecResetMFA/function.json b/ExecResetMFA/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecResetMFA/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/ExecResetPass/function.json b/ExecResetPass/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecResetPass/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/ExecResetPass/run.ps1 b/ExecResetPass/run.ps1 deleted file mode 100644 index aef245f5248d..000000000000 --- a/ExecResetPass/run.ps1 +++ /dev/null @@ -1,31 +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." -Write-Host "$($Request.query.ID)" -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter -$mustChange = [System.Convert]::ToBoolean($request.query.MustChange) - -try { - $Reset = Set-CIPPResetPassword -userid $Request.query.ID -tenantFilter $TenantFilter -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' -forceChangePasswordNextSignIn $mustChange - $Results = [pscustomobject]@{"Results" = "$Reset" } -} -catch { - $Results = [pscustomobject]@{"Results" = "Failed to reset password for $($Request.query.displayName): $($_.Exception.Message)" } - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to reset password for $($Request.query.displayName): $($_.Exception.Message)" -Sev "Error" - -} - -# 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/ExecRestoreBackup/function.json b/ExecRestoreBackup/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecRestoreBackup/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/ExecRestoreBackup/run.ps1 b/ExecRestoreBackup/run.ps1 deleted file mode 100644 index 1b0a39db9893..000000000000 --- a/ExecRestoreBackup/run.ps1 +++ /dev/null @@ -1,34 +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" -try { - foreach ($line in ($Request.body | ConvertFrom-Json | Select-Object * -ExcludeProperty ETag)) { - Write-Host ($line) - $Table = Get-CippTable -tablename $line.table - $ht2 = @{} - $line.psobject.properties | ForEach-Object { $ht2[$_.Name] = [string]$_.Value } - $Table.Entity = $ht2 - Add-CIPPAzDataTableEntity @Table -Force - - } - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Created backup" -Sev "Debug" - - $body = [pscustomobject]@{ - "Results" = "Succesfully restored backup."; - } -} -catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to create backup: $($_.Exception.Message)" -Sev "Error" - $body = [pscustomobject]@{"Results" = "Backup Creation failed: $($_.Exception.Message)" } -} - - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $body - }) diff --git a/ExecRestoreDeleted/function.json b/ExecRestoreDeleted/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecRestoreDeleted/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/ExecRestoreDeleted/run.ps1 b/ExecRestoreDeleted/run.ps1 deleted file mode 100644 index 3ebea4012d78..000000000000 --- a/ExecRestoreDeleted/run.ps1 +++ /dev/null @@ -1,24 +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" - -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter - -try { - $GraphRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/v1.0/directory/deletedItems/$($Request.query.ID)/restore" -tenantid $TenantFilter -type POST -body '{}' -verbose - $Results = [pscustomobject]@{"Results" = "Successfully completed request." } -} -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 - }) \ No newline at end of file diff --git a/ExecRevokeSessions/function.json b/ExecRevokeSessions/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecRevokeSessions/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/ExecRevokeSessions/run.ps1 b/ExecRevokeSessions/run.ps1 deleted file mode 100644 index f3185f6de2fd..000000000000 --- a/ExecRevokeSessions/run.ps1 +++ /dev/null @@ -1,23 +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" - -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter -try { - $RevokeSessions = Revoke-CIPPSessions -userid $Request.Query.id -tenantFilter $TenantFilter -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' - $Results = [pscustomobject]@{"Results" = $RevokeSessions } -} -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 - }) \ No newline at end of file diff --git a/ExecRunBackup/function.json b/ExecRunBackup/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecRunBackup/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/ExecRunBackup/run.ps1 b/ExecRunBackup/run.ps1 deleted file mode 100644 index 32e6c1025d77..000000000000 --- a/ExecRunBackup/run.ps1 +++ /dev/null @@ -1,44 +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" -try { - if ($request.query.Selected) { - $BackupTables = $request.query.Selected -split ',' - } - else { - $BackupTables = @( - "bpa" - "Config" - "Domains" - "ExcludedLicenses" - "templates" - "standards" - "SchedulerConfig" - ) - } - $CSVfile = foreach ($CSVTable in $BackupTables) { - $Table = Get-CippTable -tablename $CSVTable - Get-CIPPAzDataTableEntity @Table | Select-Object *, @{l = 'table'; e = { $CSVTable } } - } - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Created backup" -Sev "Debug" - - $body = [pscustomobject]@{ - "Results" = "Created backup"; - backup = $CSVfile - } -} -catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to create backup: $($_.Exception.Message)" -Sev "Error" - $body = [pscustomobject]@{"Results" = "Backup Creation failed: $($_.Exception.Message)" } -} - - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $body - }) diff --git a/ExecSAMSetup/function.json b/ExecSAMSetup/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecSAMSetup/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/ExecSAMSetup/run.ps1 b/ExecSAMSetup/run.ps1 deleted file mode 100644 index 898f4cd7c44d..000000000000 --- a/ExecSAMSetup/run.ps1 +++ /dev/null @@ -1,199 +0,0 @@ -using namespace System.Net -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) -Set-Location (Get-Item $PSScriptRoot).Parent.FullName -$UserCreds = ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($request.headers.'x-ms-client-principal')) | ConvertFrom-Json) - -if ($Request.query.error) { - Add-Type -AssemblyName System.Web - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - ContentType = 'text/html' - StatusCode = [HttpStatusCode]::Forbidden - Body = Get-normalizedError -Message [System.Web.HttpUtility]::UrlDecode($Request.Query.error_description) - }) - exit -} -if ("admin" -notin $UserCreds.userRoles) { - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - ContentType = 'text/html' - StatusCode = [HttpStatusCode]::Forbidden - Body = 'Could not find an admin cookie in your browser. Make sure you do not have an adblocker active, use a Chromium browser, and allow cookies. If our automatic refresh does not work, try pressing the URL bar and hitting enter. We will try to refresh ourselves in 3 seconds.' - }) - exit -} - -$APIName = $TriggerMetadata.FunctionName -Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Accessed this API" -Sev "Debug" -if ($env:MSI_SECRET) { - Disable-AzContextAutosave -Scope Process | Out-Null - $AzSession = Connect-AzAccount -Identity -} -if (!$ENV:SetFromProfile) { - Write-Host "We're reloading from KV" - Get-CIPPAuthentication -} - -$KV = $ENV:WEBSITE_DEPLOYMENT_ID -$Table = Get-CIPPTable -TableName SAMWizard -$Rows = Get-CIPPAzDataTableEntity @Table | Where-Object -Property Timestamp -GT (Get-Date).AddMinutes(-10) - -try { - if ($Request.query.count -lt 1 ) { $Results = "No authentication code found. Please go back to the wizard." } - - if ($request.body.setkeys) { - if ($request.body.tenantid) { Set-AzKeyVaultSecret -VaultName $kv -Name 'tenantid' -SecretValue (ConvertTo-SecureString -String $request.body.tenantid -AsPlainText -Force) } - if ($request.body.RefreshToken) { Set-AzKeyVaultSecret -VaultName $kv -Name 'RefreshToken' -SecretValue (ConvertTo-SecureString -String $request.body.RefreshToken -AsPlainText -Force) } - if ($request.body.applicationid) { Set-AzKeyVaultSecret -VaultName $kv -Name 'applicationid' -SecretValue (ConvertTo-SecureString -String $request.body.applicationid -AsPlainText -Force) } - if ($request.body.applicationsecret) { Set-AzKeyVaultSecret -VaultName $kv -Name 'applicationsecret' -SecretValue (ConvertTo-SecureString -String $request.body.applicationsecret -AsPlainText -Force) } - $Results = @{ Results = "The keys have been replaced. Please perform a permissions check." } - } - if ($Request.query.error -eq 'invalid_client') { $Results = "Client ID was not found in Azure. Try waiting 10 seconds to try again, if you have gotten this error after 5 minutes, please restart the process." } - if ($request.query.code) { - try { - $TenantId = $Rows.tenantid - if (!$TenantId) { $TenantId = $ENV:TenantId } - $AppID = $Rows.appid - if (!$AppID) { $appid = $env:ApplicationId } - $URL = ($Request.headers.'x-ms-original-url').split('?') | Select-Object -First 1 - $clientsecret = Get-AzKeyVaultSecret -VaultName $kv -Name 'applicationsecret' -AsPlainText - if (!$clientsecret) { $clientsecret = $ENV:ApplicationSecret } - $RefreshToken = Invoke-RestMethod -Method POST -Body "client_id=$appid&scope=https://graph.microsoft.com/.default+offline_access+openid+profile&code=$($request.query.code)&grant_type=authorization_code&redirect_uri=$($url)&client_secret=$clientsecret" -Uri "https://login.microsoftonline.com/$TenantId/oauth2/v2.0/token" - Set-AzKeyVaultSecret -VaultName $kv -Name 'RefreshToken' -SecretValue (ConvertTo-SecureString -String $RefreshToken.refresh_token -AsPlainText -Force) - $Results = "Authentication is now complete. You may now close this window." - try { - $SetupPhase = $rows.validated = $true - Add-CIPPAzDataTableEntity @Table -Entity $Rows -Force | Out-Null - } - catch { - #no need. - } - } - catch { - $Results = "Authentication failed. $($_.Exception.message)" - } - } - if ($request.query.CreateSAM) { - $Rows = @{ - RowKey = "setup" - PartitionKey = "setup" - validated = $false - SamSetup = "NotStarted" - partnersetup = $false - appid = "NotStarted" - tenantid = "NotStarted" - } - Add-CIPPAzDataTableEntity @Table -Entity $Rows -Force | Out-Null - $Rows = Get-CIPPAzDataTableEntity @Table | Where-Object -Property Timestamp -GT (Get-Date).AddMinutes(-10) - - if ($Request.query.partnersetup) { - $SetupPhase = $Rows.partnersetup = $true - Add-CIPPAzDataTableEntity @Table -Entity $Rows -Force | Out-Null - } - $step = 1 - $DeviceLogon = New-DeviceLogin -clientid "1b730954-1685-4b74-9bfd-dac224a7b894" -Scope 'https://graph.microsoft.com/.default' -FirstLogon - $SetupPhase = $rows.SamSetup = [string]($DeviceLogon | ConvertTo-Json) - Add-CIPPAzDataTableEntity @Table -Entity $Rows -Force | Out-Null - $Results = @{ message = "Your code is $($DeviceLogon.user_code). Enter the code" ; step = $step; url = $DeviceLogon.verification_uri } - } - if ($Request.query.CheckSetupProcess -and $request.query.step -eq 1) { - $SAMSetup = $Rows.SamSetup | ConvertFrom-Json -ErrorAction SilentlyContinue - $Token = (New-DeviceLogin -clientid "1b730954-1685-4b74-9bfd-dac224a7b894" -Scope 'https://graph.microsoft.com/.default' -device_code $SAMSetup.device_code) - if ($token.Access_Token) { - $step = 2 - $URL = ($Request.headers.'x-ms-original-url').split('?') | Select-Object -First 1 - $PartnerSetup = $Rows.partnersetup - $TenantId = (Invoke-RestMethod "https://graph.microsoft.com/v1.0/organization" -Headers @{ authorization = "Bearer $($Token.Access_Token)" } -Method GET -ContentType 'application/json').value.id - $SetupPhase = $rows.tenantid = [string]($TenantId) - Add-CIPPAzDataTableEntity @Table -Entity $Rows -Force | Out-Null - if ($PartnerSetup) { - $app = Get-Content '.\Cache_SAMSetup\SAMManifest.json' | ConvertFrom-Json - $App.web.redirectUris = @($App.web.redirectUris + $URL) - $app = $app | ConvertTo-Json -Depth 15 - $AppId = (Invoke-RestMethod "https://graph.microsoft.com/v1.0/applications" -Headers @{ authorization = "Bearer $($Token.Access_Token)" } -Method POST -Body $app -ContentType 'application/json') - $rows.appid = [string]($AppId.appId) - Add-CIPPAzDataTableEntity @Table -Entity $Rows -Force | Out-Null - $attempt = 0 - do { - try { - try { - $SPNDefender = (Invoke-RestMethod "https://graph.microsoft.com/v1.0/servicePrincipals" -Headers @{ authorization = "Bearer $($Token.Access_Token)" } -Method POST -Body "{ `"appId`": `"fc780465-2017-40d4-a0c5-307022471b92`" }" -ContentType 'application/json') - } - catch { - Write-Host "didn't deploy spn for defender, probably already there." - } - try { - $SPNTeams = (Invoke-RestMethod "https://graph.microsoft.com/v1.0/servicePrincipals" -Headers @{ authorization = "Bearer $($Token.Access_Token)" } -Method POST -Body "{ `"appId`": `"48ac35b8-9aa8-4d74-927d-1f4a14a0b239`" }" -ContentType 'application/json') - } - catch { - Write-Host "didn't deploy spn for Teams, probably already there." - } - $SPN = (Invoke-RestMethod "https://graph.microsoft.com/v1.0/servicePrincipals" -Headers @{ authorization = "Bearer $($Token.Access_Token)" } -Method POST -Body "{ `"appId`": `"$($AppId.appId)`" }" -ContentType 'application/json') - Start-Sleep 3 - $GroupID = (Invoke-RestMethod "https://graph.microsoft.com/v1.0/groups?`$filter=startswith(displayName,'AdminAgents')" -Headers @{ authorization = "Bearer $($Token.Access_Token)" } -Method Get -ContentType 'application/json').value.id - Write-Host "Id is $GroupID" - $AddingToAdminAgent = (Invoke-RestMethod "https://graph.microsoft.com/v1.0/groups/$($GroupID)/members/`$ref" -Headers @{ authorization = "Bearer $($Token.Access_Token)" } -Method POST -Body "{ `"@odata.id`": `"https://graph.microsoft.com/v1.0/directoryObjects/$($SPN.id)`"}" -ContentType 'application/json') - Write-Host "Added to adminagents" - $attempt ++ - } - catch { - $attempt ++ - } - } until ($attempt -gt 5) - } - else { - $app = Get-Content '.\Cache_SAMSetup\SAMManifestNoPartner.json' - $AppId = (Invoke-RestMethod "https://graph.microsoft.com/v1.0/applications" -Headers @{ authorization = "Bearer $($Token.Access_Token)" } -Method POST -Body $app -ContentType 'application/json') - $rows.appid = [string]($AppId.appId) - Add-CIPPAzDataTableEntity @Table -Entity $Rows -Force | Out-Null - } - $AppPassword = (Invoke-RestMethod "https://graph.microsoft.com/v1.0/applications/$($AppID.id)/addPassword" -Headers @{ authorization = "Bearer $($Token.Access_Token)" } -Method POST -Body '{"passwordCredential":{"displayName":"CIPPInstall"}}' -ContentType 'application/json').secretText - Set-AzKeyVaultSecret -VaultName $kv -Name 'tenantid' -SecretValue (ConvertTo-SecureString -String $TenantId -AsPlainText -Force) - Set-AzKeyVaultSecret -VaultName $kv -Name 'applicationid' -SecretValue (ConvertTo-SecureString -String $Appid.appid -AsPlainText -Force) - Set-AzKeyVaultSecret -VaultName $kv -Name 'applicationsecret' -SecretValue (ConvertTo-SecureString -String $AppPassword -AsPlainText -Force) - $Results = @{"message" = "Created application. Waiting 30 seconds for Azure propagation"; step = $step } - } - else { - $step = 1 - $Results = @{ message = "Your code is $($SAMSetup.user_code). Enter the code " ; step = $step; url = $SAMSetup.verification_uri } - } - - } - switch ($request.query.step) { - 2 { - $step = 2 - $TenantId = $Rows.tenantid - $AppID = $rows.appid - $PartnerSetup = $Rows.partnersetup - $SetupPhase = $rows.SamSetup = [string]($FirstLogonRefreshtoken | ConvertTo-Json) - Add-CIPPAzDataTableEntity @Table -Entity $Rows -Force | Out-Null - $URL = ($Request.headers.'x-ms-original-url').split('?') | Select-Object -First 1 - $Validated = $Rows.validated - if ($Validated) { $step = 3 } - $Results = @{ message = "Give the next approval by clicking " ; step = $step; url = "https://login.microsoftonline.com/$TenantId/oauth2/v2.0/authorize?scope=https://graph.microsoft.com/.default+offline_access+openid+profile&response_type=code&client_id=$($appid)&redirect_uri=$($url)" } - } - 3 { - - $step = 4 - $Results = @{"message" = "Received token."; step = $step } - - - } - 4 { - Remove-AzDataTableEntity @Table -Entity $Rows - - $step = 5 - $Results = @{"message" = "Installation completed."; step = $step - } - } - } - -} -catch { - $Results = [pscustomobject]@{"Results" = "Failed. $($_.InvocationInfo.ScriptLineNumber): $($_.Exception.message)" ; step = $step } -} - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Results - }) diff --git a/ExecSendOrgMessage/function.json b/ExecSendOrgMessage/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecSendOrgMessage/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/ExecSendOrgMessage/run.ps1 b/ExecSendOrgMessage/run.ps1 deleted file mode 100644 index e42b4c988521..000000000000 --- a/ExecSendOrgMessage/run.ps1 +++ /dev/null @@ -1,116 +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." - -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter -$Device = $request.query.ID -try { - - $type = switch ($request.Query.type) { - 'taskbar' { - '844ec9d0-dd31-459c-a1e7-21fb1b39d5da' - $placementDetails = @(@{ - placement = 'default' - variants = @(@{ - variantId = "b3fce1ee-9658-4267-b174-23d4a1be148f" - localizedTexts = @(@{ - locale = "invariant" - text = @{ - "clickUrl" = $Request.query.URL - } - }) - }) - }) - } - 'notification' { - '1ff7c7e7-128c-4e18-a926-bdac4e906ea1' - $placementDetails = @(@{ - placement = 'default' - variants = @(@{ - variantId = "7a1419c9-9263-4202-9225-35b326b92792" - localizedTexts = @(@{ - locale = "invariant" - text = @{ - "clickUrl" = $Request.query.URL - } - }) - }) - }) - } - 'getStarted' { - $placementDetails = @(@{ - placement = 'card0' - variants = @(@{ - variantId = "ed0d0fa2-df72-42f4-9866-66cf3de1fafb" - localizedTexts = @(@{ - locale = "invariant" - text = @{ - "message" = "My Message Value" - "clickUrl" = "https://example.com/clickUrl/" - "title" = "This message" - "buttonText" = "PlzClick" - } - }) - }) - } - @{ - placement = 'card1' - variants = @(@{ - variantId = "ed0d0fa2-df72-42f4-9866-66cf3de1fafb" - localizedTexts = @(@{ - locale = "invariant" - text = @{ - "message" = "My Message Value" - "clickUrl" = "https://example.com/clickUrl/" - "title" = "This message" - "buttonText" = "PlzClick" - } - }) - }) - }) - } - - } - $freq = $request.query.freq - $object = [pscustomobject]@{ - startDateTime = (Get-Date).ToString("O") - endDateTime = (Get-Date).AddYears('1').ToString("O") - frequency = $freq - targeting = @{ - targetingType = 'aadGroup' - includeIds = @($Device) - } - content = @{ - "guidedContentId" = "$Type" - placementDetails = $placementDetails - logoInfo = @{ - contentType = "png" - logoCdnUrl = 'https://hulpnu.nl/tools/Red.jpg' - } - } - } - $tmpbody = ConvertTo-Json -Depth 15 -Compress -InputObject $object - Write-Host $tmpbody - - $GraphRequest = New-GraphPOSTRequest -noauthcheck $true -type "POST" -uri "https://graph.microsoft.com/beta/deviceManagement/organizationalMessageDetails" -tenantid $tenantfilter -body $tmpbody - $StatusCode = [HttpStatusCode]::OK -} -catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $StatusCode = [HttpStatusCode]::Forbidden - $GraphRequest = $ErrorMessage -} -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = @($GraphRequest) - }) diff --git a/ExecSendPush/function.json b/ExecSendPush/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecSendPush/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/ExecSendPush/run.ps1 b/ExecSendPush/run.ps1 deleted file mode 100644 index e5939f959b65..000000000000 --- a/ExecSendPush/run.ps1 +++ /dev/null @@ -1,118 +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" - -$TenantFilter = $Request.Query.TenantFilter -$UserEmail = $Request.Query.UserEmail -$MFAAppID = '981f26a1-7f43-403b-a875-f8b09b8cd720' - -# Function to keep trying to get the access token while we wait for MS to actually set the temp password -function get-clientaccess { - param( - $uri, - $body, - $count = 1 - ) - try { - $ClientToken = Invoke-RestMethod -Method post -Uri $uri -Body $body -ea stop - } - catch { - if ($count -lt 20) { - - $count++ - Start-Sleep 1 - $ClientToken = get-clientaccess -uri $uri -body $body -count $count - } - else { - Throw "Could not get Client Token: $_" - } - } - return $ClientToken -} - - -# Get all service principals -$SPResult = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/servicePrincipals?`$top=999&`$select=id,appId" -tenantid $TenantFilter - -# Check if we have one for the MFA App -$SPID = ($SPResult | Where-Object { $_.appId -eq $MFAAppID }).id - -# Create a serivce principal if needed -if (!$SPID) { - - $SPBody = [pscustomobject]@{ - appId = $MFAAppID - } - $SPID = (New-GraphPostRequest -uri "https://graph.microsoft.com/v1.0/servicePrincipals" -tenantid $TenantFilter -type POST -body $SPBody -verbose).id -} - - -$PassReqBody = @{ - "passwordCredential" = @{ - "displayName" = "MFA Temporary Password" - "endDateTime" = $(((Get-Date).addminutes(5))) - "startDateTime" = $((Get-Date).addminutes(-5)) - } -} | ConvertTo-Json -Depth 5 - -$TempPass = (New-GraphPostRequest -uri "https://graph.microsoft.com/v1.0/servicePrincipals/$SPID/addPassword" -tenantid $TenantFilter -type POST -body $PassReqBody -verbose).secretText - -# Give it a chance to apply -#Start-Sleep 5 - -# Generate the XML for the push request -$XML = @" - -1.0 -$UserEmail -en-usOverrideVoiceOtpfalse69ff05bf-eb61-47f7-a70e-e7d77b6d47d0 -truetrueradiusUNKNOWN: -"@ - -# Request to get client token -$body = @{ - 'resource' = 'https://adnotifications.windowsazure.com/StrongAuthenticationService.svc/Connector' - 'client_id' = $MFAAppID - 'client_secret' = $TempPass - 'grant_type' = "client_credentials" - 'scope' = "openid" -} - -# Attempt to get a token using the temp password -$ClientUri = "https://login.microsoftonline.com/$TenantFilter/oauth2/token" -try { - $ClientToken = get-clientaccess -Uri $ClientUri -Body $body -} -catch { - $Body = "Failed to create temporary password" -} - -# If we got a token send a push -if ($ClientToken) { - - $ClientHeaders = @{ "Authorization" = "Bearer $($ClientToken.access_token)" } - - $obj = Invoke-RestMethod -Uri 'https://adnotifications.windowsazure.com/StrongAuthenticationService.svc/Connector//BeginTwoWayAuthentication' -Method POST -Headers $ClientHeaders -Body $XML -ContentType 'application/xml' - - if ($obj.BeginTwoWayAuthenticationResponse.result) { - $Body = "Received an MFA confirmation: $($obj.BeginTwoWayAuthenticationResponse.result.value | Out-String)" - } - if ($obj.BeginTwoWayAuthenticationResponse.AuthenticationResult -ne $true) { - $Body = "Authentication Failed! Does the user have Push/Phone call MFA configured? Errorcode: $($obj.BeginTwoWayAuthenticationResponse.result.value | Out-String)" - $colour = 'danger' - } - -} - -$Results = [pscustomobject]@{"Results" = $Body; colour = $colour } -Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Sent push request to $UserEmail - Result: $($obj.BeginTwoWayAuthenticationResponse.result.value | Out-String)" -Sev "Info" - -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Results - }) - diff --git a/ExecSetMailboxQuota/function.json b/ExecSetMailboxQuota/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecSetMailboxQuota/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/ExecSetMailboxQuota/run.ps1 b/ExecSetMailboxQuota/run.ps1 deleted file mode 100644 index 1d348cc5f9cd..000000000000 --- a/ExecSetMailboxQuota/run.ps1 +++ /dev/null @@ -1,43 +0,0 @@ -using namespace System.Net - -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) -try { - $APIName = $TriggerMetadata.FunctionName - 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 - $quota = $Request.body.input - $Results = try { - if ($Request.Body.ProhibitSendQuota) { - $quota = New-ExoRequest -tenantid $TenantFilter -cmdlet "Set-Mailbox" -cmdParams @{Identity = $Username; ProhibitSendQuota = $quota } - "Changed ProhibitSendQuota for $username - $($message)" - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Changed ProhibitSendQuota for $username - $($message)" -Sev "Info" -tenant $TenantFilter - } - if ($Request.Body.ProhibitSendReceiveQuota) { - $quota = New-ExoRequest -tenantid $TenantFilter -cmdlet "Set-Mailbox" -cmdParams @{Identity = $Username; ProhibitSendReceiveQuota = $quota } - "Changed ProhibitSendReceiveQuota for $username - $($message)" - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Changed ProhibitSendReceiveQuota for $username - $($message)" -Sev "Info" -tenant $TenantFilter - } - if ($Request.Body.IssueWarningQuota) { - $quota = New-ExoRequest -tenantid $TenantFilter -cmdlet "Set-Mailbox" -cmdParams @{Identity = $Username; IssueWarningQuota = $quota } - "Changed IssueWarningQuota for $username - $($message)" - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Changed IssueWarningQuota for $username - $($message)" -Sev "Info" -tenant $TenantFilter - } - } - catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Could not add OOO for $($username)" -Sev "Error" -tenant $TenantFilter - "Could not add out of office message for $($username). Error: $($_.Exception.Message)" - } - - $body = [pscustomobject]@{"Results" = @($results) } -} -catch { - $body = [pscustomobject]@{"Results" = @("Could not set Out of Office user: $($_.Exception.message)") } -} - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Body - }) diff --git a/ExecSetOoO/function.json b/ExecSetOoO/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecSetOoO/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/ExecSetOoO/run.ps1 b/ExecSetOoO/run.ps1 deleted file mode 100644 index bb34c7069454..000000000000 --- a/ExecSetOoO/run.ps1 +++ /dev/null @@ -1,43 +0,0 @@ -using namespace System.Net - -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) -try { - $APIName = $TriggerMetadata.FunctionName - 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 - if ($Request.body.input) { - $InternalMessage = $Request.body.input - $ExternalMessage = $Request.body.input - } - else { - $InternalMessage = $Request.body.InternalMessage - $ExternalMessage = $Request.body.ExternalMessage - } - $StartTime = $Request.body.StartTime - $EndTime = $Request.body.EndTime - - $Results = try { - if ($Request.Body.AutoReplyState -ne "Scheduled") { - Set-CIPPOutOfOffice -userid $Request.body.user -tenantFilter $TenantFilter -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' -InternalMessage $InternalMessage -ExternalMessage $ExternalMessage -State $Request.Body.AutoReplyState - } - else { - Set-CIPPOutOfOffice -userid $Request.body.user -tenantFilter $TenantFilter -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' -InternalMessage $InternalMessage -ExternalMessage $ExternalMessage -StartTime $StartTime -EndTime $EndTime -State $Request.Body.AutoReplyState - } - } - catch { - "Could not add out of office message for $($username). Error: $($_.Exception.Message)" - } - - $body = [pscustomobject]@{"Results" = @($results) } -} -catch { - $body = [pscustomobject]@{"Results" = @("Could not set Out of Office user: $($_.Exception.message)") } -} - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Body - }) diff --git a/ExecSetSecurityAlert/function.json b/ExecSetSecurityAlert/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecSetSecurityAlert/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/ExecSetSecurityAlert/run.ps1 b/ExecSetSecurityAlert/run.ps1 deleted file mode 100644 index 25d9ee4e7c66..000000000000 --- a/ExecSetSecurityAlert/run.ps1 +++ /dev/null @@ -1,29 +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" - -# Interact with query parameters or the body of the request. -$tenantfilter = $Request.Query.TenantFilter -$AlertFilter = $Request.Query.GUID -$Status = $Request.Query.Status -$AssignBody = '{"status":"' + $Status + '","vendorInformation":{"provider":"' + $Request.query.provider + '","vendor":"' + $Request.query.vendor + '"}}' -try { - $GraphRequest = New-Graphpostrequest -uri "https://graph.microsoft.com/beta/security/alerts/$AlertFilter" -type PATCH -tenantid $TenantFilter -body $Assignbody - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantfilter) -message "Set alert $AlertFilter to status $Status" -Sev "Info" - $body = [pscustomobject]@{"Results" = "Set status for alert to $Status" } - -} -catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantfilter) -message "Failed to update alert $($AlertFilter): $($_.Exception.Message)" -Sev "Error" - $body = [pscustomobject]@{"Results" = "Failed to change status: $($_.Exception.Message)" } -} - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $body - }) diff --git a/ExecSetSecurityIncident/function.json b/ExecSetSecurityIncident/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecSetSecurityIncident/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/ExecSetSecurityIncident/run.ps1 b/ExecSetSecurityIncident/run.ps1 deleted file mode 100644 index d12d10cc8df9..000000000000 --- a/ExecSetSecurityIncident/run.ps1 +++ /dev/null @@ -1,79 +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" - -$first='' -# Interact with query parameters or the body of the request. -$tenantfilter = $Request.Query.TenantFilter -$IncidentFilter = $Request.Query.GUID -$Status = $Request.Query.Status -$Assigned = $Request.Query.Assigned -$Classification = $Request.Query.Classification -$Determination = $Request.Query.Determination -$Redirected = $Request.Query.Redirected -as [int] -$BodyBuild -$AssignBody = '{' - -try { - # We won't update redirected incidents because the incident it is redirected to should instead be updated - if($Redirected -lt 1) - { - # Set received status - if($null -ne $Status) - { - $AssignBody += $first + '"status":"' + $Status + '"' - $BodyBuild += $first + "Set status for incident to " + $Status - $first = ', ' - } - - # Set received classification and determination - if($null -ne $Classification) - { - if($null -eq $Determination){ - # Maybe some poindexter tries to send a classification without a determination - throw - } - - $AssignBody += $first + '"classification":"' + $Classification + '", "determination":"' + $Determination + '"' - $BodyBuild += $first + "Set classification & determination for incident to " + $Classification + ' ' + $Determination - $first = ', ' - } - - # Set received asignee - if($null -ne $Assigned) - { - $AssignBody += $first + '"assignedTo":"' + $Assigned + '"' - if($null -eq $Status) - { - $BodyBuild += $first + "Set assigned for incident to " + $Assigned - } - $first = ', ' - } - - $AssignBody += '}' - - $ResponseBody = [pscustomobject]@{"Results" = $BodyBuild } - New-Graphpostrequest -uri "https://graph.microsoft.com/beta/security/incidents/$IncidentFilter" -type PATCH -tenantid $TenantFilter -body $Assignbody -asApp $true - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantfilter) -message "Update incident $IncidentFilter with values $Assignbody" -Sev "Info" - } - else { - $ResponseBody = [pscustomobject]@{"Results" = "Cannot update redirected incident" } - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantfilter) -message "Refuse to pdate incident $IncidentFilter with values $Assignbody because it is redirected to another incident" -Sev "Info" - } - - $body = $ResponseBody -} -catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantfilter) -message "Failed to update alert $($AlertFilter): $($_.Exception.Message)" -Sev "Error" - $body = [pscustomobject]@{"Results" = "Failed to update incident: $($_.Exception.Message)" } -} - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $body - }) diff --git a/ExecUniversalSearch/function.json b/ExecUniversalSearch/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ExecUniversalSearch/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/ExecUniversalSearch/run.ps1 b/ExecUniversalSearch/run.ps1 deleted file mode 100644 index 2d7801a7b630..000000000000 --- a/ExecUniversalSearch/run.ps1 +++ /dev/null @@ -1,30 +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." - -# Interact with query parameters or the body of the request. - -try { - $tenantfilter = Get-Tenants - $payload = '{ "returnsPartialResults":true, "displayName":"getUsers", "target": { "allTenants":true }, "operationDefinition": { "values":["@sys.normalize([ConsistencyLevel: eventual GET /v1.0/users?$top=5&$search=\"userPrincipalName:' + $request.query.name + '\" OR \"displayName:' + $request.query.name + '\"])"] }, "aggregationDefinition": { "values":["@sys.append([/result],50)"] } }' - $GraphRequest = (New-GraphPOSTRequest -noauthcheck $true -type "POST" -uri "https://graph.microsoft.com/beta/tenantRelationships/managedTenants/managedTenantOperations" -tenantid $env:TenantID -body $payload).result.Results | ConvertFrom-Json | Where-Object { $_.'_TenantId' -in $tenantfilter.customerId } - $StatusCode = [HttpStatusCode]::OK -} -catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $StatusCode = [HttpStatusCode]::Forbidden - $GraphRequest = "Could not connect to Azure Lighthouse API: $($ErrorMessage)" -} -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = @($GraphRequest) - }) diff --git a/ExecUserSettings/function.json b/ExecUserSettings/function.json deleted file mode 100644 index bf6c3ef0c49a..000000000000 --- a/ExecUserSettings/function.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "scriptFile": "../Modules/CippEntryPoints/CippEntryPoints.psm1", - "entryPoint": "Receive-CippHttpTrigger", - "bindings": [ - { - "authLevel": "anonymous", - "type": "httpTrigger", - "direction": "in", - "name": "Request", - "methods": ["get", "post"] - }, - { - "type": "http", - "direction": "out", - "name": "Response" - } - ] -} diff --git a/GetCippAlerts/function.json b/GetCippAlerts/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/GetCippAlerts/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/GetCippAlerts/run.ps1 b/GetCippAlerts/run.ps1 deleted file mode 100644 index 4bb100fcff4d..000000000000 --- a/GetCippAlerts/run.ps1 +++ /dev/null @@ -1,64 +0,0 @@ -using namespace System.Net - -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) - -$Alerts = [System.Collections.ArrayList]@() -$Table = Get-CippTable -tablename CippAlerts -$PartitionKey = Get-Date -UFormat '%Y%m%d' -$Filter = "PartitionKey eq '{0}'" -f $PartitionKey -$Rows = Get-CIPPAzDataTableEntity @Table -Filter $Filter | Sort-Object TableTimestamp -Descending | Select-Object -First 10 - - - -Set-Location (Get-Item $PSScriptRoot).Parent.FullName -$APIVersion = Get-Content "version_latest.txt" | Out-String -$CIPPVersion = $request.query.localversion - -$RemoteAPIVersion = Invoke-RestMethod -Uri "https://raw.githubusercontent.com/KelvinTegelaar/CIPP-API/master/version_latest.txt" -$RemoteCIPPVersion = Invoke-RestMethod -Uri "https://raw.githubusercontent.com/KelvinTegelaar/CIPP/master/public/version_latest.txt" - -$version = [PSCustomObject]@{ - LocalCIPPVersion = $CIPPVersion - RemoteCIPPVersion = $RemoteCIPPVersion - LocalCIPPAPIVersion = $APIVersion - RemoteCIPPAPIVersion = $RemoteAPIVersion - OutOfDateCIPP = ([version]$RemoteCIPPVersion -gt [version]$CIPPVersion) - OutOfDateCIPPAPI = ([version]$RemoteAPIVersion -gt [version]$APIVersion) -} -if ($version.outOfDateCIPP) { - $Alerts.add(@{Alert = 'Your CIPP Frontend is out of date. Please update to the latest version. Find more on the following '; link = "https://docs.cipp.app/setup/installation/updating"; type = "warning" }) - Write-LogMessage -message "Your CIPP Frontend is out of date. Please update to the latest version" -API 'Updates' -tenant "All Tenants" -sev Alert - -} -if ($version.outOfDateCIPPAPI) { - $Alerts.add(@{Alert = 'Your CIPP API is out of date. Please update to the latest version. Find more on the following'; link = "https://docs.cipp.app/setup/installation/updating"; type = "warning" }) - Write-LogMessage -message "Your CIPP API is out of date. Please update to the latest version" -API 'Updates' -tenant "All Tenants" -sev Alert -} - - -if ($env:ApplicationID -eq 'LongApplicationID' -or $null -eq $ENV:ApplicationID) { $Alerts.add(@{Alert = 'You have not yet setup your SAM Setup. Please go to the SAM Wizard in settings to finish setup'; link = "/cipp/setup"; type = "warning" }) } -if ($env:FUNCTIONS_EXTENSION_VERSION -ne '~4') { - $Alerts.add(@{Alert = 'Your Function App is running on a Runtime version lower than 4. This impacts performance. Go to Settings -> Backend -> Function App Configuration -> Function Runtime Settings and set this to 4 for maximum performance'; link = "/cipp/setup"; type = "warning" }) -} -if ($psversiontable.psversion.toString() -lt 7.2) { $Alerts.add(@{Alert = 'Your Function App is running on Powershell 7. This impacts performance. Go to Settings -> Backend -> Function App Configuration -> General Settings and set PowerShell Core Version to 7.2 for maximum performance'; link = "/cipp/setup"; type = "danger" }) } -if ($env:WEBSITE_RUN_FROM_PACKAGE -ne '1') { - $Alerts.add( - @{Alert = 'Your Function App is running in write mode. This will cause performance issues and increase cost. Please check this '; - link = "https://docs.cipp.app/setup/installation/runfrompackage"; - type = "warning" - }) -} -if ($Rows) { $Rows | ForEach-Object { $alerts.add($_) } } -$Alerts = @($Alerts) -$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. - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Alerts - }) diff --git a/GetDashboard/function.json b/GetDashboard/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/GetDashboard/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/GetDashboard/run.ps1 b/GetDashboard/run.ps1 deleted file mode 100644 index 8c9bafcebc28..000000000000 --- a/GetDashboard/run.ps1 +++ /dev/null @@ -1,247 +0,0 @@ -using namespace System.Net - -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) -Function Test-CronRange { - <# - .EXAMPLE - # * always passes - Test-CronRange -Range '*' -InputValue 10 -Verbose - # a min-max range - Test-CronRange -Range '1-15' -InputValue 10 -Verbose - # stepped value - Test-CronRange -Range '*/15' -InputValue 30 -verbose - # A specific value list - Test-CronRange -Range '2,5,8,9' -InputValue 10 -verbose - Test-CronRange -Range '*/4' -InputValue 60 -verbose - #> - [cmdletbinding()] - param( - [ValidatePattern('^[\d-*/,]*$')] - [string]$range - , - [int]$inputvalue - ) - Write-Verbose "Testing $range" - If ($range -eq '*') { - Return $true - } - If ($range -match '^\d+$') { - Write-Verbose 'Specific Value(int)' - Return ($inputvalue -eq [int]$range) - } - If ($range -match '[\d]+-[\d]+([/][\d])*') { - Write-Verbose 'min-max range' - [int]$min, [int]$max = $range -split '-' - Return ($inputvalue -ge $min -and $inputvalue -le $max) - } - If ($range -match ('([*]+|[\d]+-[\d]+)[/][\d]+')) { - Write-Verbose 'Step Value' - $list, $step = $range -split '/' - Write-Verbose "Using Step of $step" - $IsInStep = ( ($inputvalue / $step).GetType().Name -eq 'Int32' ) - Return ( $IsInStep ) - } - If ($range -match '(\d+)(,\s*\d+)*') { - Write-Verbose 'value list' - $list = @() - $list = $range -split ',' - Return ( $list -contains $InputValue ) - } - Write-Error "Could not process Range format: $Range" -} -Function ConvertFrom-DateTable { - Param ( - $DateTable - ) - $datestring = '{0}-{1:00}-{2:00} {3:00}:{4:00}' -f $DateTable.year, $DateTable.month, $DateTable.day, $DateTable.hour, $DateTable.Minute - $date = [datetime]::ParseExact($datestring, 'yyyy-MM-dd HH:mm', $null) - return $date -} -Function Invoke-CronIncrement { - param( - [psobject] - $DateTable - , - [ValidateSet('Minute', 'Hour', 'Day', 'Month')] - [string] - $Increment - ) - $date = ConvertFrom-DateTable -DateTable $DateTable - $date = switch ($Increment) { - 'Minute' { $date.AddMinutes(1) } - 'Hour' { $date.AddHours(1) } - 'Day' { $date.AddDays(1) } - 'Month' { $date.AddMonths(1) } - } - $output = [ordered]@{ - Minute = $date.Minute - Hour = $date.hour - Day = $date.day - Weekday = $date.DayOfWeek.value__ - Month = $date.month - Year = $date.year - } - Return $output -} -Function Get-CronNextExecutionTime { - <# - .SYNOPSIS - Currently only support * or digits - todo: add support for ',' '-' '/' ',' - .EXAMPLE - Get-CronNextExecutionTime -Expression '* * * * *' - Get-CronNextExecutionTime -Expression '5 * * * *' - Get-CronNextExecutionTime -Expression '* 13-21 * * *' - Get-CronNextExecutionTime -Expression '0 0 2 * *' - Get-CronNextExecutionTime -Expression '15 14 * 1-3 *' - Get-CronNextExecutionTime -Expression '15 14 * * 4' - Get-CronNextExecutionTime -Expression '15 14 * 2 *' - Get-CronNextExecutionTime -Expression '15 14-20 * * *' - Get-CronNextExecutionTime -Expression '15 14 * * 1' - #> - [cmdletbinding()] - param( - [string] - $Expression = '* * * * *' - , - $InputDate - ) - # Split Expression in variables and set to INT if possible - $cronMinute, $cronHour, $cronDay, $cronMonth, $cronWeekday = $Expression -Split ' ' - Get-Variable -Scope local | Where-Object { $_.name -like 'cron*' } | ForEach-Object { - If ($_.Value -ne '*') { - Try { - [int]$newValue = $_.Value - Set-Variable -Name $_.Name -Value $newValue -ErrorAction Ignore - } - Catch {} - } - } - # Get the next default Time (= next minute) - $nextdate = If ($InputDate) { $InputDate } Else { Get-Date } - $nextdate = $nextdate.addMinutes(1) - $next = [ordered]@{ - Minute = $nextdate.Minute - Hour = $nextdate.hour - Day = $nextdate.day - Weekday = $nextdate.DayOfWeek.value__ - Month = $nextdate.month - Year = $nextdate.year - } - # Increase Minutes until it is in the range. - # If Minutes passes the 60 mark, the hour is incremented - $done = $false - Do { - If ((Test-CronRange -InputValue $next.Minute -range $cronMinute) -eq $False) { - Do { - $next = Invoke-CronIncrement -DateTable $Next -Increment Minute - } While ( (Test-CronRange -InputValue $next.Minute -range $cronMinute) -eq $False ) - continue - } - # Check if the next Hour is in the desired range - # Add a Day because the desired Hour has already passed - If ((Test-CronRange -InputValue $next.Hour -range $cronHour) -eq $False) { - Do { - $next = Invoke-CronIncrement -DateTable $Next -Increment Hour - $next.Minute = 0 - } While ((Test-CronRange -InputValue $next.Hour -range $cronHour) -eq $False) - continue - } - # Increase Days until it is in the range. - # If Days passes the 30/31 mark, the Month is incremented - If ((Test-CronRange -InputValue $next.day -range $cronday) -eq $False) { - Do { - $next = Invoke-CronIncrement -DateTable $Next -Increment Day - $next.Hour = 0 - $next.Minute = 0 - } While ((Test-CronRange -InputValue $next.day -range $cronday) -eq $False) - continue - } - # Increase Months until it is in the range. - # If Months passes the 12 mark, the Year is incremented - If ((Test-CronRange -InputValue $next.Month -range $cronMonth) -eq $False) { - Do { - $next = Invoke-CronIncrement -DateTable $Next -Increment Month - $next.Hour = 0 - $next.Minute = 0 - } While ((Test-CronRange -InputValue $next.Month -range $cronMonth) -eq $False) - continue - } - If ((Test-CronRange -InputValue $Next.WeekDay -Range $cronWeekday) -eq $false) { - Do { - $next = Invoke-CronIncrement -DateTable $Next -Increment Day - $next.Hour = 0 - $next.Minute = 0 - } While ( (Test-CronRange -InputValue $Next.WeekDay -Range $cronWeekday) -eq $false ) - continue - } - $done = $true - } While ($done -eq $false) - $date = ConvertFrom-DateTable -DateTable $next - If (!$date) { Throw 'Could not create date' } - - # Add Days until weekday matches - - Return $Date -} - -$Table = Get-CippTable -tablename CippLogs -$PartitionKey = Get-Date -UFormat '%Y%m%d' -$Filter = "PartitionKey eq '{0}'" -f $PartitionKey -$Rows = Get-CIPPAzDataTableEntity @Table -Filter $Filter | Sort-Object TableTimestamp -Descending | Select-Object -First 10 - -$Standards = Get-CippTable -tablename standards -$QueuedStandards = (Get-CIPPAzDataTableEntity @Standards -Property RowKey | Measure-Object).Count - -$Apps = Get-CippTable -tablename apps -$QueuedApps = (Get-CIPPAzDataTableEntity @Apps -Property RowKey | Measure-Object).Count - -$SlimRows = New-Object System.Collections.ArrayList -foreach ($Row in $Rows) { - $SlimRows.Add(@{ - Tenant = $Row.Tenant - Message = $Row.Message - }) -} -$Alerts = [System.Collections.ArrayList]@() -if ($env:ApplicationID -eq 'LongApplicationID' -or $null -eq $ENV:ApplicationID) { $Alerts.add('You have not yet setup your SAM Setup. Please go to the SAM Wizard in settings to finish setup') } -if ($env:FUNCTIONS_EXTENSION_VERSION -ne '~4') { $Alerts.add('Your Function App is running on a Runtime version lower than 4. This impacts performance. Go to Settings -> Backend -> Function App Configuration -> Function Runtime Settings and set this to 4 for maximum performance') } -if ($psversiontable.psversion.toString() -lt 7.2) { $Alerts.add('Your Function App is running on Powershell 7. This impacts performance. Go to Settings -> Backend -> Function App Configuration -> General Settings and set PowerShell Core Version to 7.2 for maximum performance') } -if ($env:WEBSITE_RUN_FROM_PACKAGE -ne '1') { $Alerts.add('Your Function App is running in write mode. Please check the release notes to enable Run from Package mode. (https://github.com/KelvinTegelaar/CIPP/releases/tag/v2.1.11.0)') } -try { - $TenantCount = (Get-Tenants -IncludeErrors | Measure-Object).Count - $TenantErrorCount = $TenantCount - (Get-Tenants | Measure-Object).Count -} -catch { - $TenantCount = 0 - $TenantErrorCount = 0 -} -$APIName = $TriggerMetadata.FunctionName -Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - -if (!$env:WEBSITE_NAME) { - #Running locally, no alerts. :) - $Alerts = $null -} -else { - $Alerts = @($Alerts) -} -$dash = [PSCustomObject]@{ - NextStandardsRun = (Get-CronNextExecutionTime -Expression '0 */3 * * *').tostring('s') - NextBPARun = (Get-CronNextExecutionTime -Expression '0 3 * * *').tostring('s') - queuedApps = [int64]$QueuedApps - queuedStandards = [int64]$QueuedStandards - tenantCount = [int64]$TenantCount - tenantErrorCount = [int64]$TenantErrorCount - RefreshTokenDate = (Get-CronNextExecutionTime -Expression '0 0 * * 0').AddDays('-7').tostring('s') -split 'T' | Select-Object -First 1 - LastLog = @($SlimRows) - Alerts = $Alerts -} -# Write to the Azure Functions log stream. - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $dash - }) diff --git a/GetVersion/function.json b/GetVersion/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/GetVersion/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/GetVersion/run.ps1 b/GetVersion/run.ps1 deleted file mode 100644 index d0e092e20571..000000000000 --- a/GetVersion/run.ps1 +++ /dev/null @@ -1,29 +0,0 @@ -using namespace System.Net - -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) -Set-Location (Get-Item $PSScriptRoot).Parent.FullName -$APIName = $TriggerMetadata.FunctionName -Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Accessed this API" -Sev "Debug" - -$APIVersion = Get-Content "version_latest.txt" | Out-String -$CIPPVersion = $request.query.localversion - -$RemoteAPIVersion = Invoke-RestMethod -Uri "https://raw.githubusercontent.com/KelvinTegelaar/CIPP-API/master/version_latest.txt" -$RemoteCIPPVersion = Invoke-RestMethod -Uri "https://raw.githubusercontent.com/KelvinTegelaar/CIPP/master/public/version_latest.txt" - -$version = [PSCustomObject]@{ - LocalCIPPVersion = $CIPPVersion - RemoteCIPPVersion = $RemoteCIPPVersion - LocalCIPPAPIVersion = $APIVersion - RemoteCIPPAPIVersion = $RemoteAPIVersion - OutOfDateCIPP = ([version]$RemoteCIPPVersion -gt [version]$CIPPVersion) - OutOfDateCIPPAPI = ([version]$RemoteAPIVersion -gt [version]$APIVersion) -} -# Write to the Azure Functions log stream. - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Version - }) \ No newline at end of file diff --git a/GraphHelper.psm1 b/GraphHelper.psm1 deleted file mode 100644 index 7ce9c97e513c..000000000000 --- a/GraphHelper.psm1 +++ /dev/null @@ -1,833 +0,0 @@ -function Get-CIPPTable { - [CmdletBinding()] - param ( - $tablename = 'CippLogs' - ) - $Context = New-AzDataTableContext -ConnectionString $env:AzureWebJobsStorage -TableName $tablename - New-AzDataTable -Context $Context | Out-Null - - @{ - Context = $Context - } -} -function Get-NormalizedError { - [CmdletBinding()] - param ( - [string]$message - ) - switch -Wildcard ($message) { - 'Request not applicable to target tenant.' { 'Required license not available for this tenant' } - "Neither tenant is B2C or tenant doesn't have premium license" { 'This feature requires a P1 license or higher' } - 'Response status code does not indicate success: 400 (Bad Request).' { 'Error 400 occured. There is an issue with the token configuration for this tenant. Please perform an access check' } - '*Microsoft.Skype.Sync.Pstn.Tnm.Common.Http.HttpResponseException*' { 'Could not connect to Teams Admin center - Tenant might be missing a Teams license' } - '*Provide valid credential.*' { 'Error 400: There is an issue with your Exchange Token configuration. Please perform an access check for this tenant' } - '*This indicate that a subscription within the tenant has lapsed*' { 'There is no exchange subscription available, or it has lapsed. Check licensing information.' } - '*User was not found.*' { 'The relationship between this tenant and the partner has been dissolved from the tenant side.' } - '*The user or administrator has not consented to use the application*' { 'CIPP cannot access this tenant. Perform a CPV Refresh and Access Check via the settings menu' } - '*AADSTS50020*' { 'AADSTS50020: The user you have used for your Secure Application Model is a guest in this tenant, or your are using GDAP and have not added the user to the correct group. Please delete the guest user to gain access to this tenant' } - '*AADSTS50177' { 'AADSTS50177: The user you have used for your Secure Application Model is a guest in this tenant, or your are using GDAP and have not added the user to the correct group. Please delete the guest user to gain access to this tenant' } - '*invalid or malformed*' { 'The request is malformed. Have you finished the SAM Setup?' } - '*Windows Store repository apps feature is not supported for this tenant*' { 'This tenant does not have WinGet support available' } - '*AADSTS650051*' { 'The application does not exist yet. Try again in 30 seconds.' } - '*AppLifecycle_2210*' { 'Failed to call Intune APIs: Does the tenant have a license available?' } - '*One or more added object references already exist for the following modified properties:*' { 'This user is already a member of this group.' } - '*Microsoft.Exchange.Management.Tasks.MemberAlreadyExistsException*' { 'This user is already a member of this group.' } - '*The property value exceeds the maximum allowed size (64KB)*' { 'One of the values exceeds the maximum allowed size (64KB).' } - Default { $message } - - } -} - -function Get-GraphToken($tenantid, $scope, $AsApp, $AppID, $refreshToken, $ReturnRefresh, $SkipCache) { - if (!$scope) { $scope = 'https://graph.microsoft.com/.default' } - if (!$env:SetFromProfile) { $CIPPAuth = Get-CIPPAuthentication; Write-Host 'Could not get Refreshtoken from environment variable. Reloading token.' } - $AuthBody = @{ - client_id = $env:ApplicationID - client_secret = $env:ApplicationSecret - scope = $Scope - refresh_token = $env:RefreshToken - grant_type = 'refresh_token' - } - if ($asApp -eq $true) { - $AuthBody = @{ - client_id = $env:ApplicationID - client_secret = $env:ApplicationSecret - scope = $Scope - grant_type = 'client_credentials' - } - } - - if ($null -ne $AppID -and $null -ne $refreshToken) { - $AuthBody = @{ - client_id = $appid - refresh_token = $RefreshToken - scope = $Scope - grant_type = 'refresh_token' - } - } - - if (!$tenantid) { $tenantid = $env:TenantID } - - $TokenKey = '{0}-{1}-{2}' -f $tenantid, $scope, $asApp - - try { - if ($script:AccessTokens.$TokenKey -and [int](Get-Date -UFormat %s -Millisecond 0) -lt $script:AccessTokens.$TokenKey.expires_on -and $SkipCache -ne $true) { - Write-Host 'Graph: cached token' - $AccessToken = $script:AccessTokens.$TokenKey - } - else { - Write-Host 'Graph: new token' - $AccessToken = (Invoke-RestMethod -Method post -Uri "https://login.microsoftonline.com/$($tenantid)/oauth2/v2.0/token" -Body $Authbody -ErrorAction Stop) - $ExpiresOn = [int](Get-Date -UFormat %s -Millisecond 0) + $AccessToken.expires_in - Add-Member -InputObject $AccessToken -NotePropertyName 'expires_on' -NotePropertyValue $ExpiresOn - if (!$script:AccessTokens) { $script:AccessTokens = [HashTable]::Synchronized(@{}) } - $script:AccessTokens.$TokenKey = $AccessToken - } - - if ($ReturnRefresh) { $header = $AccessToken } else { $header = @{ Authorization = "Bearer $($AccessToken.access_token)" } } - return $header - #Write-Host $header['Authorization'] - } - catch { - # Track consecutive Graph API failures - $TenantsTable = Get-CippTable -tablename Tenants - $Filter = "PartitionKey eq 'Tenants' and (defaultDomainName eq '{0}' or customerId eq '{0}')" -f $tenantid - $Tenant = Get-CIPPAzDataTableEntity @TenantsTable -Filter $Filter - if (!$Tenant.RowKey) { - $donotset = $true - $Tenant = [pscustomobject]@{ - GraphErrorCount = $null - LastGraphTokenError = $null - LastGraphError = $null - PartitionKey = 'TenantFailed' - RowKey = 'Failed' - } - } - $Tenant.LastGraphError = if ( $_.ErrorDetails.Message) { - $msg = $_.ErrorDetails.Message | ConvertFrom-Json - "$($msg.error):$($msg.error_description)" - } - else { - $_.Exception.message - } - $Tenant.GraphErrorCount++ - - if (!$donotset) { Update-AzDataTableEntity @TenantsTable -Entity $Tenant } - throw "Could not get token: $($Tenant.LastGraphError)" - } -} - -function Write-LogMessage ($message, $tenant = 'None', $API = 'None', $tenantId = $null, $user, $sev) { - try { - $username = ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($user)) | ConvertFrom-Json).userDetails - } - catch { - $username = $user - } - - $Table = Get-CIPPTable -tablename CippLogs - - if (!$tenant) { $tenant = 'None' } - if (!$username) { $username = 'CIPP' } - if ($sev -eq 'Debug' -and $env:DebugMode -ne 'true') { - Write-Information 'Not writing to log file - Debug mode is not enabled.' - return - } - $PartitionKey = (Get-Date -UFormat '%Y%m%d').ToString() - $TableRow = @{ - 'Tenant' = [string]$tenant - 'API' = [string]$API - 'Message' = [string]$message - 'Username' = [string]$username - 'Severity' = [string]$sev - 'SentAsAlert' = $false - 'PartitionKey' = $PartitionKey - 'RowKey' = ([guid]::NewGuid()).ToString() - } - - - if ($tenantId) { - $TableRow.Add('TenantID', [string]$tenantId) - } - - $Table.Entity = $TableRow - Add-CIPPAzDataTableEntity @Table | Out-Null -} - -function New-GraphGetRequest { - Param( - $uri, - $tenantid, - $scope, - $AsApp, - $noPagination, - $NoAuthCheck, - $skipTokenCache, - [switch]$ComplexFilter, - [switch]$CountOnly - ) - - if ($NoAuthCheck -or (Get-AuthorisedRequest -Uri $uri -TenantID $tenantid)) { - if ($scope -eq 'ExchangeOnline') { - $AccessToken = Get-ClassicAPIToken -resource 'https://outlook.office365.com' -Tenantid $tenantid - $headers = @{ Authorization = "Bearer $($AccessToken.access_token)" } - } - else { - $headers = Get-GraphToken -tenantid $tenantid -scope $scope -AsApp $asapp -SkipCache $skipTokenCache - } - - if ($ComplexFilter) { - $headers['ConsistencyLevel'] = 'eventual' - } - $nextURL = $uri - - # Track consecutive Graph API failures - $TenantsTable = Get-CippTable -tablename Tenants - $Filter = "PartitionKey eq 'Tenants' and (defaultDomainName eq '{0}' or customerId eq '{0}')" -f $tenantid - $Tenant = Get-CIPPAzDataTableEntity @TenantsTable -Filter $Filter - if (!$Tenant) { - $Tenant = @{ - GraphErrorCount = 0 - LastGraphError = $null - PartitionKey = 'TenantFailed' - RowKey = 'Failed' - } - } - - $ReturnedData = do { - try { - $Data = (Invoke-RestMethod -Uri $nextURL -Method GET -Headers $headers -ContentType 'application/json; charset=utf-8') - if ($CountOnly) { - $Data.'@odata.count' - $nextURL = $null - } - else { - if ($data.value) { $data.value } else { ($Data) } - if ($noPagination) { $nextURL = $null } else { $nextURL = $data.'@odata.nextLink' } - } - } - catch { - $Message = ($_.ErrorDetails.Message | ConvertFrom-Json -ErrorAction SilentlyContinue).error.message - if ($Message -eq $null) { $Message = $($_.Exception.Message) } - if ($Message -ne 'Request not applicable to target tenant.' -and $Tenant) { - $Tenant.LastGraphError = $Message - $Tenant.GraphErrorCount++ - Update-AzDataTableEntity @TenantsTable -Entity $Tenant - } - throw $Message - } - } until ($null -eq $NextURL) - $Tenant.LastGraphError = '' - Update-AzDataTableEntity @TenantsTable -Entity $Tenant - return $ReturnedData - } - else { - Write-Error 'Not allowed. You cannot manage your own tenant or tenants not under your scope' - } -} - -function New-GraphPOSTRequest ($uri, $tenantid, $body, $type, $scope, $AsApp, $NoAuthCheck, $skipTokenCache, $AddedHeaders) { - if ($NoAuthCheck -or (Get-AuthorisedRequest -Uri $uri -TenantID $tenantid)) { - $headers = Get-GraphToken -tenantid $tenantid -scope $scope -AsApp $asapp -SkipCache $skipTokenCache - if ($AddedHeaders) { - foreach ($header in $AddedHeaders.getenumerator()) { - $headers.Add($header.Key, $header.Value) - } - } - Write-Verbose "Using $($uri) as url" - if (!$type) { - $type = 'POST' - } - - try { - $ReturnedData = (Invoke-RestMethod -Uri $($uri) -Method $TYPE -Body $body -Headers $headers -ContentType 'application/json; charset=utf-8') - } - catch { - $ErrorMess = $($_.Exception.Message) - $Message = ($_.ErrorDetails.Message | ConvertFrom-Json -ErrorAction SilentlyContinue).error.message - if (!$Message) { $Message = $ErrorMess } - throw $Message - } - return $ReturnedData - } - else { - Write-Error 'Not allowed. You cannot manage your own tenant or tenants not under your scope' - } -} - -function convert-skuname($skuname, $skuID) { - Set-Location (Get-Item $PSScriptRoot).FullName - $ConvertTable = Import-Csv Conversiontable.csv - if ($skuname) { $ReturnedName = ($ConvertTable | Where-Object { $_.String_Id -eq $skuname } | Select-Object -Last 1).'Product_Display_Name' } - if ($skuID) { $ReturnedName = ($ConvertTable | Where-Object { $_.guid -eq $skuid } | Select-Object -Last 1).'Product_Display_Name' } - if ($ReturnedName) { return $ReturnedName } else { return $skuname, $skuID } -} - -function Get-ClassicAPIToken($tenantID, $Resource) { - $TokenKey = '{0}-{1}' -f $TenantID, $Resource - if ($script:classictoken.$TokenKey -and [int](Get-Date -UFormat %s -Millisecond 0) -lt $script:classictoken.$TokenKey.expires_on) { - Write-Host 'Classic: cached token' - return $script:classictoken.$TokenKey - } - else { - Write-Host 'Using classic' - $uri = "https://login.microsoftonline.com/$($TenantID)/oauth2/token" - $Body = @{ - client_id = $env:ApplicationID - client_secret = $env:ApplicationSecret - resource = $Resource - refresh_token = $env:RefreshToken - grant_type = 'refresh_token' - } - try { - if (!$script:classictoken) { $script:classictoken = [HashTable]::Synchronized(@{}) } - $script:classictoken.$TokenKey = Invoke-RestMethod $uri -Body $body -ContentType 'application/x-www-form-urlencoded' -ErrorAction SilentlyContinue -Method post - return $script:classictoken.$TokenKey - } - catch { - # Track consecutive Graph API failures - $TenantsTable = Get-CippTable -tablename Tenants - $Filter = "PartitionKey eq 'Tenants' and (defaultDomainName eq '{0}' or customerId eq '{0}')" -f $tenantid - $Tenant = Get-CIPPAzDataTableEntity @TenantsTable -Filter $Filter - if (!$Tenant) { - $Tenant = @{ - GraphErrorCount = $null - LastGraphTokenError = $null - LastGraphError = $null - PartitionKey = 'TenantFailed' - RowKey = 'Failed' - } - } - $Tenant.LastGraphError = $_.Exception.Message - $Tenant.GraphErrorCount++ - - Update-AzDataTableEntity @TenantsTable -Entity $Tenant - Throw "Failed to obtain Classic API Token for $TenantID - $_" - } - } -} - -function New-TeamsAPIGetRequest($Uri, $tenantID, $Method = 'GET', $Resource = '48ac35b8-9aa8-4d74-927d-1f4a14a0b239', $ContentType = 'application/json') { - - if ((Get-AuthorisedRequest -Uri $uri -TenantID $tenantid)) { - $token = Get-ClassicAPIToken -Tenant $tenantid -Resource $Resource - - $NextURL = $Uri - $ReturnedData = do { - try { - $Data = Invoke-RestMethod -ContentType "$ContentType;charset=UTF-8" -Uri $NextURL -Method $Method -Headers @{ - Authorization = "Bearer $($token.access_token)"; - 'x-ms-client-request-id' = [guid]::NewGuid().ToString(); - 'x-ms-client-session-id' = [guid]::NewGuid().ToString() - 'x-ms-correlation-id' = [guid]::NewGuid() - 'X-Requested-With' = 'XMLHttpRequest' - 'x-ms-tnm-applicationid' = '045268c0-445e-4ac1-9157-d58f67b167d9' - - } - $Data - if ($noPagination) { $nextURL = $null } else { $nextURL = $data.NextLink } - } - catch { - throw "Failed to make Teams API Get Request $_" - } - } until ($null -eq $NextURL) - return $ReturnedData - } - else { - Write-Error 'Not allowed. You cannot manage your own tenant or tenants not under your scope' - } -} - -function New-ClassicAPIGetRequest($TenantID, $Uri, $Method = 'GET', $Resource = 'https://admin.microsoft.com', $ContentType = 'application/json') { - - if ((Get-AuthorisedRequest -Uri $uri -TenantID $tenantid)) { - $token = Get-ClassicAPIToken -Tenant $tenantID -Resource $Resource - - $NextURL = $Uri - $ReturnedData = do { - try { - $Data = Invoke-RestMethod -ContentType "$ContentType;charset=UTF-8" -Uri $NextURL -Method $Method -Headers @{ - Authorization = "Bearer $($token.access_token)"; - 'x-ms-client-request-id' = [guid]::NewGuid().ToString(); - 'x-ms-client-session-id' = [guid]::NewGuid().ToString() - 'x-ms-correlation-id' = [guid]::NewGuid() - 'X-Requested-With' = 'XMLHttpRequest' - } - $Data - if ($noPagination) { $nextURL = $null } else { $nextURL = $data.NextLink } - } - catch { - throw "Failed to make Classic Get Request $_" - } - } until ($null -eq $NextURL) - return $ReturnedData - } - else { - Write-Error 'Not allowed. You cannot manage your own tenant or tenants not under your scope' - } -} - -function New-ClassicAPIPostRequest($TenantID, $Uri, $Method = 'POST', $Resource = 'https://admin.microsoft.com', $Body) { - - if ((Get-AuthorisedRequest -Uri $uri -TenantID $tenantid)) { - $token = Get-ClassicAPIToken -Tenant $tenantID -Resource $Resource - try { - $ReturnedData = Invoke-RestMethod -ContentType 'application/json;charset=UTF-8' -Uri $Uri -Method $Method -Body $Body -Headers @{ - Authorization = "Bearer $($token.access_token)"; - 'x-ms-client-request-id' = [guid]::NewGuid().ToString(); - 'x-ms-client-session-id' = [guid]::NewGuid().ToString() - 'x-ms-correlation-id' = [guid]::NewGuid() - 'X-Requested-With' = 'XMLHttpRequest' - 'X-RequestForceAuthentication' = $true - - } - - } - catch { - throw "Failed to make Classic Get Request $_" - } - return $ReturnedData - } - else { - Write-Error 'Not allowed. You cannot manage your own tenant or tenants not under your scope' - } -} - -function Get-AuthorisedRequest { - [CmdletBinding()] - Param( - [string]$TenantID, - [string]$Uri - ) - if (!$TenantID) { - $TenantID = $env:TenantId - } - if ($Uri -like 'https://graph.microsoft.com/beta/contracts*' -or $Uri -like '*/customers/*' -or $Uri -eq 'https://graph.microsoft.com/v1.0/me/sendMail' -or $Uri -like '*/tenantRelationships/*') { - return $true - } - $Tenants = Get-Tenants -IncludeErrors - $SkipList = Get-Tenants -SkipList - if (($env:PartnerTenantAvailable -eq $true -and $SkipList.customerId -notcontains $TenantID -and $SkipList.defaultDomainName -notcontains $TenantID) -or (($Tenants.customerId -contains $TenantID -or $Tenants.defaultDomainName -contains $TenantID) -and $TenantID -ne $env:TenantId)) { - return $true - } - else { - return $false - } -} - - -function Get-Tenants { - param ( - [Parameter( ParameterSetName = 'Skip', Mandatory = $True )] - [switch]$SkipList, - [Parameter( ParameterSetName = 'Standard')] - [switch]$IncludeAll, - [switch]$IncludeErrors - ) - - $TenantsTable = Get-CippTable -tablename 'Tenants' - $ExcludedFilter = "PartitionKey eq 'Tenants' and Excluded eq true" - - $SkipListCache = Get-CIPPAzDataTableEntity @TenantsTable -Filter $ExcludedFilter - if ($SkipList) { - return $SkipListCache - } - - if ($IncludeAll.IsPresent) { - $Filter = "PartitionKey eq 'Tenants'" - } - elseif ($IncludeErrors.IsPresent) { - $Filter = "PartitionKey eq 'Tenants' and Excluded eq false" - } - else { - $Filter = "PartitionKey eq 'Tenants' and Excluded eq false and GraphErrorCount lt 50" - } - $IncludedTenantsCache = Get-CIPPAzDataTableEntity @TenantsTable -Filter $Filter - - if (($IncludedTenantsCache | Measure-Object).Count -gt 0) { - try { - $LastRefresh = ($IncludedTenantsCache | Where-Object { $_.customerId } | Sort-Object LastRefresh -Descending | Select-Object -First 1).LastRefresh | Get-Date -ErrorAction Stop - } - catch { $LastRefresh = $false } - } - else { - $LastRefresh = $false - } - if (!$LastRefresh -or $LastRefresh -lt (Get-Date).Addhours(-24).ToUniversalTime()) { - try { - Write-Host "Renewing. Cache not hit. $LastRefresh" - $TenantList = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/tenantRelationships/managedTenants/tenants?`$top=999" -tenantid $env:TenantID ) | Select-Object id, @{l = 'customerId'; e = { $_.tenantId } }, @{l = 'DefaultdomainName'; e = { [string]($_.contract.defaultDomainName) } } , @{l = 'MigratedToNewTenantAPI'; e = { $true } }, DisplayName, domains, @{n = 'delegatedPrivilegeStatus'; exp = { $_.tenantStatusInformation.delegatedPrivilegeStatus } } | Where-Object { $_.defaultDomainName -NotIn $SkipListCache.defaultDomainName -and $_.defaultDomainName -ne $null } - - } - catch { - Write-Host "Get-Tenants - Lighthouse Error, using contract/delegatedAdminRelationship calls. Error: $($_.Exception.Message)" - [System.Collections.Generic.List[PSCustomObject]]$BulkRequests = @( - @{ - id = 'Contracts' - method = 'GET' - url = "/contracts?`$top=999" - }, - @{ - id = 'GDAPRelationships' - method = 'GET' - url = '/tenantRelationships/delegatedAdminRelationships' - } - ) - - $BulkResults = New-GraphBulkRequest -Requests $BulkRequests -tenantid $TenantFilter -NoAuthCheck:$true - $Contracts = Get-GraphBulkResultByID -Results $BulkResults -ID 'Contracts' -Value - $GDAPRelationships = Get-GraphBulkResultByID -Results $BulkResults -ID 'GDAPRelationships' -Value - - $ContractList = $Contracts | Select-Object id, customerId, DefaultdomainName, DisplayName, domains, @{l = 'MigratedToNewTenantAPI'; e = { $true } }, @{ n = 'delegatedPrivilegeStatus'; exp = { $CustomerId = $_.customerId; if (($GDAPRelationships | Where-Object { $_.customer.tenantId -EQ $CustomerId -and $_.status -EQ 'active' } | Measure-Object).Count -gt 0) { 'delegatedAndGranularDelegetedAdminPrivileges' } else { 'delegatedAdminPrivileges' } } } | Where-Object -Property defaultDomainName -NotIn $SkipListCache.defaultDomainName - - $GDAPOnlyList = $GDAPRelationships | Where-Object { $_.status -eq 'active' -and $Contracts.customerId -notcontains $_.customer.tenantId } | Select-Object id, @{l = 'customerId'; e = { $($_.customer.tenantId) } }, @{l = 'defaultDomainName'; e = { (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/tenantRelationships/findTenantInformationByTenantId(tenantId='$($_.customer.tenantId)')" -noauthcheck $true -asApp:$true -tenant $env:TenantId).defaultDomainName } }, @{l = 'MigratedToNewTenantAPI'; e = { $true } }, @{n = 'displayName'; exp = { $_.customer.displayName } }, domains, @{n = 'delegatedPrivilegeStatus'; exp = { 'granularDelegatedAdminPrivileges' } } | Where-Object { $_.defaultDomainName -NotIn $SkipListCache.defaultDomainName -and $_.defaultDomainName -ne $null } | Sort-Object -Property customerId -Unique - - $TenantList = @($ContractList) + @($GDAPOnlyList) - } - <#if (!$TenantList.customerId) { - $TenantList = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/contracts?`$top=999" -tenantid $env:TenantID ) | Select-Object id, customerId, DefaultdomainName, DisplayName, domains | Where-Object -Property defaultDomainName -NotIn $SkipListCache.defaultDomainName - }#> - $IncludedTenantsCache = [system.collections.generic.list[hashtable]]::new() - if ($env:PartnerTenantAvailable) { - $IncludedTenantsCache.Add(@{ - RowKey = $env:TenantID - PartitionKey = 'Tenants' - customerId = $env:TenantID - defaultDomainName = $env:TenantID - displayName = '*Partner Tenant' - domains = 'PartnerTenant' - Excluded = $false - ExcludeUser = '' - ExcludeDate = '' - GraphErrorCount = 0 - LastGraphError = '' - LastRefresh = (Get-Date).ToUniversalTime() - }) | Out-Null - } - foreach ($Tenant in $TenantList) { - if ($Tenant.defaultDomainName -eq 'Invalid' -or !$Tenant.defaultDomainName) { continue } - $IncludedTenantsCache.Add(@{ - RowKey = [string]$Tenant.customerId - PartitionKey = 'Tenants' - customerId = [string]$Tenant.customerId - defaultDomainName = [string]$Tenant.defaultDomainName - displayName = [string]$Tenant.DisplayName - delegatedPrivilegeStatus = [string]$Tenant.delegatedPrivilegeStatus - domains = '' - Excluded = $false - ExcludeUser = '' - ExcludeDate = '' - GraphErrorCount = 0 - LastGraphError = '' - LastRefresh = (Get-Date).ToUniversalTime() - }) | Out-Null - } - - if ($IncludedTenantsCache) { - $TenantsTable.Force = $true - Add-CIPPAzDataTableEntity @TenantsTable -Entity $IncludedTenantsCache - } - } - return ($IncludedTenantsCache | Where-Object -Property defaultDomainName -NE $null | Sort-Object -Property displayName) - -} - -function Remove-CIPPCache { - param ( - $TenantsOnly - ) - # Remove all tenants except excluded - $TenantsTable = Get-CippTable -tablename 'Tenants' - $Filter = "PartitionKey eq 'Tenants' and Excluded eq false" - $ClearIncludedTenants = Get-CIPPAzDataTableEntity @TenantsTable -Filter $Filter - Remove-AzDataTableEntity @TenantsTable -Entity $ClearIncludedTenants - if ($tenantsonly -eq 'false') { - Write-Host 'Clearing all' - # Remove Domain Analyser cached results - $DomainsTable = Get-CippTable -tablename 'Domains' - $Filter = "PartitionKey eq 'TenantDomains'" - $ClearDomainAnalyserRows = Get-CIPPAzDataTableEntity @DomainsTable -Filter $Filter | ForEach-Object { - $_.DomainAnalyser = '' - $_ - } - Update-AzDataTableEntity @DomainsTable -Entity $ClearDomainAnalyserRows - #Clear BPA - $BPATable = Get-CippTable -tablename 'cachebpa' - $ClearBPARows = Get-CIPPAzDataTableEntity @BPATable - Remove-AzDataTableEntity @BPATable -Entity $ClearBPARows - $ENV:SetFromProfile = $null - $Script:SkipListCache = $Null - $Script:SkipListCacheEmpty = $Null - $Script:IncludedTenantsCache = $Null - } -} - -function New-ExoRequest ($tenantid, $cmdlet, $cmdParams, $useSystemMailbox, $Anchor, $NoAuthCheck) { - if ((Get-AuthorisedRequest -TenantID $tenantid) -or $NoAuthCheck -eq $True) { - $token = Get-ClassicAPIToken -resource 'https://outlook.office365.com' -Tenantid $tenantid - $tenant = (get-tenants -IncludeErrors | Where-Object { $_.defaultDomainName -eq $tenantid -or $_.customerId -eq $tenantid }).customerId - if ($cmdParams) { - $Params = $cmdParams - } - else { - $Params = @{} - } - $ExoBody = ConvertTo-Json -Depth 5 -InputObject @{ - CmdletInput = @{ - CmdletName = $cmdlet - Parameters = $Params - } - } - if (!$Anchor) { - if ($cmdparams.Identity) { $Anchor = $cmdparams.Identity } - if ($cmdparams.anr) { $Anchor = $cmdparams.anr } - if ($cmdparams.User) { $Anchor = $cmdparams.User } - - if (!$Anchor -or $useSystemMailbox) { - $OnMicrosoft = (New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/domains?$top=999' -tenantid $tenantid -NoAuthCheck $NoAuthCheck | Where-Object -Property isInitial -EQ $true).id - $anchor = "UPN:SystemMailbox{8cc370d3-822a-4ab8-a926-bb94bd0641a9}@$($OnMicrosoft)" - - } - } - Write-Host "Using $Anchor" - $Headers = @{ - Authorization = "Bearer $($token.access_token)" - Prefer = 'odata.maxpagesize = 1000' - 'parameter-based-routing' = $true - 'X-AnchorMailbox' = $anchor - - } - try { - $ReturnedData = Invoke-RestMethod "https://outlook.office365.com/adminapi/beta/$($tenant)/InvokeCommand" -Method POST -Body $ExoBody -Headers $Headers -ContentType 'application/json; charset=utf-8' - if ($ReturnedData.'@adminapi.warnings') { - $ReturnedData.value = $ReturnedData.'@adminapi.warnings' - } - } - catch { - $ErrorMess = $($_.Exception.Message) - $ReportedError = ($_.ErrorDetails | ConvertFrom-Json -ErrorAction SilentlyContinue) - $Message = if ($ReportedError.error.details.message) { - $ReportedError.error.details.message - } - elseif ($ReportedError.error.message) { $ReportedError.error.message } - else { $ReportedError.error.innererror.internalException.message } - if ($null -eq $Message) { $Message = $ErrorMess } - throw $Message - } - return $ReturnedData.value - } - else { - Write-Error 'Not allowed. You cannot manage your own tenant or tenants not under your scope' - } -} - -function Read-JwtAccessDetails { - <# - .SYNOPSIS - Parse Microsoft JWT access tokens - - .DESCRIPTION - Extract JWT access token details for verification - - .PARAMETER Token - Token to get details for - - #> - [cmdletbinding()] - param( - [Parameter(Mandatory = $true)] - [string]$Token - ) - - # Default token object - $TokenDetails = [PSCustomObject]@{ - AppId = '' - AppName = '' - Audience = '' - AuthMethods = '' - IPAddress = '' - Name = '' - Scope = '' - TenantId = '' - UserPrincipalName = '' - } - - if (!$Token.Contains('.') -or !$token.StartsWith('eyJ')) { return $TokenDetails } - - # Get token payload - $tokenPayload = $token.Split('.')[1].Replace('-', '+').Replace('_', '/') - while ($tokenPayload.Length % 4) { - $tokenPayload = '{0}=' -f $tokenPayload - } - - # Convert base64 to json to object - $tokenByteArray = [System.Convert]::FromBase64String($tokenPayload) - $tokenArray = [System.Text.Encoding]::ASCII.GetString($tokenByteArray) - $TokenObj = $tokenArray | ConvertFrom-Json - - # Convert token details to human readable - $TokenDetails.AppId = $TokenObj.appid - $TokenDetails.AppName = $TokenObj.app_displayname - $TokenDetails.Audience = $TokenObj.aud - $TokenDetails.AuthMethods = $TokenObj.amr - $TokenDetails.IPAddress = $TokenObj.ipaddr - $TokenDetails.Name = $TokenObj.name - $TokenDetails.Scope = $TokenObj.scp -split ' ' - $TokenDetails.TenantId = $TokenObj.tid - $TokenDetails.UserPrincipalName = $TokenObj.upn - - return $TokenDetails -} - -function Get-CIPPMSolUsers { - [CmdletBinding()] - param ( - [string]$tenant - ) - $AADGraphtoken = (Get-GraphToken -scope 'https://graph.windows.net/.default') - $tenantid = (get-tenants | Where-Object -Property defaultDomainName -EQ $tenant).customerId - $TrackingGuid = (New-Guid).GUID - $LogonPost = @" -http://provisioning.microsoftonline.com/IProvisioningWebService/MsolConnecturn:uuid:$TrackingGuidhttp://www.w3.org/2005/08/addressing/anonymous$($AADGraphtoken['Authorization'])50afce61-c917-435b-8c6d-60aa5a8b8aa71.2.183.57Version47$($TrackingGuid)https://provisioningapi.microsoftonline.com/provisioningwebservice.svcVersion4 -"@ - $DataBlob = (Invoke-RestMethod -Method POST -Uri 'https://provisioningapi.microsoftonline.com/provisioningwebservice.svc' -ContentType 'application/soap+xml; charset=utf-8' -Body $LogonPost).envelope.header.BecContext.DataBlob.'#text' - - $MSOLXML = @" -http://provisioning.microsoftonline.com/IProvisioningWebService/ListUsersurn:uuid:$TrackingGuidhttp://www.w3.org/2005/08/addressing/anonymous$($AADGraphtoken['Authorization'])$DataBlob250afce61-c917-435b-8c6d-60aa5a8b8aa71.2.183.57Version474e6cb653-c968-4a3a-8a11-2c8919218aebhttps://provisioningapi.microsoftonline.com/provisioningwebservice.svcVersion16$($tenantid)500AscendingNone -"@ - $userlist = do { - if ($null -eq $page) { - $Page = (Invoke-RestMethod -Uri 'https://provisioningapi.microsoftonline.com/provisioningwebservice.svc' -Method post -Body $MSOLXML -ContentType 'application/soap+xml; charset=utf-8').envelope.body.ListUsersResponse.listusersresult.returnvalue - $Page.results.user - } - else { - $Page = (Invoke-RestMethod -Uri 'https://provisioningapi.microsoftonline.com/provisioningwebservice.svc' -Method post -Body $MSOLXML -ContentType 'application/soap+xml; charset=utf-8').envelope.body.NavigateUserResultsResponse.NavigateUserResultsResult.returnvalue - $Page.results.user - } - $MSOLXML = @" -http://provisioning.microsoftonline.com/IProvisioningWebService/NavigateUserResultsurn:uuid:$TrackingGuidhttp://www.w3.org/2005/08/addressing/anonymous$($AADGraphtoken['Authorization'])$DataBlob13050afce61-c917-435b-8c6d-60aa5a8b8aa71.2.183.57Version47$($TrackingGuid)https://provisioningapi.microsoftonline.com/provisioningwebservice.svcVersion16$($tenantid)$($page.listcontext)Next -"@ - } until ($page.IsLastPage -eq $true -or $null -eq $page) - return $userlist -} - -function New-DeviceLogin { - [CmdletBinding()] - param ( - [string]$clientid, - [string]$scope, - [switch]$FirstLogon, - [string]$device_code, - [string]$TenantId - ) - $encodedscope = [uri]::EscapeDataString($scope) - if ($FirstLogon) { - if ($TenantID) { - $ReturnCode = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$($TenantID)/oauth2/v2.0/devicecode" -Method POST -Body "client_id=$($Clientid)&scope=$encodedscope+offline_access+profile+openid" - - } - else { - $ReturnCode = Invoke-RestMethod -Uri 'https://login.microsoftonline.com/organizations/oauth2/v2.0/devicecode' -Method POST -Body "client_id=$($Clientid)&scope=$encodedscope+offline_access+profile+openid" - } - } - else { - $Checking = Invoke-RestMethod -SkipHttpErrorCheck -Uri 'https://login.microsoftonline.com/organizations/oauth2/v2.0/token' -Method POST -Body "client_id=$($Clientid)&scope=$encodedscope+offline_access+profile+openid&grant_type=device_code&device_code=$($device_code)" - if ($checking.refresh_token) { - $ReturnCode = $Checking - } - else { - $returncode = $Checking.error - } - } - return $ReturnCode -} - -function New-passwordString { - [CmdletBinding()] - param ( - [int]$count = 12 - ) - Set-Location (Get-Item $PSScriptRoot).FullName - $SettingsTable = Get-CippTable -tablename 'Settings' - $PasswordType = (Get-CIPPAzDataTableEntity @SettingsTable).passwordType - if ($PasswordType -eq 'Correct-Battery-Horse') { - $Words = Get-Content .\words.txt - (Get-Random -InputObject $words -Count 4) -join '-' - } - else { - -join ('abcdefghkmnrstuvwxyzABCDEFGHKLMNPRSTUVWXYZ23456789$%&*#'.ToCharArray() | Get-Random -Count $count) - } -} - -function New-GraphBulkRequest { - Param( - $tenantid, - $NoAuthCheck, - $scope, - $asapp, - $Requests - ) - - if ($NoAuthCheck -or (Get-AuthorisedRequest -Uri $uri -TenantID $tenantid)) { - $headers = Get-GraphToken -tenantid $tenantid -scope $scope -AsApp $asapp - - $URL = 'https://graph.microsoft.com/beta/$batch' - - # Track consecutive Graph API failures - $TenantsTable = Get-CippTable -tablename Tenants - $Filter = "PartitionKey eq 'Tenants' and (defaultDomainName eq '{0}' or customerId eq '{0}')" -f $tenantid - $Tenant = Get-CIPPAzDataTableEntity @TenantsTable -Filter $Filter - if (!$Tenant) { - $Tenant = @{ - GraphErrorCount = 0 - LastGraphError = $null - PartitionKey = 'TenantFailed' - RowKey = 'Failed' - } - } - try { - $ReturnedData = for ($i = 0; $i -lt $Requests.count; $i += 20) { - $req = @{} - # Use select to create hashtables of id, method and url for each call - $req['requests'] = ($Requests[$i..($i + 19)]) - Invoke-RestMethod -Uri $URL -Method POST -Headers $headers -ContentType 'application/json; charset=utf-8' -Body ($req | ConvertTo-Json -Depth 10) - } - - foreach ($MoreData in $ReturnedData.Responses | Where-Object { $_.body.'@odata.nextLink' }) { - Write-Host 'Getting more' - $AdditionalValues = New-GraphGetRequest -ComplexFilter -uri $MoreData.body.'@odata.nextLink' -tenantid $tenantid -NoAuthCheck:$NoAuthCheck - $NewValues = [System.Collections.Generic.List[PSCustomObject]]$MoreData.body.value - $AdditionalValues | ForEach-Object { $NewValues.add($_) } - $MoreData.body.value = $NewValues - } - - } - catch { - $Message = ($_.ErrorDetails.Message | ConvertFrom-Json -ErrorAction SilentlyContinue).error.message - if ($Message -eq $null) { $Message = $($_.Exception.Message) } - if ($Message -ne 'Request not applicable to target tenant.') { - $Tenant.LastGraphError = $Message - $Tenant.GraphErrorCount++ - Update-AzDataTableEntity @TenantsTable -Entity $Tenant - } - throw $Message - } - - $Tenant.LastGraphError = '' - Update-AzDataTableEntity @TenantsTable -Entity $Tenant - - return $ReturnedData.responses - } - else { - Write-Error 'Not allowed. You cannot manage your own tenant or tenants not under your scope' - } -} - -function Get-GraphBulkResultByID ($Results, $ID, [switch]$Value) { - if ($Value) { - ($Results | Where-Object { $_.id -eq $ID }).body.value - } - else { - ($Results | Where-Object { $_.id -eq $ID }).body - } -} diff --git a/ListAPDevices/function.json b/ListAPDevices/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListAPDevices/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/ListAPDevices/run.ps1 b/ListAPDevices/run.ps1 deleted file mode 100644 index 7139f25c8c34..000000000000 --- a/ListAPDevices/run.ps1 +++ /dev/null @@ -1,30 +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." - -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter -$userid = $Request.Query.UserID -try { - $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceManagement/windowsAutopilotDeviceIdentities?`$top=999" -tenantid $TenantFilter - $StatusCode = [HttpStatusCode]::OK -} -catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $StatusCode = [HttpStatusCode]::Forbidden - $GraphRequest = $ErrorMessage -} - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = @($GraphRequest) - }) \ No newline at end of file diff --git a/ListAlertsQueue/function.json b/ListAlertsQueue/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListAlertsQueue/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/ListAlertsQueue/run.ps1 b/ListAlertsQueue/run.ps1 deleted file mode 100644 index bcee463ba113..000000000000 --- a/ListAlertsQueue/run.ps1 +++ /dev/null @@ -1,46 +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.' -$Table = Get-CIPPTable -TableName 'SchedulerConfig' -$Filter = "PartitionKey eq 'Alert'" -$QueuedApps = Get-CIPPAzDataTableEntity @Table -Filter $Filter - -$CurrentStandards = foreach ($QueueFile in $QueuedApps) { - [PSCustomObject]@{ - tenantName = $QueueFile.tenant - AdminPassword = [bool]$QueueFile.AdminPassword - DefenderMalware = [bool]$QueueFile.DefenderMalware - DefenderStatus = [bool]$QueueFile.DefenderStatus - MFAAdmins = [bool]$QueueFile.MFAAdmins - MFAAlertUsers = [bool]$QueueFile.MFAAlertUsers - NewGA = [bool]$QueueFile.NewGA - NewRole = [bool]$QueueFile.NewRole - QuotaUsed = [bool]$QueueFile.QuotaUsed - UnusedLicenses = [bool]$QueueFile.UnusedLicenses - OverusedLicenses = [bool]$QueueFile.OverusedLicenses - AppSecretExpiry = [bool]$QueueFile.AppSecretExpiry - ApnCertExpiry = [bool]$QueueFile.ApnCertExpiry - VppTokenExpiry = [bool]$QueueFile.VppTokenExpiry - DepTokenExpiry = [bool]$QueueFile.DepTokenExpiry - NoCAConfig = [bool]$QueueFile.NoCAConfig - SecDefaultsUpsell = [bool]$QueueFile.SecDefaultsUpsell - SharepointQuota = [bool]$QueueFile.SharePointQuota - ExpiringLicenses = [bool]$QueueFile.ExpiringLicenses - tenantId = $QueueFile.tenantid - } -} - - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @($CurrentStandards) - }) diff --git a/ListAllTenantDeviceCompliance/function.json b/ListAllTenantDeviceCompliance/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListAllTenantDeviceCompliance/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/ListAllTenantDeviceCompliance/run.ps1 b/ListAllTenantDeviceCompliance/run.ps1 deleted file mode 100644 index ef5e3119b6d5..000000000000 --- a/ListAllTenantDeviceCompliance/run.ps1 +++ /dev/null @@ -1,39 +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." - -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter -try { - if ($TenantFilter -eq 'AllTenants') { - $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/tenantRelationships/managedTenants/managedDeviceCompliances" - $StatusCode = [HttpStatusCode]::OK - } - else { - $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/tenantRelationships/managedTenants/managedDeviceCompliances?`$top=999&`$filter=organizationId eq '$TenantFilter'" - $StatusCode = [HttpStatusCode]::OK - } - - if ($GraphRequest.value.count -lt 1) { - $StatusCode = [HttpStatusCode]::Forbidden - $GraphRequest = "No data found - This client might not be onboarded in Lighthouse" - } -} -catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $StatusCode = [HttpStatusCode]::Forbidden - $GraphRequest = "Could not connect to Azure Lighthouse API: $($ErrorMessage)" -} -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = @($GraphRequest) - }) diff --git a/ListAppStatus/function.json b/ListAppStatus/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListAppStatus/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/ListAppStatus/run.ps1 b/ListAppStatus/run.ps1 deleted file mode 100644 index 4788e37b468d..000000000000 --- a/ListAppStatus/run.ps1 +++ /dev/null @@ -1,34 +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." - -# Interact with query parameters or the body of the request. -$tenantfilter = $Request.Query.TenantFilter -$appFilter = $Request.Query.AppFilter -Write-Host "Using $appFilter" -$body = @" -{"select":["DeviceName","UserPrincipalName","Platform","AppVersion","InstallState","InstallStateDetail","LastModifiedDateTime","DeviceId","ErrorCode","UserName","UserId","ApplicationId","AssignmentFilterIdsList","AppInstallState","AppInstallStateDetails","HexErrorCode"],"skip":0,"top":999,"filter":"(ApplicationId eq '$Appfilter')","orderBy":[]} -"@ -try { - $GraphRequest = New-Graphpostrequest -uri "https://graph.microsoft.com/beta/deviceManagement/reports/getDeviceInstallStatusReport" -tenantid $TenantFilter -body $body - $StatusCode = [HttpStatusCode]::OK -} -catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $StatusCode = [HttpStatusCode]::Forbidden - $GraphRequest = $ErrorMessage -} - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = @($GraphRequest) - }) diff --git a/ListApplicationQueue/function.json b/ListApplicationQueue/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListApplicationQueue/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/ListApplicationQueue/run.ps1 b/ListApplicationQueue/run.ps1 deleted file mode 100644 index ec28f3dec728..000000000000 --- a/ListApplicationQueue/run.ps1 +++ /dev/null @@ -1,33 +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." -$Table = Get-CippTable -tablename 'apps' -$QueuedApps = (Get-CIPPAzDataTableEntity @Table) - -$CurrentApps = foreach ($QueueFile in $QueuedApps) { - Write-Host $QueueFile - $ApplicationFile = $QueueFile.JSON | ConvertFrom-Json -depth 10 - [PSCustomObject]@{ - tenantName = $ApplicationFile.tenant - applicationName = $ApplicationFile.Applicationname - cmdLine = $ApplicationFile.IntuneBody.installCommandLine - assignTo = $ApplicationFile.assignTo - id = $($QueueFile.RowKey) - status = $($QueueFile.status) - } -} - - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @($CurrentApps) - }) diff --git a/ListApps/function.json b/ListApps/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListApps/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/ListApps/run.ps1 b/ListApps/run.ps1 deleted file mode 100644 index 8291fa283489..000000000000 --- a/ListApps/run.ps1 +++ /dev/null @@ -1,29 +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." - -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter -try { - $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceAppManagement/mobileApps?`$top=999&`$filter=(microsoft.graph.managedApp/appAvailability%20eq%20null%20or%20microsoft.graph.managedApp/appAvailability%20eq%20%27lineOfBusiness%27%20or%20isAssigned%20eq%20true)&`$orderby=displayName&" -tenantid $TenantFilter - $StatusCode = [HttpStatusCode]::OK -} -catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $StatusCode = [HttpStatusCode]::Forbidden - $GraphRequest = $ErrorMessage -} - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = @($GraphRequest) - }) diff --git a/ListAppsRepository/function.json b/ListAppsRepository/function.json deleted file mode 100644 index c26ed09a89e4..000000000000 --- a/ListAppsRepository/function.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "bindings": [ - { - "authLevel": "anonymous", - "type": "httpTrigger", - "direction": "in", - "name": "Request", - "methods": ["get", "post"] - }, - { - "type": "http", - "direction": "out", - "name": "Response" - } - ] -} diff --git a/ListAppsRepository/run.ps1 b/ListAppsRepository/run.ps1 deleted file mode 100644 index 1cd40055f84a..000000000000 --- a/ListAppsRepository/run.ps1 +++ /dev/null @@ -1,65 +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' - -$Search = $Request.Body.Search -$Repository = $Request.Body.Repository -$Packages = @() -$Message = '' -$IsError = $false - -try { - if (!([string]::IsNullOrEmpty($Search))) { - if ([string]::IsNullOrEmpty($Repository)) { - $Repository = 'https://chocolatey.org/api/v2' - } - - # Latest version, top 30 results matching search term - $SearchPath = "Search()?`$filter=IsLatestVersion&`$skip=0&`$top=30&searchTerm='$Search'&targetFramework=''&includePrerelease=false" - - $Url = "$Repository/$SearchPath" - $RepoPackages = Invoke-RestMethod $Url -ErrorAction Stop - - if (($RepoPackages | Measure-Object).Count -gt 0) { - $Packages = foreach ($RepoPackage in $RepoPackages) { - [PSCustomObject]@{ - packagename = $RepoPackage.title.'#text' - author = $RepoPackage.author.Name - applicationName = $RepoPackage.properties.Title - version = $RepoPackage.properties.Version - description = $RepoPackage.summary.'#text' - customRepo = $Repository - created = Get-Date -Date $RepoPackage.properties.Created.'#text' -Format 'MM/dd/yyyy HH:mm:ss' - } - } - } - else { - $IsError = $true - $Message = 'No results found' - } - } - else { - $IsError = $true - $Message = 'No search terms specified' - } -} -catch { - $IsError = $true - $Message = "Repository error: $($_.Exception.Message)" -} - -$PackageSearch = @{ - Search = $Search - Results = @($Packages | Sort-Object -Property packagename) - Message = $Message - IsError = $IsError -} - -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $PackageSearch - }) diff --git a/ListAutopilotconfig/function.json b/ListAutopilotconfig/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListAutopilotconfig/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/ListAutopilotconfig/run.ps1 b/ListAutopilotconfig/run.ps1 deleted file mode 100644 index 11042abf346d..000000000000 --- a/ListAutopilotconfig/run.ps1 +++ /dev/null @@ -1,36 +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." - -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter -$userid = $Request.Query.UserID -try { - if ($request.query.type -eq "ApProfile") { - $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceManagement/windowsAutopilotDeploymentProfiles?`$expand=assignments" -tenantid $TenantFilter - } - - if ($request.query.type -eq "ESP") { - $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceManagement/deviceEnrollmentConfigurations?`$expand=assignments" -tenantid $TenantFilter | Where-Object -Property "@odata.type" -EQ "#microsoft.graph.windows10EnrollmentCompletionPageConfiguration" - } - $StatusCode = [HttpStatusCode]::OK -} -catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $StatusCode = [HttpStatusCode]::Forbidden - $GraphRequest = $ErrorMessage -} - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = @($GraphRequest) - }) diff --git a/ListAzureADConnectStatus/function.json b/ListAzureADConnectStatus/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListAzureADConnectStatus/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/ListAzureADConnectStatus/run.ps1 b/ListAzureADConnectStatus/run.ps1 deleted file mode 100644 index 8a97a04820b0..000000000000 --- a/ListAzureADConnectStatus/run.ps1 +++ /dev/null @@ -1,72 +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." - -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter -$DataToReturn = $Request.Query.DataToReturn - -if (($DataToReturn -eq 'AzureADConnectSettings') -or ([string]::IsNullOrEmpty($DataToReturn)) ) { - $ADConnectStatusGraph = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/organization" -tenantid $TenantFilter - #$ADConnectStatusGraph = New-ClassicAPIGetRequest -Resource "74658136-14ec-4630-ad9b-26e160ff0fc6" -TenantID $TenantFilter -Uri "https://main.iam.ad.ext.azure.com/api/Directories/ADConnectStatus" -Method "GET" - #$PasswordSyncStatusGraph = New-ClassicAPIGetRequest -Resource "74658136-14ec-4630-ad9b-26e160ff0fc6" -TenantID $TenantFilter -Uri "https://main.iam.ad.ext.azure.com/api/Directories/GetPasswordSyncStatus" -Method "GET" - $AzureADConnectSettings = [PSCustomObject]@{ - dirSyncEnabled = [boolean]$ADConnectStatusGraph.onPremisesSyncEnabled - #dirSyncConfigured = [boolean]$ADConnectStatusGraph.dirSyncConfigured - #passThroughAuthenticationEnabled = [boolean]$ADConnectStatusGraph.passThroughAuthenticationEnabled - #seamlessSingleSignOnEnabled = [boolean]$ADConnectStatusGraph.seamlessSingleSignOnEnabled - numberOfHoursFromLastSync = $ADConnectStatusGraph.onPremisesLastSyncDateTime - #passwordSyncStatus = [boolean]$PasswordSyncStatusGraph - raw = $ADConnectStatusGraph - } -} - -if (($DataToReturn -eq 'AzureADObjectsInError') -or ([string]::IsNullOrEmpty($DataToReturn)) ) { - $selectlist = "id", "displayName", "onPremisesProvisioningErrors", "createdDateTime" - $Types = "Users", "Contacts", "Groups" - - $GraphRequest = foreach ($Type in $types) { - New-GraphGetRequest -uri "https://graph.microsoft.com/beta/$($Type)?`$select=$($selectlist -join ',')" -tenantid $TenantFilter | ForEach-Object { - if ($_.id -ne $null) { - $_ | Add-Member -NotePropertyName ObjectType -NotePropertyValue $Type - $_ - } - - } - } - $ObjectsInError = @($GraphRequest) -} - -if ([string]::IsNullOrEmpty($DataToReturn)) { - $FinalObject = [PSCustomObject]@{ - AzureADConnectSettings = $AzureADConnectSettings - ObjectsInError = $ObjectsInError - } -} -if ($DataToReturn -eq 'AzureADConnectSettings') { - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $AzureADConnectSettings - }) -} -elseif ($DataToReturn -eq 'AzureADObjectsInError') { - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @($ObjectsInError) - }) -} -else { - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @($FinalObject) - }) -} - diff --git a/ListBPA/function.json b/ListBPA/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListBPA/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/ListBPA/run.ps1 b/ListBPA/run.ps1 deleted file mode 100644 index 247175c44ebf..000000000000 --- a/ListBPA/run.ps1 +++ /dev/null @@ -1,78 +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" - -$Table = get-cipptable 'cachebpav2' -$name = $Request.query.Report -if ($name -eq $null) { $name = 'CIPP Best Practices v1.0 - Table view' } - -# Get all possible JSON files for reports, find the correct one, select the Columns -$JSONFields = @() -$Columns = $null -$CippRoot = (Get-Item $PSScriptRoot).Parent.FullName -(Get-ChildItem -Path "$CippRoot\Config\*.BPATemplate.json" -Recurse | Select-Object -ExpandProperty FullName | ForEach-Object { - $Template = $(Get-Content $_) | ConvertFrom-Json - if ($Template.Name -eq $NAME) { - $JSONFields = $Template.Fields | Where-Object { $_.StoreAs -eq 'JSON' } | ForEach-Object { $_.name } - $Columns = $Template.fields.FrontendFields | Where-Object -Property name -NE $null - $Style = $Template.Style - } -}) - - -if ($Request.query.tenantFilter -ne 'AllTenants' -and $Style -eq 'Tenant') { - $mergedObject = New-Object pscustomobject - - $Data = (Get-CIPPAzDataTableEntity @Table -Filter "PartitionKey eq '$($Request.query.tenantFilter)'") | ForEach-Object { - $row = $_ - $JSONFields | ForEach-Object { - $jsonContent = $row.$_ - if ($jsonContent -ne $null -and $jsonContent -ne 'FAILED') { - $row.$_ = $jsonContent | ConvertFrom-Json -Depth 15 - } - } - $row.PSObject.Properties | ForEach-Object { - $mergedObject | Add-Member -NotePropertyName $_.Name -NotePropertyValue $_.Value -Force - } - } - - $Data = $mergedObject -} -else { - $Tenants = Get-Tenants -IncludeErrors - $Data = (Get-CIPPAzDataTableEntity @Table -Filter "RowKey eq '$NAME'") | ForEach-Object { - $row = $_ - $JSONFields | ForEach-Object { - $jsonContent = $row.$_ - if ($jsonContent -ne $null -and $jsonContent -ne 'FAILED') { - $row.$_ = $jsonContent | ConvertFrom-Json -Depth 15 - } - } - $row | Where-Object -Property PartitionKey -In $Tenants.customerId - } - - -} - -$Results = [PSCustomObject]@{ - Data = $Data - Columns = $Columns - Style = $Style -} - -if (!$Results) { - $Results = @{ - Columns = @( value = 'Results'; name = 'Results') - Data = @(@{ Results = 'The BPA has not yet run.' }) - } -} - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = ($Results | ConvertTo-Json -Depth 15) - }) diff --git a/ListBPATemplates/function.json b/ListBPATemplates/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListBPATemplates/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/ListBPATemplates/run.ps1 b/ListBPATemplates/run.ps1 deleted file mode 100644 index 53b7a23034fc..000000000000 --- a/ListBPATemplates/run.ps1 +++ /dev/null @@ -1,33 +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-Host 'PowerShell HTTP trigger function processed a request.' -Write-Host $Request.query.id - -Set-Location (Get-Item $PSScriptRoot).Parent.FullName -$Templates = Get-ChildItem 'Config\*.BPATemplate.json' - -if ($Request.Query.RawJson) { - $Templates = $Templates | ForEach-Object { - $(Get-Content $_) | ConvertFrom-Json - } -} else { - $Templates = $Templates | ForEach-Object { - $Template = $(Get-Content $_) | ConvertFrom-Json - @{ - Data = $Template.fields - Name = $Template.Name - Style = $Template.Style - } - } -} -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = ($Templates | ConvertTo-Json -Depth 10) - }) diff --git a/ListBasicAuth/function.json b/ListBasicAuth/function.json deleted file mode 100644 index 77f0dced2d90..000000000000 --- a/ListBasicAuth/function.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "bindings": [ - { - "authLevel": "anonymous", - "type": "httpTrigger", - "direction": "in", - "name": "Request", - "methods": ["get", "post"] - }, - { - "type": "http", - "direction": "out", - "name": "Response" - }, - { - "type": "queue", - "direction": "out", - "name": "Msg", - "queueName": "baqueue" - } - ] -} diff --git a/ListBasicAuth/run.ps1 b/ListBasicAuth/run.ps1 deleted file mode 100644 index e9ccd5c46cc3..000000000000 --- a/ListBasicAuth/run.ps1 +++ /dev/null @@ -1,59 +0,0 @@ -using namespace System.Net - -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) -$APIName = $TriggerMetadata.FunctionName - -# Write to the Azure Functions log stream. -Write-Host "PowerShell HTTP trigger function processed a request." -Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Accessed this API" -Sev "Debug" -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter -$currentTime = Get-Date -Format "yyyy-MM-ddTHH:MM:ss" -$ts = (Get-Date).AddDays(-30) -$endTime = $ts.ToString("yyyy-MM-ddTHH:MM:ss") -##Create Filter for basic auth sign-ins -$filters = "createdDateTime ge $($endTime)Z and createdDateTime lt $($currentTime)Z and (clientAppUsed eq 'AutoDiscover' or clientAppUsed eq 'Exchange ActiveSync' or clientAppUsed eq 'Exchange Online PowerShell' or clientAppUsed eq 'Exchange Web Services' or clientAppUsed eq 'IMAP4' or clientAppUsed eq 'MAPI Over HTTP' or clientAppUsed eq 'Offline Address Book' or clientAppUsed eq 'Outlook Anywhere (RPC over HTTP)' or clientAppUsed eq 'Other clients' or clientAppUsed eq 'POP3' or clientAppUsed eq 'Reporting Web Services' or clientAppUsed eq 'Authenticated SMTP' or clientAppUsed eq 'Outlook Service')" -if ($TenantFilter -ne 'AllTenants') { - - try { - $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/auditLogs/signIns?api-version=beta&filter=$($filters)" -tenantid $TenantFilter -erroraction stop | Select-Object userPrincipalName, clientAppUsed, Status | Sort-Object -Unique -Property userPrincipalName - $response = $GraphRequest - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Retrieved basic authentication report" -Sev "Debug" -tenant $TenantFilter - - # Associate values to output bindings by calling 'Push-OutputBinding'. - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @($response) - }) - } - catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to retrieve basic authentication report: $($_.Exception.message) " -Sev "Error" -tenant $TenantFilter - # Associate values to output bindings by calling 'Push-OutputBinding'. - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = '500' - Body = $(Get-NormalizedError -message $_.Exception.message) - }) - } -} -else { - $Table = Get-CIPPTable -TableName cachebasicauth - $Rows = Get-CIPPAzDataTableEntity @Table | Where-Object -Property Timestamp -GT (Get-Date).AddHours(-1) - if (!$Rows) { - Push-OutputBinding -Name Msg -Value (Get-Date).ToString() - $GraphRequest = [PSCustomObject]@{ - Tenant = 'Loading data for all tenants. Please check back in 10 minutes' - } - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @($GraphRequest) - }) - } - else { - $GraphRequest = $Rows - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @($GraphRequest) - }) - } -} \ No newline at end of file diff --git a/ListBasicAuthAllTenants/function.json b/ListBasicAuthAllTenants/function.json deleted file mode 100644 index 241cfb854118..000000000000 --- a/ListBasicAuthAllTenants/function.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "bindings": [ - { - "name": "QueueItem", - "type": "queueTrigger", - "direction": "in", - "queueName": "baqueue" - } - ] -} diff --git a/ListBasicAuthAllTenants/run.ps1 b/ListBasicAuthAllTenants/run.ps1 deleted file mode 100644 index 1fcbca1b4807..000000000000 --- a/ListBasicAuthAllTenants/run.ps1 +++ /dev/null @@ -1,39 +0,0 @@ -# Input bindings are passed in via param block. -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" - -Get-Tenants | ForEach-Object -Parallel { - $domainName = $_.defaultDomainName - Import-Module '.\GraphHelper.psm1' - $currentTime = Get-Date -Format "yyyy-MM-ddTHH:MM:ss" - $ts = (Get-Date).AddDays(-30) - $endTime = $ts.ToString("yyyy-MM-ddTHH:MM:ss") - $filters = "createdDateTime ge $($endTime)Z and createdDateTime lt $($currentTime)Z and (clientAppUsed eq 'AutoDiscover' or clientAppUsed eq 'Exchange ActiveSync' or clientAppUsed eq 'Exchange Online PowerShell' or clientAppUsed eq 'Exchange Web Services' or clientAppUsed eq 'IMAP4' or clientAppUsed eq 'MAPI Over HTTP' or clientAppUsed eq 'Offline Address Book' or clientAppUsed eq 'Outlook Anywhere (RPC over HTTP)' or clientAppUsed eq 'Other clients' or clientAppUsed eq 'POP3' or clientAppUsed eq 'Reporting Web Services' or clientAppUsed eq 'Authenticated SMTP' or clientAppUsed eq 'Outlook Service')" - try { - $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/auditLogs/signIns?api-version=beta&filter=$($filters)" -tenantid $domainName -ErrorAction stop | Sort-Object -Unique -Property clientAppUsed | ForEach-Object { - @{ - Tenant = $domainName - clientAppUsed = $_.clientAppUsed - userPrincipalName = $_.UserPrincipalName - RowKey = "$($_.UserPrincipalName)-$($_.clientAppUsed)" - PartitionKey = 'basicauth' - } - } - } - catch { - $GraphRequest = @{ - Tenant = $domainName - clientAppUsed = "Could not connect to Tenant: $($_.Exception.message)" - userPrincipalName = $domainName - RowKey = $domainName - PartitionKey = 'basicauth' - } - } - $Table = Get-CIPPTable -TableName cachebasicauth - Add-CIPPAzDataTableEntity @Table -Entity $GraphRequest -Force | Out-Null - -} - - diff --git a/ListCAtemplates/function.json b/ListCAtemplates/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListCAtemplates/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/ListCAtemplates/run.ps1 b/ListCAtemplates/run.ps1 deleted file mode 100644 index 99c5660c4345..000000000000 --- a/ListCAtemplates/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" -Set-Location (Get-Item $PSScriptRoot).Parent.FullName - -# Write to the Azure Functions log stream. -Write-Host "PowerShell HTTP trigger function processed a request." -Write-Host $Request.query.id -#Migrating old policies whenever you do a list -$Table = Get-CippTable -tablename 'templates' - -$Templates = Get-ChildItem "Config\*.CATemplate.json" | ForEach-Object { - $Entity = @{ - JSON = "$(Get-Content $_)" - RowKey = "$($_.name)" - PartitionKey = "CATemplate" - GUID = "$($_.name)" - } - Add-CIPPAzDataTableEntity @Table -Entity $Entity -Force -} - -#List new policies -$Table = Get-CippTable -tablename 'templates' -$Filter = "PartitionKey eq 'CATemplate'" -$Templates = (Get-CIPPAzDataTableEntity @Table -Filter $Filter) | ForEach-Object { - $data = $_.JSON | ConvertFrom-Json -Depth 100 - $data | Add-Member -NotePropertyName "GUID" -NotePropertyValue $_.GUID -Force - $data -} | Sort-Object -Property displayName - -if ($Request.query.ID) { $Templates = $Templates | Where-Object -Property GUID -EQ $Request.query.id } - -$Templates = ConvertTo-Json -InputObject @($Templates) -Depth 100 -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Templates - }) diff --git a/ListCalendarPermissions/function.json b/ListCalendarPermissions/function.json deleted file mode 100644 index bec6849b58ab..000000000000 --- a/ListCalendarPermissions/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/ListCalendarPermissions/run.ps1 b/ListCalendarPermissions/run.ps1 deleted file mode 100644 index 385c64c70232..000000000000 --- a/ListCalendarPermissions/run.ps1 +++ /dev/null @@ -1,29 +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" -$UserID = $request.Query.UserID -$Tenantfilter = $request.Query.tenantfilter - -try { - $GetCalParam = @{Identity = $UserID; FolderScope = 'Calendar' } - $CalendarFolder = New-ExoRequest -tenantid $Tenantfilter -cmdlet "Get-MailboxFolderStatistics" -cmdParams $GetCalParam | Select-Object -First 1 - $CalParam = @{Identity = "$($UserID):\$($CalendarFolder.name)" } - $GraphRequest = New-ExoRequest -tenantid $Tenantfilter -cmdlet "Get-MailboxFolderPermission" -cmdParams $CalParam -UseSystemMailbox $true | Select-Object Identity, User, AccessRights, FolderName - Write-LogMessage -API 'List Calendar Permissions' -tenant $tenantfilter -message "Calendar permissions listed for $($tenantfilter)" -sev Debug - $StatusCode = [HttpStatusCode]::OK -} -catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $StatusCode = [HttpStatusCode]::Forbidden - $GraphRequest = $ErrorMessage -} - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = @($GraphRequest) - }) diff --git a/ListConditionalAccessPolicies/function.json b/ListConditionalAccessPolicies/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListConditionalAccessPolicies/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/ListContacts/function.json b/ListContacts/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListContacts/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/ListContacts/run.ps1 b/ListContacts/run.ps1 deleted file mode 100644 index 35b934b44fbc..000000000000 --- a/ListContacts/run.ps1 +++ /dev/null @@ -1,35 +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" - -$selectlist = "id", "companyName", "displayName", "mail", "onPremisesSyncEnabled", "editURL" - -# Write to the Azure Functions log stream. -Write-Host "PowerShell HTTP trigger function processed a request." - - -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter -$ContactID = $Request.Query.ContactID - -Write-Host "Tenant Filter: $TenantFilter" -try { - $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/contacts/$($ContactID)?`$top=999&`$select=$($selectlist -join ',')" -tenantid $TenantFilter | Select-Object $selectlist | ForEach-Object { - $_.editURL = "https://outlook.office365.com/ecp/@$TenantFilter/UsersGroups/EditContact.aspx?exsvurl=1&realm=$($env:TenantID)&mkt=en-US&id=$($_.id)" - $_ - } - $StatusCode = [HttpStatusCode]::OK -} -catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $StatusCode = [HttpStatusCode]::Forbidden - $GraphRequest = $ErrorMessage -} -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = @($GraphRequest | Where-Object -Property id -ne $null) - }) diff --git a/ListDefenderState/function.json b/ListDefenderState/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListDefenderState/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/ListDefenderState/run.ps1 b/ListDefenderState/run.ps1 deleted file mode 100644 index 896121445df0..000000000000 --- a/ListDefenderState/run.ps1 +++ /dev/null @@ -1,31 +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" -$StatusCode = [HttpStatusCode]::OK - -# Write to the Azure Functions log stream. -Write-Host "PowerShell HTTP trigger function processed a request." - -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter -try { - $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/tenantRelationships/managedTenants/windowsProtectionStates?`$top=999&`$filter=tenantId eq '$TenantFilter'" - if ($GraphRequest.tenantDisplayName.length -lt 1) { - $StatusCode = [HttpStatusCode]::Forbidden - $GraphRequest = "No data found - This client might not be onboarded in Lighthouse" - } -} -catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $StatusCode = [HttpStatusCode]::Forbidden - $GraphRequest = "Could not connect to Azure Lighthouse API: $($ErrorMessage)" -} -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = @($GraphRequest) - }) diff --git a/ListDefenderTVM/function.json b/ListDefenderTVM/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListDefenderTVM/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/ListDefenderTVM/run.ps1 b/ListDefenderTVM/run.ps1 deleted file mode 100644 index 16a934b94c21..000000000000 --- a/ListDefenderTVM/run.ps1 +++ /dev/null @@ -1,43 +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." - -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter -try { - $GraphRequest = New-GraphgetRequest -tenantid $TenantFilter -uri "https://api.securitycenter.microsoft.com/api/machines/SoftwareVulnerabilitiesByMachine?`$top=999" -scope "https://api.securitycenter.microsoft.com/.default" | Group-Object cveid - $GroupObj = foreach ($cve in $GraphRequest) { - [pscustomobject]@{ - customerId = $TenantFilter - affectedDevicesCount = $cve.count - cveId = $cve.name - affectedDevices = ($cve.group.deviceName -join ', ') - osPlatform = ($cve.group.osplatform | Sort-Object -Unique) - softwareVendor = ($cve.group.softwareVendor | Sort-Object -Unique) - softwareName = ($cve.group.softwareName | Sort-Object -Unique) - vulnerabilitySeverityLevel = ($cve.group.vulnerabilitySeverityLevel | Sort-Object -Unique) - cvssScore = ($cve.group.cvssScore | Sort-Object -Unique) - securityUpdateAvailable = ($cve.group.securityUpdateAvailable | Sort-Object -Unique) - exploitabilityLevel = ($cve.group.exploitabilityLevel | Sort-Object -Unique) - } - } - $StatusCode = [HttpStatusCode]::OK -} -catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $StatusCode = [HttpStatusCode]::Forbidden - $GroupObj = $ErrorMessage -} -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = @($GroupObj) - }) diff --git a/ListDeletedItems/function.json b/ListDeletedItems/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListDeletedItems/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/ListDeletedItems/run.ps1 b/ListDeletedItems/run.ps1 deleted file mode 100644 index a90b359d42a2..000000000000 --- a/ListDeletedItems/run.ps1 +++ /dev/null @@ -1,23 +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" - -$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" - -# Write to the Azure Functions log stream. -Write-Host "PowerShell HTTP trigger function processed a request." -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter -$Types = "Application", "User", "Device", "Group" -$GraphRequest = foreach ($Type in $Types) { - (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/directory/deletedItems/microsoft.graph.$($Type)" -tenantid $TenantFilter) | Where-Object -Property '@odata.context' -NotLike "*graph.microsoft.com*" | Select-Object *, @{ Name = 'TargetType'; Expression = { $Type } } -} -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @($GraphRequest) - }) \ No newline at end of file diff --git a/ListDeviceDetails/function.json b/ListDeviceDetails/function.json deleted file mode 100644 index 3d31416065c2..000000000000 --- a/ListDeviceDetails/function.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "bindings": [ - { - "authLevel": "anonymous", - "type": "httpTrigger", - "direction": "in", - "name": "Request", - "methods": ["get", "post"] - }, - { - "type": "http", - "direction": "out", - "name": "Response" - }, - { - "type": "queue", - "direction": "out", - "name": "Msg", - "queueName": "generalAllTenantQueue" - } - ] -} diff --git a/ListDeviceDetails/run.ps1 b/ListDeviceDetails/run.ps1 deleted file mode 100644 index 14e97fb6a155..000000000000 --- a/ListDeviceDetails/run.ps1 +++ /dev/null @@ -1,93 +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." - -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter -$DeviceID = $Request.Query.DeviceID -$DeviceName = $Request.Query.DeviceName -$DeviceSerial = $Request.Query.DeviceSerial - -try { - if ($DeviceID) { - $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceManagement/managedDevices/$DeviceID" -Tenantid $tenantfilter - } elseif ($DeviceSerial -or $DeviceName) { - $Found = $False - if ($SeriaNumber -and $DeviceName) { - $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceManagement/managedDevices?`$filter=serialnumber eq '$DeviceSerial' and deviceName eq '$DeviceName'" -Tenantid $tenantfilter - - if (($GraphRequest | Measure-Object).count -eq 1 -and $GraphRequest.'@odata.count' -ne 0 ) { - $Found = $True - } - } - if ($DeviceSerial -and $Found -eq $False) { - $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceManagement/managedDevices?`$filter=serialnumber eq '$DeviceSerial'" -Tenantid $tenantfilter - if (($GraphRequest | Measure-Object).count -eq 1 -and $GraphRequest.'@odata.count' -ne 0 ) { - $Found = $True - } - } - if ($DeviceName -and $Found -eq $False) { - $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceManagement/managedDevices?`$filter=deviceName eq '$DeviceName'" -Tenantid $tenantfilter - if (($GraphRequest | Measure-Object).count -eq 1 -and $GraphRequest.'@odata.count' -ne 0 ) { - $Found = $True - } - } - - } - - if (!(($GraphRequest | Measure-Object).count -eq 1 -and $GraphRequest.'@odata.count' -ne 0 )) { - $GraphRequest = $Null - } - - if ($GraphRequest){ - [System.Collections.Generic.List[PSCustomObject]]$BulkRequests = @( - @{ - id = 'DeviceGroups' - method = 'GET' - url = "/devices(deviceID='$($GraphRequest.azureADDeviceId)')/memberOf" - }, - @{ - id = 'CompliancePolicies' - method = 'GET' - url = "/deviceManagement/managedDevices('$($GraphRequest.id)')/deviceCompliancePolicyStates" - }, - @{ - id = 'DetectedApps' - method = 'GET' - url = "deviceManagement/managedDevices('$($GraphRequest.id)')?expand=detectedApps" - } - ) - - $BulkResults = New-GraphBulkRequest -Requests $BulkRequests -tenantid $TenantFilter - - $DeviceGroups = Get-GraphBulkResultByID -Results $BulkResults -ID 'DeviceGroups' -Value - $CompliancePolicies = Get-GraphBulkResultByID -Results $BulkResults -ID 'CompliancePolicies' -Value - $DetectedApps = Get-GraphBulkResultByID -Results $BulkResults -ID 'DetectedApps' - - $Null = $GraphRequest | Add-Member -NotePropertyName 'DetectedApps' -NotePropertyValue ($DetectedApps.DetectedApps | select-object id, displayName, version) - $Null = $GraphRequest | Add-Member -NotePropertyName 'CompliancePolicies' -NotePropertyValue ($CompliancePolicies | select-object id, displayname, UserPrincipalName, state) - $Null = $GraphRequest | Add-Member -NotePropertyName 'DeviceGroups' -NotePropertyValue ($DeviceGroups | select-object id, displayName, description) - - - } - - $StatusCode = [HttpStatusCode]::OK -} catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $StatusCode = [HttpStatusCode]::Forbidden - $GraphRequest = $ErrorMessage - -} -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = $GraphRequest - }) diff --git a/ListDevices/function.json b/ListDevices/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListDevices/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/ListDevices/run.ps1 b/ListDevices/run.ps1 deleted file mode 100644 index e25cc83040c7..000000000000 --- a/ListDevices/run.ps1 +++ /dev/null @@ -1,29 +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." - -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter -try { - $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceManagement/managedDevices" -Tenantid $tenantfilter - $StatusCode = [HttpStatusCode]::OK -} -catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $StatusCode = [HttpStatusCode]::Forbidden - $GraphRequest = $ErrorMessage - -} -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = @($GraphRequest) - }) diff --git a/ListDomainHealth/function.json b/ListDomainHealth/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListDomainHealth/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/ListDomainHealth/run.ps1 b/ListDomainHealth/run.ps1 deleted file mode 100644 index 29dc7ff06f36..000000000000 --- a/ListDomainHealth/run.ps1 +++ /dev/null @@ -1,146 +0,0 @@ -using namespace System.Net - -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) - -Import-Module DNSHealth - -try { - $ConfigTable = Get-CippTable -tablename Config - $Filter = "PartitionKey eq 'Domains' and RowKey eq 'Domains'" - $Config = Get-CIPPAzDataTableEntity @ConfigTable -Filter $Filter - - $ValidResolvers = @('Google', 'CloudFlare', 'Quad9') - if ($ValidResolvers -contains $Config.Resolver) { - $Resolver = $Config.Resolver - } else { - $Resolver = 'Google' - $Config = @{ - PartitionKey = 'Domains' - RowKey = 'Domains' - Resolver = $Resolver - } - Add-CIPPAzDataTableEntity @ConfigTable -Entity $Config -Force - } -} catch { - $Resolver = 'Google' -} - -Set-DnsResolver -Resolver $Resolver - -$UserCreds = ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($request.headers.'x-ms-client-principal')) | ConvertFrom-Json) - -$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.' - -$StatusCode = [HttpStatusCode]::OK -try { - if ($Request.Query.Action) { - if ($Request.Query.Domain -match '^(((?!-))(xn--|_{1,1})?[a-z0-9-]{0,61}[a-z0-9]{1,1}\.)*(xn--)?([a-z0-9][a-z0-9\-]{0,60}|[a-z0-9-]{1,30}\.[a-z]{2,})$') { - $DomainTable = Get-CIPPTable -Table 'Domains' - $Filter = "RowKey eq '{0}'" -f $Request.Query.Domain - $DomainInfo = Get-CIPPAzDataTableEntity @DomainTable -Filter $Filter - switch ($Request.Query.Action) { - 'ListDomainInfo' { - $Body = $DomainInfo - } - 'GetDkimSelectors' { - $Body = ($DomainInfo.DkimSelectors | ConvertFrom-Json) -join ',' - } - 'ReadSpfRecord' { - $SpfQuery = @{ - Domain = $Request.Query.Domain - } - - if ($Request.Query.ExpectedInclude) { - $SpfQuery.ExpectedInclude = $Request.Query.ExpectedInclude - } - - if ($Request.Query.Record) { - $SpfQuery.Record = $Request.Query.Record - } - - $Body = Read-SpfRecord @SpfQuery - } - 'ReadDmarcPolicy' { - $Body = Read-DmarcPolicy -Domain $Request.Query.Domain - } - 'ReadDkimRecord' { - $DkimQuery = @{ - Domain = $Request.Query.Domain - } - if ($Request.Query.Selector) { - $DkimQuery.Selectors = ($Request.Query.Selector).trim() -split '\s*,\s*' - - if ('admin' -in $UserCreds.userRoles -or 'editor' -in $UserCreds.userRoles) { - $DkimSelectors = [string]($DkimQuery.Selectors | ConvertTo-Json -Compress) - if ($DomainInfo) { - $DomainInfo.DkimSelectors = $DkimSelectors - } else { - $DomainInfo = @{ - 'RowKey' = $Request.Query.Domain - 'PartitionKey' = 'ManualEntry' - 'TenantId' = 'NoTenant' - 'MailProviders' = '' - 'TenantDetails' = '' - 'DomainAnalyser' = '' - 'DkimSelectors' = $DkimSelectors - } - } - Write-Host $DomainInfo - Add-CIPPAzDataTableEntity @DomainTable -Entity $DomainInfo -Force - } - } elseif (![string]::IsNullOrEmpty($DomainInfo.DkimSelectors)) { - $DkimQuery.Selectors = [System.Collections.Generic.List[string]]($DomainInfo.DkimSelectors | ConvertFrom-Json) - } - $Body = Read-DkimRecord @DkimQuery - - } - 'ReadMXRecord' { - $Body = Read-MXRecord -Domain $Request.Query.Domain - } - 'TestDNSSEC' { - $Body = Test-DNSSEC -Domain $Request.Query.Domain - } - 'ReadWhoisRecord' { - $Body = Read-WhoisRecord -Query $Request.Query.Domain - } - 'ReadNSRecord' { - $Body = Read-NSRecord -Domain $Request.Query.Domain - } - 'TestHttpsCertificate' { - $HttpsQuery = @{ - Domain = $Request.Query.Domain - } - if ($Request.Query.Subdomains) { - $HttpsQuery.Subdomains = ($Request.Query.Subdomains).trim() -split '\s*,\s*' - } else { - $HttpsQuery.Subdomains = 'www' - } - - $Body = Test-HttpsCertificate @HttpsQuery - } - 'TestMtaSts' { - $HttpsQuery = @{ - Domain = $Request.Query.Domain - } - $Body = Test-MtaSts @HttpsQuery - } - } - } else { - $body = [pscustomobject]@{'Results' = "Domain: $($Request.Query.Domain) is invalid" } - } - } -} 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)" } -} - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = $body - }) diff --git a/ListDomains/function.json b/ListDomains/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListDomains/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/ListDomains/run.ps1 b/ListDomains/run.ps1 deleted file mode 100644 index fafe94ee47a8..000000000000 --- a/ListDomains/run.ps1 +++ /dev/null @@ -1,29 +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." - -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter - -try { - $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/domains" -tenantid $TenantFilter | Select-Object id, isdefault, isinitial | Sort-Object isdefault - $StatusCode = [HttpStatusCode]::OK -} -catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $StatusCode = [HttpStatusCode]::Forbidden - $GraphRequest = $ErrorMessage -} -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = @($GraphRequest) - }) \ No newline at end of file diff --git a/ListExConnectorTemplates/function.json b/ListExConnectorTemplates/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListExConnectorTemplates/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/ListExConnectorTemplates/run.ps1 b/ListExConnectorTemplates/run.ps1 deleted file mode 100644 index 8ab8d57480bc..000000000000 --- a/ListExConnectorTemplates/run.ps1 +++ /dev/null @@ -1,29 +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" -$Table = Get-CippTable -tablename 'templates' - -#List new policies -$Table = Get-CippTable -tablename 'templates' -$Filter = "PartitionKey eq 'ExConnectorTemplate'" -$Templates = (Get-CIPPAzDataTableEntity @Table -Filter $Filter) | ForEach-Object { - $GUID = $_.RowKey - $Direction = $_.direction - $data = $_.JSON | ConvertFrom-Json - $data | Add-Member -NotePropertyName "GUID" -NotePropertyValue $GUID - $data | Add-Member -NotePropertyName "cippconnectortype" -NotePropertyValue $Direction - $data -} - -if ($Request.query.ID) { $Templates = $Templates | Where-Object -Property RowKey -EQ $Request.query.id } - - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @($Templates) - }) diff --git a/ListExchangeConnectors/function.json b/ListExchangeConnectors/function.json deleted file mode 100644 index bec6849b58ab..000000000000 --- a/ListExchangeConnectors/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/ListExchangeConnectors/run.ps1 b/ListExchangeConnectors/run.ps1 deleted file mode 100644 index 8009c69671af..000000000000 --- a/ListExchangeConnectors/run.ps1 +++ /dev/null @@ -1,25 +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" -$Tenantfilter = $request.Query.tenantfilter - -$Results = try { - New-ExoRequest -tenantid $Tenantfilter -cmdlet "Get-OutboundConnector" | Select-Object *, @{n = 'cippconnectortype'; e = { 'outbound' } } - New-ExoRequest -tenantid $Tenantfilter -cmdlet "Get-InboundConnector" | Select-Object *, @{n = 'cippconnectortype'; e = { 'Inbound' } } - $StatusCode = [HttpStatusCode]::OK -} -catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $StatusCode = [HttpStatusCode]::Forbidden - $ErrorMessage -} - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = @($Results) - }) diff --git a/ListExtensionsConfig/function.json b/ListExtensionsConfig/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListExtensionsConfig/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/ListExtensionsConfig/run.ps1 b/ListExtensionsConfig/run.ps1 deleted file mode 100644 index 1de02456f1a2..000000000000 --- a/ListExtensionsConfig/run.ps1 +++ /dev/null @@ -1,19 +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' - -$Table = Get-CIPPTable -TableName Extensionsconfig -try { - $Body = (Get-CIPPAzDataTableEntity @Table).config | ConvertFrom-Json -Depth 10 -ErrorAction Stop -} catch { - $Body = @{} -} -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $body - }) diff --git a/ListExternalTenantInfo/function.json b/ListExternalTenantInfo/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListExternalTenantInfo/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/ListExternalTenantInfo/run.ps1 b/ListExternalTenantInfo/run.ps1 deleted file mode 100644 index 6d34411ec825..000000000000 --- a/ListExternalTenantInfo/run.ps1 +++ /dev/null @@ -1,70 +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." - -# Interact with query parameters or the body of the request. -$Tenant = $request.query.tenant - -# Normalize to tenantid and determine if tenant exists -$TenantId = (Invoke-RestMethod -Method GET "https://login.windows.net/$tenant/.well-known/openid-configuration").token_endpoint.Split('/')[3] - -if ($TenantId) { - $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/tenantRelationships/findTenantInformationByTenantId(tenantId='$TenantId')" -noauthcheck $true -tenantid $TenantFilter - $StatusCode = [HttpStatusCode]::OK -} - -if ($GraphRequest) { - - $TenantDefaultDomain = $GraphRequest.defaultDomainName - - $body = @" - - - - http://schemas.microsoft.com/exchange/2010/Autodiscover/Autodiscover/GetFederationInformation - https://autodiscover-s.outlook.com/autodiscover/autodiscover.svc - - http://www.w3.org/2005/08/addressing/anonymous - - - - - - $TenantDefaultDomain - - - - -"@ - - # Create the headers - $headers = @{ - "Content-Type" = "text/xml; charset=utf-8" - "SOAPAction" = '"http://schemas.microsoft.com/exchange/2010/Autodiscover/Autodiscover/GetFederationInformation"' - "User-Agent" = "AutodiscoverClient" - } - - # Invoke - $response = Invoke-RestMethod -UseBasicParsing -Method Post -Uri "https://autodiscover-s.outlook.com/autodiscover/autodiscover.svc" -Body $body -Headers $headers - - # Return - $TenantDomains = $response.Envelope.body.GetFederationInformationResponseMessage.response.Domains.Domain | Sort-Object -} - -$results = [PSCustomObject]@{ - GraphRequest = $GraphRequest - Domains = $TenantDomains -} - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = $results - }) diff --git a/ListFunctionParameters/function.json b/ListFunctionParameters/function.json deleted file mode 100644 index bf6c3ef0c49a..000000000000 --- a/ListFunctionParameters/function.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "scriptFile": "../Modules/CippEntryPoints/CippEntryPoints.psm1", - "entryPoint": "Receive-CippHttpTrigger", - "bindings": [ - { - "authLevel": "anonymous", - "type": "httpTrigger", - "direction": "in", - "name": "Request", - "methods": ["get", "post"] - }, - { - "type": "http", - "direction": "out", - "name": "Response" - } - ] -} diff --git a/ListGDAPInvite/function.json b/ListGDAPInvite/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListGDAPInvite/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/ListGDAPInvite/run.ps1 b/ListGDAPInvite/run.ps1 deleted file mode 100644 index f8f61376c5f8..000000000000 --- a/ListGDAPInvite/run.ps1 +++ /dev/null @@ -1,25 +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.' - -Write-Host ($Request | ConvertTo-Json) -if (![string]::IsNullOrEmpty($Request.Query.RelationshipId)) { - $Table = Get-CIPPTable -TableName 'GDAPInvites' - $Invite = Get-CIPPAzDataTableEntity @Table -Filter "RowKey eq '$($Request.Query.RelationshipId)'" - Write-Host $Invite -} else { - $Invite = @{} -} -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Invite - }) diff --git a/ListGDAPQueue/function.json b/ListGDAPQueue/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListGDAPQueue/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/ListGDAPQueue/run.ps1 b/ListGDAPQueue/run.ps1 deleted file mode 100644 index 384b509cdc63..000000000000 --- a/ListGDAPQueue/run.ps1 +++ /dev/null @@ -1,28 +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.' -$Table = Get-CIPPTable -TableName 'GDAPMigration' -$QueuedApps = Get-CIPPAzDataTableEntity @Table - -$CurrentStandards = foreach ($QueueFile in $QueuedApps) { - [PSCustomObject]@{ - Tenant = $QueueFile.tenant - Status = $QueueFile.status - StartAt = $QueueFile.startAt - } -} - - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @($CurrentStandards) - }) diff --git a/ListGDAPRoles/function.json b/ListGDAPRoles/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListGDAPRoles/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/ListGDAPRoles/run.ps1 b/ListGDAPRoles/run.ps1 deleted file mode 100644 index fc389cb54702..000000000000 --- a/ListGDAPRoles/run.ps1 +++ /dev/null @@ -1,28 +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.' -$Table = Get-CIPPTable -TableName 'GDAPRoles' -$Groups = Get-CIPPAzDataTableEntity @Table - -$MappedGroups = foreach ($Group in $Groups) { - [PSCustomObject]@{ - GroupName = $Group.GroupName - GroupId = $Group.GroupId - RoleName = $Group.RoleName - roleDefinitionId = $Group.roleDefinitionId - } -} - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @($MappedGroups) - }) diff --git a/ListGenericAllTenants/run.ps1 b/ListGenericAllTenants/run.ps1 index df23529c61d7..d51627ab7aea 100644 --- a/ListGenericAllTenants/run.ps1 +++ b/ListGenericAllTenants/run.ps1 @@ -12,7 +12,7 @@ Get-CIPPAzDataTableEntity @Table | Remove-AzDataTableEntity @table $RawGraphRequest = Get-Tenants | ForEach-Object -Parallel { $domainName = $_.defaultDomainName - Import-Module '.\GraphHelper.psm1' + Import-Module CippCore try { Write-Host $using:fullUrl New-GraphGetRequest -uri $using:fullUrl -tenantid $_.defaultDomainName -ComplexFilter -ErrorAction Stop | Select-Object *, @{l = 'Tenant'; e = { $domainName } }, @{l = 'CippStatus'; e = { 'Good' } } diff --git a/ListGenericTestFunction/function.json b/ListGenericTestFunction/function.json deleted file mode 100644 index 3d31416065c2..000000000000 --- a/ListGenericTestFunction/function.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "bindings": [ - { - "authLevel": "anonymous", - "type": "httpTrigger", - "direction": "in", - "name": "Request", - "methods": ["get", "post"] - }, - { - "type": "http", - "direction": "out", - "name": "Response" - }, - { - "type": "queue", - "direction": "out", - "name": "Msg", - "queueName": "generalAllTenantQueue" - } - ] -} diff --git a/ListGenericTestFunction/run.ps1 b/ListGenericTestFunction/run.ps1 deleted file mode 100644 index 64b7583f9f3c..000000000000 --- a/ListGenericTestFunction/run.ps1 +++ /dev/null @@ -1,13 +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' -$graphRequest = ($request.headers.'x-ms-original-url').split('/api') | Select-Object -First 1 - -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @($graphRequest) - }) -clobber \ No newline at end of file diff --git a/ListGroupTemplates/function.json b/ListGroupTemplates/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListGroupTemplates/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/ListGroupTemplates/run.ps1 b/ListGroupTemplates/run.ps1 deleted file mode 100644 index df07537a56a7..000000000000 --- a/ListGroupTemplates/run.ps1 +++ /dev/null @@ -1,30 +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" -Set-Location (Get-Item $PSScriptRoot).Parent.FullName - -# Write to the Azure Functions log stream. -Write-Host "PowerShell HTTP trigger function processed a request." -Write-Host $Request.query.id - -#List new policies -$Table = Get-CippTable -tablename 'templates' -$Filter = "PartitionKey eq 'GroupTemplate'" -$Templates = (Get-CIPPAzDataTableEntity @Table -Filter $Filter) | ForEach-Object { - $data = $_.JSON | ConvertFrom-Json - $data | Add-Member -MemberType NoteProperty -Name GUID -Value $_.RowKey -Force - $data -} | Sort-Object -Property displayName - -if ($Request.query.ID) { $Templates = $Templates | Where-Object -Property GUID -EQ $Request.query.id } - - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @($Templates) - }) diff --git a/ListGroups/function.json b/ListGroups/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListGroups/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/ListGroups/run.ps1 b/ListGroups/run.ps1 deleted file mode 100644 index 8739c362b27e..000000000000 --- a/ListGroups/run.ps1 +++ /dev/null @@ -1,72 +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." - -# Interact with query parameters or the body of the request. - -$TenantFilter = $Request.Query.TenantFilter -$selectstring = "id,createdDateTime,displayName,description,mail,mailEnabled,mailNickname,resourceProvisioningOptions,securityEnabled,visibility,organizationId,onPremisesSamAccountName,membershipRule,grouptypes,onPremisesSyncEnabled,resourceProvisioningOptions,userPrincipalName&`$expand=members(`$select=userPrincipalName)" - -if ($Request.Query.GroupID) { - $groupid = $Request.query.groupid - $selectstring = "id,createdDateTime,displayName,description,mail,mailEnabled,mailNickname,resourceProvisioningOptions,securityEnabled,visibility,organizationId,onPremisesSamAccountName,membershipRule,groupTypes,userPrincipalName" -} -if ($Request.Query.members) { - $members = "members" - $selectstring = "id,userPrincipalName,displayName,hideFromOutlookClients,hideFromAddressLists,mail,mailEnabled,mailNickname,resourceProvisioningOptions,securityEnabled,visibility,organizationId,onPremisesSamAccountName,membershipRule" -} - -if ($Request.Query.owners) { - $members = "owners" - $selectstring = "id,userPrincipalName,displayName,hideFromOutlookClients,hideFromAddressLists,mail,mailEnabled,mailNickname,resourceProvisioningOptions,securityEnabled,visibility,organizationId,onPremisesSamAccountName,membershipRule" -} -try { - $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/groups/$($GroupID)/$($members)?`$top=999&select=$selectstring" -tenantid $TenantFilter | Select-Object *, @{ Name = 'primDomain'; Expression = { $_.mail -split "@" | Select-Object -Last 1 } }, - @{Name = 'membersCsv'; Expression = { $_.members.userPrincipalName -join "," } }, - @{Name = 'teamsEnabled'; Expression = { if ($_.resourceProvisioningOptions -Like '*Team*') { $true }else { $false } } }, - @{Name = 'calculatedGroupType'; Expression = { - - if ($_.mailEnabled -and $_.securityEnabled) { - "Mail-Enabled Security" - } - if (!$_.mailEnabled -and $_.securityEnabled) { - "Security" - } - if ($_.groupTypes -contains 'Unified') { - "Microsoft 365" - } - if (([string]::isNullOrEmpty($_.groupTypes)) -and ($_.mailEnabled) -and (!$_.securityEnabled)) { - "Distribution List" - } - } - }, - @{Name = 'dynamicGroupBool'; Expression = { - if ($_.groupTypes -contains 'DynamicMembership') { - $true - } - else { - $false - } - } - } - - $StatusCode = [HttpStatusCode]::OK -} -catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $StatusCode = [HttpStatusCode]::Forbidden - $GraphRequest = $ErrorMessage -} -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = @($GraphRequest) - }) diff --git a/ListHaloClients/function.json b/ListHaloClients/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListHaloClients/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/ListHaloClients/run.ps1 b/ListHaloClients/run.ps1 deleted file mode 100644 index dc5d64867528..000000000000 --- a/ListHaloClients/run.ps1 +++ /dev/null @@ -1,43 +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." - -# Interact with query parameters or the body of the request. -try { - $Table = Get-CIPPTable -TableName Extensionsconfig - $Configuration = ((Get-CIPPAzDataTableEntity @Table).config | ConvertFrom-Json).HaloPSA - $Token = Get-HaloToken -configuration $Configuration - $i = 1 - $RawHaloClients = do { - $Result = Invoke-RestMethod -Uri "$($Configuration.ResourceURL)/Client?page_no=$i&page_size=999&pageinate=true" -ContentType 'application/json' -Method GET -Headers @{Authorization = "Bearer $($token.access_token)" } - $Result.clients | Select-Object * -ExcludeProperty logo - $i++ - $pagecount = [Math]::Ceiling($Result.record_count / 999) - } while ($i -le $pagecount) - $HaloClients = $RawHaloClients | ForEach-Object { - [PSCustomObject]@{ - label = $_.name - value = $_.id - } - } - $StatusCode = [HttpStatusCode]::OK -} -catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $StatusCode = [HttpStatusCode]::Forbidden - $HaloClients = $ErrorMessage -} - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = @($HaloClients) - }) diff --git a/ListInactiveAccounts/function.json b/ListInactiveAccounts/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListInactiveAccounts/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/ListInactiveAccounts/run.ps1 b/ListInactiveAccounts/run.ps1 deleted file mode 100644 index 097e65b15c85..000000000000 --- a/ListInactiveAccounts/run.ps1 +++ /dev/null @@ -1,30 +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." - -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter -if ($TenantFilter -eq "AllTenants") { $TenantFilter = (get-tenants).customerId } -try { - $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/tenantRelationships/managedTenants/inactiveUsers?`$count=true" -tenantid $env:TenantId | Where-Object { $_.tenantId -in $TenantFilter } - $StatusCode = [HttpStatusCode]::OK -} -catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $StatusCode = [HttpStatusCode]::Forbidden - $GraphRequest = "Could not connect to Azure Lighthouse API: $($ErrorMessage)" -} - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = @($GraphRequest) - }) diff --git a/ListIntuneIntents/function.json b/ListIntuneIntents/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListIntuneIntents/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/ListIntuneIntents/run.ps1 b/ListIntuneIntents/run.ps1 deleted file mode 100644 index 09f3e3a50464..000000000000 --- a/ListIntuneIntents/run.ps1 +++ /dev/null @@ -1,29 +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." - -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter -try { - $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceManagement/Intents?`$expand=settings,categories" -tenantid $TenantFilter - $StatusCode = [HttpStatusCode]::OK -} -catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $StatusCode = [HttpStatusCode]::Forbidden - $GraphRequest = $ErrorMessage -} - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = @($GraphRequest) - }) diff --git a/ListIntunePolicy/function.json b/ListIntunePolicy/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListIntunePolicy/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/ListIntunePolicy/run.ps1 b/ListIntunePolicy/run.ps1 deleted file mode 100644 index 048d6f60f50b..000000000000 --- a/ListIntunePolicy/run.ps1 +++ /dev/null @@ -1,62 +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." - -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter -$id = $Request.Query.ID -$urlname = $Request.Query.URLName -try { - if ($ID) { - $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$($urlname)('$ID')" -tenantid $tenantfilter - } - else { - - $GraphURLS = @("https://graph.microsoft.com/beta/deviceManagement/deviceConfigurations?`$select=id,displayName,lastModifiedDateTime,roleScopeTagIds,microsoft.graph.unsupportedDeviceConfiguration/originalEntityTypeName&`$expand=assignments&top=1000", - "https://graph.microsoft.com/beta/deviceManagement/groupPolicyConfigurations?`$expand=assignments&top=1000" - "https://graph.microsoft.com/beta/deviceAppManagement/mobileAppConfigurations?`$expand=assignments&`$filter=microsoft.graph.androidManagedStoreAppConfiguration/appSupportsOemConfig%20eq%20true" - "https://graph.microsoft.com/beta/deviceManagement/configurationPolicies" - ) - - $GraphRequest = $GraphURLS | ForEach-Object { - $URLName = (($_).split('?') | Select-Object -First 1) -replace 'https://graph.microsoft.com/beta/deviceManagement/', '' - New-GraphGetRequest -uri $_ -tenantid $TenantFilter - - } | ForEach-Object { - $policyTypeName = switch -Wildcard ($_."assignments@odata.context") { - "*microsoft.graph.windowsIdentityProtectionConfiguration*" { "Identity Protection" } - "*microsoft.graph.windows10EndpointProtectionConfiguration*" { "Endpoint Protection" } - "*microsoft.graph.windows10CustomConfiguration*" { "Custom" } - "*groupPolicyConfigurations*" { "Administrative Templates" } - "*windowsDomainJoinConfiguration*" { "Domain Join configuration" } - "*windowsUpdateForBusinessConfiguration*" { "Update Configuration" } - "*windowsHealthMonitoringConfiguration*" { "Health Monitoring" } - default { $_."assignments@odata.context" } - } - if ($_.displayname -eq $null) { $_ | Add-Member -NotePropertyName displayName -NotePropertyValue $_.name } - $_ | Add-Member -NotePropertyName PolicyTypeName -NotePropertyValue $policyTypeName - $_ | Add-Member -NotePropertyName URLName -NotePropertyValue $URLName - $_ - } | Where-Object { $_.DisplayName -ne $null } - - } - $StatusCode = [HttpStatusCode]::OK -} -catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $StatusCode = [HttpStatusCode]::Forbidden - $GraphRequest = $ErrorMessage -} -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = @($GraphRequest) - }) diff --git a/ListIntuneTemplates/function.json b/ListIntuneTemplates/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListIntuneTemplates/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/ListIntuneTemplates/run.ps1 b/ListIntuneTemplates/run.ps1 deleted file mode 100644 index f35dd082841b..000000000000 --- a/ListIntuneTemplates/run.ps1 +++ /dev/null @@ -1,44 +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' -Set-Location (Get-Item $PSScriptRoot).Parent.FullName - -$Table = Get-CippTable -tablename 'templates' - -$Templates = Get-ChildItem 'Config\*.IntuneTemplate.json' | ForEach-Object { - $Entity = @{ - JSON = "$(Get-Content $_)" - RowKey = "$($_.name)" - PartitionKey = 'IntuneTemplate' - GUID = "$($_.name)" - } - Add-CIPPAzDataTableEntity @Table -Entity $Entity -Force -} - -#List new policies -$Table = Get-CippTable -tablename 'templates' -$Filter = "PartitionKey eq 'IntuneTemplate'" -$Templates = (Get-CIPPAzDataTableEntity @Table -Filter $Filter).JSON | ConvertFrom-Json -if ($Request.query.View) { - $Templates = $Templates | ForEach-Object { - $data = $_.RAWJson | ConvertFrom-Json - $data | Add-Member -NotePropertyName 'displayName' -NotePropertyValue $_.Displayname -Force - $data | Add-Member -NotePropertyName 'description' -NotePropertyValue $_.Description -Force - $data | Add-Member -NotePropertyName 'Type' -NotePropertyValue $_.Type - $data | Add-Member -NotePropertyName 'GUID' -NotePropertyValue $_.GUID - $data - } -} - -if ($Request.query.ID) { $Templates = $Templates | Where-Object -Property guid -EQ $Request.query.id } - - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = ($Templates | ConvertTo-Json -Depth 10) - }) diff --git a/ListKnownIPDb/function.json b/ListKnownIPDb/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListKnownIPDb/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/ListKnownIPDb/run.ps1 b/ListKnownIPDb/run.ps1 deleted file mode 100644 index 5a2b9996f7b5..000000000000 --- a/ListKnownIPDb/run.ps1 +++ /dev/null @@ -1,20 +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.' -$Table = Get-CIPPTable -TableName 'knownlocationdb' -$Filter = "Tenant eq '$($Request.Query.TenantFilter)'" -$KnownIPDb = Get-CIPPAzDataTableEntity @Table -Filter $Filter - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @($KnownIPDb) - }) diff --git a/ListLicenses/function.json b/ListLicenses/function.json deleted file mode 100644 index 8968c43fc37f..000000000000 --- a/ListLicenses/function.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "bindings": [ - { - "authLevel": "anonymous", - "type": "httpTrigger", - "direction": "in", - "name": "Request", - "methods": ["get", "post"] - }, - { - "type": "http", - "direction": "out", - "name": "Response" - }, - { - "type": "queue", - "direction": "out", - "name": "Msg", - "queueName": "licqueue" - } - ] -} diff --git a/ListLicenses/run.ps1 b/ListLicenses/run.ps1 deleted file mode 100644 index 869d5044184e..000000000000 --- a/ListLicenses/run.ps1 +++ /dev/null @@ -1,36 +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.' - -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter -$RawGraphRequest = if ($TenantFilter -ne 'AllTenants') { - $GraphRequest = Get-CIPPLicenseOverview -TenantFilter $TenantFilter -} -else { - $Table = Get-CIPPTable -TableName cachelicenses - $Rows = Get-CIPPAzDataTableEntity @Table | Where-Object -Property Timestamp -GT (Get-Date).AddHours(-1) - if (!$Rows) { - Push-OutputBinding -Name Msg -Value (Get-Date).ToString() - $GraphRequest = [PSCustomObject]@{ - Tenant = 'Loading data for all tenants. Please check back in 1 minute' - License = 'Loading data for all tenants. Please check back in 1 minute' - } - } - else { - $GraphRequest = $Rows - } -} - -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @($GraphRequest) - }) -Clobber \ No newline at end of file diff --git a/ListLicensesAllTenants/run.ps1 b/ListLicensesAllTenants/run.ps1 index e7cdf761879e..abc69465c094 100644 --- a/ListLicensesAllTenants/run.ps1 +++ b/ListLicensesAllTenants/run.ps1 @@ -6,7 +6,6 @@ Write-Host "PowerShell queue trigger function processed work item: $QueueItem" $RawGraphRequest = Get-Tenants | ForEach-Object -Parallel { $domainName = $_.defaultDomainName - Import-Module '.\GraphHelper.psm1' Import-Module '.\Modules\AzBobbyTables' Import-Module '.\Modules\CIPPCore' try { diff --git a/ListLogs/function.json b/ListLogs/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListLogs/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/ListLogs/run.ps1 b/ListLogs/run.ps1 deleted file mode 100644 index ee201dbea8d7..000000000000 --- a/ListLogs/run.ps1 +++ /dev/null @@ -1,54 +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' - -if ($request.Query.Filter -eq 'True') { - $LogLevel = if ($Request.query.Severity) { ($Request.query.Severity).split(',') } else { 'Info', 'Warn', 'Error', 'Critical', 'Alert' } - $PartitionKey = $Request.query.DateFilter - $username = $Request.Query.User -} -else { - $LogLevel = 'Info', 'Warn', 'Error', 'Critical', 'Alert' - $PartitionKey = Get-Date -UFormat '%Y%m%d' - $username = '*' -} -$Table = Get-CIPPTable - -$ReturnedLog = if ($Request.Query.ListLogs) { - - Get-CIPPAzDataTableEntity @Table -Property PartitionKey | Sort-Object -Unique PartitionKey | Select-Object PartitionKey | ForEach-Object { - @{ - value = $_.PartitionKey - label = $_.PartitionKey - } - } -} -else { - $Filter = "PartitionKey eq '{0}'" -f $PartitionKey - $Rows = Get-CIPPAzDataTableEntity @Table -Filter $Filter | Where-Object { $_.Severity -In $LogLevel -and $_.user -like $username } - foreach ($Row in $Rows) { - @{ - DateTime = $Row.Timestamp - Tenant = $Row.Tenant - API = $Row.API - Message = $Row.Message - User = $Row.Username - Severity = $Row.Severity - TenantID = if ($Row.TenantID -ne $null) { - $Row.TenantID - } else { - 'None' - } - } - } - -} - -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @($ReturnedLog) - }) diff --git a/ListMFAUsers/function.json b/ListMFAUsers/function.json deleted file mode 100644 index 26f0727fe6fd..000000000000 --- a/ListMFAUsers/function.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "bindings": [ - { - "authLevel": "anonymous", - "type": "httpTrigger", - "direction": "in", - "name": "Request", - "methods": ["get", "post"] - }, - { - "type": "http", - "direction": "out", - "name": "Response" - }, - { - "type": "queue", - "direction": "out", - "name": "Msg", - "queueName": "mfaqueue" - } - ] -} diff --git a/ListMFAUsers/run.ps1 b/ListMFAUsers/run.ps1 deleted file mode 100644 index 40bc53bed91d..000000000000 --- a/ListMFAUsers/run.ps1 +++ /dev/null @@ -1,36 +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.' - -if ($Request.query.TenantFilter -ne 'AllTenants') { - $GraphRequest = Get-CIPPMFAState -TenantFilter $Request.query.TenantFilter -} -else { - $Table = Get-CIPPTable -TableName cachemfa - - $Rows = Get-CIPPAzDataTableEntity @Table | Where-Object -Property Timestamp -GT (Get-Date).AddHours(-2) - if (!$Rows) { - $Queue = New-CippQueueEntry -Name 'MFA Users - All Tenants' -Link '/identity/reports/mfa-report?customerId=AllTenants' - Write-Information ($Queue | ConvertTo-Json) - Push-OutputBinding -Name Msg -Value $Queue.RowKey - $GraphRequest = [PSCustomObject]@{ - UPN = 'Loading data for all tenants. Please check back in 10 minutes' - } - } - else { - $GraphRequest = $Rows - } -} -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @($GraphRequest) - }) diff --git a/ListMFAUsersAllTenants/run.ps1 b/ListMFAUsersAllTenants/run.ps1 index f34fb82921f1..8ab611e514fe 100644 --- a/ListMFAUsersAllTenants/run.ps1 +++ b/ListMFAUsersAllTenants/run.ps1 @@ -13,7 +13,6 @@ try { $GraphRequest = Get-Tenants | ForEach-Object -Parallel { $domainName = $_.defaultDomainName - Import-Module '.\GraphHelper.psm1' Import-Module '.\modules\CippCore' $Table = Get-CIPPTable -TableName cachemfa Try { diff --git a/ListMailQuarantine/function.json b/ListMailQuarantine/function.json deleted file mode 100644 index bec6849b58ab..000000000000 --- a/ListMailQuarantine/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/ListMailQuarantine/run.ps1 b/ListMailQuarantine/run.ps1 deleted file mode 100644 index 2d558ddb3776..000000000000 --- a/ListMailQuarantine/run.ps1 +++ /dev/null @@ -1,24 +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" -$Tenantfilter = $request.Query.tenantfilter - -try { - $GraphRequest = New-ExoRequest -tenantid $Tenantfilter -cmdlet "Get-QuarantineMessage" - $StatusCode = [HttpStatusCode]::OK -} -catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $StatusCode = [HttpStatusCode]::Forbidden - $GraphRequest = $ErrorMessage -} - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = @($GraphRequest) - }) diff --git a/ListMailboxCAS/function.json b/ListMailboxCAS/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListMailboxCAS/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/ListMailboxCAS/run.ps1 b/ListMailboxCAS/run.ps1 deleted file mode 100644 index 60d0b4d145db..000000000000 --- a/ListMailboxCAS/run.ps1 +++ /dev/null @@ -1,36 +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." - -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter -try { - $GraphRequest = New-GraphGetRequest -uri "https://outlook.office365.com/adminapi/beta/$($tenantfilter)/CasMailbox" -Tenantid $tenantfilter -scope ExchangeOnline | Select-Object @{ Name = 'displayName'; Expression = { $_.'DisplayName' } }, - @{ Name = 'primarySmtpAddress'; Expression = { $_.'PrimarySMTPAddress' } }, - @{ Name = 'ecpenabled'; Expression = { $_.'ECPEnabled' } }, - @{ Name = 'owaenabled'; Expression = { $_.'OWAEnabled' } }, - @{ Name = 'imapenabled'; Expression = { $_.'IMAPEnabled' } }, - @{ Name = 'popenabled'; Expression = { $_.'POPEnabled' } }, - @{ Name = 'mapienabled'; Expression = { $_.'MAPIEnabled' } }, - @{ Name = 'ewsenabled'; Expression = { $_.'EWSEnabled' } }, - @{ Name = 'activesyncenabled'; Expression = { $_.'ActiveSyncEnabled' } } - $StatusCode = [HttpStatusCode]::OK -} -catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $StatusCode = [HttpStatusCode]::Forbidden - $GraphRequest = $ErrorMessage -} -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = @($GraphRequest) - }) diff --git a/ListMailboxMobileDevices/function.json b/ListMailboxMobileDevices/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListMailboxMobileDevices/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/ListMailboxMobileDevices/run.ps1 b/ListMailboxMobileDevices/run.ps1 deleted file mode 100644 index 59924b4a2765..000000000000 --- a/ListMailboxMobileDevices/run.ps1 +++ /dev/null @@ -1,49 +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." - -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter -$Mailbox = $Request.Query.Mailbox - -Write-Host $TenantFilter -Write-Host $Mailbox - -$Bytes = [System.Text.Encoding]::UTF8.GetBytes($Mailbox) -$base64IdentityParam = [Convert]::ToBase64String($Bytes) - -try { - $GraphRequest = New-GraphGetRequest -uri "https://outlook.office365.com:443/adminapi/beta/$($TenantFilter)/mailbox('$($base64IdentityParam)')/MobileDevice/Exchange.GetMobileDeviceStatistics()/?IsEncoded=True" -Tenantid $tenantfilter -scope ExchangeOnline | Select-Object @{ Name = 'clientType'; Expression = { $_.ClientType } }, - @{ Name = 'clientVersion'; Expression = { $_.ClientVersion } }, - @{ Name = 'deviceAccessState'; Expression = { $_.DeviceAccessState } }, - @{ Name = 'deviceFriendlyName'; Expression = { if ([string]::IsNullOrEmpty($_.DeviceFriendlyName)) { "Unknown" }else { $_.DeviceFriendlyName } } }, - @{ Name = 'deviceModel'; Expression = { $_.DeviceModel } }, - @{ Name = 'deviceOS'; Expression = { $_.DeviceOS } }, - @{ Name = 'deviceType'; Expression = { $_.DeviceType } }, - @{ Name = 'firstSync'; Expression = { $_.FirstSyncTime.toString() } }, - @{ Name = 'lastSyncAttempt'; Expression = { $_.LastSyncAttemptTime.toString() } }, - @{ Name = 'lastSuccessSync'; Expression = { $_.LastSuccessSync.toString() } }, - @{ Name = 'status'; Expression = { $_.Status } }, - @{ Name = 'deviceID'; Expression = { $_.deviceID } }, - @{ Name = 'Guid'; Expression = { $_.Guid } } - - $StatusCode = [HttpStatusCode]::OK -} -catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $StatusCode = [HttpStatusCode]::Forbidden - $GraphRequest = $ErrorMessage -} -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = @($GraphRequest) - }) diff --git a/ListMailboxRestores/function.json b/ListMailboxRestores/function.json deleted file mode 100644 index bf6c3ef0c49a..000000000000 --- a/ListMailboxRestores/function.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "scriptFile": "../Modules/CippEntryPoints/CippEntryPoints.psm1", - "entryPoint": "Receive-CippHttpTrigger", - "bindings": [ - { - "authLevel": "anonymous", - "type": "httpTrigger", - "direction": "in", - "name": "Request", - "methods": ["get", "post"] - }, - { - "type": "http", - "direction": "out", - "name": "Response" - } - ] -} diff --git a/ListMailboxRules/function.json b/ListMailboxRules/function.json deleted file mode 100644 index ccf1e3f0a86d..000000000000 --- a/ListMailboxRules/function.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "bindings": [ - { - "authLevel": "anonymous", - "type": "httpTrigger", - "direction": "in", - "name": "Request", - "methods": ["get", "post"] - }, - { - "type": "http", - "direction": "out", - "name": "Response" - }, - { - "type": "queue", - "direction": "out", - "name": "Msg", - "queueName": "mbxrulequeue" - } - ] -} diff --git a/ListMailboxRules/run.ps1 b/ListMailboxRules/run.ps1 deleted file mode 100644 index 08cc420b409a..000000000000 --- a/ListMailboxRules/run.ps1 +++ /dev/null @@ -1,49 +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.' - -# 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 Msg -Value $TenantFilter - $GraphRequest = [PSCustomObject]@{ - Tenant = 'Loading data. Please check back in 1 minute' - Licenses = 'Loading data. Please check back in 1 minute' - } -} -else { - if ($TenantFilter -ne 'AllTenants') { - $GraphRequest = $Rows | Where-Object -Property Tenant -EQ $TenantFilter | ForEach-Object { - $NewObj = $_.Rules | ConvertFrom-Json - $NewObj | Add-Member -NotePropertyName 'Tenant' -NotePropertyValue $TenantFilter - $NewObj - } - } - else { - $GraphRequest = $Rows | ForEach-Object { - $TenantName = $_.Tenant - $NewObj = $_.Rules | ConvertFrom-Json - $NewObj | Add-Member -NotePropertyName 'Tenant' -NotePropertyValue $TenantName - $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 - Body = @($GraphRequest) - }) \ No newline at end of file diff --git a/ListMailboxRulesAllTenants/run.ps1 b/ListMailboxRulesAllTenants/run.ps1 index f47e6b1b105a..28782db5e6cb 100644 --- a/ListMailboxRulesAllTenants/run.ps1 +++ b/ListMailboxRulesAllTenants/run.ps1 @@ -13,7 +13,6 @@ else { } $Tenants | ForEach-Object -Parallel { $domainName = $_.defaultDomainName - Import-Module '.\GraphHelper.psm1' Import-Module '.\Modules\CIPPcore' try { diff --git a/ListMailboxStatistics/function.json b/ListMailboxStatistics/function.json deleted file mode 100644 index 3d31416065c2..000000000000 --- a/ListMailboxStatistics/function.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "bindings": [ - { - "authLevel": "anonymous", - "type": "httpTrigger", - "direction": "in", - "name": "Request", - "methods": ["get", "post"] - }, - { - "type": "http", - "direction": "out", - "name": "Response" - }, - { - "type": "queue", - "direction": "out", - "name": "Msg", - "queueName": "generalAllTenantQueue" - } - ] -} diff --git a/ListMailboxStatistics/run.ps1 b/ListMailboxStatistics/run.ps1 deleted file mode 100644 index 507a96ac924e..000000000000 --- a/ListMailboxStatistics/run.ps1 +++ /dev/null @@ -1,60 +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." - -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter -try { - - $GraphRequest = if ($TenantFilter -ne 'AllTenants') { - New-GraphGetRequest -uri "https://graph.microsoft.com/beta/reports/getMailboxUsageDetail(period='D7')" -tenantid $TenantFilter | ConvertFrom-Csv | Select-Object @{ Name = 'UPN'; Expression = { $_.'User Principal Name' } }, - @{ Name = 'displayName'; Expression = { $_.'Display Name' } }, - @{ Name = 'MailboxType'; Expression = { $_.'Recipient Type' } }, - @{ Name = 'LastActive'; Expression = { $_.'Last Activity Date' } }, - @{ Name = 'UsedGB'; Expression = { [math]::round($_.'Storage Used (Byte)' / 1GB, 2) } }, - @{ Name = 'QuotaGB'; Expression = { [math]::round($_.'Prohibit Send/Receive Quota (Byte)' / 1GB, 2) } }, - @{ Name = 'ItemCount'; Expression = { $_.'Item Count' } }, - @{ Name = 'HasArchive'; Expression = { If (($_.'Has Archive').ToLower() -eq 'true') { [bool]$true } else { [bool]$false } } } - $StatusCode = [HttpStatusCode]::OK - } - else { - $Table = Get-CIPPTable -TableName "cachereports" - $Rows = Get-CIPPAzDataTableEntity @Table | Where-Object -Property Timestamp -GT (Get-Date).AddHours(-1) - if (!$Rows) { - $Queue = New-CippQueueEntry -Name "Reports" -Link '/email/reports/mailbox-statistics?customerId=AllTenants' - Push-OutputBinding -Name Msg -Value "reports/getMailboxUsageDetail(period='D7')?`$format=application/json" - [PSCustomObject]@{ - Tenant = 'Loading data for all tenants. Please check back after the job completes' - } - $StatusCode = [HttpStatusCode]::OK - } - else { - $Rows.Data | ConvertFrom-Json | Select-Object *, @{ Name = 'UPN'; Expression = { $_.'UserPrincipalName' } }, - @{ Name = 'MailboxType'; Expression = { $_.'RecipientType' } }, - @{ Name = 'LastActive'; Expression = { $_.'LastActivityDate' } }, - @{ Name = 'UsedGB'; Expression = { [math]::round($_.'storageUsedInBytes' / 1GB, 2) } }, - @{ Name = 'QuotaGB'; Expression = { [math]::round($_.'prohibitSendReceiveQuotaInBytes' / 1GB, 2) } } - $StatusCode = [HttpStatusCode]::OK - } - } - - -} -catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $StatusCode = [HttpStatusCode]::Forbidden - $GraphRequest = $ErrorMessage -} -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = @($GraphRequest) - }) -clobber diff --git a/ListMailboxes/function.json b/ListMailboxes/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListMailboxes/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/ListMailboxes/run.ps1 b/ListMailboxes/run.ps1 deleted file mode 100644 index 544a716a761b..000000000000 --- a/ListMailboxes/run.ps1 +++ /dev/null @@ -1,82 +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.' - -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter -try { - if ([bool]$Request.Query.SkipLicense -ne $true) { - $users = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/?`$top=999&`$select=id,userPrincipalName,assignedLicenses" -Tenantid $tenantfilter - } else { - $users = @() - } - - $ExoRequest = @{ - tenantid = $TenantFilter - cmdlet = 'Get-Mailbox' - cmdParams = @{} - } - - $AllowedParameters = @( - @{Parameter = 'Anr'; Type = 'String' } - @{Parameter = 'Archive'; Type = 'Bool' } - @{Parameter = 'Filter'; Type = 'String' } - @{Parameter = 'GroupMailbox'; Type = 'Bool' } - @{Parameter = 'PublicFolder'; Type = 'Bool' } - @{Parameter = 'RecipientTypeDetails'; Type = 'String' } - @{Parameter = 'SoftDeletedMailbox'; Type = 'Bool' } - ) - - foreach ($Param in $Request.Query.Keys) { - $CmdParam = $AllowedParameters | Where-Object { $_.Parameter -eq $Param } - if ($CmdParam) { - switch ($CmdParam.Type) { - 'String' { - if (![string]::IsNullOrEmpty($Request.Query.$Param)) { - $ExoRequest.cmdParams.$Param = $Request.Query.$Param - } - } - 'Bool' { - if ([bool]$Request.Query.$Param -eq $true) { - $ExoRequest.cmdParams.$Param = $true - } - } - } - } - } - - Write-Host ($ExoRequest | ConvertTo-Json) - - $GraphRequest = (New-ExoRequest @ExoRequest) | Select-Object id, ExchangeGuid, ArchiveGuid, @{ Name = 'UPN'; Expression = { $_.'UserPrincipalName' } }, - - @{ Name = 'displayName'; Expression = { $_.'DisplayName' } }, - @{ Name = 'SharedMailboxWithLicense'; Expression = { - $ID = $_.id - $Shared = if ($_.'RecipientTypeDetails' -eq 'SharedMailbox') { $true } else { $false } - if (($users | Where-Object -Property ID -EQ $ID).assignedLicenses.skuid -and $Shared) { $true } else { $false } - } - }, - - @{ Name = 'primarySmtpAddress'; Expression = { $_.'PrimarySMTPAddress' } }, - @{ Name = 'recipientType'; Expression = { $_.'RecipientType' } }, - @{ Name = 'recipientTypeDetails'; Expression = { $_.'RecipientTypeDetails' } }, - @{ Name = 'AdditionalEmailAddresses'; Expression = { ($_.'EmailAddresses' | Where-Object { $_ -clike 'smtp:*' }).Replace('smtp:', '') -join ', ' } } - $StatusCode = [HttpStatusCode]::OK -} catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $StatusCode = [HttpStatusCode]::Forbidden - $GraphRequest = $ErrorMessage -} -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = @($GraphRequest) - }) diff --git a/ListMessageTrace/function.json b/ListMessageTrace/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListMessageTrace/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/ListMessageTrace/run.ps1 b/ListMessageTrace/run.ps1 deleted file mode 100644 index 6aae3ba30afa..000000000000 --- a/ListMessageTrace/run.ps1 +++ /dev/null @@ -1,39 +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" - - -try { - $TenantFilter = $request.query.TenantFilter - $SearchParams = @{ - StartDate = (Get-Date).AddDays( - $($request.query.days)).ToString('s') - EndDate = (Get-Date).ToString('s') - } - - if ($null -ne $request.query.recipient) { $Searchparams.Add('RecipientAddress', $($request.query.recipient)) } - if ($null -ne $request.query.sender) { $Searchparams.Add('SenderAddress', $($request.query.sender)) } - $type = $request.query.Tracedetail - $trace = if ($Request.Query.Tracedetail) { - New-ExoRequest -tenantid $Tenantfilter -cmdlet "Get-MessageTraceDetail" -cmdParams $Searchparams - Get-MessageTraceDetail -MessageTraceId $Request.Query.ID -RecipientAddress $request.query.recipient -erroraction stop | Select-Object Event, Action, Detail, @{ Name = 'Date'; Expression = { $_.Date.Tostring('s') } } - } - else { - New-ExoRequest -tenantid $Tenantfilter -cmdlet "Get-MessageTrace" -cmdParams $Searchparams | Select-Object MessageTraceId, Status, Subject, RecipientAddress, SenderAddress, @{ Name = 'Date'; Expression = { $_.Received.tostring('s') } } - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantfilter) -message "Executed message trace" -Sev "Info" - - } -} -catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantfilter) -message "Failed executing messagetrace. Error: $($_.Exception.Message)" -Sev "Error" - $trace = @{Status = "Failed to retrieve message trace $($_.Exception.Message)" } -} - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @($trace) - }) diff --git a/ListNamedLocations/function.json b/ListNamedLocations/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListNamedLocations/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/ListNamedLocations/run.ps1 b/ListNamedLocations/run.ps1 deleted file mode 100644 index 3fec85f0a0fd..000000000000 --- a/ListNamedLocations/run.ps1 +++ /dev/null @@ -1,33 +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." - -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter -try { - $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/identity/conditionalAccess/namedLocations" -Tenantid $tenantfilter | Select-Object *, - @{ - name = "rangeOrLocation" - expression = { if ($_.ipRanges) { $_.ipranges.cidrAddress -join ', ' } else { $_.countriesAndRegions -join ', ' } } - } - $StatusCode = [HttpStatusCode]::OK -} -catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $StatusCode = [HttpStatusCode]::Forbidden - $GraphRequest = $ErrorMessage - -} -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = @($GraphRequest) - }) diff --git a/ListNotificationConfig/function.json b/ListNotificationConfig/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListNotificationConfig/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/ListNotificationConfig/run.ps1 b/ListNotificationConfig/run.ps1 deleted file mode 100644 index f65c1f16b644..000000000000 --- a/ListNotificationConfig/run.ps1 +++ /dev/null @@ -1,33 +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' - -$Table = Get-CIPPTable -TableName SchedulerConfig -$Filter = "RowKey eq 'CippNotifications' and PartitionKey eq 'CippNotifications'" -$Config = Get-CIPPAzDataTableEntity @Table -Filter $Filter -if ($Config) { - $Config = $Config | ConvertTo-Json -Depth 10 | ConvertFrom-Json -Depth 10 -AsHashtable -} else { - $Config = @{} -} -#$config | Add-Member -NotePropertyValue @() -NotePropertyName 'logsToInclude' -Force -$config.logsToInclude = @(([pscustomobject]$config | Select-Object * -ExcludeProperty schedule, type, tenantid, onepertenant, sendtoIntegration, partitionkey, rowkey, tenant, ETag, email, logsToInclude, Severity, Alert, Info, Error, timestamp, webhook, includeTenantId).psobject.properties.name) -if (!$config.logsToInclude) { - $config.logsToInclude = @('None') -} -if (!$config.Severity) { - $config.Severity = @('Alert') -} else { - $config.Severity = $config.Severity -split ',' -} -$body = [PSCustomObject]$Config - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $body - }) diff --git a/ListOAuthApps/function.json b/ListOAuthApps/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListOAuthApps/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/ListOAuthApps/run.ps1 b/ListOAuthApps/run.ps1 deleted file mode 100644 index d88ab1c30664..000000000000 --- a/ListOAuthApps/run.ps1 +++ /dev/null @@ -1,49 +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." - -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter -if ($TenantFilter -eq "AllTenants") { $Tenants = (Get-Tenants).defaultDomainName } else { $tenants = $TenantFilter } - -try { - $GraphRequest = foreach ($Tenant in $Tenants) { - try { - $ServicePrincipals = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/servicePrincipals?`$select=id,displayName,appid" -tenantid $Tenant - New-GraphGetRequest -uri "https://graph.microsoft.com/beta/oauth2PermissionGrants" -tenantid $Tenant | ForEach-Object { - $CurrentServicePrincipal = ($ServicePrincipals | Where-Object -Property id -EQ $_.clientId) - [PSCustomObject]@{ - Tenant = $Tenant - Name = $CurrentServicePrincipal.displayName - ApplicationID = $CurrentServicePrincipal.appid - ObjectID = $_.clientId - Scope = ($_.scope -join ',') - StartTime = $_.startTime - } - } - $StatusCode = [HttpStatusCode]::OK - } - catch { - continue - } - } -} -catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $StatusCode = [HttpStatusCode]::Forbidden - $GraphRequest = $ErrorMessage -} - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = @($GraphRequest) - }) diff --git a/ListOoO/function.json b/ListOoO/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListOoO/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/ListOoO/run.ps1 b/ListOoO/run.ps1 deleted file mode 100644 index 7a6a7222358d..000000000000 --- a/ListOoO/run.ps1 +++ /dev/null @@ -1,21 +0,0 @@ -using namespace System.Net - -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) - -$APIName = $TriggerMetadata.FunctionName -$Tenantfilter = $request.query.tenantFilter -try { - $Body = Get-CIPPOutOfOffice -userid $Request.query.userid -tenantFilter $TenantFilter -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' -} -catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $Body = [pscustomobject]@{"Results" = "Failed. $ErrorMessage" } - -} - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Body - }) diff --git a/ListOrg/function.json b/ListOrg/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListOrg/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/ListOrg/run.ps1 b/ListOrg/run.ps1 deleted file mode 100644 index 92ee467c194f..000000000000 --- a/ListOrg/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" - - -# Write to the Azure Functions log stream. -Write-Host "PowerShell HTTP trigger function processed a request." - -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter -if ($TenantFilter -eq "AllTenants") { - -} -else { - $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/organization" -tenantid $TenantFilter -} - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $GraphRequest - }) diff --git a/ListPartnerRelationships/function.json b/ListPartnerRelationships/function.json deleted file mode 100644 index 0847eee4046a..000000000000 --- a/ListPartnerRelationships/function.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "bindings": [ - { - "authLevel": "anonymous", - "type": "httpTrigger", - "direction": "in", - "name": "Request", - "methods": ["get", "post"] - }, - { - "type": "http", - "direction": "out", - "name": "Response" - }, - { - "type": "queue", - "direction": "out", - "name": "QueueTenant", - "queueName": "GraphRequestQueue" - } - ] -} diff --git a/ListPartnerRelationships/run.ps1 b/ListPartnerRelationships/run.ps1 deleted file mode 100644 index 4a6d47d586c7..000000000000 --- a/ListPartnerRelationships/run.ps1 +++ /dev/null @@ -1,30 +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' - -try { - $GraphRequestList = @{ - Endpoint = 'policies/crossTenantAccessPolicy/partners' - TenantFilter = $Request.Query.TenantFilter - QueueNameOverride = 'Partner Relationships' - ReverseTenantLookup = $true - } - $GraphRequest = Get-GraphRequestList @GraphRequestList -} catch { - $GraphRequest = @() -} - -$StatusCode = [HttpStatusCode]::OK - -$results = [PSCustomObject]@{ - Results = @($GraphRequest) -} -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = $results - }) diff --git a/ListPhishPolicies/function.json b/ListPhishPolicies/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListPhishPolicies/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/ListPhishPolicies/run.ps1 b/ListPhishPolicies/run.ps1 deleted file mode 100644 index 3d9dff6712ab..000000000000 --- a/ListPhishPolicies/run.ps1 +++ /dev/null @@ -1,41 +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." - -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter -$AntiPhishRules = New-ExoRequest -tenantid $TenantFilter -cmdlet "Get-AntiPhishRule" -$AntiPhishPolicies = New-ExoRequest -tenantid $TenantFilter -cmdlet "Get-AntiPhishPolicy" - -$GraphRequest = $AntiPhishPolicies | Select-Object name, -@{Name = 'GUID'; Expression = {$(( -join (( 0x41..0x5A) + ( 0x61..0x7A) | Get-Random -Count 13 | % {[char]$_}) ))}}, -@{ Name = 'ExcludedDomains'; Expression = {$($_.ExcludedDomains) -join "
"}}, -@{ Name = 'ExcludedSenders'; Expression = {$($_.ExcludedSenders) -join "
" } }, -@{ Name = 'PhishThresholdLevel'; Expression = { - switch ($_.PhishThresholdLevel) { - 1 { $result = 'Standard' } - 2 { $result = 'Aggressive' } - 3 { $result = 'More Aggressive' } - 4 { $result = 'Most Aggressive' } - Default { $result = 'Unknown' } - } - $result - } -}, -@{ Name = 'ExcludedDomainCount'; Expression = { $_.ExcludedDomains | Measure-Object | Select-Object -ExpandProperty Count } }, -@{ Name = 'ExcludedSenderCount'; Expression = { $_.ExcludedSenders | Measure-Object | Select-Object -ExpandProperty Count } }, Enabled, WhenChangedUTC, -@{ Name = 'Priority'; Expression = { foreach ($item in $AntiPhishRules) { if ($item.name -eq $_.name) { $item.priority } } } } - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @($GraphRequest) - }) diff --git a/ListPotentialApps/function.json b/ListPotentialApps/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListPotentialApps/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/ListPotentialApps/run.ps1 b/ListPotentialApps/run.ps1 deleted file mode 100644 index 338b8b92e306..000000000000 --- a/ListPotentialApps/run.ps1 +++ /dev/null @@ -1,25 +0,0 @@ -using namespace System.Net - -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) -Set-Location (Get-Item $PSScriptRoot).Parent.FullName -$APIName = $TriggerMetadata.FunctionName -Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Accessed this API" -Sev "Debug" - -if ($request.body.type -eq "WinGet") { - $body = @" -{"MaximumResults":50,"Filters":[{"PackageMatchField":"Market","RequestMatch":{"KeyWord":"US","MatchType":"CaseInsensitive"}}],"Query":{"KeyWord":"$($Request.Body.SearchString)","MatchType":"Substring"}} -"@ - $DataRequest = (Invoke-RestMethod -Uri "https://storeedgefd.dsx.mp.microsoft.com/v9.0/manifestSearch" -Method POST -Body $body -ContentType "Application/json").data | Select-Object @{l = 'applicationName'; e = { $_.packagename } }, @{l = 'packagename'; e = { $_.packageIdentifier } } | Sort-Object -Property applicationName -} - -if ($Request.body.type -eq "Choco") { - $DataRequest = Invoke-RestMethod -Uri "https://community.chocolatey.org/api/v2/Search()?`$filter=IsLatestVersion&`$skip=0&`$top=999&searchTerm=%27$($request.body.SearchString)%27&targetFramework=%27%27&includePrerelease=false" -ContentType 'application/json' | Select-Object @{l = 'applicationName'; e = { $_.properties.Title } }, @{l = 'packagename'; e = { $_.title.'#text' } } | Sort-Object -Property applicationName -} - - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @($DataRequest) - }) \ No newline at end of file diff --git a/ListRoles/function.json b/ListRoles/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListRoles/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/ListRoles/run.ps1 b/ListRoles/run.ps1 deleted file mode 100644 index fb774e322424..000000000000 --- a/ListRoles/run.ps1 +++ /dev/null @@ -1,33 +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." - -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter -$SelectList = 'id', 'displayName', 'userPrincipalName' - -[System.Collections.Generic.List[PSCustomObject]]$Roles = New-GraphGetRequest -uri "https://graph.microsoft.com/v1.0/directoryRoles?`$expand=members" -tenantid $TenantFilter -$GraphRequest = foreach ($Role in $Roles) { - - #[System.Collections.Generic.List[PSCustomObject]]$Members = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/directoryRoles/$($Role.id)/members?`$select=$($selectlist -join ',')" -tenantid $TenantFilter | Select-Object $SelectList - $Members = if ($Role.members) { $role.members | ForEach-Object { " $($_.displayName) ($($_.userPrincipalName))" } } else { "none" } - [PSCustomObject]@{ - DisplayName = $Role.displayName - Description = $Role.description - Members = $Members -join ',' - } -} - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $GraphRequest - }) \ No newline at end of file diff --git a/ListScheduledItems/function.json b/ListScheduledItems/function.json deleted file mode 100644 index b0ca1676cc0b..000000000000 --- a/ListScheduledItems/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/ListScheduledItems/run.ps1 b/ListScheduledItems/run.ps1 deleted file mode 100644 index 748dbcfeafd3..000000000000 --- a/ListScheduledItems/run.ps1 +++ /dev/null @@ -1,15 +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.' -$Table = Get-CIPPTable -TableName 'ScheduledTasks' -$ScheduledTasks = Get-CIPPAzDataTableEntity @Table -Filter "PartitionKey eq 'ScheduledTask' and Hidden ne 'True'" - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @($ScheduledTasks) - }) \ No newline at end of file diff --git a/ListServiceHealth/function.json b/ListServiceHealth/function.json deleted file mode 100644 index 4ee273331c44..000000000000 --- a/ListServiceHealth/function.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "bindings": [ - { - "authLevel": "anonymous", - "type": "httpTrigger", - "direction": "in", - "name": "Request", - "methods": ["get", "post"] - }, - { - "type": "http", - "direction": "out", - "name": "Response" - } - ] -} diff --git a/ListServiceHealth/run.ps1 b/ListServiceHealth/run.ps1 deleted file mode 100644 index 738b6c1feed2..000000000000 --- a/ListServiceHealth/run.ps1 +++ /dev/null @@ -1,36 +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." - - -$ResultHealthSummary = Get-Tenants | ForEach-Object -Parallel { - Import-Module '.\GraphHelper.psm1' - $tenantname = $_.displayName - Write-Host $tenantname - $prop = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/admin/serviceAnnouncement/issues?`$filter=endDateTime eq null" -tenantid $_.defaultDomainName - $prop | Add-Member -NotePropertyName 'tenant' -NotePropertyValue $tenantname - $prop -} -$Results = foreach ($h in $ResultHealthSummary) { - [PSCustomObject]@{ - TenantName = $h.tenant - issueId = $h.ID - service = $h.service - type = $h.feature - desc = $h.impactDescription - } -} - -$StatusCode = [HttpStatusCode]::OK - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = @($Results) - }) diff --git a/ListSharedMailboxAccountEnabled/function.json b/ListSharedMailboxAccountEnabled/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListSharedMailboxAccountEnabled/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/ListSharedMailboxAccountEnabled/run.ps1 b/ListSharedMailboxAccountEnabled/run.ps1 deleted file mode 100644 index 45762d45d8f5..000000000000 --- a/ListSharedMailboxAccountEnabled/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." - -$TenantFilter = $Request.Query.TenantFilter - -# Get Shared Mailbox Stuff -try { - $SharedMailboxList = (New-GraphGetRequest -uri "https://outlook.office365.com/adminapi/beta/$($TenantFilter)/Mailbox?`$filter=RecipientTypeDetails eq 'SharedMailbox'" -Tenantid $TenantFilter -scope ExchangeOnline) - $AllUsersAccountState = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/users?select=userPrincipalName,accountEnabled,displayName,givenName,surname' -tenantid $Tenantfilter - $EnabledUsersWithSharedMailbox = foreach ($SharedMailbox in $SharedMailboxList) { - # Match the User - $User = $AllUsersAccountState | Where-Object { $_.userPrincipalName -eq $SharedMailbox.userPrincipalName } | Select-Object -Property userPrincipalName, accountEnabled, displayName, givenName, surname -First 1 - if ($User.accountEnabled) { - $User | Select-Object ` - @{Name='UserPrincipalName';Expression={$User.UserPrincipalName}}, ` - @{Name='displayName';Expression={$User.displayName}}, - @{Name='givenName';Expression={$User.givenName}}, - @{Name='surname';Expression={$User.surname}}, - @{Name='accountEnabled';Expression={$User.accountEnabled}} - - } - } -} -catch { - Write-LogMessage -API 'Tenant' -tenant $tenantfilter -message "Shared Mailbox Enabled Accounts on $($tenantfilter). Error: $($_.exception.message)" -sev 'Error' -} - -$GraphRequest = $EnabledUsersWithSharedMailbox -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @($GraphRequest) - }) \ No newline at end of file diff --git a/ListSharedMailboxStatistics/function.json b/ListSharedMailboxStatistics/function.json deleted file mode 100644 index 4ee273331c44..000000000000 --- a/ListSharedMailboxStatistics/function.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "bindings": [ - { - "authLevel": "anonymous", - "type": "httpTrigger", - "direction": "in", - "name": "Request", - "methods": ["get", "post"] - }, - { - "type": "http", - "direction": "out", - "name": "Response" - } - ] -} diff --git a/ListSharedMailboxStatistics/run.ps1 b/ListSharedMailboxStatistics/run.ps1 deleted file mode 100644 index fb4c19680a47..000000000000 --- a/ListSharedMailboxStatistics/run.ps1 +++ /dev/null @@ -1,35 +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." - -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter -try { - $GraphRequest = New-GraphGetRequest -uri "https://outlook.office365.com/adminapi/beta/$($tenantFilter)/Mailbox?RecipientTypeDetails=sharedmailbox" -Tenantid $tenantFilter -scope ExchangeOnline | ForEach-Object { - try { - New-ExoRequest -tenantid $TenantFilter -cmdlet "Get-MailboxStatistics" -cmdParams @{Identity = $_.GUID } - } - catch { - continue - } - } - $StatusCode = [HttpStatusCode]::OK -} -catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $StatusCode = [HttpStatusCode]::Forbidden - $GraphRequest = $ErrorMessage -} -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = @($GraphRequest) - }) diff --git a/ListSharepointQuota/function.json b/ListSharepointQuota/function.json deleted file mode 100644 index 925eab5aeae1..000000000000 --- a/ListSharepointQuota/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/ListSharepointSettings/function.json b/ListSharepointSettings/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListSharepointSettings/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/ListSharepointSettings/run.ps1 b/ListSharepointSettings/run.ps1 deleted file mode 100644 index 17c1f8e773d7..000000000000 --- a/ListSharepointSettings/run.ps1 +++ /dev/null @@ -1,25 +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." - -# Interact with query parameters or the body of the request. -$tenant = $Request.Query.TenantFilter -$User = $Request.query.user -$USERToGet = $Request.query.usertoGet -$body = '{"isResharingByExternalUsersEnabled": "False"}' -$Request = New-GraphPostRequest -tenantid $tenant -Uri "https://graph.microsoft.com/beta/admin/sharepoint/settings" -Type patch -Body $body -ContentType "application/json" - -Write-LogMessage -API "Standards" -tenant $tenantFilter -message "Disabled Password Expiration" -sev Info -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @($GraphRequest) - }) diff --git a/ListSignIns/function.json b/ListSignIns/function.json deleted file mode 100644 index 77f0dced2d90..000000000000 --- a/ListSignIns/function.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "bindings": [ - { - "authLevel": "anonymous", - "type": "httpTrigger", - "direction": "in", - "name": "Request", - "methods": ["get", "post"] - }, - { - "type": "http", - "direction": "out", - "name": "Response" - }, - { - "type": "queue", - "direction": "out", - "name": "Msg", - "queueName": "baqueue" - } - ] -} diff --git a/ListSignIns/run.ps1 b/ListSignIns/run.ps1 deleted file mode 100644 index 2883c345c8e5..000000000000 --- a/ListSignIns/run.ps1 +++ /dev/null @@ -1,48 +0,0 @@ -using namespace System.Net - -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) -$APIName = $TriggerMetadata.FunctionName - -# Write to the Azure Functions log stream. -Write-Host 'PowerShell HTTP trigger function processed a request.' -Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter -try { - if ($Request.query.failedlogonOnly) { - $FailedLogons = " and (status/errorCode eq 50126)" - } - - $filters = if ($Request.query.Filter) { - $request.query.filter - } - else { - $currentTime = Get-Date -Format 'yyyy-MM-dd' - $ts = (Get-Date).AddDays(-7) - $endTime = $ts.ToString('yyyy-MM-dd') - "createdDateTime ge $($endTime) and createdDateTime lt $($currentTime) and userDisplayName ne 'On-Premises Directory Synchronization Service Account' $FailedLogons" - } - Write-Host $Filters - - $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/auditLogs/signIns?api-version=beta&`$filter=$($filters)" -tenantid $TenantFilter -erroraction stop - $response = $GraphRequest | Select-Object *, - @{l = "additionalDetails"; e = { $_.status.additionalDetails } } , - @{l = "errorCode"; e = { $_.status.errorCode } }, - @{l = "locationcipp"; e = { "$($_.location.city) - $($_.location.countryOrRegion)" } } - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Retrieved sign in report' -Sev 'Debug' -tenant $TenantFilter - - # Associate values to output bindings by calling 'Push-OutputBinding'. - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @($response) - }) -} -catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to retrieve Sign In report: $($_.Exception.message) " -Sev 'Error' -tenant $TenantFilter - # Associate values to output bindings by calling 'Push-OutputBinding'. - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = '500' - Body = $(Get-NormalizedError -message $_.Exception.message) - }) -} diff --git a/ListSites/function.json b/ListSites/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListSites/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/ListSites/run.ps1 b/ListSites/run.ps1 deleted file mode 100644 index 64300086ccae..000000000000 --- a/ListSites/run.ps1 +++ /dev/null @@ -1,47 +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." - -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter -$type = $request.query.Type -$UserUPN = $request.query.UserUPN -try { - $Result = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/reports/get$($type)Detail(period='D7')" -tenantid $TenantFilter | ConvertFrom-Csv - - if ($UserUPN) { - $ParsedRequest = $Result | Where-Object { $_.'Owner Principal Name' -eq $UserUPN } - } - else { - $ParsedRequest = $Result - } - - - $GraphRequest = $ParsedRequest | Select-Object @{ Name = 'UPN'; Expression = { $_.'Owner Principal Name' } }, - @{ Name = 'displayName'; Expression = { $_.'Owner Display Name' } }, - @{ Name = 'LastActive'; Expression = { $_.'Last Activity Date' } }, - @{ Name = 'FileCount'; Expression = { [int]$_.'File Count' } }, - @{ Name = 'UsedGB'; Expression = { [math]::round($_.'Storage Used (Byte)' / 1GB, 2) } }, - @{ Name = 'URL'; Expression = { $_.'Site URL' } }, - @{ Name = 'Allocated'; Expression = { [math]::round($_.'Storage Allocated (Byte)' / 1GB, 2) } }, - @{ Name = 'Template'; Expression = { $_.'Root Web Template' } } - $StatusCode = [HttpStatusCode]::OK -} -catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $StatusCode = [HttpStatusCode]::Forbidden - $GraphRequest = $ErrorMessage -} -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = @($GraphRequest) - }) diff --git a/ListSpamFilterTemplates/function.json b/ListSpamFilterTemplates/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListSpamFilterTemplates/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/ListSpamFilterTemplates/run.ps1 b/ListSpamFilterTemplates/run.ps1 deleted file mode 100644 index cbee13867932..000000000000 --- a/ListSpamFilterTemplates/run.ps1 +++ /dev/null @@ -1,27 +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" -$Table = Get-CippTable -tablename 'templates' - -#List new policies -$Table = Get-CippTable -tablename 'templates' -$Filter = "PartitionKey eq 'SpamfilterTemplate'" -$Templates = (Get-CIPPAzDataTableEntity @Table -Filter $Filter) | ForEach-Object { - $GUID = $_.RowKey - $data = $_.JSON | ConvertFrom-Json - $data | Add-Member -NotePropertyName "GUID" -NotePropertyValue $GUID - $data -} - -if ($Request.query.ID) { $Templates = $Templates | Where-Object -Property RowKey -EQ $Request.query.id } - - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @($Templates) - }) diff --git a/ListSpamfilter/function.json b/ListSpamfilter/function.json deleted file mode 100644 index bec6849b58ab..000000000000 --- a/ListSpamfilter/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/ListSpamfilter/run.ps1 b/ListSpamfilter/run.ps1 deleted file mode 100644 index 8e9e131dfe50..000000000000 --- a/ListSpamfilter/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" -$Tenantfilter = $request.Query.tenantfilter - -try { - $Policies = New-ExoRequest -tenantid $Tenantfilter -cmdlet "Get-HostedContentFilterPolicy" | Select-Object * -ExcludeProperty *odata*, *data.type* - $RuleState = New-ExoRequest -tenantid $Tenantfilter -cmdlet "Get-HostedContentFilterRule" | Select-Object * -ExcludeProperty *odata*, *data.type* - $GraphRequest = $Policies | Select-Object *, @{l = 'ruleState'; e = { $name = $_.name; ($RuleState | Where-Object name -EQ $name).State } }, @{l = 'rulePrio'; e = { $name = $_.name; ($RuleState | Where-Object name -EQ $name).Priority } } - $StatusCode = [HttpStatusCode]::OK -} -catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $StatusCode = [HttpStatusCode]::Forbidden - $GraphRequest = $ErrorMessage -} - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = @($GraphRequest) - }) diff --git a/ListStandards/function.json b/ListStandards/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListStandards/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/ListStandards/run.ps1 b/ListStandards/run.ps1 deleted file mode 100644 index 84cc3ea0acf4..000000000000 --- a/ListStandards/run.ps1 +++ /dev/null @@ -1,46 +0,0 @@ -using namespace System.Net - -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) -Set-Location (Get-Item $PSScriptRoot).Parent.FullName -$APIName = $TriggerMetadata.FunctionName -Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' -$Table = Get-CippTable -tablename 'standards' - -$Filter = "PartitionKey eq 'standards'" - -try { - if ($Request.query.TenantFilter) { - $tenants = (Get-CIPPAzDataTableEntity @Table -Filter $Filter).JSON | ConvertFrom-Json -Depth 15 -ErrorAction Stop | Where-Object Tenant -EQ $Request.query.tenantFilter - } - else { - $Tenants = (Get-CIPPAzDataTableEntity @Table -Filter $Filter).JSON | ConvertFrom-Json -Depth 15 -ErrorAction Stop - } -} -catch {} - -$CurrentStandards = foreach ($tenant in $tenants) { - [PSCustomObject]@{ - displayName = $tenant.tenant - appliedBy = $tenant.addedBy - appliedAt = $tenant.appliedAt - standards = $tenant.Standards - StandardsExport = ($tenant.Standards.psobject.properties.name) -join ', ' - } -} -if (!$CurrentStandards) { - $CurrentStandards = [PSCustomObject]@{ - displayName = 'No Standards applied' - appliedBy = $null - appliedAt = $null - standards = @{none = $null } - } -} - -$CurrentStandards = ConvertTo-Json -InputObject @($CurrentStandards) -Depth 15 -Compress - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $CurrentStandards - }) diff --git a/ListTeams/function.json b/ListTeams/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListTeams/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/ListTeams/run.ps1 b/ListTeams/run.ps1 deleted file mode 100644 index 2acf5160bdd5..000000000000 --- a/ListTeams/run.ps1 +++ /dev/null @@ -1,43 +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." - -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter -if ($request.query.type -eq "List") { - $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/groups?`$filter=resourceProvisioningOptions/Any(x:x eq 'Team')&`$select=id,displayname,description,visibility,mailNickname" -tenantid $TenantFilter -} -$TeamID = $request.query.ID -Write-Host $TeamID -if ($request.query.type -eq "Team") { - $Team = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/teams/$($TeamID)" -tenantid $TenantFilter -asapp $true - $Channels = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/teams/$($TeamID)/Channels" -tenantid $TenantFilter -asapp $true - $UserList = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/teams/$($TeamID)/Members" -tenantid $TenantFilter -asapp $true - $AppsList = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/teams/$($TeamID)/installedApps?`$expand=teamsAppDefinition" -tenantid $TenantFilter -asapp $true - - $Owners = $UserList | Where-Object -Property Roles -EQ "Owner" - $Members = $UserList | Where-Object -Property email -NotIn $owners.email - $GraphRequest = [PSCustomObject]@{ - Name = $team.DisplayName - TeamInfo = @($team) - ChannelInfo = @($channels) - Members = @($Members) - Owners = @($owners) - InstalledApps = @($AppsList) - } -} - - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @($GraphRequest) - }) \ No newline at end of file diff --git a/ListTeamsActivity/function.json b/ListTeamsActivity/function.json deleted file mode 100644 index c26ed09a89e4..000000000000 --- a/ListTeamsActivity/function.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "bindings": [ - { - "authLevel": "anonymous", - "type": "httpTrigger", - "direction": "in", - "name": "Request", - "methods": ["get", "post"] - }, - { - "type": "http", - "direction": "out", - "name": "Response" - } - ] -} diff --git a/ListTeamsActivity/run.ps1 b/ListTeamsActivity/run.ps1 deleted file mode 100644 index 88246bffcf8c..000000000000 --- a/ListTeamsActivity/run.ps1 +++ /dev/null @@ -1,23 +0,0 @@ -using namespace System.Net - -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) -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." - -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter -$type = $request.query.Type -$GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/reports/get$($type)Detail(period='D30')" -tenantid $TenantFilter | ConvertFrom-Csv | Select-Object @{ Name = 'UPN'; Expression = { $_.'User Principal Name' } }, -@{ Name = 'LastActive'; Expression = { $_.'Last Activity Date' } }, -@{ Name = 'TeamsChat'; Expression = { $_.'Team Chat Message Count' } }, -@{ Name = 'CallCount'; Expression = { $_.'Call Count' } }, -@{ Name = 'MeetingCount'; Expression = { $_.'Meeting Count' } } - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @($GraphRequest) - }) \ No newline at end of file diff --git a/ListTeamsVoice/function.json b/ListTeamsVoice/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListTeamsVoice/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/ListTeamsVoice/run.ps1 b/ListTeamsVoice/run.ps1 deleted file mode 100644 index 6b8dcdbda05e..000000000000 --- a/ListTeamsVoice/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." - -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter -$tenantid = (Get-Tenants | Where-Object -Property defaultDomainName -EQ $Request.Query.TenantFilter).customerId -try { - $users = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users?`$top=999&`$select=id,userPrincipalName,displayname" -tenantid $TenantFilter) - $GraphRequest = (New-TeamsAPIGetRequest -uri "https://api.interfaces.records.teams.microsoft.com/Skype.TelephoneNumberMgmt/Tenants/$($Tenantid)/telephone-numbers?locale=en-US" -tenantid $TenantFilter).TelephoneNumbers | ForEach-Object { - $CompleteRequest = $_ | Select-Object *, "AssignedTo" - $CompleteRequest.AcquisitionDate = $CompleteRequest.AcquisitionDate -split 'T' | Select-Object -First 1 - - if ($CompleteRequest.TargetId -eq "00000000-0000-0000-0000-000000000000") { - $CompleteRequest.AssignedTo = "Unassigned" - } - else { - $CompleteRequest.AssignedTo = ($users | Where-Object -Property Id -EQ $CompleteRequest.TargetId).userPrincipalName - - } - $CompleteRequest - } - $StatusCode = [HttpStatusCode]::OK -} -catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $StatusCode = [HttpStatusCode]::Forbidden - $GraphRequest = $ErrorMessage -} -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = @($GraphRequest) - }) diff --git a/ListTenantDetails/function.json b/ListTenantDetails/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListTenantDetails/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/ListTenantDetails/run.ps1 b/ListTenantDetails/run.ps1 deleted file mode 100644 index 765e899d48e0..000000000000 --- a/ListTenantDetails/run.ps1 +++ /dev/null @@ -1,43 +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' - -try { - $tenantfilter = $Request.Query.TenantFilter - $org = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/organization' -tenantid $tenantfilter | Select-Object displayName, city, country, countryLetterCode, street, state, postalCode, - @{ Name = 'businessPhones'; Expression = { $_.businessPhones -join ', ' } }, - @{ Name = 'technicalNotificationMails'; Expression = { $_.technicalNotificationMails -join ', ' } }, - tenantType, createdDateTime, onPremisesLastPasswordSyncDateTime, onPremisesLastSyncDateTime, onPremisesSyncEnabled, assignedPlans -} -catch { - $org = [PSCustomObject]@{ - displayName = 'Error loading tenant' - city = '' - country = '' - countryLetterCode = '' - street = '' - state = '' - postalCode = '' - businessPhones = '' - technicalNotificationMails = '' - createdDateTime = '' - onPremisesLastPasswordSyncDateTime = '' - onPremisesLastSyncDateTime = '' - onPremisesSyncEnabled = '' - assignedPlans = @() - } -} -finally { - $Body = $org -} - -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Body - }) - diff --git a/ListTenants/function.json b/ListTenants/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListTenants/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/ListTenants/run.ps1 b/ListTenants/run.ps1 deleted file mode 100644 index 13fc9bc5f736..000000000000 --- a/ListTenants/run.ps1 +++ /dev/null @@ -1,70 +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' - - -# Clear Cache -if ($request.Query.ClearCache -eq 'true') { - Remove-CIPPCache -tenantsOnly $request.query.TenantsOnly - $GraphRequest = [pscustomobject]@{'Results' = 'Successfully completed request.' } - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $GraphRequest - }) - exit -} - -try { - $tenantfilter = $Request.Query.TenantFilter - $Tenants = Get-Tenants -IncludeErrors - - if ($null -eq $TenantFilter -or $TenantFilter -eq 'null') { - $TenantList = [system.collections.generic.list[object]]::new() - if ($Request.Query.AllTenantSelector -eq $true) { - $TenantList.Add(@{ - customerId = 'AllTenants' - defaultDomainName = 'AllTenants' - displayName = '*All Tenants' - domains = 'AllTenants' - GraphErrorCount = 0 - }) | Out-Null - - if (($Tenants).length -gt 1) { - $TenantList.AddRange($Tenants) | Out-Null - } - elseif ($Tenants) { - $TenantList.Add($Tenants) | Out-Null - } - $body = $TenantList - } - else { - $Body = $Tenants - } - } - else { - $body = $Tenants | Where-Object -Property defaultDomainName -EQ $Tenantfilter - } - - Write-LogMessage -user $request.headers.'x-ms-client-principal' -tenant $Tenantfilter -API $APINAME -message 'Listed Tenant Details' -Sev 'Debug' -} -catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -tenant $Tenantfilter -API $APINAME -message "List Tenant failed. The error is: $($_.Exception.Message)" -Sev 'Error' - $body = [pscustomobject]@{ - 'Results' = "Failed to retrieve tenants: $($_.Exception.Message)" - defaultDomainName = '' - displayName = 'Failed to retrieve tenants. Perform a permission check.' - customerId = '' - - } -} - -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @($Body) - }) - diff --git a/ListTransportRules/function.json b/ListTransportRules/function.json deleted file mode 100644 index bec6849b58ab..000000000000 --- a/ListTransportRules/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/ListTransportRules/run.ps1 b/ListTransportRules/run.ps1 deleted file mode 100644 index 4bdbab41b2ca..000000000000 --- a/ListTransportRules/run.ps1 +++ /dev/null @@ -1,24 +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" -$Tenantfilter = $request.Query.tenantfilter - -try { - $GraphRequest = New-ExoRequest -tenantid $Tenantfilter -cmdlet "Get-TransportRule" - $StatusCode = [HttpStatusCode]::OK -} -catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $StatusCode = [HttpStatusCode]::Forbidden - $GraphRequest = $ErrorMessage -} - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = @($GraphRequest) - }) diff --git a/ListTransportRulesTemplates/function.json b/ListTransportRulesTemplates/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListTransportRulesTemplates/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/ListTransportRulesTemplates/run.ps1 b/ListTransportRulesTemplates/run.ps1 deleted file mode 100644 index 6e6b8f6d761f..000000000000 --- a/ListTransportRulesTemplates/run.ps1 +++ /dev/null @@ -1,39 +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" -$Table = Get-CippTable -tablename 'templates' - -$Templates = Get-ChildItem "Config\*.TransportRuleTemplate.json" | ForEach-Object { - - $Entity = @{ - JSON = "$(Get-Content $_)" - RowKey = "$($_.name)" - PartitionKey = "TransportTemplate" - GUID = "$($_.name)" - } - Add-CIPPAzDataTableEntity @Table -Entity $Entity -Force - -} - -#List new policies -$Table = Get-CippTable -tablename 'templates' -$Filter = "PartitionKey eq 'TransportTemplate'" -$Templates = (Get-CIPPAzDataTableEntity @Table -Filter $Filter) | ForEach-Object { - $GUID = $_.RowKey - $data = $_.JSON | ConvertFrom-Json - $data | Add-Member -NotePropertyName "GUID" -NotePropertyValue $GUID - $data -} - -if ($Request.query.ID) { $Templates = $Templates | Where-Object -Property RowKey -EQ $Request.query.id } - - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @($Templates) - }) diff --git a/ListUserConditionalAccessPolicies/function.json b/ListUserConditionalAccessPolicies/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListUserConditionalAccessPolicies/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/ListUserConditionalAccessPolicies/run.ps1 b/ListUserConditionalAccessPolicies/run.ps1 deleted file mode 100644 index d84419daff67..000000000000 --- a/ListUserConditionalAccessPolicies/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." - -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter -$UserID = $Request.Query.UserID - -try { - $json = '{"conditions":{"users":{"allUsers":2,"included":{"userIds":["' + $UserID + '"],"groupIds":[]},"excluded":{"userIds":[],"groupIds":[]}},"servicePrincipals":{"allServicePrincipals":1,"includeAllMicrosoftApps":false,"excludeAllMicrosoftApps":false,"userActions":[],"stepUpTags":[]},"conditions":{"minUserRisk":{"noRisk":false,"lowRisk":false,"mediumRisk":false,"highRisk":false,"applyCondition":false},"minSigninRisk":{"noRisk":false,"lowRisk":false,"mediumRisk":false,"highRisk":false,"applyCondition":false},"servicePrincipalRiskLevels":{"noRisk":false,"lowRisk":false,"mediumRisk":false,"highRisk":false,"applyCondition":false},"devicePlatforms":{"all":2,"included":{"android":false,"ios":false,"windowsPhone":false,"windows":false,"macOs":false,"linux":false},"excluded":null,"applyCondition":false},"locations":{"applyCondition":true,"includeLocationType":2,"excludeAllTrusted":false},"clientApps":{"applyCondition":false,"specificClientApps":false,"webBrowsers":false,"exchangeActiveSync":false,"onlyAllowSupportedPlatforms":false,"mobileDesktop":false},"clientAppsV2":{"applyCondition":false,"webBrowsers":false,"mobileDesktop":false,"modernAuth":false,"exchangeActiveSync":false,"onlyAllowSupportedPlatforms":false,"otherClients":false},"deviceState":{"includeDeviceStateType":1,"excludeDomainJoionedDevice":false,"excludeCompliantDevice":false,"applyCondition":true}}},"country":"","device":{}}' - $UserPolicies = (New-ClassicAPIPostRequest -uri "https://main.iam.ad.ext.azure.com/api/Policies/Evaluate?" -tenantid $tenantfilter -Method POST -body $json -resource '74658136-14ec-4630-ad9b-26e160ff0fc6' -verbose | Where-Object { $_.applied -eq $true }) - $ConditionalAccessPolicyOutput = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/identity/conditionalAccess/policies" -tenantid $tenantfilter -} -catch { - $ConditionalAccessPolicyOutput = @{} -} - -$GraphRequest = foreach ($cap in $ConditionalAccessPolicyOutput) { - if ($cap.id -in $UserPolicies.policyId) { - $temp = [PSCustomObject]@{ - id = $cap.id - displayName = $cap.displayName - } - $temp - } -} - -Write-Host $GraphRequest - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @($GraphRequest) - }) diff --git a/ListUserCounts/function.json b/ListUserCounts/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListUserCounts/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/ListUserCounts/run.ps1 b/ListUserCounts/run.ps1 deleted file mode 100644 index 419884710cdf..000000000000 --- a/ListUserCounts/run.ps1 +++ /dev/null @@ -1,38 +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.' - -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter -if ($Request.Query.TenantFilter -eq 'AllTenants') { - $users = 'Not Supported' - $LicUsers = 'Not Supported' - $GAs = 'Not Supported' - $Guests = 'Not Supported' -} else { - $Users = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users?`$count=true&`$top=1" -CountOnly -ComplexFilter -tenantid $TenantFilter - $LicUsers = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users?`$count=true&`$top=1&`$filter=assignedLicenses/`$count ne 0" -CountOnly -ComplexFilter -tenantid $TenantFilter - $GAs = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/directoryRoles/roleTemplateId=62e90394-69f5-4237-9190-012177145e10/members?`$count=true" -CountOnly -ComplexFilter -tenantid $TenantFilter - $guests = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users?`$count=true&`$top=1&`$filter=userType eq 'Guest'" -CountOnly -ComplexFilter -tenantid $TenantFilter -} -$StatusCode = [HttpStatusCode]::OK -$Counts = @{ - Users = $users - LicUsers = $LicUsers - Gas = $Gas - Guests = $guests -} - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = $Counts - }) diff --git a/ListUserDevices/function.json b/ListUserDevices/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListUserDevices/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/ListUserDevices/run.ps1 b/ListUserDevices/run.ps1 deleted file mode 100644 index c31bb6a92c6b..000000000000 --- a/ListUserDevices/run.ps1 +++ /dev/null @@ -1,56 +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." - -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter -$UserID = $Request.Query.UserID - -function Get-EPMID { - param( - $deviceID, - $EPMDevices - ) - try { - return ($EPMDevices | Where-Object { $_.azureADDeviceId -eq $deviceID }).id - } - catch { - return $null - } -} -try { - $EPMDevices = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$UserID/managedDevices" -Tenantid $tenantfilter - $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$UserID/ownedDevices?`$top=999" -Tenantid $tenantfilter | Select-Object @{ Name = 'ID'; Expression = { $_.'id' } }, - @{ Name = 'accountEnabled'; Expression = { $_.'accountEnabled' } }, - @{ Name = 'approximateLastSignInDateTime'; Expression = { $_.'approximateLastSignInDateTime' | Out-String } }, - @{ Name = 'createdDateTime'; Expression = { $_.'createdDateTime' | Out-String } }, - @{ Name = 'deviceOwnership'; Expression = { $_.'deviceOwnership' } }, - @{ Name = 'displayName'; Expression = { $_.'displayName' } }, - @{ Name = 'enrollmentType'; Expression = { $_.'enrollmentType' } }, - @{ Name = 'isCompliant'; Expression = { $_.'isCompliant' } }, - @{ Name = 'managementType'; Expression = { $_.'managementType' } }, - @{ Name = 'manufacturer'; Expression = { $_.'manufacturer' } }, - @{ Name = 'model'; Expression = { $_.'model' } }, - @{ Name = 'operatingSystem'; Expression = { $_.'operatingSystem' } }, - @{ Name = 'onPremisesSyncEnabled'; Expression = { $(if ([string]::IsNullOrEmpty($_.'onPremisesSyncEnabled')) { $false }else { $true }) } }, - @{ Name = 'operatingSystemVersion'; Expression = { $_.'operatingSystemVersion' } }, - @{ Name = 'trustType'; Expression = { $_.'trustType' } }, - @{ Name = 'EPMID'; Expression = { $(Get-EPMID -deviceID $_.'deviceId' -EPMDevices $EPMDevices) } } -} -catch { - $GraphRequest = @() -} - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @($GraphRequest) - }) diff --git a/ListUserGroups/function.json b/ListUserGroups/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListUserGroups/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/ListUserGroups/run.ps1 b/ListUserGroups/run.ps1 deleted file mode 100644 index 6a97be613f40..000000000000 --- a/ListUserGroups/run.ps1 +++ /dev/null @@ -1,34 +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." - -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter -$UserID = $Request.Query.UserID - - -$URI = "https://graph.microsoft.com/beta/users/$UserID/memberOf/$/microsoft.graph.group?`$select=id,displayName,mailEnabled,securityEnabled,groupTypes,onPremisesSyncEnabled,mail,isAssignableToRole`&$orderby=displayName asc" -Write-Host $URI -$GraphRequest = New-GraphGetRequest -uri $URI -tenantid $TenantFilter -noPagination $true -verbose | select-object id, -@{ Name = 'DisplayName'; Expression = { $_.displayName} }, -@{ Name = 'MailEnabled'; Expression = { $_.mailEnabled} }, -@{ Name = 'Mail'; Expression = { $_.mail} }, -@{ Name = 'SecurityGroup'; Expression = {$_.securityEnabled} }, -@{ Name = 'GroupTypes'; Expression = { $_.groupTypes -join ','} }, -@{ Name = 'OnPremisesSync'; Expression = { $_.onPremisesSyncEnabled} }, -@{ Name = 'IsAssignableToRole'; Expression = { $_.isAssignableToRole} } - - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @($GraphRequest) - }) \ No newline at end of file diff --git a/ListUserMailboxDetails/function.json b/ListUserMailboxDetails/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListUserMailboxDetails/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/ListUserMailboxDetails/run.ps1 b/ListUserMailboxDetails/run.ps1 deleted file mode 100644 index 90affe48fe95..000000000000 --- a/ListUserMailboxDetails/run.ps1 +++ /dev/null @@ -1,164 +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." - -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter -$UserID = $Request.Query.UserID - - -$TenantFilter = $Request.Query.TenantFilter -try { - $Bytes = [System.Text.Encoding]::UTF8.GetBytes($Request.Query.UserID) - $base64IdentityParam = [Convert]::ToBase64String($Bytes) - $CASRequest = New-GraphGetRequest -uri "https://outlook.office365.com/adminapi/beta/$($tenantfilter)/CasMailbox('$UserID')" -Tenantid $tenantfilter -scope ExchangeOnline -noPagination $true - $MailRequest = New-GraphGetRequest -uri "https://outlook.office365.com/adminapi/beta/$($tenantfilter)/Mailbox('$UserID')" -Tenantid $tenantfilter -scope ExchangeOnline -noPagination $true - $FetchParam = @{ - anr = $MailRequest.PrimarySmtpAddress - } - $MailboxDetailedRequest = New-ExoRequest -TenantID $TenantFilter -cmdlet 'Get-Mailbox' -cmdParams $FetchParam - try { - $Archive = New-ExoRequest -TenantID $TenantFilter -cmdlet 'Get-Mailbox' -cmdParams $FetchParam - if ($Archive.ArchiveStatus -eq "Active") { - $ArchiveEnabled = $True - } - else { - $ArchiveEnabled = $False - } - - $FetchParam = @{ - Identity = $MailRequest.PrimarySmtpAddress - Archive = $true - } - - $ArchiveSize = New-ExoRequest -TenantID $TenantFilter -cmdlet 'Get-MailboxStatistics' -cmdParams $FetchParam - } - catch { - $ArchiveEnabled = $False - $ArchiveSize = @{ - TotalItemSize = "0" - ItemCount = "0" - } - } - $FetchParam = @{ - SenderAddress = $MailRequest.PrimarySmtpAddress - } - $BlockedSender = New-ExoRequest -TenantID $TenantFilter -cmdlet 'Get-BlockedSenderAddress' -cmdParams $FetchParam - if ($BlockedSender) { - $BlockedForSpam = $True - } - else { - $BlockedForSpam = $False - } - $StatsRequest = New-GraphGetRequest -uri "https://outlook.office365.com/adminapi/beta/$($tenantfilter)/Mailbox('$($MailRequest.PrimarySmtpAddress)')/Exchange.GetMailboxStatistics()" -Tenantid $tenantfilter -scope ExchangeOnline -noPagination $true - $PermsRequest = New-GraphGetRequest -uri "https://outlook.office365.com/adminapi/beta/$($tenantfilter)/Mailbox('$($MailRequest.PrimarySmtpAddress)')/MailboxPermission" -Tenantid $tenantfilter -scope ExchangeOnline -noPagination $true - $PermsRequest2 = New-GraphGetRequest -uri "https://outlook.office365.com/adminapi/beta/$($tenantfilter)/Recipient('$base64IdentityParam')?`$expand=RecipientPermission&isEncoded=true" -Tenantid $tenantfilter -scope ExchangeOnline - -} -catch { - Write-Error "Failed Fetching Data $($_.Exception.message): $($_.InvocationInfo.ScriptLineNumber)" -} - -$ParsedPerms = foreach ($Perm in $PermsRequest, $PermsRequest2.RecipientPermission) { - - if ($perm.Trustee) { - $perm | Where-Object Trustee | ForEach-Object { [PSCustomObject]@{ - User = $_.Trustee - AccessRights = $_.accessRights -join ', ' - } - } - - } - if ($perm.PermissionList) { - $perm | Where-Object User | ForEach-Object { [PSCustomObject]@{ - User = $_.User - AccessRights = $_.PermissionList.accessRights -join ', ' - } - } - } -} - -$forwardingaddress = if ($MailboxDetailedRequest.ForwardingAddress) { - $MailboxDetailedRequest.ForwardingAddress -} -elseif ($MailboxDetailedRequest.ForwardingSmtpAddress -and $MailboxDetailedRequest.ForwardingAddress) { - $MailboxDetailedRequest.ForwardingAddress + ' ' + $MailboxDetailedRequest.ForwardingSmtpAddress -} -else { - $MailboxDetailedRequest.ForwardingSmtpAddress -} - -if ($ArchiveSize) { - $GraphRequest = [ordered]@{ - ForwardAndDeliver = $MailboxDetailedRequest.DeliverToMailboxAndForward - ForwardingAddress = $ForwardingAddress - LitiationHold = $MailboxDetailedRequest.LitigationHoldEnabled - HiddenFromAddressLists = $MailboxDetailedRequest.HiddenFromAddressListsEnabled - EWSEnabled = $CASRequest.EwsEnabled - MailboxMAPIEnabled = $CASRequest.MAPIEnabled - MailboxOWAEnabled = $CASRequest.OWAEnabled - MailboxImapEnabled = $CASRequest.ImapEnabled - MailboxPopEnabled = $CASRequest.PopEnabled - MailboxActiveSyncEnabled = $CASRequest.ActiveSyncEnabled - Permissions = $ParsedPerms - ProhibitSendQuota = [math]::Round([float]($MailboxDetailedRequest.ProhibitSendQuota -split ' GB')[0], 2) - ProhibitSendReceiveQuota = [math]::Round([float]($MailboxDetailedRequest.ProhibitSendReceiveQuota -split ' GB')[0], 2) - ItemCount = [math]::Round($StatsRequest.ItemCount, 2) - TotalItemSize = [math]::Round($StatsRequest.TotalItemSize / 1Gb, 2) - TotalArchiveItemSize = $ArchiveSize.totalItemSize.split('(')[0] - TotalArchiveItemCount = [math]::Round($ArchiveSize.ItemCount, 2) - BlockedForSpam = $BlockedForSpam - ArchiveMailBox = $ArchiveEnabled - AutoExpandingArchive = $Archive.AutoExpandingArchiveEnabled - RecipientTypeDetails = $MailboxDetailedRequest.RecipientTypeDetails - } -} -else { - $GraphRequest = [ordered]@{ - ForwardAndDeliver = $MailboxDetailedRequest.DeliverToMailboxAndForward - ForwardingAddress = $ForwardingAddress - LitiationHold = $MailboxDetailedRequest.LitigationHoldEnabled - HiddenFromAddressLists = $MailboxDetailedRequest.HiddenFromAddressListsEnabled - EWSEnabled = $CASRequest.EwsEnabled - MailboxMAPIEnabled = $CASRequest.MAPIEnabled - MailboxOWAEnabled = $CASRequest.OWAEnabled - MailboxImapEnabled = $CASRequest.ImapEnabled - MailboxPopEnabled = $CASRequest.PopEnabled - MailboxActiveSyncEnabled = $CASRequest.ActiveSyncEnabled - Permissions = $ParsedPerms - ProhibitSendQuota = [math]::Round([float]($MailboxDetailedRequest.ProhibitSendQuota -split ' GB')[0], 2) - ProhibitSendReceiveQuota = [math]::Round([float]($MailboxDetailedRequest.ProhibitSendReceiveQuota -split ' GB')[0], 2) - ItemCount = [math]::Round($StatsRequest.ItemCount, 2) - TotalItemSize = [math]::Round($StatsRequest.TotalItemSize / 1Gb, 2) - TotalArchiveItemSize = 0 - TotalArchiveItemCount = 0 - BlockedForSpam = $BlockedForSpam - ArchiveMailBox = $ArchiveEnabled - AutoExpandingArchive = $Archive.AutoExpandingArchiveEnabled - RecipientTypeDetails = $MailboxDetailedRequest.RecipientTypeDetails - } -} - - -#$GraphRequest = [ordered]@{ -# Connectivity = $CASRequest -# Mailbox = $MailRequest -# MailboxDetail = $MailboxDetailedRequest -# Stats = $StatsRequest -# Permissions = $ParsedPerms -# Result = $Result -#} - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @($GraphRequest) - }) \ No newline at end of file diff --git a/ListUserMailboxRules/function.json b/ListUserMailboxRules/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListUserMailboxRules/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/ListUserMailboxRules/run.ps1 b/ListUserMailboxRules/run.ps1 deleted file mode 100644 index 37e218452d9b..000000000000 --- a/ListUserMailboxRules/run.ps1 +++ /dev/null @@ -1,39 +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." - -# Interact with query parameters or the body of the request. -try { -$TenantFilter = $Request.Query.TenantFilter -$UserID = $Request.Query.UserID - $GraphRequest = New-ExoRequest -tenantid $TenantFilter -cmdlet "Get-InboxRule" -cmdParams @{mailbox = $UserID} | Select-Object - @{ Name = 'DisplayName'; Expression = { $_.displayName} }, - @{ Name = 'Description'; Expression = { $_.Description} }, - @{ Name = 'Redirect To'; Expression = { $_.RedirectTo} }, - @{ Name = 'Copy To Folder'; Expression = { $_.CopyToFolder} }, - @{ Name = 'Move To Folder'; Expression = { $_.MoveToFolder} }, - @{ Name = 'Soft Delete Message'; Expression = { $_.SoftDeleteMessage} }, - @{ Name = 'Delete Message'; Expression = { $_.DeleteMessage} } -} - catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to retrieve mailbox rules $($request.query.id): $($_.Exception.message) " -Sev 'Error' -tenant $TenantFilter - # Associate values to output bindings by calling 'Push-OutputBinding'. - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = '500' - Body = $(Get-NormalizedError -message $_.Exception.message) - }) - } - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @($GraphRequest) -}) \ No newline at end of file diff --git a/ListUserPhoto/function.json b/ListUserPhoto/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListUserPhoto/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/ListUserPhoto/run.ps1 b/ListUserPhoto/run.ps1 deleted file mode 100644 index e142f8382913..000000000000 --- a/ListUserPhoto/run.ps1 +++ /dev/null @@ -1,27 +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." - -# Interact with query parameters or the body of the request. -$tenantFilter = $Request.Query.TenantFilter -$userId = $Request.Query.UserID - - -$URI = "https://graph.microsoft.com/v1.0/users/$userId/photos/240x240/`$value" -Write-Host $URI -$graphRequest = New-GraphGetRequest -uri $URI -tenantid $tenantFilter - - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @($graphRequest) - }) \ No newline at end of file diff --git a/ListUserSettings/function.json b/ListUserSettings/function.json deleted file mode 100644 index bf6c3ef0c49a..000000000000 --- a/ListUserSettings/function.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "scriptFile": "../Modules/CippEntryPoints/CippEntryPoints.psm1", - "entryPoint": "Receive-CippHttpTrigger", - "bindings": [ - { - "authLevel": "anonymous", - "type": "httpTrigger", - "direction": "in", - "name": "Request", - "methods": ["get", "post"] - }, - { - "type": "http", - "direction": "out", - "name": "Response" - } - ] -} diff --git a/ListUserSigninLogs/function.json b/ListUserSigninLogs/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListUserSigninLogs/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/ListUserSigninLogs/run.ps1 b/ListUserSigninLogs/run.ps1 deleted file mode 100644 index fa8f7edb1fce..000000000000 --- a/ListUserSigninLogs/run.ps1 +++ /dev/null @@ -1,51 +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." - -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter -$UserID = $Request.Query.UserID -try { - $URI = "https://graph.microsoft.com/beta/auditLogs/signIns?`$filter=(userId eq '$UserID')&`$top=50&`$orderby=createdDateTime desc" - Write-Host $URI - $GraphRequest = New-GraphGetRequest -uri $URI -tenantid $TenantFilter -noPagination $true -verbose | Select-Object @{ Name = 'Date'; Expression = { $(($_.createdDateTime | Out-String) -replace '\r\n') } }, - id, - @{ Name = 'Application'; Expression = { $_.resourceDisplayName } }, - @{ Name = 'LoginStatus'; Expression = { $_.status.errorCode } }, - @{ Name = 'ConditionalAccessStatus'; Expression = { $_.conditionalAccessStatus } }, - @{ Name = 'OverallLoginStatus'; Expression = { if (($_.conditionalAccessStatus -eq 'Success' -or 'Not Applied') -and $_.status.errorCode -eq 0) { 'Success' } else { 'Failed' } } }, - @{ Name = 'IPAddress'; Expression = { $_.ipAddress } }, - @{ Name = 'Town'; Expression = { $_.location.city } }, - @{ Name = 'State'; Expression = { $_.location.state } }, - @{ Name = 'Country'; Expression = { $_.location.countryOrRegion } }, - @{ Name = 'Device'; Expression = { $_.deviceDetail.displayName } }, - @{ Name = 'DeviceCompliant'; Expression = { $_.deviceDetail.isCompliant } }, - @{ Name = 'OS'; Expression = { $_.deviceDetail.operatingSystem } }, - @{ Name = 'Browser'; Expression = { $_.deviceDetail.browser } }, - @{ Name = 'AppliedCAPs'; Expression = { ($_.appliedConditionalAccessPolicies | ForEach-Object { @{Result = $_.result; Name = $_.displayName } }) } }, - @{ Name = 'AdditionalDetails'; Expression = { $_.status.additionalDetails } }, - @{ Name = 'FailureReason'; Expression = { $_.status.failureReason } }, - @{ Name = 'FullDetails'; Expression = { $_ } } - # Associate values to output bindings by calling 'Push-OutputBinding'. - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @($GraphRequest) - }) -} -catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to retrieve Sign In report: $($_.Exception.message) " -Sev 'Error' -tenant $TenantFilter - # Associate values to output bindings by calling 'Push-OutputBinding'. - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = '500' - Body = $(Get-NormalizedError -message $_.Exception.message) - }) -} - diff --git a/ListUsers/function.json b/ListUsers/function.json deleted file mode 100644 index 3d31416065c2..000000000000 --- a/ListUsers/function.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "bindings": [ - { - "authLevel": "anonymous", - "type": "httpTrigger", - "direction": "in", - "name": "Request", - "methods": ["get", "post"] - }, - { - "type": "http", - "direction": "out", - "name": "Response" - }, - { - "type": "queue", - "direction": "out", - "name": "Msg", - "queueName": "generalAllTenantQueue" - } - ] -} diff --git a/ListUsers/run.ps1 b/ListUsers/run.ps1 deleted file mode 100644 index 4c50e052e256..000000000000 --- a/ListUsers/run.ps1 +++ /dev/null @@ -1,83 +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' - -$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' -# 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 -Set-Location (Get-Item $PSScriptRoot).Parent.FullName -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter -$GraphFilter = $Request.Query.graphFilter -$userid = $Request.Query.UserID - -$GraphRequest = if ($TenantFilter -ne 'AllTenants') { - New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($userid)?`$top=999&`$select=$($selectlist -join ',')&`$filter=$GraphFilter&`$count=true" -tenantid $TenantFilter -ComplexFilter | Select-Object $selectlist | ForEach-Object { - $_.onPremisesSyncEnabled = [bool]($_.onPremisesSyncEnabled) - $_.Aliases = $_.Proxyaddresses -join ', ' - $SkuID = $_.AssignedLicenses.skuid - $_.LicJoined = ($ConvertTable | Where-Object { $_.guid -in $skuid }).'Product_Display_Name' -join ', ' - $_.primDomain = ($_.userPrincipalName -split '@' | Select-Object -Last 1) - $_ - } -} -else { - $Table = Get-CIPPTable -TableName 'cacheusers' - $Rows = Get-CIPPAzDataTableEntity @Table | Where-Object -Property Timestamp -GT (Get-Date).AddHours(-1) - if (!$Rows) { - $Queue = New-CippQueueEntry -Name 'Users' -Link '/identity/administration/users?customerId=AllTenants' - Push-OutputBinding -Name Msg -Value "users/$($userid)?`$top=999&`$select=$($selectlist -join ',')&`$filter=$GraphFilter&`$count=true" - [PSCustomObject]@{ - Tenant = 'Loading data for all tenants. Please check back after the job completes' - QueueId = $Queue.RowKey - } - } - else { - $Rows.Data | ConvertFrom-Json | Select-Object $selectlist | ForEach-Object { - $_.onPremisesSyncEnabled = [bool]($_.onPremisesSyncEnabled) - $_.Aliases = $_.Proxyaddresses -join ', ' - $SkuID = $_.AssignedLicenses.skuid - $_.LicJoined = ($ConvertTable | Where-Object { $_.guid -in $skuid }).'Product_Display_Name' -join ', ' - $_.primDomain = ($_.userPrincipalName -split '@' | Select-Object -Last 1) - $_ - } - } -} - - -if ($userid -and $Request.query.IncludeLogonDetails) { - $startDate = (Get-Date).AddDays(-7) - $endDate = (Get-Date) - $sessionid = Get-Random -Maximum 1000 -Minimum 1 - $SearchParam = @{ - SessionCommand = 'ReturnLargeSet' - Operations = @('UserLoggedIn', 'UserLoginFailed', 'TeamsSessionStarted', 'MailboxLogin') - sessionid = $sessionid - startDate = $startDate - endDate = $endDate - UserIds = @($GraphRequest.userPrincipalName) - } - $AuditlogsLogon = (New-ExoRequest -tenantid $Tenantfilter -cmdlet 'Search-unifiedAuditLog' -cmdParams $SearchParam | Sort-Object -Property CreationDate | Select-Object -Last 1).auditdata | ConvertFrom-Json - $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 $AuditlogsLogon.applicationId - $LastSignIn = [PSCustomObject]@{ - AppDisplayName = if ($AppName) { $AppName.'Application Name' } else { "$($AuditlogsLogon.Workload) - $($AuditlogsLogon.ApplicationId) " } - CreatedDateTime = $AuditlogsLogon.CreationTime - Id = $AuditlogsLogon.errorNumber - Status = $AuditlogsLogon.ResultStatus - } - $GraphRequest = $GraphRequest | Select-Object *, - @{ Name = 'LastSigninApplication'; Expression = { $LastSignIn.AppDisplayName } }, - @{ Name = 'LastSigninDate'; Expression = { $($LastSignIn.CreatedDateTime | Out-String) } }, - @{ Name = 'LastSigninStatus'; Expression = { $AuditlogsLogon.operation } }, - @{ Name = 'LastSigninResult'; Expression = { $LastSignIn.status } }, - @{ Name = 'LastSigninFailureReason'; Expression = { if ($LastSignIn.Id -eq 0) { 'Sucessfully signed in' } else { $LastSignIn.Id } } } -} -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @($GraphRequest) - }) \ No newline at end of file diff --git a/ListWebhookAlert/function.json b/ListWebhookAlert/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListWebhookAlert/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/ListWebhookAlert/run.ps1 b/ListWebhookAlert/run.ps1 deleted file mode 100644 index add6382e248a..000000000000 --- a/ListWebhookAlert/run.ps1 +++ /dev/null @@ -1,16 +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" -$WebhookTable = Get-CIPPTable -TableName webhookTable -$WebhookRow = Get-CIPPAzDataTableEntity @WebhookTable - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @($WebhookRow) - }) - diff --git a/ListmailboxPermissions/function.json b/ListmailboxPermissions/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/ListmailboxPermissions/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/ListmailboxPermissions/run.ps1 b/ListmailboxPermissions/run.ps1 deleted file mode 100644 index 571485b8f123..000000000000 --- a/ListmailboxPermissions/run.ps1 +++ /dev/null @@ -1,62 +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." - -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter - -Write-Host "Tenant Filter: $TenantFilter" -try { - $Bytes = [System.Text.Encoding]::UTF8.GetBytes($Request.Query.UserID) - $base64IdentityParam = [Convert]::ToBase64String($Bytes) - $PermsRequest = New-GraphGetRequest -uri "https://outlook.office365.com/adminapi/beta/$($tenantfilter)/Mailbox('$($Request.Query.UserID)')/MailboxPermission" -Tenantid $tenantfilter -scope ExchangeOnline - $PermsRequest2 = New-GraphGetRequest -uri "https://outlook.office365.com/adminapi/beta/$($tenantfilter)/Recipient('$base64IdentityParam')?`$expand=RecipientPermission&isEncoded=true" -Tenantid $tenantfilter -scope ExchangeOnline - $PermRequest3 = New-ExoRequest -Anchor $Request.Query.UserID -tenantid $Tenantfilter -cmdlet "Get-Mailbox" -cmdParams @{Identity = $($Request.Query.UserID); } - - $GraphRequest = foreach ($Perm in $PermsRequest, $PermsRequest2.RecipientPermission, $PermRequest3) { - - if ($perm.Trustee) { - $perm | Where-Object Trustee | ForEach-Object { [PSCustomObject]@{ - User = $_.Trustee - Permissions = $_.accessRights - } - } - - } - if ($perm.PermissionList) { - $perm | Where-Object User | ForEach-Object { [PSCustomObject]@{ - User = $_.User - Permissions = $_.PermissionList.accessRights -join ', ' - } - } - } - if ($perm.GrantSendonBehalfTo -ne $null) { - $perm.GrantSendonBehalfTo | ForEach-Object { [PSCustomObject]@{ - User = $_ - Permissions = "SendOnBehalf" - } - } - } - } - $StatusCode = [HttpStatusCode]::OK -} -catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $StatusCode = [HttpStatusCode]::Forbidden - $GraphRequest = $ErrorMessage -} -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = @($GraphRequest) - }) - - diff --git a/AddAPDevice/run.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddAPDevice.ps1 similarity index 91% rename from AddAPDevice/run.ps1 rename to Modules/CIPPCore/Public/Entrypoints/Invoke-AddAPDevice.ps1 index 7f689191c4c5..be59d3c44b89 100644 --- a/AddAPDevice/run.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddAPDevice.ps1 @@ -1,9 +1,14 @@ -using namespace System.Net + using namespace System.Net -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) + Function Invoke-AddAPDevice { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) -$APIName = $TriggerMetadata.FunctionName + $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Accessed this API" -Sev "Debug" @@ -40,4 +45,6 @@ Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK Body = $body - }) \ No newline at end of file + }) + + } diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-AddAlert.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddAlert.ps1 new file mode 100644 index 000000000000..25740fc87531 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddAlert.ps1 @@ -0,0 +1,97 @@ +using namespace System.Net + +Function Invoke-AddAlert { + <# + .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' + + $Tenants = ($Request.body | Select-Object Select_*).psobject.properties.value + $Results = foreach ($Tenant in $tenants) { + try { + $TenantID = if ($tenant -ne 'AllTenants') { + (get-tenants | Where-Object -Property defaultDomainName -EQ $Tenant).customerId + } else { + 'AllTenants' + } + if ($Request.body.SetAlerts) { + $CompleteObject = @{ + tenant = $tenant + tenantid = $TenantID + AdminPassword = [bool]$Request.body.AdminPassword + DefenderMalware = [bool]$Request.body.DefenderMalware + DefenderStatus = [bool]$Request.body.DefenderStatus + MFAAdmins = [bool]$Request.body.MFAAdmins + MFAAlertUsers = [bool]$Request.body.MFAAlertUsers + NewGA = [bool]$Request.body.NewGA + NewRole = [bool]$Request.body.NewRole + QuotaUsed = [bool]$Request.body.QuotaUsed + UnusedLicenses = [bool]$Request.body.UnusedLicenses + OverusedLicenses = [bool]$Request.body.OverusedLicenses + AppSecretExpiry = [bool]$Request.body.AppSecretExpiry + ApnCertExpiry = [bool]$Request.body.ApnCertExpiry + VppTokenExpiry = [bool]$Request.body.VppTokenExpiry + DepTokenExpiry = [bool]$Request.body.DepTokenExpiry + NoCAConfig = [bool]$Request.body.NoCAConfig + SecDefaultsUpsell = [bool]$Request.body.SecDefaultsUpsell + SharePointQuota = [bool]$Request.body.SharePointQuota + ExpiringLicenses = [bool]$Request.body.ExpiringLicenses + type = 'Alert' + RowKey = $TenantID + PartitionKey = 'Alert' + } + + $Table = get-cipptable -TableName 'SchedulerConfig' + Add-CIPPAzDataTableEntity @Table -Entity $CompleteObject -Force + } + $URL = ($request.headers.'x-ms-original-url').split('/api') | Select-Object -First 1 + if ($Tenant -eq 'AllTenants') { + Get-Tenants | ForEach-Object { + foreach ($eventType in $Request.body.EventTypes.value) { + $params = @{ + TenantFilter = $_.defaultDomainName + auditLogAPI = $true + operations = ($Request.body.Operations.value -join ',') + allowedLocations = ($Request.body.AllowedLocations.value -join ',') + BaseURL = $URL + EventType = $eventType + ExecutingUser = $Request.headers.'x-ms-client-principal' + } + Push-OutputBinding -Name Subscription -Value $Params + } + } + } else { + foreach ($eventType in $Request.body.EventTypes.value) { + $params = @{ + TenantFilter = $tenant + auditLogAPI = $true + operations = ($Request.body.Operations.value -join ',') + allowedLocations = ($Request.body.AllowedLocations.value -join ',') + BaseURL = $URL + EventType = $eventType + ExecutingUser = $Request.headers.'x-ms-client-principal' + } + New-CIPPGraphSubscription @params + } + } + "Successfully added Alert for $($Tenant) to queue." + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $tenant -message "Successfully added Alert for $($Tenant) to queue." -Sev 'Info' + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $tenant -message "Failed to add Alert for for $($Tenant) to queue" -Sev 'Error' + "Failed to add Alert for for $($Tenant) to queue $($_.Exception.message)" + } + } + + $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/AddAutopilotConfig/run.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddAutopilotConfig.ps1 similarity index 94% rename from AddAutopilotConfig/run.ps1 rename to Modules/CIPPCore/Public/Entrypoints/Invoke-AddAutopilotConfig.ps1 index 4711ab7997d4..f850042fc7d2 100644 --- a/AddAutopilotConfig/run.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddAutopilotConfig.ps1 @@ -1,9 +1,14 @@ -using namespace System.Net + using namespace System.Net -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) + Function Invoke-AddAutopilotConfig { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) -$APIName = $TriggerMetadata.FunctionName + $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Accessed this API" -Sev "Debug" @@ -68,3 +73,5 @@ Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ }) + + } diff --git a/AddCAPolicy/run.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddCAPolicy.ps1 similarity index 85% rename from AddCAPolicy/run.ps1 rename to Modules/CIPPCore/Public/Entrypoints/Invoke-AddCAPolicy.ps1 index ae7ec4a3584d..ab0fcfffb7d3 100644 --- a/AddCAPolicy/run.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddCAPolicy.ps1 @@ -1,9 +1,14 @@ -using namespace System.Net + using namespace System.Net -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) + Function Invoke-AddCAPolicy { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) -$APIName = $TriggerMetadata.FunctionName + $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Accessed this API" -Sev "Debug" $Tenants = ($Request.body | Select-Object Select_*).psobject.properties.value @@ -30,3 +35,5 @@ Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK Body = $body }) + + } diff --git a/AddCATemplate/run.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddCATemplate.ps1 similarity index 93% rename from AddCATemplate/run.ps1 rename to Modules/CIPPCore/Public/Entrypoints/Invoke-AddCATemplate.ps1 index f5d1010676d5..9fcd305891ba 100644 --- a/AddCATemplate/run.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddCATemplate.ps1 @@ -1,9 +1,14 @@ -using namespace System.Net + using namespace System.Net -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) + Function Invoke-AddCATemplate { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) -$APIName = $TriggerMetadata.FunctionName + $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Accessed this API" -Sev "Debug" $TenantFilter = $Request.Query.TenantFilter @@ -63,3 +68,5 @@ Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK Body = $body }) + + } diff --git a/AddChocoApp/run.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddChocoApp.ps1 similarity index 92% rename from AddChocoApp/run.ps1 rename to Modules/CIPPCore/Public/Entrypoints/Invoke-AddChocoApp.ps1 index 13fced9492e5..033f7a909a6a 100644 --- a/AddChocoApp/run.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddChocoApp.ps1 @@ -1,11 +1,15 @@ -using namespace System.Net + using namespace System.Net -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) + Function Invoke-AddChocoApp { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) -$APIName = $TriggerMetadata.FunctionName + $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Accessed this API" -Sev "Debug" -Set-Location (Get-Item $PSScriptRoot).Parent.FullName Write-Host "PowerShell HTTP trigger function processed a request." $ChocoApp = $request.body @@ -56,3 +60,5 @@ Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK Body = $body }) + + } diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-AddChocoApp_OrchestrationStarter.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddChocoApp_OrchestrationStarter.ps1 new file mode 100644 index 000000000000..fbbcb29a1dce --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddChocoApp_OrchestrationStarter.ps1 @@ -0,0 +1,26 @@ +using namespace System.Net + +Function Invoke-AddChocoApp_OrchestrationStarter { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + Write-LogMessage -API 'ChocoApps' -message 'Attempted to start upload but an instance was already running.' -sev Info + $InstanceId = Start-NewOrchestration -FunctionName 'Applications_Orchestrator' + Write-Host "Started orchestration with ID = '$InstanceId'" + $Orchestrator = New-OrchestrationCheckStatusResponse -Request $Request -InstanceId $InstanceId + Write-LogMessage -API 'ChocoApps' -message 'Started uploading applications to tenants' -sev Info + $Results = [pscustomobject]@{'Results' = 'Started application queue' } + + Write-Host ($Orchestrator | ConvertTo-Json) + + + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $results + }) + +} \ No newline at end of file diff --git a/AddContact/run.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddContact.ps1 similarity index 88% rename from AddContact/run.ps1 rename to Modules/CIPPCore/Public/Entrypoints/Invoke-AddContact.ps1 index abc29a96ab10..1c4f2963635d 100644 --- a/AddContact/run.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddContact.ps1 @@ -1,9 +1,14 @@ -using namespace System.Net + using namespace System.Net -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) + Function Invoke-AddContact { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) -$APIName = $TriggerMetadata.FunctionName + $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Accessed this API" -Sev "Debug" $contactobj = $Request.body @@ -39,3 +44,5 @@ Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK Body = $Body }) + + } diff --git a/AddDefenderDeployment/run.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddDefenderDeployment.ps1 similarity index 99% rename from AddDefenderDeployment/run.ps1 rename to Modules/CIPPCore/Public/Entrypoints/Invoke-AddDefenderDeployment.ps1 index de00187282f9..8d2fcc9113b3 100644 --- a/AddDefenderDeployment/run.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddDefenderDeployment.ps1 @@ -1,9 +1,14 @@ -using namespace System.Net + using namespace System.Net -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) + Function Invoke-AddDefenderDeployment { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) -$APIName = $TriggerMetadata.FunctionName + $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Accessed this API" -Sev "Debug" $Tenants = ($Request.body.selectedTenants).defaultDomainName @@ -235,3 +240,5 @@ Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK Body = $body }) + + } diff --git a/AddEnrollment/run.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddEnrollment.ps1 similarity index 93% rename from AddEnrollment/run.ps1 rename to Modules/CIPPCore/Public/Entrypoints/Invoke-AddEnrollment.ps1 index e894e094a6f7..512c7ac30956 100644 --- a/AddEnrollment/run.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddEnrollment.ps1 @@ -1,9 +1,14 @@ -using namespace System.Net + using namespace System.Net -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) + Function Invoke-AddEnrollment { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) -$APIName = $TriggerMetadata.FunctionName + $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Accessed this API" -Sev "Debug" @@ -55,3 +60,5 @@ Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK Body = $body }) + + } diff --git a/AddExConnector/run.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddExConnector.ps1 similarity index 83% rename from AddExConnector/run.ps1 rename to Modules/CIPPCore/Public/Entrypoints/Invoke-AddExConnector.ps1 index 2b6170111c12..fb4e739bfed4 100644 --- a/AddExConnector/run.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddExConnector.ps1 @@ -1,9 +1,14 @@ -using namespace System.Net + using namespace System.Net -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) + Function Invoke-AddExConnector { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) -$APIName = $TriggerMetadata.FunctionName + $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Accessed this API" -Sev "Debug" $ConnectorType = ($Request.body.PowerShellCommand | ConvertFrom-Json).cippConnectorType $RequestParams = $Request.Body.PowerShellCommand | ConvertFrom-Json | Select-Object -Property * -ExcludeProperty GUID, cippConnectorType, comments @@ -26,3 +31,5 @@ Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK Body = @{Results = @($Result) } }) + + } diff --git a/AddExConnectorTemplate/run.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddExConnectorTemplate.ps1 similarity index 91% rename from AddExConnectorTemplate/run.ps1 rename to Modules/CIPPCore/Public/Entrypoints/Invoke-AddExConnectorTemplate.ps1 index 6f00ce655732..099d51c2a7c0 100644 --- a/AddExConnectorTemplate/run.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddExConnectorTemplate.ps1 @@ -1,9 +1,14 @@ -using namespace System.Net + using namespace System.Net -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) + Function Invoke-AddExConnectorTemplate { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) -$APIName = $TriggerMetadata.FunctionName + $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Accessed this API" -Sev "Debug" Write-Host ($request | ConvertTo-Json -Compress) @@ -47,3 +52,5 @@ Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK Body = $body }) + + } diff --git a/AddGroup/run.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddGroup.ps1 similarity index 94% rename from AddGroup/run.ps1 rename to Modules/CIPPCore/Public/Entrypoints/Invoke-AddGroup.ps1 index 88e9d50debda..b52d4091b595 100644 --- a/AddGroup/run.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddGroup.ps1 @@ -1,9 +1,14 @@ -using namespace System.Net + using namespace System.Net -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) + Function Invoke-AddGroup { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) -$APIName = $TriggerMetadata.FunctionName + $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Accessed this API" -Sev "Debug" $groupobj = $Request.body @@ -65,4 +70,6 @@ $body = [pscustomobject]@{"Results" = @($results) } Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK Body = $Body - }) \ No newline at end of file + }) + + } diff --git a/AddGroupTemplate/run.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddGroupTemplate.ps1 similarity index 87% rename from AddGroupTemplate/run.ps1 rename to Modules/CIPPCore/Public/Entrypoints/Invoke-AddGroupTemplate.ps1 index bf53245a4d57..19ec092ca49b 100644 --- a/AddGroupTemplate/run.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddGroupTemplate.ps1 @@ -1,9 +1,14 @@ -using namespace System.Net + using namespace System.Net -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) + Function Invoke-AddGroupTemplate { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) -$APIName = $TriggerMetadata.FunctionName + $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Accessed this API" -Sev "Debug" $GUID = (New-Guid).GUID @@ -41,3 +46,5 @@ Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK Body = $body }) + + } diff --git a/AddGuest/run.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddGuest.ps1 similarity index 91% rename from AddGuest/run.ps1 rename to Modules/CIPPCore/Public/Entrypoints/Invoke-AddGuest.ps1 index 9e340718d370..4c94ec4740f9 100644 --- a/AddGuest/run.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddGuest.ps1 @@ -1,9 +1,14 @@ -using namespace System.Net + using namespace System.Net -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) + Function Invoke-AddGuest { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) -$APIName = $TriggerMetadata.FunctionName + $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Accessed this API" -Sev "Debug" $Results = [System.Collections.ArrayList]@() $userobj = $Request.body @@ -47,3 +52,5 @@ Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK Body = $Body }) + + } diff --git a/AddIntuneTemplate/run.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddIntuneTemplate.ps1 similarity index 96% rename from AddIntuneTemplate/run.ps1 rename to Modules/CIPPCore/Public/Entrypoints/Invoke-AddIntuneTemplate.ps1 index 1d5810379230..281c482d4d42 100644 --- a/AddIntuneTemplate/run.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddIntuneTemplate.ps1 @@ -1,9 +1,14 @@ -using namespace System.Net + using namespace System.Net -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) + Function Invoke-AddIntuneTemplate { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) -$APIName = $TriggerMetadata.FunctionName + $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Accessed this API" -Sev "Debug" $GUID = (New-Guid).GUID @@ -120,3 +125,5 @@ Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK Body = $body }) + + } diff --git a/AddMSPApp/run.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddMSPApp.ps1 similarity index 95% rename from AddMSPApp/run.ps1 rename to Modules/CIPPCore/Public/Entrypoints/Invoke-AddMSPApp.ps1 index 133a12ed7974..85c883333511 100644 --- a/AddMSPApp/run.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddMSPApp.ps1 @@ -1,11 +1,15 @@ -using namespace System.Net + using namespace System.Net -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) + Function Invoke-AddMSPApp { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) -$APIName = $TriggerMetadata.FunctionName + $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' -Set-Location (Get-Item $PSScriptRoot).Parent.FullName Write-Host 'PowerShell HTTP trigger function processed a request.' $RMMApp = $request.body @@ -89,3 +93,5 @@ Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK Body = $body }) + + } diff --git a/AddNamedLocation/run.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddNamedLocation.ps1 similarity index 91% rename from AddNamedLocation/run.ps1 rename to Modules/CIPPCore/Public/Entrypoints/Invoke-AddNamedLocation.ps1 index 723b573c8bb3..48556531ca75 100644 --- a/AddNamedLocation/run.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddNamedLocation.ps1 @@ -1,9 +1,14 @@ -using namespace System.Net + using namespace System.Net -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) + Function Invoke-AddNamedLocation { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) -$APIName = $TriggerMetadata.FunctionName + $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Accessed this API" -Sev "Debug" @@ -55,3 +60,5 @@ Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK Body = $body }) + + } diff --git a/AddOfficeApp/run.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddOfficeApp.ps1 similarity index 97% rename from AddOfficeApp/run.ps1 rename to Modules/CIPPCore/Public/Entrypoints/Invoke-AddOfficeApp.ps1 index 7d87c7cca41f..732aa7dc231a 100644 --- a/AddOfficeApp/run.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddOfficeApp.ps1 @@ -1,9 +1,14 @@ -using namespace System.Net + using namespace System.Net -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) + Function Invoke-AddOfficeApp { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) -$APIName = $TriggerMetadata.FunctionName + $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Accessed this API" -Sev "Debug" @@ -93,3 +98,5 @@ Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ }) + + } diff --git a/AddPolicy/run.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddPolicy.ps1 similarity index 94% rename from AddPolicy/run.ps1 rename to Modules/CIPPCore/Public/Entrypoints/Invoke-AddPolicy.ps1 index e3fdeb1b12d6..4884caffb04b 100644 --- a/AddPolicy/run.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddPolicy.ps1 @@ -1,9 +1,14 @@ -using namespace System.Net + using namespace System.Net -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) + Function Invoke-AddPolicy { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) -$APIName = $TriggerMetadata.FunctionName + $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Accessed this API" -Sev "Debug" $Tenants = ($Request.body | Select-Object Select_*).psobject.properties.value @@ -73,3 +78,5 @@ Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK Body = $body }) + + } diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-AddScheduledItem.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddScheduledItem.ps1 new file mode 100644 index 000000000000..22be136d7623 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddScheduledItem.ps1 @@ -0,0 +1,17 @@ +using namespace System.Net + +Function Invoke-AddScheduledItem { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + $Result = Add-CIPPScheduledTask -Task $Request.body -hidden $false + + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @{ Results = $Result } + }) + +} diff --git a/AddSharedMailbox/run.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddSharedMailbox.ps1 similarity index 86% rename from AddSharedMailbox/run.ps1 rename to Modules/CIPPCore/Public/Entrypoints/Invoke-AddSharedMailbox.ps1 index 35f242fb479c..32596817183b 100644 --- a/AddSharedMailbox/run.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddSharedMailbox.ps1 @@ -1,9 +1,14 @@ -using namespace System.Net + using namespace System.Net -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) + Function Invoke-AddSharedMailbox { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) -$APIName = $TriggerMetadata.FunctionName + $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Accessed this API" -Sev "Debug" $groupobj = $Request.body @@ -38,3 +43,5 @@ Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK Body = $Body }) + + } diff --git a/AddSpamFilter/run.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddSpamFilter.ps1 similarity index 89% rename from AddSpamFilter/run.ps1 rename to Modules/CIPPCore/Public/Entrypoints/Invoke-AddSpamFilter.ps1 index 5b4cff20e52f..e9be0668bd97 100644 --- a/AddSpamFilter/run.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddSpamFilter.ps1 @@ -1,9 +1,14 @@ + using namespace System.Net -using namespace System.Net - -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) + Function Invoke-AddSpamFilter { + <# + .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" @@ -35,3 +40,5 @@ Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK Body = @{Results = @($Result) } }) + + } diff --git a/AddSpamFilterTemplate/run.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddSpamFilterTemplate.ps1 similarity index 92% rename from AddSpamFilterTemplate/run.ps1 rename to Modules/CIPPCore/Public/Entrypoints/Invoke-AddSpamFilterTemplate.ps1 index e8a6175b4cf8..45fae4ecbfc0 100644 --- a/AddSpamFilterTemplate/run.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddSpamFilterTemplate.ps1 @@ -1,9 +1,14 @@ -using namespace System.Net + using namespace System.Net -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) + Function Invoke-AddSpamFilterTemplate { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) -$APIName = $TriggerMetadata.FunctionName + $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Accessed this API" -Sev "Debug" Write-Host ($request | ConvertTo-Json -Compress) @@ -42,3 +47,5 @@ Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK Body = $body }) + + } diff --git a/AddStandardsDeploy/run.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddStandardsDeploy.ps1 similarity index 86% rename from AddStandardsDeploy/run.ps1 rename to Modules/CIPPCore/Public/Entrypoints/Invoke-AddStandardsDeploy.ps1 index a62ed9102df7..fda5dbc33053 100644 --- a/AddStandardsDeploy/run.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddStandardsDeploy.ps1 @@ -1,9 +1,14 @@ -using namespace System.Net + using namespace System.Net -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) + Function Invoke-AddStandardsDeploy { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) -$APIName = $TriggerMetadata.FunctionName + $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' @@ -41,3 +46,5 @@ Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK Body = $body }) + + } diff --git a/AddTeam/run.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddTeam.ps1 similarity index 90% rename from AddTeam/run.ps1 rename to Modules/CIPPCore/Public/Entrypoints/Invoke-AddTeam.ps1 index b7750696392c..d11998bc4260 100644 --- a/AddTeam/run.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddTeam.ps1 @@ -1,9 +1,14 @@ -using namespace System.Net + using namespace System.Net -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) + Function Invoke-AddTeam { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) -$APIName = $TriggerMetadata.FunctionName + $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Accessed this API" -Sev "Debug" $userobj = $Request.body @@ -49,3 +54,5 @@ Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK Body = $Body }) + + } diff --git a/AddTransportRule/run.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddTransportRule.ps1 similarity index 89% rename from AddTransportRule/run.ps1 rename to Modules/CIPPCore/Public/Entrypoints/Invoke-AddTransportRule.ps1 index 173f2662cc3f..4a5ddf22abbc 100644 --- a/AddTransportRule/run.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddTransportRule.ps1 @@ -1,9 +1,14 @@ -using namespace System.Net + using namespace System.Net -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) + Function Invoke-AddTransportRule { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) -$APIName = $TriggerMetadata.FunctionName + $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Accessed this API" -Sev "Debug" $RequestParams = $Request.Body.PowerShellCommand | ConvertFrom-Json | Select-Object -Property * -ExcludeProperty GUID, Comments, HasSenderOverride, ExceptIfHasSenderOverride, ExceptIfMessageContainsDataClassifications, MessageContainsDataClassifications @@ -37,3 +42,5 @@ Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK Body = @{Results = @($Result) } }) + + } diff --git a/AddTransportTemplate/run.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddTransportTemplate.ps1 similarity index 96% rename from AddTransportTemplate/run.ps1 rename to Modules/CIPPCore/Public/Entrypoints/Invoke-AddTransportTemplate.ps1 index 551074fd1761..43d8b28b13cd 100644 --- a/AddTransportTemplate/run.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddTransportTemplate.ps1 @@ -1,9 +1,14 @@ -using namespace System.Net + using namespace System.Net -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) + Function Invoke-AddTransportTemplate { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) -$APIName = $TriggerMetadata.FunctionName + $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Accessed this API" -Sev "Debug" Write-Host ($request | ConvertTo-Json -Compress) @@ -42,3 +47,5 @@ Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK Body = $body }) + + } diff --git a/AddUser/run.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddUser.ps1 similarity index 96% rename from AddUser/run.ps1 rename to Modules/CIPPCore/Public/Entrypoints/Invoke-AddUser.ps1 index 7de7b212c642..f9eb6ba28546 100644 --- a/AddUser/run.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddUser.ps1 @@ -1,9 +1,14 @@ -using namespace System.Net + using namespace System.Net -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) + Function Invoke-AddUser { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) -$APIName = $TriggerMetadata.FunctionName + $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Accessed this API" -Sev "Debug" $Results = [System.Collections.ArrayList]@() $userobj = $Request.body @@ -112,3 +117,5 @@ Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK Body = $Body }) + + } diff --git a/AddWinGetApp/run.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddWinGetApp.ps1 similarity index 90% rename from AddWinGetApp/run.ps1 rename to Modules/CIPPCore/Public/Entrypoints/Invoke-AddWinGetApp.ps1 index a84e5ac41b03..be59d93845f4 100644 --- a/AddWinGetApp/run.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddWinGetApp.ps1 @@ -1,11 +1,15 @@ -using namespace System.Net + using namespace System.Net -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) + Function Invoke-AddWinGetApp { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) -$APIName = $TriggerMetadata.FunctionName + $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Accessed this API" -Sev "Debug" -Set-Location (Get-Item $PSScriptRoot).Parent.FullName Write-Host "PowerShell HTTP trigger function processed a request." $WinGetApp = $request.body @@ -57,3 +61,5 @@ Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK Body = $body }) + + } diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-BestPracticeAnalyser_List.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-BestPracticeAnalyser_List.ps1 new file mode 100644 index 000000000000..82f02778a5f2 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-BestPracticeAnalyser_List.ps1 @@ -0,0 +1,33 @@ + using namespace System.Net + + Function Invoke-BestPracticeAnalyser_List { + <# + .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" + +$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)) + }) + + } diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-EditCAPolicy.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-EditCAPolicy.ps1 new file mode 100644 index 000000000000..da71838797bc --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-EditCAPolicy.ps1 @@ -0,0 +1,35 @@ +using namespace System.Net + +Function Invoke-EditCAPolicy { + <# + .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' + + $Tenant = $request.query.tenantFilter + $ID = $request.query.guid + $results = try { + $EditBody = "{`"state`": `"$($request.query.state)`"}" + $Request = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta//identity/conditionalAccess/policies/$($id)" -tenantid $tenant -type PATCH -body $EditBody + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($Tenant) -message "Edited CA policy $($ID)" -Sev 'Error' + 'Successfully edited CA policy' + } catch { + "Failed to add CA policy: $($_.Exception.Message)" + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($Tenant) -message "Failed editing CA policy $($ID). Error: $($_.Exception.Message)" -Sev 'Error' + continue + } + + $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/EditExConnector/run.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-EditExConnector.ps1 similarity index 82% rename from EditExConnector/run.ps1 rename to Modules/CIPPCore/Public/Entrypoints/Invoke-EditExConnector.ps1 index 9c53f3e6e555..89a13dbb80bc 100644 --- a/EditExConnector/run.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-EditExConnector.ps1 @@ -1,9 +1,14 @@ -using namespace System.Net + using namespace System.Net -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) + Function Invoke-EditExConnector { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) -$APIName = $TriggerMetadata.FunctionName + $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Accessed this API" -Sev "Debug" $Tenantfilter = $request.Query.tenantfilter @@ -28,3 +33,5 @@ Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK Body = @{Results = $Result } }) + + } diff --git a/EditGroup/run.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-EditGroup.ps1 similarity index 97% rename from EditGroup/run.ps1 rename to Modules/CIPPCore/Public/Entrypoints/Invoke-EditGroup.ps1 index ed3f3afa4f7d..7cce727e5294 100644 --- a/EditGroup/run.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-EditGroup.ps1 @@ -1,9 +1,14 @@ -using namespace System.Net + using namespace System.Net -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) + Function Invoke-EditGroup { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) -$APIName = $TriggerMetadata.FunctionName + $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Accessed this API" -Sev "Debug" $Results = [System.Collections.ArrayList]@() @@ -178,3 +183,5 @@ Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK Body = $Body }) + + } diff --git a/EditPolicy/run.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-EditPolicy.ps1 similarity index 90% rename from EditPolicy/run.ps1 rename to Modules/CIPPCore/Public/Entrypoints/Invoke-EditPolicy.ps1 index 5bf4dbd5f09a..076ecde86889 100644 --- a/EditPolicy/run.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-EditPolicy.ps1 @@ -1,9 +1,14 @@ -using namespace System.Net + using namespace System.Net -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) + Function Invoke-EditPolicy { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) -$APIName = $TriggerMetadata.FunctionName + $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' @@ -36,3 +41,5 @@ Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK Body = $body }) + + } diff --git a/EditSpamFilter/run.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-EditSpamFilter.ps1 similarity index 81% rename from EditSpamFilter/run.ps1 rename to Modules/CIPPCore/Public/Entrypoints/Invoke-EditSpamFilter.ps1 index 72ec5aa10967..7138186ae76b 100644 --- a/EditSpamFilter/run.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-EditSpamFilter.ps1 @@ -1,9 +1,14 @@ -using namespace System.Net + using namespace System.Net -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) + Function Invoke-EditSpamFilter { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) -$APIName = $TriggerMetadata.FunctionName + $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Accessed this API" -Sev "Debug" $Tenantfilter = $request.Query.tenantfilter @@ -27,3 +32,5 @@ Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK Body = @{Results = $Result } }) + + } diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-EditTenant.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-EditTenant.ps1 new file mode 100644 index 000000000000..0c10dc387b08 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-EditTenant.ps1 @@ -0,0 +1,60 @@ +using namespace System.Net + +Function Invoke-EditTenant { + <# + .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' + + $tenantDisplayName = $request.body.displayName + $tenantDefaultDomainName = $request.body.defaultDomainName + $Tenant = $request.body.tenantid + $customerContextId = $request.body.customerId + + $tokens = try { + $AADGraphtoken = (Get-GraphToken -scope 'https://graph.windows.net/.default') + $allTenantsDetails = (Invoke-RestMethod -Method GET -Uri 'https://graph.windows.net/myorganization/contracts?api-version=1.6' -ContentType 'application/json' -Headers $AADGraphtoken) + $tenantObjectId = $allTenantsDetails.value | Where-Object { $_.customerContextId -eq $customerContextId } | Select-Object 'objectId' + } catch { + $Results = "Failed to retrieve list of tenants. Error: $($_.Exception.Message)" + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantDisplayName) -message "Failed to retrieve list of tenants. Error: $($_.Exception.Message)" -Sev 'Error' + } + + + if ($tenantObjectId) { + try { + $bodyToPatch = '{"displayName":"' + $tenantDisplayName + '","defaultDomainName":"' + $tenantDefaultDomainName + '"}' + $patchTenant = (Invoke-RestMethod -Method PATCH -Uri "https://graph.windows.net/myorganization/contracts/$($tenantObjectId.objectId)?api-version=1.6" -Body $bodyToPatch -ContentType 'application/json' -Headers $AADGraphtoken -ErrorAction Stop) + $Filter = "PartitionKey eq 'Tenants' and defaultDomainName eq '{0}'" -f $tenantDefaultDomainName + try { + $TenantsTable = Get-CippTable -tablename Tenants + $Tenant = Get-CIPPAzDataTableEntity @TenantsTable -Filter $Filter + $Tenant.displayName = $tenantDisplayName + Update-AzDataTableEntity @TenantsTable -Entity $Tenant + } catch { + $AddedText = 'but could not edit the tenant cache. Clear the tenant cache to display the updated details' + } + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $tenantDisplayName -message "Edited tenant $tenantDisplayName" -Sev 'Info' + $results = "Successfully amended details for $($Tenant.displayName) $AddedText" + } catch { + $results = "Failed to amend details for $tenantDisplayName : $($_.Exception.Message)" + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $tenantDisplayName -message "Failed amending details $tenantDisplayName. Error: $($_.Exception.Message)" -Sev 'Error' + } + } else { + $Results = 'Could not find the tenant to edit in the contract endpoint. Please ensure you have a reseller relationship with the tenant you are trying to edit.' + } + + $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/Entrypoints/Invoke-EditTransportRule.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-EditTransportRule.ps1 new file mode 100644 index 000000000000..11c669a95358 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-EditTransportRule.ps1 @@ -0,0 +1,35 @@ +using namespace System.Net + +Function Invoke-EditTransportRule { + <# + .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' + $Tenantfilter = $request.Query.tenantfilter + + + $Params = @{ + Identity = $request.query.guid + } + + try { + $cmdlet = if ($request.query.state -eq 'enable') { 'Enable-TransportRule' } else { 'Disable-TransportRule' } + $GraphRequest = New-ExoRequest -tenantid $Tenantfilter -cmdlet $cmdlet -cmdParams $params -UseSystemMailbox $true + $Result = "Set transport rule $($Request.query.guid) to $($request.query.State)" + Write-LogMessage -API 'TransportRules' -tenant $tenantfilter -message "Set transport rule $($Request.query.guid) to $($request.query.State)" -sev Debug + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception + $Result = $ErrorMessage + } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @{Results = $Result } + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-EditUser.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-EditUser.ps1 new file mode 100644 index 000000000000..996352c449dd --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-EditUser.ps1 @@ -0,0 +1,114 @@ +using namespace System.Net + +Function Invoke-EditUser { + <# + .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' + $userobj = $Request.body + $Results = [System.Collections.ArrayList]@() + $licenses = ($userobj | Select-Object 'License_*').psobject.properties.value + $Aliases = if ($userobj.AddedAliases) { ($userobj.AddedAliases).Split([Environment]::NewLine) } + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + #Edit the user + try { + Write-Host "$([boolean]$UserObj.mustchangepass)" + $Email = "$($UserObj.username)@$($UserObj.domain)" + $UserprincipalName = "$($UserObj.username)@$($UserObj.domain)" + $BodyToship = [pscustomobject] @{ + 'givenName' = $userobj.firstname + 'surname' = $userobj.lastname + 'city' = $userobj.city + 'country' = $userobj.country + 'department' = $userobj.department + 'displayName' = $UserObj.Displayname + 'postalCode' = $userobj.postalCode + 'companyName' = $userobj.companyName + 'mailNickname' = $UserObj.username + 'jobTitle' = $UserObj.JobTitle + 'userPrincipalName' = $Email + 'usageLocation' = $UserObj.usageLocation + 'mobilePhone' = $userobj.mobilePhone + 'streetAddress' = $userobj.streetAddress + 'businessPhones' = @($userobj.businessPhone) + 'passwordProfile' = @{ + 'forceChangePasswordNextSignIn' = [boolean]$UserObj.mustchangepass + } + } | ForEach-Object { + $NonEmptyProperties = $_.psobject.Properties | Select-Object -ExpandProperty Name + $_ | Select-Object -Property $NonEmptyProperties | ConvertTo-Json + } + $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' + 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 + $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 { + 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)") + } + + + #Reassign the licenses + try { + + if ($licenses -or $userobj.RemoveAllLicenses) { + $licenses = (($userobj | Select-Object 'License_*').psobject.properties | Where-Object { $_.value -EQ $true }).name -replace 'License_', '' + $CurrentLicenses = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($userobj.Userid)" -tenantid $Userobj.tenantid + $RemovalList = ($CurrentLicenses.assignedLicenses | Where-Object -Property skuid -NotIn $licenses).skuid + $LicensesToRemove = if ($RemovalList) { ConvertTo-Json @( $RemovalList ) } else { '[]' } + + $liclist = foreach ($license in $Licenses) { '{"disabledPlans": [],"skuId": "' + $license + '" },' } + $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 + + 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.' ) + } + + } 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)") + } + + #Add Aliases, removal currently not supported. + try { + if ($Aliases) { + foreach ($Alias in $Aliases) { + New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($userobj.Userid)" -tenantid $Userobj.tenantid -type 'patch' -body "{`"mail`": `"$Alias`"}" -verbose + } + New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($userobj.Userid)" -tenantid $Userobj.tenantid -type 'patch' -body "{`"mail`": `"$UserprincipalName`"}" -verbose + Write-LogMessage -API $APINAME -tenant ($UserObj.tenantid) -user $request.headers.'x-ms-client-principal' -message "Added Aliases to $($userobj.displayname)" -Sev 'Info' + $results.add( 'Success. added aliasses to user.') + } + + } 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)") + } + + if ($Request.body.CopyFrom -ne '') { + $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) + } + $body = @{'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/Entrypoints/Invoke-ExecAccessChecks.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecAccessChecks.ps1 new file mode 100644 index 000000000000..93a72e2e296d --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecAccessChecks.ps1 @@ -0,0 +1,36 @@ +using namespace System.Net + +Function Invoke-ExecAccessChecks { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + if ($Request.query.Permissions -eq 'true') { + $Results = Test-CIPPAccessPermissions -tenantfilter $ENV:tenantid -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' + } + + if ($Request.query.Tenants -eq 'true') { + $Results = Test-CIPPAccessTenant -Tenantcsv $Request.body.TenantId + } + if ($Request.query.GDAP -eq 'true') { + $Results = Test-CIPPGDAPRelationships + } + + $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/Entrypoints/Invoke-ExecAddGDAPRole.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecAddGDAPRole.ps1 new file mode 100644 index 000000000000..61701c1d51a9 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecAddGDAPRole.ps1 @@ -0,0 +1,66 @@ +using namespace System.Net + +Function Invoke-ExecAddGDAPRole { + <# + .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' + $Groups = $Request.body.gdapRoles + $CustomSuffix = $Request.body.customSuffix + $Table = Get-CIPPTable -TableName 'GDAPRoles' + + $Results = [System.Collections.Generic.List[string]]::new() + $ExistingGroups = New-GraphGetRequest -NoAuthCheck $True -uri 'https://graph.microsoft.com/beta/groups' -tenantid $env:TenantID + + $RoleMappings = foreach ($group in $Groups) { + if ($CustomSuffix) { + $GroupName = "M365 GDAP $($Group.Name) - $CustomSuffix" + $MailNickname = "M365GDAP$(($Group.Name).replace(' ',''))$($CustomSuffix)" + } else { + $GroupName = "M365 GDAP $($Group.Name)" + $MailNickname = "M365GDAP$(($Group.Name).replace(' ',''))" + } + try { + if ($GroupName -in $ExistingGroups.displayName) { + @{ + PartitionKey = 'Roles' + RowKey = ($ExistingGroups | Where-Object -Property displayName -EQ $GroupName).id + RoleName = $Group.Name + GroupName = $GroupName + GroupId = ($ExistingGroups | Where-Object -Property displayName -EQ $GroupName).id + roleDefinitionId = $group.ObjectId + } + $Results.Add("M365 GDAP $($Group.Name) already exists") + } else { + $BodyToship = [pscustomobject] @{'displayName' = $GroupName; 'description' = "This group is used to manage M365 partner tenants at the $($group.name) level."; securityEnabled = $true; mailEnabled = $false; mailNickname = $MailNickname } | ConvertTo-Json + $GraphRequest = New-GraphPostRequest -NoAuthCheck $True -uri 'https://graph.microsoft.com/beta/groups' -tenantid $env:TenantID -type POST -body $BodyToship -verbose + @{ + PartitionKey = 'Roles' + RowKey = $GraphRequest.Id + RoleName = $Group.Name + GroupName = $GroupName + GroupId = $GraphRequest.Id + roleDefinitionId = $group.ObjectId + } + $Results.Add("$GroupName added successfully") + } + } catch { + $Results.Add("Could not create GDAP group $($GroupName): $($_.Exception.Message)") + } + } + + Add-CIPPAzDataTableEntity @Table -Entity $RoleMappings -Force + + $body = @{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/Entrypoints/Invoke-ExecAddSPN.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecAddSPN.ps1 new file mode 100644 index 000000000000..de779bfe083d --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecAddSPN.ps1 @@ -0,0 +1,29 @@ +using namespace System.Net + +Function Invoke-ExecAddSPN { + <# + .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' + + # Interact with query parameters or the body of the request. + $Body = if ($Request.Query.Enable) { '{"accountEnabled":"true"}' } else { '{"accountEnabled":"false"}' } + try { + $GraphRequest = New-GraphPostRequest -uri 'https://graph.microsoft.com/v1.0/servicePrincipals' -tenantid $ENV:TenantID -type POST -Body "{ `"appId`": `"2832473f-ec63-45fb-976f-5d45a7d4bb91`" }" -NoAuthCheck $true + $Results = [pscustomobject]@{'Results' = "Successfully completed request. Add your GDAP migration permissions to your SAM application here: https://portal.azure.com/#view/Microsoft_AAD_RegisteredApps/ApplicationMenuBlade/~/CallAnAPI/appId/$($ENV:ApplicationID)/isMSAApp/ " } + } catch { + $Results = [pscustomobject]@{'Results' = "Failed to add SPN. Please manually execute 'New-AzureADServicePrincipal -AppId 2832473f-ec63-45fb-976f-5d45a7d4bb91' The error was $($_.Exception.Message)" } + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Results + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecAlertsList.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecAlertsList.ps1 new file mode 100644 index 000000000000..1b6141e1fcda --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecAlertsList.ps1 @@ -0,0 +1,108 @@ +using namespace System.Net + +Function Invoke-ExecAlertsList { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + function New-FlatArray ([Array]$arr) { + $arr | ForEach-Object { + if ($_ -is 'Array') { + New-FlatArray $_ + } else { $_ } + } + } + try { + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + $GraphRequest = if ($TenantFilter -ne 'AllTenants') { + $Alerts = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/security/alerts' -tenantid $TenantFilter + $AlertsObj = foreach ($Alert In $alerts) { + @{ + Tenant = $TenantFilter + GUID = $GUID + Id = $alert.Id + Title = $alert.Title + Category = $alert.category + EventDateTime = $alert.eventDateTime + Severity = $alert.Severity + Status = $alert.Status + RawResult = $($Alerts | Where-Object { $_.Id -eq $alert.Id }) + InvolvedUsers = $($Alerts | Where-Object { $_.Id -eq $alert.Id }).userStates + } + } + + $DisplayableAlerts = New-FlatArray $AlertsObj | Where-Object { $_.Id -ne $null } | Sort-Object -Property EventDateTime -Descending + + [PSCustomObject]@{ + NewAlertsCount = $DisplayableAlerts | Where-Object { $_.Status -eq 'newAlert' } | Measure-Object | Select-Object -ExpandProperty Count + InProgressAlertsCount = $DisplayableAlerts | Where-Object { $_.Status -eq 'inProgress' } | Measure-Object | Select-Object -ExpandProperty Count + SeverityHighAlertsCount = ($DisplayableAlerts | Where-Object { ($_.Status -eq 'inProgress') -or ($_.Status -eq 'newAlert') } | Where-Object { $_.Severity -eq 'high' } | Measure-Object | Select-Object -ExpandProperty Count) + SeverityMediumAlertsCount = $DisplayableAlerts | Where-Object { ($_.Status -eq 'inProgress') -or ($_.Status -eq 'newAlert') } | Where-Object { $_.Severity -eq 'medium' } | Measure-Object | Select-Object -ExpandProperty Count + SeverityLowAlertsCount = $DisplayableAlerts | Where-Object { ($_.Status -eq 'inProgress') -or ($_.Status -eq 'newAlert') } | Where-Object { $_.Severity -eq 'low' } | Measure-Object | Select-Object -ExpandProperty Count + SeverityInformationalCount = $DisplayableAlerts | Where-Object { ($_.Status -eq 'inProgress') -or ($_.Status -eq 'newAlert') } | Where-Object { $_.Severity -eq 'informational' } | Measure-Object | Select-Object -ExpandProperty Count + MSResults = $DisplayableAlerts + } + } else { + $Table = Get-CIPPTable -TableName cachealertsandincidents + $Filter = "PartitionKey eq 'alert'" + $Rows = Get-CIPPAzDataTableEntity @Table -filter $Filter | Where-Object -Property Timestamp -GT (Get-Date).AddMinutes(-10) + if (!$Rows) { + Push-OutputBinding -Name alertqueue -Value (Get-Date).ToString() + [PSCustomObject]@{ + Waiting = $true + } + } else { + $Alerts = $Rows + $AlertsObj = foreach ($Alert in $alerts) { + $AlertInfo = $Alert.Alert | ConvertFrom-Json + @{ + Tenant = $Alert.Tenant + GUID = $GUID + Id = $AlertInfo.Id + Title = $AlertInfo.Title + Category = $AlertInfo.category + EventDateTime = $AlertInfo.eventDateTime + Severity = $AlertInfo.Severity + Status = $AlertInfo.Status + RawResult = $AlertInfo + InvolvedUsers = $AlertInfo.userStates + } + } + $DisplayableAlerts = New-FlatArray $AlertsObj | Where-Object { $_.Id -ne $null } | Sort-Object -Property EventDateTime -Descending + [PSCustomObject]@{ + NewAlertsCount = $DisplayableAlerts | Where-Object { $_.Status -eq 'newAlert' } | Measure-Object | Select-Object -ExpandProperty Count + InProgressAlertsCount = $DisplayableAlerts | Where-Object { $_.Status -eq 'inProgress' } | Measure-Object | Select-Object -ExpandProperty Count + SeverityHighAlertsCount = ($DisplayableAlerts | Where-Object { ($_.Status -eq 'inProgress') -or ($_.Status -eq 'newAlert') } | Where-Object { $_.Severity -eq 'high' } | Measure-Object | Select-Object -ExpandProperty Count) + SeverityMediumAlertsCount = $DisplayableAlerts | Where-Object { ($_.Status -eq 'inProgress') -or ($_.Status -eq 'newAlert') } | Where-Object { $_.Severity -eq 'medium' } | Measure-Object | Select-Object -ExpandProperty Count + SeverityLowAlertsCount = $DisplayableAlerts | Where-Object { ($_.Status -eq 'inProgress') -or ($_.Status -eq 'newAlert') } | Where-Object { $_.Severity -eq 'low' } | Measure-Object | Select-Object -ExpandProperty Count + SeverityInformationalCount = $DisplayableAlerts | Where-Object { ($_.Status -eq 'inProgress') -or ($_.Status -eq 'newAlert') } | Where-Object { $_.Severity -eq 'informational' } | Measure-Object | Select-Object -ExpandProperty Count + MSResults = $DisplayableAlerts + } + } + } + + } catch { + $StatusCode = [HttpStatusCode]::Forbidden + $body = $_.Exception.message + } + if (!$body) { + $StatusCode = [HttpStatusCode]::OK + $body = $GraphRequest + } + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = $Body + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecAlertsListAllTenants.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecAlertsListAllTenants.ps1 new file mode 100644 index 000000000000..fc14d337dc28 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecAlertsListAllTenants.ps1 @@ -0,0 +1,60 @@ +using namespace System.Net + +Function Invoke-ExecAlertsListAllTenants { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + + Get-Tenants | ForEach-Object -Parallel { + $domainName = $_.defaultDomainName + Import-Module '.\Modules\AzBobbyTables' + Import-Module '.\Modules\CIPPCore' + $Table = Get-CIPPTable -TableName 'cachealertsandincidents' + + try { + $Alerts = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/security/alerts' -tenantid $domainName + foreach ($Alert in $Alerts) { + $GUID = (New-Guid).Guid + $alertJson = $Alert | ConvertTo-Json + $GraphRequest = @{ + Alert = [string]$alertJson + RowKey = [string]$GUID + Tenant = $domainName + PartitionKey = 'alert' + } + Add-CIPPAzDataTableEntity @Table -Entity $GraphRequest -Force | Out-Null + + } + + } catch { + $GUID = (New-Guid).Guid + $AlertText = ConvertTo-Json -InputObject @{ + Title = "Could not connect to tenant to retrieve data: $($_.Exception.Message)" + Id = '' + Category = '' + EventDateTime = '' + Severity = '' + Status = '' + userStates = @('None') + vendorInformation = @{ + vendor = 'CIPP' + provider = 'CIPP' + } + } + $GraphRequest = @{ + Alert = [string]$AlertText + RowKey = [string]$GUID + PartitionKey = 'alert' + Tenant = $domainName + } + Add-CIPPAzDataTableEntity @Table -Entity $GraphRequest -Force | Out-Null + + + } + } + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecAppApproval.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecAppApproval.ps1 new file mode 100644 index 000000000000..561d060eb99b --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecAppApproval.ps1 @@ -0,0 +1,33 @@ +using namespace System.Net + +Function Invoke-ExecAppApproval { + <# + .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' + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + Write-Host "$($Request.query.ID)" + # Interact with query parameters or the body of the request. + + $applicationid = if ($request.query.applicationid) { $request.query.applicationid } else { $env:ApplicationID } + $Results = get-tenants | ForEach-Object { + [PSCustomObject]@{ + defaultDomainName = $_.defaultDomainName + link = "https://login.microsoftonline.com/$($_.customerId)/v2.0/adminconsent?client_id=$applicationid&scope=$applicationid/.default" + } + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Results + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecAssignApp.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecAssignApp.ps1 new file mode 100644 index 000000000000..4825fc8a9f81 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecAssignApp.ps1 @@ -0,0 +1,59 @@ +using namespace System.Net + +Function Invoke-ExecAssignApp { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # Interact with query parameters or the body of the request. + $tenantfilter = $Request.Query.TenantFilter + $appFilter = $Request.Query.ID + $AssignTo = $Request.Query.AssignTo + $AssignBody = switch ($AssignTo) { + + 'AllUsers' { + @' +{"mobileAppAssignments":[{"@odata.type":"#microsoft.graph.mobileAppAssignment","target":{"@odata.type":"#microsoft.graph.allLicensedUsersAssignmentTarget"},"intent":"Required","settings":null}]} +'@ + } + + 'AllDevices' { + @' +{"mobileAppAssignments":[{"@odata.type":"#microsoft.graph.mobileAppAssignment","target":{"@odata.type":"#microsoft.graph.allDevicesAssignmentTarget"},"intent":"Required","settings":null}]} +'@ + } + + 'Both' { + @' +{"mobileAppAssignments":[{"@odata.type":"#microsoft.graph.mobileAppAssignment","target":{"@odata.type":"#microsoft.graph.allLicensedUsersAssignmentTarget"},"intent":"Required","settings":null},{"@odata.type":"#microsoft.graph.mobileAppAssignment","target":{"@odata.type":"#microsoft.graph.allDevicesAssignmentTarget"},"intent":"Required","settings":null}]} +'@ + } + + } + $body = [pscustomobject]@{'Results' = "$($TenantFilter): Assigned app to $assignTo" } + try { + $GraphRequest = New-Graphpostrequest -uri "https://graph.microsoft.com/beta/deviceAppManagement/mobileApps/$appFilter/assign" -tenantid $TenantFilter -body $Assignbody + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantfilter) -message "Assigned $($appFilter) to $assignTo" -Sev 'Info' + + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantfilter) -message "Failed to assign app $($appFilter): $($_.Exception.Message)" -Sev 'Error' + $body = [pscustomobject]@{'Results' = "Failed to assign. $($_.Exception.Message)" } + } + + # 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/Entrypoints/Invoke-ExecAutoExtendGDAP.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecAutoExtendGDAP.ps1 new file mode 100644 index 000000000000..d0f1b5385e0c --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecAutoExtendGDAP.ps1 @@ -0,0 +1,23 @@ +using namespace System.Net + +Function Invoke-ExecAutoExtendGDAP { + <# + .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' + + # Interact with query parameters or the body of the request. + $Results = Set-CIPPGDAPAutoExtend -RelationShipid $Request.query.ID + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @{ Results = $Results } + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecBECCheck.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecBECCheck.ps1 new file mode 100644 index 000000000000..7413636f7061 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecBECCheck.ps1 @@ -0,0 +1,36 @@ +using namespace System.Net + +Function Invoke-ExecBECCheck { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $body = if ($request.query.GUID) { + $Table = Get-CippTable -tablename 'cachebec' + $Filter = "PartitionKey eq 'bec' and RowKey eq '$($request.query.GUID)'" + $JSONOutput = Get-CIPPAzDataTableEntity @Table -Filter $Filter + if (!$JSONOutput) { + @{ Waiting = $true } + } else { + $JSONOutput.Results + } + } else { + $OrchRequest = [PSCustomObject]@{ + TenantFilter = $request.query.tenantfilter + UserID = $request.query.userid + userName = $request.query.userName + } + $InstanceId = Start-NewOrchestration -FunctionName 'Durable_BECRun' -InputObject $OrchRequest + @{ GUID = $request.query.userid } + } + + + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $body + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecBECRemediate.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecBECRemediate.ps1 new file mode 100644 index 000000000000..b863aeac8f06 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecBECRemediate.ps1 @@ -0,0 +1,51 @@ +using namespace System.Net + +Function Invoke-ExecBECRemediate { + <# + .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' + Write-Host 'PowerShell HTTP trigger function processed a request.' + + $TenantFilter = $request.body.tenantfilter + $SuspectUser = $request.body.userid + $username = $request.body.username + Write-Host $TenantFilter + Write-Host $SuspectUser + $Results = try { + Set-CIPPResetPassword -userid $username -tenantFilter $TenantFilter -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' + Set-CIPPSignInState -userid $username -AccountEnabled $false -tenantFilter $TenantFilter -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' + Revoke-CIPPSessions -userid $SuspectUser -username $request.body.username -ExecutingUser $request.headers.'x-ms-client-principal' -APIName $APINAME -tenantFilter $TenantFilter + $RuleDisabled = 0 + New-ExoRequest -anchor $username -tenantid $TenantFilter -cmdlet 'get-inboxrule' -cmdParams @{Mailbox = $username } | ForEach-Object { + $null = New-ExoRequest -anchor $username -tenantid $TenantFilter -cmdlet 'Disable-InboxRule' -cmdParams @{Confirm = $false; Identity = $_.Identity } + "Disabled Inbox Rule $($_.Identity) for $username" + $RuleDisabled ++ + } + if ($RuleDisabled) { + "Disabled $RuleDisabled Inbox Rules for $username" + } else { + "No Inbox Rules found for $username. We have not disabled any rules." + } + + Write-LogMessage -API 'BECRemediate' -tenant $tenantfilter -message "Executed Remediation for $SuspectUser" -sev 'Info' + + } catch { + #Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantfilter) -message "Failed to assign app $($appFilter): $($_.Exception.Message)" -Sev "Error" + $results = [pscustomobject]@{'Results' = "Failed to execute remediation. $($_.Exception.Message)" } + Write-LogMessage -API 'BECRemediate' -tenant $tenantfilter -message "Executed Remediation for $SuspectUser failed" -sev 'Error' + } + $results = [pscustomobject]@{'Results' = @($Results) } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Results + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecBackendURLs.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecBackendURLs.ps1 new file mode 100644 index 000000000000..4a29002ad122 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecBackendURLs.ps1 @@ -0,0 +1,42 @@ +using namespace System.Net + +Function Invoke-ExecBackendURLs { + <# + .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' + + $Subscription = ($ENV:WEBSITE_OWNER_NAME).split('+') | Select-Object -First 1 + $SWAName = $ENV:Website_SITE_NAME -replace 'cipp', 'CIPP-SWA-' + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + $results = [PSCustomObject]@{ + ResourceGroup = "https://portal.azure.com/#@Go/resource/subscriptions/$Subscription/resourceGroups/$ENV:Website_Resource_Group/overview" + KeyVault = "https://portal.azure.com/#@Go/resource/subscriptions/$Subscription/resourceGroups/$ENV:Website_Resource_Group/providers/Microsoft.KeyVault/vaults/$($ENV:WEBSITE_SITE_NAME)/secrets" + FunctionApp = "https://portal.azure.com/#@Go/resource/subscriptions/$Subscription/resourceGroups/$ENV:Website_Resource_Group/providers/Microsoft.Web/sites/$($ENV:WEBSITE_SITE_NAME)/appServices" + FunctionConfig = "https://portal.azure.com/#@Go/resource/subscriptions/$Subscription/resourceGroups/$ENV:Website_Resource_Group/providers/Microsoft.Web/sites/$($ENV:WEBSITE_SITE_NAME)/configuration" + FunctionDeployment = "https://portal.azure.com/#@Go/resource/subscriptions/$Subscription/resourceGroups/$ENV:Website_Resource_Group/providers/Microsoft.Web/sites/$($ENV:WEBSITE_SITE_NAME)/vstscd" + SWADomains = "https://portal.azure.com/#@Go/resource/subscriptions/$Subscription/resourceGroups/$ENV:Website_Resource_Group/providers/Microsoft.Web/staticSites/$SWAName/customDomains" + SWARoles = "https://portal.azure.com/#@Go/resource/subscriptions/$Subscription/resourceGroups/$ENV:Website_Resource_Group/providers/Microsoft.Web/staticSites/$SWAName/roleManagement" + Subscription = $Subscription + RGName = $ENV:Website_Resource_Group + FunctionName = $ENV:WEBSITE_SITE_NAME + SWAName = $SWAName + } + + + $body = @{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/Entrypoints/Invoke-ExecCPVPermissions.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecCPVPermissions.ps1 new file mode 100644 index 000000000000..7573e9fd209c --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecCPVPermissions.ps1 @@ -0,0 +1,51 @@ +using namespace System.Net + +Function Invoke-ExecCPVPermissions { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + $TenantFilter = (get-tenants -IncludeAll -IncludeErrors | Where-Object -Property customerId -EQ $Request.query.Tenantfilter).defaultDomainName + Write-Host "Our Tenantfilter is $TenantFilter" + + $CPVConsentParams = @{ + Tenantfilter = $TenantFilter + } + if ($Request.Query.ResetSP -eq 'true') { + $CPVConsentParams.ResetSP = $true + } + + $GraphRequest = try { + Set-CIPPCPVConsent @CPVConsentParams + Add-CIPPApplicationPermission -RequiredResourceAccess 'CippDefaults' -ApplicationId $ENV:ApplicationID -tenantfilter $TenantFilter + Add-CIPPDelegatedPermission -RequiredResourceAccess 'CippDefaults' -ApplicationId $ENV:ApplicationID -tenantfilter $TenantFilter + $Success = $true + } catch { + "Failed to update permissions for $($TenantFilter): $($_.Exception.Message)" + $Success = $false + } + + $Tenant = Get-Tenants -IncludeAll -IncludeErrors | Where-Object -Property defaultDomainName -EQ $Tenantfilter + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @{ + Results = $GraphRequest + Metadata = @{ + Heading = 'CPV Permission - {0} ({1})' -f $Tenant.displayName, $Tenant.defaultDomainName + Success = $Success + } + } + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecClrImmId.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecClrImmId.ps1 new file mode 100644 index 000000000000..3506522f2c8c --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecClrImmId.ps1 @@ -0,0 +1,37 @@ +using namespace System.Net + +Function Invoke-ExecClrImmId { + <# + .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' + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # Interact with query parameters or the body of the request. + Try { + $TenantFilter = $Request.Query.TenantFilter + $UserID = $Request.Query.ID + $Body = [pscustomobject] @{ + onPremisesImmutableId = $null + } | ConvertTo-Json + $GraphRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$UserID" -tenantid $TenantFilter -type PATCH -body $Body + $Results = [pscustomobject]@{'Results' = 'Successfully Cleared ImmutableId' } + } catch { + $Results = [pscustomobject]@{'Results' = "Failed. $_.Exception.Message"; colour = 'danger' } + $_.Exception + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Results + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecConverttoSharedMailbox.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecConverttoSharedMailbox.ps1 new file mode 100644 index 000000000000..cb16432e8937 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecConverttoSharedMailbox.ps1 @@ -0,0 +1,33 @@ +using namespace System.Net + +Function Invoke-ExecConverttoSharedMailbox { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + + # Interact with query parameters or the body of the request. + Try { + $MailboxType = if ($request.query.ConvertToUser -eq 'true') { 'Regular' } else { 'Shared' } + $ConvertedMailbox = Set-CIPPMailboxType -userid $Request.query.id -tenantFilter $Request.query.TenantFilter -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' -MailboxType $MailboxType + $Results = [pscustomobject]@{'Results' = "$ConvertedMailbox" } + } catch { + $Results = [pscustomobject]@{'Results' = "Failed to convert $($request.query.id) - $($_.Exception.Message)" } + } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Results + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecCopyForSent.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecCopyForSent.ps1 new file mode 100644 index 000000000000..a039be57dfba --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecCopyForSent.ps1 @@ -0,0 +1,34 @@ +using namespace System.Net + +Function Invoke-ExecCopyForSent { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + + # Interact with query parameters or the body of the request. + Try { + $MessageCopyForSentAsEnabled = if ($request.query.MessageCopyForSentAsEnabled -eq 'false') { 'false' } else { 'true' } + $MessageResult = Set-CIPPMessageCopy -userid $Request.query.id -tenantFilter $Request.query.TenantFilter -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' -MessageCopyForSentAsEnabled $MessageCopyForSentAsEnabled + $Results = [pscustomobject]@{'Results' = "$MessageResult" } + } catch { + $Results = [pscustomobject]@{'Results' = "set MessageCopyForSentAsEnabled to $MessageCopyForSentAsEnabled failed - $($_.Exception.Message)" } + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Results + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecCreateTAP.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecCreateTAP.ps1 new file mode 100644 index 000000000000..9919b0564510 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecCreateTAP.ps1 @@ -0,0 +1,28 @@ +using namespace System.Net + +Function Invoke-ExecCreateTAP { + <# + .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' + + # Interact with query parameters or the body of the request. + try { + $TAP = New-CIPPTAP -userid $Request.query.ID -TenantFilter $Request.query.tenantfilter -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' + $Results = [pscustomobject]@{'Results' = "$TAP" } + } 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 + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecDeleteGDAPRelationship.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecDeleteGDAPRelationship.ps1 new file mode 100644 index 000000000000..b51a86b0098d --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecDeleteGDAPRelationship.ps1 @@ -0,0 +1,31 @@ +using namespace System.Net + +Function Invoke-ExecDeleteGDAPRelationship { + <# + .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' + + # Interact with query parameters or the body of the request. + $GDAPID = $request.query.GDAPId + try { + $DELETE = New-GraphPostRequest -NoAuthCheck $True -uri "https://traf-pcsvcadmin-prod.trafficmanager.net/CustomerServiceAdminApi/Web/v1/delegatedAdminRelationships/$($GDAPID)/requests" -type POST -body '{"action":"terminate"}' -tenantid $env:TenantID -scope 'https://api.partnercustomeradministration.microsoft.com/.default' + $Results = [pscustomobject]@{'Results' = "Success. GDAP relationship for $($GDAPID) been revoked" } + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Success. GDAP relationship for $($GDAPID) been revoked" -Sev 'Info' + + } 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 + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecDeleteGDAPRoleMapping.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecDeleteGDAPRoleMapping.ps1 new file mode 100644 index 000000000000..729c327b3528 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecDeleteGDAPRoleMapping.ps1 @@ -0,0 +1,33 @@ +using namespace System.Net + +Function Invoke-ExecDeleteGDAPRoleMapping { + <# + .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' + $Table = Get-CIPPTable -TableName 'GDAPRoles' + + Write-Host $Table + try { + $Filter = "PartitionKey eq 'Roles' and RowKey eq '{0}'" -f $Request.Query.GroupId + $Entity = Get-CIPPAzDataTableEntity @Table -Filter $Filter + Remove-AzDataTableEntity @Table -Entity $Entity + $Results = [pscustomobject]@{'Results' = 'Success. GDAP relationship mapping deleted' } + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "GDAP relationship mapping deleted for $($Request.Query.GroupId)" -Sev 'Info' + + } 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 + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecDeviceAction.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecDeviceAction.ps1 new file mode 100644 index 000000000000..90f9e86d4c6d --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecDeviceAction.ps1 @@ -0,0 +1,34 @@ +using namespace System.Net + +Function Invoke-ExecDeviceAction { + <# + .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' + + # Interact with query parameters or the body of the request. + + + try { + if ($Request.Query.Action -eq 'setDeviceName') { + $ActionBody = @{ deviceName = $Request.Body.input } | ConvertTo-Json -Compress + } + $ActionResult = New-CIPPDeviceAction -Action $Request.Query.Action -ActionBody $ActionBody -DeviceFilter $Request.Query.GUID -TenantFilter $Request.Query.TenantFilter -ExecutingUser $request.headers.'x-ms-client-principal' -APINAME $APINAME + $body = [pscustomobject]@{'Results' = "$ActionResult" } + + } catch { + $body = [pscustomobject]@{'Results' = "Failed to queue action $action on $DeviceFilter $($_.Exception.Message)" } + } + + # 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/Entrypoints/Invoke-ExecDisableEmailForward.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecDisableEmailForward.ps1 new file mode 100644 index 000000000000..12c57868e68d --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecDisableEmailForward.ps1 @@ -0,0 +1,32 @@ +using namespace System.Net + +Function Invoke-ExecDisableEmailForward { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + try { + $APIName = $TriggerMetadata.FunctionName + 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 + $Results = try { + Set-CIPPForwarding -userid $Request.body.user -tenantFilter $TenantFilter -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' -Forward $null -keepCopy $false -ForwardingSMTPAddress $null -Disable $true + } catch { + "Could not disable forwarding message for $($username). Error: $($_.Exception.Message)" + } + + $body = [pscustomobject]@{'Results' = @($results) } + } catch { + $body = [pscustomobject]@{'Results' = @("Could not disable forwarding user: $($_.Exception.message)") } + } + + # 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/Entrypoints/Invoke-ExecDisableUser.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecDisableUser.ps1 new file mode 100644 index 000000000000..3e32878e726d --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecDisableUser.ps1 @@ -0,0 +1,26 @@ +using namespace System.Net + +Function Invoke-ExecDisableUser { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $TriggerMetadata.FunctionName + try { + ([System.Convert]::ToBoolean($Request.Query.Enable)) + $State = Set-CIPPSignInState -userid $Request.query.ID -TenantFilter $Request.Query.TenantFilter -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' -AccountEnabled ([System.Convert]::ToBoolean($Request.Query.Enable)) + $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 + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecDnsConfig.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecDnsConfig.ps1 new file mode 100644 index 000000000000..067da939c2ca --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecDnsConfig.ps1 @@ -0,0 +1,113 @@ +using namespace System.Net + +Function Invoke-ExecDnsConfig { + <# + .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' + + # List of supported resolvers + $ValidResolvers = @( + 'Google' + 'Cloudflare' + 'Quad9' + ) + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + $StatusCode = [HttpStatusCode]::OK + try { + $ConfigTable = Get-CippTable -tablename Config + $Filter = "PartitionKey eq 'Domains' and RowKey eq 'Domains'" + $Config = Get-CIPPAzDataTableEntity @ConfigTable -Filter $Filter + + $DomainTable = Get-CippTable -tablename 'Domains' + + if ($ValidResolvers -notcontains $Config.Resolver) { + $Config = @{ + PartitionKey = 'Domains' + RowKey = 'Domains' + Resolver = 'Google' + } + Add-CIPPAzDataTableEntity @ConfigTable -Entity $Config -Force + } + + $updated = $false + + switch ($Request.Query.Action) { + 'SetConfig' { + if ($Request.Query.Resolver) { + $Resolver = $Request.Query.Resolver + if ($ValidResolvers -contains $Resolver) { + try { + $Config.Resolver = $Resolver + } catch { + $Config = @{ + Resolver = $Resolver + } + } + $updated = $true + } + } + if ($updated) { + Add-CIPPAzDataTableEntity @ConfigTable -Entity $Config -Force + Write-LogMessage -API $APINAME -tenant 'Global' -user $request.headers.'x-ms-client-principal' -message 'DNS configuration updated' -Sev 'Info' + $body = [pscustomobject]@{'Results' = 'Success: DNS configuration updated.' } + } else { + $StatusCode = [HttpStatusCode]::BadRequest + $body = [pscustomobject]@{'Results' = 'Error: No DNS resolver provided.' } + } + } + 'SetDkimConfig' { + $Domain = $Request.Query.Domain + $Selector = ($Request.Query.Selector).trim() -split '\s*,\s*' + $DomainTable = Get-CIPPTable -Table 'Domains' + $Filter = "RowKey eq '{0}'" -f $Domain + $DomainInfo = Get-CIPPAzDataTableEntity @DomainTable -Filter $Filter + $DkimSelectors = [string]($Selector | ConvertTo-Json -Compress) + if ($DomainInfo) { + $DomainInfo.DkimSelectors = $DkimSelectors + } else { + $DomainInfo = @{ + 'RowKey' = $Request.Query.Domain + 'PartitionKey' = 'ManualEntry' + 'TenantId' = 'NoTenant' + 'MailProviders' = '' + 'TenantDetails' = '' + 'DomainAnalyser' = '' + 'DkimSelectors' = $DkimSelectors + } + } + Add-CIPPAzDataTableEntity @DomainTable -Entity $DomainInfo -Force + } + 'GetConfig' { + $body = [pscustomobject]$Config + Write-LogMessage -API $APINAME -tenant 'Global' -user $request.headers.'x-ms-client-principal' -message 'Retrieved DNS configuration' -Sev 'Info' + } + 'RemoveDomain' { + $Filter = "RowKey eq '{0}'" -f $Request.Query.Domain + $DomainRow = Get-CIPPAzDataTableEntity @DomainTable -Filter $Filter -Property PartitionKey, RowKey + Remove-AzDataTableEntity @DomainTable -Entity $DomainRow + Write-LogMessage -API $APINAME -tenant 'Global' -user $request.headers.'x-ms-client-principal' -message "Removed Domain - $($Request.Query.Domain) " -Sev 'Info' + $body = [pscustomobject]@{ 'Results' = "Domain removed - $($Request.Query.Domain)" } + } + } + } catch { + Write-LogMessage -API $APINAME -tenant $($name) -user $request.headers.'x-ms-client-principal' -message "DNS Config API failed. $($_.Exception.Message)" -Sev 'Error' + $body = [pscustomobject]@{'Results' = "Failed. $($_.Exception.Message)" } + $StatusCode = [HttpStatusCode]::BadRequest + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = $body + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecEditCalendarPermissions.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecEditCalendarPermissions.ps1 new file mode 100644 index 000000000000..f9737f7bb8ad --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecEditCalendarPermissions.ps1 @@ -0,0 +1,37 @@ +using namespace System.Net + +Function Invoke-ExecEditCalendarPermissions { + <# + .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' + $UserID = ($request.query.UserID) + $UserToGetPermissions = $Request.query.UserToGetPermissions + $Tenantfilter = $request.Query.tenantfilter + $Permissions = @($Request.query.permissions) + $folderName = $Request.query.folderName + + + try { + if ($Request.query.removeaccess) { + $result = Set-CIPPCalenderPermission -UserID $UserID -folderName $folderName -RemoveAccess $Request.query.removeaccess -TenantFilter $TenantFilter + } else { + $result = Set-CIPPCalenderPermission -UserID $UserID -folderName $folderName -TenantFilter $Tenantfilter -UserToGetPermissions $UserToGetPermissions -Permissions $Permissions + $Result = "Successfully set permissions on folder $($CalParam.Identity). The user $UserToGetPermissions now has $Permissions permissions on this folder." + } + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception + $Result = $ErrorMessage + } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @{Results = $Result } + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecEditMailboxPermissions.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecEditMailboxPermissions.ps1 new file mode 100644 index 000000000000..97200abfc763 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecEditMailboxPermissions.ps1 @@ -0,0 +1,116 @@ +using namespace System.Net + +Function Invoke-ExecEditMailboxPermissions { + <# + .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' + $Username = $request.body.userID + $Tenantfilter = $request.body.tenantfilter + if ($username -eq $null) { exit } + $userid = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($username)" -tenantid $Tenantfilter).id + $Results = [System.Collections.ArrayList]@() + + $RemoveFullAccess = ($Request.body.RemoveFullAccess).value + foreach ($RemoveUser in $RemoveFullAccess) { + try { + $MailboxPerms = New-ExoRequest -Anchor $username -tenantid $Tenantfilter -cmdlet 'Remove-mailboxpermission' -cmdParams @{Identity = $userid; user = $RemoveUser; accessRights = @('FullAccess'); } + $results.add("Removed $($removeuser) from $($username) Shared Mailbox permissions") + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME-message "Removed $($RemoveUser) from $($username) Shared Mailbox permission" -Sev 'Info' -tenant $TenantFilter + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME-message "Could not remove mailbox permissions for $($removeuser) on $($username)" -Sev 'Error' -tenant $TenantFilter + $results.add("Could not remove $($removeuser) shared mailbox permissions for $($username). Error: $($_.Exception.Message)") + } + } + $AddFullAccess = ($Request.body.AddFullAccess).value + + foreach ($UserAutomap in $AddFullAccess) { + try { + $MailboxPerms = New-ExoRequest -Anchor $username -tenantid $Tenantfilter -cmdlet 'Add-MailboxPermission' -cmdParams @{Identity = $userid; user = $UserAutomap; accessRights = @('FullAccess'); automapping = $true } + $results.add( "Granted $($UserAutomap) access to $($username) Mailbox with automapping") + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME-message "Granted $($UserAutomap) access to $($username) Mailbox with automapping" -Sev 'Info' -tenant $TenantFilter + + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME-message "Could not add mailbox permissions for $($UserAutomap) on $($username)" -Sev 'Error' -tenant $TenantFilter + $results.add( "Could not add $($UserAutomap) shared mailbox permissions for $($username). Error: $($_.Exception.Message)") + } + } + $AddFullAccessNoAutoMap = ($Request.body.AddFullAccessNoAutoMap).value + + foreach ($UserNoAutomap in $AddFullAccessNoAutoMap) { + try { + $MailboxPerms = New-ExoRequest -Anchor $username -tenantid $Tenantfilter -cmdlet 'Add-MailboxPermission' -cmdParams @{Identity = $userid; user = $UserNoAutomap; accessRights = @('FullAccess'); automapping = $false } + $results.add( "Granted $UserNoAutomap access to $($username) Mailbox without automapping") + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME-message "Granted $UserNoAutomap access to $($username) Mailbox without automapping" -Sev 'Info' -tenant $TenantFilter + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME-message "Could not add mailbox permissions for $($UserNoAutomap) on $($username)" -Sev 'Error' -tenant $TenantFilter + $results.add("Could not add $($UserNoAutomap) shared mailbox permissions for $($username). Error: $($_.Exception.Message)") + } + } + + $AddSendAS = ($Request.body.AddSendAs).value + + foreach ($UserSendAs in $AddSendAS) { + try { + $MailboxPerms = New-ExoRequest -Anchor $username -tenantid $Tenantfilter -cmdlet 'Add-RecipientPermission' -cmdParams @{Identity = $userid; Trustee = $UserSendAs; accessRights = @('SendAs') } + $results.add( "Granted $UserSendAs access to $($username) with Send As permissions") + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME-message "Granted $UserSendAs access to $($username) with Send As permissions" -Sev 'Info' -tenant $TenantFilter + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME-message "Could not add mailbox permissions for $($UserSendAs) on $($username)" -Sev 'Error' -tenant $TenantFilter + $results.add("Could not add $($UserSendAs) send-as permissions for $($username). Error: $($_.Exception.Message)") + } + } + + $RemoveSendAs = ($Request.body.RemoveSendAs).value + + foreach ($UserSendAs in $RemoveSendAs) { + try { + $MailboxPerms = New-ExoRequest -Anchor $username -tenantid $Tenantfilter -cmdlet 'Remove-RecipientPermission' -cmdParams @{Identity = $userid; Trustee = $UserSendAs; accessRights = @('SendAs') } + $results.add( "Removed $UserSendAs from $($username) with Send As permissions") + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME-message "Removed $UserSendAs from $($username) with Send As permissions" -Sev 'Info' -tenant $TenantFilter + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME-message "Could not remove mailbox permissions for $($UserSendAs) on $($username)" -Sev 'Error' -tenant $TenantFilter + $results.add("Could not remove $($UserSendAs) send-as permissions for $($username). Error: $($_.Exception.Message)") + } + } + + $AddSendOnBehalf = ($Request.body.AddSendOnBehalf).value + + foreach ($UserSendOnBehalf in $AddSendOnBehalf) { + try { + $MailboxPerms = New-ExoRequest -Anchor $username -tenantid $Tenantfilter -cmdlet 'Set-Mailbox' -cmdParams @{Identity = $userid; GrantSendonBehalfTo = @{'@odata.type' = '#Exchange.GenericHashTable'; add = $UserSendOnBehalf }; } + $results.add( "Granted $UserSendOnBehalf access to $($username) with Send On Behalf Permissions") + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME-message "Granted $UserSendOnBehalf access to $($username) with Send On Behalf Permissions" -Sev 'Info' -tenant $TenantFilter + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME-message "Could not add send on behalf permissions for $($UserSendOnBehalf) on $($username)" -Sev 'Error' -tenant $TenantFilter + $results.add("Could not add $($UserSendOnBehalf) send on behalf permissions for $($username). Error: $($_.Exception.Message)") + } + } + + $RemoveSendOnBehalf = ($Request.body.RemoveSendOnBehalf).value + + foreach ($UserSendOnBehalf in $RemoveSendOnBehalf) { + try { + $MailboxPerms = New-ExoRequest -Anchor $username -tenantid $Tenantfilter -cmdlet 'Set-Mailbox' -cmdParams @{Identity = $userid; GrantSendonBehalfTo = @{'@odata.type' = '#Exchange.GenericHashTable'; remove = $UserSendOnBehalf }; } + $results.add( "Removed $UserSendOnBehalf from $($username) Send on Behalf Permissions") + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME-message "Removed $UserSendOnBehalf from $($username) Send on Behalf Permissions" -Sev 'Info' -tenant $TenantFilter + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME-message "Could not Remove send on behalf permissions for $($UserSendOnBehalf) on $($username)" -Sev 'Error' -tenant $TenantFilter + $results.add("Could not remove $($UserSendOnBehalf) send on behalf permissions for $($username). Error: $($_.Exception.Message)") + } + } + + $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/Entrypoints/Invoke-ExecEditTemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecEditTemplate.ps1 new file mode 100644 index 000000000000..1be43b61462d --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecEditTemplate.ps1 @@ -0,0 +1,49 @@ +using namespace System.Net + +Function Invoke-ExecEditTemplate { + <# + .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' + + try { + $Table = Get-CippTable -tablename 'templates' + $Table.Force = $true + $guid = $request.body.guid + $JSON = $request.body | Select-Object * -ExcludeProperty GUID | ConvertTo-Json + $Type = $request.Query.Type + + if ($Type -eq 'IntuneTemplate') { + Write-Host 'Intune Template' + Write-Host '' + $RawJSON = $request.body | Select-Object * -ExcludeProperty displayName, description, type, GUID | ConvertTo-Json -Depth 10 -Compress + Set-CIPPIntuneTemplate -RawJSON $RawJSON -GUID $GUID -DisplayName $Request.body.displayName -Description $Request.body.description -templateType $Request.body.type + } else { + Add-CIPPAzDataTableEntity @Table -Entity @{ + JSON = "$JSON" + RowKey = "$GUID" + PartitionKey = "$Type" + GUID = "$GUID" + } + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Edited template $($Request.body.name) with GUID $GUID" -Sev 'Debug' + } + $body = [pscustomobject]@{ 'Results' = 'Successfully saved the template' } + + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to edit template: $($_.Exception.Message)" -Sev 'Error' + $body = [pscustomobject]@{'Results' = "Editing template failed: $($_.Exception.Message)" } + } + + + # 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/Entrypoints/Invoke-ExecEmailForward.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecEmailForward.ps1 new file mode 100644 index 000000000000..f9b05a8f662a --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecEmailForward.ps1 @@ -0,0 +1,73 @@ +using namespace System.Net + +Function Invoke-ExecEmailForward { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $Tenantfilter = $request.body.tenantfilter + $username = $request.body.userid + $ForwardingAddress = $request.body.ForwardInternal.value + $ForwardingSMTPAddress = $request.body.ForwardExternal + $DisableForwarding = $request.body.disableForwarding + $APIName = $TriggerMetadata.FunctionName + + if ($ForwardingAddress) { + try { + New-ExoRequest -tenantid $TenantFilter -cmdlet 'Set-mailbox' -cmdParams @{Identity = $Username; ForwardingAddress = $ForwardingAddress ; DeliverToMailboxAndForward = [bool]$request.body.keepCopy } -Anchor $username + if (-not $request.body.KeepCopy) { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Set Forwarding for $($username) to $($ForwardingAddress) and not keeping a copy" -Sev 'Info' -tenant $TenantFilter + $results = "Forwarding all email for $($username) to $($ForwardingAddress) and not keeping a copy" + } elseif ($request.body.KeepCopy) { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Set Forwarding for $($username) to $($ForwardingAddress) and keeping a copy" -Sev 'Info' -tenant $TenantFilter + $results = "Forwarding all email for $($username) to $($ForwardingAddress) and keeping a copy" + } + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Could not add forwarding for $($username)" -Sev 'Error' -tenant $TenantFilter + $results = "Could not add forwarding for $($username). Error: $($_.Exception.Message)" + + } + } + + elseif ($ForwardingSMTPAddress) { + try { + New-ExoRequest -tenantid $TenantFilter -cmdlet 'Set-mailbox' -cmdParams @{Identity = $Username; ForwardingSMTPAddress = $ForwardingSMTPAddress ; DeliverToMailboxAndForward = [bool]$request.body.keepCopy } -Anchor $username + if (-not $request.body.KeepCopy) { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Set forwarding for $($username) to $($ForwardingSMTPAddress) and not keeping a copy" -Sev 'Info' -tenant $TenantFilter + $results = "Forwarding all email for $($username) to $($ForwardingSMTPAddress) and not keeping a copy" + } elseif ($request.body.KeepCopy) { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Set forwarding for $($username) to $($ForwardingSMTPAddress) and keeping a copy" -Sev 'Info' -tenant $TenantFilter + $results = "Forwarding all email for $($username) to $($ForwardingSMTPAddress) and keeping a copy" + } + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Could not add forwarding for $($username)" -Sev 'Error' -tenant $TenantFilter + $results = "Could not add forwarding for $($username). Error: $($_.Exception.Message)" + + } + + } + + elseif ($DisableForwarding -eq 'True') { + try { + New-ExoRequest -tenantid $TenantFilter -cmdlet 'Set-Mailbox' -cmdParams @{Identity = $Username; ForwardingAddress = $null; ForwardingSMTPAddress = $null; DeliverToMailboxAndForward = $false } + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Disabled Email forwarding for $($username)" -Sev 'Info' -tenant $TenantFilter + $results = "Disabled Email Forwarding for $($username)" + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Could not disable Email forwarding for $($username)" -Sev 'Error' -tenant $TenantFilter + $results = "Could not disable Email forwarding for $($username). Error: $($_.Exception.Message)" + + } + } + + $Body = @{'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/Entrypoints/Invoke-ExecEnableArchive.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecEnableArchive.ps1 new file mode 100644 index 000000000000..ac4cf5f8686b --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecEnableArchive.ps1 @@ -0,0 +1,32 @@ +using namespace System.Net + +Function Invoke-ExecEnableArchive { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + + # Interact with query parameters or the body of the request. + Try { + $ResultsArch = Set-CIPPMailboxArchive -userid $Request.query.id -tenantFilter $Request.query.TenantFilter -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' -ArchiveEnabled $true + $Results = [pscustomobject]@{'Results' = "$ResultsArch" } + } 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 + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecExcludeLicenses.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecExcludeLicenses.ps1 new file mode 100644 index 000000000000..c20795dcb97c --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecExcludeLicenses.ps1 @@ -0,0 +1,71 @@ +using namespace System.Net + +Function Invoke-ExecExcludeLicenses { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + $Table = Get-CIPPTable -TableName ExcludedLicenses + try { + + if ($Request.Query.List) { + $Rows = Get-CIPPAzDataTableEntity @Table + if ($Rows.Count -lt 1) { + $TableBaseData = '[{"GUID":"16ddbbfc-09ea-4de2-b1d7-312db6112d70","Product_Display_Name":"MICROSOFT TEAMS (FREE)"},{"GUID":"1f2f344a-700d-42c9-9427-5cea1d5d7ba6","Product_Display_Name":"MICROSOFT STREAM"},{"GUID":"338148b6-1b11-4102-afb9-f92b6cdc0f8d","Product_Display_Name":"DYNAMICS 365 P1 TRIAL FOR INFORMATION WORKERS"},{"GUID":"606b54a9-78d8-4298-ad8b-df6ef4481c80","Product_Display_Name":"Power Virtual Agents Viral Trial"},{"GUID":"61e6bd70-fbdb-4deb-82ea-912842f39431","Product_Display_Name":"Dynamics 365 Customer Service Insights Trial"},{"GUID":"6470687e-a428-4b7a-bef2-8a291ad947c9","Product_Display_Name":"WINDOWS STORE FOR BUSINESS"},{"GUID":"710779e8-3d4a-4c88-adb9-386c958d1fdf","Product_Display_Name":"MICROSOFT TEAMS EXPLORATORY"},{"GUID":"74fbf1bb-47c6-4796-9623-77dc7371723b","Product_Display_Name":"Microsoft Teams Trial"},{"GUID":"90d8b3f8-712e-4f7b-aa1e-62e7ae6cbe96","Product_Display_Name":"Business Apps (free)"},{"GUID":"a403ebcc-fae0-4ca2-8c8c-7a907fd6c235","Product_Display_Name":"Power BI (free)"},{"GUID":"bc946dac-7877-4271-b2f7-99d2db13cd2c","Product_Display_Name":"Dynamics 365 Customer Voice Trial"},{"GUID":"dcb1a3ae-b33f-4487-846a-a640262fadf4","Product_Display_Name":"Microsoft Power Apps Plan 2 Trial"},{"GUID":"f30db892-07e9-47e9-837c-80727f46fd3d","Product_Display_Name":"MICROSOFT FLOW FREE"},{"GUID":"fcecd1f9-a91e-488d-a918-a96cdb6ce2b0","Product_Display_Name":"Microsoft Dynamics AX7 User Trial"}]' | ConvertFrom-Json -AsHashtable -Depth 10 + $TableRows = foreach ($Row in $TableBaseData) { + $Row.PartitionKey = 'License' + $Row.RowKey = $Row.GUID + + Add-CIPPAzDataTableEntity @Table -Entity ([pscustomobject]$Row) -Force | Out-Null + } + + $Rows = Get-CIPPAzDataTableEntity @Table + + Write-LogMessage -API $APINAME -user $request.headers.'x-ms-client-principal' -message 'got excluded licenses list' -Sev 'Info' + } + $body = @($Rows) + } + + # Interact with query parameters or the body of the request. + $name = $Request.Query.TenantFilter + if ($Request.Query.AddExclusion) { + $AddObject = @{ + PartitionKey = 'License' + RowKey = $Request.body.GUID + 'GUID' = $Request.body.GUID + 'Product_Display_Name' = $request.body.SKUName + } + Add-CIPPAzDataTableEntity @Table -Entity $AddObject -Force + + Write-LogMessage -API $APINAME -user $request.headers.'x-ms-client-principal' -message "Added exclusion $($request.body.SKUName)" -Sev 'Info' + $body = [pscustomobject]@{'Results' = "Success. We've added $($request.body.SKUName) to the excluded list." } + } + + if ($Request.Query.RemoveExclusion) { + $Filter = "RowKey eq '{0}' and PartitionKey eq 'License'" -f $Request.Query.Guid + $Entity = Get-CIPPAzDataTableEntity @Table -Filter $Filter -Property PartitionKey, RowKey + Remove-AzDataTableEntity @Table -Entity $Entity + Write-LogMessage -API $APINAME -user $request.headers.'x-ms-client-principal' -message "Removed exclusion $($Request.Query.GUID)" -Sev 'Info' + $body = [pscustomobject]@{'Results' = "Success. We've removed $($Request.query.guid) from the excluded list." } + } + } catch { + Write-LogMessage -API $APINAME -user $request.headers.'x-ms-client-principal' -message "Exclusion API failed. $($_.Exception.Message)" -Sev 'Error' + $body = [pscustomobject]@{'Results' = "Failed. $($_.Exception.Message)" } + } + + # 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/Entrypoints/Invoke-ExecExcludeTenant.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecExcludeTenant.ps1 new file mode 100644 index 000000000000..ca63f9f20afa --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecExcludeTenant.ps1 @@ -0,0 +1,71 @@ +using namespace System.Net + +Function Invoke-ExecExcludeTenant { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + 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.' + $user = $request.headers.'x-ms-client-principal' + $username = ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($user)) | ConvertFrom-Json).userDetails + $date = (Get-Date).tostring('yyyy-MM-dd') + $TenantsTable = Get-CippTable -tablename Tenants + + if ($Request.Query.List) { + $ExcludedFilter = "PartitionKey eq 'Tenants' and Excluded eq true" + $ExcludedTenants = Get-CIPPAzDataTableEntity @TenantsTable -Filter $ExcludedFilter + Write-LogMessage -API $APINAME -user $request.headers.'x-ms-client-principal' -message 'got excluded tenants list' -Sev 'Info' + $body = @($ExcludedTenants) + } elseif ($Request.query.ListAll) { + $ExcludedTenants = Get-CIPPAzDataTableEntity @TenantsTable -filter "PartitionKey eq 'Tenants'" + Write-LogMessage -API $APINAME -user $request.headers.'x-ms-client-principal' -message 'got excluded tenants list' -Sev 'Info' + $body = @($ExcludedTenants) + } + try { + # Interact with query parameters or the body of the request. + $name = $Request.Query.TenantFilter + if ($Request.Query.AddExclusion) { + $Tenants = Get-Tenants -IncludeAll | Where-Object { $Request.body.value -contains $_.customerId } + + $Excluded = foreach ($Tenant in $Tenants) { + $Tenant.Excluded = $true + $Tenant.ExcludeUser = $username + $Tenant.ExcludeDate = $date + $Tenant + } + Write-Host ($Excluded | ConvertTo-Json) + Update-AzDataTableEntity @TenantsTable -Entity ([pscustomobject]$Excluded) + #Remove-CIPPCache + Write-LogMessage -API $APINAME -tenant $($name) -user $request.headers.'x-ms-client-principal' -message "Added exclusion for customer(s): $($Excluded.defaultDomainName -join ',')" -Sev 'Info' + $body = [pscustomobject]@{'Results' = "Success. Added exclusions for customer(s): $($Excluded.defaultDomainName -join ',')" } + } + + if ($Request.Query.RemoveExclusion) { + $Filter = "PartitionKey eq 'Tenants' and defaultDomainName eq '{0}'" -f $name + $Tenant = Get-CIPPAzDataTableEntity @TenantsTable -Filter $Filter + $Tenant.Excluded = $false + $Tenant.ExcludeUser = '' + $Tenant.ExcludeDate = '' + Update-AzDataTableEntity @TenantsTable -Entity $Tenant + #Remove-CIPPCache + Write-LogMessage -API $APINAME -tenant $($name) -user $request.headers.'x-ms-client-principal' -message "Removed exclusion for customer $($name)" -Sev 'Info' + $body = [pscustomobject]@{'Results' = "Success. We've removed $name from the excluded tenants." } + } + } catch { + Write-LogMessage -API $APINAME -tenant $($name) -user $request.headers.'x-ms-client-principal' -message "Exclusion API failed. $($_.Exception.Message)" -Sev 'Error' + $body = [pscustomobject]@{'Results' = "Failed. $($_.Exception.Message)" } + } + if (!$body) { $body = @() } + + # 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/Entrypoints/Invoke-ExecExtensionMapping.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecExtensionMapping.ps1 new file mode 100644 index 000000000000..1e4c8c8677e3 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecExtensionMapping.ps1 @@ -0,0 +1,81 @@ + using namespace System.Net + + Function Invoke-ExecExtensionMapping { + <# + .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' + + +# Write to the Azure Functions log stream. +Write-Host 'PowerShell HTTP trigger function processed a request.' +$Table = Get-CIPPTable -TableName CippMapping + +if ($Request.Query.List) { + switch ($Request.Query.List) { + 'Halo' { + $body = Get-HaloMapping -CIPPMapping $Table + } + + 'NinjaOrgs' { + $Body = Get-NinjaOneOrgMapping -CIPPMapping $Table + } + + 'NinjaFields' { + $Body = Get-NinjaOneFieldMapping -CIPPMapping $Table + + } + } +} + +try { + if ($Request.Query.AddMapping) { + switch ($Request.Query.AddMapping) { + 'Halo' { + $body = Set-HaloMapping -CIPPMapping $Table -APIName $APIName -Request $Request + } + + 'NinjaOrgs' { + $Body = Set-NinjaOneOrgMapping -CIPPMapping $Table -APIName $APIName -Request $Request + } + + 'NinjaFields' { + $Body = Set-NinjaOneFieldMapping -CIPPMapping $Table -APIName $APIName -Request $Request -TriggerMetadata $TriggerMetadata + } + } + } +} +catch { + Write-LogMessage -API $APINAME -user $request.headers.'x-ms-client-principal' -message "mapping API failed. $($_.Exception.Message)" -Sev 'Error' + $body = [pscustomobject]@{'Results' = "Failed. $($_.Exception.Message)" } +} + +try { + if ($Request.Query.AutoMapping) { + switch ($Request.Query.AutoMapping) { + 'NinjaOrgs' { + Push-OutputBinding -Name NinjaProcess -Value @{'NinjaAction' = 'StartAutoMapping' } + $Body = [pscustomobject]@{'Results' = 'Automapping Request has been queued. Exact name matches will appear first and matches on device names and serials will take longer. Please check the CIPP Logbook and refresh the page once complete.' } + } + + + } + } +} +catch { + Write-LogMessage -API $APINAME -user $request.headers.'x-ms-client-principal' -message "mapping API failed. $($_.Exception.Message)" -Sev 'Error' + $body = [pscustomobject]@{'Results' = "Failed. $($_.Exception.Message)" } +} + +# 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/Entrypoints/Invoke-ExecExtensionNinjaOneQueue.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecExtensionNinjaOneQueue.ps1 new file mode 100644 index 000000000000..3f78672c9894 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecExtensionNinjaOneQueue.ps1 @@ -0,0 +1,19 @@ +using namespace System.Net + +Function Invoke-ExecExtensionNinjaOneQueue { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + + + Switch ($QueueItem.NinjaAction) { + 'StartAutoMapping' { Invoke-NinjaOneOrgMapping } + 'AutoMapTenant' { Invoke-NinjaOneOrgMappingTenant -QueueItem $QueueItem } + 'SyncTenant' { Invoke-NinjaOneTenantSync -QueueItem $QueueItem } + } + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecExtensionSync.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecExtensionSync.ps1 new file mode 100644 index 000000000000..38f050341aed --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecExtensionSync.ps1 @@ -0,0 +1,76 @@ +using namespace System.Net + +Function Invoke-ExecExtensionSync { + <# + .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 ($Request.Query.Extension -eq 'Gradient') { + try { + Write-LogMessage -API 'Scheduler_Billing' -tenant 'none' -message 'Starting billing processing.' -sev Info + $Table = Get-CIPPTable -TableName Extensionsconfig + $Configuration = (Get-CIPPAzDataTableEntity @Table).config | ConvertFrom-Json -Depth 10 + foreach ($ConfigItem in $Configuration.psobject.properties.name) { + switch ($ConfigItem) { + 'Gradient' { + If ($Configuration.Gradient.enabled -and $Configuration.Gradient.BillingEnabled) { + Push-OutputBinding -Name gradientqueue -Value 'LetsGo' + $Results = [pscustomobject]@{'Results' = 'Succesfully started Gradient Sync' } + } + } + } + } + } catch { + $Results = [pscustomobject]@{'Results' = "Could not start Gradient Sync: $($_.Exception.Message)" } + + Write-LogMessage -API 'Scheduler_Billing' -tenant 'none' -message "Could not start billing processing $($_.Exception.Message)" -sev Error + } + } + + if ($Request.Query.Extension -eq 'NinjaOne') { + try { + $Table = Get-CIPPTable -TableName NinjaOneSettings + + $CIPPMapping = Get-CIPPTable -TableName CippMapping + $Filter = "PartitionKey eq 'NinjaOrgsMapping'" + $TenantsToProcess = Get-AzDataTableEntity @CIPPMapping -Filter $Filter | Where-Object { $Null -ne $_.NinjaOne -and $_.NinjaOne -ne '' } + + foreach ($Tenant in $TenantsToProcess) { + Push-OutputBinding -Name NinjaProcess -Value @{ + 'NinjaAction' = 'SyncTenant' + 'MappedTenant' = $Tenant + } + + } + + $AddObject = @{ + PartitionKey = 'NinjaConfig' + RowKey = 'NinjaLastRunTime' + 'SettingValue' = (Get-Date).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ss.fffK') + } + + Add-AzDataTableEntity @Table -Entity $AddObject -Force + + Write-LogMessage -API 'NinjaOneAutoMap_Queue' -user 'CIPP' -message "NinjaOne Synchronization Queued for $(($TenantsToProcess | Measure-Object).count) Tenants" -Sev 'Info' + + $Results = [pscustomobject]@{'Results' = "NinjaOne Synchronization Queued for $(($TenantsToProcess | Measure-Object).count) Tenants" } + } catch { + $Results = [pscustomobject]@{'Results' = "Could not start NinjaOne Sync: $($_.Exception.Message)" } + Write-LogMessage -API 'Scheduler_Billing' -tenant 'none' -message "Could not start NinjaOne Sync $($_.Exception.Message)" -sev Error + } + + } + + + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Results + }) -clobber + +} diff --git a/ExecExtensionTest/run.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecExtensionTest.ps1 similarity index 78% rename from ExecExtensionTest/run.ps1 rename to Modules/CIPPCore/Public/Entrypoints/Invoke-ExecExtensionTest.ps1 index 32ed9300eb52..afbdfacc402c 100644 --- a/ExecExtensionTest/run.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecExtensionTest.ps1 @@ -1,9 +1,14 @@ -using namespace System.Net + using namespace System.Net -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) + Function Invoke-ExecExtensionTest { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) -$APIName = $TriggerMetadata.FunctionName + $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Accessed this API" -Sev "Debug" $Table = Get-CIPPTable -TableName Extensionsconfig $Configuration = ((Get-CIPPAzDataTableEntity @Table).config | ConvertFrom-Json) @@ -12,7 +17,7 @@ try { switch ($Request.query.extensionName) { "HaloPSA" { $token = Get-HaloToken -configuration $Configuration.HaloPSA - $Results = [pscustomobject]@{"Results" = "Succesfully Connected to HaloPSA" } + $Results = [pscustomobject]@{"Results" = "Successfully Connected to HaloPSA" } } "Gradient" { $GradientToken = Get-GradientToken -Configuration $Configuration.Gradient @@ -26,6 +31,10 @@ try { "CIPP-API" { $Results = [pscustomobject]@{"Results" = "You cannot test the CIPP-API from CIPP. Please check the documentation on how to test the CIPP-API." } } + "NinjaOne" { + $token = Get-NinjaOneToken -configuration $Configuration.NinjaOne + $Results = [pscustomobject]@{"Results" = "Succesfully Connected to NinjaOne" } + } } } catch { @@ -36,4 +45,6 @@ catch { Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK Body = $Results - }) \ No newline at end of file + }) + + } diff --git a/ExecExtensionsConfig/run.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecExtensionsConfig.ps1 similarity index 69% rename from ExecExtensionsConfig/run.ps1 rename to Modules/CIPPCore/Public/Entrypoints/Invoke-ExecExtensionsConfig.ps1 index 3e2291063751..fd9725fe5ff9 100644 --- a/ExecExtensionsConfig/run.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecExtensionsConfig.ps1 @@ -1,9 +1,14 @@ -using namespace System.Net + using namespace System.Net -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) + Function Invoke-ExecExtensionsConfig { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) -$APIName = $TriggerMetadata.FunctionName + $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' #Connect-AzAccount -UseDeviceAuthentication @@ -14,13 +19,25 @@ $results = try { $APIConfig = New-CIPPAPIConfig -ExecutingUser $request.headers.'x-ms-client-principal' -resetpassword $request.body.CIPPAPI.ResetPassword $AddedText = $APIConfig.Results } + + # Check if NinjaOne URL is set correctly and the intance has at least version 5.6 + if ($request.body.NinjaOne) { + try { + [version]$Version = (Invoke-WebRequest -Method GET -Uri "https://$($request.body.NinjaOne.Instance -replace '/ws','')/app-version.txt" -ea stop).content + } catch { + throw "Failed to connect to NinjaOne check your Instance is set correctly eg 'app.ninjarmmm.com'" + } + if ($Version -lt [version]'5.6.0.0') { + throw "NinjaOne 5.6.0.0 is required. This will be rolling out regionally between the end of November and mid-December. Please try again at a later date." + } + } + $Table = Get-CIPPTable -TableName Extensionsconfig foreach ($APIKey in ([pscustomobject]$request.body).psobject.properties.name) { Write-Host "Working on $apikey" if ($request.body.$APIKey.APIKey -eq "SentToKeyVault" -or $request.body.$APIKey.APIKey -eq "") { Write-Host "Not sending to keyvault. Key previously set or left blank." - } - else { + } else { Write-Host "writing API Key to keyvault, and clearing." Write-Host "$ENV:WEBSITE_DEPLOYMENT_ID" if ($request.body.$APIKey.APIKey) { @@ -38,8 +55,7 @@ $results = try { Add-CIPPAzDataTableEntity @Table -Entity $Config -Force | Out-Null "Successfully set the configuration. $AddedText" -} -catch { +} catch { "Failed to set configuration: $($_.Exception.message) Linenumber: $($_.InvocationInfo.ScriptLineNumber)" } @@ -51,3 +67,5 @@ Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK Body = $body }) + + } diff --git a/ExecGDAPInvite/run.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecGDAPInvite.ps1 similarity index 92% rename from ExecGDAPInvite/run.ps1 rename to Modules/CIPPCore/Public/Entrypoints/Invoke-ExecGDAPInvite.ps1 index a7b48f56a7d2..050a162ebd6f 100644 --- a/ExecGDAPInvite/run.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecGDAPInvite.ps1 @@ -1,9 +1,14 @@ -using namespace System.Net + using namespace System.Net -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) + Function Invoke-ExecGDAPInvite { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) -$APIName = $TriggerMetadata.FunctionName + $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' $RoleMappings = $Request.body.gdapRoles @@ -75,4 +80,6 @@ $body = @{ Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK Body = $body - }) \ No newline at end of file + }) + + } diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecGDAPInviteApproved.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecGDAPInviteApproved.ps1 new file mode 100644 index 000000000000..23565a19602e --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecGDAPInviteApproved.ps1 @@ -0,0 +1,22 @@ +using namespace System.Net + +Function Invoke-ExecGDAPInviteApproved { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' + + Set-CIPPGDAPInviteGroups + + $body = @{Results = @('Processing recently activated GDAP relationships') } + + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $body + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecGDAPInviteQueue.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecGDAPInviteQueue.ps1 new file mode 100644 index 000000000000..60d7ddbb29d2 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecGDAPInviteQueue.ps1 @@ -0,0 +1,42 @@ +using namespace System.Net + +Function Invoke-ExecGDAPInviteQueue { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + #$TenantFilter = $env:TenantID + + $Table = Get-CIPPTable -TableName 'GDAPInvites' + $Invite = Get-CIPPAzDataTableEntity @Table -Filter "RowKey eq '$QueueItem'" + $APINAME = 'GDAPInvites' + $RoleMappings = $Invite.RoleMappings | ConvertFrom-Json + Write-Host ($Invite | ConvertTo-Json -Compress) + + foreach ($role in $RoleMappings) { + try { + $Mappingbody = ConvertTo-Json -Depth 10 -InputObject @{ + 'accessContainer' = @{ + 'accessContainerId' = "$($Role.GroupId)" + 'accessContainerType' = 'securityGroup' + } + 'accessDetails' = @{ + 'unifiedRoles' = @(@{ + 'roleDefinitionId' = "$($Role.roleDefinitionId)" + }) + } + } + New-GraphPostRequest -NoAuthCheck $True -uri "https://graph.microsoft.com/beta/tenantRelationships/delegatedAdminRelationships/$($QueueItem)/accessAssignments" -tenantid $env:TenantID -type POST -body $MappingBody -verbose + Start-Sleep -Milliseconds 100 + } catch { + Write-LogMessage -API $APINAME -message "GDAP Group mapping failed - $($role.GroupId): $($_.Exception.Message)" -Sev Error + exit 1 + } + Write-LogMessage -API $APINAME -message "Groups mapped for GDAP Relationship: $($GdapInvite.RowKey)" -Sev Info + } + Remove-AzDataTableEntity @Table -Entity $Invite + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecGDAPMigration.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecGDAPMigration.ps1 new file mode 100644 index 000000000000..7b5ce0a31a1d --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecGDAPMigration.ps1 @@ -0,0 +1,33 @@ +using namespace System.Net + +Function Invoke-ExecGDAPMigration { + <# + .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' + + $Groups = $Request.body.gdapRoles + $Tenants = $Request.body.selectedTenants + $Results = [System.Collections.ArrayList]@() + + foreach ($Tenant in $Tenants) { + $obj = [PSCustomObject]@{ + tenant = $Tenant + gdapRoles = $Groups + } + Push-OutputBinding -Name gdapqueue -Value $obj + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Started GDAP Migration for $($tenant.displayName)" -Sev 'Debug' + $results.add("Started GDAP Migration for $($tenant.displayName)") | Out-Null + } + $body = @{Results = @($Results) } + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $body + }) + +} diff --git a/ExecGDAPMigrationQueue/run.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecGDAPMigrationQueue.ps1 similarity index 94% rename from ExecGDAPMigrationQueue/run.ps1 rename to Modules/CIPPCore/Public/Entrypoints/Invoke-ExecGDAPMigrationQueue.ps1 index a76f06393028..bb59a42fed9c 100644 --- a/ExecGDAPMigrationQueue/run.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecGDAPMigrationQueue.ps1 @@ -1,9 +1,14 @@ -# Input bindings are passed in via param block. -param( $QueueItem, $TriggerMetadata) + using namespace System.Net -# Write out the queue message and metadata to the information log. -Write-Host "PowerShell queue trigger function processed work item: $QueueItem" -#$TenantFilter = $env:TenantID + Function Invoke-ExecGDAPMigrationQueue { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + #$TenantFilter = $env:TenantID $RoleMappings = $QueueItem.gdapRoles $tenant = $queueitem.tenant $Table = Get-CIPPTable -TableName 'gdapmigration' @@ -90,3 +95,5 @@ if ($CheckActive.status -eq 'Active') { } + + } diff --git a/ExecGeoIPLookup/run.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecGeoIPLookup.ps1 similarity index 79% rename from ExecGeoIPLookup/run.ps1 rename to Modules/CIPPCore/Public/Entrypoints/Invoke-ExecGeoIPLookup.ps1 index 27ec9a354887..ebd5cab52f88 100644 --- a/ExecGeoIPLookup/run.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecGeoIPLookup.ps1 @@ -1,9 +1,14 @@ -using namespace System.Net + using namespace System.Net -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) + Function Invoke-ExecGeoIPLookup { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) -$APIName = $TriggerMetadata.FunctionName + $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 @@ -22,3 +27,5 @@ Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK Body = $LocationInfo }) + + } diff --git a/ExecGetLocalAdminPassword/run.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecGetLocalAdminPassword.ps1 similarity index 71% rename from ExecGetLocalAdminPassword/run.ps1 rename to Modules/CIPPCore/Public/Entrypoints/Invoke-ExecGetLocalAdminPassword.ps1 index 3050065feaec..c58267717c20 100644 --- a/ExecGetLocalAdminPassword/run.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecGetLocalAdminPassword.ps1 @@ -1,9 +1,14 @@ -using namespace System.Net + using namespace System.Net -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) + Function Invoke-ExecGetLocalAdminPassword { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) -$APIName = $TriggerMetadata.FunctionName + $APIName = $TriggerMetadata.FunctionName try { $GraphRequest = Get-CIPPLapsPassword -device $($request.query.guid) -tenantFilter $Request.Query.TenantFilter -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' @@ -21,3 +26,5 @@ Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK Body = $Body }) + + } diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecGetRecoveryKey.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecGetRecoveryKey.ps1 new file mode 100644 index 000000000000..7190225450a5 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecGetRecoveryKey.ps1 @@ -0,0 +1,36 @@ +using namespace System.Net + +Function Invoke-ExecGetRecoveryKey { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + try { + $GraphRequest = Get-CIPPBitlockerKey -device $Request.query.GUID -tenantFilter $TenantFilter -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' + $Body = [pscustomobject]@{'Results' = $GraphRequest } + + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $Body = [pscustomobject]@{'Results' = "Failed. $ErrorMessage" } + + } + + # 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/Entrypoints/Invoke-ExecGraphRequest.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecGraphRequest.ps1 new file mode 100644 index 000000000000..7ebe9d3aa714 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecGraphRequest.ps1 @@ -0,0 +1,111 @@ +using namespace System.Net + +Function Invoke-ExecGraphRequest { + <# + .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' + + Function ConvertTo-FlatObject { + # https://evotec.xyz/powershell-converting-advanced-object-to-flat-object/ - MIT License + [CmdletBinding()] + Param ( + [Parameter(ValueFromPipeLine)][Object[]]$Objects, + [String]$Separator = '.', + [ValidateSet('', 0, 1)]$Base = 1, + [int]$Depth = 5, + [Parameter(DontShow)][String[]]$Path, + [Parameter(DontShow)][System.Collections.IDictionary] $OutputObject + ) + Begin { + $InputObjects = [System.Collections.Generic.List[Object]]::new() + } + Process { + foreach ($O in $Objects) { + $InputObjects.Add($O) + } + } + End { + If ($PSBoundParameters.ContainsKey('OutputObject')) { + $Object = $InputObjects[0] + $Iterate = [ordered] @{} + if ($null -eq $Object) { + #Write-Verbose -Message "ConvertTo-FlatObject - Object is null" + } elseif ($Object.GetType().Name -in 'String', 'DateTime', 'TimeSpan', 'Version', 'Enum') { + $Object = $Object.ToString() + } elseif ($Depth) { + $Depth-- + If ($Object -is [System.Collections.IDictionary]) { + $Iterate = $Object + } elseif ($Object -is [Array] -or $Object -is [System.Collections.IEnumerable]) { + $i = $Base + foreach ($Item in $Object.GetEnumerator()) { + $Iterate["$i"] = $Item + $i += 1 + } + } else { + foreach ($Prop in $Object.PSObject.Properties) { + if ($Prop.IsGettable) { + $Iterate["$($Prop.Name)"] = $Object.$($Prop.Name) + } + } + } + } + If ($Iterate.Keys.Count) { + foreach ($Key in $Iterate.Keys) { + ConvertTo-FlatObject -Objects @(, $Iterate["$Key"]) -Separator $Separator -Base $Base -Depth $Depth -Path ($Path + $Key) -OutputObject $OutputObject + } + } else { + $Property = $Path -Join $Separator + $OutputObject[$Property] = $Object + } + } elseif ($InputObjects.Count -gt 0) { + foreach ($ItemObject in $InputObjects) { + $OutputObject = [ordered]@{} + ConvertTo-FlatObject -Objects @(, $ItemObject) -Separator $Separator -Base $Base -Depth $Depth -Path $Path -OutputObject $OutputObject + [PSCustomObject] $OutputObject + } + } + } + } + $TenantFilter = $Request.Query.TenantFilter + try { + if ($TenantFilter -ne 'AllTenants') { + $RawGraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/$($Request.Query.Endpoint)" -tenantid $TenantFilter -NoPagination [boolean]$Request.query.DisablePagination -ComplexFilter + } else { + $RawGraphRequest = Get-Tenants | ForEach-Object -Parallel { + Import-Module '.\Modules\AzBobbyTables' + Import-Module '.\Modules\CIPPCore' + try { + $DefaultDomainName = $_.defaultDomainName + $TenantName = $_.displayName + New-GraphGetRequest -uri "https://graph.microsoft.com/beta/$($using:Request.Query.Endpoint)" -tenantid $DefaultDomainName -NoPagination [boolean]$using:Request.query.DisablePagination -ComplexFilter | Select-Object @{ + label = 'Tenant' + expression = { $TenantName } + }, * + } catch { + continue + } + } + + } + $GraphRequest = $RawGraphRequest | Where-Object -Property '@odata.context' -EQ $null | ConvertTo-FlatObject + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $StatusCode = [HttpStatusCode]::Forbidden + $GraphRequest = $ErrorMessage + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @($GraphRequest) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecGroupsDelete.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecGroupsDelete.ps1 new file mode 100644 index 000000000000..c4f5be9d67f7 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecGroupsDelete.ps1 @@ -0,0 +1,32 @@ +using namespace System.Net + +Function Invoke-ExecGroupsDelete { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + + # Interact with query parameters or the body of the request. + Try { + $RemoveResults = Remove-CIPPGroup -ID $Request.query.id -GroupType $Request.query.GroupType -tenantFilter $Request.query.TenantFilter -displayName $Request.query.displayName -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' + $Results = [pscustomobject]@{'Results' = $RemoveResults } + } 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 + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecGroupsDeliveryManagement.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecGroupsDeliveryManagement.ps1 new file mode 100644 index 000000000000..d77c8a56d6e7 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecGroupsDeliveryManagement.ps1 @@ -0,0 +1,33 @@ +using namespace System.Net + +Function Invoke-ExecGroupsDeliveryManagement { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + + # Interact with query parameters or the body of the request. + Try { + $SetResults = Set-CIPPGroupAuthentication -ID $Request.query.id -GroupType $Request.query.GroupType -OnlyAllowInternalString $Request.query.OnlyAllowInternal -tenantFilter $Request.query.TenantFilter -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' + $Results = [pscustomobject]@{'Results' = $SetResults } + } catch { + $Results = [pscustomobject]@{'Results' = "Failed. $($_.Exception.Message)" } + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantfilter) -message "Delivery Management failed: $($_.Exception.Message)" -Sev 'Error' + } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Results + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecGroupsHideFromGAL.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecGroupsHideFromGAL.ps1 new file mode 100644 index 000000000000..6307f2ef898d --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecGroupsHideFromGAL.ps1 @@ -0,0 +1,28 @@ +using namespace System.Net + +Function Invoke-ExecGroupsHideFromGAL { + <# + .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' + + # Interact with query parameters or the body of the request. + Try { + $GroupStatus = Set-CIPPGroupGAL -Id $Request.query.id -tenantFilter $Request.query.TenantFilter -GroupType $Request.query.groupType -HiddenString $Request.query.HidefromGAL -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' + $Results = [pscustomobject]@{'Results' = $GroupStatus } + } catch { + $Results = [pscustomobject]@{'Results' = "Failed. $($_.Exception.Message)" } + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantfilter) -message "Hide/UnHide from GAL failed: $($_.Exception.Message)" -Sev 'Error' + } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Results + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecHideFromGAL.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecHideFromGAL.ps1 new file mode 100644 index 000000000000..787bdd798e36 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecHideFromGAL.ps1 @@ -0,0 +1,31 @@ +using namespace System.Net + +Function Invoke-ExecHideFromGAL { + <# + .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' + + + $TenantFilter = $request.query.tenantfilter + Try { + $Hidden = [System.Convert]::ToBoolean($Request.query.HideFromGal) + $HideResults = Set-CIPPHideFromGAL -tenantFilter $tenantFilter -userid $Request.query.ID -HideFromGAL $Hidden -ExecutingUser $request.headers.'x-ms-client-principal' -APIName 'ExecOffboardUser' + $Results = [pscustomobject]@{'Results' = $HideResults } + + } catch { + $Results = [pscustomobject]@{'Results' = "Failed. $($_.Exception.Message)" } + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantfilter) -message "Hide/UnHide from GAL failed: $($_.Exception.Message)" -Sev 'Error' + } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Results + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecIncidentsList.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecIncidentsList.ps1 new file mode 100644 index 000000000000..e3bb573809ef --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecIncidentsList.ps1 @@ -0,0 +1,84 @@ +using namespace System.Net + +Function Invoke-ExecIncidentsList { + <# + .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' + try { + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + $GraphRequest = if ($TenantFilter -ne 'AllTenants') { + $incidents = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/security/incidents' -tenantid $Request.Query.TenantFilter -AsApp $true + + foreach ($incident in $incidents) { + [PSCustomObject]@{ + Tenant = $Request.Query.TenantFilter + Id = $incident.id + Status = $incident.status + IncidentUrl = $incident.incidentWebUrl + RedirectId = $incident.redirectIncidentId + DisplayName = $incident.displayName + Created = $incident.createdDateTime + Updated = $incident.lastUpdateDateTime + AssignedTo = $incident.assignedTo + Classification = $incident.classification + Determination = $incident.determination + Severity = $incident.severity + Tags = ($IncidentObj.tags -join ', ') + Comments = $incident.comments + } + } + } else { + $Table = Get-CIPPTable -TableName cachealertsandincidents + $Filter = "PartitionKey eq 'Incident'" + $Rows = Get-CIPPAzDataTableEntity @Table -filter $Filter | Where-Object -Property Timestamp -GT (Get-Date).AddMinutes(-10) + if (!$Rows) { + Push-OutputBinding -Name incidentqueue -Value (Get-Date).ToString() + [PSCustomObject]@{ + Waiting = $true + } + } else { + $incidents = $Rows + foreach ($incident in $incidents) { + $IncidentObj = $incident.Incident | ConvertFrom-Json + [PSCustomObject]@{ + Tenant = $incident.Tenant + Id = $IncidentObj.id + Status = $IncidentObj.status + IncidentUrl = $IncidentObj.incidentWebUrl + RedirectId = $IncidentObj.redirectIncidentId + DisplayName = $IncidentObj.displayName + Created = $IncidentObj.createdDateTime + Updated = $IncidentObj.lastUpdateDateTime + AssignedTo = $IncidentObj.assignedTo + Classification = $IncidentObj.classification + Determination = $IncidentObj.determination + Severity = $IncidentObj.severity + Tags = ($IncidentObj.tags -join ', ') + Comments = @($IncidentObj.comments) + } + } + } + } + } catch { + $StatusCode = [HttpStatusCode]::Forbidden + $body = $_.Exception.message + } + if (!$body) { + $StatusCode = [HttpStatusCode]::OK + $body = [PSCustomObject]@{ + MSResults = ($GraphRequest | Where-Object -Property id -NE $null) + } + } + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = $Body + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecIncidentsListAllTenants.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecIncidentsListAllTenants.ps1 new file mode 100644 index 000000000000..25e24aa519ec --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecIncidentsListAllTenants.ps1 @@ -0,0 +1,57 @@ +using namespace System.Net + +Function Invoke-ExecIncidentsListAllTenants { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + + Get-Tenants | ForEach-Object -Parallel { + $domainName = $_.defaultDomainName + Import-Module '.\Modules\AzBobbyTables' + Import-Module '.\Modules\CIPPCore' + $Table = Get-CIPPTable -TableName 'cachealertsandincidents' + + try { + $incidents = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/security/incidents' -tenantid $domainName -AsApp $true + $GraphRequest = foreach ($incident in $incidents) { + $GUID = (New-Guid).Guid + $GraphRequest = @{ + Incident = [string]($incident | ConvertTo-Json -Depth 10) + RowKey = [string]$GUID + PartitionKey = 'Incident' + Tenant = [string]$domainName + } + Add-CIPPAzDataTableEntity @Table -Entity $GraphRequest -Force | Out-Null + } + + } catch { + $GUID = (New-Guid).Guid + $AlertText = ConvertTo-Json -InputObject @{ + Tenant = $domainName + displayName = "Could not connect to Tenant: $($_.Exception.Message)" + comments = @{ + createdDateTime = (Get-Date).ToString('s') + createdbyDisplayName = 'CIPP' + comment = 'Could not connect' + } + classification = 'Unknown' + determination = 'Unknown' + severity = 'CIPP' + } + $GraphRequest = @{ + Incident = [string]$AlertText + RowKey = [string]$GUID + PartitionKey = 'Incident' + Tenant = [string]$domainName + } + Add-CIPPAzDataTableEntity @Table -Entity $GraphRequest -Force | Out-Null + + + } + } + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecListAppId.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecListAppId.ps1 new file mode 100644 index 000000000000..d3695a00742f --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecListAppId.ps1 @@ -0,0 +1,26 @@ +using namespace System.Net + +Function Invoke-ExecListAppId { + <# + .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' + $ResponseURL = "$(($Request.headers.'x-ms-original-url').replace('/api/ExecListAppId','/api/ExecSAMSetup'))" + + $Results = @{ + applicationId = $ENV:ApplicationID + tenantId = $ENV:TenantID + refreshUrl = "https://login.microsoftonline.com/$ENV:TenantID/oauth2/v2.0/authorize?client_id=$ENV:ApplicationID&response_type=code&redirect_uri=$ResponseURL&response_mode=query&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default+offline_access+profile+openid&state=1&prompt=select_account" + } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Results + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecMailboxMobileDevices.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecMailboxMobileDevices.ps1 new file mode 100644 index 000000000000..15f96d33503a --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecMailboxMobileDevices.ps1 @@ -0,0 +1,33 @@ +using namespace System.Net + +Function Invoke-ExecMailboxMobileDevices { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + + # Interact with query parameters or the body of the request. + Try { + $MobileResults = Set-CIPPMobileDevice -UserId $request.query.Userid -DeviceId $request.query.deviceid -Quarantine $request.query.Quarantine -tenantFilter $request.query.tenantfilter -APIName $APINAME -Delete $Request.query.Delete -ExecutingUser $request.headers.'x-ms-client-principal' + $Results = [pscustomobject]@{'Results' = $MobileResults } + } catch { + $Results = [pscustomobject]@{'Results' = "Failed $($request.query.Userid): $($_.Exception.Message)" } + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Results + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecMaintenanceScripts.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecMaintenanceScripts.ps1 new file mode 100644 index 000000000000..567e6dc3a1c4 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecMaintenanceScripts.ps1 @@ -0,0 +1,78 @@ +using namespace System.Net + +Function Invoke-ExecMaintenanceScripts { + <# + .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' + try { + $GraphToken = Get-GraphToken -returnRefresh $true + $AccessTokenDetails = Read-JwtAccessDetails -Token $GraphToken.access_token + + $ReplacementStrings = @{ + '##TENANTID##' = $env:TenantID + '##RESOURCEGROUP##' = $env:WEBSITE_RESOURCE_GROUP + '##FUNCTIONAPP##' = $env:WEBSITE_SITE_NAME + '##SUBSCRIPTION##' = (($env:WEBSITE_OWNER_NAME).split('+') | Select-Object -First 1) + '##TOKENIP##' = $AccessTokenDetails.IPAddress + } + } catch { Write-Host $_.Exception.Message } + #$ReplacementStrings | Format-Table + + try { + $ScriptFile = $Request.Query.ScriptFile + + try { + $Filename = Split-Path -Leaf $ScriptFile + } catch {} + + if (!$ScriptFile -or [string]::IsNullOrEmpty($ScriptFile)) { + $ScriptFiles = Get-ChildItem .\ExecMaintenanceScripts\Scripts | Select-Object -ExpandProperty PSChildName + + $ScriptOptions = foreach ($ScriptFile in $ScriptFiles) { + @{label = $ScriptFile; value = $ScriptFile } + } + $Body = @{ ScriptFiles = @($ScriptOptions) } + } elseif (!(Get-ChildItem .\ExecMaintenanceScripts\Scripts\$Filename -ErrorAction SilentlyContinue)) { + $Body = @{ Status = 'Script does not exist' } + } else { + $Script = Get-Content -Raw .\ExecMaintenanceScripts\Scripts\$Filename + foreach ($i in $ReplacementStrings.Keys) { + $Script = $Script -replace $i, $ReplacementStrings.$i + } + + $ScriptContent = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($Script)) + + if ($Request.Query.MakeLink) { + $Table = Get-CippTable -TableName 'MaintenanceScripts' + $LinkGuid = ([guid]::NewGuid()).ToString() + + $MaintenanceScriptRow = @{ + 'RowKey' = $LinkGuid + 'PartitionKey' = 'Maintenance' + 'ScriptContent' = $ScriptContent + } + Add-CIPPAzDataTableEntity @Table -Entity $MaintenanceScriptRow -Force + + $Body = @{ Link = "/api/PublicScripts?guid=$LinkGuid" } + } else { + $Body = @{ ScriptContent = $ScriptContent } + } + } + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantfilter) -message "Failed to retrieve maintenance scripts. Error: $($_.Exception.Message)" -Sev 'Error' + $Body = @{Status = "Failed to retrieve maintenance scripts $($_.Exception.Message)" } + } + + # 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/Entrypoints/Invoke-ExecNotificationConfig.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecNotificationConfig.ps1 new file mode 100644 index 000000000000..24df02441efd --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecNotificationConfig.ps1 @@ -0,0 +1,53 @@ +using namespace System.Net + +Function Invoke-ExecNotificationConfig { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + $sev = ([pscustomobject]$Request.body.Severity).value -join (',') + $results = try { + $Table = Get-CIPPTable -TableName SchedulerConfig + $SchedulerConfig = @{ + 'tenant' = 'Any' + 'tenantid' = 'TenantId' + 'type' = 'CIPPNotifications' + 'schedule' = 'Every 15 minutes' + 'Severity' = [string]$sev + 'email' = "$($Request.Body.Email)" + 'webhook' = "$($Request.Body.Webhook)" + 'onePerTenant' = [boolean]$Request.Body.onePerTenant + 'sendtoIntegration' = [boolean]$Request.Body.sendtoIntegration + 'includeTenantId' = [boolean]$Request.Body.includeTenantId + 'PartitionKey' = 'CippNotifications' + 'RowKey' = 'CippNotifications' + } + foreach ($logvalue in [pscustomobject]$Request.body.logsToInclude) { + $SchedulerConfig[([pscustomobject]$logvalue.value)] = $true + } + + Add-CIPPAzDataTableEntity @Table -Entity $SchedulerConfig -Force | Out-Null + 'Successfully set the configuration' + } catch { + "Failed to set configuration: $($_.Exception.message)" + } + + + $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/Entrypoints/Invoke-ExecOffboardTenant.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecOffboardTenant.ps1 new file mode 100644 index 000000000000..8a43ad253d09 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecOffboardTenant.ps1 @@ -0,0 +1,170 @@ +using namespace System.Net + +Function Invoke-ExecOffboardTenant { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + try { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' + + $Tenantfilter = $request.body.tenantfilter + + $results = [System.Collections.ArrayList]@() + $errors = [System.Collections.ArrayList]@() + + if ($request.body.RemoveCSPGuestUsers) { + # Delete guest users who's domains match the CSP tenants + try { + try { + $domains = (New-GraphGETRequest -Uri "https://graph.microsoft.com/v1.0/domains?`$select=id" -tenantid $env:TenantID -NoAuthCheck:$true).id + $CSPGuestUsers = (New-GraphGETRequest -Uri "https://graph.microsoft.com/v1.0/users?`$select=id,mail&`$filter=userType eq 'Guest' and $(($domains | ForEach-Object { "endswith(mail, '$_')" }) -join ' or ')&`$count=true" -tenantid $Tenantfilter -ComplexFilter) + } catch { + $errors.Add("Failed to retrieve guest users: $($_.Exception.message)") + } + + if ($CSPGuestUsers) { + [System.Collections.Generic.List[PSCustomObject]]$BulkRequests = @($CSPGuestUsers | ForEach-Object { + @{ + id = $($_.id) + method = 'DELETE' + url = "/users/$($_.id)" + } + }) + + $BulkResults = New-GraphBulkRequest -Requests $BulkRequests -tenantid $TenantFilter + + $results.Add('Succesfully removed guest users') + } else { + $results.Add('No guest users found to remove') + } + } catch { + $errors.Add("Something went wrong while deleting guest users: $($_.Exception.message)") + } + } + + if ($request.body.RemoveCSPnotificationContacts) { + Write-Host "DO WE GET HERE?" + # Remove all email adresses that match the CSP tenants domains from the contact properties in /organization + try { + try { + $domains = (New-GraphGETRequest -Uri "https://graph.microsoft.com/v1.0/domains?`$select=id" -tenantid $env:TenantID -NoAuthCheck:$true).id + } catch { + throw "Failed to retrieve CSP domains: $($_.Exception.message)" + } + + try { + # Get /organization data + $orgContacts = New-GraphGETRequest -Uri "https://graph.microsoft.com/v1.0/organization?`$select=id,marketingNotificationEmails,securityComplianceNotificationMails,technicalNotificationMails" -tenantid $TenantFilter + + } catch { + throw "Failed to retrieve CSP domains: $($_.Exception.message)" + } + } catch { + $errors.Add("$($_.Exception.message)") + } + + # foreach through the properties we want to check/update + @('marketingNotificationEmails','securityComplianceNotificationMails','technicalNotificationMails') | ForEach-Object { + $property = $_ + $propertyContacts = $orgContacts.($($property)) + + if ($propertyContacts -AND ($domains -notcontains ($propertyContacts | ForEach-Object { $_.Split("@")[1] }))) { + $newPropertyContent = [System.Collections.Generic.List[object]]($propertyContacts | Where-Object { $domains -notcontains $_.Split("@")[1] }) + + $patchContactBody = if (!($newPropertyContent)) { "{ `"$($property)`" : [] }" } else { [pscustomobject]@{ $property = $newPropertyContent } | ConvertTo-Json } + + try { + New-GraphPostRequest -type PATCH -body $patchContactBody -Uri "https://graph.microsoft.com/v1.0/organization/$($orgContacts.id)" -tenantid $Tenantfilter -ContentType "application/json" + $results.Add("Succesfully removed notification contacts from $($property): $(($propertyContacts | Where-Object { $domains -contains $_.Split("@")[1] }))") + } catch { + $errors.Add("Failed to update property $($property): $($_.Exception.message)") + } + } else { + $results.Add("No notification contacts found in $($property)") + } + } + # Add logic for privacyProfile later - rvdwegen + + } + + if ($request.body.RemoveMSPvendorApps) { + # 9fcfb031-1bf6-4848-8732-5573fd64fc09 - Augmentt + # 9359814a-7403-4af9-9113-d5c8cab020ed - Rewst CSP connector + # 06bfda05-2d5e-4b3b-ac5d-79f07e402973 - Rewst Prod + # c19d36e8-6537-4998-9872-ea8b962bd0b6 - Rewst Azure Integration + # d7db2a1c-c38b-4bd1-a30f-0915167ba928 - Datto Backupify/Saas Protection + # 0c3cdc94-15ba-4b89-9222-29f599727b1c - AutoTask Client Portal SSO + # 62603940-b9b0-454f-b138-eb8d571f21d3 - Eshgro Smarter 365? + # Possible others, Scapmann, PatchMyPC, Datto M365 management, Kaseya crap, Exclaimer(?), HP, Lenovo, Dell, Apple(???), resellers(all region tenants?), Action1, Liquit + # Current idea, do a filtered serviceprincipals request based on the appOwner tenantids of known MSP vendors, load that data into a multi-select on the GUI + } + + # All customer tenant specific actions ALWAYS have to be completed before this action! + if ($request.body.RemoveMultitenantApps) { + # Remove multi-tenant apps with the CSP tenant as origin + try { + $multitenantCSPApps = (New-GraphGETRequest -Uri "https://graph.microsoft.com/v1.0/servicePrincipals?`$count=true&`$select=displayName,appId,id,appOwnerOrganizationId&`$filter=appOwnerOrganizationId eq $($env:TenantID)" -tenantid $Tenantfilter -ComplexFilter) + $sortedArray = $multitenantCSPApps | Sort-Object @{Expression = { if ($_.appId -eq $env:applicationid) { 1 } else { 0 } }; Ascending = $true } + $sortedArray | ForEach-Object { + try { + $delete = (New-GraphPostRequest -type 'DELETE' -Uri "https://graph.microsoft.com/v1.0/serviceprincipals/$($_.id)" -tenantid $Tenantfilter) + $results.Add("Succesfully removed app $($_.displayName)") + } catch { + #$results.Add("Failed to removed app $($_.displayName)") + $errors.Add("Failed to removed app $($_.displayName)") + } + } + } catch { + #$results.Add("Failed to retrieve multitenant apps, no apps have been removed: $($_.Exception.message)") + $errors.Add("Failed to retrieve multitenant apps, no apps have been removed: $($_.Exception.message)") + } + } + + if ($request.body.TerminateGDAP) { + # Terminate GDAP relationships + try { + $delegatedAdminRelationships = (New-GraphGETRequest -Uri "https://graph.microsoft.com/v1.0/tenantRelationships/delegatedAdminRelationships?`$filter=(status eq 'active') AND (customer/tenantId eq '$TenantFilter')" -tenantid $env:TenantID) + $delegatedAdminRelationships | ForEach-Object { + try { + $terminate = (New-GraphPostRequest -type 'POST' -Uri "https://graph.microsoft.com/v1.0/tenantRelationships/delegatedAdminRelationships/$($_.id)/requests" -body '{"action":"terminate"}' -ContentType 'application/json' -tenantid $env:TenantID) + $results.Add("Succesfully terminated GDAP relationship $($_.displayName) from tenant $TenantFilter") + } catch { + #$results.Add("Failed to terminate GDAP relationship $($_.displayName): $($_.Exception.message)") + $errors.Add("Failed to terminate GDAP relationship $($_.displayName): $($_.Exception.message)") + } + } + } catch { + #$results.Add("Failed to retrieve GDAP relationships, no relationships have been terminated: $($_.Exception.message)") + $errors.Add("Failed to retrieve GDAP relationships, no relationships have been terminated: $($_.Exception.message)") + } + } + + if ($request.body.TerminateContract) { + # Terminate contract relationship + try { + $terminate = (New-GraphPostRequest -type 'PATCH' -body '{ "relationshipToPartner": "none" }' -Uri "https://api.partnercenter.microsoft.com/v1/customers/$TenantFilter" -ContentType 'application/json' -scope 'https://api.partnercenter.microsoft.com/user_impersonation' -tenantid $env:TenantID) + $results.Add('Succesfully terminated contract relationship') + } catch { + #$results.Add("Failed to terminate contract relationship: $($_.Exception.message)") + $errors.Add("Failed to terminate contract relationship: $($_.Exception.message)") + } + } + + $StatusCode = [HttpStatusCode]::OK + $body = [pscustomobject]@{ + 'Results' = @($results) + 'Errors' = @($errors) + } + } catch { + $StatusCode = [HttpStatusCode]::OK + $body = $_.Exception.message + } + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = $Body + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecOffboardUser.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecOffboardUser.ps1 new file mode 100644 index 000000000000..6e6e9970f39a --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecOffboardUser.ps1 @@ -0,0 +1,50 @@ +using namespace System.Net + +Function Invoke-ExecOffboardUser { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + try { + 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 + $Results = if ($Request.body.Scheduled.enabled) { + $taskObject = [PSCustomObject]@{ + TenantFilter = $Tenantfilter + Name = "Offboarding: $Username" + Command = @{ + value = 'Invoke-CIPPOffboardingJob' + } + Parameters = @{ + Username = $Username + APIName = 'Scheduled Offboarding' + options = $request.body + } + ScheduledTime = $Request.body.scheduled.date + PostExecution = @{ + Webhook = [bool]$Request.Body.PostExecution.webhook + Email = [bool]$Request.Body.PostExecution.email + PSA = [bool]$Request.Body.PostExecution.psa + } + } + + Add-CIPPScheduledTask -Task $taskObject -hidden $false + } else { + Invoke-CIPPOffboardingJob -Username $Username -TenantFilter $Tenantfilter -Options $Request.body -APIName $APIName -ExecutingUser $request.headers.'x-ms-client-principal' + } + $StatusCode = [HttpStatusCode]::OK + $body = [pscustomobject]@{'Results' = @($results) } + } catch { + $StatusCode = [HttpStatusCode]::Forbidden + $body = $_.Exception.message + } + $Request.Body.PostExecution + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = $Body + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecOffboard_Mailboxpermissions.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecOffboard_Mailboxpermissions.ps1 new file mode 100644 index 000000000000..18e70672635d --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecOffboard_Mailboxpermissions.ps1 @@ -0,0 +1,15 @@ +using namespace System.Net + +Function Invoke-ExecOffboard_Mailboxpermissions { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + foreach ($Mailbox in $Mailboxes) { + Remove-CIPPMailboxPermissions -PermissionsLevel @('FullAccess', 'SendAs', 'SendOnBehalf') -userid $Mailbox.UserPrincipalName -AccessUser $QueueItem.User -TenantFilter $QueueItem.TenantFilter -APIName $APINAME -ExecutingUser $QueueItem.ExecutingUser + } + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecOneDriveShortCut.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecOneDriveShortCut.ps1 new file mode 100644 index 000000000000..2f820ab4a068 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecOneDriveShortCut.ps1 @@ -0,0 +1,27 @@ +using namespace System.Net + +Function Invoke-ExecOneDriveShortCut { + <# + .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' + + Try { + $MessageResult = New-CIPPOneDriveShortCut -username $Request.body.username -userid $Request.body.userid -TenantFilter $Request.Body.TenantFilter -URL $Request.body.input -ExecutingUser $request.headers.'x-ms-client-principal' + $Results = [pscustomobject]@{ 'Results' = "$MessageResult" } + } catch { + $Results = [pscustomobject]@{'Results' = "Onedrive Shortcut creation failed: $($_.Exception.Message)" } + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Results + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecPasswordConfig.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecPasswordConfig.ps1 new file mode 100644 index 000000000000..78e27e7f01f3 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecPasswordConfig.ps1 @@ -0,0 +1,46 @@ +using namespace System.Net + +Function Invoke-ExecPasswordConfig { + <# + .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' + + $Table = Get-CIPPTable -TableName Settings + $PasswordType = (Get-CIPPAzDataTableEntity @Table) + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + $results = try { + if ($Request.Query.List) { + @{ passwordType = $PasswordType.passwordType } + } else { + $SchedulerConfig = @{ + 'passwordType' = "$($Request.Body.passwordType)" + 'passwordCount' = '12' + 'PartitionKey' = 'settings' + 'RowKey' = 'settings' + } + + Add-CIPPAzDataTableEntity @Table -Entity $SchedulerConfig -Force | Out-Null + 'Successfully set the configuration' + } + } catch { + "Failed to set configuration: $($_.Exception.message)" + } + + + $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/Entrypoints/Invoke-ExecQuarantineManagement.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecQuarantineManagement.ps1 new file mode 100644 index 000000000000..7f85df715207 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecQuarantineManagement.ps1 @@ -0,0 +1,42 @@ +using namespace System.Net + +Function Invoke-ExecQuarantineManagement { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + + # Interact with query parameters or the body of the request. + Try { + $tenantfilter = $Request.Query.TenantFilter + $params = @{ + Identity = $request.query.ID + AllowSender = [boolean]$Request.query.AllowSender + ReleasetoAll = [boolean]$Request.query.type + ActionType = $Request.query.type + } + Write-Host $params + New-ExoRequest -tenantid $TenantFilter -cmdlet 'Release-QuarantineMessage' -cmdParams $Params + $Results = [pscustomobject]@{'Results' = "Successfully processed $($request.query.ID)" } + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantfilter) -message "$($request.query.id)" -Sev 'Info' + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantfilter) -message "Quarantine Management failed: $($_.Exception.Message)" -Sev 'Error' + $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 + }) + +} diff --git a/ExecResetMFA/run.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecResetMFA.ps1 similarity index 71% rename from ExecResetMFA/run.ps1 rename to Modules/CIPPCore/Public/Entrypoints/Invoke-ExecResetMFA.ps1 index bfe6da2efe2d..457e8abcba1c 100644 --- a/ExecResetMFA/run.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecResetMFA.ps1 @@ -1,41 +1,47 @@ using namespace System.Net -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) +Function Invoke-ExecResetMFA { + <# + .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' + $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.' -Write-Host "$($Request.query.ID)" -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter -try { - $AADGraphtoken = (Get-GraphToken -scope 'https://graph.windows.net/.default') - $tenantid = (Get-Tenants | Where-Object -Property defaultDomainName -EQ $TenantFilter).customerId - $TrackingGuid = (New-Guid).GUID - $LogonPost = @" + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + Write-Host "$($Request.query.ID)" + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + try { + $AADGraphtoken = (Get-GraphToken -scope 'https://graph.windows.net/.default') + $tenantid = (Get-Tenants | Where-Object -Property defaultDomainName -EQ $TenantFilter).customerId + $TrackingGuid = (New-Guid).GUID + $LogonPost = @" http://provisioning.microsoftonline.com/IProvisioningWebService/MsolConnecturn:uuid:$TrackingGuidhttp://www.w3.org/2005/08/addressing/anonymous$($AADGraphtoken['Authorization'])50afce61-c917-435b-8c6d-60aa5a8b8aa71.2.183.57Version47$($TrackingGuid)https://provisioningapi.microsoftonline.com/provisioningwebservice.svcVersion4 "@ - $DataBlob = (Invoke-RestMethod -Method POST -Uri 'https://provisioningapi.microsoftonline.com/provisioningwebservice.svc' -ContentType 'application/soap+xml; charset=utf-8' -Body $LogonPost).envelope.header.BecContext.DataBlob.'#text' - $MSOLXML = @" + $DataBlob = (Invoke-RestMethod -Method POST -Uri 'https://provisioningapi.microsoftonline.com/provisioningwebservice.svc' -ContentType 'application/soap+xml; charset=utf-8' -Body $LogonPost).envelope.header.BecContext.DataBlob.'#text' + $MSOLXML = @" http://provisioning.microsoftonline.com/IProvisioningWebService/SetUserurn:uuid:$TrackingGuidhttp://www.w3.org/2005/08/addressing/anonymous$($AADGraphtoken['Authorization'])$($DataBlob)9450afce61-c917-435b-8c6d-60aa5a8b8aa71.2.183.57Version47$TrackingGuidhttps://provisioningapi.microsoftonline.com/provisioningwebservice.svcVersion16$($tenantid)$($Request.query.id)*0001-01-01T00:00:00Enabled "@ - $SetMFA = (Invoke-RestMethod -Uri 'https://provisioningapi.microsoftonline.com/provisioningwebservice.svc' -Method post -Body $MSOLXML -ContentType 'application/soap+xml; charset=utf-8') + $SetMFA = (Invoke-RestMethod -Uri 'https://provisioningapi.microsoftonline.com/provisioningwebservice.svc' -Method post -Body $MSOLXML -ContentType 'application/soap+xml; charset=utf-8') - $Results = [pscustomobject]@{'Results' = 'Successfully completed request. User must supply MFA at next logon' } - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Reset Multi factor authentication settings for $($Request.query.id)" -Sev 'Info' -} -catch { - $Results = [pscustomobject]@{'Results' = "Failed to reset MFA methods for $($Request.query.id): $($_.Exception.Message)" } - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to reset MFA: $($_.Exception.Message)" -Sev 'Error' + $Results = [pscustomobject]@{'Results' = 'Successfully completed request. User must supply MFA at next logon' } + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Reset Multi factor authentication settings for $($Request.query.id)" -Sev 'Info' + } catch { + $Results = [pscustomobject]@{'Results' = "Failed to reset MFA methods for $($Request.query.id): $($_.Exception.Message)" } + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to reset MFA: $($_.Exception.Message)" -Sev 'Error' -} + } -# 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 + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Results + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecResetPass.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecResetPass.ps1 new file mode 100644 index 000000000000..0d16795f9104 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecResetPass.ps1 @@ -0,0 +1,37 @@ +using namespace System.Net + +Function Invoke-ExecResetPass { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + Write-Host "$($Request.query.ID)" + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + $mustChange = [System.Convert]::ToBoolean($request.query.MustChange) + + try { + $Reset = Set-CIPPResetPassword -userid $Request.query.ID -tenantFilter $TenantFilter -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' -forceChangePasswordNextSignIn $mustChange + $Results = [pscustomobject]@{'Results' = "$Reset" } + } catch { + $Results = [pscustomobject]@{'Results' = "Failed to reset password for $($Request.query.displayName): $($_.Exception.Message)" } + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to reset password for $($Request.query.displayName): $($_.Exception.Message)" -Sev 'Error' + + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Results + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecRestoreBackup.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecRestoreBackup.ps1 new file mode 100644 index 000000000000..0342d10f68c5 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecRestoreBackup.ps1 @@ -0,0 +1,40 @@ +using namespace System.Net + +Function Invoke-ExecRestoreBackup { + <# + .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' + try { + foreach ($line in ($Request.body | ConvertFrom-Json | Select-Object * -ExcludeProperty ETag)) { + Write-Host ($line) + $Table = Get-CippTable -tablename $line.table + $ht2 = @{} + $line.psobject.properties | ForEach-Object { $ht2[$_.Name] = [string]$_.Value } + $Table.Entity = $ht2 + Add-CIPPAzDataTableEntity @Table -Force + + } + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Created backup' -Sev 'Debug' + + $body = [pscustomobject]@{ + 'Results' = 'Succesfully restored backup.' + } + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to create backup: $($_.Exception.Message)" -Sev 'Error' + $body = [pscustomobject]@{'Results' = "Backup Creation failed: $($_.Exception.Message)" } + } + + + # 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/Entrypoints/Invoke-ExecRestoreDeleted.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecRestoreDeleted.ps1 new file mode 100644 index 000000000000..a78905f8386a --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecRestoreDeleted.ps1 @@ -0,0 +1,30 @@ +using namespace System.Net + +Function Invoke-ExecRestoreDeleted { + <# + .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' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + + try { + $GraphRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/v1.0/directory/deletedItems/$($Request.query.ID)/restore" -tenantid $TenantFilter -type POST -body '{}' -verbose + $Results = [pscustomobject]@{'Results' = 'Successfully completed request.' } + } 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 + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecRevokeSessions.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecRevokeSessions.ps1 new file mode 100644 index 000000000000..bab48ef09239 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecRevokeSessions.ps1 @@ -0,0 +1,29 @@ +using namespace System.Net + +Function Invoke-ExecRevokeSessions { + <# + .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' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + try { + $RevokeSessions = Revoke-CIPPSessions -userid $Request.Query.id -tenantFilter $TenantFilter -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' + $Results = [pscustomobject]@{'Results' = $RevokeSessions } + } 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 + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecRunBackup.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecRunBackup.ps1 new file mode 100644 index 000000000000..a237798e8e01 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecRunBackup.ps1 @@ -0,0 +1,49 @@ +using namespace System.Net + +Function Invoke-ExecRunBackup { + <# + .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' + try { + if ($request.query.Selected) { + $BackupTables = $request.query.Selected -split ',' + } else { + $BackupTables = @( + 'bpa' + 'Config' + 'Domains' + 'ExcludedLicenses' + 'templates' + 'standards' + 'SchedulerConfig' + ) + } + $CSVfile = foreach ($CSVTable in $BackupTables) { + $Table = Get-CippTable -tablename $CSVTable + Get-CIPPAzDataTableEntity @Table | Select-Object *, @{l = 'table'; e = { $CSVTable } } + } + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Created backup' -Sev 'Debug' + + $body = [pscustomobject]@{ + 'Results' = 'Created backup' + backup = $CSVfile + } + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to create backup: $($_.Exception.Message)" -Sev 'Error' + $body = [pscustomobject]@{'Results' = "Backup Creation failed: $($_.Exception.Message)" } + } + + + # 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/Entrypoints/Invoke-ExecSAMSetup.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecSAMSetup.ps1 new file mode 100644 index 000000000000..1319ced9aa86 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecSAMSetup.ps1 @@ -0,0 +1,198 @@ +using namespace System.Net + +Function Invoke-ExecSAMSetup { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $UserCreds = ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($request.headers.'x-ms-client-principal')) | ConvertFrom-Json) + if ($Request.query.error) { + Add-Type -AssemblyName System.Web + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + ContentType = 'text/html' + StatusCode = [HttpStatusCode]::Forbidden + Body = Get-normalizedError -Message [System.Web.HttpUtility]::UrlDecode($Request.Query.error_description) + }) + exit + } + if ('admin' -notin $UserCreds.userRoles) { + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + ContentType = 'text/html' + StatusCode = [HttpStatusCode]::Forbidden + Body = 'Could not find an admin cookie in your browser. Make sure you do not have an adblocker active, use a Chromium browser, and allow cookies. If our automatic refresh does not work, try pressing the URL bar and hitting enter. We will try to refresh ourselves in 3 seconds.' + }) + exit + } + + $APIName = $TriggerMetadata.FunctionName + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' + if ($env:MSI_SECRET) { + Disable-AzContextAutosave -Scope Process | Out-Null + $AzSession = Connect-AzAccount -Identity + } + if (!$ENV:SetFromProfile) { + Write-Host "We're reloading from KV" + Get-CIPPAuthentication + } + + $KV = $ENV:WEBSITE_DEPLOYMENT_ID + $Table = Get-CIPPTable -TableName SAMWizard + $Rows = Get-CIPPAzDataTableEntity @Table | Where-Object -Property Timestamp -GT (Get-Date).AddMinutes(-10) + + try { + if ($Request.query.count -lt 1 ) { $Results = 'No authentication code found. Please go back to the wizard.' } + + if ($request.body.setkeys) { + if ($request.body.tenantid) { Set-AzKeyVaultSecret -VaultName $kv -Name 'tenantid' -SecretValue (ConvertTo-SecureString -String $request.body.tenantid -AsPlainText -Force) } + if ($request.body.RefreshToken) { Set-AzKeyVaultSecret -VaultName $kv -Name 'RefreshToken' -SecretValue (ConvertTo-SecureString -String $request.body.RefreshToken -AsPlainText -Force) } + if ($request.body.applicationid) { Set-AzKeyVaultSecret -VaultName $kv -Name 'applicationid' -SecretValue (ConvertTo-SecureString -String $request.body.applicationid -AsPlainText -Force) } + if ($request.body.applicationsecret) { Set-AzKeyVaultSecret -VaultName $kv -Name 'applicationsecret' -SecretValue (ConvertTo-SecureString -String $request.body.applicationsecret -AsPlainText -Force) } + $Results = @{ Results = 'The keys have been replaced. Please perform a permissions check.' } + } + if ($Request.query.error -eq 'invalid_client') { $Results = 'Client ID was not found in Azure. Try waiting 10 seconds to try again, if you have gotten this error after 5 minutes, please restart the process.' } + if ($request.query.code) { + try { + $TenantId = $Rows.tenantid + if (!$TenantId) { $TenantId = $ENV:TenantId } + $AppID = $Rows.appid + if (!$AppID) { $appid = $env:ApplicationId } + $URL = ($Request.headers.'x-ms-original-url').split('?') | Select-Object -First 1 + $clientsecret = Get-AzKeyVaultSecret -VaultName $kv -Name 'applicationsecret' -AsPlainText + if (!$clientsecret) { $clientsecret = $ENV:ApplicationSecret } + $RefreshToken = Invoke-RestMethod -Method POST -Body "client_id=$appid&scope=https://graph.microsoft.com/.default+offline_access+openid+profile&code=$($request.query.code)&grant_type=authorization_code&redirect_uri=$($url)&client_secret=$clientsecret" -Uri "https://login.microsoftonline.com/$TenantId/oauth2/v2.0/token" + Set-AzKeyVaultSecret -VaultName $kv -Name 'RefreshToken' -SecretValue (ConvertTo-SecureString -String $RefreshToken.refresh_token -AsPlainText -Force) + $Results = 'Authentication is now complete. You may now close this window.' + try { + $SetupPhase = $rows.validated = $true + Add-CIPPAzDataTableEntity @Table -Entity $Rows -Force | Out-Null + } catch { + #no need. + } + } catch { + $Results = "Authentication failed. $($_.Exception.message)" + } + } + if ($request.query.CreateSAM) { + $Rows = @{ + RowKey = 'setup' + PartitionKey = 'setup' + validated = $false + SamSetup = 'NotStarted' + partnersetup = $false + appid = 'NotStarted' + tenantid = 'NotStarted' + } + Add-CIPPAzDataTableEntity @Table -Entity $Rows -Force | Out-Null + $Rows = Get-CIPPAzDataTableEntity @Table | Where-Object -Property Timestamp -GT (Get-Date).AddMinutes(-10) + + if ($Request.query.partnersetup) { + $SetupPhase = $Rows.partnersetup = $true + Add-CIPPAzDataTableEntity @Table -Entity $Rows -Force | Out-Null + } + $step = 1 + $DeviceLogon = New-DeviceLogin -clientid '1b730954-1685-4b74-9bfd-dac224a7b894' -Scope 'https://graph.microsoft.com/.default' -FirstLogon + $SetupPhase = $rows.SamSetup = [string]($DeviceLogon | ConvertTo-Json) + Add-CIPPAzDataTableEntity @Table -Entity $Rows -Force | Out-Null + $Results = @{ message = "Your code is $($DeviceLogon.user_code). Enter the code" ; step = $step; url = $DeviceLogon.verification_uri } + } + if ($Request.query.CheckSetupProcess -and $request.query.step -eq 1) { + $SAMSetup = $Rows.SamSetup | ConvertFrom-Json -ErrorAction SilentlyContinue + $Token = (New-DeviceLogin -clientid '1b730954-1685-4b74-9bfd-dac224a7b894' -Scope 'https://graph.microsoft.com/.default' -device_code $SAMSetup.device_code) + if ($token.Access_Token) { + $step = 2 + $URL = ($Request.headers.'x-ms-original-url').split('?') | Select-Object -First 1 + $PartnerSetup = $Rows.partnersetup + $TenantId = (Invoke-RestMethod 'https://graph.microsoft.com/v1.0/organization' -Headers @{ authorization = "Bearer $($Token.Access_Token)" } -Method GET -ContentType 'application/json').value.id + $SetupPhase = $rows.tenantid = [string]($TenantId) + Add-CIPPAzDataTableEntity @Table -Entity $Rows -Force | Out-Null + if ($PartnerSetup) { + $app = Get-Content '.\Cache_SAMSetup\SAMManifest.json' | ConvertFrom-Json + $App.web.redirectUris = @($App.web.redirectUris + $URL) + $app = $app | ConvertTo-Json -Depth 15 + $AppId = (Invoke-RestMethod 'https://graph.microsoft.com/v1.0/applications' -Headers @{ authorization = "Bearer $($Token.Access_Token)" } -Method POST -Body $app -ContentType 'application/json') + $rows.appid = [string]($AppId.appId) + Add-CIPPAzDataTableEntity @Table -Entity $Rows -Force | Out-Null + $attempt = 0 + do { + try { + try { + $SPNDefender = (Invoke-RestMethod 'https://graph.microsoft.com/v1.0/servicePrincipals' -Headers @{ authorization = "Bearer $($Token.Access_Token)" } -Method POST -Body "{ `"appId`": `"fc780465-2017-40d4-a0c5-307022471b92`" }" -ContentType 'application/json') + } catch { + Write-Host "didn't deploy spn for defender, probably already there." + } + try { + $SPNTeams = (Invoke-RestMethod 'https://graph.microsoft.com/v1.0/servicePrincipals' -Headers @{ authorization = "Bearer $($Token.Access_Token)" } -Method POST -Body "{ `"appId`": `"48ac35b8-9aa8-4d74-927d-1f4a14a0b239`" }" -ContentType 'application/json') + } catch { + Write-Host "didn't deploy spn for Teams, probably already there." + } + $SPN = (Invoke-RestMethod 'https://graph.microsoft.com/v1.0/servicePrincipals' -Headers @{ authorization = "Bearer $($Token.Access_Token)" } -Method POST -Body "{ `"appId`": `"$($AppId.appId)`" }" -ContentType 'application/json') + Start-Sleep 3 + $GroupID = (Invoke-RestMethod "https://graph.microsoft.com/v1.0/groups?`$filter=startswith(displayName,'AdminAgents')" -Headers @{ authorization = "Bearer $($Token.Access_Token)" } -Method Get -ContentType 'application/json').value.id + Write-Host "Id is $GroupID" + $AddingToAdminAgent = (Invoke-RestMethod "https://graph.microsoft.com/v1.0/groups/$($GroupID)/members/`$ref" -Headers @{ authorization = "Bearer $($Token.Access_Token)" } -Method POST -Body "{ `"@odata.id`": `"https://graph.microsoft.com/v1.0/directoryObjects/$($SPN.id)`"}" -ContentType 'application/json') + Write-Host 'Added to adminagents' + $attempt ++ + } catch { + $attempt ++ + } + } until ($attempt -gt 5) + } else { + $app = Get-Content '.\Cache_SAMSetup\SAMManifestNoPartner.json' + $AppId = (Invoke-RestMethod 'https://graph.microsoft.com/v1.0/applications' -Headers @{ authorization = "Bearer $($Token.Access_Token)" } -Method POST -Body $app -ContentType 'application/json') + $rows.appid = [string]($AppId.appId) + Add-CIPPAzDataTableEntity @Table -Entity $Rows -Force | Out-Null + } + $AppPassword = (Invoke-RestMethod "https://graph.microsoft.com/v1.0/applications/$($AppID.id)/addPassword" -Headers @{ authorization = "Bearer $($Token.Access_Token)" } -Method POST -Body '{"passwordCredential":{"displayName":"CIPPInstall"}}' -ContentType 'application/json').secretText + Set-AzKeyVaultSecret -VaultName $kv -Name 'tenantid' -SecretValue (ConvertTo-SecureString -String $TenantId -AsPlainText -Force) + Set-AzKeyVaultSecret -VaultName $kv -Name 'applicationid' -SecretValue (ConvertTo-SecureString -String $Appid.appid -AsPlainText -Force) + Set-AzKeyVaultSecret -VaultName $kv -Name 'applicationsecret' -SecretValue (ConvertTo-SecureString -String $AppPassword -AsPlainText -Force) + $Results = @{'message' = 'Created application. Waiting 30 seconds for Azure propagation'; step = $step } + } else { + $step = 1 + $Results = @{ message = "Your code is $($SAMSetup.user_code). Enter the code " ; step = $step; url = $SAMSetup.verification_uri } + } + + } + switch ($request.query.step) { + 2 { + $step = 2 + $TenantId = $Rows.tenantid + $AppID = $rows.appid + $PartnerSetup = $Rows.partnersetup + $SetupPhase = $rows.SamSetup = [string]($FirstLogonRefreshtoken | ConvertTo-Json) + Add-CIPPAzDataTableEntity @Table -Entity $Rows -Force | Out-Null + $URL = ($Request.headers.'x-ms-original-url').split('?') | Select-Object -First 1 + $Validated = $Rows.validated + if ($Validated) { $step = 3 } + $Results = @{ message = 'Give the next approval by clicking ' ; step = $step; url = "https://login.microsoftonline.com/$TenantId/oauth2/v2.0/authorize?scope=https://graph.microsoft.com/.default+offline_access+openid+profile&response_type=code&client_id=$($appid)&redirect_uri=$($url)" } + } + 3 { + + $step = 4 + $Results = @{'message' = 'Received token.'; step = $step } + + + } + 4 { + Remove-AzDataTableEntity @Table -Entity $Rows + + $step = 5 + $Results = @{'message' = 'Installation completed.'; step = $step + } + } + } + + } catch { + $Results = [pscustomobject]@{'Results' = "Failed. $($_.InvocationInfo.ScriptLineNumber): $($_.Exception.message)" ; step = $step } + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Results + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecScheduledCommand.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecScheduledCommand.ps1 new file mode 100644 index 000000000000..ce73476b5c97 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecScheduledCommand.ps1 @@ -0,0 +1,93 @@ + using namespace System.Net + + Function Invoke-ExecScheduledCommand { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $commandParameters = $QueueItem.Parameters + +$tenant = $QueueItem.Parameters['TenantFilter'] +Write-Host 'started task' +try { + try { + $results = & $QueueItem.command @commandParameters + } + catch { + $results = "Task Failed: $($_.Exception.Message)" + + } + + Write-Host 'ran the command' + if ($results -is [String]) { + $results = @{ Results = $results } + } + if ($results -is [array]) { + $results = $results | Where-Object { $_ -is [string] } + $results = $results | ForEach-Object { @{ Results = $_ } } + } + + $results = $results | Select-Object * -ExcludeProperty RowKey, PartitionKey + + $StoredResults = $results | ConvertTo-Json -Compress -Depth 20 | Out-String + if ($StoredResults.Length -gt 64000 -or $task.Tenant -eq 'AllTenants') { + $StoredResults = @{ Results = 'The results for this query are too long to store in this table, or the query was meant for All Tenants. Please use the options to send the results to another target to be able to view the results. ' } | ConvertTo-Json -Compress + } +} +catch { + $errorMessage = $_.Exception.Message + if ($task.Recurrence -gt 0) { $State = 'Failed - Planned' } else { $State = 'Failed' } + Update-AzDataTableEntity @Table -Entity @{ + PartitionKey = $task.PartitionKey + RowKey = $task.RowKey + Results = "$errorMessage" + TaskState = $State + } + Write-LogMessage -API 'Scheduler_UserTasks' -tenant $tenant -message "Failed to execute task $($task.Name): $errorMessage" -sev Error +} + + +$TableDesign = '' +$HTML = ($results | Select-Object * -ExcludeProperty RowKey, PartitionKey | ConvertTo-Html -Fragment) -replace '', "$TableDesign
" | Out-String +$title = "Scheduled Task $($task.Name) - $($task.ExpectedRunTime)" +Write-Host $title +switch -wildcard ($task.PostExecution) { + '*psa*' { Send-CIPPAlert -Type 'psa' -Title $title -HTMLContent $HTML } + '*email*' { Send-CIPPAlert -Type 'email' -Title $title -HTMLContent $HTML } + '*webhook*' { + $Webhook = [PSCustomObject]@{ + 'Tenant' = $tenant + 'TaskInfo' = $QueueItem.TaskInfo + 'Results' = $Results + } + Send-CIPPAlert -Type 'webhook' -Title $title -JSONContent $($Webhook | ConvertTo-Json -Depth 20) + } +} + +Write-Host 'ran the command' + +if ($task.Recurrence -le '0' -or $task.Recurrence -eq $null) { + Update-AzDataTableEntity @Table -Entity @{ + PartitionKey = $task.PartitionKey + RowKey = $task.RowKey + Results = "$StoredResults" + TaskState = 'Completed' + } +} +else { + $nextRun = (Get-Date).AddDays($task.Recurrence) + $nextRunUnixTime = [int64]($nextRun - (Get-Date '1/1/1970')).TotalSeconds + Update-AzDataTableEntity @Table -Entity @{ + PartitionKey = $task.PartitionKey + RowKey = $task.RowKey + Results = "$StoredResults" + TaskState = 'Planned' + ScheduledTime = "$nextRunUnixTime" + } +} +Write-LogMessage -API 'Scheduler_UserTasks' -tenant $tenant -message "Successfully executed task: $($task.name)" -sev Info + + } diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecSchedulerBillingRun.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecSchedulerBillingRun.ps1 new file mode 100644 index 000000000000..2b4fd7d70190 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecSchedulerBillingRun.ps1 @@ -0,0 +1,28 @@ +using namespace System.Net + +Function Invoke-ExecSchedulerBillingRun { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + try { + Write-LogMessage -API 'Scheduler_Billing' -tenant 'none' -message 'Starting billing processing.' -sev Info + + $Table = Get-CIPPTable -TableName Extensionsconfig + $Configuration = (Get-CIPPAzDataTableEntity @Table).config | ConvertFrom-Json -Depth 10 + foreach ($ConfigItem in $Configuration.psobject.properties.name) { + switch ($ConfigItem) { + 'Gradient' { + If ($Configuration.Gradient.enabled -and $Configuration.Gradient.BillingEnabled) { + New-GradientServiceSyncRun + } + } + } + } + } catch { + Write-LogMessage -API 'Scheduler_Billing' -tenant 'none' -message "Could not start billing processing $($_.Exception.Message)" -sev Error + } + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecSendOrgMessage.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecSendOrgMessage.ps1 new file mode 100644 index 000000000000..b70f200aae55 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecSendOrgMessage.ps1 @@ -0,0 +1,122 @@ +using namespace System.Net + +Function Invoke-ExecSendOrgMessage { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + $Device = $request.query.ID + try { + + $type = switch ($request.Query.type) { + 'taskbar' { + '844ec9d0-dd31-459c-a1e7-21fb1b39d5da' + $placementDetails = @(@{ + placement = 'default' + variants = @(@{ + variantId = 'b3fce1ee-9658-4267-b174-23d4a1be148f' + localizedTexts = @(@{ + locale = 'invariant' + text = @{ + 'clickUrl' = $Request.query.URL + } + }) + }) + }) + } + 'notification' { + '1ff7c7e7-128c-4e18-a926-bdac4e906ea1' + $placementDetails = @(@{ + placement = 'default' + variants = @(@{ + variantId = '7a1419c9-9263-4202-9225-35b326b92792' + localizedTexts = @(@{ + locale = 'invariant' + text = @{ + 'clickUrl' = $Request.query.URL + } + }) + }) + }) + } + 'getStarted' { + $placementDetails = @(@{ + placement = 'card0' + variants = @(@{ + variantId = 'ed0d0fa2-df72-42f4-9866-66cf3de1fafb' + localizedTexts = @(@{ + locale = 'invariant' + text = @{ + 'message' = 'My Message Value' + 'clickUrl' = 'https://example.com/clickUrl/' + 'title' = 'This message' + 'buttonText' = 'PlzClick' + } + }) + }) + } + @{ + placement = 'card1' + variants = @(@{ + variantId = 'ed0d0fa2-df72-42f4-9866-66cf3de1fafb' + localizedTexts = @(@{ + locale = 'invariant' + text = @{ + 'message' = 'My Message Value' + 'clickUrl' = 'https://example.com/clickUrl/' + 'title' = 'This message' + 'buttonText' = 'PlzClick' + } + }) + }) + }) + } + + } + $freq = $request.query.freq + $object = [pscustomobject]@{ + startDateTime = (Get-Date).ToString('O') + endDateTime = (Get-Date).AddYears('1').ToString('O') + frequency = $freq + targeting = @{ + targetingType = 'aadGroup' + includeIds = @($Device) + } + content = @{ + 'guidedContentId' = "$Type" + placementDetails = $placementDetails + logoInfo = @{ + contentType = 'png' + logoCdnUrl = 'https://hulpnu.nl/tools/Red.jpg' + } + } + } + $tmpbody = ConvertTo-Json -Depth 15 -Compress -InputObject $object + Write-Host $tmpbody + + $GraphRequest = New-GraphPOSTRequest -noauthcheck $true -type 'POST' -uri 'https://graph.microsoft.com/beta/deviceManagement/organizationalMessageDetails' -tenantid $tenantfilter -body $tmpbody + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $StatusCode = [HttpStatusCode]::Forbidden + $GraphRequest = $ErrorMessage + } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @($GraphRequest) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecSendPush.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecSendPush.ps1 new file mode 100644 index 000000000000..aeeb61d4f9c8 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecSendPush.ps1 @@ -0,0 +1,122 @@ +using namespace System.Net + +Function Invoke-ExecSendPush { + <# + .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' + + $TenantFilter = $Request.Query.TenantFilter + $UserEmail = $Request.Query.UserEmail + $MFAAppID = '981f26a1-7f43-403b-a875-f8b09b8cd720' + + # Function to keep trying to get the access token while we wait for MS to actually set the temp password + function get-clientaccess { + param( + $uri, + $body, + $count = 1 + ) + try { + $ClientToken = Invoke-RestMethod -Method post -Uri $uri -Body $body -ea stop + } catch { + if ($count -lt 20) { + + $count++ + Start-Sleep 1 + $ClientToken = get-clientaccess -uri $uri -body $body -count $count + } else { + Throw "Could not get Client Token: $_" + } + } + return $ClientToken + } + + + # Get all service principals + $SPResult = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/servicePrincipals?`$top=999&`$select=id,appId" -tenantid $TenantFilter + + # Check if we have one for the MFA App + $SPID = ($SPResult | Where-Object { $_.appId -eq $MFAAppID }).id + + # Create a serivce principal if needed + if (!$SPID) { + + $SPBody = [pscustomobject]@{ + appId = $MFAAppID + } + $SPID = (New-GraphPostRequest -uri 'https://graph.microsoft.com/v1.0/servicePrincipals' -tenantid $TenantFilter -type POST -body $SPBody -verbose).id + } + + + $PassReqBody = @{ + 'passwordCredential' = @{ + 'displayName' = 'MFA Temporary Password' + 'endDateTime' = $(((Get-Date).addminutes(5))) + 'startDateTime' = $((Get-Date).addminutes(-5)) + } + } | ConvertTo-Json -Depth 5 + + $TempPass = (New-GraphPostRequest -uri "https://graph.microsoft.com/v1.0/servicePrincipals/$SPID/addPassword" -tenantid $TenantFilter -type POST -body $PassReqBody -verbose).secretText + + # Give it a chance to apply + #Start-Sleep 5 + + # Generate the XML for the push request + $XML = @" + +1.0 +$UserEmail +en-usOverrideVoiceOtpfalse69ff05bf-eb61-47f7-a70e-e7d77b6d47d0 +truetrueradiusUNKNOWN: +"@ + + # Request to get client token + $body = @{ + 'resource' = 'https://adnotifications.windowsazure.com/StrongAuthenticationService.svc/Connector' + 'client_id' = $MFAAppID + 'client_secret' = $TempPass + 'grant_type' = 'client_credentials' + 'scope' = 'openid' + } + + # Attempt to get a token using the temp password + $ClientUri = "https://login.microsoftonline.com/$TenantFilter/oauth2/token" + try { + $ClientToken = get-clientaccess -Uri $ClientUri -Body $body + } catch { + $Body = 'Failed to create temporary password' + } + + # If we got a token send a push + if ($ClientToken) { + + $ClientHeaders = @{ 'Authorization' = "Bearer $($ClientToken.access_token)" } + + $obj = Invoke-RestMethod -Uri 'https://adnotifications.windowsazure.com/StrongAuthenticationService.svc/Connector//BeginTwoWayAuthentication' -Method POST -Headers $ClientHeaders -Body $XML -ContentType 'application/xml' + + if ($obj.BeginTwoWayAuthenticationResponse.result) { + $Body = "Received an MFA confirmation: $($obj.BeginTwoWayAuthenticationResponse.result.value | Out-String)" + } + if ($obj.BeginTwoWayAuthenticationResponse.AuthenticationResult -ne $true) { + $Body = "Authentication Failed! Does the user have Push/Phone call MFA configured? Errorcode: $($obj.BeginTwoWayAuthenticationResponse.result.value | Out-String)" + $colour = 'danger' + } + + } + + $Results = [pscustomobject]@{'Results' = $Body; colour = $colour } + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Sent push request to $UserEmail - Result: $($obj.BeginTwoWayAuthenticationResponse.result.value | Out-String)" -Sev 'Info' + + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Results + }) + + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecSetMailboxQuota.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecSetMailboxQuota.ps1 new file mode 100644 index 000000000000..f2059365139c --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecSetMailboxQuota.ps1 @@ -0,0 +1,48 @@ +using namespace System.Net + +Function Invoke-ExecSetMailboxQuota { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + try { + $APIName = $TriggerMetadata.FunctionName + 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 + $quota = $Request.body.input + $Results = try { + if ($Request.Body.ProhibitSendQuota) { + $quota = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Set-Mailbox' -cmdParams @{Identity = $Username; ProhibitSendQuota = $quota } + "Changed ProhibitSendQuota for $username - $($message)" + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Changed ProhibitSendQuota for $username - $($message)" -Sev 'Info' -tenant $TenantFilter + } + if ($Request.Body.ProhibitSendReceiveQuota) { + $quota = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Set-Mailbox' -cmdParams @{Identity = $Username; ProhibitSendReceiveQuota = $quota } + "Changed ProhibitSendReceiveQuota for $username - $($message)" + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Changed ProhibitSendReceiveQuota for $username - $($message)" -Sev 'Info' -tenant $TenantFilter + } + if ($Request.Body.IssueWarningQuota) { + $quota = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Set-Mailbox' -cmdParams @{Identity = $Username; IssueWarningQuota = $quota } + "Changed IssueWarningQuota for $username - $($message)" + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Changed IssueWarningQuota for $username - $($message)" -Sev 'Info' -tenant $TenantFilter + } + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Could not adjust mailbox quota for $($username)" -Sev 'Error' -tenant $TenantFilter + "Could not adjust mailbox quota for $($username). Error: $($_.Exception.Message)" + } + + $body = [pscustomobject]@{'Results' = @($results) } + } catch { + $body = [pscustomobject]@{'Results' = @("Could not adjust mailbox quota: $($_.Exception.message)") } + } + + # 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/Entrypoints/Invoke-ExecSetOoO.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecSetOoO.ps1 new file mode 100644 index 000000000000..128df28ca6a9 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecSetOoO.ps1 @@ -0,0 +1,46 @@ +using namespace System.Net + +Function Invoke-ExecSetOoO { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + try { + $APIName = $TriggerMetadata.FunctionName + 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 + if ($Request.body.input) { + $InternalMessage = $Request.body.input + $ExternalMessage = $Request.body.input + } else { + $InternalMessage = $Request.body.InternalMessage + $ExternalMessage = $Request.body.ExternalMessage + } + $StartTime = $Request.body.StartTime + $EndTime = $Request.body.EndTime + + $Results = try { + if ($Request.Body.AutoReplyState -ne 'Scheduled') { + Set-CIPPOutOfOffice -userid $Request.body.user -tenantFilter $TenantFilter -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' -InternalMessage $InternalMessage -ExternalMessage $ExternalMessage -State $Request.Body.AutoReplyState + } else { + Set-CIPPOutOfOffice -userid $Request.body.user -tenantFilter $TenantFilter -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' -InternalMessage $InternalMessage -ExternalMessage $ExternalMessage -StartTime $StartTime -EndTime $EndTime -State $Request.Body.AutoReplyState + } + } catch { + "Could not add out of office message for $($username). Error: $($_.Exception.Message)" + } + + $body = [pscustomobject]@{'Results' = $($results) } + } catch { + $body = [pscustomobject]@{'Results' = "Could not set Out of Office user: $($_.Exception.message)" } + } + + # 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/Entrypoints/Invoke-ExecSetSecurityAlert.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecSetSecurityAlert.ps1 new file mode 100644 index 000000000000..1a13261e7c03 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecSetSecurityAlert.ps1 @@ -0,0 +1,35 @@ +using namespace System.Net + +Function Invoke-ExecSetSecurityAlert { + <# + .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' + + # Interact with query parameters or the body of the request. + $tenantfilter = $Request.Query.TenantFilter + $AlertFilter = $Request.Query.GUID + $Status = $Request.Query.Status + $AssignBody = '{"status":"' + $Status + '","vendorInformation":{"provider":"' + $Request.query.provider + '","vendor":"' + $Request.query.vendor + '"}}' + try { + $GraphRequest = New-Graphpostrequest -uri "https://graph.microsoft.com/beta/security/alerts/$AlertFilter" -type PATCH -tenantid $TenantFilter -body $Assignbody + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantfilter) -message "Set alert $AlertFilter to status $Status" -Sev 'Info' + $body = [pscustomobject]@{'Results' = "Set status for alert to $Status" } + + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantfilter) -message "Failed to update alert $($AlertFilter): $($_.Exception.Message)" -Sev 'Error' + $body = [pscustomobject]@{'Results' = "Failed to change status: $($_.Exception.Message)" } + } + + # 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/Entrypoints/Invoke-ExecSetSecurityIncident.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecSetSecurityIncident.ps1 new file mode 100644 index 000000000000..64b2ad0b6bcf --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecSetSecurityIncident.ps1 @@ -0,0 +1,79 @@ +using namespace System.Net + +Function Invoke-ExecSetSecurityIncident { + <# + .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' + + $first = '' + # Interact with query parameters or the body of the request. + $tenantfilter = $Request.Query.TenantFilter + $IncidentFilter = $Request.Query.GUID + $Status = $Request.Query.Status + $Assigned = $Request.Query.Assigned + $Classification = $Request.Query.Classification + $Determination = $Request.Query.Determination + $Redirected = $Request.Query.Redirected -as [int] + $BodyBuild + $AssignBody = '{' + + try { + # We won't update redirected incidents because the incident it is redirected to should instead be updated + if ($Redirected -lt 1) { + # Set received status + if ($null -ne $Status) { + $AssignBody += $first + '"status":"' + $Status + '"' + $BodyBuild += $first + 'Set status for incident to ' + $Status + $first = ', ' + } + + # Set received classification and determination + if ($null -ne $Classification) { + if ($null -eq $Determination) { + # Maybe some poindexter tries to send a classification without a determination + throw + } + + $AssignBody += $first + '"classification":"' + $Classification + '", "determination":"' + $Determination + '"' + $BodyBuild += $first + 'Set classification & determination for incident to ' + $Classification + ' ' + $Determination + $first = ', ' + } + + # Set received asignee + if ($null -ne $Assigned) { + $AssignBody += $first + '"assignedTo":"' + $Assigned + '"' + if ($null -eq $Status) { + $BodyBuild += $first + 'Set assigned for incident to ' + $Assigned + } + $first = ', ' + } + + $AssignBody += '}' + + $ResponseBody = [pscustomobject]@{'Results' = $BodyBuild } + New-Graphpostrequest -uri "https://graph.microsoft.com/beta/security/incidents/$IncidentFilter" -type PATCH -tenantid $TenantFilter -body $Assignbody -asApp $true + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantfilter) -message "Update incident $IncidentFilter with values $Assignbody" -Sev 'Info' + } else { + $ResponseBody = [pscustomobject]@{'Results' = 'Cannot update redirected incident' } + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantfilter) -message "Refuse to pdate incident $IncidentFilter with values $Assignbody because it is redirected to another incident" -Sev 'Info' + } + + $body = $ResponseBody + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantfilter) -message "Failed to update alert $($AlertFilter): $($_.Exception.Message)" -Sev 'Error' + $body = [pscustomobject]@{'Results' = "Failed to update incident: $($_.Exception.Message)" } + } + + # 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/Entrypoints/Invoke-ExecUniversalSearch.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecUniversalSearch.ps1 new file mode 100644 index 000000000000..838f23ee3cd6 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecUniversalSearch.ps1 @@ -0,0 +1,36 @@ +using namespace System.Net + +Function Invoke-ExecUniversalSearch { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # Interact with query parameters or the body of the request. + + try { + $tenantfilter = Get-Tenants + $payload = '{ "returnsPartialResults":true, "displayName":"getUsers", "target": { "allTenants":true }, "operationDefinition": { "values":["@sys.normalize([ConsistencyLevel: eventual GET /v1.0/users?$top=5&$search=\"userPrincipalName:' + $request.query.name + '\" OR \"displayName:' + $request.query.name + '\"])"] }, "aggregationDefinition": { "values":["@sys.append([/result],50)"] } }' + $GraphRequest = (New-GraphPOSTRequest -noauthcheck $true -type 'POST' -uri 'https://graph.microsoft.com/beta/tenantRelationships/managedTenants/managedTenantOperations' -tenantid $env:TenantID -body $payload).result.Results | ConvertFrom-Json | Where-Object { $_.'_TenantId' -in $tenantfilter.customerId } + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $StatusCode = [HttpStatusCode]::Forbidden + $GraphRequest = "Could not connect to Azure Lighthouse API: $($ErrorMessage)" + } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @($GraphRequest) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-GetCippAlerts.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-GetCippAlerts.ps1 new file mode 100644 index 000000000000..9a5e25e55df5 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-GetCippAlerts.ps1 @@ -0,0 +1,68 @@ +using namespace System.Net + +Function Invoke-GetCippAlerts { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $Alerts = [System.Collections.ArrayList]@() + $Table = Get-CippTable -tablename CippAlerts + $PartitionKey = Get-Date -UFormat '%Y%m%d' + $Filter = "PartitionKey eq '{0}'" -f $PartitionKey + $Rows = Get-CIPPAzDataTableEntity @Table -Filter $Filter | Sort-Object TableTimestamp -Descending | Select-Object -First 10 + + $APIVersion = Get-Content 'version_latest.txt' | Out-String + $CIPPVersion = $request.query.localversion + + $RemoteAPIVersion = Invoke-RestMethod -Uri 'https://raw.githubusercontent.com/KelvinTegelaar/CIPP-API/master/version_latest.txt' + $RemoteCIPPVersion = Invoke-RestMethod -Uri 'https://raw.githubusercontent.com/KelvinTegelaar/CIPP/master/public/version_latest.txt' + + $version = [PSCustomObject]@{ + LocalCIPPVersion = $CIPPVersion + RemoteCIPPVersion = $RemoteCIPPVersion + LocalCIPPAPIVersion = $APIVersion + RemoteCIPPAPIVersion = $RemoteAPIVersion + OutOfDateCIPP = ([version]$RemoteCIPPVersion -gt [version]$CIPPVersion) + OutOfDateCIPPAPI = ([version]$RemoteAPIVersion -gt [version]$APIVersion) + } + if ($version.outOfDateCIPP) { + $Alerts.add(@{Alert = 'Your CIPP Frontend is out of date. Please update to the latest version. Find more on the following '; link = 'https://docs.cipp.app/setup/installation/updating'; type = 'warning' }) + Write-LogMessage -message 'Your CIPP Frontend is out of date. Please update to the latest version' -API 'Updates' -tenant 'All Tenants' -sev Alert + + } + if ($version.outOfDateCIPPAPI) { + $Alerts.add(@{Alert = 'Your CIPP API is out of date. Please update to the latest version. Find more on the following'; link = 'https://docs.cipp.app/setup/installation/updating'; type = 'warning' }) + Write-LogMessage -message 'Your CIPP API is out of date. Please update to the latest version' -API 'Updates' -tenant 'All Tenants' -sev Alert + } + + + if ($env:ApplicationID -eq 'LongApplicationID' -or $null -eq $ENV:ApplicationID) { $Alerts.add(@{Alert = 'You have not yet setup your SAM Setup. Please go to the SAM Wizard in settings to finish setup'; link = '/cipp/setup'; type = 'warning' }) } + if ($env:FUNCTIONS_EXTENSION_VERSION -ne '~4') { + $Alerts.add(@{Alert = 'Your Function App is running on a Runtime version lower than 4. This impacts performance. Go to Settings -> Backend -> Function App Configuration -> Function Runtime Settings and set this to 4 for maximum performance'; link = '/cipp/setup'; type = 'warning' }) + } + if ($psversiontable.psversion.toString() -lt 7.2) { $Alerts.add(@{Alert = 'Your Function App is running on Powershell 7. This impacts performance. Go to Settings -> Backend -> Function App Configuration -> General Settings and set PowerShell Core Version to 7.2 for maximum performance'; link = '/cipp/setup'; type = 'danger' }) } + if ($env:WEBSITE_RUN_FROM_PACKAGE -ne '1') { + $Alerts.add( + @{Alert = 'Your Function App is running in write mode. This will cause performance issues and increase cost. Please check this ' + link = 'https://docs.cipp.app/setup/installation/runfrompackage' + type = 'warning' + }) + } + if ($Rows) { $Rows | ForEach-Object { $alerts.add($_) } } + $Alerts = @($Alerts) + $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. + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Alerts + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-GetVersion.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-GetVersion.ps1 new file mode 100644 index 000000000000..b92ecb48d6e6 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-GetVersion.ps1 @@ -0,0 +1,36 @@ +using namespace System.Net + +Function Invoke-GetVersion { + <# + .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' + + $APIVersion = Get-Content 'version_latest.txt' | Out-String + $CIPPVersion = $request.query.localversion + + $RemoteAPIVersion = Invoke-RestMethod -Uri 'https://raw.githubusercontent.com/KelvinTegelaar/CIPP-API/master/version_latest.txt' + $RemoteCIPPVersion = Invoke-RestMethod -Uri 'https://raw.githubusercontent.com/KelvinTegelaar/CIPP/master/public/version_latest.txt' + + $version = [PSCustomObject]@{ + LocalCIPPVersion = $CIPPVersion + RemoteCIPPVersion = $RemoteCIPPVersion + LocalCIPPAPIVersion = $APIVersion + RemoteCIPPAPIVersion = $RemoteAPIVersion + OutOfDateCIPP = ([version]$RemoteCIPPVersion -gt [version]$CIPPVersion) + OutOfDateCIPPAPI = ([version]$RemoteAPIVersion -gt [version]$APIVersion) + } + # Write to the Azure Functions log stream. + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Version + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListAPDevices.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListAPDevices.ps1 new file mode 100644 index 000000000000..fce90a91487c --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListAPDevices.ps1 @@ -0,0 +1,36 @@ +using namespace System.Net + +Function Invoke-ListAPDevices { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + $userid = $Request.Query.UserID + try { + $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceManagement/windowsAutopilotDeviceIdentities?`$top=999" -tenantid $TenantFilter + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $StatusCode = [HttpStatusCode]::Forbidden + $GraphRequest = $ErrorMessage + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @($GraphRequest) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListAlertsQueue.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListAlertsQueue.ps1 new file mode 100644 index 000000000000..af4f752ac582 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListAlertsQueue.ps1 @@ -0,0 +1,53 @@ +using namespace System.Net + +Function Invoke-ListAlertsQueue { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + $Table = Get-CIPPTable -TableName 'SchedulerConfig' + $Filter = "PartitionKey eq 'Alert'" + $QueuedApps = Get-CIPPAzDataTableEntity @Table -Filter $Filter + + $CurrentStandards = foreach ($QueueFile in $QueuedApps) { + [PSCustomObject]@{ + tenantName = $QueueFile.tenant + AdminPassword = [bool]$QueueFile.AdminPassword + DefenderMalware = [bool]$QueueFile.DefenderMalware + DefenderStatus = [bool]$QueueFile.DefenderStatus + MFAAdmins = [bool]$QueueFile.MFAAdmins + MFAAlertUsers = [bool]$QueueFile.MFAAlertUsers + NewGA = [bool]$QueueFile.NewGA + NewRole = [bool]$QueueFile.NewRole + QuotaUsed = [bool]$QueueFile.QuotaUsed + UnusedLicenses = [bool]$QueueFile.UnusedLicenses + OverusedLicenses = [bool]$QueueFile.OverusedLicenses + AppSecretExpiry = [bool]$QueueFile.AppSecretExpiry + ApnCertExpiry = [bool]$QueueFile.ApnCertExpiry + VppTokenExpiry = [bool]$QueueFile.VppTokenExpiry + DepTokenExpiry = [bool]$QueueFile.DepTokenExpiry + NoCAConfig = [bool]$QueueFile.NoCAConfig + SecDefaultsUpsell = [bool]$QueueFile.SecDefaultsUpsell + SharepointQuota = [bool]$QueueFile.SharePointQuota + ExpiringLicenses = [bool]$QueueFile.ExpiringLicenses + tenantId = $QueueFile.tenantid + } + } + + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @($CurrentStandards) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListAllTenantDeviceCompliance.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListAllTenantDeviceCompliance.ps1 new file mode 100644 index 000000000000..d9d49840c7b4 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListAllTenantDeviceCompliance.ps1 @@ -0,0 +1,44 @@ +using namespace System.Net + +Function Invoke-ListAllTenantDeviceCompliance { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + try { + if ($TenantFilter -eq 'AllTenants') { + $GraphRequest = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/tenantRelationships/managedTenants/managedDeviceCompliances' + $StatusCode = [HttpStatusCode]::OK + } else { + $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/tenantRelationships/managedTenants/managedDeviceCompliances?`$top=999&`$filter=organizationId eq '$TenantFilter'" + $StatusCode = [HttpStatusCode]::OK + } + + if ($GraphRequest.value.count -lt 1) { + $StatusCode = [HttpStatusCode]::Forbidden + $GraphRequest = 'No data found - This client might not be onboarded in Lighthouse' + } + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $StatusCode = [HttpStatusCode]::Forbidden + $GraphRequest = "Could not connect to Azure Lighthouse API: $($ErrorMessage)" + } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @($GraphRequest) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListAppConsentRequests.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListAppConsentRequests.ps1 new file mode 100644 index 000000000000..9cfc10853e23 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListAppConsentRequests.ps1 @@ -0,0 +1,59 @@ +using namespace System.Net + +function Invoke-ListAppConsentRequests { + <# + .FUNCTIONALITY + Entrypoint + #> + param($Request, $TriggerMetadata) + + $APIName = $TriggerMetadata.FunctionName + $TenantFilter = $Request.Query.TenantFilter + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' + + try { + if ($Request.Query.TenantFilter -eq 'AllTenants') { + throw 'AllTenants is not yet supported' + } else { + $TenantFilter = $Request.Query.TenantFilter + } + + $appConsentRequests = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/identityGovernance/appConsent/appConsentRequests' -tenantid $TenantFilter # Need the beta endpoint to get consentType + $Results = foreach ($app in $appConsentRequests) { + $userConsentRequests = New-GraphGetRequest -Uri "https://graph.microsoft.com/v1.0/identityGovernance/appConsent/appConsentRequests/$($app.id)/userConsentRequests" -tenantid $TenantFilter + $userConsentRequests | ForEach-Object { + [pscustomobject]@{ + appId = $app.appId + appDisplayName = $app.appDisplayName + requestUser = $_.createdBy.user.userPrincipalName + requestReason = $_.reason + requestDate = $_.createdDateTime + requestStatus = $_.status + reviewedBy = $_.approval.stages.reviewedBy.userPrincipalName + reviewedJustification = $_.approval.stages.justification + reviewedDate = $_.approval.stages.reviewedDateTime + reviewedStatus = $_.approval.stages.status + scopes = $app.pendingScopes.displayName + consentUrl = if ($app.consentType -eq 'Static') { + # if something is going wrong here you've probably stumbled on a fourth variation - rvdwegen + "https://login.microsoftonline.com/$($TenantFilter)/adminConsent?client_id=$($app.appId)&bf_id=$($app.id)&redirect_uri=https://entra.microsoft.com/TokenAuthorize" + } elseif ($app.pendingScopes.displayName) { + "https://login.microsoftonline.com/$($TenantFilter)/v2.0/adminConsent?client_id=$($app.appId)&scope=$($app.pendingScopes.displayName -Join(' '))&bf_id=$($app.id)&redirect_uri=https://entra.microsoft.com/TokenAuthorize" + } else { + "https://login.microsoftonline.com/$($TenantFilter)/adminConsent?client_id=$($app.appId)&bf_id=$($app.id)&redirect_uri=https://entra.microsoft.com/TokenAuthorize" + } + } + } + } + $StatusCode = [HttpStatusCode]::OK + } catch { + $StatusCode = [HttpStatusCode]::OK + Write-LogMessage -user $ExecutingUser -API $APIName -message 'app consent request list failed' -Sev 'Error' -tenant $TenantFilter + $Results = @{ appDisplayName = "Error: $($_.Exception.Message)" } + } + + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @($Results) + }) +} \ No newline at end of file diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListAppStatus.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListAppStatus.ps1 new file mode 100644 index 000000000000..1b6723d21c17 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListAppStatus.ps1 @@ -0,0 +1,40 @@ +using namespace System.Net + +Function Invoke-ListAppStatus { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # Interact with query parameters or the body of the request. + $tenantfilter = $Request.Query.TenantFilter + $appFilter = $Request.Query.AppFilter + Write-Host "Using $appFilter" + $body = @" +{"select":["DeviceName","UserPrincipalName","Platform","AppVersion","InstallState","InstallStateDetail","LastModifiedDateTime","DeviceId","ErrorCode","UserName","UserId","ApplicationId","AssignmentFilterIdsList","AppInstallState","AppInstallStateDetails","HexErrorCode"],"skip":0,"top":999,"filter":"(ApplicationId eq '$Appfilter')","orderBy":[]} +"@ + try { + $GraphRequest = New-Graphpostrequest -uri 'https://graph.microsoft.com/beta/deviceManagement/reports/getDeviceInstallStatusReport' -tenantid $TenantFilter -body $body + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $StatusCode = [HttpStatusCode]::Forbidden + $GraphRequest = $ErrorMessage + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @($GraphRequest) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListApplicationQueue.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListApplicationQueue.ps1 new file mode 100644 index 000000000000..13e945aa16ed --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListApplicationQueue.ps1 @@ -0,0 +1,40 @@ +using namespace System.Net + +Function Invoke-ListApplicationQueue { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + $Table = Get-CippTable -tablename 'apps' + $QueuedApps = (Get-CIPPAzDataTableEntity @Table) + + $CurrentApps = foreach ($QueueFile in $QueuedApps) { + Write-Host $QueueFile + $ApplicationFile = $QueueFile.JSON | ConvertFrom-Json -Depth 10 + [PSCustomObject]@{ + tenantName = $ApplicationFile.tenant + applicationName = $ApplicationFile.Applicationname + cmdLine = $ApplicationFile.IntuneBody.installCommandLine + assignTo = $ApplicationFile.assignTo + id = $($QueueFile.RowKey) + status = $($QueueFile.status) + } + } + + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @($CurrentApps) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListApps.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListApps.ps1 new file mode 100644 index 000000000000..aca3cafdcd2f --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListApps.ps1 @@ -0,0 +1,35 @@ +using namespace System.Net + +Function Invoke-ListApps { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + try { + $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceAppManagement/mobileApps?`$top=999&`$filter=(microsoft.graph.managedApp/appAvailability%20eq%20null%20or%20microsoft.graph.managedApp/appAvailability%20eq%20%27lineOfBusiness%27%20or%20isAssigned%20eq%20true)&`$orderby=displayName&" -tenantid $TenantFilter + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $StatusCode = [HttpStatusCode]::Forbidden + $GraphRequest = $ErrorMessage + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @($GraphRequest) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListAppsRepository.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListAppsRepository.ps1 new file mode 100644 index 000000000000..e85a43e1740b --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListAppsRepository.ps1 @@ -0,0 +1,69 @@ +using namespace System.Net + +Function Invoke-ListAppsRepository { + <# + .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' + + $Search = $Request.Body.Search + $Repository = $Request.Body.Repository + $Packages = @() + $Message = '' + $IsError = $false + + try { + if (!([string]::IsNullOrEmpty($Search))) { + if ([string]::IsNullOrEmpty($Repository)) { + $Repository = 'https://chocolatey.org/api/v2' + } + + # Latest version, top 30 results matching search term + $SearchPath = "Search()?`$filter=IsLatestVersion&`$skip=0&`$top=30&searchTerm='$Search'&targetFramework=''&includePrerelease=false" + + $Url = "$Repository/$SearchPath" + $RepoPackages = Invoke-RestMethod $Url -ErrorAction Stop + + if (($RepoPackages | Measure-Object).Count -gt 0) { + $Packages = foreach ($RepoPackage in $RepoPackages) { + [PSCustomObject]@{ + packagename = $RepoPackage.title.'#text' + author = $RepoPackage.author.Name + applicationName = $RepoPackage.properties.Title + version = $RepoPackage.properties.Version + description = $RepoPackage.summary.'#text' + customRepo = $Repository + created = Get-Date -Date $RepoPackage.properties.Created.'#text' -Format 'MM/dd/yyyy HH:mm:ss' + } + } + } else { + $IsError = $true + $Message = 'No results found' + } + } else { + $IsError = $true + $Message = 'No search terms specified' + } + } catch { + $IsError = $true + $Message = "Repository error: $($_.Exception.Message)" + } + + $PackageSearch = @{ + Search = $Search + Results = @($Packages | Sort-Object -Property packagename) + Message = $Message + IsError = $IsError + } + + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $PackageSearch + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListAutopilotconfig.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListAutopilotconfig.ps1 new file mode 100644 index 000000000000..43ae12082452 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListAutopilotconfig.ps1 @@ -0,0 +1,42 @@ +using namespace System.Net + +Function Invoke-ListAutopilotconfig { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + $userid = $Request.Query.UserID + try { + if ($request.query.type -eq 'ApProfile') { + $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceManagement/windowsAutopilotDeploymentProfiles?`$expand=assignments" -tenantid $TenantFilter + } + + if ($request.query.type -eq 'ESP') { + $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceManagement/deviceEnrollmentConfigurations?`$expand=assignments" -tenantid $TenantFilter | Where-Object -Property '@odata.type' -EQ '#microsoft.graph.windows10EnrollmentCompletionPageConfiguration' + } + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $StatusCode = [HttpStatusCode]::Forbidden + $GraphRequest = $ErrorMessage + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @($GraphRequest) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListAzureADConnectStatus.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListAzureADConnectStatus.ps1 new file mode 100644 index 000000000000..f1b1b0592e76 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListAzureADConnectStatus.ps1 @@ -0,0 +1,77 @@ +using namespace System.Net + +Function Invoke-ListAzureADConnectStatus { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + $DataToReturn = $Request.Query.DataToReturn + + if (($DataToReturn -eq 'AzureADConnectSettings') -or ([string]::IsNullOrEmpty($DataToReturn)) ) { + $ADConnectStatusGraph = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/organization' -tenantid $TenantFilter + #$ADConnectStatusGraph = New-ClassicAPIGetRequest -Resource "74658136-14ec-4630-ad9b-26e160ff0fc6" -TenantID $TenantFilter -Uri "https://main.iam.ad.ext.azure.com/api/Directories/ADConnectStatus" -Method "GET" + #$PasswordSyncStatusGraph = New-ClassicAPIGetRequest -Resource "74658136-14ec-4630-ad9b-26e160ff0fc6" -TenantID $TenantFilter -Uri "https://main.iam.ad.ext.azure.com/api/Directories/GetPasswordSyncStatus" -Method "GET" + $AzureADConnectSettings = [PSCustomObject]@{ + dirSyncEnabled = [boolean]$ADConnectStatusGraph.onPremisesSyncEnabled + #dirSyncConfigured = [boolean]$ADConnectStatusGraph.dirSyncConfigured + #passThroughAuthenticationEnabled = [boolean]$ADConnectStatusGraph.passThroughAuthenticationEnabled + #seamlessSingleSignOnEnabled = [boolean]$ADConnectStatusGraph.seamlessSingleSignOnEnabled + numberOfHoursFromLastSync = $ADConnectStatusGraph.onPremisesLastSyncDateTime + #passwordSyncStatus = [boolean]$PasswordSyncStatusGraph + raw = $ADConnectStatusGraph + } + } + + if (($DataToReturn -eq 'AzureADObjectsInError') -or ([string]::IsNullOrEmpty($DataToReturn)) ) { + $selectlist = 'id', 'displayName', 'onPremisesProvisioningErrors', 'createdDateTime' + $Types = 'Users', 'Contacts', 'Groups' + + $GraphRequest = foreach ($Type in $types) { + New-GraphGetRequest -uri "https://graph.microsoft.com/beta/$($Type)?`$select=$($selectlist -join ',')" -tenantid $TenantFilter | ForEach-Object { + if ($_.id -ne $null) { + $_ | Add-Member -NotePropertyName ObjectType -NotePropertyValue $Type + $_ + } + + } + } + $ObjectsInError = @($GraphRequest) + } + + if ([string]::IsNullOrEmpty($DataToReturn)) { + $FinalObject = [PSCustomObject]@{ + AzureADConnectSettings = $AzureADConnectSettings + ObjectsInError = $ObjectsInError + } + } + if ($DataToReturn -eq 'AzureADConnectSettings') { + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $AzureADConnectSettings + }) + } elseif ($DataToReturn -eq 'AzureADObjectsInError') { + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @($ObjectsInError) + }) + } else { + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @($FinalObject) + }) + } + + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListBPA.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListBPA.ps1 new file mode 100644 index 000000000000..eea73a9c4b9e --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListBPA.ps1 @@ -0,0 +1,83 @@ +using namespace System.Net + +Function Invoke-ListBPA { + <# + .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" + + $Table = get-cipptable 'cachebpav2' + $name = $Request.query.Report + if ($name -eq $null) { $name = 'CIPP Best Practices v1.0 - Table view' } + + # Get all possible JSON files for reports, find the correct one, select the Columns + $JSONFields = @() + $Columns = $null +(Get-ChildItem -Path 'Config\*.BPATemplate.json' -Recurse | Select-Object -ExpandProperty FullName | ForEach-Object { + $Template = $(Get-Content $_) | ConvertFrom-Json + if ($Template.Name -eq $NAME) { + $JSONFields = $Template.Fields | Where-Object { $_.StoreAs -eq 'JSON' } | ForEach-Object { $_.name } + $Columns = $Template.fields.FrontendFields | Where-Object -Property name -NE $null + $Style = $Template.Style + } + }) + + + if ($Request.query.tenantFilter -ne 'AllTenants' -and $Style -eq 'Tenant') { + $mergedObject = New-Object pscustomobject + + $Data = (Get-CIPPAzDataTableEntity @Table -Filter "PartitionKey eq '$($Request.query.tenantFilter)'") | ForEach-Object { + $row = $_ + $JSONFields | ForEach-Object { + $jsonContent = $row.$_ + if ($jsonContent -ne $null -and $jsonContent -ne 'FAILED') { + $row.$_ = $jsonContent | ConvertFrom-Json -Depth 15 + } + } + $row.PSObject.Properties | ForEach-Object { + $mergedObject | Add-Member -NotePropertyName $_.Name -NotePropertyValue $_.Value -Force + } + } + + $Data = $mergedObject + } else { + $Tenants = Get-Tenants -IncludeErrors + $Data = (Get-CIPPAzDataTableEntity @Table -Filter "RowKey eq '$NAME'") | ForEach-Object { + $row = $_ + $JSONFields | ForEach-Object { + $jsonContent = $row.$_ + if ($jsonContent -ne $null -and $jsonContent -ne 'FAILED') { + $row.$_ = $jsonContent | ConvertFrom-Json -Depth 15 + } + } + $row | Where-Object -Property PartitionKey -In $Tenants.customerId + } + + + } + + $Results = [PSCustomObject]@{ + Data = $Data + Columns = $Columns + Style = $Style + } + + if (!$Results) { + $Results = @{ + Columns = @( value = 'Results'; name = 'Results') + Data = @(@{ Results = 'The BPA has not yet run.' }) + } + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = ($Results | ConvertTo-Json -Depth 15) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListBPATemplates.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListBPATemplates.ps1 new file mode 100644 index 000000000000..2185772864cd --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListBPATemplates.ps1 @@ -0,0 +1,39 @@ +using namespace System.Net + +Function Invoke-ListBPATemplates { + <# + .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' + + Write-Host 'PowerShell HTTP trigger function processed a request.' + Write-Host $Request.query.id + + $Templates = Get-ChildItem 'Config\*.BPATemplate.json' + + if ($Request.Query.RawJson) { + $Templates = $Templates | ForEach-Object { + $(Get-Content $_) | ConvertFrom-Json + } + } else { + $Templates = $Templates | ForEach-Object { + $Template = $(Get-Content $_) | ConvertFrom-Json + @{ + Data = $Template.fields + Name = $Template.Name + Style = $Template.Style + } + } + } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = ($Templates | ConvertTo-Json -Depth 10) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListBasicAuth.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListBasicAuth.ps1 new file mode 100644 index 000000000000..bf831b65cc9b --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListBasicAuth.ps1 @@ -0,0 +1,63 @@ +using namespace System.Net + +Function Invoke-ListBasicAuth { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + $currentTime = Get-Date -Format 'yyyy-MM-ddTHH:MM:ss' + $ts = (Get-Date).AddDays(-30) + $endTime = $ts.ToString('yyyy-MM-ddTHH:MM:ss') + ##Create Filter for basic auth sign-ins + $filters = "createdDateTime ge $($endTime)Z and createdDateTime lt $($currentTime)Z and (clientAppUsed eq 'AutoDiscover' or clientAppUsed eq 'Exchange ActiveSync' or clientAppUsed eq 'Exchange Online PowerShell' or clientAppUsed eq 'Exchange Web Services' or clientAppUsed eq 'IMAP4' or clientAppUsed eq 'MAPI Over HTTP' or clientAppUsed eq 'Offline Address Book' or clientAppUsed eq 'Outlook Anywhere (RPC over HTTP)' or clientAppUsed eq 'Other clients' or clientAppUsed eq 'POP3' or clientAppUsed eq 'Reporting Web Services' or clientAppUsed eq 'Authenticated SMTP' or clientAppUsed eq 'Outlook Service')" + if ($TenantFilter -ne 'AllTenants') { + + try { + $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/auditLogs/signIns?api-version=beta&filter=$($filters)" -tenantid $TenantFilter -erroraction stop | Select-Object userPrincipalName, clientAppUsed, Status | Sort-Object -Unique -Property userPrincipalName + $response = $GraphRequest + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Retrieved basic authentication report' -Sev 'Debug' -tenant $TenantFilter + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @($response) + }) + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to retrieve basic authentication report: $($_.Exception.message) " -Sev 'Error' -tenant $TenantFilter + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = '500' + Body = $(Get-NormalizedError -message $_.Exception.message) + }) + } + } else { + $Table = Get-CIPPTable -TableName cachebasicauth + $Rows = Get-CIPPAzDataTableEntity @Table | Where-Object -Property Timestamp -GT (Get-Date).AddHours(-1) + if (!$Rows) { + Push-OutputBinding -Name Msg -Value (Get-Date).ToString() + $GraphRequest = [PSCustomObject]@{ + Tenant = 'Loading data for all tenants. Please check back in 10 minutes' + } + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @($GraphRequest) + }) + } else { + $GraphRequest = $Rows + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @($GraphRequest) + }) + } + } + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListBasicAuthAllTenants.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListBasicAuthAllTenants.ps1 new file mode 100644 index 000000000000..e4be4bafbb02 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListBasicAuthAllTenants.ps1 @@ -0,0 +1,47 @@ +using namespace System.Net + +Function Invoke-ListBasicAuthAllTenants { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + + Get-Tenants | ForEach-Object -Parallel { + $domainName = $_.defaultDomainName + Import-Module '.\Modules\AzBobbyTables' + Import-Module '.\Modules\CIPPCore' + + $currentTime = Get-Date -Format 'yyyy-MM-ddTHH:MM:ss' + $ts = (Get-Date).AddDays(-30) + $endTime = $ts.ToString('yyyy-MM-ddTHH:MM:ss') + $filters = "createdDateTime ge $($endTime)Z and createdDateTime lt $($currentTime)Z and (clientAppUsed eq 'AutoDiscover' or clientAppUsed eq 'Exchange ActiveSync' or clientAppUsed eq 'Exchange Online PowerShell' or clientAppUsed eq 'Exchange Web Services' or clientAppUsed eq 'IMAP4' or clientAppUsed eq 'MAPI Over HTTP' or clientAppUsed eq 'Offline Address Book' or clientAppUsed eq 'Outlook Anywhere (RPC over HTTP)' or clientAppUsed eq 'Other clients' or clientAppUsed eq 'POP3' or clientAppUsed eq 'Reporting Web Services' or clientAppUsed eq 'Authenticated SMTP' or clientAppUsed eq 'Outlook Service')" + try { + $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/auditLogs/signIns?api-version=beta&filter=$($filters)" -tenantid $domainName -ErrorAction stop | Sort-Object -Unique -Property clientAppUsed | ForEach-Object { + @{ + Tenant = $domainName + clientAppUsed = $_.clientAppUsed + userPrincipalName = $_.UserPrincipalName + RowKey = "$($_.UserPrincipalName)-$($_.clientAppUsed)" + PartitionKey = 'basicauth' + } + } + } catch { + $GraphRequest = @{ + Tenant = $domainName + clientAppUsed = "Could not connect to Tenant: $($_.Exception.message)" + userPrincipalName = $domainName + RowKey = $domainName + PartitionKey = 'basicauth' + } + } + $Table = Get-CIPPTable -TableName cachebasicauth + Add-CIPPAzDataTableEntity @Table -Entity $GraphRequest -Force | Out-Null + + } + + + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListCAtemplates.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListCAtemplates.ps1 new file mode 100644 index 000000000000..14ec616c0616 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListCAtemplates.ps1 @@ -0,0 +1,48 @@ +using namespace System.Net + +Function Invoke-ListCAtemplates { + <# + .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' + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + Write-Host $Request.query.id + #Migrating old policies whenever you do a list + $Table = Get-CippTable -tablename 'templates' + + $Templates = Get-ChildItem 'Config\*.CATemplate.json' | ForEach-Object { + $Entity = @{ + JSON = "$(Get-Content $_)" + RowKey = "$($_.name)" + PartitionKey = 'CATemplate' + GUID = "$($_.name)" + } + Add-CIPPAzDataTableEntity @Table -Entity $Entity -Force + } + + #List new policies + $Table = Get-CippTable -tablename 'templates' + $Filter = "PartitionKey eq 'CATemplate'" + $Templates = (Get-CIPPAzDataTableEntity @Table -Filter $Filter) | ForEach-Object { + $data = $_.JSON | ConvertFrom-Json -Depth 100 + $data | Add-Member -NotePropertyName 'GUID' -NotePropertyValue $_.GUID -Force + $data + } | Sort-Object -Property displayName + + if ($Request.query.ID) { $Templates = $Templates | Where-Object -Property GUID -EQ $Request.query.id } + + $Templates = ConvertTo-Json -InputObject @($Templates) -Depth 100 + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Templates + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListCalendarPermissions.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListCalendarPermissions.ps1 new file mode 100644 index 000000000000..3bbefa764b84 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListCalendarPermissions.ps1 @@ -0,0 +1,35 @@ +using namespace System.Net + +Function Invoke-ListCalendarPermissions { + <# + .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' + $UserID = $request.Query.UserID + $Tenantfilter = $request.Query.tenantfilter + + try { + $GetCalParam = @{Identity = $UserID; FolderScope = 'Calendar' } + $CalendarFolder = New-ExoRequest -tenantid $Tenantfilter -cmdlet 'Get-MailboxFolderStatistics' -cmdParams $GetCalParam | Select-Object -First 1 + $CalParam = @{Identity = "$($UserID):\$($CalendarFolder.name)" } + $GraphRequest = New-ExoRequest -tenantid $Tenantfilter -cmdlet 'Get-MailboxFolderPermission' -cmdParams $CalParam -UseSystemMailbox $true | Select-Object Identity, User, AccessRights, FolderName + Write-LogMessage -API 'List Calendar Permissions' -tenant $tenantfilter -message "Calendar permissions listed for $($tenantfilter)" -sev Debug + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $StatusCode = [HttpStatusCode]::Forbidden + $GraphRequest = $ErrorMessage + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @($GraphRequest) + }) + +} diff --git a/ListConditionalAccessPolicies/run.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListConditionalAccessPolicies.ps1 similarity index 99% rename from ListConditionalAccessPolicies/run.ps1 rename to Modules/CIPPCore/Public/Entrypoints/Invoke-ListConditionalAccessPolicies.ps1 index a14f71181e1d..affec8e72291 100644 --- a/ListConditionalAccessPolicies/run.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListConditionalAccessPolicies.ps1 @@ -1,9 +1,14 @@ -using namespace System.Net + using namespace System.Net -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) + Function Invoke-ListConditionalAccessPolicies { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) -$APIName = $TriggerMetadata.FunctionName + $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Accessed this API" -Sev "Debug" @@ -448,4 +453,6 @@ catch { Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = $StatusCode Body = @($GraphRequest) - }) \ No newline at end of file + }) + + } diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListContacts.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListContacts.ps1 new file mode 100644 index 000000000000..768417a1db23 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListContacts.ps1 @@ -0,0 +1,41 @@ +using namespace System.Net + +Function Invoke-ListContacts { + <# + .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' + + $selectlist = 'id', 'companyName', 'displayName', 'mail', 'onPremisesSyncEnabled', 'editURL' + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + $ContactID = $Request.Query.ContactID + + Write-Host "Tenant Filter: $TenantFilter" + try { + $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/contacts/$($ContactID)?`$top=999&`$select=$($selectlist -join ',')" -tenantid $TenantFilter | Select-Object $selectlist | ForEach-Object { + $_.editURL = "https://outlook.office365.com/ecp/@$TenantFilter/UsersGroups/EditContact.aspx?exsvurl=1&realm=$($env:TenantID)&mkt=en-US&id=$($_.id)" + $_ + } + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $StatusCode = [HttpStatusCode]::Forbidden + $GraphRequest = $ErrorMessage + } + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @($GraphRequest | Where-Object -Property id -NE $null) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDefenderState.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDefenderState.ps1 new file mode 100644 index 000000000000..5b5a244c7e72 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDefenderState.ps1 @@ -0,0 +1,37 @@ +using namespace System.Net + +Function Invoke-ListDefenderState { + <# + .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' + $StatusCode = [HttpStatusCode]::OK + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + try { + $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/tenantRelationships/managedTenants/windowsProtectionStates?`$top=999&`$filter=tenantId eq '$TenantFilter'" + if ($GraphRequest.tenantDisplayName.length -lt 1) { + $StatusCode = [HttpStatusCode]::Forbidden + $GraphRequest = 'No data found - This client might not be onboarded in Lighthouse' + } + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $StatusCode = [HttpStatusCode]::Forbidden + $GraphRequest = "Could not connect to Azure Lighthouse API: $($ErrorMessage)" + } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @($GraphRequest) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDefenderTVM.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDefenderTVM.ps1 new file mode 100644 index 000000000000..2011f161abaf --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDefenderTVM.ps1 @@ -0,0 +1,49 @@ +using namespace System.Net + +Function Invoke-ListDefenderTVM { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + try { + $GraphRequest = New-GraphgetRequest -tenantid $TenantFilter -uri "https://api.securitycenter.microsoft.com/api/machines/SoftwareVulnerabilitiesByMachine?`$top=999" -scope 'https://api.securitycenter.microsoft.com/.default' | Group-Object cveid + $GroupObj = foreach ($cve in $GraphRequest) { + [pscustomobject]@{ + customerId = $TenantFilter + affectedDevicesCount = $cve.count + cveId = $cve.name + affectedDevices = ($cve.group.deviceName -join ', ') + osPlatform = ($cve.group.osplatform | Sort-Object -Unique) + softwareVendor = ($cve.group.softwareVendor | Sort-Object -Unique) + softwareName = ($cve.group.softwareName | Sort-Object -Unique) + vulnerabilitySeverityLevel = ($cve.group.vulnerabilitySeverityLevel | Sort-Object -Unique) + cvssScore = ($cve.group.cvssScore | Sort-Object -Unique) + securityUpdateAvailable = ($cve.group.securityUpdateAvailable | Sort-Object -Unique) + exploitabilityLevel = ($cve.group.exploitabilityLevel | Sort-Object -Unique) + } + } + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $StatusCode = [HttpStatusCode]::Forbidden + $GroupObj = $ErrorMessage + } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @($GroupObj) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDeletedItems.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDeletedItems.ps1 new file mode 100644 index 000000000000..2f3488655fa0 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDeletedItems.ps1 @@ -0,0 +1,30 @@ +using namespace System.Net + +Function Invoke-ListDeletedItems { + <# + .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' + + $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' + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + $Types = 'Application', 'User', 'Device', 'Group' + $GraphRequest = foreach ($Type in $Types) { + (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/directory/deletedItems/microsoft.graph.$($Type)" -tenantid $TenantFilter) | Where-Object -Property '@odata.context' -NotLike '*graph.microsoft.com*' | Select-Object *, @{ Name = 'TargetType'; Expression = { $Type } } + } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @($GraphRequest) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDeviceDetails.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDeviceDetails.ps1 new file mode 100644 index 000000000000..f3a4d9f309c9 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDeviceDetails.ps1 @@ -0,0 +1,100 @@ +using namespace System.Net + +Function Invoke-ListDeviceDetails { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + $DeviceID = $Request.Query.DeviceID + $DeviceName = $Request.Query.DeviceName + $DeviceSerial = $Request.Query.DeviceSerial + + try { + if ($DeviceID) { + $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceManagement/managedDevices/$DeviceID" -Tenantid $tenantfilter + } elseif ($DeviceSerial -or $DeviceName) { + $Found = $False + if ($SeriaNumber -and $DeviceName) { + $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceManagement/managedDevices?`$filter=serialnumber eq '$DeviceSerial' and deviceName eq '$DeviceName'" -Tenantid $tenantfilter + + if (($GraphRequest | Measure-Object).count -eq 1 -and $GraphRequest.'@odata.count' -ne 0 ) { + $Found = $True + } + } + if ($DeviceSerial -and $Found -eq $False) { + $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceManagement/managedDevices?`$filter=serialnumber eq '$DeviceSerial'" -Tenantid $tenantfilter + if (($GraphRequest | Measure-Object).count -eq 1 -and $GraphRequest.'@odata.count' -ne 0 ) { + $Found = $True + } + } + if ($DeviceName -and $Found -eq $False) { + $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceManagement/managedDevices?`$filter=deviceName eq '$DeviceName'" -Tenantid $tenantfilter + if (($GraphRequest | Measure-Object).count -eq 1 -and $GraphRequest.'@odata.count' -ne 0 ) { + $Found = $True + } + } + + } + + if (!(($GraphRequest | Measure-Object).count -eq 1 -and $GraphRequest.'@odata.count' -ne 0 )) { + $GraphRequest = $Null + } + + if ($GraphRequest) { + [System.Collections.Generic.List[PSCustomObject]]$BulkRequests = @( + @{ + id = 'DeviceGroups' + method = 'GET' + url = "/devices(deviceID='$($GraphRequest.azureADDeviceId)')/memberOf" + }, + @{ + id = 'CompliancePolicies' + method = 'GET' + url = "/deviceManagement/managedDevices('$($GraphRequest.id)')/deviceCompliancePolicyStates" + }, + @{ + id = 'DetectedApps' + method = 'GET' + url = "deviceManagement/managedDevices('$($GraphRequest.id)')?expand=detectedApps" + } + ) + + $BulkResults = New-GraphBulkRequest -Requests $BulkRequests -tenantid $TenantFilter + + $DeviceGroups = Get-GraphBulkResultByID -Results $BulkResults -ID 'DeviceGroups' -Value + $CompliancePolicies = Get-GraphBulkResultByID -Results $BulkResults -ID 'CompliancePolicies' -Value + $DetectedApps = Get-GraphBulkResultByID -Results $BulkResults -ID 'DetectedApps' + + $Null = $GraphRequest | Add-Member -NotePropertyName 'DetectedApps' -NotePropertyValue ($DetectedApps.DetectedApps | Select-Object id, displayName, version) + $Null = $GraphRequest | Add-Member -NotePropertyName 'CompliancePolicies' -NotePropertyValue ($CompliancePolicies | Select-Object id, displayname, UserPrincipalName, state) + $Null = $GraphRequest | Add-Member -NotePropertyName 'DeviceGroups' -NotePropertyValue ($DeviceGroups | Select-Object id, displayName, description) + + + } + + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $StatusCode = [HttpStatusCode]::Forbidden + $GraphRequest = $ErrorMessage + + } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = $GraphRequest + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDevices.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDevices.ps1 new file mode 100644 index 000000000000..8587a32155e3 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDevices.ps1 @@ -0,0 +1,35 @@ +using namespace System.Net + +Function Invoke-ListDevices { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + try { + $GraphRequest = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/deviceManagement/managedDevices' -Tenantid $tenantfilter + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $StatusCode = [HttpStatusCode]::Forbidden + $GraphRequest = $ErrorMessage + + } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @($GraphRequest) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDomainHealth.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDomainHealth.ps1 new file mode 100644 index 000000000000..695fb64ffa29 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDomainHealth.ps1 @@ -0,0 +1,153 @@ +using namespace System.Net + +Function Invoke-ListDomainHealth { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + Import-Module DNSHealth + + try { + $ConfigTable = Get-CippTable -tablename Config + $Filter = "PartitionKey eq 'Domains' and RowKey eq 'Domains'" + $Config = Get-CIPPAzDataTableEntity @ConfigTable -Filter $Filter + + $ValidResolvers = @('Google', 'CloudFlare', 'Quad9') + if ($ValidResolvers -contains $Config.Resolver) { + $Resolver = $Config.Resolver + } else { + $Resolver = 'Google' + $Config = @{ + PartitionKey = 'Domains' + RowKey = 'Domains' + Resolver = $Resolver + } + Add-CIPPAzDataTableEntity @ConfigTable -Entity $Config -Force + } + } catch { + $Resolver = 'Google' + } + + Set-DnsResolver -Resolver $Resolver + + $UserCreds = ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($request.headers.'x-ms-client-principal')) | ConvertFrom-Json) + + $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.' + + $StatusCode = [HttpStatusCode]::OK + try { + if ($Request.Query.Action) { + if ($Request.Query.Domain -match '^(((?!-))(xn--|_{1,1})?[a-z0-9-]{0,61}[a-z0-9]{1,1}\.)*(xn--)?([a-z0-9][a-z0-9\-]{0,60}|[a-z0-9-]{1,30}\.[a-z]{2,})$') { + $DomainTable = Get-CIPPTable -Table 'Domains' + $Filter = "RowKey eq '{0}'" -f $Request.Query.Domain + $DomainInfo = Get-CIPPAzDataTableEntity @DomainTable -Filter $Filter + switch ($Request.Query.Action) { + 'ListDomainInfo' { + $Body = $DomainInfo + } + 'GetDkimSelectors' { + $Body = ($DomainInfo.DkimSelectors | ConvertFrom-Json) -join ',' + } + 'ReadSpfRecord' { + $SpfQuery = @{ + Domain = $Request.Query.Domain + } + + if ($Request.Query.ExpectedInclude) { + $SpfQuery.ExpectedInclude = $Request.Query.ExpectedInclude + } + + if ($Request.Query.Record) { + $SpfQuery.Record = $Request.Query.Record + } + + $Body = Read-SpfRecord @SpfQuery + } + 'ReadDmarcPolicy' { + $Body = Read-DmarcPolicy -Domain $Request.Query.Domain + } + 'ReadDkimRecord' { + $DkimQuery = @{ + Domain = $Request.Query.Domain + } + if ($Request.Query.Selector) { + $DkimQuery.Selectors = ($Request.Query.Selector).trim() -split '\s*,\s*' + + if ('admin' -in $UserCreds.userRoles -or 'editor' -in $UserCreds.userRoles) { + $DkimSelectors = [string]($DkimQuery.Selectors | ConvertTo-Json -Compress) + if ($DomainInfo) { + $DomainInfo.DkimSelectors = $DkimSelectors + } else { + $DomainInfo = @{ + 'RowKey' = $Request.Query.Domain + 'PartitionKey' = 'ManualEntry' + 'TenantId' = 'NoTenant' + 'MailProviders' = '' + 'TenantDetails' = '' + 'DomainAnalyser' = '' + 'DkimSelectors' = $DkimSelectors + } + } + Write-Host $DomainInfo + Add-CIPPAzDataTableEntity @DomainTable -Entity $DomainInfo -Force + } + } elseif (![string]::IsNullOrEmpty($DomainInfo.DkimSelectors)) { + $DkimQuery.Selectors = [System.Collections.Generic.List[string]]($DomainInfo.DkimSelectors | ConvertFrom-Json) + } + $Body = Read-DkimRecord @DkimQuery + + } + 'ReadMXRecord' { + $Body = Read-MXRecord -Domain $Request.Query.Domain + } + 'TestDNSSEC' { + $Body = Test-DNSSEC -Domain $Request.Query.Domain + } + 'ReadWhoisRecord' { + $Body = Read-WhoisRecord -Query $Request.Query.Domain + } + 'ReadNSRecord' { + $Body = Read-NSRecord -Domain $Request.Query.Domain + } + 'TestHttpsCertificate' { + $HttpsQuery = @{ + Domain = $Request.Query.Domain + } + if ($Request.Query.Subdomains) { + $HttpsQuery.Subdomains = ($Request.Query.Subdomains).trim() -split '\s*,\s*' + } else { + $HttpsQuery.Subdomains = 'www' + } + + $Body = Test-HttpsCertificate @HttpsQuery + } + 'TestMtaSts' { + $HttpsQuery = @{ + Domain = $Request.Query.Domain + } + $Body = Test-MtaSts @HttpsQuery + } + } + } else { + $body = [pscustomobject]@{'Results' = "Domain: $($Request.Query.Domain) is invalid" } + } + } + } 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)" } + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = $body + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDomains.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDomains.ps1 new file mode 100644 index 000000000000..113b9d53a304 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDomains.ps1 @@ -0,0 +1,35 @@ +using namespace System.Net + +Function Invoke-ListDomains { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + + try { + $GraphRequest = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/domains' -tenantid $TenantFilter | Select-Object id, isdefault, isinitial | Sort-Object isdefault + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $StatusCode = [HttpStatusCode]::Forbidden + $GraphRequest = $ErrorMessage + } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @($GraphRequest) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListExConnectorTemplates.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListExConnectorTemplates.ps1 new file mode 100644 index 000000000000..28dc15275c83 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListExConnectorTemplates.ps1 @@ -0,0 +1,36 @@ +using namespace System.Net + +Function Invoke-ListExConnectorTemplates { + <# + .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' + $Table = Get-CippTable -tablename 'templates' + + #List new policies + $Table = Get-CippTable -tablename 'templates' + $Filter = "PartitionKey eq 'ExConnectorTemplate'" + $Templates = (Get-CIPPAzDataTableEntity @Table -Filter $Filter) | ForEach-Object { + $GUID = $_.RowKey + $Direction = $_.direction + $data = $_.JSON | ConvertFrom-Json + $data | Add-Member -NotePropertyName 'GUID' -NotePropertyValue $GUID + $data | Add-Member -NotePropertyName 'cippconnectortype' -NotePropertyValue $Direction + $data + } + + if ($Request.query.ID) { $Templates = $Templates | Where-Object -Property RowKey -EQ $Request.query.id } + + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @($Templates) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListExchangeConnectors.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListExchangeConnectors.ps1 new file mode 100644 index 000000000000..35b1863f45f8 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListExchangeConnectors.ps1 @@ -0,0 +1,31 @@ +using namespace System.Net + +Function Invoke-ListExchangeConnectors { + <# + .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' + $Tenantfilter = $request.Query.tenantfilter + + $Results = try { + New-ExoRequest -tenantid $Tenantfilter -cmdlet 'Get-OutboundConnector' | Select-Object *, @{n = 'cippconnectortype'; e = { 'outbound' } } + New-ExoRequest -tenantid $Tenantfilter -cmdlet 'Get-InboundConnector' | Select-Object *, @{n = 'cippconnectortype'; e = { 'Inbound' } } + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $StatusCode = [HttpStatusCode]::Forbidden + $ErrorMessage + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @($Results) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListExtensionsConfig.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListExtensionsConfig.ps1 new file mode 100644 index 000000000000..5e9cd48198c8 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListExtensionsConfig.ps1 @@ -0,0 +1,26 @@ +using namespace System.Net + +Function Invoke-ListExtensionsConfig { + <# + .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' + + $Table = Get-CIPPTable -TableName Extensionsconfig + try { + $Body = (Get-CIPPAzDataTableEntity @Table).config | ConvertFrom-Json -Depth 10 -ErrorAction Stop + } catch { + $Body = @{} + } + # 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/Entrypoints/Invoke-ListExternalTenantInfo.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListExternalTenantInfo.ps1 new file mode 100644 index 000000000000..2bec443954b5 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListExternalTenantInfo.ps1 @@ -0,0 +1,77 @@ +using namespace System.Net + +Function Invoke-ListExternalTenantInfo { + <# + .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' + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # Interact with query parameters or the body of the request. + $Tenant = $request.query.tenant + + # Normalize to tenantid and determine if tenant exists + $TenantId = (Invoke-RestMethod -Method GET "https://login.windows.net/$tenant/.well-known/openid-configuration").token_endpoint.Split('/')[3] + + if ($TenantId) { + $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/tenantRelationships/findTenantInformationByTenantId(tenantId='$TenantId')" -noauthcheck $true -tenantid $TenantFilter + $StatusCode = [HttpStatusCode]::OK + } + + if ($GraphRequest) { + + $TenantDefaultDomain = $GraphRequest.defaultDomainName + + $body = @" + + + + http://schemas.microsoft.com/exchange/2010/Autodiscover/Autodiscover/GetFederationInformation + https://autodiscover-s.outlook.com/autodiscover/autodiscover.svc + + http://www.w3.org/2005/08/addressing/anonymous + + + + + + $TenantDefaultDomain + + + + +"@ + + # Create the headers + $headers = @{ + 'Content-Type' = 'text/xml; charset=utf-8' + 'SOAPAction' = '"http://schemas.microsoft.com/exchange/2010/Autodiscover/Autodiscover/GetFederationInformation"' + 'User-Agent' = 'AutodiscoverClient' + } + + # Invoke + $response = Invoke-RestMethod -UseBasicParsing -Method Post -Uri 'https://autodiscover-s.outlook.com/autodiscover/autodiscover.svc' -Body $body -Headers $headers + + # Return + $TenantDomains = $response.Envelope.body.GetFederationInformationResponseMessage.response.Domains.Domain | Sort-Object + } + + $results = [PSCustomObject]@{ + GraphRequest = $GraphRequest + Domains = $TenantDomains + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = $results + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGDAPInvite.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGDAPInvite.ps1 new file mode 100644 index 000000000000..3ae888f60ec8 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGDAPInvite.ps1 @@ -0,0 +1,32 @@ +using namespace System.Net + +Function Invoke-ListGDAPInvite { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + Write-Host ($Request | ConvertTo-Json) + if (![string]::IsNullOrEmpty($Request.Query.RelationshipId)) { + $Table = Get-CIPPTable -TableName 'GDAPInvites' + $Invite = Get-CIPPAzDataTableEntity @Table -Filter "RowKey eq '$($Request.Query.RelationshipId)'" + Write-Host $Invite + } else { + $Invite = @{} + } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Invite + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGDAPQueue.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGDAPQueue.ps1 new file mode 100644 index 000000000000..94f43d623abe --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGDAPQueue.ps1 @@ -0,0 +1,35 @@ +using namespace System.Net + +Function Invoke-ListGDAPQueue { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + $Table = Get-CIPPTable -TableName 'GDAPMigration' + $QueuedApps = Get-CIPPAzDataTableEntity @Table + + $CurrentStandards = foreach ($QueueFile in $QueuedApps) { + [PSCustomObject]@{ + Tenant = $QueueFile.tenant + Status = $QueueFile.status + StartAt = $QueueFile.startAt + } + } + + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @($CurrentStandards) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGDAPRoles.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGDAPRoles.ps1 new file mode 100644 index 000000000000..0102748cb4f8 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGDAPRoles.ps1 @@ -0,0 +1,35 @@ +using namespace System.Net + +Function Invoke-ListGDAPRoles { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + $Table = Get-CIPPTable -TableName 'GDAPRoles' + $Groups = Get-CIPPAzDataTableEntity @Table + + $MappedGroups = foreach ($Group in $Groups) { + [PSCustomObject]@{ + GroupName = $Group.GroupName + GroupId = $Group.GroupId + RoleName = $Group.RoleName + roleDefinitionId = $Group.roleDefinitionId + } + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @($MappedGroups) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGenericAllTenants.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGenericAllTenants.ps1 new file mode 100644 index 000000000000..00ddc0156cbb --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGenericAllTenants.ps1 @@ -0,0 +1,49 @@ +using namespace System.Net + +Function Invoke-ListGenericAllTenants { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $TableURLName = ($QueueItem.tolower().split('?').Split('/') | Select-Object -First 1).toString() + $QueueKey = (Get-CippQueue | Where-Object -Property Name -EQ $TableURLName | Select-Object -Last 1).RowKey + Update-CippQueueEntry -RowKey $QueueKey -Status 'Started' + $Table = Get-CIPPTable -TableName "cache$TableURLName" + $fullUrl = "https://graph.microsoft.com/beta/$QueueItem" + Get-CIPPAzDataTableEntity @Table | Remove-AzDataTableEntity @table + + $RawGraphRequest = Get-Tenants | ForEach-Object -Parallel { + $domainName = $_.defaultDomainName + Import-Module '.\Modules\AzBobbyTables' + Import-Module '.\Modules\CIPPCore' + try { + Write-Host $using:fullUrl + New-GraphGetRequest -uri $using:fullUrl -tenantid $_.defaultDomainName -ComplexFilter -ErrorAction Stop | Select-Object *, @{l = 'Tenant'; e = { $domainName } }, @{l = 'CippStatus'; e = { 'Good' } } + } catch { + [PSCustomObject]@{ + Tenant = $domainName + CippStatus = "Could not connect to tenant. $($_.Exception.message)" + } + } + } + + Update-CippQueueEntry -RowKey $QueueKey -Status 'Processing' + foreach ($Request in $RawGraphRequest) { + $Json = ConvertTo-Json -Compress -InputObject $request + $GraphRequest = [PSCustomObject]@{ + Tenant = [string]$Request.tenant + RowKey = [string](New-Guid) + PartitionKey = [string]$URL + Data = [string]$Json + + } + Add-CIPPAzDataTableEntity @Table -Entity $GraphRequest -Force | Out-Null + } + + + Update-CippQueueEntry -RowKey $QueueKey -Status 'Completed' + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGenericTestFunction.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGenericTestFunction.ps1 new file mode 100644 index 000000000000..80012cd30de9 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGenericTestFunction.ps1 @@ -0,0 +1,20 @@ +using namespace System.Net + +Function Invoke-ListGenericTestFunction { + <# + .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' + $graphRequest = ($request.headers.'x-ms-original-url').split('/api') | Select-Object -First 1 + + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @($graphRequest) + }) -clobber + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGroupTemplates.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGroupTemplates.ps1 new file mode 100644 index 000000000000..205410cd9f92 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGroupTemplates.ps1 @@ -0,0 +1,36 @@ +using namespace System.Net + +Function Invoke-ListGroupTemplates { + <# + .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' + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + Write-Host $Request.query.id + + #List new policies + $Table = Get-CippTable -tablename 'templates' + $Filter = "PartitionKey eq 'GroupTemplate'" + $Templates = (Get-CIPPAzDataTableEntity @Table -Filter $Filter) | ForEach-Object { + $data = $_.JSON | ConvertFrom-Json + $data | Add-Member -MemberType NoteProperty -Name GUID -Value $_.RowKey -Force + $data + } | Sort-Object -Property displayName + + if ($Request.query.ID) { $Templates = $Templates | Where-Object -Property GUID -EQ $Request.query.id } + + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @($Templates) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGroups.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGroups.ps1 new file mode 100644 index 000000000000..c2196b1a4e4a --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGroups.ps1 @@ -0,0 +1,77 @@ +using namespace System.Net + +Function Invoke-ListGroups { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # Interact with query parameters or the body of the request. + + $TenantFilter = $Request.Query.TenantFilter + $selectstring = "id,createdDateTime,displayName,description,mail,mailEnabled,mailNickname,resourceProvisioningOptions,securityEnabled,visibility,organizationId,onPremisesSamAccountName,membershipRule,grouptypes,onPremisesSyncEnabled,resourceProvisioningOptions,userPrincipalName&`$expand=members(`$select=userPrincipalName)" + + if ($Request.Query.GroupID) { + $groupid = $Request.query.groupid + $selectstring = 'id,createdDateTime,displayName,description,mail,mailEnabled,mailNickname,resourceProvisioningOptions,securityEnabled,visibility,organizationId,onPremisesSamAccountName,membershipRule,groupTypes,userPrincipalName' + } + if ($Request.Query.members) { + $members = 'members' + $selectstring = 'id,userPrincipalName,displayName,hideFromOutlookClients,hideFromAddressLists,mail,mailEnabled,mailNickname,resourceProvisioningOptions,securityEnabled,visibility,organizationId,onPremisesSamAccountName,membershipRule' + } + + if ($Request.Query.owners) { + $members = 'owners' + $selectstring = 'id,userPrincipalName,displayName,hideFromOutlookClients,hideFromAddressLists,mail,mailEnabled,mailNickname,resourceProvisioningOptions,securityEnabled,visibility,organizationId,onPremisesSamAccountName,membershipRule' + } + try { + $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/groups/$($GroupID)/$($members)?`$top=999&select=$selectstring" -tenantid $TenantFilter | Select-Object *, @{ Name = 'primDomain'; Expression = { $_.mail -split '@' | Select-Object -Last 1 } }, + @{Name = 'membersCsv'; Expression = { $_.members.userPrincipalName -join ',' } }, + @{Name = 'teamsEnabled'; Expression = { if ($_.resourceProvisioningOptions -Like '*Team*') { $true }else { $false } } }, + @{Name = 'calculatedGroupType'; Expression = { + + if ($_.mailEnabled -and $_.securityEnabled) { + 'Mail-Enabled Security' + } + if (!$_.mailEnabled -and $_.securityEnabled) { + 'Security' + } + if ($_.groupTypes -contains 'Unified') { + 'Microsoft 365' + } + if (([string]::isNullOrEmpty($_.groupTypes)) -and ($_.mailEnabled) -and (!$_.securityEnabled)) { + 'Distribution List' + } + } + }, + @{Name = 'dynamicGroupBool'; Expression = { + if ($_.groupTypes -contains 'DynamicMembership') { + $true + } else { + $false + } + } + } + + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $StatusCode = [HttpStatusCode]::Forbidden + $GraphRequest = $ErrorMessage + } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @($GraphRequest) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListHaloClients.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListHaloClients.ps1 new file mode 100644 index 000000000000..84b1b3cae514 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListHaloClients.ps1 @@ -0,0 +1,49 @@ +using namespace System.Net + +Function Invoke-ListHaloClients { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # Interact with query parameters or the body of the request. + try { + $Table = Get-CIPPTable -TableName Extensionsconfig + $Configuration = ((Get-CIPPAzDataTableEntity @Table).config | ConvertFrom-Json).HaloPSA + $Token = Get-HaloToken -configuration $Configuration + $i = 1 + $RawHaloClients = do { + $Result = Invoke-RestMethod -Uri "$($Configuration.ResourceURL)/Client?page_no=$i&page_size=999&pageinate=true" -ContentType 'application/json' -Method GET -Headers @{Authorization = "Bearer $($token.access_token)" } + $Result.clients | Select-Object * -ExcludeProperty logo + $i++ + $pagecount = [Math]::Ceiling($Result.record_count / 999) + } while ($i -le $pagecount) + $HaloClients = $RawHaloClients | ForEach-Object { + [PSCustomObject]@{ + label = $_.name + value = $_.id + } + } + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $StatusCode = [HttpStatusCode]::Forbidden + $HaloClients = $ErrorMessage + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @($HaloClients) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListInactiveAccounts.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListInactiveAccounts.ps1 new file mode 100644 index 000000000000..3ce42719c362 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListInactiveAccounts.ps1 @@ -0,0 +1,36 @@ +using namespace System.Net + +Function Invoke-ListInactiveAccounts { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + if ($TenantFilter -eq 'AllTenants') { $TenantFilter = (get-tenants).customerId } + try { + $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/tenantRelationships/managedTenants/inactiveUsers?`$count=true" -tenantid $env:TenantId | Where-Object { $_.tenantId -in $TenantFilter } + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $StatusCode = [HttpStatusCode]::Forbidden + $GraphRequest = "Could not connect to Azure Lighthouse API: $($ErrorMessage)" + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @($GraphRequest) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListIntuneIntents.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListIntuneIntents.ps1 new file mode 100644 index 000000000000..cb98c87d6e67 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListIntuneIntents.ps1 @@ -0,0 +1,35 @@ +using namespace System.Net + +Function Invoke-ListIntuneIntents { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + try { + $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceManagement/Intents?`$expand=settings,categories" -tenantid $TenantFilter + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $StatusCode = [HttpStatusCode]::Forbidden + $GraphRequest = $ErrorMessage + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @($GraphRequest) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListIntunePolicy.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListIntunePolicy.ps1 new file mode 100644 index 000000000000..5429292d5a6c --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListIntunePolicy.ps1 @@ -0,0 +1,67 @@ +using namespace System.Net + +Function Invoke-ListIntunePolicy { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + $id = $Request.Query.ID + $urlname = $Request.Query.URLName + try { + if ($ID) { + $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$($urlname)('$ID')" -tenantid $tenantfilter + } else { + + $GraphURLS = @("https://graph.microsoft.com/beta/deviceManagement/deviceConfigurations?`$select=id,displayName,lastModifiedDateTime,roleScopeTagIds,microsoft.graph.unsupportedDeviceConfiguration/originalEntityTypeName&`$expand=assignments&top=1000", + "https://graph.microsoft.com/beta/deviceManagement/groupPolicyConfigurations?`$expand=assignments&top=1000" + "https://graph.microsoft.com/beta/deviceAppManagement/mobileAppConfigurations?`$expand=assignments&`$filter=microsoft.graph.androidManagedStoreAppConfiguration/appSupportsOemConfig%20eq%20true" + 'https://graph.microsoft.com/beta/deviceManagement/configurationPolicies' + ) + + $GraphRequest = $GraphURLS | ForEach-Object { + $URLName = (($_).split('?') | Select-Object -First 1) -replace 'https://graph.microsoft.com/beta/deviceManagement/', '' + New-GraphGetRequest -uri $_ -tenantid $TenantFilter + + } | ForEach-Object { + $policyTypeName = switch -Wildcard ($_.'assignments@odata.context') { + '*microsoft.graph.windowsIdentityProtectionConfiguration*' { 'Identity Protection' } + '*microsoft.graph.windows10EndpointProtectionConfiguration*' { 'Endpoint Protection' } + '*microsoft.graph.windows10CustomConfiguration*' { 'Custom' } + '*groupPolicyConfigurations*' { 'Administrative Templates' } + '*windowsDomainJoinConfiguration*' { 'Domain Join configuration' } + '*windowsUpdateForBusinessConfiguration*' { 'Update Configuration' } + '*windowsHealthMonitoringConfiguration*' { 'Health Monitoring' } + default { $_.'assignments@odata.context' } + } + if ($_.displayname -eq $null) { $_ | Add-Member -NotePropertyName displayName -NotePropertyValue $_.name } + $_ | Add-Member -NotePropertyName PolicyTypeName -NotePropertyValue $policyTypeName + $_ | Add-Member -NotePropertyName URLName -NotePropertyValue $URLName + $_ + } | Where-Object { $_.DisplayName -ne $null } + + } + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $StatusCode = [HttpStatusCode]::Forbidden + $GraphRequest = $ErrorMessage + } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @($GraphRequest) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListIntuneTemplates.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListIntuneTemplates.ps1 new file mode 100644 index 000000000000..e3270a1834b0 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListIntuneTemplates.ps1 @@ -0,0 +1,50 @@ +using namespace System.Net + +Function Invoke-ListIntuneTemplates { + <# + .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' + + $Table = Get-CippTable -tablename 'templates' + + $Templates = Get-ChildItem 'Config\*.IntuneTemplate.json' | ForEach-Object { + $Entity = @{ + JSON = "$(Get-Content $_)" + RowKey = "$($_.name)" + PartitionKey = 'IntuneTemplate' + GUID = "$($_.name)" + } + Add-CIPPAzDataTableEntity @Table -Entity $Entity -Force + } + + #List new policies + $Table = Get-CippTable -tablename 'templates' + $Filter = "PartitionKey eq 'IntuneTemplate'" + $Templates = (Get-CIPPAzDataTableEntity @Table -Filter $Filter).JSON | ConvertFrom-Json + if ($Request.query.View) { + $Templates = $Templates | ForEach-Object { + $data = $_.RAWJson | ConvertFrom-Json + $data | Add-Member -NotePropertyName 'displayName' -NotePropertyValue $_.Displayname -Force + $data | Add-Member -NotePropertyName 'description' -NotePropertyValue $_.Description -Force + $data | Add-Member -NotePropertyName 'Type' -NotePropertyValue $_.Type + $data | Add-Member -NotePropertyName 'GUID' -NotePropertyValue $_.GUID + $data + } + } + + if ($Request.query.ID) { $Templates = $Templates | Where-Object -Property guid -EQ $Request.query.id } + + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = ($Templates | ConvertTo-Json -Depth 10) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListKnownIPDb.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListKnownIPDb.ps1 new file mode 100644 index 000000000000..061146ae725f --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListKnownIPDb.ps1 @@ -0,0 +1,27 @@ +using namespace System.Net + +Function Invoke-ListKnownIPDb { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + $Table = Get-CIPPTable -TableName 'knownlocationdb' + $Filter = "Tenant eq '$($Request.Query.TenantFilter)'" + $KnownIPDb = Get-CIPPAzDataTableEntity @Table -Filter $Filter + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @($KnownIPDb) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLicenses.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLicenses.ps1 new file mode 100644 index 000000000000..27c2db9767a3 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLicenses.ps1 @@ -0,0 +1,41 @@ +using namespace System.Net + +Function Invoke-ListLicenses { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + $RawGraphRequest = if ($TenantFilter -ne 'AllTenants') { + $GraphRequest = Get-CIPPLicenseOverview -TenantFilter $TenantFilter + } else { + $Table = Get-CIPPTable -TableName cachelicenses + $Rows = Get-CIPPAzDataTableEntity @Table | Where-Object -Property Timestamp -GT (Get-Date).AddHours(-1) + if (!$Rows) { + Push-OutputBinding -Name LicenseQueue -Value (Get-Date).ToString() + $GraphRequest = [PSCustomObject]@{ + Tenant = 'Loading data for all tenants. Please check back in 1 minute' + License = 'Loading data for all tenants. Please check back in 1 minute' + } + } else { + $GraphRequest = $Rows + } + } + + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @($GraphRequest) + }) -Clobber + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLicensesAllTenants.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLicensesAllTenants.ps1 new file mode 100644 index 000000000000..7d6c25d9daa7 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLicensesAllTenants.ps1 @@ -0,0 +1,35 @@ +using namespace System.Net + +Function Invoke-ListLicensesAllTenants { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + + $RawGraphRequest = Get-Tenants | ForEach-Object -Parallel { + $domainName = $_.defaultDomainName + + Import-Module '.\Modules\AzBobbyTables' + Import-Module '.\Modules\CIPPCore' + try { + Write-Host "Processing $domainName" + Get-CIPPLicenseOverview -TenantFilter $domainName + } catch { + [pscustomobject]@{ + Tenant = [string]$domainName + License = "Could not connect to client: $($_.Exception.Message)" + 'PartitionKey' = 'License' + 'RowKey' = "$($domainName)-$(New-Guid)" + } + } + } + + $Table = Get-CIPPTable -TableName cachelicenses + foreach ($GraphRequest in $RawGraphRequest) { + Add-CIPPAzDataTableEntity @Table -Entity $GraphRequest -Force | Out-Null + } + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLogs.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLogs.ps1 new file mode 100644 index 000000000000..319b43a00995 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLogs.ps1 @@ -0,0 +1,59 @@ +using namespace System.Net + +Function Invoke-ListLogs { + <# + .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 ($request.Query.Filter -eq 'True') { + $LogLevel = if ($Request.query.Severity) { ($Request.query.Severity).split(',') } else { 'Info', 'Warn', 'Error', 'Critical', 'Alert' } + $PartitionKey = $Request.query.DateFilter + $username = $Request.Query.User + } else { + $LogLevel = 'Info', 'Warn', 'Error', 'Critical', 'Alert' + $PartitionKey = Get-Date -UFormat '%Y%m%d' + $username = '*' + } + $Table = Get-CIPPTable + + $ReturnedLog = if ($Request.Query.ListLogs) { + + Get-CIPPAzDataTableEntity @Table -Property PartitionKey | Sort-Object -Unique PartitionKey | Select-Object PartitionKey | ForEach-Object { + @{ + value = $_.PartitionKey + label = $_.PartitionKey + } + } + } else { + $Filter = "PartitionKey eq '{0}'" -f $PartitionKey + $Rows = Get-CIPPAzDataTableEntity @Table -Filter $Filter | Where-Object { $_.Severity -In $LogLevel -and $_.user -like $username } + foreach ($Row in $Rows) { + @{ + DateTime = $Row.Timestamp + Tenant = $Row.Tenant + API = $Row.API + Message = $Row.Message + User = $Row.Username + Severity = $Row.Severity + TenantID = if ($Row.TenantID -ne $null) { + $Row.TenantID + } else { + 'None' + } + } + } + + } + + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @($ReturnedLog) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMFAUsers.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMFAUsers.ps1 new file mode 100644 index 000000000000..32314d2298d8 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMFAUsers.ps1 @@ -0,0 +1,41 @@ +using namespace System.Net + +Function Invoke-ListMFAUsers { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + if ($Request.query.TenantFilter -ne 'AllTenants') { + $GraphRequest = Get-CIPPMFAState -TenantFilter $Request.query.TenantFilter + } else { + $Table = Get-CIPPTable -TableName cachemfa + + $Rows = Get-CIPPAzDataTableEntity @Table | Where-Object -Property Timestamp -GT (Get-Date).AddHours(-2) + if (!$Rows) { + $Queue = New-CippQueueEntry -Name 'MFA Users - All Tenants' -Link '/identity/reports/mfa-report?customerId=AllTenants' + Write-Information ($Queue | ConvertTo-Json) + Push-OutputBinding -Name mfaqueue -Value $Queue.RowKey + $GraphRequest = [PSCustomObject]@{ + UPN = 'Loading data for all tenants. Please check back in 10 minutes' + } + } else { + $GraphRequest = $Rows + } + } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @($GraphRequest) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMFAUsersAllTenants.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMFAUsersAllTenants.ps1 new file mode 100644 index 000000000000..8123a963e1ff --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMFAUsersAllTenants.ps1 @@ -0,0 +1,63 @@ +using namespace System.Net + +Function Invoke-ListMFAUsersAllTenants { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + + + Write-Information "Item: $QueueItem" + Write-Information ($TriggerMetadata | ConvertTo-Json) + + try { + Update-CippQueueEntry -RowKey $QueueItem -Status 'Running' + + $GraphRequest = Get-Tenants | ForEach-Object -Parallel { + $domainName = $_.defaultDomainName + Import-Module '.\modules\CippCore' + Import-Module '.\Modules\AzBobbyTables' + + $Table = Get-CIPPTable -TableName cachemfa + Try { + $GraphRequest = Get-CIPPMFAState -TenantFilter $domainName -ErrorAction Stop + } catch { + $GraphRequest = $null + } + if (!$GraphRequest) { + $GraphRequest = @{ + Tenant = [string]$tenantName + UPN = [string]$domainName + AccountEnabled = 'none' + PerUser = [string]'Could not connect to tenant' + MFARegistration = 'none' + CoveredByCA = [string]'Could not connect to tenant' + CoveredBySD = 'none' + RowKey = [string]"$domainName" + PartitionKey = 'users' + } + } + Add-CIPPAzDataTableEntity @Table -Entity $GraphRequest -Force | Out-Null + } + } catch { + $Table = Get-CIPPTable -TableName cachemfa + $GraphRequest = @{ + Tenant = [string]$tenantName + UPN = [string]$domainName + AccountEnabled = 'none' + PerUser = [string]'Could not connect to tenant' + MFARegistration = 'none' + CoveredByCA = [string]'Could not connect to tenant' + CoveredBySD = 'none' + RowKey = [string]"$domainName" + PartitionKey = 'users' + } + Add-CIPPAzDataTableEntity @Table -Entity $GraphRequest -Force | Out-Null + } finally { + Update-CippQueueEntry -RowKey $QueueItem -Status 'Completed' + } + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailQuarantine.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailQuarantine.ps1 new file mode 100644 index 000000000000..dba4d4a425aa --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailQuarantine.ps1 @@ -0,0 +1,30 @@ +using namespace System.Net + +Function Invoke-ListMailQuarantine { + <# + .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' + $Tenantfilter = $request.Query.tenantfilter + + try { + $GraphRequest = New-ExoRequest -tenantid $Tenantfilter -cmdlet 'Get-QuarantineMessage' + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $StatusCode = [HttpStatusCode]::Forbidden + $GraphRequest = $ErrorMessage + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @($GraphRequest) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxCAS.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxCAS.ps1 new file mode 100644 index 000000000000..ef93210d4c25 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxCAS.ps1 @@ -0,0 +1,42 @@ +using namespace System.Net + +Function Invoke-ListMailboxCAS { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + try { + $GraphRequest = New-GraphGetRequest -uri "https://outlook.office365.com/adminapi/beta/$($tenantfilter)/CasMailbox" -Tenantid $tenantfilter -scope ExchangeOnline | Select-Object @{ Name = 'displayName'; Expression = { $_.'DisplayName' } }, + @{ Name = 'primarySmtpAddress'; Expression = { $_.'PrimarySMTPAddress' } }, + @{ Name = 'ecpenabled'; Expression = { $_.'ECPEnabled' } }, + @{ Name = 'owaenabled'; Expression = { $_.'OWAEnabled' } }, + @{ Name = 'imapenabled'; Expression = { $_.'IMAPEnabled' } }, + @{ Name = 'popenabled'; Expression = { $_.'POPEnabled' } }, + @{ Name = 'mapienabled'; Expression = { $_.'MAPIEnabled' } }, + @{ Name = 'ewsenabled'; Expression = { $_.'EWSEnabled' } }, + @{ Name = 'activesyncenabled'; Expression = { $_.'ActiveSyncEnabled' } } + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $StatusCode = [HttpStatusCode]::Forbidden + $GraphRequest = $ErrorMessage + } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @($GraphRequest) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxMobileDevices.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxMobileDevices.ps1 new file mode 100644 index 000000000000..8199d4204326 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxMobileDevices.ps1 @@ -0,0 +1,55 @@ +using namespace System.Net + +Function Invoke-ListMailboxMobileDevices { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + $Mailbox = $Request.Query.Mailbox + + Write-Host $TenantFilter + Write-Host $Mailbox + + $Bytes = [System.Text.Encoding]::UTF8.GetBytes($Mailbox) + $base64IdentityParam = [Convert]::ToBase64String($Bytes) + + try { + $GraphRequest = New-GraphGetRequest -uri "https://outlook.office365.com:443/adminapi/beta/$($TenantFilter)/mailbox('$($base64IdentityParam)')/MobileDevice/Exchange.GetMobileDeviceStatistics()/?IsEncoded=True" -Tenantid $tenantfilter -scope ExchangeOnline | Select-Object @{ Name = 'clientType'; Expression = { $_.ClientType } }, + @{ Name = 'clientVersion'; Expression = { $_.ClientVersion } }, + @{ Name = 'deviceAccessState'; Expression = { $_.DeviceAccessState } }, + @{ Name = 'deviceFriendlyName'; Expression = { if ([string]::IsNullOrEmpty($_.DeviceFriendlyName)) { 'Unknown' }else { $_.DeviceFriendlyName } } }, + @{ Name = 'deviceModel'; Expression = { $_.DeviceModel } }, + @{ Name = 'deviceOS'; Expression = { $_.DeviceOS } }, + @{ Name = 'deviceType'; Expression = { $_.DeviceType } }, + @{ Name = 'firstSync'; Expression = { $_.FirstSyncTime.toString() } }, + @{ Name = 'lastSyncAttempt'; Expression = { $_.LastSyncAttemptTime.toString() } }, + @{ Name = 'lastSuccessSync'; Expression = { $_.LastSuccessSync.toString() } }, + @{ Name = 'status'; Expression = { $_.Status } }, + @{ Name = 'deviceID'; Expression = { $_.deviceID } }, + @{ Name = 'Guid'; Expression = { $_.Guid } } + + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $StatusCode = [HttpStatusCode]::Forbidden + $GraphRequest = $ErrorMessage + } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @($GraphRequest) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxRules.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxRules.ps1 new file mode 100644 index 000000000000..7eda4d2074af --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxRules.ps1 @@ -0,0 +1,54 @@ +using namespace System.Net + +Function Invoke-ListMailboxRules { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # 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 + $GraphRequest = [PSCustomObject]@{ + Tenant = 'Loading data. Please check back in 1 minute' + Licenses = 'Loading data. Please check back in 1 minute' + } + } else { + if ($TenantFilter -ne 'AllTenants') { + $GraphRequest = $Rows | Where-Object -Property Tenant -EQ $TenantFilter | ForEach-Object { + $NewObj = $_.Rules | ConvertFrom-Json + $NewObj | Add-Member -NotePropertyName 'Tenant' -NotePropertyValue $TenantFilter + $NewObj + } + } else { + $GraphRequest = $Rows | ForEach-Object { + $TenantName = $_.Tenant + $NewObj = $_.Rules | ConvertFrom-Json + $NewObj | Add-Member -NotePropertyName 'Tenant' -NotePropertyValue $TenantName + $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 + Body = @($GraphRequest) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxRulesAllTenants.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxRulesAllTenants.ps1 new file mode 100644 index 000000000000..ee394cb28adc --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxRulesAllTenants.ps1 @@ -0,0 +1,62 @@ +using namespace System.Net + +Function Invoke-ListMailboxRulesAllTenants { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $Tenants = if ($QueueItem -ne 'AllTenants') { + [PSCustomObject]@{ + defaultDomainName = $QueueItem + } + } else { + Get-Tenants + } + $Tenants | ForEach-Object -Parallel { + $domainName = $_.defaultDomainName + Import-Module '.\Modules\CIPPcore' + Import-Module '.\Modules\AzBobbyTables' + + try { + + $Rules = New-ExoRequest -tenantid $domainName -cmdlet 'Get-Mailbox' | ForEach-Object -Parallel { + Import-Module '.\Modules\AzBobbyTables' + Import-Module '.\Modules\CIPPCore' + New-ExoRequest -Anchor $_.UserPrincipalName -tenantid $domainName -cmdlet 'Get-InboxRule' -cmdParams @{Mailbox = $_.GUID } + } + foreach ($Rule in $Rules) { + $GraphRequest = @{ + Rules = [string]($Rule | ConvertTo-Json) + RowKey = [string](New-Guid).guid + Tenant = [string]$domainName + PartitionKey = 'mailboxrules' + } + $Table = Get-CIPPTable -TableName cachembxrules + Add-CIPPAzDataTableEntity @Table -Entity $GraphRequest -Force | Out-Null + } + } catch { + $Rules = @{ + Name = "Could not connect to tenant $($_.Exception.message)" + } | ConvertTo-Json + $GraphRequest = @{ + Rules = [string]$Rules + RowKey = [string]$domainName + Tenant = [string]$domainName + + PartitionKey = 'mailboxrules' + } + $Table = Get-CIPPTable -TableName cachembxrules + 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-ListMailboxStatistics.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxStatistics.ps1 new file mode 100644 index 000000000000..d1f1af749fb7 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxStatistics.ps1 @@ -0,0 +1,64 @@ +using namespace System.Net + +Function Invoke-ListMailboxStatistics { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + try { + + $GraphRequest = if ($TenantFilter -ne 'AllTenants') { + New-GraphGetRequest -uri "https://graph.microsoft.com/beta/reports/getMailboxUsageDetail(period='D7')" -tenantid $TenantFilter | ConvertFrom-Csv | Select-Object @{ Name = 'UPN'; Expression = { $_.'User Principal Name' } }, + @{ Name = 'displayName'; Expression = { $_.'Display Name' } }, + @{ Name = 'MailboxType'; Expression = { $_.'Recipient Type' } }, + @{ Name = 'LastActive'; Expression = { $_.'Last Activity Date' } }, + @{ Name = 'UsedGB'; Expression = { [math]::round($_.'Storage Used (Byte)' / 1GB, 2) } }, + @{ Name = 'QuotaGB'; Expression = { [math]::round($_.'Prohibit Send/Receive Quota (Byte)' / 1GB, 2) } }, + @{ Name = 'ItemCount'; Expression = { $_.'Item Count' } }, + @{ Name = 'HasArchive'; Expression = { If (($_.'Has Archive').ToLower() -eq 'true') { [bool]$true } else { [bool]$false } } } + $StatusCode = [HttpStatusCode]::OK + } else { + $Table = Get-CIPPTable -TableName 'cachereports' + $Rows = Get-CIPPAzDataTableEntity @Table | Where-Object -Property Timestamp -GT (Get-Date).AddHours(-1) + if (!$Rows) { + $Queue = New-CippQueueEntry -Name 'Reports' -Link '/email/reports/mailbox-statistics?customerId=AllTenants' + Push-OutputBinding -Name mailboxstats -Value "reports/getMailboxUsageDetail(period='D7')?`$format=application/json" + [PSCustomObject]@{ + Tenant = 'Loading data for all tenants. Please check back after the job completes' + } + $StatusCode = [HttpStatusCode]::OK + } else { + $Rows.Data | ConvertFrom-Json | Select-Object *, @{ Name = 'UPN'; Expression = { $_.'UserPrincipalName' } }, + @{ Name = 'MailboxType'; Expression = { $_.'RecipientType' } }, + @{ Name = 'LastActive'; Expression = { $_.'LastActivityDate' } }, + @{ Name = 'UsedGB'; Expression = { [math]::round($_.'storageUsedInBytes' / 1GB, 2) } }, + @{ Name = 'QuotaGB'; Expression = { [math]::round($_.'prohibitSendReceiveQuotaInBytes' / 1GB, 2) } } + $StatusCode = [HttpStatusCode]::OK + } + } + + + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $StatusCode = [HttpStatusCode]::Forbidden + $GraphRequest = $ErrorMessage + } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @($GraphRequest) + }) -clobber + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxes.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxes.ps1 new file mode 100644 index 000000000000..c924a85ea1dd --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxes.ps1 @@ -0,0 +1,77 @@ +using namespace System.Net + +Function Invoke-ListMailboxes { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + try { + $Select = 'id,ExchangeGuid,ArchiveGuid,UserPrincipalName,DisplayName,PrimarySMTPAddress,RecipientType,RecipientTypeDetails,EmailAddresses' + $ExoRequest = @{ + tenantid = $TenantFilter + cmdlet = 'Get-Mailbox' + cmdParams = @{resultsize = 'unlimited' } + Select = $select + } + + $AllowedParameters = @( + @{Parameter = 'Anr'; Type = 'String' } + @{Parameter = 'Archive'; Type = 'Bool' } + @{Parameter = 'Filter'; Type = 'String' } + @{Parameter = 'GroupMailbox'; Type = 'Bool' } + @{Parameter = 'PublicFolder'; Type = 'Bool' } + @{Parameter = 'RecipientTypeDetails'; Type = 'String' } + @{Parameter = 'SoftDeletedMailbox'; Type = 'Bool' } + ) + + foreach ($Param in $Request.Query.Keys) { + $CmdParam = $AllowedParameters | Where-Object { $_.Parameter -eq $Param } + if ($CmdParam) { + switch ($CmdParam.Type) { + 'String' { + if (![string]::IsNullOrEmpty($Request.Query.$Param)) { + $ExoRequest.cmdParams.$Param = $Request.Query.$Param + } + } + 'Bool' { + if ([bool]$Request.Query.$Param -eq $true) { + $ExoRequest.cmdParams.$Param = $true + } + } + } + } + } + + Write-Host ($ExoRequest | ConvertTo-Json) + $GraphRequest = (New-ExoRequest @ExoRequest) | Select-Object id, ExchangeGuid, ArchiveGuid, @{ Name = 'UPN'; Expression = { $_.'UserPrincipalName' } }, + + @{ Name = 'displayName'; Expression = { $_.'DisplayName' } }, + @{ Name = 'primarySmtpAddress'; Expression = { $_.'PrimarySMTPAddress' } }, + @{ Name = 'recipientType'; Expression = { $_.'RecipientType' } }, + @{ Name = 'recipientTypeDetails'; Expression = { $_.'RecipientTypeDetails' } }, + @{ Name = 'AdditionalEmailAddresses'; Expression = { ($_.'EmailAddresses' | Where-Object { $_ -clike 'smtp:*' }).Replace('smtp:', '') -join ', ' } } + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $StatusCode = [HttpStatusCode]::Forbidden + $GraphRequest = $ErrorMessage + } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @($GraphRequest) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMessageTrace.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMessageTrace.ps1 new file mode 100644 index 000000000000..5ec6203892c4 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMessageTrace.ps1 @@ -0,0 +1,44 @@ +using namespace System.Net + +Function Invoke-ListMessageTrace { + <# + .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' + + + try { + $TenantFilter = $request.query.TenantFilter + $SearchParams = @{ + StartDate = (Get-Date).AddDays( - $($request.query.days)).ToString('s') + EndDate = (Get-Date).ToString('s') + } + + if ($null -ne $request.query.recipient) { $Searchparams.Add('RecipientAddress', $($request.query.recipient)) } + if ($null -ne $request.query.sender) { $Searchparams.Add('SenderAddress', $($request.query.sender)) } + $type = $request.query.Tracedetail + $trace = if ($Request.Query.Tracedetail) { + New-ExoRequest -tenantid $Tenantfilter -cmdlet 'Get-MessageTraceDetail' -cmdParams $Searchparams + Get-MessageTraceDetail -MessageTraceId $Request.Query.ID -RecipientAddress $request.query.recipient -erroraction stop | Select-Object Event, Action, Detail, @{ Name = 'Date'; Expression = { $_.Date.Tostring('s') } } + } else { + New-ExoRequest -tenantid $Tenantfilter -cmdlet 'Get-MessageTrace' -cmdParams $Searchparams | Select-Object MessageTraceId, Status, Subject, RecipientAddress, SenderAddress, @{ Name = 'Date'; Expression = { $_.Received.tostring('s') } } + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantfilter) -message 'Executed message trace' -Sev 'Info' + + } + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantfilter) -message "Failed executing messagetrace. Error: $($_.Exception.Message)" -Sev 'Error' + $trace = @{Status = "Failed to retrieve message trace $($_.Exception.Message)" } + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @($trace) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListNamedLocations.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListNamedLocations.ps1 new file mode 100644 index 000000000000..0acac97628d5 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListNamedLocations.ps1 @@ -0,0 +1,39 @@ +using namespace System.Net + +Function Invoke-ListNamedLocations { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + try { + $GraphRequest = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/identity/conditionalAccess/namedLocations' -Tenantid $tenantfilter | Select-Object *, + @{ + name = 'rangeOrLocation' + expression = { if ($_.ipRanges) { $_.ipranges.cidrAddress -join ', ' } else { $_.countriesAndRegions -join ', ' } } + } + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $StatusCode = [HttpStatusCode]::Forbidden + $GraphRequest = $ErrorMessage + + } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @($GraphRequest) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListNotificationConfig.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListNotificationConfig.ps1 new file mode 100644 index 000000000000..68545565ee6b --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListNotificationConfig.ps1 @@ -0,0 +1,40 @@ +using namespace System.Net + +Function Invoke-ListNotificationConfig { + <# + .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' + + $Table = Get-CIPPTable -TableName SchedulerConfig + $Filter = "RowKey eq 'CippNotifications' and PartitionKey eq 'CippNotifications'" + $Config = Get-CIPPAzDataTableEntity @Table -Filter $Filter + if ($Config) { + $Config = $Config | ConvertTo-Json -Depth 10 | ConvertFrom-Json -Depth 10 -AsHashtable + } else { + $Config = @{} + } + #$config | Add-Member -NotePropertyValue @() -NotePropertyName 'logsToInclude' -Force + $config.logsToInclude = @(([pscustomobject]$config | Select-Object * -ExcludeProperty schedule, type, tenantid, onepertenant, sendtoIntegration, partitionkey, rowkey, tenant, ETag, email, logsToInclude, Severity, Alert, Info, Error, timestamp, webhook, includeTenantId).psobject.properties.name) + if (!$config.logsToInclude) { + $config.logsToInclude = @('None') + } + if (!$config.Severity) { + $config.Severity = @('Alert') + } else { + $config.Severity = $config.Severity -split ',' + } + $body = [PSCustomObject]$Config + + # 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/Entrypoints/Invoke-ListOAuthApps.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListOAuthApps.ps1 new file mode 100644 index 000000000000..13fafdf39a2c --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListOAuthApps.ps1 @@ -0,0 +1,54 @@ +using namespace System.Net + +Function Invoke-ListOAuthApps { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + if ($TenantFilter -eq 'AllTenants') { $Tenants = (Get-Tenants).defaultDomainName } else { $tenants = $TenantFilter } + + try { + $GraphRequest = foreach ($Tenant in $Tenants) { + try { + $ServicePrincipals = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/servicePrincipals?`$select=id,displayName,appid" -tenantid $Tenant + New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/oauth2PermissionGrants' -tenantid $Tenant | ForEach-Object { + $CurrentServicePrincipal = ($ServicePrincipals | Where-Object -Property id -EQ $_.clientId) + [PSCustomObject]@{ + Tenant = $Tenant + Name = $CurrentServicePrincipal.displayName + ApplicationID = $CurrentServicePrincipal.appid + ObjectID = $_.clientId + Scope = ($_.scope -join ',') + StartTime = $_.startTime + } + } + $StatusCode = [HttpStatusCode]::OK + } catch { + continue + } + } + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $StatusCode = [HttpStatusCode]::Forbidden + $GraphRequest = $ErrorMessage + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @($GraphRequest) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListOoO.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListOoO.ps1 new file mode 100644 index 000000000000..b83c74d7dd42 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListOoO.ps1 @@ -0,0 +1,27 @@ +using namespace System.Net + +Function Invoke-ListOoO { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $TriggerMetadata.FunctionName + $Tenantfilter = $request.query.tenantFilter + try { + $Body = Get-CIPPOutOfOffice -userid $Request.query.userid -tenantFilter $TenantFilter -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $Body = [pscustomobject]@{'Results' = "Failed. $ErrorMessage" } + + } + + # 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/Entrypoints/Invoke-ListOrg.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListOrg.ps1 new file mode 100644 index 000000000000..20842ce9dafb --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListOrg.ps1 @@ -0,0 +1,32 @@ +using namespace System.Net + +Function Invoke-ListOrg { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + if ($TenantFilter -eq 'AllTenants') { + + } else { + $GraphRequest = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/organization' -tenantid $TenantFilter + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $GraphRequest + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListPartnerRelationships.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListPartnerRelationships.ps1 new file mode 100644 index 000000000000..591b6b23d3bf --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListPartnerRelationships.ps1 @@ -0,0 +1,37 @@ +using namespace System.Net + +Function Invoke-ListPartnerRelationships { + <# + .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' + + try { + $GraphRequestList = @{ + Endpoint = 'policies/crossTenantAccessPolicy/partners' + TenantFilter = $Request.Query.TenantFilter + QueueNameOverride = 'Partner Relationships' + ReverseTenantLookup = $true + } + $GraphRequest = Get-GraphRequestList @GraphRequestList + } catch { + $GraphRequest = @() + } + + $StatusCode = [HttpStatusCode]::OK + + $results = [PSCustomObject]@{ + Results = @($GraphRequest) + } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = $results + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListPhishPolicies.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListPhishPolicies.ps1 new file mode 100644 index 000000000000..1b3d767f85fd --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListPhishPolicies.ps1 @@ -0,0 +1,48 @@ +using namespace System.Net + +Function Invoke-ListPhishPolicies { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + $AntiPhishRules = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-AntiPhishRule' + $AntiPhishPolicies = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-AntiPhishPolicy' + + $GraphRequest = $AntiPhishPolicies | Select-Object name, + @{Name = 'GUID'; Expression = { $(( -join (( 0x41..0x5A) + ( 0x61..0x7A) | Get-Random -Count 13 | ForEach-Object { [char]$_ }) )) } }, + @{ Name = 'ExcludedDomains'; Expression = { $($_.ExcludedDomains) -join '
' } }, + @{ Name = 'ExcludedSenders'; Expression = { $($_.ExcludedSenders) -join '
' } }, + @{ Name = 'PhishThresholdLevel'; Expression = { + switch ($_.PhishThresholdLevel) { + 1 { $result = 'Standard' } + 2 { $result = 'Aggressive' } + 3 { $result = 'More Aggressive' } + 4 { $result = 'Most Aggressive' } + Default { $result = 'Unknown' } + } + $result + } + }, + @{ Name = 'ExcludedDomainCount'; Expression = { $_.ExcludedDomains | Measure-Object | Select-Object -ExpandProperty Count } }, + @{ Name = 'ExcludedSenderCount'; Expression = { $_.ExcludedSenders | Measure-Object | Select-Object -ExpandProperty Count } }, Enabled, WhenChangedUTC, + @{ Name = 'Priority'; Expression = { foreach ($item in $AntiPhishRules) { if ($item.name -eq $_.name) { $item.priority } } } } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @($GraphRequest) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListPotentialApps.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListPotentialApps.ps1 new file mode 100644 index 000000000000..86062e4e80fa --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListPotentialApps.ps1 @@ -0,0 +1,32 @@ +using namespace System.Net + +Function Invoke-ListPotentialApps { + <# + .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 ($request.body.type -eq 'WinGet') { + $body = @" +{"MaximumResults":50,"Filters":[{"PackageMatchField":"Market","RequestMatch":{"KeyWord":"US","MatchType":"CaseInsensitive"}}],"Query":{"KeyWord":"$($Request.Body.SearchString)","MatchType":"Substring"}} +"@ + $DataRequest = (Invoke-RestMethod -Uri 'https://storeedgefd.dsx.mp.microsoft.com/v9.0/manifestSearch' -Method POST -Body $body -ContentType 'Application/json').data | Select-Object @{l = 'applicationName'; e = { $_.packagename } }, @{l = 'packagename'; e = { $_.packageIdentifier } } | Sort-Object -Property applicationName + } + + if ($Request.body.type -eq 'Choco') { + $DataRequest = Invoke-RestMethod -Uri "https://community.chocolatey.org/api/v2/Search()?`$filter=IsLatestVersion&`$skip=0&`$top=999&searchTerm=%27$($request.body.SearchString)%27&targetFramework=%27%27&includePrerelease=false" -ContentType 'application/json' | Select-Object @{l = 'applicationName'; e = { $_.properties.Title } }, @{l = 'packagename'; e = { $_.title.'#text' } } | Sort-Object -Property applicationName + } + + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @($DataRequest) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListRoles.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListRoles.ps1 new file mode 100644 index 000000000000..6eca5db05c5b --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListRoles.ps1 @@ -0,0 +1,40 @@ +using namespace System.Net + +Function Invoke-ListRoles { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + $SelectList = 'id', 'displayName', 'userPrincipalName' + + [System.Collections.Generic.List[PSCustomObject]]$Roles = New-GraphGetRequest -uri "https://graph.microsoft.com/v1.0/directoryRoles?`$expand=members" -tenantid $TenantFilter + $GraphRequest = foreach ($Role in $Roles) { + + #[System.Collections.Generic.List[PSCustomObject]]$Members = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/directoryRoles/$($Role.id)/members?`$select=$($selectlist -join ',')" -tenantid $TenantFilter | Select-Object $SelectList + $Members = if ($Role.members) { $role.members | ForEach-Object { " $($_.displayName) ($($_.userPrincipalName))" } } else { 'none' } + [PSCustomObject]@{ + DisplayName = $Role.displayName + Description = $Role.description + Members = $Members -join ',' + } + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $GraphRequest + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListScheduledItems.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListScheduledItems.ps1 new file mode 100644 index 000000000000..d23de674c779 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListScheduledItems.ps1 @@ -0,0 +1,22 @@ +using namespace System.Net + +Function Invoke-ListScheduledItems { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + $Table = Get-CIPPTable -TableName 'ScheduledTasks' + $ScheduledTasks = Get-CIPPAzDataTableEntity @Table -Filter "PartitionKey eq 'ScheduledTask' and Hidden ne 'True'" + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @($ScheduledTasks) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListServiceHealth.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListServiceHealth.ps1 new file mode 100644 index 000000000000..48144aa28668 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListServiceHealth.ps1 @@ -0,0 +1,44 @@ +using namespace System.Net + +Function Invoke-ListServiceHealth { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + 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.' + + + $ResultHealthSummary = Get-Tenants | ForEach-Object -Parallel { + Import-Module '.\Modules\AzBobbyTables' + Import-Module '.\Modules\CIPPCore' + $tenantname = $_.displayName + Write-Host $tenantname + $prop = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/admin/serviceAnnouncement/issues?`$filter=endDateTime eq null" -tenantid $_.defaultDomainName + $prop | Add-Member -NotePropertyName 'tenant' -NotePropertyValue $tenantname + $prop + } + $Results = foreach ($h in $ResultHealthSummary) { + [PSCustomObject]@{ + TenantName = $h.tenant + issueId = $h.ID + service = $h.service + type = $h.feature + desc = $h.impactDescription + } + } + + $StatusCode = [HttpStatusCode]::OK + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @($Results) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSharedMailboxAccountEnabled.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSharedMailboxAccountEnabled.ps1 new file mode 100644 index 000000000000..f40095596f18 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSharedMailboxAccountEnabled.ps1 @@ -0,0 +1,48 @@ +using namespace System.Net + +Function Invoke-ListSharedMailboxAccountEnabled { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + $TenantFilter = $Request.Query.TenantFilter + + # Get Shared Mailbox Stuff + try { + $SharedMailboxList = (New-GraphGetRequest -uri "https://outlook.office365.com/adminapi/beta/$($TenantFilter)/Mailbox?`$filter=RecipientTypeDetails eq 'SharedMailbox'" -Tenantid $TenantFilter -scope ExchangeOnline) + $AllUsersAccountState = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/users?select=userPrincipalName,accountEnabled,displayName,givenName,surname' -tenantid $Tenantfilter + $EnabledUsersWithSharedMailbox = foreach ($SharedMailbox in $SharedMailboxList) { + # Match the User + $User = $AllUsersAccountState | Where-Object { $_.userPrincipalName -eq $SharedMailbox.userPrincipalName } | Select-Object -Property userPrincipalName, accountEnabled, displayName, givenName, surname -First 1 + if ($User.accountEnabled) { + $User | Select-Object ` + @{Name = 'UserPrincipalName'; Expression = { $User.UserPrincipalName } }, ` + @{Name = 'displayName'; Expression = { $User.displayName } }, + @{Name = 'givenName'; Expression = { $User.givenName } }, + @{Name = 'surname'; Expression = { $User.surname } }, + @{Name = 'accountEnabled'; Expression = { $User.accountEnabled } } + + } + } + } catch { + Write-LogMessage -API 'Tenant' -tenant $tenantfilter -message "Shared Mailbox Enabled Accounts on $($tenantfilter). Error: $($_.exception.message)" -sev 'Error' + } + + $GraphRequest = $EnabledUsersWithSharedMailbox + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @($GraphRequest) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSharedMailboxStatistics.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSharedMailboxStatistics.ps1 new file mode 100644 index 000000000000..387d82b3f6dd --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSharedMailboxStatistics.ps1 @@ -0,0 +1,40 @@ +using namespace System.Net + +Function Invoke-ListSharedMailboxStatistics { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + try { + $GraphRequest = New-GraphGetRequest -uri "https://outlook.office365.com/adminapi/beta/$($tenantFilter)/Mailbox?RecipientTypeDetails=sharedmailbox" -Tenantid $tenantFilter -scope ExchangeOnline | ForEach-Object { + try { + New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-MailboxStatistics' -cmdParams @{Identity = $_.GUID } + } catch { + continue + } + } + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $StatusCode = [HttpStatusCode]::Forbidden + $GraphRequest = $ErrorMessage + } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @($GraphRequest) + }) + +} diff --git a/ListSharepointQuota/run.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSharepointQuota.ps1 similarity index 88% rename from ListSharepointQuota/run.ps1 rename to Modules/CIPPCore/Public/Entrypoints/Invoke-ListSharepointQuota.ps1 index df0f0abf3f0f..6efbb47e7e96 100644 --- a/ListSharepointQuota/run.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSharepointQuota.ps1 @@ -1,43 +1,50 @@ -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' - -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter - -if ($Request.Query.TenantFilter -eq 'AllTenants') { - $UsedStoragePercentage = 'Not Supported' -} else { - $tenantName = (New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/domains' -tenantid $TenantFilter | Where-Object { $_.isInitial -eq $true }).id.Split('.')[0] - - $sharepointToken = (Get-GraphToken -scope "https://$($tenantName)-admin.sharepoint.com/.default" -tenantid $TenantFilter) - $sharepointToken.Add('accept', 'application/json') - # Implement a try catch later to deal with sharepoint guest user settings - $sharepointQuota = (Invoke-RestMethod -Method 'GET' -Headers $sharepointToken -Uri "https://$($tenantName)-admin.sharepoint.com/_api/StorageQuotas()?api-version=1.3.2" -ErrorAction Stop).value | Sort-Object -Property GeoUsedStorageMB -Descending | Select-Object -First 1 - - if ($sharepointQuota) { - $UsedStoragePercentage = [int](($sharepointQuota.GeoUsedStorageMB / $sharepointQuota.TenantStorageMB) * 100) - } -} - -$sharepointQuotaDetails = @{ - GeoUsedStorageMB = $sharepointQuota.GeoUsedStorageMB - TenantStorageMB = $sharepointQuota.TenantStorageMB - Percentage = $UsedStoragePercentage - Dashboard = "$($UsedStoragePercentage) / 100" -} - -$StatusCode = [HttpStatusCode]::OK - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = $sharepointQuotaDetails - }) \ No newline at end of file + using namespace System.Net + + Function Invoke-ListSharepointQuota { + <# + .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' + +# Write to the Azure Functions log stream. +Write-Host 'PowerShell HTTP trigger function processed a request' + +# Interact with query parameters or the body of the request. +$TenantFilter = $Request.Query.TenantFilter + +if ($Request.Query.TenantFilter -eq 'AllTenants') { + $UsedStoragePercentage = 'Not Supported' +} else { + $tenantName = (New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/domains' -tenantid $TenantFilter | Where-Object { $_.isInitial -eq $true }).id.Split('.')[0] + + $sharepointToken = (Get-GraphToken -scope "https://$($tenantName)-admin.sharepoint.com/.default" -tenantid $TenantFilter) + $sharepointToken.Add('accept', 'application/json') + # Implement a try catch later to deal with sharepoint guest user settings + $sharepointQuota = (Invoke-RestMethod -Method 'GET' -Headers $sharepointToken -Uri "https://$($tenantName)-admin.sharepoint.com/_api/StorageQuotas()?api-version=1.3.2" -ErrorAction Stop).value | Sort-Object -Property GeoUsedStorageMB -Descending | Select-Object -First 1 + + if ($sharepointQuota) { + $UsedStoragePercentage = [int](($sharepointQuota.GeoUsedStorageMB / $sharepointQuota.TenantStorageMB) * 100) + } +} + +$sharepointQuotaDetails = @{ + GeoUsedStorageMB = $sharepointQuota.GeoUsedStorageMB + TenantStorageMB = $sharepointQuota.TenantStorageMB + Percentage = $UsedStoragePercentage + Dashboard = "$($UsedStoragePercentage) / 100" +} + +$StatusCode = [HttpStatusCode]::OK + +# Associate values to output bindings by calling 'Push-OutputBinding'. +Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = $sharepointQuotaDetails + }) + + } diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSharepointSettings.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSharepointSettings.ps1 new file mode 100644 index 000000000000..e769c7ee9879 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSharepointSettings.ps1 @@ -0,0 +1,32 @@ +using namespace System.Net + +Function Invoke-ListSharepointSettings { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # Interact with query parameters or the body of the request. + $tenant = $Request.Query.TenantFilter + $User = $Request.query.user + $USERToGet = $Request.query.usertoGet + $body = '{"isResharingByExternalUsersEnabled": "False"}' + $Request = New-GraphPostRequest -tenantid $tenant -Uri 'https://graph.microsoft.com/beta/admin/sharepoint/settings' -Type patch -Body $body -ContentType 'application/json' + + Write-LogMessage -API 'Standards' -tenant $tenantFilter -message 'Disabled Password Expiration' -sev Info + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @($GraphRequest) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSignIns.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSignIns.ps1 new file mode 100644 index 000000000000..debfb0931ac0 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSignIns.ps1 @@ -0,0 +1,53 @@ +using namespace System.Net + +Function Invoke-ListSignIns { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + try { + if ($Request.query.failedlogonOnly) { + $FailedLogons = ' and (status/errorCode eq 50126)' + } + + $filters = if ($Request.query.Filter) { + $request.query.filter + } else { + $currentTime = Get-Date -Format 'yyyy-MM-dd' + $ts = (Get-Date).AddDays(-7) + $endTime = $ts.ToString('yyyy-MM-dd') + "createdDateTime ge $($endTime) and createdDateTime lt $($currentTime) and userDisplayName ne 'On-Premises Directory Synchronization Service Account' $FailedLogons" + } + Write-Host $Filters + + $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/auditLogs/signIns?api-version=beta&`$filter=$($filters)" -tenantid $TenantFilter -erroraction stop + $response = $GraphRequest | Select-Object *, + @{l = 'additionalDetails'; e = { $_.status.additionalDetails } } , + @{l = 'errorCode'; e = { $_.status.errorCode } }, + @{l = 'locationcipp'; e = { "$($_.location.city) - $($_.location.countryOrRegion)" } } + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Retrieved sign in report' -Sev 'Debug' -tenant $TenantFilter + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @($response) + }) + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to retrieve Sign In report: $($_.Exception.message) " -Sev 'Error' -tenant $TenantFilter + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = '500' + Body = $(Get-NormalizedError -message $_.Exception.message) + }) + } + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSites.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSites.ps1 new file mode 100644 index 000000000000..f224af6d2282 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSites.ps1 @@ -0,0 +1,52 @@ +using namespace System.Net + +Function Invoke-ListSites { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + $type = $request.query.Type + $UserUPN = $request.query.UserUPN + try { + $Result = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/reports/get$($type)Detail(period='D7')" -tenantid $TenantFilter | ConvertFrom-Csv + + if ($UserUPN) { + $ParsedRequest = $Result | Where-Object { $_.'Owner Principal Name' -eq $UserUPN } + } else { + $ParsedRequest = $Result + } + + + $GraphRequest = $ParsedRequest | Select-Object @{ Name = 'UPN'; Expression = { $_.'Owner Principal Name' } }, + @{ Name = 'displayName'; Expression = { $_.'Owner Display Name' } }, + @{ Name = 'LastActive'; Expression = { $_.'Last Activity Date' } }, + @{ Name = 'FileCount'; Expression = { [int]$_.'File Count' } }, + @{ Name = 'UsedGB'; Expression = { [math]::round($_.'Storage Used (Byte)' / 1GB, 2) } }, + @{ Name = 'URL'; Expression = { $_.'Site URL' } }, + @{ Name = 'Allocated'; Expression = { [math]::round($_.'Storage Allocated (Byte)' / 1GB, 2) } }, + @{ Name = 'Template'; Expression = { $_.'Root Web Template' } } + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $StatusCode = [HttpStatusCode]::Forbidden + $GraphRequest = $ErrorMessage + } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @($GraphRequest) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSpamFilterTemplates.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSpamFilterTemplates.ps1 new file mode 100644 index 000000000000..9782073ffb25 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSpamFilterTemplates.ps1 @@ -0,0 +1,34 @@ +using namespace System.Net + +Function Invoke-ListSpamFilterTemplates { + <# + .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' + $Table = Get-CippTable -tablename 'templates' + + #List new policies + $Table = Get-CippTable -tablename 'templates' + $Filter = "PartitionKey eq 'SpamfilterTemplate'" + $Templates = (Get-CIPPAzDataTableEntity @Table -Filter $Filter) | ForEach-Object { + $GUID = $_.RowKey + $data = $_.JSON | ConvertFrom-Json + $data | Add-Member -NotePropertyName 'GUID' -NotePropertyValue $GUID + $data + } + + if ($Request.query.ID) { $Templates = $Templates | Where-Object -Property RowKey -EQ $Request.query.id } + + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @($Templates) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSpamfilter.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSpamfilter.ps1 new file mode 100644 index 000000000000..3e705b9f46a5 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSpamfilter.ps1 @@ -0,0 +1,32 @@ +using namespace System.Net + +Function Invoke-ListSpamfilter { + <# + .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' + $Tenantfilter = $request.Query.tenantfilter + + try { + $Policies = New-ExoRequest -tenantid $Tenantfilter -cmdlet 'Get-HostedContentFilterPolicy' | Select-Object * -ExcludeProperty *odata*, *data.type* + $RuleState = New-ExoRequest -tenantid $Tenantfilter -cmdlet 'Get-HostedContentFilterRule' | Select-Object * -ExcludeProperty *odata*, *data.type* + $GraphRequest = $Policies | Select-Object *, @{l = 'ruleState'; e = { $name = $_.name; ($RuleState | Where-Object name -EQ $name).State } }, @{l = 'rulePrio'; e = { $name = $_.name; ($RuleState | Where-Object name -EQ $name).Priority } } + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $StatusCode = [HttpStatusCode]::Forbidden + $GraphRequest = $ErrorMessage + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @($GraphRequest) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListStandards.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListStandards.ps1 new file mode 100644 index 000000000000..de338c53e239 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListStandards.ps1 @@ -0,0 +1,51 @@ +using namespace System.Net + +Function Invoke-ListStandards { + <# + .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' + $Table = Get-CippTable -tablename 'standards' + + $Filter = "PartitionKey eq 'standards'" + + try { + if ($Request.query.TenantFilter) { + $tenants = (Get-CIPPAzDataTableEntity @Table -Filter $Filter).JSON | ConvertFrom-Json -Depth 15 -ErrorAction Stop | Where-Object Tenant -EQ $Request.query.tenantFilter + } else { + $Tenants = (Get-CIPPAzDataTableEntity @Table -Filter $Filter).JSON | ConvertFrom-Json -Depth 15 -ErrorAction Stop + } + } catch {} + + $CurrentStandards = foreach ($tenant in $tenants) { + [PSCustomObject]@{ + displayName = $tenant.tenant + appliedBy = $tenant.addedBy + appliedAt = $tenant.appliedAt + standards = $tenant.Standards + StandardsExport = ($tenant.Standards.psobject.properties.name) -join ', ' + } + } + if (!$CurrentStandards) { + $CurrentStandards = [PSCustomObject]@{ + displayName = 'No Standards applied' + appliedBy = $null + appliedAt = $null + standards = @{none = $null } + } + } + + $CurrentStandards = ConvertTo-Json -InputObject @($CurrentStandards) -Depth 15 -Compress + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $CurrentStandards + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListTeams.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListTeams.ps1 new file mode 100644 index 000000000000..5c83df245e5f --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListTeams.ps1 @@ -0,0 +1,50 @@ +using namespace System.Net + +Function Invoke-ListTeams { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + if ($request.query.type -eq 'List') { + $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/groups?`$filter=resourceProvisioningOptions/Any(x:x eq 'Team')&`$select=id,displayname,description,visibility,mailNickname" -tenantid $TenantFilter + } + $TeamID = $request.query.ID + Write-Host $TeamID + if ($request.query.type -eq 'Team') { + $Team = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/teams/$($TeamID)" -tenantid $TenantFilter -asapp $true + $Channels = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/teams/$($TeamID)/Channels" -tenantid $TenantFilter -asapp $true + $UserList = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/teams/$($TeamID)/Members" -tenantid $TenantFilter -asapp $true + $AppsList = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/teams/$($TeamID)/installedApps?`$expand=teamsAppDefinition" -tenantid $TenantFilter -asapp $true + + $Owners = $UserList | Where-Object -Property Roles -EQ 'Owner' + $Members = $UserList | Where-Object -Property email -NotIn $owners.email + $GraphRequest = [PSCustomObject]@{ + Name = $team.DisplayName + TeamInfo = @($team) + ChannelInfo = @($channels) + Members = @($Members) + Owners = @($owners) + InstalledApps = @($AppsList) + } + } + + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @($GraphRequest) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListTeamsActivity.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListTeamsActivity.ps1 new file mode 100644 index 000000000000..944fb90c7bf7 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListTeamsActivity.ps1 @@ -0,0 +1,30 @@ +using namespace System.Net + +Function Invoke-ListTeamsActivity { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + $type = $request.query.Type + $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/reports/get$($type)Detail(period='D30')" -tenantid $TenantFilter | ConvertFrom-Csv | Select-Object @{ Name = 'UPN'; Expression = { $_.'User Principal Name' } }, + @{ Name = 'LastActive'; Expression = { $_.'Last Activity Date' } }, + @{ Name = 'TeamsChat'; Expression = { $_.'Team Chat Message Count' } }, + @{ Name = 'CallCount'; Expression = { $_.'Call Count' } }, + @{ Name = 'MeetingCount'; Expression = { $_.'Meeting Count' } } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @($GraphRequest) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListTeamsVoice.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListTeamsVoice.ps1 new file mode 100644 index 000000000000..ef5e1ca9d3d2 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListTeamsVoice.ps1 @@ -0,0 +1,47 @@ +using namespace System.Net + +Function Invoke-ListTeamsVoice { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + $tenantid = (Get-Tenants | Where-Object -Property defaultDomainName -EQ $Request.Query.TenantFilter).customerId + try { + $users = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users?`$top=999&`$select=id,userPrincipalName,displayname" -tenantid $TenantFilter) + $GraphRequest = (New-TeamsAPIGetRequest -uri "https://api.interfaces.records.teams.microsoft.com/Skype.TelephoneNumberMgmt/Tenants/$($Tenantid)/telephone-numbers?locale=en-US" -tenantid $TenantFilter).TelephoneNumbers | ForEach-Object { + $CompleteRequest = $_ | Select-Object *, 'AssignedTo' + $CompleteRequest.AcquisitionDate = $CompleteRequest.AcquisitionDate -split 'T' | Select-Object -First 1 + + if ($CompleteRequest.TargetId -eq '00000000-0000-0000-0000-000000000000') { + $CompleteRequest.AssignedTo = 'Unassigned' + } else { + $CompleteRequest.AssignedTo = ($users | Where-Object -Property Id -EQ $CompleteRequest.TargetId).userPrincipalName + + } + $CompleteRequest + } + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $StatusCode = [HttpStatusCode]::Forbidden + $GraphRequest = $ErrorMessage + } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @($GraphRequest) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListTenantDetails.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListTenantDetails.ps1 new file mode 100644 index 000000000000..85e3330926c0 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListTenantDetails.ps1 @@ -0,0 +1,48 @@ +using namespace System.Net + +Function Invoke-ListTenantDetails { + <# + .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' + + try { + $tenantfilter = $Request.Query.TenantFilter + $org = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/organization' -tenantid $tenantfilter | Select-Object displayName, city, country, countryLetterCode, street, state, postalCode, + @{ Name = 'businessPhones'; Expression = { $_.businessPhones -join ', ' } }, + @{ Name = 'technicalNotificationMails'; Expression = { $_.technicalNotificationMails -join ', ' } }, + tenantType, createdDateTime, onPremisesLastPasswordSyncDateTime, onPremisesLastSyncDateTime, onPremisesSyncEnabled, assignedPlans + } catch { + $org = [PSCustomObject]@{ + displayName = 'Error loading tenant' + city = '' + country = '' + countryLetterCode = '' + street = '' + state = '' + postalCode = '' + businessPhones = '' + technicalNotificationMails = '' + createdDateTime = '' + onPremisesLastPasswordSyncDateTime = '' + onPremisesLastSyncDateTime = '' + onPremisesSyncEnabled = '' + assignedPlans = @() + } + } finally { + $Body = $org + } + + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Body + }) + + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListTenants.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListTenants.ps1 new file mode 100644 index 000000000000..93425c195e45 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListTenants.ps1 @@ -0,0 +1,73 @@ +using namespace System.Net + +Function Invoke-ListTenants { + <# + .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' + + + # Clear Cache + if ($request.Query.ClearCache -eq 'true') { + Remove-CIPPCache -tenantsOnly $request.query.TenantsOnly + $GraphRequest = [pscustomobject]@{'Results' = 'Successfully completed request.' } + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $GraphRequest + }) + exit + } + + try { + $tenantfilter = $Request.Query.TenantFilter + $Tenants = Get-Tenants -IncludeErrors + + if ($null -eq $TenantFilter -or $TenantFilter -eq 'null') { + $TenantList = [system.collections.generic.list[object]]::new() + if ($Request.Query.AllTenantSelector -eq $true) { + $TenantList.Add(@{ + customerId = 'AllTenants' + defaultDomainName = 'AllTenants' + displayName = '*All Tenants' + domains = 'AllTenants' + GraphErrorCount = 0 + }) | Out-Null + + if (($Tenants).length -gt 1) { + $TenantList.AddRange($Tenants) | Out-Null + } elseif ($Tenants) { + $TenantList.Add($Tenants) | Out-Null + } + $body = $TenantList + } else { + $Body = $Tenants + } + } else { + $body = $Tenants | Where-Object -Property defaultDomainName -EQ $Tenantfilter + } + + Write-LogMessage -user $request.headers.'x-ms-client-principal' -tenant $Tenantfilter -API $APINAME -message 'Listed Tenant Details' -Sev 'Debug' + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -tenant $Tenantfilter -API $APINAME -message "List Tenant failed. The error is: $($_.Exception.Message)" -Sev 'Error' + $body = [pscustomobject]@{ + 'Results' = "Failed to retrieve tenants: $($_.Exception.Message)" + defaultDomainName = '' + displayName = 'Failed to retrieve tenants. Perform a permission check.' + customerId = '' + + } + } + + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @($Body) + }) + + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListTransportRules.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListTransportRules.ps1 new file mode 100644 index 000000000000..18e9fb3959d2 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListTransportRules.ps1 @@ -0,0 +1,30 @@ +using namespace System.Net + +Function Invoke-ListTransportRules { + <# + .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' + $Tenantfilter = $request.Query.tenantfilter + + try { + $GraphRequest = New-ExoRequest -tenantid $Tenantfilter -cmdlet 'Get-TransportRule' + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $StatusCode = [HttpStatusCode]::Forbidden + $GraphRequest = $ErrorMessage + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @($GraphRequest) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListTransportRulesTemplates.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListTransportRulesTemplates.ps1 new file mode 100644 index 000000000000..1c42c21d9470 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListTransportRulesTemplates.ps1 @@ -0,0 +1,46 @@ +using namespace System.Net + +Function Invoke-ListTransportRulesTemplates { + <# + .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' + $Table = Get-CippTable -tablename 'templates' + + $Templates = Get-ChildItem 'Config\*.TransportRuleTemplate.json' | ForEach-Object { + + $Entity = @{ + JSON = "$(Get-Content $_)" + RowKey = "$($_.name)" + PartitionKey = 'TransportTemplate' + GUID = "$($_.name)" + } + Add-CIPPAzDataTableEntity @Table -Entity $Entity -Force + + } + + #List new policies + $Table = Get-CippTable -tablename 'templates' + $Filter = "PartitionKey eq 'TransportTemplate'" + $Templates = (Get-CIPPAzDataTableEntity @Table -Filter $Filter) | ForEach-Object { + $GUID = $_.RowKey + $data = $_.JSON | ConvertFrom-Json + $data | Add-Member -NotePropertyName 'GUID' -NotePropertyValue $GUID + $data + } + + if ($Request.query.ID) { $Templates = $Templates | Where-Object -Property RowKey -EQ $Request.query.id } + + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @($Templates) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListUserConditionalAccessPolicies.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListUserConditionalAccessPolicies.ps1 new file mode 100644 index 000000000000..1557184a8bb6 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListUserConditionalAccessPolicies.ps1 @@ -0,0 +1,47 @@ +using namespace System.Net + +Function Invoke-ListUserConditionalAccessPolicies { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + $UserID = $Request.Query.UserID + + try { + $json = '{"conditions":{"users":{"allUsers":2,"included":{"userIds":["' + $UserID + '"],"groupIds":[]},"excluded":{"userIds":[],"groupIds":[]}},"servicePrincipals":{"allServicePrincipals":1,"includeAllMicrosoftApps":false,"excludeAllMicrosoftApps":false,"userActions":[],"stepUpTags":[]},"conditions":{"minUserRisk":{"noRisk":false,"lowRisk":false,"mediumRisk":false,"highRisk":false,"applyCondition":false},"minSigninRisk":{"noRisk":false,"lowRisk":false,"mediumRisk":false,"highRisk":false,"applyCondition":false},"servicePrincipalRiskLevels":{"noRisk":false,"lowRisk":false,"mediumRisk":false,"highRisk":false,"applyCondition":false},"devicePlatforms":{"all":2,"included":{"android":false,"ios":false,"windowsPhone":false,"windows":false,"macOs":false,"linux":false},"excluded":null,"applyCondition":false},"locations":{"applyCondition":true,"includeLocationType":2,"excludeAllTrusted":false},"clientApps":{"applyCondition":false,"specificClientApps":false,"webBrowsers":false,"exchangeActiveSync":false,"onlyAllowSupportedPlatforms":false,"mobileDesktop":false},"clientAppsV2":{"applyCondition":false,"webBrowsers":false,"mobileDesktop":false,"modernAuth":false,"exchangeActiveSync":false,"onlyAllowSupportedPlatforms":false,"otherClients":false},"deviceState":{"includeDeviceStateType":1,"excludeDomainJoionedDevice":false,"excludeCompliantDevice":false,"applyCondition":true}}},"country":"","device":{}}' + $ConditionalAccessPolicyOutput = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/identity/conditionalAccess/policies' -tenantid $tenantfilter + } catch { + $ConditionalAccessPolicyOutput = @{} + } + + $GraphRequest = foreach ($cap in $ConditionalAccessPolicyOutput) { + if ($cap.id -in $UserPolicies.policyId) { + $temp = [PSCustomObject]@{ + id = $cap.id + displayName = $cap.displayName + } + $temp + } + } + + Write-Host $GraphRequest + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @($GraphRequest) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListUserCounts.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListUserCounts.ps1 new file mode 100644 index 000000000000..f94a0a79027c --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListUserCounts.ps1 @@ -0,0 +1,45 @@ +using namespace System.Net + +Function Invoke-ListUserCounts { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + if ($Request.Query.TenantFilter -eq 'AllTenants') { + $users = 'Not Supported' + $LicUsers = 'Not Supported' + $GAs = 'Not Supported' + $Guests = 'Not Supported' + } else { + $Users = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users?`$count=true&`$top=1" -CountOnly -ComplexFilter -tenantid $TenantFilter + $LicUsers = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users?`$count=true&`$top=1&`$filter=assignedLicenses/`$count ne 0" -CountOnly -ComplexFilter -tenantid $TenantFilter + $GAs = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/directoryRoles/roleTemplateId=62e90394-69f5-4237-9190-012177145e10/members?`$count=true" -CountOnly -ComplexFilter -tenantid $TenantFilter + $guests = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users?`$count=true&`$top=1&`$filter=userType eq 'Guest'" -CountOnly -ComplexFilter -tenantid $TenantFilter + } + $StatusCode = [HttpStatusCode]::OK + $Counts = @{ + Users = $users + LicUsers = $LicUsers + Gas = $Gas + Guests = $guests + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = $Counts + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListUserDevices.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListUserDevices.ps1 new file mode 100644 index 000000000000..0bbcb27b4422 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListUserDevices.ps1 @@ -0,0 +1,61 @@ +using namespace System.Net + +Function Invoke-ListUserDevices { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + $UserID = $Request.Query.UserID + + function Get-EPMID { + param( + $deviceID, + $EPMDevices + ) + try { + return ($EPMDevices | Where-Object { $_.azureADDeviceId -eq $deviceID }).id + } catch { + return $null + } + } + try { + $EPMDevices = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$UserID/managedDevices" -Tenantid $tenantfilter + $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$UserID/ownedDevices?`$top=999" -Tenantid $tenantfilter | Select-Object @{ Name = 'ID'; Expression = { $_.'id' } }, + @{ Name = 'accountEnabled'; Expression = { $_.'accountEnabled' } }, + @{ Name = 'approximateLastSignInDateTime'; Expression = { $_.'approximateLastSignInDateTime' | Out-String } }, + @{ Name = 'createdDateTime'; Expression = { $_.'createdDateTime' | Out-String } }, + @{ Name = 'deviceOwnership'; Expression = { $_.'deviceOwnership' } }, + @{ Name = 'displayName'; Expression = { $_.'displayName' } }, + @{ Name = 'enrollmentType'; Expression = { $_.'enrollmentType' } }, + @{ Name = 'isCompliant'; Expression = { $_.'isCompliant' } }, + @{ Name = 'managementType'; Expression = { $_.'managementType' } }, + @{ Name = 'manufacturer'; Expression = { $_.'manufacturer' } }, + @{ Name = 'model'; Expression = { $_.'model' } }, + @{ Name = 'operatingSystem'; Expression = { $_.'operatingSystem' } }, + @{ Name = 'onPremisesSyncEnabled'; Expression = { $(if ([string]::IsNullOrEmpty($_.'onPremisesSyncEnabled')) { $false }else { $true }) } }, + @{ Name = 'operatingSystemVersion'; Expression = { $_.'operatingSystemVersion' } }, + @{ Name = 'trustType'; Expression = { $_.'trustType' } }, + @{ Name = 'EPMID'; Expression = { $(Get-EPMID -deviceID $_.'deviceId' -EPMDevices $EPMDevices) } } + } catch { + $GraphRequest = @() + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @($GraphRequest) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListUserGroups.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListUserGroups.ps1 new file mode 100644 index 000000000000..fff7eb222d9c --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListUserGroups.ps1 @@ -0,0 +1,41 @@ +using namespace System.Net + +Function Invoke-ListUserGroups { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + $UserID = $Request.Query.UserID + + + $URI = "https://graph.microsoft.com/beta/users/$UserID/memberOf/$/microsoft.graph.group?`$select=id,displayName,mailEnabled,securityEnabled,groupTypes,onPremisesSyncEnabled,mail,isAssignableToRole`&$orderby=displayName asc" + Write-Host $URI + $GraphRequest = New-GraphGetRequest -uri $URI -tenantid $TenantFilter -noPagination $true -verbose | Select-Object id, + @{ Name = 'DisplayName'; Expression = { $_.displayName } }, + @{ Name = 'MailEnabled'; Expression = { $_.mailEnabled } }, + @{ Name = 'Mail'; Expression = { $_.mail } }, + @{ Name = 'SecurityGroup'; Expression = { $_.securityEnabled } }, + @{ Name = 'GroupTypes'; Expression = { $_.groupTypes -join ',' } }, + @{ Name = 'OnPremisesSync'; Expression = { $_.onPremisesSyncEnabled } }, + @{ Name = 'IsAssignableToRole'; Expression = { $_.isAssignableToRole } } + + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @($GraphRequest) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListUserMailboxDetails.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListUserMailboxDetails.ps1 new file mode 100644 index 000000000000..e59ecf17a22a --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListUserMailboxDetails.ps1 @@ -0,0 +1,164 @@ +using namespace System.Net + +Function Invoke-ListUserMailboxDetails { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + $UserID = $Request.Query.UserID + + + $TenantFilter = $Request.Query.TenantFilter + try { + $Bytes = [System.Text.Encoding]::UTF8.GetBytes($Request.Query.UserID) + $base64IdentityParam = [Convert]::ToBase64String($Bytes) + $CASRequest = New-GraphGetRequest -uri "https://outlook.office365.com/adminapi/beta/$($tenantfilter)/CasMailbox('$UserID')" -Tenantid $tenantfilter -scope ExchangeOnline -noPagination $true + $MailRequest = New-GraphGetRequest -uri "https://outlook.office365.com/adminapi/beta/$($tenantfilter)/Mailbox('$UserID')" -Tenantid $tenantfilter -scope ExchangeOnline -noPagination $true + $FetchParam = @{ + anr = $MailRequest.PrimarySmtpAddress + } + $MailboxDetailedRequest = New-ExoRequest -TenantID $TenantFilter -cmdlet 'Get-Mailbox' -cmdParams $FetchParam + try { + $Archive = New-ExoRequest -TenantID $TenantFilter -cmdlet 'Get-Mailbox' -cmdParams $FetchParam + if ($Archive.ArchiveStatus -eq 'Active') { + $ArchiveEnabled = $True + } else { + $ArchiveEnabled = $False + } + + $FetchParam = @{ + Identity = $MailRequest.PrimarySmtpAddress + Archive = $true + } + + $ArchiveSize = New-ExoRequest -TenantID $TenantFilter -cmdlet 'Get-MailboxStatistics' -cmdParams $FetchParam + } catch { + $ArchiveEnabled = $False + $ArchiveSize = @{ + TotalItemSize = '0' + ItemCount = '0' + } + } + $FetchParam = @{ + SenderAddress = $MailRequest.PrimarySmtpAddress + } + $BlockedSender = New-ExoRequest -TenantID $TenantFilter -cmdlet 'Get-BlockedSenderAddress' -cmdParams $FetchParam + if ($BlockedSender) { + $BlockedForSpam = $True + } else { + $BlockedForSpam = $False + } + $StatsRequest = New-GraphGetRequest -uri "https://outlook.office365.com/adminapi/beta/$($tenantfilter)/Mailbox('$($MailRequest.PrimarySmtpAddress)')/Exchange.GetMailboxStatistics()" -Tenantid $tenantfilter -scope ExchangeOnline -noPagination $true + $PermsRequest = New-GraphGetRequest -uri "https://outlook.office365.com/adminapi/beta/$($tenantfilter)/Mailbox('$($MailRequest.PrimarySmtpAddress)')/MailboxPermission" -Tenantid $tenantfilter -scope ExchangeOnline -noPagination $true + $PermsRequest2 = New-GraphGetRequest -uri "https://outlook.office365.com/adminapi/beta/$($tenantfilter)/Recipient('$base64IdentityParam')?`$expand=RecipientPermission&isEncoded=true" -Tenantid $tenantfilter -scope ExchangeOnline + + } catch { + Write-Error "Failed Fetching Data $($_.Exception.message): $($_.InvocationInfo.ScriptLineNumber)" + } + + $ParsedPerms = foreach ($Perm in $PermsRequest, $PermsRequest2.RecipientPermission) { + + if ($perm.Trustee) { + $perm | Where-Object Trustee | ForEach-Object { [PSCustomObject]@{ + User = $_.Trustee + AccessRights = $_.accessRights -join ', ' + } + } + + } + if ($perm.PermissionList) { + $perm | Where-Object User | ForEach-Object { [PSCustomObject]@{ + User = $_.User + AccessRights = $_.PermissionList.accessRights -join ', ' + } + } + } + } + + $forwardingaddress = if ($MailboxDetailedRequest.ForwardingAddress) { + $MailboxDetailedRequest.ForwardingAddress + } elseif ($MailboxDetailedRequest.ForwardingSmtpAddress -and $MailboxDetailedRequest.ForwardingAddress) { + $MailboxDetailedRequest.ForwardingAddress + ' ' + $MailboxDetailedRequest.ForwardingSmtpAddress + } else { + $MailboxDetailedRequest.ForwardingSmtpAddress + } + + if ($ArchiveSize) { + $GraphRequest = [ordered]@{ + ForwardAndDeliver = $MailboxDetailedRequest.DeliverToMailboxAndForward + ForwardingAddress = $ForwardingAddress + LitiationHold = $MailboxDetailedRequest.LitigationHoldEnabled + HiddenFromAddressLists = $MailboxDetailedRequest.HiddenFromAddressListsEnabled + EWSEnabled = $CASRequest.EwsEnabled + MailboxMAPIEnabled = $CASRequest.MAPIEnabled + MailboxOWAEnabled = $CASRequest.OWAEnabled + MailboxImapEnabled = $CASRequest.ImapEnabled + MailboxPopEnabled = $CASRequest.PopEnabled + MailboxActiveSyncEnabled = $CASRequest.ActiveSyncEnabled + Permissions = $ParsedPerms + ProhibitSendQuota = [math]::Round([float]($MailboxDetailedRequest.ProhibitSendQuota -split ' GB')[0], 2) + ProhibitSendReceiveQuota = [math]::Round([float]($MailboxDetailedRequest.ProhibitSendReceiveQuota -split ' GB')[0], 2) + ItemCount = [math]::Round($StatsRequest.ItemCount, 2) + TotalItemSize = [math]::Round($StatsRequest.TotalItemSize / 1Gb, 2) + TotalArchiveItemSize = $ArchiveSize.totalItemSize.split('(')[0] + TotalArchiveItemCount = [math]::Round($ArchiveSize.ItemCount, 2) + BlockedForSpam = $BlockedForSpam + ArchiveMailBox = $ArchiveEnabled + AutoExpandingArchive = $Archive.AutoExpandingArchiveEnabled + RecipientTypeDetails = $MailboxDetailedRequest.RecipientTypeDetails + } + } else { + $GraphRequest = [ordered]@{ + ForwardAndDeliver = $MailboxDetailedRequest.DeliverToMailboxAndForward + ForwardingAddress = $ForwardingAddress + LitiationHold = $MailboxDetailedRequest.LitigationHoldEnabled + HiddenFromAddressLists = $MailboxDetailedRequest.HiddenFromAddressListsEnabled + EWSEnabled = $CASRequest.EwsEnabled + MailboxMAPIEnabled = $CASRequest.MAPIEnabled + MailboxOWAEnabled = $CASRequest.OWAEnabled + MailboxImapEnabled = $CASRequest.ImapEnabled + MailboxPopEnabled = $CASRequest.PopEnabled + MailboxActiveSyncEnabled = $CASRequest.ActiveSyncEnabled + Permissions = $ParsedPerms + ProhibitSendQuota = [math]::Round([float]($MailboxDetailedRequest.ProhibitSendQuota -split ' GB')[0], 2) + ProhibitSendReceiveQuota = [math]::Round([float]($MailboxDetailedRequest.ProhibitSendReceiveQuota -split ' GB')[0], 2) + ItemCount = [math]::Round($StatsRequest.ItemCount, 2) + TotalItemSize = [math]::Round($StatsRequest.TotalItemSize / 1Gb, 2) + TotalArchiveItemSize = 0 + TotalArchiveItemCount = 0 + BlockedForSpam = $BlockedForSpam + ArchiveMailBox = $ArchiveEnabled + AutoExpandingArchive = $Archive.AutoExpandingArchiveEnabled + RecipientTypeDetails = $MailboxDetailedRequest.RecipientTypeDetails + } + } + + + #$GraphRequest = [ordered]@{ + # Connectivity = $CASRequest + # Mailbox = $MailRequest + # MailboxDetail = $MailboxDetailedRequest + # Stats = $StatsRequest + # Permissions = $ParsedPerms + # Result = $Result + #} + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @($GraphRequest) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListUserMailboxRules.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListUserMailboxRules.ps1 new file mode 100644 index 000000000000..4a0a433fc1d4 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListUserMailboxRules.ps1 @@ -0,0 +1,45 @@ +using namespace System.Net + +Function Invoke-ListUserMailboxRules { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # Interact with query parameters or the body of the request. + try { + $TenantFilter = $Request.Query.TenantFilter + $UserID = $Request.Query.UserID + $GraphRequest = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-InboxRule' -cmdParams @{mailbox = $UserID } | Select-Object + @{ Name = 'DisplayName'; Expression = { $_.displayName } }, + @{ Name = 'Description'; Expression = { $_.Description } }, + @{ Name = 'Redirect To'; Expression = { $_.RedirectTo } }, + @{ Name = 'Copy To Folder'; Expression = { $_.CopyToFolder } }, + @{ Name = 'Move To Folder'; Expression = { $_.MoveToFolder } }, + @{ Name = 'Soft Delete Message'; Expression = { $_.SoftDeleteMessage } }, + @{ Name = 'Delete Message'; Expression = { $_.DeleteMessage } } + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to retrieve mailbox rules $($request.query.id): $($_.Exception.message) " -Sev 'Error' -tenant $TenantFilter + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = '500' + Body = $(Get-NormalizedError -message $_.Exception.message) + }) + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @($GraphRequest) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListUserPhoto.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListUserPhoto.ps1 new file mode 100644 index 000000000000..bd596e0a379a --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListUserPhoto.ps1 @@ -0,0 +1,34 @@ +using namespace System.Net + +Function Invoke-ListUserPhoto { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # Interact with query parameters or the body of the request. + $tenantFilter = $Request.Query.TenantFilter + $userId = $Request.Query.UserID + + + $URI = "https://graph.microsoft.com/v1.0/users/$userId/photos/240x240/`$value" + Write-Host $URI + $graphRequest = New-GraphGetRequest -uri $URI -tenantid $tenantFilter + + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @($graphRequest) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListUserSettings.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListUserSettings.ps1 index 47ae2f685830..274c5d8383f1 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListUserSettings.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListUserSettings.ps1 @@ -18,8 +18,7 @@ function Invoke-ListUserSettings { $UserSettings = $UserSettings | Select-Object -ExpandProperty JSON | ConvertFrom-Json -Depth 10 -ErrorAction SilentlyContinue $StatusCode = [HttpStatusCode]::OK $Results = $UserSettings - } - catch { + } catch { $Results = "Function Error: $($_.Exception.Message)" $StatusCode = [HttpStatusCode]::BadRequest } diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListUserSigninLogs.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListUserSigninLogs.ps1 new file mode 100644 index 000000000000..d4fe27a93764 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListUserSigninLogs.ps1 @@ -0,0 +1,57 @@ +using namespace System.Net + +Function Invoke-ListUserSigninLogs { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + $UserID = $Request.Query.UserID + try { + $URI = "https://graph.microsoft.com/beta/auditLogs/signIns?`$filter=(userId eq '$UserID')&`$top=50&`$orderby=createdDateTime desc" + Write-Host $URI + $GraphRequest = New-GraphGetRequest -uri $URI -tenantid $TenantFilter -noPagination $true -verbose | Select-Object @{ Name = 'Date'; Expression = { $(($_.createdDateTime | Out-String) -replace '\r\n') } }, + id, + @{ Name = 'Application'; Expression = { $_.resourceDisplayName } }, + @{ Name = 'LoginStatus'; Expression = { $_.status.errorCode } }, + @{ Name = 'ConditionalAccessStatus'; Expression = { $_.conditionalAccessStatus } }, + @{ Name = 'OverallLoginStatus'; Expression = { if (($_.conditionalAccessStatus -eq 'Success' -or 'Not Applied') -and $_.status.errorCode -eq 0) { 'Success' } else { 'Failed' } } }, + @{ Name = 'IPAddress'; Expression = { $_.ipAddress } }, + @{ Name = 'Town'; Expression = { $_.location.city } }, + @{ Name = 'State'; Expression = { $_.location.state } }, + @{ Name = 'Country'; Expression = { $_.location.countryOrRegion } }, + @{ Name = 'Device'; Expression = { $_.deviceDetail.displayName } }, + @{ Name = 'DeviceCompliant'; Expression = { $_.deviceDetail.isCompliant } }, + @{ Name = 'OS'; Expression = { $_.deviceDetail.operatingSystem } }, + @{ Name = 'Browser'; Expression = { $_.deviceDetail.browser } }, + @{ Name = 'AppliedCAPs'; Expression = { ($_.appliedConditionalAccessPolicies | ForEach-Object { @{Result = $_.result; Name = $_.displayName } }) } }, + @{ Name = 'AdditionalDetails'; Expression = { $_.status.additionalDetails } }, + @{ Name = 'FailureReason'; Expression = { $_.status.failureReason } }, + @{ Name = 'FullDetails'; Expression = { $_ } } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @($GraphRequest) + }) + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to retrieve Sign In report: $($_.Exception.message) " -Sev 'Error' -tenant $TenantFilter + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = '500' + Body = $(Get-NormalizedError -message $_.Exception.message) + }) + } + + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListUsers.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListUsers.ps1 new file mode 100644 index 000000000000..961117510a0e --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListUsers.ps1 @@ -0,0 +1,87 @@ +using namespace System.Net + +Function Invoke-ListUsers { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + 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' + # 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 + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + $GraphFilter = $Request.Query.graphFilter + $userid = $Request.Query.UserID + + $GraphRequest = if ($TenantFilter -ne 'AllTenants') { + New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($userid)?`$top=999&`$select=$($selectlist -join ',')&`$filter=$GraphFilter&`$count=true" -tenantid $TenantFilter -ComplexFilter | Select-Object $selectlist | ForEach-Object { + $_.onPremisesSyncEnabled = [bool]($_.onPremisesSyncEnabled) + $_.Aliases = $_.Proxyaddresses -join ', ' + $SkuID = $_.AssignedLicenses.skuid + $_.LicJoined = ($ConvertTable | Where-Object { $_.guid -in $skuid }).'Product_Display_Name' -join ', ' + $_.primDomain = ($_.userPrincipalName -split '@' | Select-Object -Last 1) + $_ + } + } else { + $Table = Get-CIPPTable -TableName 'cacheusers' + $Rows = Get-CIPPAzDataTableEntity @Table | Where-Object -Property Timestamp -GT (Get-Date).AddHours(-1) + if (!$Rows) { + $Queue = New-CippQueueEntry -Name 'Users' -Link '/identity/administration/users?customerId=AllTenants' + Push-OutputBinding -Name listusers -Value "users/$($userid)?`$top=999&`$select=$($selectlist -join ',')&`$filter=$GraphFilter&`$count=true" + [PSCustomObject]@{ + Tenant = 'Loading data for all tenants. Please check back after the job completes' + QueueId = $Queue.RowKey + } + } else { + $Rows.Data | ConvertFrom-Json | Select-Object $selectlist | ForEach-Object { + $_.onPremisesSyncEnabled = [bool]($_.onPremisesSyncEnabled) + $_.Aliases = $_.Proxyaddresses -join ', ' + $SkuID = $_.AssignedLicenses.skuid + $_.LicJoined = ($ConvertTable | Where-Object { $_.guid -in $skuid }).'Product_Display_Name' -join ', ' + $_.primDomain = ($_.userPrincipalName -split '@' | Select-Object -Last 1) + $_ + } + } + } + + + if ($userid -and $Request.query.IncludeLogonDetails) { + $startDate = (Get-Date).AddDays(-7) + $endDate = (Get-Date) + $sessionid = Get-Random -Maximum 1000 -Minimum 1 + $SearchParam = @{ + SessionCommand = 'ReturnLargeSet' + Operations = @('UserLoggedIn', 'UserLoginFailed', 'TeamsSessionStarted', 'MailboxLogin') + sessionid = $sessionid + startDate = $startDate + endDate = $endDate + UserIds = @($GraphRequest.userPrincipalName) + } + $AuditlogsLogon = (New-ExoRequest -tenantid $Tenantfilter -cmdlet 'Search-unifiedAuditLog' -cmdParams $SearchParam | Sort-Object -Property CreationDate | Select-Object -Last 1).auditdata | ConvertFrom-Json + $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 $AuditlogsLogon.applicationId + $LastSignIn = [PSCustomObject]@{ + AppDisplayName = if ($AppName) { $AppName.'Application Name' } else { "$($AuditlogsLogon.Workload) - $($AuditlogsLogon.ApplicationId) " } + CreatedDateTime = $AuditlogsLogon.CreationTime + Id = $AuditlogsLogon.errorNumber + Status = $AuditlogsLogon.ResultStatus + } + $GraphRequest = $GraphRequest | Select-Object *, + @{ Name = 'LastSigninApplication'; Expression = { $LastSignIn.AppDisplayName } }, + @{ Name = 'LastSigninDate'; Expression = { $($LastSignIn.CreatedDateTime | Out-String) } }, + @{ Name = 'LastSigninStatus'; Expression = { $AuditlogsLogon.operation } }, + @{ Name = 'LastSigninResult'; Expression = { $LastSignIn.status } }, + @{ Name = 'LastSigninFailureReason'; Expression = { if ($LastSignIn.Id -eq 0) { 'Sucessfully signed in' } else { $LastSignIn.Id } } } + } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @($GraphRequest) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListWebhookAlert.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListWebhookAlert.ps1 new file mode 100644 index 000000000000..6eb63f8a57ae --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListWebhookAlert.ps1 @@ -0,0 +1,23 @@ +using namespace System.Net + +Function Invoke-ListWebhookAlert { + <# + .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' + $WebhookTable = Get-CIPPTable -TableName webhookTable + $WebhookRow = Get-CIPPAzDataTableEntity @WebhookTable + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @($WebhookRow) + }) + + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListmailboxPermissions.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListmailboxPermissions.ps1 new file mode 100644 index 000000000000..d855df71778b --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListmailboxPermissions.ps1 @@ -0,0 +1,68 @@ +using namespace System.Net + +Function Invoke-ListmailboxPermissions { + <# + .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' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + + Write-Host "Tenant Filter: $TenantFilter" + try { + $Bytes = [System.Text.Encoding]::UTF8.GetBytes($Request.Query.UserID) + $base64IdentityParam = [Convert]::ToBase64String($Bytes) + $PermsRequest = New-GraphGetRequest -uri "https://outlook.office365.com/adminapi/beta/$($tenantfilter)/Mailbox('$($Request.Query.UserID)')/MailboxPermission" -Tenantid $tenantfilter -scope ExchangeOnline + $PermsRequest2 = New-GraphGetRequest -uri "https://outlook.office365.com/adminapi/beta/$($tenantfilter)/Recipient('$base64IdentityParam')?`$expand=RecipientPermission&isEncoded=true" -Tenantid $tenantfilter -scope ExchangeOnline + $PermRequest3 = New-ExoRequest -Anchor $Request.Query.UserID -tenantid $Tenantfilter -cmdlet 'Get-Mailbox' -cmdParams @{Identity = $($Request.Query.UserID); } + + $GraphRequest = foreach ($Perm in $PermsRequest, $PermsRequest2.RecipientPermission, $PermRequest3) { + + if ($perm.Trustee) { + $perm | Where-Object Trustee | ForEach-Object { [PSCustomObject]@{ + User = $_.Trustee + Permissions = $_.accessRights + } + } + + } + if ($perm.PermissionList) { + $perm | Where-Object User | ForEach-Object { [PSCustomObject]@{ + User = $_.User + Permissions = $_.PermissionList.accessRights -join ', ' + } + } + } + if ($perm.GrantSendonBehalfTo -ne $null) { + $perm.GrantSendonBehalfTo | ForEach-Object { [PSCustomObject]@{ + User = $_ + Permissions = 'SendOnBehalf' + } + } + } + } + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $StatusCode = [HttpStatusCode]::Forbidden + $GraphRequest = $ErrorMessage + } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @($GraphRequest) + }) + + + +} diff --git a/Modules/CIPPCore/Public/GraphHelper/Convert-SKUName.ps1 b/Modules/CIPPCore/Public/GraphHelper/Convert-SKUName.ps1 new file mode 100644 index 000000000000..2bd91fcf7a19 --- /dev/null +++ b/Modules/CIPPCore/Public/GraphHelper/Convert-SKUName.ps1 @@ -0,0 +1,6 @@ +function Convert-SKUname($skuname, $skuID) { + $ConvertTable = Import-Csv Conversiontable.csv + if ($skuname) { $ReturnedName = ($ConvertTable | Where-Object { $_.String_Id -eq $skuname } | Select-Object -Last 1).'Product_Display_Name' } + if ($skuID) { $ReturnedName = ($ConvertTable | Where-Object { $_.guid -eq $skuid } | Select-Object -Last 1).'Product_Display_Name' } + if ($ReturnedName) { return $ReturnedName } else { return $skuname, $skuID } +} diff --git a/Modules/CIPPCore/Public/GraphHelper/Get-AuthorisedRequest.ps1 b/Modules/CIPPCore/Public/GraphHelper/Get-AuthorisedRequest.ps1 new file mode 100644 index 000000000000..89f8684d2e8e --- /dev/null +++ b/Modules/CIPPCore/Public/GraphHelper/Get-AuthorisedRequest.ps1 @@ -0,0 +1,21 @@ + +function Get-AuthorisedRequest { + [CmdletBinding()] + Param( + [string]$TenantID, + [string]$Uri + ) + if (!$TenantID) { + $TenantID = $env:TenantId + } + if ($Uri -like 'https://graph.microsoft.com/beta/contracts*' -or $Uri -like '*/customers/*' -or $Uri -eq 'https://graph.microsoft.com/v1.0/me/sendMail' -or $Uri -like '*/tenantRelationships/*') { + return $true + } + $Tenants = Get-Tenants -IncludeErrors + $SkipList = Get-Tenants -SkipList + if (($env:PartnerTenantAvailable -eq $true -and $SkipList.customerId -notcontains $TenantID -and $SkipList.defaultDomainName -notcontains $TenantID) -or (($Tenants.customerId -contains $TenantID -or $Tenants.defaultDomainName -contains $TenantID) -and $TenantID -ne $env:TenantId)) { + return $true + } else { + return $false + } +} diff --git a/Modules/CIPPCore/Public/GraphHelper/Get-CIPPTable.ps1 b/Modules/CIPPCore/Public/GraphHelper/Get-CIPPTable.ps1 new file mode 100644 index 000000000000..99567e300e18 --- /dev/null +++ b/Modules/CIPPCore/Public/GraphHelper/Get-CIPPTable.ps1 @@ -0,0 +1,12 @@ +function Get-CIPPTable { + [CmdletBinding()] + param ( + $tablename = 'CippLogs' + ) + $Context = New-AzDataTableContext -ConnectionString $env:AzureWebJobsStorage -TableName $tablename + New-AzDataTable -Context $Context | Out-Null + + @{ + Context = $Context + } +} \ No newline at end of file diff --git a/Modules/CIPPCore/Public/GraphHelper/Get-ClassicAPIToken.ps1 b/Modules/CIPPCore/Public/GraphHelper/Get-ClassicAPIToken.ps1 new file mode 100644 index 000000000000..6568e28b867a --- /dev/null +++ b/Modules/CIPPCore/Public/GraphHelper/Get-ClassicAPIToken.ps1 @@ -0,0 +1,41 @@ +function Get-ClassicAPIToken($tenantID, $Resource) { + $TokenKey = '{0}-{1}' -f $TenantID, $Resource + if ($script:classictoken.$TokenKey -and [int](Get-Date -UFormat %s -Millisecond 0) -lt $script:classictoken.$TokenKey.expires_on) { + Write-Host 'Classic: cached token' + return $script:classictoken.$TokenKey + } else { + Write-Host 'Using classic' + $uri = "https://login.microsoftonline.com/$($TenantID)/oauth2/token" + $Body = @{ + client_id = $env:ApplicationID + client_secret = $env:ApplicationSecret + resource = $Resource + refresh_token = $env:RefreshToken + grant_type = 'refresh_token' + } + try { + if (!$script:classictoken) { $script:classictoken = [HashTable]::Synchronized(@{}) } + $script:classictoken.$TokenKey = Invoke-RestMethod $uri -Body $body -ContentType 'application/x-www-form-urlencoded' -ErrorAction SilentlyContinue -Method post + return $script:classictoken.$TokenKey + } catch { + # Track consecutive Graph API failures + $TenantsTable = Get-CippTable -tablename Tenants + $Filter = "PartitionKey eq 'Tenants' and (defaultDomainName eq '{0}' or customerId eq '{0}')" -f $tenantid + $Tenant = Get-CIPPAzDataTableEntity @TenantsTable -Filter $Filter + if (!$Tenant) { + $Tenant = @{ + GraphErrorCount = $null + LastGraphTokenError = $null + LastGraphError = $null + PartitionKey = 'TenantFailed' + RowKey = 'Failed' + } + } + $Tenant.LastGraphError = $_.Exception.Message + $Tenant.GraphErrorCount++ + + Update-AzDataTableEntity @TenantsTable -Entity $Tenant + Throw "Failed to obtain Classic API Token for $TenantID - $_" + } + } +} \ No newline at end of file diff --git a/Modules/CIPPCore/Public/GraphHelper/Get-GraphBulkResultByID.ps1 b/Modules/CIPPCore/Public/GraphHelper/Get-GraphBulkResultByID.ps1 new file mode 100644 index 000000000000..e71d8c8ffb25 --- /dev/null +++ b/Modules/CIPPCore/Public/GraphHelper/Get-GraphBulkResultByID.ps1 @@ -0,0 +1,7 @@ +function Get-GraphBulkResultByID ($Results, $ID, [switch]$Value) { + if ($Value) { + ($Results | Where-Object { $_.id -eq $ID }).body.value + } else { + ($Results | Where-Object { $_.id -eq $ID }).body + } +} diff --git a/Modules/CIPPCore/Public/GraphHelper/Get-GraphToken.ps1 b/Modules/CIPPCore/Public/GraphHelper/Get-GraphToken.ps1 new file mode 100644 index 000000000000..8a654c8e979a --- /dev/null +++ b/Modules/CIPPCore/Public/GraphHelper/Get-GraphToken.ps1 @@ -0,0 +1,74 @@ +function Get-GraphToken($tenantid, $scope, $AsApp, $AppID, $refreshToken, $ReturnRefresh, $SkipCache) { + if (!$scope) { $scope = 'https://graph.microsoft.com/.default' } + if (!$env:SetFromProfile) { $CIPPAuth = Get-CIPPAuthentication; Write-Host 'Could not get Refreshtoken from environment variable. Reloading token.' } + $AuthBody = @{ + client_id = $env:ApplicationID + client_secret = $env:ApplicationSecret + scope = $Scope + refresh_token = $env:RefreshToken + grant_type = 'refresh_token' + } + if ($asApp -eq $true) { + $AuthBody = @{ + client_id = $env:ApplicationID + client_secret = $env:ApplicationSecret + scope = $Scope + grant_type = 'client_credentials' + } + } + + if ($null -ne $AppID -and $null -ne $refreshToken) { + $AuthBody = @{ + client_id = $appid + refresh_token = $RefreshToken + scope = $Scope + grant_type = 'refresh_token' + } + } + + if (!$tenantid) { $tenantid = $env:TenantID } + + $TokenKey = '{0}-{1}-{2}' -f $tenantid, $scope, $asApp + + try { + if ($script:AccessTokens.$TokenKey -and [int](Get-Date -UFormat %s -Millisecond 0) -lt $script:AccessTokens.$TokenKey.expires_on -and $SkipCache -ne $true) { + Write-Host 'Graph: cached token' + $AccessToken = $script:AccessTokens.$TokenKey + } else { + Write-Host 'Graph: new token' + $AccessToken = (Invoke-RestMethod -Method post -Uri "https://login.microsoftonline.com/$($tenantid)/oauth2/v2.0/token" -Body $Authbody -ErrorAction Stop) + $ExpiresOn = [int](Get-Date -UFormat %s -Millisecond 0) + $AccessToken.expires_in + Add-Member -InputObject $AccessToken -NotePropertyName 'expires_on' -NotePropertyValue $ExpiresOn + if (!$script:AccessTokens) { $script:AccessTokens = [HashTable]::Synchronized(@{}) } + $script:AccessTokens.$TokenKey = $AccessToken + } + + if ($ReturnRefresh) { $header = $AccessToken } else { $header = @{ Authorization = "Bearer $($AccessToken.access_token)" } } + return $header + } catch { + # Track consecutive Graph API failures + $TenantsTable = Get-CippTable -tablename Tenants + $Filter = "PartitionKey eq 'Tenants' and (defaultDomainName eq '{0}' or customerId eq '{0}')" -f $tenantid + $Tenant = Get-CIPPAzDataTableEntity @TenantsTable -Filter $Filter + if (!$Tenant.RowKey) { + $donotset = $true + $Tenant = [pscustomobject]@{ + GraphErrorCount = $null + LastGraphTokenError = $null + LastGraphError = $null + PartitionKey = 'TenantFailed' + RowKey = 'Failed' + } + } + $Tenant.LastGraphError = if ( $_.ErrorDetails.Message) { + $msg = $_.ErrorDetails.Message | ConvertFrom-Json + "$($msg.error):$($msg.error_description)" + } else { + $_.Exception.message + } + $Tenant.GraphErrorCount++ + + if (!$donotset) { Update-AzDataTableEntity @TenantsTable -Entity $Tenant } + throw "Could not get token: $($Tenant.LastGraphError)" + } +} diff --git a/Modules/CIPPCore/Public/GraphHelper/Get-NormalizedError.ps1 b/Modules/CIPPCore/Public/GraphHelper/Get-NormalizedError.ps1 new file mode 100644 index 000000000000..96d5b0b4533c --- /dev/null +++ b/Modules/CIPPCore/Public/GraphHelper/Get-NormalizedError.ps1 @@ -0,0 +1,27 @@ +function Get-NormalizedError { + [CmdletBinding()] + param ( + [string]$message + ) + switch -Wildcard ($message) { + 'Request not applicable to target tenant.' { 'Required license not available for this tenant' } + "Neither tenant is B2C or tenant doesn't have premium license" { 'This feature requires a P1 license or higher' } + 'Response status code does not indicate success: 400 (Bad Request).' { 'Error 400 occured. There is an issue with the token configuration for this tenant. Please perform an access check' } + '*Microsoft.Skype.Sync.Pstn.Tnm.Common.Http.HttpResponseException*' { 'Could not connect to Teams Admin center - Tenant might be missing a Teams license' } + '*Provide valid credential.*' { 'Error 400: There is an issue with your Exchange Token configuration. Please perform an access check for this tenant' } + '*This indicate that a subscription within the tenant has lapsed*' { 'There is no exchange subscription available, or it has lapsed. Check licensing information.' } + '*User was not found.*' { 'The relationship between this tenant and the partner has been dissolved from the tenant side.' } + '*The user or administrator has not consented to use the application*' { 'CIPP cannot access this tenant. Perform a CPV Refresh and Access Check via the settings menu' } + '*AADSTS50020*' { 'AADSTS50020: The user you have used for your Secure Application Model is a guest in this tenant, or your are using GDAP and have not added the user to the correct group. Please delete the guest user to gain access to this tenant' } + '*AADSTS50177' { 'AADSTS50177: The user you have used for your Secure Application Model is a guest in this tenant, or your are using GDAP and have not added the user to the correct group. Please delete the guest user to gain access to this tenant' } + '*invalid or malformed*' { 'The request is malformed. Have you finished the SAM Setup?' } + '*Windows Store repository apps feature is not supported for this tenant*' { 'This tenant does not have WinGet support available' } + '*AADSTS650051*' { 'The application does not exist yet. Try again in 30 seconds.' } + '*AppLifecycle_2210*' { 'Failed to call Intune APIs: Does the tenant have a license available?' } + '*One or more added object references already exist for the following modified properties:*' { 'This user is already a member of this group.' } + '*Microsoft.Exchange.Management.Tasks.MemberAlreadyExistsException*' { 'This user is already a member of this group.' } + '*The property value exceeds the maximum allowed size (64KB)*' { 'One of the values exceeds the maximum allowed size (64KB).' } + Default { $message } + + } +} diff --git a/Modules/CIPPCore/Public/GraphHelper/Get-Tenants.ps1 b/Modules/CIPPCore/Public/GraphHelper/Get-Tenants.ps1 new file mode 100644 index 000000000000..4f0c1a16cbf8 --- /dev/null +++ b/Modules/CIPPCore/Public/GraphHelper/Get-Tenants.ps1 @@ -0,0 +1,110 @@ +function Get-Tenants { + param ( + [Parameter( ParameterSetName = 'Skip', Mandatory = $True )] + [switch]$SkipList, + [Parameter( ParameterSetName = 'Standard')] + [switch]$IncludeAll, + [switch]$IncludeErrors + ) + + $TenantsTable = Get-CippTable -tablename 'Tenants' + $ExcludedFilter = "PartitionKey eq 'Tenants' and Excluded eq true" + + $SkipListCache = Get-CIPPAzDataTableEntity @TenantsTable -Filter $ExcludedFilter + if ($SkipList) { + return $SkipListCache + } + + if ($IncludeAll.IsPresent) { + $Filter = "PartitionKey eq 'Tenants'" + } elseif ($IncludeErrors.IsPresent) { + $Filter = "PartitionKey eq 'Tenants' and Excluded eq false" + } else { + $Filter = "PartitionKey eq 'Tenants' and Excluded eq false and GraphErrorCount lt 50" + } + $IncludedTenantsCache = Get-CIPPAzDataTableEntity @TenantsTable -Filter $Filter + + if (($IncludedTenantsCache | Measure-Object).Count -gt 0) { + try { + $LastRefresh = ($IncludedTenantsCache | Where-Object { $_.customerId } | Sort-Object LastRefresh -Descending | Select-Object -First 1).LastRefresh | Get-Date -ErrorAction Stop + } catch { $LastRefresh = $false } + } else { + $LastRefresh = $false + } + if (!$LastRefresh -or $LastRefresh -lt (Get-Date).Addhours(-24).ToUniversalTime()) { + try { + Write-Host "Renewing. Cache not hit. $LastRefresh" + $TenantList = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/tenantRelationships/managedTenants/tenants?`$top=999" -tenantid $env:TenantID ) | Select-Object id, @{l = 'customerId'; e = { $_.tenantId } }, @{l = 'DefaultdomainName'; e = { [string]($_.contract.defaultDomainName) } } , @{l = 'MigratedToNewTenantAPI'; e = { $true } }, DisplayName, domains, @{n = 'delegatedPrivilegeStatus'; exp = { $_.tenantStatusInformation.delegatedPrivilegeStatus } } | Where-Object { $_.defaultDomainName -NotIn $SkipListCache.defaultDomainName -and $_.defaultDomainName -ne $null } + + } catch { + Write-Host "Get-Tenants - Lighthouse Error, using contract/delegatedAdminRelationship calls. Error: $($_.Exception.Message)" + [System.Collections.Generic.List[PSCustomObject]]$BulkRequests = @( + @{ + id = 'Contracts' + method = 'GET' + url = "/contracts?`$top=999" + }, + @{ + id = 'GDAPRelationships' + method = 'GET' + url = '/tenantRelationships/delegatedAdminRelationships' + } + ) + + $BulkResults = New-GraphBulkRequest -Requests $BulkRequests -tenantid $TenantFilter -NoAuthCheck:$true + $Contracts = Get-GraphBulkResultByID -Results $BulkResults -ID 'Contracts' -Value + $GDAPRelationships = Get-GraphBulkResultByID -Results $BulkResults -ID 'GDAPRelationships' -Value + + $ContractList = $Contracts | Select-Object id, customerId, DefaultdomainName, DisplayName, domains, @{l = 'MigratedToNewTenantAPI'; e = { $true } }, @{ n = 'delegatedPrivilegeStatus'; exp = { $CustomerId = $_.customerId; if (($GDAPRelationships | Where-Object { $_.customer.tenantId -EQ $CustomerId -and $_.status -EQ 'active' } | Measure-Object).Count -gt 0) { 'delegatedAndGranularDelegetedAdminPrivileges' } else { 'delegatedAdminPrivileges' } } } | Where-Object -Property defaultDomainName -NotIn $SkipListCache.defaultDomainName + + $GDAPOnlyList = $GDAPRelationships | Where-Object { $_.status -eq 'active' -and $Contracts.customerId -notcontains $_.customer.tenantId } | Select-Object id, @{l = 'customerId'; e = { $($_.customer.tenantId) } }, @{l = 'defaultDomainName'; e = { (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/tenantRelationships/findTenantInformationByTenantId(tenantId='$($_.customer.tenantId)')" -noauthcheck $true -asApp:$true -tenant $env:TenantId).defaultDomainName } }, @{l = 'MigratedToNewTenantAPI'; e = { $true } }, @{n = 'displayName'; exp = { $_.customer.displayName } }, domains, @{n = 'delegatedPrivilegeStatus'; exp = { 'granularDelegatedAdminPrivileges' } } | Where-Object { $_.defaultDomainName -NotIn $SkipListCache.defaultDomainName -and $_.defaultDomainName -ne $null } | Sort-Object -Property customerId -Unique + + $TenantList = @($ContractList) + @($GDAPOnlyList) + } + <#if (!$TenantList.customerId) { + $TenantList = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/contracts?`$top=999" -tenantid $env:TenantID ) | Select-Object id, customerId, DefaultdomainName, DisplayName, domains | Where-Object -Property defaultDomainName -NotIn $SkipListCache.defaultDomainName + }#> + $IncludedTenantsCache = [system.collections.generic.list[hashtable]]::new() + if ($env:PartnerTenantAvailable) { + $IncludedTenantsCache.Add(@{ + RowKey = $env:TenantID + PartitionKey = 'Tenants' + customerId = $env:TenantID + defaultDomainName = $env:TenantID + displayName = '*Partner Tenant' + domains = 'PartnerTenant' + Excluded = $false + ExcludeUser = '' + ExcludeDate = '' + GraphErrorCount = 0 + LastGraphError = '' + LastRefresh = (Get-Date).ToUniversalTime() + }) | Out-Null + } + foreach ($Tenant in $TenantList) { + if ($Tenant.defaultDomainName -eq 'Invalid' -or !$Tenant.defaultDomainName) { continue } + $IncludedTenantsCache.Add(@{ + RowKey = [string]$Tenant.customerId + PartitionKey = 'Tenants' + customerId = [string]$Tenant.customerId + defaultDomainName = [string]$Tenant.defaultDomainName + displayName = [string]$Tenant.DisplayName + delegatedPrivilegeStatus = [string]$Tenant.delegatedPrivilegeStatus + domains = '' + Excluded = $false + ExcludeUser = '' + ExcludeDate = '' + GraphErrorCount = 0 + LastGraphError = '' + LastRefresh = (Get-Date).ToUniversalTime() + }) | Out-Null + } + + if ($IncludedTenantsCache) { + $TenantsTable.Force = $true + Add-CIPPAzDataTableEntity @TenantsTable -Entity $IncludedTenantsCache + } + } + return ($IncludedTenantsCache | Where-Object -Property defaultDomainName -NE $null | Sort-Object -Property displayName) + +} diff --git a/Modules/CIPPCore/Public/GraphHelper/New-ClassicAPIGetRequest.ps1 b/Modules/CIPPCore/Public/GraphHelper/New-ClassicAPIGetRequest.ps1 new file mode 100644 index 000000000000..1528e0e4393d --- /dev/null +++ b/Modules/CIPPCore/Public/GraphHelper/New-ClassicAPIGetRequest.ps1 @@ -0,0 +1,27 @@ + +function New-ClassicAPIGetRequest($TenantID, $Uri, $Method = 'GET', $Resource = 'https://admin.microsoft.com', $ContentType = 'application/json') { + + if ((Get-AuthorisedRequest -Uri $uri -TenantID $tenantid)) { + $token = Get-ClassicAPIToken -Tenant $tenantID -Resource $Resource + + $NextURL = $Uri + $ReturnedData = do { + try { + $Data = Invoke-RestMethod -ContentType "$ContentType;charset=UTF-8" -Uri $NextURL -Method $Method -Headers @{ + Authorization = "Bearer $($token.access_token)" + 'x-ms-client-request-id' = [guid]::NewGuid().ToString() + 'x-ms-client-session-id' = [guid]::NewGuid().ToString() + 'x-ms-correlation-id' = [guid]::NewGuid() + 'X-Requested-With' = 'XMLHttpRequest' + } + $Data + if ($noPagination) { $nextURL = $null } else { $nextURL = $data.NextLink } + } catch { + throw "Failed to make Classic Get Request $_" + } + } until ($null -eq $NextURL) + return $ReturnedData + } else { + Write-Error 'Not allowed. You cannot manage your own tenant or tenants not under your scope' + } +} \ No newline at end of file diff --git a/Modules/CIPPCore/Public/GraphHelper/New-DeviceLogin.ps1 b/Modules/CIPPCore/Public/GraphHelper/New-DeviceLogin.ps1 new file mode 100644 index 000000000000..1d80e47ba069 --- /dev/null +++ b/Modules/CIPPCore/Public/GraphHelper/New-DeviceLogin.ps1 @@ -0,0 +1,27 @@ +function New-DeviceLogin { + [CmdletBinding()] + param ( + [string]$clientid, + [string]$scope, + [switch]$FirstLogon, + [string]$device_code, + [string]$TenantId + ) + $encodedscope = [uri]::EscapeDataString($scope) + if ($FirstLogon) { + if ($TenantID) { + $ReturnCode = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$($TenantID)/oauth2/v2.0/devicecode" -Method POST -Body "client_id=$($Clientid)&scope=$encodedscope+offline_access+profile+openid" + + } else { + $ReturnCode = Invoke-RestMethod -Uri 'https://login.microsoftonline.com/organizations/oauth2/v2.0/devicecode' -Method POST -Body "client_id=$($Clientid)&scope=$encodedscope+offline_access+profile+openid" + } + } else { + $Checking = Invoke-RestMethod -SkipHttpErrorCheck -Uri 'https://login.microsoftonline.com/organizations/oauth2/v2.0/token' -Method POST -Body "client_id=$($Clientid)&scope=$encodedscope+offline_access+profile+openid&grant_type=device_code&device_code=$($device_code)" + if ($checking.refresh_token) { + $ReturnCode = $Checking + } else { + $returncode = $Checking.error + } + } + return $ReturnCode +} \ No newline at end of file diff --git a/Modules/CIPPCore/Public/GraphHelper/New-ExoRequest.ps1 b/Modules/CIPPCore/Public/GraphHelper/New-ExoRequest.ps1 new file mode 100644 index 000000000000..d5df999e6a03 --- /dev/null +++ b/Modules/CIPPCore/Public/GraphHelper/New-ExoRequest.ps1 @@ -0,0 +1,66 @@ +function New-ExoRequest ($tenantid, $cmdlet, $cmdParams, $useSystemMailbox, $Anchor, $NoAuthCheck, $Select) { + + if ((Get-AuthorisedRequest -TenantID $tenantid) -or $NoAuthCheck -eq $True) { + $token = Get-ClassicAPIToken -resource 'https://outlook.office365.com' -Tenantid $tenantid + $tenant = (get-tenants -IncludeErrors | Where-Object { $_.defaultDomainName -eq $tenantid -or $_.customerId -eq $tenantid }).customerId + if ($cmdParams) { + $Params = $cmdParams + } else { + $Params = @{} + } + $ExoBody = ConvertTo-Json -Depth 5 -InputObject @{ + CmdletInput = @{ + CmdletName = $cmdlet + Parameters = $Params + } + } + if (!$Anchor) { + if ($cmdparams.Identity) { $Anchor = $cmdparams.Identity } + if ($cmdparams.anr) { $Anchor = $cmdparams.anr } + if ($cmdparams.User) { $Anchor = $cmdparams.User } + + if (!$Anchor -or $useSystemMailbox) { + $OnMicrosoft = (New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/domains?$top=999' -tenantid $tenantid -NoAuthCheck $NoAuthCheck | Where-Object -Property isInitial -EQ $true).id + + $anchor = "UPN:SystemMailbox{8cc370d3-822a-4ab8-a926-bb94bd0641a9}@$($OnMicrosoft)" + + + } + } + Write-Host "Using $Anchor" + $Headers = @{ + Authorization = "Bearer $($token.access_token)" + Prefer = 'odata.maxpagesize = 1000' + 'parameter-based-routing' = $true + 'X-AnchorMailbox' = $anchor + + } + try { + if ($Select) { $Select = "`$select=$Select" } + $URL = "https://outlook.office365.com/adminapi/beta/$($tenant)/InvokeCommand?$Select" + + $ReturnedData = + do { + $Return = Invoke-RestMethod $URL -Method POST -Body $ExoBody -Headers $Headers -ContentType 'application/json; charset=utf-8' + $URL = $Return.'@odata.nextLink' + $Return + } until ($null -eq $URL) + + if ($ReturnedData.'@adminapi.warnings' -and $ReturnedData.value -eq $null) { + $ReturnedData.value = $ReturnedData.'@adminapi.warnings' + } + } catch { + $ErrorMess = $($_.Exception.Message) + $ReportedError = ($_.ErrorDetails | ConvertFrom-Json -ErrorAction SilentlyContinue) + $Message = if ($ReportedError.error.details.message) { + $ReportedError.error.details.message + } elseif ($ReportedError.error.message) { $ReportedError.error.message } + else { $ReportedError.error.innererror.internalException.message } + if ($null -eq $Message) { $Message = $ErrorMess } + throw $Message + } + return $ReturnedData.value + } else { + Write-Error 'Not allowed. You cannot manage your own tenant or tenants not under your scope' + } +} \ No newline at end of file diff --git a/Modules/CIPPCore/Public/GraphHelper/New-GraphBulkRequest.ps1 b/Modules/CIPPCore/Public/GraphHelper/New-GraphBulkRequest.ps1 new file mode 100644 index 000000000000..d328a7518865 --- /dev/null +++ b/Modules/CIPPCore/Public/GraphHelper/New-GraphBulkRequest.ps1 @@ -0,0 +1,61 @@ +function New-GraphBulkRequest { + Param( + $tenantid, + $NoAuthCheck, + $scope, + $asapp, + $Requests + ) + + if ($NoAuthCheck -or (Get-AuthorisedRequest -Uri $uri -TenantID $tenantid)) { + $headers = Get-GraphToken -tenantid $tenantid -scope $scope -AsApp $asapp + + $URL = 'https://graph.microsoft.com/beta/$batch' + + # Track consecutive Graph API failures + $TenantsTable = Get-CippTable -tablename Tenants + $Filter = "PartitionKey eq 'Tenants' and (defaultDomainName eq '{0}' or customerId eq '{0}')" -f $tenantid + $Tenant = Get-CIPPAzDataTableEntity @TenantsTable -Filter $Filter + if (!$Tenant) { + $Tenant = @{ + GraphErrorCount = 0 + LastGraphError = $null + PartitionKey = 'TenantFailed' + RowKey = 'Failed' + } + } + try { + $ReturnedData = for ($i = 0; $i -lt $Requests.count; $i += 20) { + $req = @{} + # Use select to create hashtables of id, method and url for each call + $req['requests'] = ($Requests[$i..($i + 19)]) + Invoke-RestMethod -Uri $URL -Method POST -Headers $headers -ContentType 'application/json; charset=utf-8' -Body ($req | ConvertTo-Json -Depth 10) + } + + foreach ($MoreData in $ReturnedData.Responses | Where-Object { $_.body.'@odata.nextLink' }) { + Write-Host 'Getting more' + $AdditionalValues = New-GraphGetRequest -ComplexFilter -uri $MoreData.body.'@odata.nextLink' -tenantid $tenantid -NoAuthCheck:$NoAuthCheck + $NewValues = [System.Collections.Generic.List[PSCustomObject]]$MoreData.body.value + $AdditionalValues | ForEach-Object { $NewValues.add($_) } + $MoreData.body.value = $NewValues + } + + } catch { + $Message = ($_.ErrorDetails.Message | ConvertFrom-Json -ErrorAction SilentlyContinue).error.message + if ($Message -eq $null) { $Message = $($_.Exception.Message) } + if ($Message -ne 'Request not applicable to target tenant.') { + $Tenant.LastGraphError = $Message + $Tenant.GraphErrorCount++ + Update-AzDataTableEntity @TenantsTable -Entity $Tenant + } + throw $Message + } + + $Tenant.LastGraphError = '' + Update-AzDataTableEntity @TenantsTable -Entity $Tenant + + return $ReturnedData.responses + } else { + Write-Error 'Not allowed. You cannot manage your own tenant or tenants not under your scope' + } +} diff --git a/Modules/CIPPCore/Public/GraphHelper/New-GraphGetRequest.ps1 b/Modules/CIPPCore/Public/GraphHelper/New-GraphGetRequest.ps1 new file mode 100644 index 000000000000..731c09da25b0 --- /dev/null +++ b/Modules/CIPPCore/Public/GraphHelper/New-GraphGetRequest.ps1 @@ -0,0 +1,67 @@ +function New-GraphGetRequest { + Param( + $uri, + $tenantid, + $scope, + $AsApp, + $noPagination, + $NoAuthCheck, + $skipTokenCache, + [switch]$ComplexFilter, + [switch]$CountOnly + ) + + if ($NoAuthCheck -or (Get-AuthorisedRequest -Uri $uri -TenantID $tenantid)) { + if ($scope -eq 'ExchangeOnline') { + $AccessToken = Get-ClassicAPIToken -resource 'https://outlook.office365.com' -Tenantid $tenantid + $headers = @{ Authorization = "Bearer $($AccessToken.access_token)" } + } else { + $headers = Get-GraphToken -tenantid $tenantid -scope $scope -AsApp $asapp -SkipCache $skipTokenCache + } + + if ($ComplexFilter) { + $headers['ConsistencyLevel'] = 'eventual' + } + $nextURL = $uri + + # Track consecutive Graph API failures + $TenantsTable = Get-CippTable -tablename Tenants + $Filter = "PartitionKey eq 'Tenants' and (defaultDomainName eq '{0}' or customerId eq '{0}')" -f $tenantid + $Tenant = Get-CIPPAzDataTableEntity @TenantsTable -Filter $Filter + if (!$Tenant) { + $Tenant = @{ + GraphErrorCount = 0 + LastGraphError = $null + PartitionKey = 'TenantFailed' + RowKey = 'Failed' + } + } + + $ReturnedData = do { + try { + $Data = (Invoke-RestMethod -Uri $nextURL -Method GET -Headers $headers -ContentType 'application/json; charset=utf-8') + if ($CountOnly) { + $Data.'@odata.count' + $nextURL = $null + } else { + if ($data.value) { $data.value } else { ($Data) } + if ($noPagination) { $nextURL = $null } else { $nextURL = $data.'@odata.nextLink' } + } + } catch { + $Message = ($_.ErrorDetails.Message | ConvertFrom-Json -ErrorAction SilentlyContinue).error.message + if ($Message -eq $null) { $Message = $($_.Exception.Message) } + if ($Message -ne 'Request not applicable to target tenant.' -and $Tenant) { + $Tenant.LastGraphError = $Message + $Tenant.GraphErrorCount++ + Update-AzDataTableEntity @TenantsTable -Entity $Tenant + } + throw $Message + } + } until ($null -eq $NextURL) + $Tenant.LastGraphError = '' + Update-AzDataTableEntity @TenantsTable -Entity $Tenant + return $ReturnedData + } else { + Write-Error 'Not allowed. You cannot manage your own tenant or tenants not under your scope' + } +} diff --git a/Modules/CIPPCore/Public/GraphHelper/New-GraphPOSTRequest.ps1 b/Modules/CIPPCore/Public/GraphHelper/New-GraphPOSTRequest.ps1 new file mode 100644 index 000000000000..a133d7a93f7d --- /dev/null +++ b/Modules/CIPPCore/Public/GraphHelper/New-GraphPOSTRequest.ps1 @@ -0,0 +1,27 @@ + +function New-GraphPOSTRequest ($uri, $tenantid, $body, $type, $scope, $AsApp, $NoAuthCheck, $skipTokenCache, $AddedHeaders) { + if ($NoAuthCheck -or (Get-AuthorisedRequest -Uri $uri -TenantID $tenantid)) { + $headers = Get-GraphToken -tenantid $tenantid -scope $scope -AsApp $asapp -SkipCache $skipTokenCache + if ($AddedHeaders) { + foreach ($header in $AddedHeaders.getenumerator()) { + $headers.Add($header.Key, $header.Value) + } + } + Write-Verbose "Using $($uri) as url" + if (!$type) { + $type = 'POST' + } + + try { + $ReturnedData = (Invoke-RestMethod -Uri $($uri) -Method $TYPE -Body $body -Headers $headers -ContentType 'application/json; charset=utf-8') + } catch { + $ErrorMess = $($_.Exception.Message) + $Message = ($_.ErrorDetails.Message | ConvertFrom-Json -ErrorAction SilentlyContinue).error.message + if (!$Message) { $Message = $ErrorMess } + throw $Message + } + return $ReturnedData + } else { + Write-Error 'Not allowed. You cannot manage your own tenant or tenants not under your scope' + } +} \ No newline at end of file diff --git a/Modules/CIPPCore/Public/GraphHelper/New-TeamsAPIGetRequest.ps1 b/Modules/CIPPCore/Public/GraphHelper/New-TeamsAPIGetRequest.ps1 new file mode 100644 index 000000000000..7ac373da6ffb --- /dev/null +++ b/Modules/CIPPCore/Public/GraphHelper/New-TeamsAPIGetRequest.ps1 @@ -0,0 +1,28 @@ +function New-TeamsAPIGetRequest($Uri, $tenantID, $Method = 'GET', $Resource = '48ac35b8-9aa8-4d74-927d-1f4a14a0b239', $ContentType = 'application/json') { + + if ((Get-AuthorisedRequest -Uri $uri -TenantID $tenantid)) { + $token = Get-ClassicAPIToken -Tenant $tenantid -Resource $Resource + + $NextURL = $Uri + $ReturnedData = do { + try { + $Data = Invoke-RestMethod -ContentType "$ContentType;charset=UTF-8" -Uri $NextURL -Method $Method -Headers @{ + Authorization = "Bearer $($token.access_token)" + 'x-ms-client-request-id' = [guid]::NewGuid().ToString() + 'x-ms-client-session-id' = [guid]::NewGuid().ToString() + 'x-ms-correlation-id' = [guid]::NewGuid() + 'X-Requested-With' = 'XMLHttpRequest' + 'x-ms-tnm-applicationid' = '045268c0-445e-4ac1-9157-d58f67b167d9' + + } + $Data + if ($noPagination) { $nextURL = $null } else { $nextURL = $data.NextLink } + } catch { + throw "Failed to make Teams API Get Request $_" + } + } until ($null -eq $NextURL) + return $ReturnedData + } else { + Write-Error 'Not allowed. You cannot manage your own tenant or tenants not under your scope' + } +} \ No newline at end of file diff --git a/Modules/CIPPCore/Public/GraphHelper/New-passwordString.ps1 b/Modules/CIPPCore/Public/GraphHelper/New-passwordString.ps1 new file mode 100644 index 000000000000..4e6e27befdc8 --- /dev/null +++ b/Modules/CIPPCore/Public/GraphHelper/New-passwordString.ps1 @@ -0,0 +1,14 @@ +function New-passwordString { + [CmdletBinding()] + param ( + [int]$count = 12 + ) + $SettingsTable = Get-CippTable -tablename 'Settings' + $PasswordType = (Get-CIPPAzDataTableEntity @SettingsTable).passwordType + if ($PasswordType -eq 'Correct-Battery-Horse') { + $Words = Get-Content .\words.txt + (Get-Random -InputObject $words -Count 4) -join '-' + } else { + -join ('abcdefghkmnrstuvwxyzABCDEFGHKLMNPRSTUVWXYZ23456789$%&*#'.ToCharArray() | Get-Random -Count $count) + } +} diff --git a/Modules/CIPPCore/Public/GraphHelper/Read-JwtAccessDetails.ps1 b/Modules/CIPPCore/Public/GraphHelper/Read-JwtAccessDetails.ps1 new file mode 100644 index 000000000000..b789fe87e298 --- /dev/null +++ b/Modules/CIPPCore/Public/GraphHelper/Read-JwtAccessDetails.ps1 @@ -0,0 +1,57 @@ +function Read-JwtAccessDetails { + <# + .SYNOPSIS + Parse Microsoft JWT access tokens + + .DESCRIPTION + Extract JWT access token details for verification + + .PARAMETER Token + Token to get details for + + #> + [cmdletbinding()] + param( + [Parameter(Mandatory = $true)] + [string]$Token + ) + + # Default token object + $TokenDetails = [PSCustomObject]@{ + AppId = '' + AppName = '' + Audience = '' + AuthMethods = '' + IPAddress = '' + Name = '' + Scope = '' + TenantId = '' + UserPrincipalName = '' + } + + if (!$Token.Contains('.') -or !$token.StartsWith('eyJ')) { return $TokenDetails } + + # Get token payload + $tokenPayload = $token.Split('.')[1].Replace('-', '+').Replace('_', '/') + while ($tokenPayload.Length % 4) { + $tokenPayload = '{0}=' -f $tokenPayload + } + + # Convert base64 to json to object + $tokenByteArray = [System.Convert]::FromBase64String($tokenPayload) + $tokenArray = [System.Text.Encoding]::ASCII.GetString($tokenByteArray) + $TokenObj = $tokenArray | ConvertFrom-Json + + # Convert token details to human readable + $TokenDetails.AppId = $TokenObj.appid + $TokenDetails.AppName = $TokenObj.app_displayname + $TokenDetails.Audience = $TokenObj.aud + $TokenDetails.AuthMethods = $TokenObj.amr + $TokenDetails.IPAddress = $TokenObj.ipaddr + $TokenDetails.Name = $TokenObj.name + $TokenDetails.Scope = $TokenObj.scp -split ' ' + $TokenDetails.TenantId = $TokenObj.tid + $TokenDetails.UserPrincipalName = $TokenObj.upn + + return $TokenDetails +} \ No newline at end of file diff --git a/Modules/CIPPCore/Public/GraphHelper/Remove-CIPPCache.ps1 b/Modules/CIPPCore/Public/GraphHelper/Remove-CIPPCache.ps1 new file mode 100644 index 000000000000..b2da4587453c --- /dev/null +++ b/Modules/CIPPCore/Public/GraphHelper/Remove-CIPPCache.ps1 @@ -0,0 +1,29 @@ +function Remove-CIPPCache { + param ( + $TenantsOnly + ) + # Remove all tenants except excluded + $TenantsTable = Get-CippTable -tablename 'Tenants' + $Filter = "PartitionKey eq 'Tenants' and Excluded eq false" + $ClearIncludedTenants = Get-CIPPAzDataTableEntity @TenantsTable -Filter $Filter + Remove-AzDataTableEntity @TenantsTable -Entity $ClearIncludedTenants + if ($tenantsonly -eq 'false') { + Write-Host 'Clearing all' + # Remove Domain Analyser cached results + $DomainsTable = Get-CippTable -tablename 'Domains' + $Filter = "PartitionKey eq 'TenantDomains'" + $ClearDomainAnalyserRows = Get-CIPPAzDataTableEntity @DomainsTable -Filter $Filter | ForEach-Object { + $_.DomainAnalyser = '' + $_ + } + Update-AzDataTableEntity @DomainsTable -Entity $ClearDomainAnalyserRows + #Clear BPA + $BPATable = Get-CippTable -tablename 'cachebpa' + $ClearBPARows = Get-CIPPAzDataTableEntity @BPATable + Remove-AzDataTableEntity @BPATable -Entity $ClearBPARows + $ENV:SetFromProfile = $null + $Script:SkipListCache = $Null + $Script:SkipListCacheEmpty = $Null + $Script:IncludedTenantsCache = $Null + } +} diff --git a/Modules/CIPPCore/Public/GraphHelper/Write-LogMessage.ps1 b/Modules/CIPPCore/Public/GraphHelper/Write-LogMessage.ps1 new file mode 100644 index 000000000000..2c5ea7d00ba7 --- /dev/null +++ b/Modules/CIPPCore/Public/GraphHelper/Write-LogMessage.ps1 @@ -0,0 +1,35 @@ +function Write-LogMessage ($message, $tenant = 'None', $API = 'None', $tenantId = $null, $user, $sev) { + try { + $username = ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($user)) | ConvertFrom-Json).userDetails + } catch { + $username = $user + } + + $Table = Get-CIPPTable -tablename CippLogs + + if (!$tenant) { $tenant = 'None' } + if (!$username) { $username = 'CIPP' } + if ($sev -eq 'Debug' -and $env:DebugMode -ne 'true') { + Write-Information 'Not writing to log file - Debug mode is not enabled.' + return + } + $PartitionKey = (Get-Date -UFormat '%Y%m%d').ToString() + $TableRow = @{ + 'Tenant' = [string]$tenant + 'API' = [string]$API + 'Message' = [string]$message + 'Username' = [string]$username + 'Severity' = [string]$sev + 'SentAsAlert' = $false + 'PartitionKey' = $PartitionKey + 'RowKey' = ([guid]::NewGuid()).ToString() + } + + + if ($tenantId) { + $TableRow.Add('TenantID', [string]$tenantId) + } + + $Table.Entity = $TableRow + Add-CIPPAzDataTableEntity @Table | Out-Null +} \ No newline at end of file diff --git a/Modules/CIPPCore/Public/GraphRequests/Get-GraphRequestList.ps1 b/Modules/CIPPCore/Public/GraphRequests/Get-GraphRequestList.ps1 index c93ebbb06c80..3b3b4660a0bf 100644 --- a/Modules/CIPPCore/Public/GraphRequests/Get-GraphRequestList.ps1 +++ b/Modules/CIPPCore/Public/GraphRequests/Get-GraphRequestList.ps1 @@ -117,7 +117,10 @@ function Get-GraphRequestList { 'AllTenants' { if ($SkipCache) { Get-Tenants -IncludeErrors | ForEach-Object -Parallel { - Import-Module .\GraphHelper.psm1 + Import-Module '.\Modules\AzBobbyTables' + Import-Module '.\Modules\CIPPCore' + + $GraphRequestParams = @{ TenantFilter = $_.defaultDomainName Endpoint = $using:Endpoint diff --git a/Modules/CIPPCore/Public/Invoke-CIPPGraphWebhookProcessing.ps1 b/Modules/CIPPCore/Public/Invoke-CIPPGraphWebhookProcessing.ps1 new file mode 100644 index 000000000000..d147b1ca0989 --- /dev/null +++ b/Modules/CIPPCore/Public/Invoke-CIPPGraphWebhookProcessing.ps1 @@ -0,0 +1,23 @@ +function Invoke-CippGraphWebhookProcessing { + [CmdletBinding()] + param ( + $Data, + $CIPPID, + $WebhookInfo + ) + + $Table = Get-CIPPTable -TableName Extensionsconfig + + $Configuration = ((Get-AzDataTableEntity @Table).config | ConvertFrom-Json) + + Switch ($WebhookInfo.Resource) { + 'devices' { + # NinjaOne Extension + if ($Configuration.NinjaOne.Enabled -eq $True) { + Invoke-NinjaOneDeviceWebhook -Data $Data -Configuration $Configuration.NinjaOne + } + } + } + + + } diff --git a/Modules/CIPPCore/Public/Invoke-CIPPGraphWebhookRenewal.ps1 b/Modules/CIPPCore/Public/Invoke-CIPPGraphWebhookRenewal.ps1 new file mode 100644 index 000000000000..ab2686655b39 --- /dev/null +++ b/Modules/CIPPCore/Public/Invoke-CIPPGraphWebhookRenewal.ps1 @@ -0,0 +1,23 @@ +function Invoke-CippGraphWebhookRenewal { + $RenewalDate = (Get-Date).AddDays(1).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffZ") + $body = @{ + "expirationDateTime" = "$RenewalDate" + } | ConvertTo-Json + + + $WebhookTable = Get-CIPPTable -TableName webhookTable + $WebhookData = Get-AzDataTableEntity @WebhookTable | Where-Object { $null -ne $_.SubscriptionID -and $_.SubscriptionID -ne '' -and ((Get-Date($_.Expiration)) -le ((Get-Date).AddHours(2))) } + + foreach ($UpdateSub in $WebhookData) { + try { + $TenantFilter = $UpdateSub.PartitionKey + $null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/subscriptions/$($UpdateSub.SubscriptionID)" -tenantid $TenantFilter -type PATCH -body $body -Verbose + $UpdateSub.Expiration = $RenewalDate + $null = Add-AzDataTableEntity @WebhookTable -Entity $UpdateSub -Force + Write-LogMessage -user 'CIPP' -API 'Renew_Graph_Subscriptions' -message "Renewed Subscription:$($UpdateSub.SubscriptionID)" -Sev "Info" -tenant $TenantFilter + + } catch { + Write-LogMessage -user 'CIPP' -API 'Renew_Graph_Subscriptions' -message "Failed to renew Webhook Subscription: $($UpdateSub.SubscriptionID)" -Sev "Error" -tenant $TenantFilter + } + } +} diff --git a/Modules/CIPPCore/Public/Invoke-CIPPOffboardingJob.ps1 b/Modules/CIPPCore/Public/Invoke-CIPPOffboardingJob.ps1 index 4232a71adaf4..7da2b800b3c9 100644 --- a/Modules/CIPPCore/Public/Invoke-CIPPOffboardingJob.ps1 +++ b/Modules/CIPPCore/Public/Invoke-CIPPOffboardingJob.ps1 @@ -14,8 +14,8 @@ function Invoke-CIPPOffboardingJob { } $userid = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($username)" -tenantid $Tenantfilter).id $Return = switch ($Options) { - { $_."ConvertToShared" -eq 'true' } { - Set-CIPPMailboxType -ExecutingUser $ExecutingUser -tenantFilter $tenantFilter -userid $username -username $username -MailboxType "Shared" -APIName $APIName + { $_.'ConvertToShared' -eq 'true' } { + Set-CIPPMailboxType -ExecutingUser $ExecutingUser -tenantFilter $tenantFilter -userid $username -username $username -MailboxType 'Shared' -APIName $APIName } { $_.RevokeSessions -eq 'true' } { Revoke-CIPPSessions -tenantFilter $tenantFilter -username $username -userid $userid -ExecutingUser $ExecutingUser -APIName $APIName @@ -27,57 +27,56 @@ function Invoke-CIPPOffboardingJob { Remove-CIPPGroups -userid $userid -tenantFilter $Tenantfilter -ExecutingUser $ExecutingUser -APIName $APIName -Username "$Username" } - { $_."HideFromGAL" -eq 'true' } { + { $_.'HideFromGAL' -eq 'true' } { Set-CIPPHideFromGAL -tenantFilter $tenantFilter -userid $username -HideFromGAL $true -ExecutingUser $ExecutingUser -APIName $APIName } - { $_."DisableSignIn" -eq 'true' } { + { $_.'DisableSignIn' -eq 'true' } { Set-CIPPSignInState -TenantFilter $tenantFilter -userid $username -AccountEnabled $false -ExecutingUser $ExecutingUser -APIName $APIName } - { $_."OnedriveAccess" -ne "" } { + { $_.'OnedriveAccess' -ne '' } { $Options.OnedriveAccess | ForEach-Object { Set-CIPPOnedriveAccess -tenantFilter $tenantFilter -userid $username -OnedriveAccessUser $_.value -ExecutingUser $ExecutingUser -APIName $APIName } } - { $_."AccessNoAutomap" -ne "" } { - $Options.AccessNoAutomap | ForEach-Object { Set-CIPPMailboxAccess -tenantFilter $tenantFilter -userid $username -AccessUser $_.value -Automap $false -AccessRights @("FullAccess") -ExecutingUser $ExecutingUser -APIName $APIName } + { $_.'AccessNoAutomap' -ne '' } { + $Options.AccessNoAutomap | ForEach-Object { Set-CIPPMailboxAccess -tenantFilter $tenantFilter -userid $username -AccessUser $_.value -Automap $false -AccessRights @('FullAccess') -ExecutingUser $ExecutingUser -APIName $APIName } } - { $_."AccessAutomap" -ne "" } { - $Options.AccessAutomap | ForEach-Object { Set-CIPPMailboxAccess -tenantFilter $tenantFilter -userid $username -AccessUser $_.value -Automap $true -AccessRights @("FullAccess") -ExecutingUser $ExecutingUser -APIName $APIName } + { $_.'AccessAutomap' -ne '' } { + $Options.AccessAutomap | ForEach-Object { Set-CIPPMailboxAccess -tenantFilter $tenantFilter -userid $username -AccessUser $_.value -Automap $true -AccessRights @('FullAccess') -ExecutingUser $ExecutingUser -APIName $APIName } } - { $_."OOO" -ne "" } { - Set-CIPPOutOfOffice -tenantFilter $tenantFilter -userid $username -InternalMessage $Options.OOO -ExternalMessage $Options.OOO -ExecutingUser $ExecutingUser -APIName $APIName -state "Enabled" + { $_.'OOO' -ne '' } { + Set-CIPPOutOfOffice -tenantFilter $tenantFilter -userid $username -InternalMessage $Options.OOO -ExternalMessage $Options.OOO -ExecutingUser $ExecutingUser -APIName $APIName -state 'Enabled' } - { $_."forward" -ne "" } { + { $_.'forward' -ne '' } { Set-CIPPForwarding -userid $userid -username $username -tenantFilter $Tenantfilter -Forward $Options.forward -KeepCopy [bool]$Options.keepCopy -ExecutingUser $ExecutingUser -APIName $APIName } - { $_."RemoveLicenses" -eq 'true' } { + { $_.'RemoveLicenses' -eq 'true' } { Remove-CIPPLicense -userid $userid -username $Username -tenantFilter $Tenantfilter -ExecutingUser $ExecutingUser -APIName $APIName } - { $_."Deleteuser" -eq 'true' } { + { $_.'Deleteuser' -eq 'true' } { Remove-CIPPUser -userid $userid -username $Username -tenantFilter $Tenantfilter -ExecutingUser $ExecutingUser -APIName $APIName } - { $_."RemoveRules" -eq 'true' } { + { $_.'RemoveRules' -eq 'true' } { Remove-CIPPRules -userid $userid -username $Username -tenantFilter $Tenantfilter -ExecutingUser $ExecutingUser -APIName $APIName } - { $_."RemoveMobile" -eq 'true' } { + { $_.'RemoveMobile' -eq 'true' } { Remove-CIPPMobileDevice -userid $userid -username $Username -tenantFilter $Tenantfilter -ExecutingUser $ExecutingUser -APIName $APIName } - { $_."RemovePermissions" } { + { $_.'RemovePermissions' } { if ($RunScheduled) { - Remove-CIPPMailboxPermissions -PermissionsLevel @("FullAccess", "SendAs", "SendOnBehalf") -userid "AllUsers" -AccessUser $UserName -TenantFilter $TenantFilter -APIName $APINAME -ExecutingUser $ExecutingUser + Remove-CIPPMailboxPermissions -PermissionsLevel @('FullAccess', 'SendAs', 'SendOnBehalf') -userid 'AllUsers' -AccessUser $UserName -TenantFilter $TenantFilter -APIName $APINAME -ExecutingUser $ExecutingUser - } - else { + } else { $object = [PSCustomObject]@{ TenantFilter = $tenantFilter User = $username executingUser = $ExecutingUser } - Push-OutputBinding -Name Msg -Value $object + Push-OutputBinding -Name offboardingmailbox -Value $object "Removal of permissions queued. This task will run in the background and send it's results to the logbook." } } diff --git a/Modules/CIPPCore/Public/Invoke-RemoveAPDevice.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveAPDevice.ps1 new file mode 100644 index 000000000000..8639d495321d --- /dev/null +++ b/Modules/CIPPCore/Public/Invoke-RemoveAPDevice.ps1 @@ -0,0 +1,41 @@ +using namespace System.Net + +Function Invoke-RemoveAPDevice { + <# + .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' + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + $Deviceid = $Request.Query.ID + + try { + if ($TenantFilter -eq $null -or $TenantFilter -eq 'null') { + $GraphRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/windowsAutopilotDeviceIdentities/$Deviceid" -type DELETE + } else { + $GraphRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/windowsAutopilotDeviceIdentities/$Deviceid" -tenantid $TenantFilter -type DELETE + } + Write-LogMessage -user $request.headers.'x-ms-client-principal' -tenant $TenantFilter -API $APINAME -message "Deleted autopilot device $Deviceid" -Sev 'Info' + $body = [pscustomobject]@{'Results' = 'Successfully deleted the autopilot device' } + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -tenant $TenantFilter -API $APINAME -message "Autopilot Delete API failed for $deviceid. The error is: $($_.Exception.Message)" -Sev 'Error' + $body = [pscustomobject]@{'Results' = "Failed to delete device: $($_.Exception.Message)" } + } + #force a sync, this can give "too many requests" if deleleting a bunch of devices though. + $GraphRequest = New-GraphPOSTRequest -uri 'https://graph.microsoft.com/beta/deviceManagement/windowsAutopilotSettings/sync' -tenantid $TenantFilter -type POST -body '{}' + + # 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/Invoke-RemoveApp.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveApp.ps1 new file mode 100644 index 000000000000..f0ca41db08a0 --- /dev/null +++ b/Modules/CIPPCore/Public/Invoke-RemoveApp.ps1 @@ -0,0 +1,36 @@ +using namespace System.Net + +Function Invoke-RemoveApp { + <# + .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' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + $policyId = $Request.Query.ID + if (!$policyId) { exit } + try { + #$unAssignRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/deviceManagement/configurationPolicies('$($policyId)')/assign" -type POST -Body '{"assignments":[]}' -tenant $TenantFilter + $GraphRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/deviceAppManagement/mobileApps/$($policyId)" -type DELETE -tenant $TenantFilter + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Deleted $policyId" -Sev 'Info' -tenant $TenantFilter + $body = [pscustomobject]@{'Results' = 'Successfully deleted the application' } + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Could not delete app $policyId. $($_.Exception.Message)" -Sev 'Error' -tenant $TenantFilter + $body = [pscustomobject]@{'Results' = "Could not delete this application: $($_.Exception.Message)" } + + } + + # 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/Invoke-RemoveCAPolicy.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveCAPolicy.ps1 new file mode 100644 index 000000000000..8cef68c26155 --- /dev/null +++ b/Modules/CIPPCore/Public/Invoke-RemoveCAPolicy.ps1 @@ -0,0 +1,35 @@ +using namespace System.Net + +Function Invoke-RemoveCAPolicy { + <# + .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' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + $policyId = $Request.Query.GUID + if (!$policyId) { exit } + try { + $GraphRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies/$($policyId)" -type DELETE -tenant $TenantFilter + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Deleted CA Policy $policyId" -Sev 'Info' -tenant $TenantFilter + $body = [pscustomobject]@{'Results' = 'Successfully deleted the policy' } + + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Could not delete CA policy $policyId. $($_.Exception.Message)" -Sev 'Error' -tenant $TenantFilter + $body = [pscustomobject]@{'Results' = "Could not delete policy: $($_.Exception.Message)" } + + } + + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $body + }) + + +} diff --git a/Modules/CIPPCore/Public/Invoke-RemoveCATemplate.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveCATemplate.ps1 new file mode 100644 index 000000000000..318184576061 --- /dev/null +++ b/Modules/CIPPCore/Public/Invoke-RemoveCATemplate.ps1 @@ -0,0 +1,36 @@ +using namespace System.Net + +Function Invoke-RemoveCATemplate { + <# + .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' + + $ID = $request.query.id + try { + $Table = Get-CippTable -tablename 'templates' + + $Filter = "PartitionKey eq 'CATemplate' and RowKey eq '$id'" + $ClearRow = Get-CIPPAzDataTableEntity @Table -Filter $Filter -Property PartitionKey, RowKey + Remove-AzDataTableEntity @Table -Entity $clearRow + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Removed Conditional Access Template with ID $ID." -Sev 'Info' + $body = [pscustomobject]@{'Results' = 'Successfully removed Conditional Access Template' } + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to remove Conditional Access template $ID. $($_.Exception.Message)" -Sev 'Error' + $body = [pscustomobject]@{'Results' = "Failed to remove template: $($_.Exception.Message)" } + } + + + # 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/Invoke-RemoveContact.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveContact.ps1 new file mode 100644 index 000000000000..c4a47e9b182a --- /dev/null +++ b/Modules/CIPPCore/Public/Invoke-RemoveContact.ps1 @@ -0,0 +1,36 @@ +using namespace System.Net + +Function Invoke-RemoveContact { + <# + .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' + $Tenantfilter = $request.Query.tenantfilter + + + $Params = @{ + Identity = $request.query.guid + } + + try { + $Params = @{ Identity = $request.query.GUID } + + $GraphRequest = New-ExoRequest -tenantid $Tenantfilter -cmdlet 'Remove-MailContact' -cmdParams $params -UseSystemMailbox $true + $Result = "Deleted $($Request.query.guid)" + Write-LogMessage -API 'TransportRules' -tenant $tenantfilter -message "Deleted contact $($Request.query.guid)" -sev Debug + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception + $Result = $ErrorMessage + } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @{Results = $Result } + }) + +} diff --git a/Modules/CIPPCore/Public/Invoke-RemoveExConnector.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveExConnector.ps1 new file mode 100644 index 000000000000..09c474712e18 --- /dev/null +++ b/Modules/CIPPCore/Public/Invoke-RemoveExConnector.ps1 @@ -0,0 +1,36 @@ +using namespace System.Net + +Function Invoke-RemoveExConnector { + <# + .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' + $Tenantfilter = $request.Query.tenantfilter + + + $Params = @{ + Identity = $request.query.guid + } + + try { + $Params = @{ Identity = $request.query.GUID } + + $GraphRequest = New-ExoRequest -tenantid $Tenantfilter -cmdlet "Remove-$($Request.query.Type)Connector" -cmdParams $params + $Result = "Deleted $($Request.query.guid)" + Write-LogMessage -API 'TransportRules' -tenant $tenantfilter -message "Deleted transport rule $($Request.query.guid)" -sev Debug + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception + $Result = $ErrorMessage + } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @{Results = $Result } + }) + +} diff --git a/Modules/CIPPCore/Public/Invoke-RemoveExConnectorTemplate.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveExConnectorTemplate.ps1 new file mode 100644 index 000000000000..3e78057683d9 --- /dev/null +++ b/Modules/CIPPCore/Public/Invoke-RemoveExConnectorTemplate.ps1 @@ -0,0 +1,35 @@ +using namespace System.Net + +Function Invoke-RemoveExConnectorTemplate { + <# + .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' + + $ID = $request.query.id + try { + $Table = Get-CippTable -tablename 'templates' + $Filter = "PartitionKey eq 'ExConnectorTemplate' and RowKey eq '$id'" + $ClearRow = Get-CIPPAzDataTableEntity @Table -Filter $Filter -Property PartitionKey, RowKey + Remove-AzDataTableEntity @Table -Entity $clearRow + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Removed Exchange Connector Template with ID $ID." -Sev 'Info' + $body = [pscustomobject]@{'Results' = 'Successfully removed Exchange Connector Template' } + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to remove Exchange Connector Template $ID. $($_.Exception.Message)" -Sev 'Error' + $body = [pscustomobject]@{'Results' = "Failed to remove template: $($_.Exception.Message)" } + } + + + # 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/Invoke-RemoveGroupTemplate.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveGroupTemplate.ps1 new file mode 100644 index 000000000000..2efd9d639307 --- /dev/null +++ b/Modules/CIPPCore/Public/Invoke-RemoveGroupTemplate.ps1 @@ -0,0 +1,38 @@ +using namespace System.Net + +Function Invoke-RemoveGroupTemplate { + <# + .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' + + $ID = $request.query.id + try { + $Table = Get-CippTable -tablename 'templates' + Write-Host $id + + $Filter = "PartitionKey eq 'GroupTemplate' and RowKey eq '$id'" + Write-Host $Filter + $ClearRow = Get-CIPPAzDataTableEntity @Table -Filter $Filter -Property PartitionKey, RowKey + Remove-AzDataTableEntity @Table -Entity $clearRow + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Removed Intune Template with ID $ID." -Sev 'Info' + $body = [pscustomobject]@{'Results' = 'Successfully removed Template' } + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to remove intune template $ID. $($_.Exception.Message)" -Sev 'Error' + $body = [pscustomobject]@{'Results' = "Failed to remove template: $($_.Exception.Message)" } + } + + + # 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/Invoke-RemoveIntuneTemplate.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveIntuneTemplate.ps1 new file mode 100644 index 000000000000..4575cf0fe57a --- /dev/null +++ b/Modules/CIPPCore/Public/Invoke-RemoveIntuneTemplate.ps1 @@ -0,0 +1,38 @@ +using namespace System.Net + +Function Invoke-RemoveIntuneTemplate { + <# + .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' + + $ID = $request.query.id + try { + $Table = Get-CippTable -tablename 'templates' + Write-Host $id + + $Filter = "PartitionKey eq 'IntuneTemplate' and RowKey eq '$id'" + Write-Host $Filter + $ClearRow = Get-CIPPAzDataTableEntity @Table -Filter $Filter -Property PartitionKey, RowKey + Remove-AzDataTableEntity @Table -Entity $clearRow + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Removed Intune Template with ID $ID." -Sev 'Info' + $body = [pscustomobject]@{'Results' = 'Successfully removed Intune Template' } + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to remove intune template $ID. $($_.Exception.Message)" -Sev 'Error' + $body = [pscustomobject]@{'Results' = "Failed to remove template: $($_.Exception.Message)" } + } + + + # 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/Invoke-RemovePolicy.ps1 b/Modules/CIPPCore/Public/Invoke-RemovePolicy.ps1 new file mode 100644 index 000000000000..58cc90823d16 --- /dev/null +++ b/Modules/CIPPCore/Public/Invoke-RemovePolicy.ps1 @@ -0,0 +1,38 @@ +using namespace System.Net + +Function Invoke-RemovePolicy { + <# + .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' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + $policyId = $Request.Query.ID + if (!$policyId) { exit } + try { + + #$unAssignRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/deviceManagement/configurationPolicies('$($policyId)')/assign" -type POST -Body '{"assignments":[]}' -tenant $TenantFilter + $GraphRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$($Request.Query.URLName)('$($policyId)')" -type DELETE -tenant $TenantFilter + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Deleted $policyId" -Sev 'Info' -tenant $TenantFilter + $body = [pscustomobject]@{'Results' = 'Successfully deleted the policy' } + + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Could not delete policy $policyId. $($_.Exception.Message)" -Sev 'Error' -tenant $TenantFilter + $body = [pscustomobject]@{'Results' = "Could not delete policy: $($_.Exception.Message)" } + + } + + # 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/Invoke-RemoveQueuedAlert.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveQueuedAlert.ps1 new file mode 100644 index 000000000000..d69ed68c84e0 --- /dev/null +++ b/Modules/CIPPCore/Public/Invoke-RemoveQueuedAlert.ps1 @@ -0,0 +1,33 @@ +using namespace System.Net + +Function Invoke-RemoveQueuedAlert { + <# + .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' + $Table = Get-CIPPTable -TableName 'SchedulerConfig' + $ID = $request.query.id + try { + $Filter = "RowKey eq '{0}' and PartitionKey eq 'Alert'" -f $ID + $Alert = Get-CIPPAzDataTableEntity @Table -Filter $Filter -Property PartitionKey, RowKey + Remove-AzDataTableEntity @Table -Entity $Alert + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Removed application queue for $ID." -Sev 'Info' + $body = [pscustomobject]@{'Results' = 'Successfully removed from queue.' } + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to remove from queue $ID. $($_.Exception.Message)" -Sev 'Error' + $body = [pscustomobject]@{'Results' = "Failed to remove alert from queue $($_.Exception.Message)" } + } + + # 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/Invoke-RemoveQueuedApp.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveQueuedApp.ps1 new file mode 100644 index 000000000000..add290577208 --- /dev/null +++ b/Modules/CIPPCore/Public/Invoke-RemoveQueuedApp.ps1 @@ -0,0 +1,35 @@ +using namespace System.Net + +Function Invoke-RemoveQueuedApp { + <# + .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' + + $ID = $request.query.id + try { + $Table = Get-CippTable -tablename 'apps' + $Filter = "PartitionKey eq 'apps' and RowKey eq '$id'" + $ClearRow = Get-CIPPAzDataTableEntity @Table -Filter $Filter -Property PartitionKey, RowKey + Remove-AzDataTableEntity @Table -Entity $clearRow + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Removed application queue for $ID." -Sev 'Info' + $body = [pscustomobject]@{'Results' = 'Successfully removed from queue.' } + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to remove application queue for $ID. $($_.Exception.Message)" -Sev 'Error' + $body = [pscustomobject]@{'Results' = 'Failed to remove standard)' } + } + + + # 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/Invoke-RemoveScheduledItem.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveScheduledItem.ps1 new file mode 100644 index 000000000000..8c5a00f3a086 --- /dev/null +++ b/Modules/CIPPCore/Public/Invoke-RemoveScheduledItem.ps1 @@ -0,0 +1,28 @@ +using namespace System.Net + +Function Invoke-RemoveScheduledItem { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $task = @{ + RowKey = $Request.Query.ID + PartitionKey = 'ScheduledTask' + } + $Table = Get-CIPPTable -TableName 'ScheduledTasks' + Remove-AzDataTableEntity @Table -Entity $task + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @{ Results = 'Task removed successfully.' } + }) + $Table = Get-CIPPTable -TableName 'ScheduledTasks' + Remove-AzDataTableEntity @Table -Entity $task + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @{ Results = 'Task removed successfully.' } + }) + +} diff --git a/Modules/CIPPCore/Public/Invoke-RemoveSpamfilter.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveSpamfilter.ps1 new file mode 100644 index 000000000000..e962aab4a7a4 --- /dev/null +++ b/Modules/CIPPCore/Public/Invoke-RemoveSpamfilter.ps1 @@ -0,0 +1,37 @@ +using namespace System.Net + +Function Invoke-RemoveSpamfilter { + <# + .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' + $Tenantfilter = $request.Query.tenantfilter + + + $Params = @{ + Identity = $request.query.name + } + + try { + $cmdlet = 'Remove-HostedContentFilterRule' + $GraphRequest = New-ExoRequest -tenantid $Tenantfilter -cmdlet $cmdlet -cmdParams $params + $cmdlet = 'Remove-HostedContentFilterPolicy' + $GraphRequest = New-ExoRequest -tenantid $Tenantfilter -cmdlet $cmdlet -cmdParams $params + $Result = "Deleted $($Request.query.name)" + Write-LogMessage -API 'TransportRules' -tenant $tenantfilter -message "Deleted transport rule $($Request.query.name)" -sev Debug + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception + $Result = $ErrorMessage + } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @{Results = $Result } + }) + +} diff --git a/Modules/CIPPCore/Public/Invoke-RemoveSpamfilterTemplate.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveSpamfilterTemplate.ps1 new file mode 100644 index 000000000000..8008d3b11a18 --- /dev/null +++ b/Modules/CIPPCore/Public/Invoke-RemoveSpamfilterTemplate.ps1 @@ -0,0 +1,35 @@ +using namespace System.Net + +Function Invoke-RemoveSpamfilterTemplate { + <# + .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' + + $ID = $request.query.id + try { + $Table = Get-CippTable -tablename 'templates' + $Filter = "PartitionKey eq 'SpamfilterTemplate' and RowKey eq '$id'" + $ClearRow = Get-CIPPAzDataTableEntity @Table -Filter $Filter -Property PartitionKey, RowKey + Remove-AzDataTableEntity @Table -Entity $clearRow + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Removed Transport Rule Template with ID $ID." -Sev 'Info' + $body = [pscustomobject]@{'Results' = 'Successfully removed Transport Rule Template' } + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to remove Transport Rule template $ID. $($_.Exception.Message)" -Sev 'Error' + $body = [pscustomobject]@{'Results' = "Failed to remove template: $($_.Exception.Message)" } + } + + + # 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/Invoke-RemoveStandard.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveStandard.ps1 new file mode 100644 index 000000000000..d3898d337a73 --- /dev/null +++ b/Modules/CIPPCore/Public/Invoke-RemoveStandard.ps1 @@ -0,0 +1,37 @@ +using namespace System.Net + +Function Invoke-RemoveStandard { + <# + .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' + + $ID = $request.query.id + try { + $Table = Get-CippTable -tablename 'standards' + $Filter = "PartitionKey eq 'standards' and RowKey eq '$id'" + $ClearRow = Get-CIPPAzDataTableEntity @Table -Filter $Filter -Property PartitionKey, RowKey + Remove-AzDataTableEntity @Table -Entity $clearRow + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Removed standards for $ID." -Sev 'Info' + $body = [pscustomobject]@{'Results' = 'Successfully removed standards deployment' } + + + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to remove standard for $ID. $($_.Exception.Message)" -Sev 'Error' + $body = [pscustomobject]@{'Results' = 'Failed to remove standard)' } + } + + + # 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/Invoke-RemoveTransportRule.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveTransportRule.ps1 new file mode 100644 index 000000000000..b340f331903f --- /dev/null +++ b/Modules/CIPPCore/Public/Invoke-RemoveTransportRule.ps1 @@ -0,0 +1,35 @@ +using namespace System.Net + +Function Invoke-RemoveTransportRule { + <# + .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' + $Tenantfilter = $request.Query.tenantfilter + + + $Params = @{ + Identity = $request.query.guid + } + + try { + $cmdlet = 'Remove-TransportRule' + $GraphRequest = New-ExoRequest -tenantid $Tenantfilter -cmdlet $cmdlet -cmdParams $params -UseSystemMailbox $true + $Result = "Deleted $($Request.query.guid)" + Write-LogMessage -API 'TransportRules' -tenant $tenantfilter -message "Deleted transport rule $($Request.query.guid)" -sev Debug + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception + $Result = $ErrorMessage + } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @{Results = $Result } + }) + +} diff --git a/Modules/CIPPCore/Public/Invoke-RemoveTransportRuleTemplate.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveTransportRuleTemplate.ps1 new file mode 100644 index 000000000000..952796e819d8 --- /dev/null +++ b/Modules/CIPPCore/Public/Invoke-RemoveTransportRuleTemplate.ps1 @@ -0,0 +1,35 @@ +using namespace System.Net + +Function Invoke-RemoveTransportRuleTemplate { + <# + .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' + + $ID = $request.query.id + try { + $Table = Get-CippTable -tablename 'templates' + $Filter = "PartitionKey eq 'TransportTemplate' and RowKey eq '$id'" + $ClearRow = Get-CIPPAzDataTableEntity @Table -Filter $Filter -Property PartitionKey, RowKey + Remove-AzDataTableEntity @Table -Entity $clearRow + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Removed Transport Rule Template with ID $ID." -Sev 'Info' + $body = [pscustomobject]@{'Results' = 'Successfully removed Transport Rule Template' } + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to remove Transport Rule template $ID. $($_.Exception.Message)" -Sev 'Error' + $body = [pscustomobject]@{'Results' = "Failed to remove template: $($_.Exception.Message)" } + } + + + # 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/Invoke-RemoveUser.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveUser.ps1 new file mode 100644 index 000000000000..386ab3e4be6b --- /dev/null +++ b/Modules/CIPPCore/Public/Invoke-RemoveUser.ps1 @@ -0,0 +1,36 @@ +using namespace System.Net + +Function Invoke-RemoveUser { + <# + .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' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + $userid = $Request.Query.ID + if (!$userid) { exit } + try { + $GraphRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($userid)" -type DELETE -tenant $TenantFilter + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Deleted $userid" -Sev 'Info' -tenant $TenantFilter + $body = [pscustomobject]@{'Results' = 'Successfully deleted the user.' } + + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Could not delete user $userid. $($_.Exception.Message)" -Sev 'Error' -tenant $TenantFilter + $body = [pscustomobject]@{'Results' = "Could not delete user: $($_.Exception.Message)" } + + } + + # 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/Invoke-RemoveWebhookAlert.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveWebhookAlert.ps1 new file mode 100644 index 000000000000..e54f283123de --- /dev/null +++ b/Modules/CIPPCore/Public/Invoke-RemoveWebhookAlert.ps1 @@ -0,0 +1,30 @@ +using namespace System.Net + +Function Invoke-RemoveWebhookAlert { + <# + .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' + + try { + $Results = Remove-CIPPGraphSubscription -TenantFilter $Request.query.TenantFilter -CIPPID $Request.query.CIPPID + $body = [pscustomobject]@{'Results' = $Results } + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to remove webhook alert. $($_.Exception.Message)" -Sev 'Error' + $body = [pscustomobject]@{'Results' = "Failed to remove webhook alert: $($_.Exception.Message)" } + } + + + # 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/New-CIPPGraphSubscription.ps1 b/Modules/CIPPCore/Public/New-CIPPGraphSubscription.ps1 index 795b99355ab3..18a58945002e 100644 --- a/Modules/CIPPCore/Public/New-CIPPGraphSubscription.ps1 +++ b/Modules/CIPPCore/Public/New-CIPPGraphSubscription.ps1 @@ -13,13 +13,6 @@ function New-CIPPGraphSubscription { $ExecutingUser ) $CIPPID = (New-Guid).GUID - $expiredate = (Get-Date).AddDays(1).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffZ") - $params = @{ - changeType = $TypeofSubscription - notificationUrl = "$BaseURL/API/PublicWebhooks?EventType=$EventType&CIPPID=$CIPPID" - resource = $Resource - expirationDateTime = $expiredate - } | ConvertTo-Json $WebhookTable = Get-CIPPTable -TableName webhookTable try { @@ -41,31 +34,46 @@ function New-CIPPGraphSubscription { Expiration = "None" WebhookNotificationUrl = [string]$Auditlog.webhook.address } + $null = Add-CIPPAzDataTableEntity @WebhookTable -Entity $WebhookRow - } - else { - $GraphRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/subscriptions" -tenantid $TenantFilter -type POST -body $params -verbose - #If creation is succesfull, we store the GUID in the storage table webhookTable to make sure we can check against this later on. - #We store the GUID as rowkey, the event type, the resource, and the expiration date as properties, we also add the Tenant name so we can easily find this later on. - #We don't store the return, because Ms decided that a renewal or re-authenticate does not change the url, but does change the id... - $WebhookRow = @{ - PartitionKey = [string]$TenantFilter - RowKey = [string]$CIPPID - EventType = [string]$EventType - Resource = [string]$Resource - Expiration = [string]$expiredate - Operations = [string]$operations - AllowedLocations = [string]$AllowedLocations - WebhookNotificationUrl = [string]$GraphRequest.notificationUrl + + } else { + # First check if there is an exsiting Webhook in place + $WebhookFilter = "PartitionKey eq '$($TenantFilter)'" + $ExistingWebhooks = Get-CIPPAzDataTableEntity @WebhookTable -Filter $WebhookFilter + $MatchedWebhook = $ExistingWebhooks | Where-Object { $_.Resource -eq $Resource } + if (($MatchedWebhook | Measure-Object).count -eq 0) { + + $expiredate = (Get-Date).AddDays(1).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffZ") + $params = @{ + changeType = $TypeofSubscription + notificationUrl = "https://$BaseURL/API/PublicWebhooks?EventType=$EventType&CIPPID=$($CIPPID)&Type=GraphSubscription" + resource = $Resource + expirationDateTime = $expiredate + } | ConvertTo-Json + + + $GraphRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/subscriptions" -tenantid $TenantFilter -type POST -body $params -verbose + #If creation is succesfull, we store the GUID in the storage table webhookTable to make sure we can check against this later on. + #We store the GUID as rowkey, the event type, the resource, and the expiration date as properties, we also add the Tenant name so we can easily find this later on. + #We don't store the return, because Ms decided that a renewal or re-authenticate does not change the url, but does change the id... + $WebhookRow = @{ + PartitionKey = [string]$TenantFilter + RowKey = [string]$CIPPID + EventType = [string]$EventType + Resource = [string]$Resource + Expiration = [string]$expiredate + SubscriptionID = [string]$GraphRequest.id + WebhookNotificationUrl = [string]$GraphRequest.notificationUrl + } + $null = Add-CIPPAzDataTableEntity @WebhookTable -Entity $WebhookRow + #todo: add remove webhook function, add check webhook function, add list webhooks function + #add refresh webhook function based on table. } - $null = Add-CIPPAzDataTableEntity @WebhookTable -Entity $WebhookRow - #todo: add remove webhook function, add check webhook function, add list webhooks function - #add refresh webhook function based on table. } Write-LogMessage -user $ExecutingUser -API $APIName -message "Created Webhook subscription for $($TenantFilter)" -Sev "Info" -tenant $TenantFilter return "Created Webhook subscription for $($TenantFilter)" - } - catch { + } catch { Write-LogMessage -user $ExecutingUser -API $APIName -message "Failed to create Webhook Subscription: $($_.Exception.Message)" -Sev "Error" -tenant $TenantFilter Return "Failed to create Webhook Subscription for $($TenantFilter): $($_.Exception.Message)" } diff --git a/Modules/CIPPCore/Public/Remove-CIPPGroups.ps1 b/Modules/CIPPCore/Public/Remove-CIPPGroups.ps1 index d94d71b2b611..aa9eeed5b90c 100644 --- a/Modules/CIPPCore/Public/Remove-CIPPGroups.ps1 +++ b/Modules/CIPPCore/Public/Remove-CIPPGroups.ps1 @@ -3,7 +3,7 @@ function Remove-CIPPGroups { param( $Username, $tenantFilter, - $APIName = "Remove From Groups", + $APIName = 'Remove From Groups', $ExecutingUser, $userid ) @@ -14,31 +14,28 @@ function Remove-CIPPGroups { $AllGroups = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/groups/?`$select=displayName,mailEnabled,id,groupTypes" -tenantid $tenantFilter) $Returnval = (New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($userid)/GetMemberGroups" -tenantid $tenantFilter -type POST -body '{"securityEnabledOnly": false}').value | ForEach-Object -Parallel { - Import-Module CIPPCore - Import-Module '.\GraphHelper.psm1' + Import-Module '.\Modules\AzBobbyTables' + Import-Module '.\Modules\CIPPCore' $group = $_ try { $Groupname = ($using:AllGroups | Where-Object -Property id -EQ $group).displayName $IsMailEnabled = ($using:AllGroups | Where-Object -Property id -EQ $group).mailEnabled - $IsM365Group = ($using:AllGroups | Where-Object { $_.id -eq $group -and $_.groupTypes -contains "Unified" }) -ne $null + $IsM365Group = ($using:AllGroups | Where-Object { $_.id -eq $group -and $_.groupTypes -contains 'Unified' }) -ne $null if ($IsM365Group) { $RemoveRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/groups/$_/members/$($using:userid)/`$ref" -tenantid $using:tenantFilter -type DELETE -body '' -Verbose - } - elseif (-not $IsMailEnabled) { + } elseif (-not $IsMailEnabled) { $RemoveRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/groups/$_/members/$($using:userid)/`$ref" -tenantid $using:tenantFilter -type DELETE -body '' -Verbose - } - elseif ($IsMailEnabled) { + } elseif ($IsMailEnabled) { $Params = @{ Identity = $Groupname; Member = $using:userid ; BypassSecurityGroupManagerCheck = $true } - New-ExoRequest -tenantid $using:tenantFilter -cmdlet "Remove-DistributionGroupMember" -cmdParams $params -UseSystemMailbox $true + New-ExoRequest -tenantid $using:tenantFilter -cmdlet 'Remove-DistributionGroupMember' -cmdParams $params -UseSystemMailbox $true } - Write-LogMessage -user $using:ExecutingUser -API $($using:APIName) -message "Removed $($using:Username) from $groupname" -Sev "Info" -tenant $using:TenantFilter + Write-LogMessage -user $using:ExecutingUser -API $($using:APIName) -message "Removed $($using:Username) from $groupname" -Sev 'Info' -tenant $using:TenantFilter "Successfully removed $($using:Username) from group $Groupname" - } - catch { - Write-LogMessage -user $using:ExecutingUser -API $($using:APIName) -message "Could not remove $($using:Username) from group $groupname" -Sev "Error" -tenant $using:TenantFilter + } catch { + Write-LogMessage -user $using:ExecutingUser -API $($using:APIName) -message "Could not remove $($using:Username) from group $groupname" -Sev 'Error' -tenant $using:TenantFilter "Could not remove $($using:Username) from group $($Groupname): $($_.Exception.Message). This is likely because its a Dynamic Group or synched with active directory" } } diff --git a/Modules/CIPPCore/Public/Remove-CIPPLicense.ps1 b/Modules/CIPPCore/Public/Remove-CIPPLicense.ps1 index 6caa7fe02eba..fea6f737657c 100644 --- a/Modules/CIPPCore/Public/Remove-CIPPLicense.ps1 +++ b/Modules/CIPPCore/Public/Remove-CIPPLicense.ps1 @@ -4,23 +4,21 @@ function Remove-CIPPLicense { $ExecutingUser, $userid, $username, - $APIName = "Remove License", + $APIName = 'Remove License', $TenantFilter ) - Set-Location (Get-Item $PSScriptRoot).FullName $ConvertTable = Import-Csv Conversiontable.csv try { $CurrentLicenses = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($userid)" -tenantid $tenantFilter).assignedlicenses.skuid $ConvertedLicense = $(($ConvertTable | Where-Object { $_.guid -in $CurrentLicenses }).'Product_Display_Name' | Sort-Object -Unique) -join ',' - $LicensesToRemove = if ($CurrentLicenses) { ConvertTo-Json @( $CurrentLicenses) } else { "[]" } + $LicensesToRemove = if ($CurrentLicenses) { ConvertTo-Json @( $CurrentLicenses) } else { '[]' } $LicenseBody = '{"addLicenses": [], "removeLicenses": ' + $LicensesToRemove + '}' $LicRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($userid)/assignlicense" -tenantid $tenantFilter -type POST -body $LicenseBody -verbose - Write-LogMessage -user $ExecutingUser -API $APIName -message "Removed license for $($username)" -Sev "Info" -tenant $TenantFilter + Write-LogMessage -user $ExecutingUser -API $APIName -message "Removed license for $($username)" -Sev 'Info' -tenant $TenantFilter Return "Removed current licenses: $ConvertedLicense" - } - catch { - Write-LogMessage -user $ExecutingUser -API $APIName -message "Could not remove license for $username" -Sev "Error" -tenant $TenantFilter + } catch { + Write-LogMessage -user $ExecutingUser -API $APIName -message "Could not remove license for $username" -Sev 'Error' -tenant $TenantFilter return "Could not remove license for $($username). Error: $($_.Exception.Message)" } } diff --git a/Modules/CIPPCore/Public/Remove-CIPPMailboxPermissions.ps1 b/Modules/CIPPCore/Public/Remove-CIPPMailboxPermissions.ps1 index c9e480445056..7035a083ff0f 100644 --- a/Modules/CIPPCore/Public/Remove-CIPPMailboxPermissions.ps1 +++ b/Modules/CIPPCore/Public/Remove-CIPPMailboxPermissions.ps1 @@ -5,42 +5,40 @@ function Remove-CIPPMailboxPermissions { $AccessUser, $TenantFilter, $PermissionsLevel, - $APIName = "Manage Shared Mailbox Access", + $APIName = 'Manage Shared Mailbox Access', $ExecutingUser ) try { - if ($userid -eq "AllUsers") { - $Mailboxes = New-ExoRequest -tenantid $TenantFilter -cmdlet "get-mailbox" + if ($userid -eq 'AllUsers') { + $Mailboxes = New-ExoRequest -tenantid $TenantFilter -cmdlet 'get-mailbox' $Mailboxes | ForEach-Object -Parallel { - Import-Module ".\Modules\CIPPCore" - import-module ".\GraphHelper.psm1" - Import-Module ".\Modules\AzBobbyTables" + Import-Module '.\Modules\AzBobbyTables' + Import-Module '.\Modules\CIPPCore' Write-Host "Removing permissions from mailbox $($_.UserPrincipalName)" - Remove-CIPPMailboxPermissions -PermissionsLevel @("FullAccess", "SendAs", "SendOnBehalf") -userid $_.UserPrincipalName -AccessUser $using:AccessUser -TenantFilter $using:TenantFilter -APIName $using:APINAME -ExecutingUser $using:ExecutingUser + Remove-CIPPMailboxPermissions -PermissionsLevel @('FullAccess', 'SendAs', 'SendOnBehalf') -userid $_.UserPrincipalName -AccessUser $using:AccessUser -TenantFilter $using:TenantFilter -APIName $using:APINAME -ExecutingUser $using:ExecutingUser } -ThrottleLimit 10 - } - else { + } else { $Results = $PermissionsLevel | ForEach-Object { switch ($_) { - "SendOnBehalf" { - $MailboxPerms = New-ExoRequest -Anchor $UserId -tenantid $Tenantfilter -cmdlet "Set-Mailbox" -cmdParams @{Identity = $userid; GrantSendonBehalfTo = @{'@odata.type' = '#Exchange.GenericHashTable'; remove = $AccessUser }; } - if ($MailboxPerms -notlike "*completed successfully but no settings of*") { - Write-LogMessage -user $ExecutingUser -API $APIName -message "Removed SendOnBehalf permissions for $($AccessUser) from $($userid)'s mailbox." -Sev "Info" -tenant $TenantFilter + 'SendOnBehalf' { + $MailboxPerms = New-ExoRequest -Anchor $UserId -tenantid $Tenantfilter -cmdlet 'Set-Mailbox' -cmdParams @{Identity = $userid; GrantSendonBehalfTo = @{'@odata.type' = '#Exchange.GenericHashTable'; remove = $AccessUser }; } + if ($MailboxPerms -notlike '*completed successfully but no settings of*') { + Write-LogMessage -user $ExecutingUser -API $APIName -message "Removed SendOnBehalf permissions for $($AccessUser) from $($userid)'s mailbox." -Sev 'Info' -tenant $TenantFilter "Removed SendOnBehalf permissions for $($AccessUser) from $($userid)'s mailbox." } } - "SendAS" { - $MailboxPerms = New-ExoRequest -Anchor $userId -tenantid $Tenantfilter -cmdlet "Remove-RecipientPermission" -cmdParams @{Identity = $userid; Trustee = $AccessUser; accessRights = @("SendAs") } + 'SendAS' { + $MailboxPerms = New-ExoRequest -Anchor $userId -tenantid $Tenantfilter -cmdlet 'Remove-RecipientPermission' -cmdParams @{Identity = $userid; Trustee = $AccessUser; accessRights = @('SendAs') } if ($MailboxPerms -notlike "*because the ACE isn't present*") { - Write-LogMessage -user $ExecutingUser -API $APIName -message "Removed SendAs permissions for $($AccessUser) from $($userid)'s mailbox." -Sev "Info" -tenant $TenantFilter + Write-LogMessage -user $ExecutingUser -API $APIName -message "Removed SendAs permissions for $($AccessUser) from $($userid)'s mailbox." -Sev 'Info' -tenant $TenantFilter "Removed SendAs permissions for $($AccessUser) from $($userid)'s mailbox." } } - "FullAccess" { - $permissions = New-ExoRequest -tenantid $TenantFilter -cmdlet "Remove-MailboxPermission" -cmdParams @{Identity = $userid; user = $AccessUser; accessRights = @("FullAccess") } -Anchor $userid + 'FullAccess' { + $permissions = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Remove-MailboxPermission' -cmdParams @{Identity = $userid; user = $AccessUser; accessRights = @('FullAccess') } -Anchor $userid if ($permissions -notlike "*because the ACE doesn't exist on the object.*") { - Write-LogMessage -user $ExecutingUser -API $APIName -message "Removed FullAccess permissions for $($AccessUser) from $($userid)'s mailbox." -Sev "Info" -tenant $TenantFilter + Write-LogMessage -user $ExecutingUser -API $APIName -message "Removed FullAccess permissions for $($AccessUser) from $($userid)'s mailbox." -Sev 'Info' -tenant $TenantFilter "Removed FullAccess permissions for $($AccessUser) from $($userid)'s mailbox." } } @@ -48,9 +46,8 @@ function Remove-CIPPMailboxPermissions { } } return $Results - } - catch { - Write-LogMessage -user $ExecutingUser -API $APIName -message "Could not remove mailbox permissions for $($userid). Error: $($_.Exception.Message)" -Sev "Error" -tenant $TenantFilter + } catch { + Write-LogMessage -user $ExecutingUser -API $APIName -message "Could not remove mailbox permissions for $($userid). Error: $($_.Exception.Message)" -Sev 'Error' -tenant $TenantFilter return "Could not remove mailbox permissions for $($userid). Error: $($_.Exception.Message)" } } diff --git a/Modules/CIPPCore/Public/Remove-CIPPMobileDevice.ps1 b/Modules/CIPPCore/Public/Remove-CIPPMobileDevice.ps1 index d5d6d6b73228..e5ae407bf35e 100644 --- a/Modules/CIPPCore/Public/Remove-CIPPMobileDevice.ps1 +++ b/Modules/CIPPCore/Public/Remove-CIPPMobileDevice.ps1 @@ -4,26 +4,24 @@ function Remove-CIPPMobileDevice { $userid, $tenantFilter, $username, - $APIName = "Remove Mobile", + $APIName = 'Remove Mobile', $ExecutingUser ) try { - $devices = New-ExoRequest -tenantid $tenantFilter -cmdlet "Get-MobileDevice" -Anchor $username -cmdParams @{mailbox = $username } | ForEach-Object { + $devices = New-ExoRequest -tenantid $tenantFilter -cmdlet 'Get-MobileDevice' -Anchor $username -cmdParams @{mailbox = $username } | ForEach-Object { try { - New-ExoRequest -tenantid $tenantFilter -cmdlet "Remove-MobileDevice" -Anchor $username -cmdParams @{Identity = $_.Identity } + New-ExoRequest -tenantid $tenantFilter -cmdlet 'Remove-MobileDevice' -Anchor $username -cmdParams @{Identity = $_.Identity } "Removed device: $($_.FriendlyName)" - } - catch { + } catch { "Could not remove device: $($_.FriendlyName)" } } - - Write-LogMessage -user $ExecutingUser -API $APIName -message "Deleted mobile devices for $($username)" -Sev "Info" -tenant $tenantFilter + if (!$Devices) { $Devices ='No mobile devices have been removed as we could not find any' } + Write-LogMessage -user $ExecutingUser -API $APIName -message "Deleted mobile devices for $($username)" -Sev 'Info' -tenant $tenantFilter return $devices - } - catch { - Write-LogMessage -user $ExecutingUser -API $APIName -message "Could not delete mobile devices for $($username): $($_.Exception.Message)" -Sev "Error" -tenant $tenantFilter + } catch { + Write-LogMessage -user $ExecutingUser -API $APIName -message "Could not delete mobile devices for $($username): $($_.Exception.Message)" -Sev 'Error' -tenant $tenantFilter return "Could not delete mobile devices for $($username). Error: $($_.Exception.Message)" } } diff --git a/Modules/CIPPCore/Public/Set-CIPPCPVConsent.ps1 b/Modules/CIPPCore/Public/Set-CIPPCPVConsent.ps1 index 8b3c1bbd0f82..d4c06d0e904f 100644 --- a/Modules/CIPPCore/Public/Set-CIPPCPVConsent.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPCPVConsent.ps1 @@ -15,7 +15,8 @@ function Set-CIPPCPVConsent { try { $DeleteSP = New-GraphpostRequest -Type DELETE -noauthcheck $true -uri "https://api.partnercenter.microsoft.com/v1/customers/$($TenantFilter)/applicationconsents/$($ENV:applicationId)" -scope 'https://api.partnercenter.microsoft.com/.default' -tenantid $env:TenantID $Results.add("Deleted Service Principal from $TenantName") - } catch { + } + catch { $Results.add("Error deleting SP - $($_.Exception.Message)") } } @@ -39,13 +40,14 @@ function Set-CIPPCPVConsent { } Add-CIPPAzDataTableEntity @Table -Entity $GraphRequest -Force $Results.add("Successfully added CPV Application to tenant $($TenantName)") | Out-Null - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Added our Service Principal to $($TenantName): $($_.Exception.message)" -Sev 'Info' -tenant $($Tenantfilter) + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Added our Service Principal to $($TenantName): $($_.Exception.message)" -Sev 'Info' -tenant $TenantName -tenantId $TenantFilter - } catch { + } + catch { $ErrorMessage = $_.Exception.Message if ($ErrorMessage -like '*409 (Conflict)*') { return @("We've already added our Service Principal to $($TenantName)") } - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Could not add our Service Principal to the client tenant $($TenantName): $($_.Exception.message)" -Sev 'Error' -tenant $($Tenantfilter) + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Could not add our Service Principal to the client tenant $($TenantName): $($_.Exception.message)" -Sev 'Error' -tenant $TenantName -tenantId $TenantFilter return @("Could not add our Service Principal to the client tenant $($TenantName): $($_.Exception.message)") } return $Results diff --git a/Modules/CIPPCore/Public/Set-CIPPGDAPInviteGroups.ps1 b/Modules/CIPPCore/Public/Set-CIPPGDAPInviteGroups.ps1 index e136536cd328..ca159b6611d5 100644 --- a/Modules/CIPPCore/Public/Set-CIPPGDAPInviteGroups.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPGDAPInviteGroups.ps1 @@ -11,7 +11,7 @@ function Set-CIPPGDAPInviteGroups { foreach ($Activation in $Activations) { if ($InviteList.RowKey -contains $Activation.id) { Write-Host "Mapping groups for GDAP relationship: $($Activation.id)" - Push-OutputBinding -Name Msg -Value $Activation.id + Push-OutputBinding -Name gdapinvitequeue -Value $Activation.id } } } diff --git a/Modules/CIPPCore/Public/Set-CIPPOutOfoffice.ps1 b/Modules/CIPPCore/Public/Set-CIPPOutOfoffice.ps1 index 9d0eb4f40120..8365e4b64a90 100644 --- a/Modules/CIPPCore/Public/Set-CIPPOutOfoffice.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPOutOfoffice.ps1 @@ -13,10 +13,16 @@ function Set-CIPPOutOfOffice { ) try { + if (-not $StartTime) { + $StartTime = (Get-Date).ToString("yyyy-MM-dd HH:mm") + } + if (-not $EndTime) { + $EndTime = (Get-Date $StartTime).AddDays(7) + } if ($State -ne "Scheduled") { $OutOfOffice = New-ExoRequest -tenantid $TenantFilter -cmdlet "Set-MailboxAutoReplyConfiguration" -cmdParams @{Identity = $userid; AutoReplyState = $State; InternalMessage = $InternalMessage; ExternalMessage = $ExternalMessage } -Anchor $userid Write-LogMessage -user $ExecutingUser -API $APIName -message "Set Out-of-office for $($userid) to $state" -Sev "Info" -tenant $TenantFilter - return "Set Out-of-office for $($userid) to $state. Message is $InternalMessage" + return "Set Out-of-office for $($userid) to $state." } else { $OutOfOffice = New-ExoRequest -tenantid $TenantFilter -cmdlet "Set-MailboxAutoReplyConfiguration" -cmdParams @{Identity = $userid; AutoReplyState = $State; InternalMessage = $InternalMessage; ExternalMessage = $ExternalMessage; StartTime = $StartTime; EndTime = $EndTime } -Anchor $userid diff --git a/Modules/CippEntrypoints/CippEntrypoints.psm1 b/Modules/CippEntrypoints/CippEntrypoints.psm1 index ffea0fd0021d..7e376917303d 100644 --- a/Modules/CippEntrypoints/CippEntrypoints.psm1 +++ b/Modules/CippEntrypoints/CippEntrypoints.psm1 @@ -2,7 +2,9 @@ using namespace System.Net function Receive-CippHttpTrigger { Param($Request, $TriggerMetadata) - + #force path to CIPP-API + Set-Location (Get-Item $PSScriptRoot).Parent.Parent.FullName + Write-Host (Get-Item $PSScriptRoot).Parent.Parent.FullName $APIName = $TriggerMetadata.FunctionName $FunctionName = 'Invoke-{0}' -f $APIName @@ -18,7 +20,7 @@ function Receive-CippHttpTrigger { function Receive-CippQueueTrigger { Param($QueueItem, $TriggerMetadata) $APIName = $TriggerMetadata.FunctionName - + Set-Location (Get-Item $PSScriptRoot).Parent.Parent.FullName $FunctionName = 'Push-{0}' -f $APIName $QueueTrigger = @{ QueueItem = $QueueItem diff --git a/Modules/CippExtensions/CippExtensions.psd1 b/Modules/CippExtensions/CippExtensions.psd1 index b66d07c0b57a..edf5fbcddae7 100644 Binary files a/Modules/CippExtensions/CippExtensions.psd1 and b/Modules/CippExtensions/CippExtensions.psd1 differ diff --git a/Modules/CippExtensions/CippExtensions.psm1 b/Modules/CippExtensions/CippExtensions.psm1 index 0b892b97d986..ad69dcdfdb5f 100644 --- a/Modules/CippExtensions/CippExtensions.psm1 +++ b/Modules/CippExtensions/CippExtensions.psm1 @@ -1,6 +1,7 @@ $Public = @(Get-ChildItem -Path $PSScriptRoot\Public\*.ps1 -ErrorAction SilentlyContinue) $Private = @(Get-ChildItem -Path $PSScriptRoot\private\*.ps1 -ErrorAction SilentlyContinue) -$Functions = $Public + $Private +$NinjaOne = @(Get-ChildItem -Path $PSScriptRoot\NinjaOne\*.ps1 -ErrorAction SilentlyContinue) +$Functions = $Public + $Private + $NinjaOne foreach ($import in @($Functions)) { try { . $import.FullName diff --git a/Modules/CippExtensions/NinjaOne/Get-NinjaOneFieldMapping.ps1 b/Modules/CippExtensions/NinjaOne/Get-NinjaOneFieldMapping.ps1 new file mode 100644 index 000000000000..8be773c2d030 --- /dev/null +++ b/Modules/CippExtensions/NinjaOne/Get-NinjaOneFieldMapping.ps1 @@ -0,0 +1,101 @@ +function Get-NinjaOneFieldMapping { + [CmdletBinding()] + param ( + $CIPPMapping + ) + try { + #Get available mappings + $Mappings = [pscustomobject]@{} + + [System.Collections.Generic.List[PSCustomObject]]$CIPPFields = @( + [PSCustomObject]@{ + InternalName = 'TenantLinks' + Description = 'Microsoft 365 Tenant Links - Field Used to Display Links to Microsoft 365 Portals and CIPP' + Scope = 'Organization' + Type = 'WYSIWYG' + }, + [PSCustomObject]@{ + InternalName = 'TenantSummary' + Description = 'Microsoft 365 Tenant Summary - Field Used to Display Tenant Summary Information' + Scope = 'Organization' + Type = 'WYSIWYG' + }, + [PSCustomObject]@{ + InternalName = 'UsersSummary' + Description = 'Microsoft 365 Users Summary - Field Used to Display User Summary Information' + Scope = 'Organization' + Type = 'WYSIWYG' + }, + [PSCustomObject]@{ + InternalName = 'DeviceLinks' + Description = 'Microsoft 365 Device Links - Field Used to Display Links to Microsoft 365 Portals and CIPP' + Scope = 'Device' + Type = 'WYSIWYG' + }, + [PSCustomObject]@{ + InternalName = 'DeviceSummary' + Description = 'Microsoft 365 Device Summary - Field Used to Display Device Summary Information' + Scope = 'Device' + Type = 'WYSIWYG' + }, + [PSCustomObject]@{ + InternalName = 'DeviceCompliance' + Description = 'Intune Device Compliance Status - Field Used to Monitor Device Compliance' + Scope = 'Device' + Type = 'TEXT' + } + ) + + $Filter = "PartitionKey eq 'NinjaFieldMapping'" + Get-AzDataTableEntity @CIPPMapping -Filter $Filter | ForEach-Object { + $Mappings | Add-Member -NotePropertyName $_.RowKey -NotePropertyValue @{ label = "$($_.NinjaOneName)"; value = "$($_.NinjaOne)" } + } + + + $Table = Get-CIPPTable -TableName Extensionsconfig + $Configuration = ((Get-AzDataTableEntity @Table).config | ConvertFrom-Json -ea stop).NinjaOne + + + + $Token = Get-NinjaOneToken -configuration $Configuration + + $NinjaCustomFieldsNodeRaw = (Invoke-WebRequest -uri "https://$($Configuration.Instance)/api/v2/device-custom-fields?scopes=node" -Method GET -Headers @{Authorization = "Bearer $($token.access_token)" } -ContentType 'application/json').content | ConvertFrom-Json -depth 100 + [System.Collections.Generic.List[PSCustomObject]]$NinjaCustomFieldsNode = $NinjaCustomFieldsNodeRaw | Where-Object { $_.apiPermission -eq 'READ_WRITE' -and $_.type -in $CIPPFields.Type } | Select-Object @{n = 'name'; e = { $_.label } }, @{n = 'value'; e = { $_.name } }, type + + $NinjaCustomFieldsOrgRaw = (Invoke-WebRequest -uri "https://$($Configuration.Instance)/api/v2/device-custom-fields?scopes=organization" -Method GET -Headers @{Authorization = "Bearer $($token.access_token)" } -ContentType 'application/json').content | ConvertFrom-Json -depth 100 + [System.Collections.Generic.List[PSCustomObject]]$NinjaCustomFieldsOrg = $NinjaCustomFieldsOrgRaw | Where-Object { $_.apiPermission -eq 'READ_WRITE' -and $_.type -in $CIPPFields.Type } | Select-Object @{n = 'name'; e = { $_.label } }, @{n = 'value'; e = { $_.name } }, type + + if ($Null -eq $NinjaCustomFieldsNode){ + [System.Collections.Generic.List[PSCustomObject]]$NinjaCustomFieldsNode = @() + } + + if ($Null -eq $NinjaCustomFieldsOrg){ + [System.Collections.Generic.List[PSCustomObject]]$NinjaCustomFieldsOrg = @() + } + + } catch { + [System.Collections.Generic.List[PSCustomObject]]$NinjaCustomFieldsNode = @() + [System.Collections.Generic.List[PSCustomObject]]$NinjaCustomFieldsOrg = @() + } + + $DoNotSync = [PSCustomObject]@{ + name = '--- Do not synchronize ---' + value = $null + type = 'unset' + } + + $NinjaCustomFieldsOrg.Insert(0, $DoNotSync) + $NinjaCustomFieldsNode.Insert(0, $DoNotSync) + + + $MappingObj = [PSCustomObject]@{ + CIPPOrgFields = $CIPPFields | Where-Object { $_.Scope -eq 'Organization' } + CIPPNodeFields = @($CIPPFields | Where-Object { $_.Scope -eq 'Device' }) + NinjaOrgFields = @($NinjaCustomFieldsOrg) + NinjaNodeFields = @($NinjaCustomFieldsNode) + Mappings = $Mappings + } + + return $MappingObj + +} \ No newline at end of file diff --git a/Modules/CippExtensions/NinjaOne/Get-NinjaOneOrgMapping.ps1 b/Modules/CippExtensions/NinjaOne/Get-NinjaOneOrgMapping.ps1 new file mode 100644 index 000000000000..822ed28b42b4 --- /dev/null +++ b/Modules/CippExtensions/NinjaOne/Get-NinjaOneOrgMapping.ps1 @@ -0,0 +1,46 @@ +function Get-NinjaOneOrgMapping { + [CmdletBinding()] + param ( + $CIPPMapping + ) + try { + #Get available mappings + $Mappings = [pscustomobject]@{} + $Tenants = Get-Tenants + + $Filter = "PartitionKey eq 'NinjaOrgsMapping'" + Get-AzDataTableEntity @CIPPMapping -Filter $Filter | ForEach-Object { + $Mappings | Add-Member -NotePropertyName $_.RowKey -NotePropertyValue @{ label = "$($_.NinjaOneName)"; value = "$($_.NinjaOne)" } + } + #Get Available Tenants + + #Get available Ninja clients + $Table = Get-CIPPTable -TableName Extensionsconfig + $Configuration = ((Get-AzDataTableEntity @Table).config | ConvertFrom-Json -ea stop).NinjaOne + + + $Token = Get-NinjaOneToken -configuration $Configuration + + $After = 0 + $PageSize = 1000 + $NinjaOrgs = do { + $Result = (Invoke-WebRequest -uri "https://$($Configuration.Instance)/api/v2/organizations?pageSize=$PageSize&after=$After" -Method GET -Headers @{Authorization = "Bearer $($token.access_token)" } -ContentType 'application/json').content | ConvertFrom-Json -depth 100 + $Result | Select-Object name, @{n = 'value'; e = { $_.id } } + $ResultCount = ($Result.id | Measure-Object -Maximum) + $After = $ResultCount.maximum + + } while ($ResultCount.count -eq $PageSize) + + } catch { + $NinjaOrgs = @() + } + + $MappingObj = [PSCustomObject]@{ + Tenants = @($Tenants) + NinjaOrgs = @($NinjaOrgs | Sort-Object name) + Mappings = $Mappings + } + + return $MappingObj + +} \ No newline at end of file diff --git a/Modules/CippExtensions/NinjaOne/Get-NinjaOneToken.ps1 b/Modules/CippExtensions/NinjaOne/Get-NinjaOneToken.ps1 new file mode 100644 index 000000000000..17ebad207a2d --- /dev/null +++ b/Modules/CippExtensions/NinjaOne/Get-NinjaOneToken.ps1 @@ -0,0 +1,26 @@ +function Get-NinjaOneToken { + [CmdletBinding()] + param ( + $Configuration + ) + + + if (!$ENV:NinjaClientSecret) { + $null = Connect-AzAccount -Identity + $ClientSecret = (Get-AzKeyVaultSecret -VaultName $ENV:WEBSITE_DEPLOYMENT_ID -Name "NinjaOne" -AsPlainText) + } else { + $ClientSecret = $ENV:NinjaClientSecret + } + + + $body = @{ + grant_type = 'client_credentials' + client_id = $Configuration.ClientId + client_secret = $ClientSecret + scope = 'monitoring management' + } + + $token = Invoke-RestMethod -Uri "https://$($Configuration.Instance -replace '/ws','')/ws/oauth/token" -Method Post -Body $body -ContentType 'application/x-www-form-urlencoded' + return $token + +} \ No newline at end of file diff --git a/Modules/CippExtensions/NinjaOne/Invoke-NinjaOneDeviceWebhook.ps1 b/Modules/CippExtensions/NinjaOne/Invoke-NinjaOneDeviceWebhook.ps1 new file mode 100644 index 000000000000..508f96eb75b8 --- /dev/null +++ b/Modules/CippExtensions/NinjaOne/Invoke-NinjaOneDeviceWebhook.ps1 @@ -0,0 +1,57 @@ +function Invoke-NinjaOneDeviceWebhook { + [CmdletBinding()] + param ( + $Data, + $Configuration + ) + try { + Write-LogMessage -user $ExecutingUser -API $APIName -message "Webhook Recieved - Updating NinjaOne Device compliance for $($Data.resourceData.id) in $($Data.tenantId)" -Sev "Info" -tenant $TenantFilter + $MappedFields = [pscustomobject]@{} + $CIPPMapping = Get-CIPPTable -TableName CippMapping + $Filter = "PartitionKey eq 'NinjaFieldMapping'" + Get-AzDataTableEntity @CIPPMapping -Filter $Filter | Where-Object { $Null -ne $_.NinjaOne -and $_.NinjaOne -ne '' } | ForEach-Object { + $MappedFields | Add-Member -NotePropertyName $_.RowKey -NotePropertyValue $($_.NinjaOne) + } + + if ($MappedFields.DeviceCompliance) { + $tenantfilter = $Data.tenantId + $M365DeviceID = $Data.resourceData.id + + $DeviceM365 = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/devices/$($M365DeviceID)" -Tenantid $tenantfilter + + $DeviceFilter = "PartitionKey eq '$($tenantfilter)' and RowKey eq '$($DeviceM365.deviceID)'" + $DeviceMapTable = Get-CippTable -tablename 'NinjaOneDeviceMap' + $Device = Get-CIPPAzDataTableEntity @DeviceMapTable -Filter $DeviceFilter + + if (($Device | Measure-Object).count -eq 1) { + $Token = Get-NinjaOneToken -configuration $Configuration + + if ($DeviceM365.isCompliant -eq $True) { + $Compliant = 'Compliant' + } else { + $Compliant = 'Non-Compliant' + } + + $ComplianceBody = @{ + "$($MappedFields.DeviceCompliance)" = $Compliant + } | ConvertTo-Json + + $Null = Invoke-WebRequest -uri "https://$($Configuration.Instance)/api/v2/device/$($Device.NinjaOneID)/custom-fields" -Method PATCH -Body $ComplianceBody -Headers @{Authorization = "Bearer $($token.access_token)" } -ContentType 'application/json' + + Write-Host "Updated NinjaOne Device Compliance" + + + } else { + Throw "Failed to process device." + } + + } + + } catch { + Write-Error "Failed NinjaOne Device Webhook for: $($Data | ConvertTo-Json -depth 100) Linenumber: $($_.InvocationInfo.ScriptLineNumber) Error: $($_.Exception.message)" + Write-LogMessage -API 'NinjaOneSync' -user 'CIPP' -message "Failed NinjaOne Device Webhook Linenumber: $($_.InvocationInfo.ScriptLineNumber) Error: $($_.Exception.message)" -Sev 'Error' + } + + + +} \ No newline at end of file diff --git a/Modules/CippExtensions/NinjaOne/Invoke-NinjaOneDocumentTemplate.ps1 b/Modules/CippExtensions/NinjaOne/Invoke-NinjaOneDocumentTemplate.ps1 new file mode 100644 index 000000000000..e816c66d4000 --- /dev/null +++ b/Modules/CippExtensions/NinjaOne/Invoke-NinjaOneDocumentTemplate.ps1 @@ -0,0 +1,40 @@ +function Invoke-NinjaOneDocumentTemplate { + [CmdletBinding()] + param ( + $Template, + $Token, + $ID + ) + + if (!$Token) { + $Table = Get-CIPPTable -TableName Extensionsconfig + $Configuration = ((Get-AzDataTableEntity @Table).config | ConvertFrom-Json).NinjaOne + $Token = Get-NinjaOneToken -configuration $Configuration + } + + if (!$ID) { + $DocumentTemplates = (Invoke-WebRequest -Uri "https://$($Configuration.Instance)/api/v2/document-templates/" -Method GET -Headers @{Authorization = "Bearer $($token.access_token)" } -ContentType 'application/json').content | ConvertFrom-Json -Depth 100 + $DocumentTemplate = $DocumentTemplates | Where-Object { $_.name -eq $Template.name } + } + else { + $DocumentTemplate = (Invoke-WebRequest -Uri "https://$($Configuration.Instance)/api/v2/document-templates/$($ID)" -Method GET -Headers @{Authorization = "Bearer $($token.access_token)" } -ContentType 'application/json').content | ConvertFrom-Json -Depth 100 + } + + $MatchedCount = ($DocumentTemplate | Measure-Object).count + if ($MatchedCount -eq 1) { + # Matched a single document template + $NinjaDocumentTemplate = $DocumentTemplate + } + elseif ($MatchedCount -eq 0) { + # Create a new Document Template + $Body = $Template | ConvertTo-Json -Depth 100 + $NinjaDocumentTemplate = (Invoke-WebRequest -Uri "https://$($Configuration.Instance)/api/v2/document-templates/" -Method POST -Headers @{Authorization = "Bearer $($token.access_token)" } -ContentType 'application/json' -Body $Body).content | ConvertFrom-Json -Depth 100 + } + else { + # Matched multiple templates. Should be impossible but lets check anyway :D + Throw "Multiple Documents Matched the Provided Criteria" + } + + return $NinjaDocumentTemplate + +} \ No newline at end of file diff --git a/Modules/CippExtensions/NinjaOne/Invoke-NinjaOneOrgMapping.ps1 b/Modules/CippExtensions/NinjaOne/Invoke-NinjaOneOrgMapping.ps1 new file mode 100644 index 000000000000..aba6264ff23b --- /dev/null +++ b/Modules/CippExtensions/NinjaOne/Invoke-NinjaOneOrgMapping.ps1 @@ -0,0 +1,107 @@ +function Invoke-NinjaOneOrgMapping { + + [System.Collections.Generic.List[PSCustomObject]]$MatchedM365Tenants = @() + [System.Collections.Generic.List[PSCustomObject]]$MatchedNinjaOrgs = @() + + $ExcludeSerials = @("0", "SystemSerialNumber", "To Be Filled By O.E.M.", "System Serial Number", "0123456789", "123456789", "............") + $CIPPMapping = Get-CIPPTable -TableName CippMapping + + + #Get available mappings + $Mappings = [pscustomobject]@{} + $Filter = "PartitionKey eq 'NinjaOrgsMapping'" + Get-AzDataTableEntity @CIPPMapping -Filter $Filter | ForEach-Object { + $Mappings | Add-Member -NotePropertyName $_.RowKey -NotePropertyValue @{ label = "$($_.NinjaOneName)"; value = "$($_.NinjaOne)" } + } + + #Get Available Tenants + $Tenants = Get-Tenants + #Get available Ninja clients + $Table = Get-CIPPTable -TableName Extensionsconfig + $Configuration = ((Get-AzDataTableEntity @Table).config | ConvertFrom-Json).NinjaOne + + $Token = Get-NinjaOneToken -configuration $Configuration + + # Fetch Ninja Orgs + $After = 0 + $PageSize = 1000 + $NinjaOrgs = do { + $Result = (Invoke-WebRequest -uri "https://$($Configuration.Instance)/api/v2/organizations?pageSize=$PageSize&after=$After" -Method GET -Headers @{Authorization = "Bearer $($token.access_token)" } -ContentType 'application/json').content | ConvertFrom-Json -depth 100 + $Result + $ResultCount = ($Result.id | Measure-Object -Maximum) + $After = $ResultCount.maximum + + } while ($ResultCount.count -eq $PageSize) + + # Exclude tenants already mapped. + Foreach ($ExistingMap in $mappings.psobject.properties) { + $ExistingTenant = $Tenants | Where-Object { $_.customerId -eq $ExistingMap.name } + $ExistingOrg = $NinjaOrgs | Where-Object { $_.id -eq $ExistingMap.value.value } + + if (($ExistingTenant | Measure-Object).count -eq 1) { + $MatchedM365Tenants.add($ExistingTenant) + } + + if (($ExistingOrg | Measure-Object).count -eq 1) { + $MatchedM365Tenants.add($ExistingOrg) + } + } + + # Fetch Ninja Devices + $After = 0 + $PageSize = 1000 + $NinjaDevicesRaw = do { + $Result = (Invoke-WebRequest -uri "https://$($Configuration.Instance)/api/v2/devices-detailed?pageSize=$PageSize&after=$After" -Method GET -Headers @{Authorization = "Bearer $($token.access_token)" } -ContentType 'application/json').content | ConvertFrom-Json -depth 100 + $Result + $ResultCount = ($Result.id | Measure-Object -Maximum) + $After = $ResultCount.maximum + + } while ($ResultCount.count -eq $PageSize) + + + $NinjaDevices = $NinjaDevicesRaw | Where-Object { $null -ne $_.system.serialNumber -and $_.system.serialNumber -notin $ExcludeSerials } | ForEach-Object { + [pscustomobject]@{ + ID = $_.id + SystemName = $_.systemName + DNSName = $_.dnsName + Serial = $_.system.serialNumber + BiosSerialNumber = $_.system.biosSerialNumber + OrgID = $_.organizationId + } + } + + # Remove any devices with duplicate serials + $ParsedNinjaDevices = $NinjaDevices | Where-Object { $_.Serial -in (($NinjaDevices | Group-Object Serial | where-object { $_.count -eq 1 }).name) } + + + # First lets match on Org names + foreach ($Tenant in $Tenants | Where-Object { $_.customerId -notin $MatchedM365Tenants.customerId }) { + $MatchedOrg = $NinjaOrgs | where-object { $_.name -eq $Tenant.displayName } + if (($MatchedOrg | Measure-Object).count -eq 1) { + $MatchedM365Tenants.add($Tenant) + $MatchedNinjaOrgs.add($MatchedOrg) + $AddObject = @{ + PartitionKey = 'NinjaOrgsMapping' + RowKey = "$($Tenant.customerId)" + 'NinjaOne' = "$($MatchedOrg.id)" + 'NinjaOneName' = "$($MatchedOrg.name)" + } + Add-AzDataTableEntity @CIPPMapping -Entity $AddObject -Force + Write-LogMessage -API 'NinjaOneAutoMap_Queue' -user 'CIPP' -message "Added mapping from Organization name match for $($Tenant.customerId). to $($($MatchedOrg.name))" -Sev 'Info' + } + } + + # Now Let match on remaining Tenants + + Foreach ($Tenant in $Tenants | Where-Object { $_.customerId -notin $MatchedM365Tenants.customerId }) { + + Push-OutputBinding -Name NinjaProcess -Value @{ + 'NinjaAction' = 'AutoMapTenant' + 'M365Tenant' = $Tenant + 'NinjaOrgs' = $NinjaOrgs | Where-Object { $_.id -notin $MatchedNinjaOrgs } + 'NinjaDevices' = $ParsedNinjaDevices + } + + } +} + \ No newline at end of file diff --git a/Modules/CippExtensions/NinjaOne/Invoke-NinjaOneOrgMappingTenant.ps1 b/Modules/CippExtensions/NinjaOne/Invoke-NinjaOneOrgMappingTenant.ps1 new file mode 100644 index 000000000000..317770c3bb78 --- /dev/null +++ b/Modules/CippExtensions/NinjaOne/Invoke-NinjaOneOrgMappingTenant.ps1 @@ -0,0 +1,73 @@ +function Invoke-NinjaOneOrgMappingTenant { + [CmdletBinding()] + param ( + $QueueItem + ) + + $Tenant = $QueueItem.M365Tenant + $NinjaOrgs = $QueueItem.NinjaOrgs + $NinjaDevices = $QueueItem.NinjaDevices + + Write-Host "Processing $($Tenant.displayName)" + + $CIPPMapping = Get-CIPPTable -TableName CippMapping + + $TenantFilter = $Tenant.customerId + + $M365DevicesRaw = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceManagement/managedDevices" -Tenantid $tenantfilter + + $M365Devices = foreach ($Device in $M365DevicesRaw) { + [pscustomobject]@{ + 'DeviceID' = $Device.id + 'DeviceName' = $Device.deviceName + 'DeviceSerial' = $Device.serialNumber + } + } + + + [System.Collections.Generic.List[PSCustomObject]]$MatchedDevices = @() + + # Match devices on serial + $DevicesToMatchSerial = $M365Devices | where-object { $null -ne $_.DeviceSerial } + foreach ($SerialMatchDevice in $DevicesToMatchSerial) { + $MatchedDevice = $NinjaDevices | where-object { $_.Serial -eq $SerialMatchDevice.DeviceSerial -or $_.BiosSerialNumber -eq $SerialMatchDevice.DeviceSerial } + if (($MatchedDevice | measure-object).count -eq 1) { + $Match = [pscustomobject]@{ + M365 = $SerialMatchDevice + Ninja = $MatchedDevice + } + $MatchedDevices.add($Match) + } + } + + # Try to match on Name + $DevicesToMatchName = $M365Devices | where-object { $_ -notin $MatchedDevices.M365 } + foreach ($NameMatchDevice in $DevicesToMatchName) { + $MatchedDevice = $NinjaDevices | where-object { $_.SystemName -eq $NameMatchDevice.DeviceName -or $_.DNSName -eq $NameMatchDevice.DeviceName } + if (($MatchedDevice | measure-object).count -eq 1) { + $Match = [pscustomobject]@{ + M365 = $NameMatchDevice + Ninja = $MatchedDevice + } + $MatchedDevices.add($Match) + } + } + + + # Match on the Org with the most devices that match + if (($MatchedDevices.Ninja.ID | Measure-Object).Count -eq 1) { + $MatchedOrgID = ($MatchedDevices.Ninja | group-object OrgID | sort-object Count -desc)[0].name + $MatchedOrg = $NinjaOrgs | Where-Object { $_.id -eq $MatchedOrgID } + + $AddObject = @{ + PartitionKey = 'NinjaOrgsMapping' + RowKey = "$($Tenant.customerId)" + 'NinjaOne' = "$($MatchedOrg.id)" + 'NinjaOneName' = "$($MatchedOrg.name)" + } + Add-AzDataTableEntity @CIPPMapping -Entity $AddObject -Force + Write-LogMessage -API 'NinjaOneAutoMap_Queue' -user 'CIPP' -message "Added mapping from Device match for $($Tenant.displayName) to $($($MatchedOrg.name))" -Sev 'Info' + + } + +} \ No newline at end of file diff --git a/Modules/CippExtensions/NinjaOne/Invoke-NinjaOneTenantSync.ps1 b/Modules/CippExtensions/NinjaOne/Invoke-NinjaOneTenantSync.ps1 new file mode 100644 index 000000000000..d84c6aaee35e --- /dev/null +++ b/Modules/CippExtensions/NinjaOne/Invoke-NinjaOneTenantSync.ps1 @@ -0,0 +1,2273 @@ +function Invoke-NinjaOneTenantSync { + [CmdletBinding()] + param ( + $QueueItem + ) + try { + + $StartTime = Get-Date + Write-Host "$(Get-Date) - Starting NinjaOne Sync" + + # Fetch Custom NinjaOne Settings + $Table = Get-CIPPTable -TableName NinjaOneSettings + $NinjaSettings = (Get-AzDataTableEntity @Table) + $CIPPUrl = ($NinjaSettings | Where-Object { $_.RowKey -eq 'CIPPURL' }).SettingValue + + # Parse out the Tenant we are processing + $MappedTenant = $QueueItem.MappedTenant + $Customer = Get-Tenants | where-object { $_.customerId -eq $MappedTenant.RowKey } + Write-Host "Processing: $($Customer.displayName)" + + Write-LogMessage -API 'NinjaOneSync' -user 'CIPP' -message "Processing NinjaOne Synchronization for $($Customer.displayName)" -Sev 'Info' + + if (($Customer | Measure-Object).count -ne 1) { + Throw "Unable to match the recieved ID to a tenant QueueItem: $($QueueItem | ConvertTo-Json -Depth 100 | Out-String) Matched Customer: $($Customer| ConvertTo-Json -Depth 100 | Out-String)" + } + + $TenantFilter = $Customer.defaultDomainName + $NinjaOneOrg = $MappedTenant.NinjaOne + + + # Get the NinjaOne general extension settings. + $Table = Get-CIPPTable -TableName Extensionsconfig + $Configuration = ((Get-AzDataTableEntity @Table).config | ConvertFrom-Json).NinjaOne + + # Pull the list of field Mappings so we know which fields to render. + $MappedFields = [pscustomobject]@{} + $CIPPMapping = Get-CIPPTable -TableName CippMapping + $Filter = "PartitionKey eq 'NinjaFieldMapping'" + Get-AzDataTableEntity @CIPPMapping -Filter $Filter | Where-Object { $Null -ne $_.NinjaOne -and $_.NinjaOne -ne '' } | ForEach-Object { + $MappedFields | Add-Member -NotePropertyName $_.RowKey -NotePropertyValue $($_.NinjaOne) + } + + # Get NinjaOne Devices + $Token = Get-NinjaOneToken -configuration $Configuration + $After = 0 + $PageSize = 1000 + $NinjaDevices = do { + $Result = (Invoke-WebRequest -uri "https://$($Configuration.Instance)/api/v2/devices-detailed?pageSize=$PageSize&after=$After&df=org = $($NinjaOneOrg)" -Method GET -Headers @{Authorization = "Bearer $($token.access_token)" } -ContentType 'application/json').content | ConvertFrom-Json -depth 100 + $Result + $ResultCount = ($Result.id | Measure-Object -Maximum) + $After = $ResultCount.maximum + + } while ($ResultCount.count -eq $PageSize) + + Write-Host "Fetched NinjaOne Devices" + + [System.Collections.Generic.List[PSCustomObject]]$NinjaOneUserDocs = @() + + if ($Configuration.UserDocumentsEnabled -eq $True) { + # Get NinjaOne User Documents + $UserDocTemplate = [PSCustomObject]@{ + name = 'CIPP - Microsoft 365 Users' + allowMultiple = $true + fields = @( + [PSCustomObject]@{ + fieldLabel = 'User Links' + fieldName = 'cippUserLinks' + fieldType = 'WYSIWYG' + fieldTechnicianPermission = 'READ_ONLY' + fieldScriptPermission = 'NONE' + fieldApiPermission = 'READ_WRITE' + fieldContent = @{ + required = $False + advancedSettings = @{ + expandLargeValueOnRender = $True + } + } + }, + [PSCustomObject]@{ + fieldLabel = 'User Summary' + fieldName = 'cippUserSummary' + fieldType = 'WYSIWYG' + fieldTechnicianPermission = 'READ_ONLY' + fieldScriptPermission = 'NONE' + fieldApiPermission = 'READ_WRITE' + fieldContent = @{ + required = $False + advancedSettings = @{ + expandLargeValueOnRender = $True + } + } + }, + [PSCustomObject]@{ + fieldLabel = 'User Devices' + fieldName = 'cippUserDevices' + fieldType = 'WYSIWYG' + fieldTechnicianPermission = 'READ_ONLY' + fieldScriptPermission = 'NONE' + fieldApiPermission = 'READ_WRITE' + fieldContent = @{ + required = $False + advancedSettings = @{ + expandLargeValueOnRender = $True + } + } + }, + [PSCustomObject]@{ + fieldLabel = 'User Groups' + fieldName = 'cippUserGroups' + fieldType = 'WYSIWYG' + fieldTechnicianPermission = 'READ_ONLY' + fieldScriptPermission = 'NONE' + fieldApiPermission = 'READ_WRITE' + fieldContent = @{ + required = $False + advancedSettings = @{ + expandLargeValueOnRender = $True + } + } + }, + [PSCustomObject]@{ + fieldLabel = 'User ID' + fieldName = 'cippUserID' + fieldType = 'TEXT' + fieldTechnicianPermission = 'READ_ONLY' + fieldScriptPermission = 'NONE' + fieldApiPermission = 'READ_WRITE' + }, + [PSCustomObject]@{ + fieldLabel = 'User UPN' + fieldName = 'cippUserUPN' + fieldType = 'TEXT' + fieldTechnicianPermission = 'READ_ONLY' + fieldScriptPermission = 'NONE' + fieldApiPermission = 'READ_WRITE' + } + ) + } + + $NinjaOneUsersTemplate = Invoke-NinjaOneDocumentTemplate -Template $UserDocTemplate -Token $Token + + + # Get NinjaOne Users + [System.Collections.Generic.List[PSCustomObject]]$NinjaOneUserDocs = ((Invoke-WebRequest -uri "https://$($Configuration.Instance)/api/v2/organization/documents?organizationIds=$($NinjaOneOrg)&templateIds=$($NinjaOneUsersTemplate.id)" -Method GET -Headers @{Authorization = "Bearer $($token.access_token)" } -ContentType 'application/json').content | ConvertFrom-Json -depth 100) + + foreach ($NinjaDoc in $NinjaOneUserDocs) { + $ParsedFields = [pscustomobject]@{} + foreach ($Field in $NinjaDoc.Fields) { + if ($Field.value.text) { + $FieldVal = $Field.value.text + } else { + $FieldVal = $Field.value + } + $ParsedFields | Add-Member -NotePropertyName $Field.name -NotePropertyValue $FieldVal + } + $NinjaDoc | Add-Member -NotePropertyName 'ParsedFields' -NotePropertyValue $ParsedFields -Force + } + + Write-Host "Fetched NinjaOne User Docs" + } + + [System.Collections.Generic.List[PSCustomObject]]$NinjaOneLicenseDocs = @() + if ($Configuration.LicenseDocumentsEnabled) { + # NinjaOne License Documents + $LicenseDocTemplate = [PSCustomObject]@{ + name = 'CIPP - Microsoft 365 Licenses' + allowMultiple = $true + fields = @( + [PSCustomObject]@{ + fieldLabel = 'License Summary' + fieldName = 'cippLicenseSummary' + fieldType = 'WYSIWYG' + fieldTechnicianPermission = 'READ_ONLY' + fieldScriptPermission = 'NONE' + fieldApiPermission = 'READ_WRITE' + fieldContent = @{ + required = $False + advancedSettings = @{ + expandLargeValueOnRender = $True + } + } + }, + [PSCustomObject]@{ + fieldLabel = 'License Users' + fieldName = 'cippLicenseUsers' + fieldType = 'WYSIWYG' + fieldTechnicianPermission = 'READ_ONLY' + fieldScriptPermission = 'NONE' + fieldApiPermission = 'READ_WRITE' + fieldContent = @{ + required = $False + advancedSettings = @{ + expandLargeValueOnRender = $True + } + } + }, + [PSCustomObject]@{ + fieldLabel = 'License ID' + fieldName = 'cippLicenseID' + fieldType = 'TEXT' + fieldTechnicianPermission = 'READ_ONLY' + fieldScriptPermission = 'NONE' + fieldApiPermission = 'READ_WRITE' + fieldContent = @{ + required = $False + } + } + ) + } + + $NinjaOneLicenseTemplate = Invoke-NinjaOneDocumentTemplate -Template $LicenseDocTemplate -Token $Token + + # Get NinjaOne Licenses + [System.Collections.Generic.List[PSCustomObject]]$NinjaOneLicenseDocs = ((Invoke-WebRequest -uri "https://$($Configuration.Instance)/api/v2/organization/documents?organizationIds=$($NinjaOneOrg)&templateIds=$($NinjaOneLicenseTemplate.id)" -Method GET -Headers @{Authorization = "Bearer $($token.access_token)" } -ContentType 'application/json').content | ConvertFrom-Json -depth 100) + + foreach ($NinjaLic in $NinjaOneLicenseDocs) { + $ParsedFields = [pscustomobject]@{} + foreach ($Field in $NinjaLic.Fields) { + if ($Field.value.text) { + $FieldVal = $Field.value.text + } else { + $FieldVal = $Field.value + } + $ParsedFields | Add-Member -NotePropertyName $Field.name -NotePropertyValue $FieldVal + } + $NinjaLic | Add-Member -NotePropertyName 'ParsedFields' -NotePropertyValue $ParsedFields -Force + } + + Write-Host "Fetched NinjaOne License Docs" + } + + + # Create the update objects we will use to update NinjaOne + $NinjaOrgUpdate = [PSCustomObject]@{} + [System.Collections.Generic.List[PSCustomObject]]$NinjaLicenseUpdates = @() + [System.Collections.Generic.List[PSCustomObject]]$NinjaLicenseCreation = @() + + # Build bulk requests array. + [System.Collections.Generic.List[PSCustomObject]]$TenantRequests = @( + @{ + id = 'Users' + method = 'GET' + url = '/users' + }, + @{ + id = 'TenantDetails' + method = 'GET' + url = '/organization' + }, + @{ + id = 'AllRoles' + method = 'GET' + url = '/directoryRoles' + }, + @{ + id = 'RawDomains' + method = 'GET' + url = '/domains' + }, + @{ + id = 'Licenses' + method = 'GET' + url = '/subscribedSkus' + }, + @{ + id = 'Devices' + method = 'GET' + url = '/deviceManagement/managedDevices' + }, + @{ + id = 'DeviceCompliancePolicies' + method = 'GET' + url = '/deviceManagement/deviceCompliancePolicies/' + }, + @{ + id = 'DeviceApps' + method = 'GET' + url = '/deviceAppManagement/mobileApps' + }, + @{ + id = 'Groups' + method = 'GET' + url = '/groups' + }, + @{ + id = 'ConditionalAccess' + method = 'GET' + url = '/identity/conditionalAccess/policies' + }, + @{ + id = 'SecureScore' + method = 'GET' + url = '/security/secureScores' + }, + @{ + id = 'SecureScoreControlProfiles' + method = 'GET' + url = '/security/secureScoreControlProfiles' + }, + @{ + id = 'Subscriptions' + method = 'GET' + url = '/directory/subscriptions' + } + + ) + + write-verbose "$(Get-Date) - Fetching Bulk Data" + try { + $TenantResults = New-GraphBulkRequest -Requests $TenantRequests -tenantid $TenantFilter -NoAuthCheck $True + } catch { + Throw "Failed to fetch bulk company data: $_" + } + + Write-Host "Fetched Bulk M365 Data" + + $Users = Get-GraphBulkResultByID -value -Results $TenantResults -ID 'Users' + + $SecureScore = Get-GraphBulkResultByID -value -Results $TenantResults -ID 'SecureScore' + + $Subscriptions = Get-GraphBulkResultByID -value -Results $TenantResults -ID 'Subscriptions' + + [System.Collections.Generic.List[PSCustomObject]]$SecureScoreProfiles = Get-GraphBulkResultByID -value -Results $TenantResults -ID 'SecureScoreControlProfiles' + + $CurrentSecureScore = ($SecureScore | Sort-Object createDateTiime -Descending)[0] + $MaxSecureScoreRank = ($SecureScoreProfiles.rank | Measure-Object -Maximum).maximum + + $MaxSecureScore = $CurrentSecureScore.maxScore + + [System.Collections.Generic.List[PSCustomObject]]$SecureScoreParsed = Foreach ($Score in $CurrentSecureScore.controlScores) { + $MatchedProfile = $SecureScoreProfiles | Where-Object { $_.id -eq $Score.controlName } + [PSCustomObject]@{ + Category = $Score.controlCategory + 'Recommended Action' = $MatchedProfile.title + 'Score Impact' = [System.Math]::Round((((($MatchedProfile.maxScore) - ($Score.score)) / $MaxSecureScore) * 100), 2) + Link = "https://security.microsoft.com/securescore?actionId=$($Score.controlName)&viewid=actions&tid=$($Customer.customerId)" + name = $Score.controlName + score = $Score.score + IsApplicable = $Score.IsApplicable + scoreInPercentage = $Score.scoreInPercentage + maxScore = $MatchedProfile.maxScore + rank = $MatchedProfile.rank + adjustedRank = $MaxSecureScoreRank - $MatchedProfile.rank + + } + } + + $TenantDetails = Get-GraphBulkResultByID -value -Results $TenantResults -ID 'TenantDetails' + + write-verbose "$(Get-Date) - Parsing Users" + # Grab licensed users + $licensedUsers = $Users | where-object { $null -ne $_.AssignedLicenses.SkuId } | Sort-Object UserPrincipalName + + write-verbose "$(Get-Date) - Parsing Roles" + # Get All Roles + $AllRoles = Get-GraphBulkResultByID -value -Results $TenantResults -ID 'AllRoles' + + $SelectList = 'id', 'displayName', 'userPrincipalName' + + [System.Collections.Generic.List[PSCustomObject]]$RolesRequestArray = @() + foreach ($Role in $AllRoles) { + $RolesRequestArray.add(@{ + id = $Role.id + method = 'GET' + url = "/directoryRoles/$($Role.id)/members?`$select=$($selectlist -join ',')" + }) + } + + try { + $MemberReturn = New-GraphBulkRequest -Requests $RolesRequestArray -tenantid $TenantFilter -NoAuthCheck $True + } catch { + $MemberReturn = $null + } + + Write-Host "Fetched M365 Roles" + + $Roles = foreach ($Result in $MemberReturn) { + [PSCustomObject]@{ + ID = $Result.id + DisplayName = ($AllRoles | where-object { $_.id -eq $Result.id }).displayName + Description = ($AllRoles | where-object { $_.id -eq $Result.id }).description + Members = $Result.body.value + ParsedMembers = $Result.body.value.Displayname -join ', ' + } + } + + + + $AdminUsers = (($Roles | Where-Object { $_.Displayname -match "Administrator" }).Members | where-object { $null -ne $_.displayName }) + + write-verbose "$(Get-Date) - Fetching Domains" + try { + $RawDomains = Get-GraphBulkResultByID -value -Results $TenantResults -ID 'RawDomains' + } catch { + $RawDomains = $null + } + $customerDomains = ($RawDomains | Where-Object { $_.IsVerified -eq $True }).id -join ', ' | Out-String + + + write-verbose "$(Get-Date) - Parsing Licenses" + # Get Licenses + $Licenses = Get-GraphBulkResultByID -value -Results $TenantResults -ID 'Licenses' + + # Get the license overview for the tenant + if ($Licenses) { + $LicensesParsed = $Licenses | where-object { $_.PrepaidUnits.Enabled -gt 0 } | Select-Object @{N = 'License Name'; E = { (Get-Culture).TextInfo.ToTitleCase((convert-skuname -skuname $_.SkuPartNumber).Tolower()) } }, @{N = 'Active'; E = { $_.PrepaidUnits.Enabled } }, @{N = 'Consumed'; E = { $_.ConsumedUnits } }, @{N = 'Unused'; E = { $_.PrepaidUnits.Enabled - $_.ConsumedUnits } } + } + + write-verbose "$(Get-Date) - Parsing Devices" + # Get all devices from Intune + $devices = Get-GraphBulkResultByID -value -Results $TenantResults -ID 'Devices' + + write-verbose "$(Get-Date) - Parsing Device Compliance Polcies" + # Fetch Compliance Policy Status + $DeviceCompliancePolicies = Get-GraphBulkResultByID -value -Results $TenantResults -ID 'DeviceCompliancePolicies' + + # Get the status of each device for each policy + [System.Collections.Generic.List[PSCustomObject]]$PolicyRequestArray = @() + foreach ($CompliancePolicy in $DeviceCompliancePolicies) { + $PolicyRequestArray.add(@{ + id = $CompliancePolicy.id + method = 'GET' + url = "/deviceManagement/deviceCompliancePolicies/$($CompliancePolicy.id)/deviceStatuses" + }) + } + + try { + $PolicyReturn = New-GraphBulkRequest -Requests $PolicyRequestArray -tenantid $TenantFilter -NoAuthCheck $True + } catch { + $PolicyReturn = $null + } + + Write-Host "Fetched M365 Device Compliance" + + $DeviceComplianceDetails = foreach ($Result in $PolicyReturn) { + [pscustomobject]@{ + ID = ($DeviceCompliancePolicies | where-object { $_.id -eq $Result.id }).id + DisplayName = ($DeviceCompliancePolicies | where-object { $_.id -eq $Result.id }).DisplayName + DeviceStatuses = $Result.body.value + } + } + + write-verbose "$(Get-Date) - Parsing Groups" + # Fetch Groups + $AllGroups = Get-GraphBulkResultByID -value -Results $TenantResults -ID 'Groups' + + # Fetch the App status for each device + [System.Collections.Generic.List[PSCustomObject]]$GroupRequestArray = @() + foreach ($Group in $AllGroups) { + $GroupRequestArray.add(@{ + id = $Group.id + method = 'GET' + url = "/groups/$($Group.id)/members" + }) + } + + try { + $GroupMembersReturn = New-GraphBulkRequest -Requests $GroupRequestArray -tenantid $TenantFilter -NoAuthCheck $True + } catch { + $GroupMembersReturn = $null + } + + Write-Host "Fetched M365 Group Membership" + + $Groups = foreach ($Result in $GroupMembersReturn) { + [pscustomobject]@{ + ID = $Result.id + DisplayName = ($AllGroups | where-object { $_.id -eq $Result.id }).DisplayName + Members = $result.body.value + } + } + + write-verbose "$(Get-Date) - Parsing Conditional Access Polcies" + # Fetch and parse conditional access polcies + $AllConditionalAccessPolcies = Get-GraphBulkResultByID -value -Results $TenantResults -ID 'ConditionalAccess' + + $ConditionalAccessMembers = foreach ($CAPolicy in $AllConditionalAccessPolcies) { + #Setup User Array + [System.Collections.Generic.List[PSCustomObject]]$CAMembers = @() + + # Check for All Include + if ($CAPolicy.conditions.users.includeUsers -contains 'All') { + $Users | foreach-object { $null = $CAMembers.add($_.id) } + } else { + # Add any specific all users to the array + $CAPolicy.conditions.users.includeUsers | foreach-object { $null = $CAMembers.add($_) } + } + + # Now all members of groups + foreach ($CAIGroup in $CAPolicy.conditions.users.includeGroups) { + foreach ($Member in ($Groups | where-object { $_.id -eq $CAIGroup }).Members) { + $null = $CAMembers.add($Member.id) + } + } + + # Now all members of roles + foreach ($CAIRole in $CAPolicy.conditions.users.includeRoles) { + foreach ($Member in ($Roles | where-object { $_.id -eq $CAIRole }).Members) { + $null = $CAMembers.add($Member.id) + } + } + + # Parse to Unique members + $CAMembers = $CAMembers | select-object -unique + + if ($CAMembers) { + # Now remove excluded users + $CAPolicy.conditions.users.excludeUsers | foreach-object { $null = $CAMembers.remove($_) } + + # Excluded Groups + foreach ($CAEGroup in $CAPolicy.conditions.users.excludeGroups) { + foreach ($Member in ($Groups | where-object { $_.id -eq $CAEGroup }).Members) { + $null = $CAMembers.remove($Member.id) + } + } + + # Excluded Roles + foreach ($CAIRole in $CAPolicy.conditions.users.excludeRoles) { + foreach ($Member in ($Roles | where-object { $_.id -eq $CAERole }).Members) { + $null = $CAMembers.remove($Member.id) + } + } + } + + [pscustomobject]@{ + ID = $CAPolicy.id + DisplayName = $CAPolicy.DisplayName + Members = $CAMembers + } + } + + write-verbose "$(Get-Date) - Fetching One Drive Details" + try { + $OneDriveDetails = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/reports/getOneDriveUsageAccountDetail(period='D7')" -tenantid $TenantFilter | convertfrom-csv + } catch { + Write-Error "Failed to fetch Onedrive Details: $_" + $OneDriveDetails = $null + } + + write-verbose "$(Get-Date) - Fetching CAS Mailbox Details" + try { + $CASFull = New-GraphGetRequest -uri "https://outlook.office365.com/adminapi/beta/$($tenantfilter)/CasMailbox" -Tenantid $Customer.defaultDomainName -scope ExchangeOnline -noPagination $true + } catch { + Write-Error "Failed to fetch CAS Details: $_" + $CASFull = $null + } + + write-verbose "$(Get-Date) - Fetching Mailbox Details" + try { + $MailboxDetailedFull = New-ExoRequest -TenantID $Customer.defaultDomainName -cmdlet 'Get-Mailbox' + } catch { + Write-Error "Failed to fetch Mailbox Details: $_" + $MailboxDetailedFull = $null + } + + write-verbose "$(Get-Date) - Fetching Blocked Mailbox Details" + try { + $BlockedSenders = New-ExoRequest -TenantID $Customer.defaultDomainName -cmdlet 'Get-BlockedSenderAddress' + } catch { + Write-Error "Failed to fetch Blocked Sender Details: $_" + $BlockedSenders = $null + } + + write-verbose "$(Get-Date) - Fetching Mailbox Stats" + try { + $MailboxStatsFull = New-GraphGetRequest -uri "https://graph.microsoft.com/v1.0/reports/getMailboxUsageDetail(period='D7')" -tenantid $TenantFilter | convertfrom-csv + } catch { + Write-Error "Failed to fetch Mailbox Stats: $_" + $MailboxStatsFull = $null + } + + Write-Host "Fetched M365 Additional Data" + + + $FetchEnd = Get-Date + + ############################ Format and Synchronize to NinjaOne ############################ + $DeviceTable = Get-CippTable -tablename 'CacheNinjaOneParsedDevices' + $DeviceMapTable = Get-CippTable -tablename 'NinjaOneDeviceMap' + + + $DeviceFilter = "PartitionKey eq '$($Customer.CustomerId)'" + [System.Collections.Generic.List[PSCustomObject]]$RawParsedDevices = Get-CIPPAzDataTableEntity @DeviceTable -Filter $DeviceFilter + if (($RawParsedDevices | Measure-Object).count -eq 0) { + [System.Collections.Generic.List[PSCustomObject]]$ParsedDevices = @() + } else { + [System.Collections.Generic.List[PSCustomObject]]$ParsedDevices = $RawParsedDevices.RawDevice | ForEach-Object { $_ | ConvertFrom-Json -Depth 100 } + } + + [System.Collections.Generic.List[PSCustomObject]]$DeviceMap = Get-CIPPAzDataTableEntity @DeviceMapTable -Filter $DeviceFilter + if (($DeviceMap | Measure-Object).count -eq 0) { + [System.Collections.Generic.List[PSCustomObject]]$DeviceMap = @() + } + + # Parse Devices + Foreach ($Device in $Devices | Where-Object { $_.id -notin $ParsedDevices.id }) { + + # First lets match on serial + $MatchedNinjaDevice = $NinjaDevices | Where-Object { $_.system.biosSerialNumber -eq $Device.SerialNumber -or $_.system.serialNumber -eq $Device.SerialNumber } + + # See if we found just one device, if not match on name + if (($MatchedNinjaDevice | Measure-Object).count -ne 1) { + $MatchedNinjaDevice = $NinjaDevices | Where-Object { $_.systemName -eq $Device.Name -or $_.dnsName -eq $Device.Name } + } + + # Check on a match again and set name + if (($MatchedNinjaDevice | Measure-Object).count -eq 1) { + $ParsedDeviceName = '' + $Device.deviceName + '' + } else { + continue + } + + # Match Users + [System.Collections.Generic.List[String]]$DeviceUsers = @() + [System.Collections.Generic.List[String]]$DeviceUserIDs = @() + [System.Collections.Generic.List[PSCustomObject]]$DeviceUsersDetail = @() + + $MappedDevice = ($DeviceMap | Where-Object { $_.M365ID -eq $device.id }) + if (($MappedDevice | Measure-Object).count -eq 0) { + $DeviceMapItem = [PSCustomObject]@{ + PartitionKey = $Customer.CustomerId + RowKey = $device.AzureADDeviceId + NinjaOneID = $MatchedNinjaDevice.id + M365ID = $device.id + } + $DeviceMap.Add($DeviceMapItem) + Add-CIPPAzDataTableEntity @DeviceMapTable -Entity $DeviceMapItem + + } elseif ($MappedDevice.NinjaOneID -ne $MatchedNinjaDevice.id) { + $MappedDevice.NinjaOneID = $MatchedNinjaDevice.id + Add-CIPPAzDataTableEntity @DeviceMapTable -Entity $MappedDevice -Force + } + + + + + Foreach ($DeviceUser in $Device.usersloggedon) { + $FoundUser = ($Users | Where-Object { $_.id -eq $DeviceUser.userid }) + $DeviceUsers.add($FoundUser.DisplayName) + $DeviceUserIDs.add($DeviceUser.userId) + $DeviceUsersDetail.add([pscustomobject]@{ + id = $FoundUser.Id + name = $FoundUser.displayName + upn = $FoundUser.userPrincipalName + lastlogin = ($DeviceUser.lastLogOnDateTime).ToString("yyyy-MM-dd") + } + ) + } + + # Compliance Polciies + [System.Collections.Generic.List[PSCustomObject]]$DevicePolcies = @() + foreach ($Policy in $DeviceComplianceDetails) { + if ($device.deviceName -in $Policy.DeviceStatuses.deviceDisplayName) { + $Status = $Policy.DeviceStatuses | Where-Object { $_.deviceDisplayName -eq $device.deviceName } + foreach ($Stat in $Status) { + if ($Stat.status -ne 'unknown') { + $DevicePolcies.add([PSCustomObject]@{ + Name = $Policy.DisplayName + User = $Stat.username + Status = $Stat.status + 'Last Report' = "$(Get-Date($Stat.lastReportedDateTime[0]) -Format 'yyyy-MM-dd HH:mm:ss')" + 'Grace Expiry' = "$(Get-Date($Stat.complianceGracePeriodExpirationDateTime[0]) -Format 'yyyy-MM-dd HH:mm:ss')" + }) + } + } + + } + } + + # Device Groups + $DeviceGroups = foreach ($Group in $Groups) { + if ($device.azureADDeviceId -in $Group.members.deviceId) { + [PSCustomObject]@{ + Name = $Group.displayName + } + } + } + + $ParsedDevice = [PSCustomObject]@{ + PartitionKey = $Customer.CustomerId + RowKey = $device.AzureADDeviceId + id = $Device.id + Name = $Device.deviceName + SerialNumber = $Device.serialNumber + OS = $Device.operatingSystem + OSVersion = $Device.osversion + Enrolled = $Device.enrolledDateTime + Compliance = $Device.complianceState + LastSync = $Device.lastSyncDateTime + PrimaryUser = $Device.userDisplayName + Owner = $Device.ownerType + DeviceType = $Device.DeviceType + Make = $Device.make + Model = $Device.model + ManagementState = $Device.managementState + RegistrationState = $Device.deviceRegistrationState + JailBroken = $Device.jailBroken + EnrollmentType = $Device.deviceEnrollmentType + EntraIDRegistration = $Device.azureADRegistered + EntraIDID = $Device.azureADDeviceId + JoinType = $Device.joinType + SecurityPatchLevel = $Device.securityPatchLevel + Users = $DeviceUsers -join ', ' + UserIDs = $DeviceUserIDs + UserDetails = $DeviceUsersDetail + CompliancePolicies = $DevicePolcies + Groups = $DeviceGroups + NinjaDevice = $MatchedNinjaDevice + DeviceLink = $ParsedDeviceName + } + + Add-CIPPAzDataTableEntity @DeviceTable -Entity @{ + PartitionKey = $Customer.CustomerId + RowKey = $device.AzureADDeviceId + RawDevice = "$($ParsedDevice | ConvertTo-Json -Depth 100 -compress)" + } + + $ParsedDevices.add($ParsedDevice) + + ### Update NinjaOne Device Fields + if ($MatchedNinjaDevice) { + $NinjaDeviceUpdate = [PSCustomObject]@{} + if ($MappedFields.DeviceLinks) { + $DeviceLinksData = @( + @{ + Name = 'Entra ID' + Link = "https://entra.microsoft.com/$($Customer.defaultDomainName)/#view/Microsoft_AAD_Devices/DeviceDetailsMenuBlade/~/Properties/deviceId/$($Device.azureADDeviceId)/deviceId/" + Icon = 'fab fa-microsoft' + }, + @{ + Name = 'Intune (Devices)' + Link = "https://intune.microsoft.com/$($Customer.defaultDomainName)/#view/Microsoft_Intune_Devices/DeviceSettingsMenuBlade/~/overview/mdmDeviceId/$($Device.id)" + Icon = 'fas fa-laptop' + }, + @{ + Name = 'View Devices in CIPP' + Link = "https://$($CIPPURL)/endpoint/reports/devices?customerId=$($Customer.defaultDomainName)" + Icon = 'far fa-eye' + } + ) + + + + $DeviceLinksHTML = Get-NinjaOneLinks -Data $DeviceLinksData -SmallCols 2 -MedCols 3 -LargeCols 3 -XLCols 3 + + $DeviceLinksHtml = '
' + $DeviceLinksHTML + '
' + + $NinjaDeviceUpdate | Add-Member -NotePropertyName $MappedFields.DeviceLinks -NotePropertyValue @{'html' = $DeviceLinksHtml } + + + } + + if ($MappedFields.DeviceSummary) { + + # Set Compliance Status + if ($Device.complianceState -eq 'compliant') { + $Compliance = '   Compliant' + } else { + $Compliance = '   Not Compliant' + } + + # Device Details + $DeviceDetailsData = [PSCustomObject]@{ + 'Device Name' = $Device.deviceName + 'Primary User' = $Device.userDisplayName + 'Primary User Email' = $Device.userPrincipalName + 'Owner' = $Device.ownerType + 'Enrolled' = $Device.enrolledDateTime + 'Last Checkin' = $Device.lastSyncDateTime + 'Compliant' = $Compliance + 'Management Type' = $Device.managementAgent + } + + $DeviceDetailsCard = Get-NinjaOneInfoCard -Title "Device Details" -Data $DeviceDetailsData -Icon 'fas fa-laptop' + + # Device Hardware + $DeviceHardwareData = [PSCustomObject]@{ + 'Serial Number' = $Device.serialNumber + 'OS' = $Device.operatingSystem + 'OS Versions' = $Device.osVersion + 'Chassis' = $Device.chassisType + 'Model' = $Device.model + 'Manufacturer' = $Device.manufacturer + } + + $DeviceHardwareCard = Get-NinjaOneInfoCard -Title "Device Details" -Data $DeviceHardwareData -Icon 'fas fa-microchip' + + # Device Enrollment + $DeviceEnrollmentData = [PSCustomObject]@{ + 'Enrollment Type' = $Device.deviceEnrollmentType + 'Join Type' = $Device.joinType + 'Registration State' = $Device.deviceRegistrationState + 'Autopilot Enrolled' = $Device.autopilotEnrolled + 'Device Guard Requirements' = $Device.hardwareinformation.deviceGuardVirtualizationBasedSecurityHardwareRequirementState + 'Virtualistation Based Security' = $Device.hardwareinformation.deviceGuardVirtualizationBasedSecurityState + 'Credential Guard' = $Device.hardwareinformation.deviceGuardLocalSystemAuthorityCredentialGuardState + } + + $DeviceEnrollmentCard = Get-NinjaOneInfoCard -Title "Device Enrollment" -Data $DeviceEnrollmentData -Icon 'fas fa-table-list' + + + # Compliance Policies + $DevicePoliciesFormatted = $DevicePolcies | ConvertTo-Html -As Table -Fragment + $DevicePoliciesHTML = ([System.Web.HttpUtility]::HtmlDecode($DevicePoliciesFormatted) -replace '
', '') -replace '', '' + $TitleLink = "https://intune.microsoft.com/$($Customer.defaultDomainName)/#view/Microsoft_Intune_Devices/DeviceSettingsMenuBlade/~/compliance/mdmDeviceId/$($Device.id)/primaryUserId/" + $DeviceCompliancePoliciesCard = Get-NinjaOneCard -Title 'Device Compliance Policies' -Body $DevicePoliciesHTML -Icon 'fas fa-list-check' -TitleLink $TitleLink + + # Device Groups + $DeviceGroupsTable = foreach ($Group in $Groups) { + if ($device.azureADDeviceId -in $Group.members.deviceId) { + [PSCustomObject]@{ + Name = $Group.displayName + } + } + } + $DeviceGroupsFormatted = $DeviceGroupsTable | ConvertTo-Html -Fragment + $DeviceGroupsHTML = ([System.Web.HttpUtility]::HtmlDecode($DeviceGroupsFormatted) -replace '', '') -replace '', '' + $DeviceGroupsCard = Get-NinjaOneCard -Title 'Device Groups' -Body $DeviceGroupsHTML -Icon 'fas fa-layer-group' + + $DeviceSummaryHTML = '
' + + '
' + $DeviceDetailsCard + + '
' + $DeviceHardwareCard + + '
' + $DeviceEnrollmentCard + + '
' + $DeviceCompliancePoliciesCard + + '
' + $DeviceGroupsCard + + '
' + + $NinjaDeviceUpdate | Add-Member -NotePropertyName $MappedFields.DeviceSummary -NotePropertyValue @{'html' = $DeviceSummaryHTML } + } + } + + if ($MappedFields.DeviceCompliance) { + if ($Device.complianceState -eq 'compliant') { + $Compliant = 'Compliant' + } else { + $Compliant = 'Non-Compliant' + } + $NinjaDeviceUpdate | Add-Member -NotePropertyName $MappedFields.DeviceCompliance -NotePropertyValue $Compliant + + } + + # Update Device + if ($MappedFields.DeviceSummary -or $MappedFields.DeviceLinks -or $MappedFields.DeviceCompliance) { + $Result = Invoke-WebRequest -uri "https://$($Configuration.Instance)/api/v2/device/$($MatchedNinjaDevice.id)/custom-fields" -Method PATCH -Headers @{Authorization = "Bearer $($token.access_token)" } -ContentType 'application/json' -Body ($NinjaDeviceUpdate | ConvertTo-Json -Depth 100) + } + } + + # Enable Device Updates Subscription if needed. + if ($MappedFields.DeviceCompliance) { + New-CIPPGraphSubscription -TenantFilter $TenantFilter -TypeofSubscription 'updated' -BaseURL $CIPPUrl -Resource 'devices' -EventType 'DeviceUpdate' -ExecutingUser 'NinjaOneSync' + } + + Write-Host "Processed Devices" + + + ########## Create / Update User Objects + + if ($Configuration.LicensedOnly -eq $True) { + $SyncUsers = $licensedUsers + } else { + $SyncUsers = $Users + } + + + $UsersTable = Get-CippTable -tablename 'CacheNinjaOneParsedUsers' + $UsersUpdateTable = Get-CippTable -tablename 'CacheNinjaOneUsersUpdate' + $UsersMapTable = Get-CippTable -tablename 'NinjaOneUserMap' + + + $UsersFilter = "PartitionKey eq '$($Customer.CustomerId)'" + [System.Collections.Generic.List[PSCustomObject]]$ParsedUsers = Get-CIPPAzDataTableEntity @UsersTable -Filter $UsersFilter + if (($ParsedUsers | Measure-Object).count -eq 0) { + [System.Collections.Generic.List[PSCustomObject]]$ParsedUsers = @() + } + + [System.Collections.Generic.List[PSCustomObject]]$NinjaUserCache = Get-CIPPAzDataTableEntity @UsersUpdateTable -Filter $UsersFilter + if (($NinjaUserCache | Measure-Object).count -eq 0) { + [System.Collections.Generic.List[PSCustomObject]]$NinjaUserCache = @() + } + + [System.Collections.Generic.List[PSCustomObject]]$UsersMap = Get-CIPPAzDataTableEntity @UsersMapTable -Filter $UsersFilter + if (($UsersMap | Measure-Object).count -eq 0) { + [System.Collections.Generic.List[PSCustomObject]]$UsersMap = @() + } + + [System.Collections.Generic.List[PSCustomObject]]$NinjaUserUpdates = $NinjaUserCache | Where-Object { $_.action -eq 'Update' } + if (($NinjaUserUpdates | Measure-Object).count -eq 0) { + [System.Collections.Generic.List[PSCustomObject]]$NinjaUserUpdates = @() + } + + [System.Collections.Generic.List[PSCustomObject]]$NinjaUserCreation = $NinjaUserCache | Where-Object { $_.action -eq 'Create' } + if (($NinjaUserCreation | Measure-Object).count -eq 0) { + [System.Collections.Generic.List[PSCustomObject]]$NinjaUserCreation = @() + } + + + foreach ($user in $SyncUsers | where-object { $_.id -notin $ParsedUsers.RowKey }) { + try { + + $NinjaOneUser = $NinjaOneUserDocs | Where-Object { $_.ParsedFields.cippUserID -eq $User.ID } + if (($NinjaOneUser | Measure-Object).count -gt 1) { + Throw "Multiple Users with the same ID found" + } + + + $UserGroups = foreach ($Group in $Groups) { + if ($User.id -in $Group.Members.id) { + $FoundGroup = $AllGroups | Where-Object { $_.id -eq $Group.id } + [PSCustomObject]@{ + 'Display Name' = $FoundGroup.displayName + 'Mail Enabled' = $FoundGroup.mailEnabled + 'Mail' = $FoundGroup.mail + 'Security Group' = $FoundGroup.securityEnabled + 'Group Types' = $FoundGroup.groupTypes -join ',' + } + } + } + + + $UserPolicies = foreach ($cap in $ConditionalAccessMembers) { + if ($User.id -in $Cap.Members) { + $temp = [PSCustomObject]@{ + displayName = $cap.displayName + } + $temp + } + } + + + #$PermsRequest = '' + $StatsRequest = '' + $MailboxDetailedRequest = '' + $CASRequest = '' + + $CASRequest = $CASFull | Where-Object { $_.ExternalDirectoryObjectId -eq $User.iD } + $MailboxDetailedRequest = $MailboxDetailedFull | Where-Object { $_.ExternalDirectoryObjectId -eq $User.iD } + $StatsRequest = $MailboxStatsFull | Where-Object { $_.'User Principal Name' -eq $User.UserPrincipalName } + + #try { + # $PermsRequest = New-GraphGetRequest -uri "https://outlook.office365.com/adminapi/beta/$($tenantfilter)/Mailbox('$($User.ID)')/MailboxPermission" -Tenantid $tenantfilter -scope ExchangeOnline -noPagination $true -NoAuthCheck $True + #} catch { + # $PermsRequest = $null + #} + + #$ParsedPerms = foreach ($Perm in $PermsRequest) { + # if ($Perm.User -ne 'NT AUTHORITY\SELF') { + # [pscustomobject]@{ + # User = $Perm.User + # AccessRights = $Perm.PermissionList.AccessRights -join ', ' + # } + # } + #} + + try { + $TotalItemSize = [math]::Round($StatsRequest.'Storage Used (Byte)' / 1Gb, 2) + } catch { + $TotalItemSize = 0 + } + + $UserMailSettings = [pscustomobject]@{ + ForwardAndDeliver = $MailboxDetailedRequest.DeliverToMailboxAndForward + ForwardingAddress = $MailboxDetailedRequest.ForwardingAddress + ' ' + $MailboxDetailedRequest.ForwardingSmtpAddress + LitiationHold = $MailboxDetailedRequest.LitigationHoldEnabled + HiddenFromAddressLists = $MailboxDetailedRequest.HiddenFromAddressListsEnabled + EWSEnabled = $CASRequest.EwsEnabled + MailboxMAPIEnabled = $CASRequest.MAPIEnabled + MailboxOWAEnabled = $CASRequest.OWAEnabled + MailboxImapEnabled = $CASRequest.ImapEnabled + MailboxPopEnabled = $CASRequest.PopEnabled + MailboxActiveSyncEnabled = $CASRequest.ActiveSyncEnabled + #Permissions = $ParsedPerms + ProhibitSendQuota = [math]::Round([float]($MailboxDetailedRequest.ProhibitSendQuota -split ' GB')[0], 2) + ProhibitSendReceiveQuota = [math]::Round([float]($MailboxDetailedRequest.ProhibitSendReceiveQuota -split ' GB')[0], 2) + ItemCount = [math]::Round($StatsRequest.'Item Count', 2) + TotalItemSize = $TotalItemSize + } + + + $UserDevicesDetailsRaw = $ParsedDevices | where-object { $User.id -in $_.UserIDS } + + + $UserDevices = foreach ($UserDevice in $ParsedDevices | where-object { $User.id -in $_.UserIDS }) { + + $MatchedNinjaDevice = $UserDevice.NinjaDevice + $ParsedDeviceName = $UserDevice.DeviceLink + + # Set Last Login Time + $LastLoginTime = ($UserDevice.UserDetails | where-object { $_.id -eq $User.id }).lastLogin + if (!$LastLoginTime) { + $LastLoginTime = 'Unknown' + } + + # Set Compliance Status + if ($UserDevice.Compliance -eq 'compliant') { + $ComplianceIcon = '' + } else { + $ComplianceIcon = '' + } + + # OS Icon + $OSIcon = Switch ($UserDevice.OS) { + 'Windows' { '' } + 'iOS' { '' } + 'Android' { '' } + 'macOS' { '' } + } + + '
  • ' + "$ComplianceIcon $OSIcon $($ParsedDeviceName) ($LastLoginTime)
  • " + + } + + + $aliases = (($user.ProxyAddresses | Where-Object { $_ -cnotmatch 'SMTP' -and $_ -notmatch '.onmicrosoft.com' }) -replace 'SMTP:', ' ') -join ', ' + + + $userLicenses = ($user.AssignedLicenses.SkuID | ForEach-Object { + $UserLic = $_ + try { + $SkuPartNumber = ($Licenses | Where-Object { $_.SkuId -eq $UserLic }).SkuPartNumber + '
  • ' + "$((Get-Culture).TextInfo.ToTitleCase((convert-skuname -skuname $SkuPartNumber).Tolower()))
  • " + } catch {} + }) -join '' + + + + $UserOneDriveStats = $OneDriveDetails | where-object { $_.'Owner Principal Name' -eq $User.userPrincipalName } | Select-Object -First 1 + $UserOneDriveUse = $UserOneDriveStats.'Storage Used (Byte)' / 1GB + $UserOneDriveTotal = $UserOneDriveStats.'Storage Allocated (Byte)' / 1GB + + if ($UserOneDriveTotal) { + $OneDriveUse = [PSCustomObject]@{ + Enabled = $True + Used = $UserOneDriveUse + Total = $UserOneDriveTotal + Percent = ($UserOneDriveUse / $UserOneDriveTotal) * 100 + } + + $OneDriveUseColor = if ($OneDriveUse.Percent -ge 95) { + '#D53948' + } elseif ($MailboxUse.Percent -ge 85) { + '#FFA500' + } else { + '#26A644' + } + + $OneDriveParsed = '
    ' + + } else { + $OneDriveUse = [PSCustomObject]@{ + Enabled = $False + Used = 0 + Total = 0 + Percent = 0 + } + + $OneDriveParsed = 'Not Enabled' + } + + + if ($UserOneDriveStats) { + $OneDriveCardData = [PSCustomObject]@{ + 'One Drive URL' = '' + ($UserOneDriveStats.'Site URL') + '' + 'Is Deleted' = "$($UserOneDriveStats.'Is Deleted')" + 'Last Activity Date' = "$($UserOneDriveStats.'Last Activity Date')" + 'File Count' = "$($UserOneDriveStats.'File Count')" + 'Active File Count' = "$($UserOneDriveStats.'Active File Count')" + 'Storage Used (Byte)' = "$($UserOneDriveStats.'Storage Used (Byte)')" + 'Storage Allocated (Byte)' = "$($UserOneDriveStats.'Storage Allocated (Byte)')" + 'One Drive Usage' = $OneDriveParsed + + } + } else { + $OneDriveCardData = [PSCustomObject]@{ + 'One Drive' = 'Disabled' + } + } + + + $UserMailboxStats = $MailboxStatsFull | where-object { $_.'User Principal Name' -eq $User.userPrincipalName } | Select-Object -First 1 + $UserMailUse = $UserMailboxStats.'Storage Used (Byte)' / 1GB + $UserMailTotal = $UserMailboxStats.'Prohibit Send/Receive Quota (Byte)' / 1GB + + + if ($UserMailTotal) { + $MailboxUse = [PSCustomObject]@{ + Enabled = $True + Used = $UserMailUse + Total = $UserMailTotal + Percent = ($UserMailUse / $UserMailTotal) * 100 + } + + $MailboxUseColor = if ($MailboxUse.Percent -ge 95) { + '#D53948' + } elseif ($MailboxUse.Percent -ge 85) { + '#FFA500' + } else { + '#26A644' + } + + $MailboxParsed = '
    ' + + } else { + $MailboxUse = [PSCustomObject]@{ + Enabled = $False + Used = 0 + Total = 0 + Percent = 0 + } + + $MailboxParsed = 'Not Enabled' + } + + + if ($UserMailSettings.ProhibitSendQuota) { + $MailboxDetailsCardData = [PSCustomObject]@{ + #'Permissions' = "$($UserMailSettings.Permissions | ConvertTo-Html -Fragment | Out-String)" + 'Prohibit Send Quota' = "$($UserMailSettings.ProhibitSendQuota)" + 'Prohibit Send Receive Quota' = "$($UserMailSettings.ProhibitSendReceiveQuota)" + 'Item Count' = "$($UserMailSettings.ProhibitSendReceiveQuota)" + 'Total Mailbox Size' = "$($UserMailSettings.ItemCount)" + 'Mailbox Usage' = $MailboxParsed + } + + $MailboxSettingsCard = [PSCustomObject]@{ + 'Forward and Deliver' = "$($UserMailSettings.ForwardAndDeliver)" + 'Forwarding Address' = "$($UserMailSettings.ForwardingAddress)" + 'Litiation Hold' = "$($UserMailSettings.LitiationHold)" + 'Hidden From Address Lists' = "$($UserMailSettings.HiddenFromAddressLists)" + 'EWS Enabled' = "$($UserMailSettings.EWSEnabled)" + 'MAPI Enabled' = "$($UserMailSettings.MailboxMAPIEnabled)" + 'OWA Enabled' = "$($UserMailSettings.MailboxOWAEnabled)" + 'IMAP Enabled' = "$($UserMailSettings.MailboxImapEnabled)" + 'POP Enabled' = "$($UserMailSettings.MailboxPopEnabled)" + 'Active Sync Enabled' = "$($UserMailSettings.MailboxActiveSyncEnabled)" + } + } else { + $MailboxDetailsCardData = [PSCustomObject]@{ + Exchange = 'Disabled' + } + $MailboxSettingsCard = [PSCustomObject]@{ + Exchange = 'Disabled' + } + } + + + # Format Conditional Access Polcies + $UserPoliciesFormatted = '
      ' + foreach ($Policy in $UserPolicies) { + $UserPoliciesFormatted = $UserPoliciesFormatted + "
    • $($Policy.displayName)
    • " + } + $UserPoliciesFormatted = $UserPoliciesFormatted + '
    ' + + + $UserOverviewCard = [PSCustomObject]@{ + 'User Name' = "$($User.displayName)" + 'User Principal Name' = "$($User.userPrincipalName)" + 'User ID' = "$($User.ID)" + 'User Enabled' = "$($User.accountEnabled)" + 'Job Title' = "$($User.jobTitle)" + 'Mobile Phone' = "$($User.mobilePhone)" + 'Business Phones' = "$($User.businessPhones -join ', ')" + 'Office Location' = "$($User.officeLocation)" + 'Aliases' = "$aliases" + 'Licenses' = "$($userLicenses)" + } + + + $Microsoft365UserLinksData = @( + @{ + Name = 'Entra ID' + Link = "https://aad.portal.azure.com/$($Customer.defaultDomainName)/#blade/Microsoft_AAD_IAM/UserDetailsMenuBlade/Profile/userId/$($User.id)" + Icon = 'fas fa-users-cog' + }, + @{ + Name = 'Sign-In Logs' + Link = "https://aad.portal.azure.com/$($Customer.defaultDomainName)/#blade/Microsoft_AAD_IAM/UserDetailsMenuBlade/SignIns/userId/$($User.id)" + Icon = 'fas fa-users-cog' + }, + @{ + Name = 'Teams Admin' + Link = "https://admin.teams.microsoft.com/users/$($User.id)/account?delegatedOrg=$($Customer.defaultDomainName)" + Icon = 'fas fa-users' + }, + @{ + Name = 'Intune (User)' + Link = "https://endpoint.microsoft.com/$($Customer.defaultDomainName)/#blade/Microsoft_AAD_IAM/UserDetailsMenuBlade/Profile/userId/$($User.ID)" + Icon = 'fas fa-laptop' + }, + @{ + Name = 'Intune (Devices)' + Link = "https://endpoint.microsoft.com/$($Customer.defaultDomainName)/#blade/Microsoft_AAD_IAM/UserDetailsMenuBlade/Devices/userId/$($User.ID)" + Icon = 'fas fa-laptop' + } + ) + + $CIPPUserLinksData = @( + @{ + Name = 'View User' + Link = "https://$($CIPPURL)/identity/administration/users/view?userId=$($User.id)&tenantDomain=$($Customer.defaultDomainName)" + Icon = 'far fa-eye' + }, + @{ + Name = 'Edit User' + Link = "https://$($CIPPURL)/identity/administration/users/edit?userId=$($User.id)&tenantDomain=$($Customer.defaultDomainName)" + Icon = 'fas fa-users-cog' + }, + @{ + Name = 'Research Compromise' + Link = "https://$($CIPPURL)/identity/administration/ViewBec?userId=$($User.id)&tenantDomain=$($Customer.defaultDomainName)" + Icon = 'fas fa-user-secret' + } + ) + + # Actions + $ActionsHTML = @" +   +   +"@ + + + # Return Data for Users Summary Table + $ParsedUser = [PSCustomObject]@{ + PartitionKey = "$($Customer.CustomerId)" + RowKey = "$($User.id)" + Name = "$($User.displayName)" + UPN = "$($User.userPrincipalName)" + Aliases = "$(($User.proxyAddresses -replace 'SMTP:', '') -join ', ')" + Licenses = "
      $userLicenses
    " + Mailbox = "$($MailboxUse)" + MailboxParsed = "$($MailboxParsed)" + OneDrive = "$($OneDriveUse)" + OneDriveParsed = "$($OneDriveParsed)" + Devices = "
      $($UserDevices -join '')
    " + Actions = "$($ActionsHTML)" + } + + + Add-CIPPAzDataTableEntity @UsersTable -Entity $ParsedUser + $ParsedUsers.add($ParsedUser) + + + if ($Configuration.UserDocumentsEnabled -eq $True) { + + # Format into Ninja HTML + # Links + $M365UserLinksHTML = Get-NinjaOneLinks -Data $Microsoft365UserLinksData -Title 'Portals' -SmallCols 2 -MedCols 3 -LargeCols 3 -XLCols 3 + $CIPPUserLinksHTML = Get-NinjaOneLinks -Data $CIPPUserLinksData -Title 'CIPP Links' -SmallCols 2 -MedCols 3 -LargeCols 3 -XLCols 3 + $UserLinksHTML = '
    ' + $M365UserLinksHTML + '
    ' + $CIPPUserLinksHTML + '
    ' + + + # UsersSummaryCards: + $UserOverviewCardHTML = Get-NinjaOneInfoCard -Title "User Details" -Data $UserOverviewCard -Icon 'fas fa-user' + $MailboxDetailsCardHTML = Get-NinjaOneInfoCard -Title "Mailbox Details" -Data $MailboxDetailsCardData -Icon 'fas fa-envelope' + $MailboxSettingsCardHTML = Get-NinjaOneInfoCard -Title "Mailbox Settings" -Data $MailboxSettingsCard -Icon 'fas fa-envelope' + $OneDriveCardHTML = Get-NinjaOneInfoCard -Title "OneDrive Details" -Data $OneDriveCardData -Icon 'fas fa-envelope' + $UserPolciesCard = Get-NinjaOneCard -Title "Assigned Conditional Access Policies" -Body $UserPoliciesFormatted + + + $UserSummaryHTML = '
    ' + + '
    ' + $UserOverviewCardHTML + + '
    ' + $MailboxDetailsCardHTML + + '
    ' + $MailboxSettingsCardHTML + + '
    ' + $OneDriveCardHTML + + '
    ' + $UserPolciesCard + + '
    ' + $DeviceSummaryCardHTML + + '
    ' + + + $UserDeviceDetailsTable = $UserDevicesDetailsRaw | Select-Object @{N = 'Name'; E = { $_.DeviceLink } }, + @{n = 'Enrolled'; e = { $_.Enrolled } }, + @{n = 'Last Sync'; e = { $_.LastSync } }, + @{n = 'OS'; e = { $_.OS } }, + @{n = 'OS Version'; e = { $_.OSVersion } }, + @{n = 'State'; e = { $_.Compliance } }, + @{n = 'Model'; e = { $_.Model } }, + @{n = 'Manufacturer'; e = { $_.Make } } + + $UserDeviceDetailHTML = $UserDeviceDetailsTable | ConvertTo-Html -As Table -Fragment + $UserDeviceDetailHTML = ([System.Web.HttpUtility]::HtmlDecode($UserDeviceDetailHTML) -replace '
    ', '') -replace '', '' + + + $UserFields = @{ + cippUserLinks = @{'html' = $UserLinksHTML } + cippUserSummary = @{'html' = $UserSummaryHTML } + cippUserGroups = @{'html' = "$($UserGroups | ConvertTo-HTML -As Table -Fragment)" } + cippUserDevices = @{'html' = $UserDeviceDetailHTML } + cippUserID = $User.id + cippUserUPN = $User.userPrincipalName + } + + + if ($NinjaOneUser) { + $UpdateObject = [PSCustomObject]@{ + PartitionKey = $Customer.CustomerId + RowKey = $User.id + Action = 'Update' + Body = "$(@{ + documentId = $NinjaOneUser.documentId + documentName = "$($User.displayName) ($($User.userPrincipalName))" + fields = $UserFields + } | ConvertTo-Json -Depth 100)" + } + $NinjaUserUpdates.Add($UpdateObject) + Add-CIPPAzDataTableEntity @UsersUpdateTable -Entity $UpdateObject + + } else { + $CreateObject = [PSCustomObject]@{ + PartitionKey = $Customer.CustomerId + RowKey = $User.id + Action = 'Create' + Body = "$(@{ + documentName = "$($User.displayName) ($($User.userPrincipalName))" + documentTemplateId = ($NinjaOneUsersTemplate.id) + organizationId = [int]$NinjaOneOrg + fields = $UserFields + } | ConvertTo-Json -Depth 100)" + } + $NinjaUserCreation.Add($CreateObject) + Add-CIPPAzDataTableEntity @UsersUpdateTable -Entity $CreateObject + } + + + $CreatedUsers = $Null + $UpdatedUsers = $Null + + try { + # Create New Users + if (($NinjaUserCreation | Measure-Object).count -ge 100) { + Write-Host "Creating NinjaOne Users" + $CreatedUsers = (Invoke-WebRequest -uri "https://$($Configuration.Instance)/api/v2/organization/documents" -Method POST -Headers @{Authorization = "Bearer $($token.access_token)" } -ContentType 'application/json' -Body ("[$($NinjaUserCreation.body -join ',')]") -EA Stop).content | ConvertFrom-Json -Depth 100 + Remove-AzDataTableEntity @UsersUpdateTable -Entity $NinjaUserCreation + [System.Collections.Generic.List[PSCustomObject]]$NinjaUserCreation = @() + } + } Catch { + Write-Host "Bulk Creation Error, but may have been successful as only 1 record with an issue could have been the cause: $_" + } + + try { + # Update Users + if (($NinjaUserUpdates | Measure-Object).count -ge 100) { + Write-Host "Updating NinjaOne Users" + $UpdatedUsers = (Invoke-WebRequest -uri "https://$($Configuration.Instance)/api/v2/organization/documents" -Method PATCH -Headers @{Authorization = "Bearer $($token.access_token)" } -ContentType 'application/json' -Body ("[$($NinjaUserUpdates.body -join ',')]") -EA Stop).content | ConvertFrom-Json -Depth 100 + Remove-AzDataTableEntity @UsersUpdateTable -Entity $NinjaUserUpdates + [System.Collections.Generic.List[PSCustomObject]]$NinjaUserUpdates = @() + } + } Catch { + Write-Host "Bulk Update Errored, but may have been successful as only 1 record with an issue could have been the cause: $_" + } + + + $UserDocResults = $UpdatedUsers + $CreatedUsers + + if (($UserDocResults | Where-Object { $Null -ne $_ -and $_ -ne '' } | Measure-Object).count -ge 1) { + $UserDocResults | Where-Object { $Null -ne $_ -and $_ -ne '' } | ForEach-Object { + $UserDoc = $_ + if ($UserDoc.updatedFields) { + $Field = $UserDoc.updatedFields | Where-Object { $_.name -eq 'cippUserID' } + } else { + $Field = $UserDoc.fields | Where-Object { $_.name -eq 'cippUserID' } + } + + if ($Null -ne $Field.value -and $Field.value -ne '') { + + $MappedUser = ($UsersMap | Where-Object { $_.M365ID -eq $Field.value }) + if (($MappedUser | Measure-Object).count -eq 0) { + $UserMapItem = [PSCustomObject]@{ + PartitionKey = $Customer.CustomerId + RowKey = $Field.value + NinjaOneID = $UserDoc.documentId + M365ID = $Field.value + } + $UsersMap.Add($UserMapItem) + Add-CIPPAzDataTableEntity @UsersMapTable -Entity $UserMapItem + + } elseif ($MappedUser.NinjaOneID -ne $UserDoc.documentId) { + $MappedUser.NinjaOneID = $UserDoc.documentId + Add-CIPPAzDataTableEntity @UsersMapTable -Entity $MappedUser -Force + } + } else { + Write-Error "Unmatched Doc: $($UserDoc | convertto-json -depth 100)" + } + + } + + } + + + } + } catch { + Write-Error "User $($User.UserPrincipalName): A fatal error occured while processing user $_" + } + + } + + + + $CreatedUsers = $Null + $UpdatedUsers = $Null + + if ($Configuration.UserDocumentsEnabled -eq $True) { + try { + # Create New Users + if (($NinjaUserCreation | Measure-Object).count -ge 1) { + Write-Host "Creating NinjaOne Users" + $CreatedUsers = (Invoke-WebRequest -uri "https://$($Configuration.Instance)/api/v2/organization/documents" -Method POST -Headers @{Authorization = "Bearer $($token.access_token)" } -ContentType 'application/json' -Body ("[$($NinjaUserCreation.body -join ',')]") -EA Stop).content | ConvertFrom-Json -Depth 100 + Remove-AzDataTableEntity @UsersUpdateTable -Entity $NinjaUserCreation + + } + } Catch { + Write-Host "Bulk Creation Error, but may have been successful as only 1 record with an issue could have been the cause: $_" + } + + try { + # Update Users + if (($NinjaUserUpdates | Measure-Object).count -ge 1) { + Write-Host "Updating NinjaOne Users" + $UpdatedUsers = (Invoke-WebRequest -uri "https://$($Configuration.Instance)/api/v2/organization/documents" -Method PATCH -Headers @{Authorization = "Bearer $($token.access_token)" } -ContentType 'application/json' -Body ("[$($NinjaUserUpdates.body -join ',')]") -EA Stop).content | ConvertFrom-Json -Depth 100 + Remove-AzDataTableEntity @UsersUpdateTable -Entity $NinjaUserUpdates + } + } Catch { + Write-Host "Bulk Update Errored, but may have been successful as only 1 record with an issue could have been the cause: $_" + } + + ### Relationship Mapping + # Parse out the NinjaOne ID to MS ID + + + $UserDocResults = $UpdatedUsers + $CreatedUsers + + if (($UserDocResults | Where-Object { $Null -ne $_ -and $_ -ne '' } | Measure-Object).count -ge 1) { + $UserDocResults | Where-Object { $Null -ne $_ -and $_ -ne '' } | ForEach-Object { + $UserDoc = $_ + if ($UserDoc.updatedFields) { + $Field = $UserDoc.updatedFields | Where-Object { $_.name -eq 'cippUserID' } + } else { + $Field = $UserDoc.fields | Where-Object { $_.name -eq 'cippUserID' } + } + + if ($Null -ne $Field.value -and $Field.value -ne '') { + + $MappedUser = ($UsersMap | Where-Object { $_.M365ID -eq $Field.value }) + if (($MappedUser | Measure-Object).count -eq 0) { + $UserMapItem = [PSCustomObject]@{ + PartitionKey = $Customer.CustomerId + RowKey = $Field.value + NinjaOneID = $UserDoc.documentId + M365ID = $Field.value + } + $UsersMap.Add($UserMapItem) + Add-CIPPAzDataTableEntity @UsersMapTable -Entity $UserMapItem + + } elseif ($MappedUser.NinjaOneID -ne $UserDoc.documentId) { + $MappedUser.NinjaOneID = $UserDoc.documentId + Add-CIPPAzDataTableEntity @UsersMapTable -Entity $MappedUser -Force + } + } else { + Write-Error "Unmatched Doc: $($UserDoc | convertto-json -depth 100)" + } + + } + } + + + # Relate Users to Devices + Foreach ($LinkDevice in $ParsedDevices | Where-Object { $null -ne $_.NinjaDevice }) { + $RelatedItems = (Invoke-WebRequest -uri "https://$($Configuration.Instance)/api/v2/related-items/with-entity/NODE/$($LinkDevice.NinjaDevice.id)" -Method GET -Headers @{Authorization = "Bearer $($token.access_token)" } -ContentType 'application/json').content | ConvertFrom-Json -depth 100 + [System.Collections.Generic.List[PSCustomObject]]$Relations = @() + Foreach ($LinkUser in $LinkDevice.UserIDs) { + $MatchedUser = $UsersMap | Where-Object { $_.M365ID -eq $LinkUser } + if (($MatchedUser | Measure-Object).count -eq 1) { + $ExistingRelation = $RelatedItems | Where-Object { $_.relEntityType -eq 'DOCUMENT' -and $_.relEntityId -eq $MatchedUser.NinjaOneID } + if (!$ExistingRelation) { + $Relations.Add( + [PSCustomObject]@{ + relEntityType = "DOCUMENT" + relEntityId = $MatchedUser.NinjaOneID + } + ) + } + } + } + + + + try { + # Update Relations + if (($Relations | Measure-Object).count -ge 1) { + Write-Host "Updating Relations" + $Null = Invoke-WebRequest -uri "https://$($Configuration.Instance)/api/v2/related-items/entity/NODE/$($LinkDevice.NinjaDevice.id)/relations" -Method POST -Headers @{Authorization = "Bearer $($token.access_token)" } -ContentType 'application/json' -Body ($Relations | ConvertTo-Json -Depth 100 -AsArray) -EA Stop + Write-Host "Completed Update" + } + } Catch { + Write-Host "Creating Relations Failed: $_" + } + } + } + + ### License Document Details + if ($Configuration.LicenseDocumentsEnabled -eq $True) { + + $LicenseDetails = foreach ($License in $Licenses) { + $MatchedSubscriptions = $Subscriptions | Where-Object -Property skuid -EQ $License.skuId + + try { + $FriendlyLicenseName = $((Get-Culture).TextInfo.ToTitleCase((convert-skuname -skuname $License.SkuPartNumber).Tolower())) + } catch { + $FriendlyLicenseName = $License.SkuPartNumber + } + + + $LicenseUsers = foreach ($SubUser in $Users) { + $MatchedLicense = $SubUser.assignedLicenses | Where-Object { $License.skuId -in $_.skuId } + $MatchedPlans = $SubUser.AssignedPlans | Where-Object { $_.servicePlanId -in $License.servicePlans.servicePlanID } + if (($MatchedLicense | Measure-Object).count -gt 0 ) { + $SubRelUserID = ($UsersMap | Where-Object { $_.M365ID -eq $SubUser.id }).NinjaOneID + if ($SubRelUserID) { + $LicUserName = '' + $SubUser.displayName + '' + } else { + $LicUserName = $SubUser.displayName + } + [PSCustomObject]@{ + Name = $LicUserName + UPN = $SubUser.userPrincipalName + 'License Assigned' = $(try { $(Get-Date(($MatchedPlans | Group-Object assignedDateTime | Sort-Object Count -Desc | Select-Object -First 1).name) -Format u) } catch { 'Unknown' }) + NinjaUserDocID = $SubRelUserID + } + } + } + + $LicenseUsersHTML = $LicenseUsers | Select-Object -ExcludeProperty NinjaUserDocID | ConvertTo-Html -As Table -Fragment + $LicenseUsersHTML = ([System.Web.HttpUtility]::HtmlDecode($LicenseUsersHTML) -replace '', '') -replace '', '' + + $LicenseSummary = [PSCustomObject]@{ + 'License Name' = $FriendlyLicenseName + 'Tenant Used' = $License.consumedUnits + 'Tenant Total' = $License.prepaidUnits.enabled + 'SKU ID' = $License.skuId + } + $LicenseOverviewCardHTML = Get-NinjaOneInfoCard -Title "License Details" -Data $LicenseSummary -Icon 'fas fa-file-invoice' + + $SubscriptionsHTML = $MatchedSubscriptions | Select-Object @{'n' = 'Subscription Licenses'; 'e' = { $_.totalLicenses } }, + @{'n' = 'Created'; 'e' = { $_.createdDateTime } }, + @{'n' = 'Renewal'; 'e' = { $_.nextLifecycleDateTime } }, + @{'n' = 'Trial'; 'e' = { $_.isTrial } }, + @{'n' = 'Status'; 'e' = { $_.Status } } | ConvertTo-Html -As Table -Fragment + + $SubscriptionsHTML = ([System.Web.HttpUtility]::HtmlDecode($SubscriptionsHTML) -replace '', '') -replace '', '' + $SubscriptionCardHTML = Get-NinjaOneCard -Title "Subscriptions" -Body $SubscriptionsHTML -Icon 'fas fa-file-invoice' + + + $LicenseItemsTable = $License.servicePlans | Select-Object @{n = 'Plan Name'; e = { convert-skuname -skuname $_.servicePlanName } }, @{n = 'Applies To'; e = { $_.appliesTo } }, @{n = 'Provisioning Status'; e = { $_.provisioningStatus } } + $LicenseItemsHTML = $LicenseItemsTable | ConvertTo-Html -As Table -Fragment + $LicenseItemsHTML = ([System.Web.HttpUtility]::HtmlDecode($LicenseItemsHTML) -replace '', '') -replace '', '' + + $LicenseItemsCardHTML = Get-NinjaOneCard -Title 'License Items' -Body $LicenseItemsHTML -Icon 'fas fa-chart-bar' + + + $LicenseSummaryHTML = '
    ' + + '
    ' + $LicenseOverviewCardHTML + + '
    ' + $SubscriptionCardHTML + + '
    ' + $LicenseItemsCardHTML + + '
    ' + + $NinjaOneLicense = $NinjaOneLicenseDocs | Where-Object { $_.ParsedFields.cippLicenseID -eq $License.ID } + + $LicenseFields = @{ + cippLicenseSummary = @{'html' = $LicenseSummaryHTML } + cippLicenseUsers = @{'html' = $LicenseUsersHTML } + cippLicenseID = $License.id + } + + + if ($NinjaOneLicense) { + $UpdateObject = [PSCustomObject]@{ + documentId = $NinjaOneLicense.documentId + documentName = "$FriendlyLicenseName" + fields = $LicenseFields + } + $NinjaLicenseUpdates.Add($UpdateObject) + } else { + $CreateObject = [PSCustomObject]@{ + documentName = "$FriendlyLicenseName" + documentTemplateId = [int]($NinjaOneLicenseTemplate.id) + organizationId = [int]$NinjaOneOrg + fields = $LicenseFields + } + $NinjaLicenseCreation.Add($CreateObject) + } + + [PSCustomObject]@{ + Name = "$FriendlyLicenseName" + Users = $LicenseUsers.NinjaUserDocID + } + + } + + try { + # Create New Subscriptions + if (($NinjaLicenseCreation | Measure-Object).count -ge 1) { + Write-Host "Creating NinjaOne Licenses" + $CreatedLicenses = (Invoke-WebRequest -uri "https://$($Configuration.Instance)/api/v2/organization/documents" -Method POST -Headers @{Authorization = "Bearer $($token.access_token)" } -ContentType 'application/json' -Body ($NinjaLicenseCreation | ConvertTo-Json -Depth 100 -AsArray) -EA Stop).content | ConvertFrom-Json -Depth 100 + } + } Catch { + Write-Host "Bulk Creation Error, but may have been successful as only 1 record with an issue could have been the cause: $_" + } + + try { + # Update Subscriptions + if (($NinjaLicenseUpdates | Measure-Object).count -ge 1) { + Write-Host "Updating NinjaOne Licenses" + $UpdatedLicenses = (Invoke-WebRequest -uri "https://$($Configuration.Instance)/api/v2/organization/documents" -Method PATCH -Headers @{Authorization = "Bearer $($token.access_token)" } -ContentType 'application/json' -Body ($NinjaLicenseUpdates | ConvertTo-Json -Depth 100 -AsArray) -EA Stop).content | ConvertFrom-Json -Depth 100 + Write-Host "Completed Update" + } + } Catch { + Write-Host "Bulk Update Errored, but may have been successful as only 1 record with an issue could have been the cause: $_" + } + + $LicenseDocs = $CreatedLicenses + $UpdatedLicenses + + if ($Configuration.LicenseDocumentsEnabled -eq $True -and $Configuration.UserDocumentsEnabled -eq $True) { + # Relate Subscriptions to Users + Foreach ($LinkLic in $LicenseDetails) { + $MatchedLicDoc = $LicenseDocs | Where-Object { $_.documentName -eq $LinkLic.name } + if (($MatchedLicDoc | Measure-Object).count -eq 1) { + # Remove existing relations + $RelatedItems = (Invoke-WebRequest -uri "https://$($Configuration.Instance)/api/v2/related-items/with-entity/DOCUMENT/$($MatchedLicDoc.documentId)" -Method GET -Headers @{Authorization = "Bearer $($token.access_token)" } -ContentType 'application/json').content | ConvertFrom-Json -depth 100 + [System.Collections.Generic.List[PSCustomObject]]$Relations = @() + Foreach ($LinkUser in $LinkLic.Users) { + $ExistingRelation = $RelatedItems | Where-Object { $_.relEntityType -eq 'DOCUMENT' -and $_.relEntityId -eq $LinkUser } + if (!$ExistingRelation) { + $Relations.Add( + [PSCustomObject]@{ + relEntityType = "DOCUMENT" + relEntityId = $LinkUser + } + ) + } + } + + + try { + # Update Relations + if (($Relations | Measure-Object).count -ge 1) { + Write-Host "Updating Relations" + $Null = Invoke-WebRequest -uri "https://$($Configuration.Instance)/api/v2/related-items/entity/DOCUMENT/$($($MatchedLicDoc.documentId))/relations" -Method POST -Headers @{Authorization = "Bearer $($token.access_token)" } -ContentType 'application/json' -Body ($Relations | ConvertTo-Json -Depth 100 -AsArray) -EA Stop + Write-Host "Completed Update" + } + } Catch { + Write-Host "Creating Relations Failed: $_" + } + + #Remove relations + foreach ($DelUser in $RelatedItems | Where-Object { $_.relEntityType -eq 'DOCUMENT' -and $_.relEntityId -notin $LinkLic.Users }) { + try { + $RelatedItems = (Invoke-WebRequest -uri "https://$($Configuration.Instance)/api/v2/related-items/$($DelUser.id)" -Method Delete -Headers @{Authorization = "Bearer $($token.access_token)" } -ContentType 'application/json').content | ConvertFrom-Json -depth 100 + } catch { + Write-Host "Failed to remove relation $($DelUser.id) from $($LinkLic.name)" + } + } + } + } + } + + } + + ####################################################################### + + + + ### M365 Links Section + if ($MappedFields.TenantLinks) { + Write-Host "Tenant Links" + + $ManagementLinksData = @( + @{ + Name = 'M365 Admin Portal' + Link = "https://portal.office.com/Partner/BeginClientSession.aspx?CTID=$($customer.CustomerId)&CSDEST=o365admincenter" + Icon = 'fas fa-cogs' + }, + @{ + Name = 'Exchange Portal' + Link = "https://admin.exchange.microsoft.com/?landingpage=homepage&form=mac_sidebar&delegatedOrg=$($Customer.DefaultDomainName)#" + Icon = 'fas fa-mail-bulk' + }, + @{ + Name = 'Entra Portal' + Link = "https://entra.microsoft.com/$($Customer.DefaultDomainName)" + Icon = 'fas fa-users-cog' + }, + @{ + Name = 'Intune Portal' + Link = "https://endpoint.microsoft.com/$($customer.DefaultDomainName)/" + Icon = 'fas fa-laptop' + }, + @{ + Name = 'Sharepoint Admin' + Link = "https://admin.microsoft.com/Partner/beginclientsession.aspx?CTID=$($Customer.CustomerId)&CSDEST=SharePoint" + Icon = 'fas fa-shapes' + }, + @{ + Name = 'Teams Admin' + Link = "https://admin.teams.microsoft.com/?delegatedOrg=$($Customer.DefaultDomainName)" + Icon = 'fas fa-users' + }, + @{ + Name = 'Security Portal' + Link = "https://security.microsoft.com/?tid=$($Customer.CustomerId)" + Icon = 'fas fa-building-shield' + }, + @{ + Name = 'Compliance Portal' + Link = "https://compliance.microsoft.com/?tid=$($Customer.CustomerId)" + Icon = 'fas fa-user-shield' + }, + @{ + Name = 'Azure Portal' + Link = "https://portal.azure.com/$($customer.DefaultDomainName)" + Icon = 'fas fa-server' + } + + ) + + $M365LinksHTML = Get-NinjaOneLinks -Data $ManagementLinksData -Title 'Portals' -SmallCols 2 -MedCols 3 -LargeCols 3 -XLCols 3 + + $CIPPLinksData = @( + + @{ + Name = 'CIPP Tenant Dashboard' + Link = "https://$CIPPUrl/home?customerId=$($Customer.CustomerId)" + Icon = 'fas fa-shield-halved' + }, + @{ + Name = 'Edit Tenant' + Link = "https://$CIPPUrl/tenant/administration/tenants/Edit?customerId=$($Customer.customerId)&tenantFilter=$($Customer.defaultDomainName)" + Icon = 'fas fa-cog' + }, + @{ + Name = 'List Users' + Link = "https://$CIPPUrl/identity/administration/users?customerId=$($Customer.customerId)" + Icon = 'fas fa-user' + }, + @{ + Name = 'List Groups' + Link = "https://$CIPPUrl/identity/administration/groups?customerId=$($Customer.customerId)" + Icon = 'fas fa-users' + }, + @{ + Name = 'List Devices' + Link = "https://$CIPPUrl/endpoint/reports/devices?customerId=$($Customer.customerId)" + Icon = 'fas fa-laptop' + }, + @{ + Name = 'Create User' + Link = "https://$CIPPUrl/identity/administration/users/add?customerId=$($Customer.customerId)" + Icon = 'fas fa-user-plus' + }, + @{ + Name = 'Create Group' + Link = "https://$CIPPUrl/identity/administration/groups/add?customerId=73be1f98-1003-4e1a-8e8a-4ffbff7ff2d6" + Icon = 'fas fa-user-group' + } + ) + + $CIPPLinksHTML = Get-NinjaOneLinks -Data $CIPPLinksData -Title 'CIPP Actions' -SmallCols 2 -MedCols 3 -LargeCols 3 -XLCols 3 + + $LinksHtml = '
    ' + $CIPPLinksHTML + '
    ' + + $NinjaOrgUpdate | Add-Member -NotePropertyName $MappedFields.TenantLinks -NotePropertyValue @{'html' = $LinksHtml } + + } + + + if ($MappedFields.TenantSummary) { + Write-Host "Tenant Summary" + + ### Tenant Overview Card + $ParsedAdmins = [PSCustomObject]@{} + + $AdminUsers | Select-Object displayname, userPrincipalName -unique | ForEach-Object { + $ParsedAdmins | Add-Member -NotePropertyName $_.displayname -NotePropertyValue $_.userPrincipalName + } + + $TenantDetailsItems = [PSCustomObject]@{ + 'Tenant Name' = $Customer.displayName + 'Default Domain' = $Customer.defaultDomainName + 'Tenant ID' = $Customer.customerId + 'Creation Date' = $TenantDetails.createdDateTime + 'Domains' = $customerDomains + 'Admin Users' = ($AdminUsers | ForEach-Object { "$($_.DisplayName)" }) -join ', ' + + } + + $TenantSummaryCard = Get-NinjaOneInfoCard -Title "Tenant Details" -Data $TenantDetailsItems -Icon 'fas fa-building' + + ### Users details card + Write-Host "User Details" + $TotalUsersCount = ($Users | measure-object).count + $GuestUsersCount = ($Users | where-object { $_.UserType -eq 'Guest' } | measure-object).count + $LicensedUsersCount = ($licensedUsers | measure-object).count + $UnlicensedUsersCount = $TotalUsersCount - $GuestUsersCount - $LicensedUsersCount + $UsersEnabledCount = ($Users | where-object { $_.accountEnabled -eq $True } | Measure-Object).count + + # Enabled Users + + $Data = @( + @{ + Label = 'Sign-In Enabled' + Amount = $UsersEnabledCount + Colour = '#26A644' + }, + @{ + Label = 'Sign-In Blocked' + Amount = $TotalUsersCount - $UsersEnabledCount + Colour = '#D53948' + } + ) + + + $UsersEnabledChartHTML = Get-NinjaInLineBarGraph -Title "User Status" -Data $Data -KeyInLine + + # User Types + + $Data = @( + @{ + Label = 'Licensed' + Amount = $LicensedUsersCount + Colour = '#55ACBF' + }, + @{ + Label = 'Unlicensed' + Amount = $UnlicensedUsersCount + Colour = '#3633B7' + }, + @{ + Label = 'Guests' + Amount = $GuestUsersCount + Colour = '#8063BF' + } + ) + + $UsersTypesChartHTML = Get-NinjaInLineBarGraph -Title "User Types" -Data $Data -KeyInLine + + # Create the Users Card + + $TitleLink = "https://$CIPPUrl/identity/administration/users?customerId=$($Customer.customerId)" + + $UsersCardBodyHTML = $UsersEnabledChartHTML + $UsersTypesChartHTML + + $UserSummaryCardHTML = Get-NinjaOneCard -Title 'User Details' -Body $UsersCardBodyHTML -Icon 'fas fa-users' -TitleLink $TitleLink + + + + ### Device Details Card + Write-Host "Device Details" + $TotalDeviceswCount = ($Devices | Measure-Object).count + $ComplianceDevicesCount = ($Devices | Where-Object { $_.complianceState -eq 'compliant' } | Measure-Object).count + $WindowsCount = ($Devices | Where-Object { $_.operatingSystem -eq 'Windows' } | Measure-Object).count + $IOSCount = ($Devices | Where-Object { $_.operatingSystem -eq 'iOS' } | Measure-Object).count + $AndroidCount = ($Devices | Where-Object { $_.operatingSystem -eq 'Android' } | Measure-Object).count + $MacOSCount = ($Devices | Where-Object { $_.operatingSystem -eq 'macOS' } | Measure-Object).count + $OnlineInLast30Days = ($Devices | Where-Object { $_.lastSyncDateTime -gt ((Get-Date).AddDays(-30)) } | Measure-Object).Count + + + # Compliance Devices + $Data = @( + @{ + Label = 'Compliant' + Amount = $ComplianceDevicesCount + Colour = '#26A644' + }, + @{ + Label = 'Non Compliant' + Amount = $TotalDeviceswCount - $ComplianceDevicesCount + Colour = '#D53948' + } + ) + + + $DeviceComplianceChartHTML = Get-NinjaInLineBarGraph -Title "Device Compliance" -Data $Data -KeyInLine + + # Device OS Types + + $Data = @( + @{ + Label = 'Windows' + Amount = $WindowsCount + Colour = '#0078D7' + }, + @{ + Label = 'macOS' + Amount = $MacOSCount + Colour = '#A3AAAE' + }, + @{ + Label = 'Android' + Amount = $AndroidCount + Colour = '#3DDC84' + }, + @{ + Label = 'iOS' + Amount = $IOSCount + Colour = '#007AFF' + } + ) + + $DeviceOsChartHTML = Get-NinjaInLineBarGraph -Title "Device Operating Systems" -Data $Data -KeyInLine + + # Last online time + + $Data = @( + @{ + Label = 'Online in last 30 days' + Amount = $OnlineInLast30Days + Colour = '#26A644' + }, + @{ + Label = 'Not seen for 30+ days' + Amount = $TotalDeviceswCount - $OnlineInLast30Days + Colour = '#CCCCCC' + } + ) + + $DeviceOnlineChartHTML = Get-NinjaInLineBarGraph -Title "Devices Online in the last 30 days" -Data $Data -KeyInLine + + # Create the Devices Card + + $TitleLink = "https://$CIPPUrl/endpoint/reports/devices?customerId=$($Customer.customerId)" + + $DeviceCardBodyHTML = $DeviceComplianceChartHTML + $DeviceOsChartHTML + $DeviceOnlineChartHTML + + $DeviceSummaryCardHTML = Get-NinjaOneCard -Title 'Device Details' -Body $DeviceCardBodyHTML -Icon 'fas fa-network-wired' -TitleLink $TitleLink + + #### Secure Score Card + Write-Host "Secure Score Details" + $Top5Actions = ($SecureScoreParsed | Where-Object { $_.scoreInPercentage -ne 100 } | Sort-Object 'Score Impact', adjustedRank -Descending) | Select-Object -First 5 + + # Score Chart + $Data = [PSCustomObject]@( + @{ + Label = 'Current Score' + Amount = $CurrentSecureScore.currentScore + Colour = '#26A644' + }, + @{ + Label = 'Points to Obtain' + Amount = $MaxSecureScoreRank - $CurrentSecureScore.currentScore + Colour = '#CCCCCC' + } + ) + + $SecureScoreHTML = Get-NinjaInLineBarGraph -Title "Secure Score - $([System.Math]::Round((($CurrentSecureScore.currentScore / $MaxSecureScoreRank) * 100),2))%" -Data $Data -KeyInLine -NoCount -NoSort + + # Recommended Actions HTML + $RecommendedActionsHTML = $Top5Actions | Select-Object 'Recommended Action', @{n = 'Score Impact'; e = { "+$($_.'Score Impact')%" } }, Category, @{n = 'Link'; e = { '' } } | ConvertTo-Html -As Table -Fragment + + $TitleLink = "https://security.microsoft.com/securescore?viewid=overview&tid=$($Customer.CustomerId)" + + $SecureScoreCardBodyHTML = $SecureScoreHTML + [System.Web.HttpUtility]::HtmlDecode($RecommendedActionsHTML) -replace '
    ', '' + $SecureScoreCardBodyHTML = $SecureScoreCardBodyHTML -replace '', '' + + $SecureScoreSummaryCardHTML = Get-NinjaOneCard -Title 'Secure Score' -Body $SecureScoreCardBodyHTML -Icon 'fas fa-shield' -TitleLink $TitleLink + + + ### CIPP Applied Standards Cards + Write-Host "Applied Standards" + $StandardsDefinitions = Get-Content 'config/standards.json' | ConvertFrom-Json -Depth 100 + + $Table = Get-CippTable -tablename 'standards' + + $Filter = "PartitionKey eq 'standards'" + + $AllStandards = (Get-AzDataTableEntity @Table -Filter $Filter).JSON | ConvertFrom-Json -Depth 100 + + $AppliedStandards = ($AllStandards | Where-Object { $_.Tenant -eq $Customer.defaultDomainName -or $_.Tenant -eq 'AllTenants' }) + + $ParsedStandards = foreach ($Standard in $AppliedStandards) { + [PSCustomObject]$Standards = $Standard.Standards + $Standards.PSObject.Properties | foreach-object { + $CheckValue = $_ + if ($CheckValue.value) { + $MatchedStandard = $StandardsDefinitions | where-object { ($_.name -split 'standards.')[1] -eq $CheckValue.name } + if (($MatchedStandard | Measure-Object).count -eq 1) { + '
  • ' + $($MatchedStandard.label) + ' (' + ($($Standard.Tenant)) + ')
  • ' + } + } + } + + } + + $TitleLink = "https://$CIPPUrl/tenant/standards/list-applied-standards?customerId=$($Customer.customerId)" + + $CIPPStandardsBodyHTML = '
      ' + $ParsedStandards + '
    ' + + $CIPPStandardsSummaryCardHTML = Get-NinjaOneCard -Title 'CIPP Applied Standards' -Body $CIPPStandardsBodyHTML -Icon 'fas fa-shield-halved' -TitleLink $TitleLink + + ### License Card + Write-Host "License Details" + $LicenseTableHTML = $LicensesParsed | Sort-Object 'License Name' | ConvertTo-HTML -As Table -Fragment + $LicenseTableHTML = ([System.Web.HttpUtility]::HtmlDecode($LicenseTableHTML) -replace '
    ', '') -replace '', '' + + $TitleLink = "https://$CIPPUrl/tenant/administration/list-licenses?customerId=$($Customer.customerId)" + $LicensesSummaryCardHTML = Get-NinjaOneCard -Title 'Licenses' -Body $LicenseTableHTML -Icon 'fas fa-chart-bar' -TitleLink $TitleLink + + + ### Summary Stats + Write-Host "Widget Details" + + [System.Collections.Generic.List[PSCustomObject]]$WidgetData = @() + + ### Fetch BPA Data + $Table = get-cipptable 'cachebpav2' + $BPAData = (Get-CIPPAzDataTableEntity @Table -Filter "PartitionKey eq '$($Customer.customerId)' and RowKey eq 'CIPP Best Practices v1.0 - Table view'") + + if ($Null -ne $BPAData.Timestamp) { + ## BPA Data Widgets + # Shared Mailboxes with Enabled Users + #$WidgetData.add([PSCustomObject]@{ + # Value = $( + # $SharedSendMailboxCount = ($BpaData.SharedMailboxeswithenabledusers | ConvertFrom-Json | Measure-Object).count + # if ($SharedSendMailboxCount -ne 0) { + # $ResultColour = '#D53948' + # } else { + # $ResultColour = '#26A644' + # } + # $SharedSendMailboxCount + # ) + # Description = 'Shared Mailboxes with enabled users' + # Colour = $ResultColour + # Link = "https://$CIPPUrl/tenant/standards/bpa-report?SearchNow=true&Report=CIPP+Best+Practices+v1.0+-+Tenant+view&tenantFilter=$($Customer.customerId)" + # }) + + # Unused Licenses + $WidgetData.add([PSCustomObject]@{ + Value = $( + $BPAUnusedLicenses = (($BpaData.Unusedlicenses | ConvertFrom-Json).availableUnits | Measure-Object -sum).sum + if ($BPAUnusedLicenses -ne 0) { + $ResultColour = '#D53948' + } else { + $ResultColour = '#26A644' + } + $BPAUnusedLicenses + ) + Description = 'Unused Licenses' + Colour = $ResultColour + Link = "https://$CIPPUrl/tenant/standards/bpa-report?SearchNow=true&Report=CIPP+Best+Practices+v1.0+-+Tenant+view&tenantFilter=$($Customer.customerId)" + }) + + + # Unified Audit Log + $WidgetData.add([PSCustomObject]@{ + Value = $(if ($BPAData.UnifiedAuditLog -eq $True) { + $ResultColour = '#26A644' + '' + } else { + $ResultColour = '#D53948' + '' + } + ) + Description = 'Unified Audit Log' + Colour = $ResultColour + Link = "https://security.microsoft.com/auditlogsearch?viewid=Async%20Search&tid=$($Customer.customerId)" + }) + + # Passwords Never Expire + $WidgetData.add([PSCustomObject]@{ + Value = $(if ($BPAData.PasswordNeverExpires -eq $True) { + $ResultColour = '#26A644' + '' + } else { + $ResultColour = '#D53948' + '' + } + ) + Description = 'Password Never Expires' + Colour = $ResultColour + Link = "https://$CIPPUrl/tenant/standards/bpa-report?SearchNow=true&Report=CIPP+Best+Practices+v1.0+-+Tenant+view&tenantFilter=$($Customer.customerId)" + }) + + # oAuth App Consent + $WidgetData.add([PSCustomObject]@{ + Value = $(if ($BPAData.OAuthAppConsent -eq $True) { + $ResultColour = '#26A644' + '' + } else { + $ResultColour = '#D53948' + '' + } + ) + Description = 'OAuth App Consent' + Colour = $ResultColour + Link = "https://entra.microsoft.com/$($Customer.customerId)/#view/Microsoft_AAD_IAM/ConsentPoliciesMenuBlade/~/UserSettings" + }) + + } + + # Blocked Senders + $BlockedSenderCount = ($BlockedSenders | Measure-Object).count + if ($BlockedSenderCount -eq 0) { + $BlockedSenderColour = '#26A644' + } else { + $BlockedSenderColour = '#D53948' + } + $WidgetData.add([PSCustomObject]@{ + Value = $BlockedSenderCount + Description = 'Blocked Senders' + Colour = $BlockedSenderColour + Link = "https://security.microsoft.com/restrictedentities?tid=$($Customer.customerId)" + }) + + # Licensed Users + $WidgetData.add([PSCustomObject]@{ + Value = ($licensedUsers | Measure-Object).count + Description = 'Licensed Users' + Colour = '#CCCCCC' + Link = "https://$CIPPUrl/identity/administration/users?customerId=$($Customer.customerId)" + }) + + # Devices + $WidgetData.add([PSCustomObject]@{ + Value = ($Devices | Measure-Object).count + Description = 'Devices' + Colour = '#CCCCCC' + Link = "https://$CIPPUrl/endpoint/reports/devices?customerId=$($Customer.customerId)" + }) + + # Groups + $WidgetData.add([PSCustomObject]@{ + Value = ($AllGroups | Measure-Object).count + Description = 'Groups' + Colour = '#CCCCCC' + Link = "https://$CIPPUrl/identity/administration/groups?customerId=$($Customer.customerId)" + }) + + # Roles + $WidgetData.add([PSCustomObject]@{ + Value = ($AllRoles | Measure-Object).count + Description = 'Roles' + Colour = '#CCCCCC' + Link = "https://$CIPPUrl/identity/administration/roles?customerId=$($Customer.customerId)" + }) + + + # AAD Premium + if ( 'AADPremiumService' -in $TenantDetails.assignedPlans.service) { + $AADPremiumStatus = '' + } else { + $AADPremiumStatus = '' + } + $WidgetData.add([PSCustomObject]@{ + Value = $AADPremiumStatus + Description = 'AAD Premium' + Colour = '#CCCCCC' + Link = "https://entra.microsoft.com/$($Customer.customerId)/#view/Microsoft_AAD_IAM/TenantOverview.ReactView" + }) + + # WindowsDefenderATP + if ( 'WindowsDefenderATP' -in $TenantDetails.assignedPlans.service) { + $DefenderStatus = '' + } else { + $DefenderStatus = '' + } + $WidgetData.add([PSCustomObject]@{ + Value = $DefenderStatus + Description = 'Windows Defender' + Colour = '#CCCCCC' + Link = "https://security.microsoft.com/machines?category=endpoints&tid=$($Customer.DefaultDomainName)#" + }) + + # On Prem Sync + if ( $TenantDetails.onPremisesSyncEnabled -eq $true) { + $OnPremSyncStatus = '' + } else { + $OnPremSyncStatus = '' + } + $WidgetData.add([PSCustomObject]@{ + Value = $OnPremSyncStatus + Description = 'AD Connect' + Colour = '#CCCCCC' + Link = "https://entra.microsoft.com/$($Customer.customerId)/#view/Microsoft_AAD_IAM/DirectoriesADConnectBlade" + }) + + + + + + + Write-Host 'Summary Details' + $SummaryDetailsCardHTML = Get-NinjaOneWidgetCard -Data $WidgetData -Icon 'fas fa-building' -SmallCols 2 -MedCols 3 -LargeCols 4 -XLCols 6 -NoCard + + + # Create the Tenant Summary Field + Write-Host "Complete Tenant Summary" + $TenantSummaryHTML = '
    ' + $SummaryDetailsCardHTML + '
    ' + + '
    ' + + '
    ' + $TenantSummaryCard + + '
    ' + $LicensesSummaryCardHTML + + '
    ' + $DeviceSummaryCardHTML + + '
    ' + $CIPPStandardsSummaryCardHTML + + '
    ' + $SecureScoreSummaryCardHTML + + '
    ' + $UserSummaryCardHTML + + '
    ' + + $NinjaOrgUpdate | Add-Member -NotePropertyName $MappedFields.TenantSummary -NotePropertyValue @{'html' = $TenantSummaryHTML } + + + + } + + if ($MappedFields.UsersSummary) { + Write-Host "User Details Section" + + $UsersTableFornatted = $ParsedUsers | sort-object name | Select-Object -First 100 Name, + @{n = 'User Principal Name'; e = { $_.UPN } }, + #Aliases, + Licenses, + @{n = 'Mailbox Usage'; e = { $_.MailboxParsed } }, + @{n = 'One Drive Usage'; e = { $_.OneDriveParsed } }, + @{n = 'Devices (Last Login)'; e = { $_.Devices } }, + Actions + + + $UsersTableHTML = $UsersTableFornatted | ConvertTo-HTML -As Table -Fragment + + $UsersTableHTML = ([System.Web.HttpUtility]::HtmlDecode($UsersTableHTML) -replace '
    ', '') -replace '', '' + + if ($ParsedUsers.count -gt 100) { + $Overflow = @" +
    + +
    +
    $($ParsedUsers.count) users found in Tenant
    +
    + Only the first 100 users are displayed here. To see all users please view users in CIPP. +
    +
    +
    +"@ + } else { + $Overflow = '' + } + + $NinjaOrgUpdate | Add-Member -NotePropertyName $MappedFields.UsersSummary -NotePropertyValue @{'html' = $Overflow + $UsersTableHTML } + + } + + + + Write-Host "Posting Details" + + $Token = Get-NinjaOneToken -configuration $Configuration + + + $Result = Invoke-WebRequest -uri "https://$($Configuration.Instance)/api/v2/organization/$($MappedTenant.NinjaOne)/custom-fields" -Method PATCH -Headers @{Authorization = "Bearer $($token.access_token)" } -ContentType 'application/json' -Body ($NinjaOrgUpdate | ConvertTo-Json -Depth 100) + + Write-Host "Cleaning Users Cache" + if (($ParsedUsers | Measure-Object).count -gt 0) { + Remove-AzDataTableEntity @UsersTable -Entity ($ParsedUsers | Select-Object PartitionKey, RowKey) + } + + Write-Host "Cleaning Device Cache" + if (($ParsedDevices | Measure-Object).count -gt 0) { + Remove-AzDataTableEntity @DeviceTable -Entity ($ParsedDevices | Select-Object PartitionKey, RowKey) + } + + Write-Host "Total Fetch Time: $((New-TimeSpan -Start $StartTime -End $FetchEnd).TotalSeconds)" + Write-Host "Completed Total Time: $((New-TimeSpan -Start $StartTime -End (Get-Date)).TotalSeconds)" + Write-LogMessage -API 'NinjaOneSync' -user 'CIPP' -message "Completed NinjaOne Sync for $($Customer.displayName). Data fetched in $((New-TimeSpan -Start $StartTime -End $FetchEnd).TotalSeconds) seconds. Total time $((New-TimeSpan -Start $StartTime -End (Get-Date)).TotalSeconds) seconds" -Sev 'info' + + } catch { + Write-Error "Failed NinjaOne Processing for $($Customer.displayName) Linenumber: $($_.InvocationInfo.ScriptLineNumber) Error: $($_.Exception.message)" + Write-LogMessage -API 'NinjaOneSync' -user 'CIPP' -message "Failed NinjaOne Processing for $($Customer.displayName) Linenumber: $($_.InvocationInfo.ScriptLineNumber) Error: $($_.Exception.message)" -Sev 'Error' + } +} \ No newline at end of file diff --git a/Modules/CippExtensions/NinjaOne/NinjaOneHelper.ps1 b/Modules/CippExtensions/NinjaOne/NinjaOneHelper.ps1 new file mode 100644 index 000000000000..af30f8a36b03 --- /dev/null +++ b/Modules/CippExtensions/NinjaOne/NinjaOneHelper.ps1 @@ -0,0 +1,248 @@ +function Get-NinjaOneTitle($Title, $Icon, $TitleLink, $TitleSize, $TitleClass) { + Return $(if ($TitleSize) { '<' + $TitleSize }else { '' + $(if ($Icon) { '  ' }) + $Title + $(if ($TitleLink) { '  ' }) + $(if ($TitleSize) { "" }else { '' }) +} + +### HTML Formatters ### +# Bar Graph +function Get-NinjaInLineBarGraph ($Data, [string]$Title, [string]$Icon, [string]$TitleLink, [switch]$KeyInLine, [switch]$NoCount, [switch]$NoSort) { + <# + Example: + $Data = @( + @{ + Label = 'Licensed' + Amount = 3 + Colour = '#55ACBF' + }, + @{ + Label = 'Unlicensed' + Amount = 1 + Colour = '#3633B7' + }, + @{ + Label = 'Guests' + Amount = 10 + Colour = '#8063BF' + } + ) + Get-NinjaInLineBarGraph -Title "Users" -Data $Data -KeyInLine + + #> + + if (!$NoSort) { + $Data = $Data | Sort-Object Amount -Descending + } + + $Total = ($Data.Amount | measure-object -sum).sum + [System.Collections.Generic.List[String]]$OutputHTML = @() + + if ($Title) { + $OutputHTML.add((Get-NinjaOneTitle -Icon $Icon -Title ($Title + $(if (!$NoCount) { " ($Total)" })) -TitleLink $TitleLink)) + } + + $OutputHTML.add('
    ') + + foreach ($Item in $Data) { + $OutputHTML.add(@" +
    +"@) + + } + + $OutputHTML.add('
    ') + + if ($KeyInline) { + $OutputHTML.add('
      ') + } else { + $OutputHTML.add('
        ') + } + + foreach ($Item in $Data) { + $OutputHTML.add(@" +
      • $($Item.Label) ($($Item.Amount))
      • +"@) + + } + + $OutputHTML.add('
      ') + + return $OutputHTML -join '' + + +} + +#### List of Links +function Get-NinjaOneLinks ($Data, $Title, [string]$Icon, [string]$TitleLink, [int]$SmallCols, [int]$MedCols, [int]$LargeCols, [int]$XLCols) { + <# +$ManagementLinksData = @( + @{ + Name = 'M365 Admin Portal' + Link = "https://portal.office.com/Partner/BeginClientSession.aspx?CTID=$($customer.CustomerId)&CSDEST=o365admincenter" + Icon = 'fas fa-cogs' + }, + @{ + Name = 'Exchange Admin Portal' + Link = "https://outlook.office365.com/ecp/?rfr=Admin_o365&exsvurl=1&delegatedOrg=$($Customer.DefaultDomainName)" + Icon = 'fas fa-mail-bulk' + }, + @{ + Name = 'Entra Admin' + Link = "https://aad.portal.azure.com/$($Customer.DefaultDomainName)" + Icon = 'fas fa-users-cog' + }) + + Get-NinjaOneLinks -Title 'M365 Admin Links' -Data $ManagementLinksData +#> + + [System.Collections.Generic.List[String]]$OutputHTML = @() + + $OutputHTML.add('
      ') + + if ($Title) { + $OutputHTML.add('
      ' + $(if ($Icon) { '  ' }) + $Title + '
      ') + + if ($TitleLink) { + $OutputHTML.add('') + } + + $OutputHTML.add('
      ') + } + + $OutputHTML.add('
      ') + $OutputHTML.add('
        ') + + $CSSCols = Get-NinjaOneCSSCol -SmallCols $SmallCols -MedCols $MedCols -LargeCols $LargeCols -XLCols $XLCols + + + foreach ($Item in $Data) { + + + $OutputHTML.add(@" +
      • $(if ($Item.Icon){"  "})$($Item.Name)
      • +"@) + + } + + $OutputHTML.add('
      ') + + return $OutputHTML -join '' + +} + + +function Get-NinjaOneWidgetCard($Title, $Data, [string]$Icon, [string]$TitleLink, [int]$SmallCols, [int]$MedCols, [int]$LargeCols, [int]$XLCols, [Switch]$NoCard) { + <# + $Data = @( + @{ + Value = 20 + Description = 'Users' + Colour = '#CCCCCC' + Link = 'https://example.com/users' + }, + @{ + Value = 42 + Description = 'Devices' + Colour = '#CCCCCC' + Link = 'https://example.com/devices' + } + ) + + $HTML = Get-NinjaOneWidgetCard -Title 'Summary Details' -Data $Data -Icon 'fas fa-building' -TitleLink 'http://example.com' -Columns 3 + + #> + + $CSSCols = Get-NinjaOneCSSCol -SmallCols $SmallCols -MedCols $MedCols -LargeCols $LargeCols -XLCols $XLCols + + + [System.Collections.Generic.List[String]]$OutputHTML = @() + + $OutputHTML.add('
      ') + + + foreach ($Item in $Data) { + + $HTML = @" + +"@ + + $OutputHTML.add($HTML) + + } + + $OutputHTML.add('
      ') + + if ($NoCard) { + return $OutputHTML -join '' + } else { + Return Get-NinjaOneCard -Title $Title -Body ($OutputHTML -join '') -Icon $Icon -TitleLink $TitleLink + } + +} + +Function Get-NinjaOneCSSCol($SmallCols, $MedCols, $LargeCols, $XLCols) { + $SmallCSS = "col-sm-$([Math]::Floor(12 / $SmallCols))" + $MediumCSS = "col-md-$([Math]::Floor(12 / $MedCols))" + $LargeCSS = "col-lg-$([Math]::Floor(12 / $LargeCols))" + $XLCSS = "col-xl-$([Math]::Floor(12 / $XLCols))" + + Return "$SmallCSS $MediumCSS $LargeCSS $XLCSS" +} + +function Get-NinjaOneCard($Title, $Body, [string]$Icon, [string]$TitleLink, [String]$Classes) { + <# + $Info = 'This is the body of a card it is wrapped in a paragraph' + + Get-NinjaOneCard -Title "Tenant Details" -Data $Info + #> + + [System.Collections.Generic.List[String]]$OutputHTML = @() + + $OutputHTML.add('
      ') + + if ($Title) { + $OutputHTML.add('
      ' + $(if ($Icon) { '  ' }) + $Title + '
      ') + + if ($TitleLink) { + $OutputHTML.add('') + } + + $OutputHTML.add('
      ') + } + + $OutputHTML.add('
      ') + $OutputHTML.add('

      ' + $Body + '

      ') + + $OutputHTML.add('
      ') + + return $OutputHTML -join '' + +} + +function Get-NinjaOneInfoCard($Title, $Data, [string]$Icon, [string]$TitleLink) { + <# + $TenantDetailsItems = [PSCustomObject]@{ + 'Name' = $Customer.displayName + 'Default Domain' = $Customer.defaultDomainName + 'Tenant ID' = $Customer.customerId + 'Domains' = $customerDomains + 'Admin Users' = ($AdminUsers | ForEach-Object {"$($_.displayname) ($($_.userPrincipalName))"}) -join ', ' + 'Creation Date' = $TenantDetails.createdDateTime + } + + Get-NinjaOneInfoCard -Title "Tenant Details" -Data $TenantDetailsItems + #> + + [System.Collections.Generic.List[String]]$ItemsHTML = @() + + foreach ($Item in $Data.PSObject.Properties) { + $ItemsHTML.add('

      ' + $Item.Name + '
      ' + $Item.Value + '

      ') + } + + return Get-NinjaOneCard -Title $Title -Body ($ItemsHTML -join '') -Icon $Icon -TitleLink $TitleLink + +} + diff --git a/Modules/CippExtensions/NinjaOne/Set-NinjaOneFieldMapping.ps1 b/Modules/CippExtensions/NinjaOne/Set-NinjaOneFieldMapping.ps1 new file mode 100644 index 000000000000..4653d51ed13a --- /dev/null +++ b/Modules/CippExtensions/NinjaOne/Set-NinjaOneFieldMapping.ps1 @@ -0,0 +1,31 @@ +function Set-NinjaOneFieldMapping { + [CmdletBinding()] + param ( + $CIPPMapping, + $APIName, + $Request, + $TriggerMetadata + ) + + $SettingsTable = Get-CIPPTable -TableName NinjaOneSettings + $AddObject = @{ + PartitionKey = 'NinjaConfig' + RowKey = 'CIPPURL' + 'SettingValue' = ([System.Uri]$TriggerMetadata.Headers.referer).Host + } + Add-AzDataTableEntity @SettingsTable -Entity $AddObject -Force + + foreach ($Mapping in ([pscustomobject]$Request.body.mappings).psobject.properties) { + $AddObject = @{ + PartitionKey = 'NinjaFieldMapping' + RowKey = "$($mapping.name)" + 'NinjaOne' = "$($mapping.value.value)" + 'NinjaOneName' = "$($mapping.value.label)" + } + Add-AzDataTableEntity @CIPPMapping -Entity $AddObject -Force + Write-LogMessage -API $APINAME -user $request.headers.'x-ms-client-principal' -message "Added mapping for $($mapping.name)." -Sev 'Info' + } + $Result = [pscustomobject]@{'Results' = "Successfully edited mapping table." } + + Return $Result +} \ No newline at end of file diff --git a/Modules/CippExtensions/NinjaOne/Set-NinjaOneOrgMapping.ps1 b/Modules/CippExtensions/NinjaOne/Set-NinjaOneOrgMapping.ps1 new file mode 100644 index 000000000000..67f9e10dfb03 --- /dev/null +++ b/Modules/CippExtensions/NinjaOne/Set-NinjaOneOrgMapping.ps1 @@ -0,0 +1,23 @@ +function Set-NinjaOneOrgMapping { + [CmdletBinding()] + param ( + $CIPPMapping, + $APIName, + $Request + ) + + + foreach ($Mapping in ([pscustomobject]$Request.body.mappings).psobject.properties) { + $AddObject = @{ + PartitionKey = 'NinjaOrgsMapping' + RowKey = "$($mapping.name)" + 'NinjaOne' = "$($mapping.value.value)" + 'NinjaOneName' = "$($mapping.value.label)" + } + Add-AzDataTableEntity @CIPPMapping -Entity $AddObject -Force + Write-LogMessage -API $APINAME -user $request.headers.'x-ms-client-principal' -message "Added mapping for $($mapping.name)." -Sev 'Info' + } + $Result = [pscustomobject]@{'Results' = "Successfully edited mapping table." } + + Return $Result +} \ No newline at end of file diff --git a/Modules/CippExtensions/Private/Get-HaloMapping.ps1 b/Modules/CippExtensions/Private/Get-HaloMapping.ps1 index 00fa41cd5dc4..d86753f29306 100644 --- a/Modules/CippExtensions/Private/Get-HaloMapping.ps1 +++ b/Modules/CippExtensions/Private/Get-HaloMapping.ps1 @@ -5,6 +5,7 @@ function Get-HaloMapping { ) #Get available mappings $Mappings = [pscustomobject]@{} + $Filter = "PartitionKey eq 'Mapping'" Get-CIPPAzDataTableEntity @CIPPMapping -Filter $Filter | ForEach-Object { $Mappings | Add-Member -NotePropertyName $_.RowKey -NotePropertyValue @{ label = "$($_.HaloPSAName)"; value = "$($_.HaloPSA)" } @@ -12,7 +13,9 @@ function Get-HaloMapping { $Tenants = Get-Tenants -IncludeAll $Table = Get-CIPPTable -TableName Extensionsconfig try { - $Configuration = ((Get-CIPPAzDataTableEntity @Table).config | ConvertFrom-Json).HaloPSA + $Configuration = ((Get-CIPPAzDataTableEntity @Table).config | ConvertFrom-Json -ea stop).HaloPSA + + $Token = Get-HaloToken -configuration $Configuration $i = 1 $RawHaloClients = do { diff --git a/Modules/CippExtensions/Private/Get-HaloToken.ps1 b/Modules/CippExtensions/Private/Get-HaloToken.ps1 index bc75822a9875..0c26b909eec5 100644 --- a/Modules/CippExtensions/Private/Get-HaloToken.ps1 +++ b/Modules/CippExtensions/Private/Get-HaloToken.ps1 @@ -11,11 +11,10 @@ function Get-HaloToken { client_secret = (Get-AzKeyVaultSecret -VaultName $ENV:WEBSITE_DEPLOYMENT_ID -Name 'HaloPSA' -AsPlainText) scope = 'all' } - if ($Configuration.Tenant -ne "None") { $Tenant = "?tenant=$($Configuration.tenant)" } + if ($Configuration.Tenant -ne 'None') { $Tenant = "?tenant=$($Configuration.Tenant)" } $token = Invoke-RestMethod -Uri "$($Configuration.AuthURL)/token$Tenant" -Method Post -Body $body -ContentType 'application/x-www-form-urlencoded' return $token - } - else { + } else { throw 'No Halo configuration' } } \ No newline at end of file diff --git a/Modules/CippExtensions/Private/New-GradientServiceSyncRun.ps1 b/Modules/CippExtensions/Private/New-GradientServiceSyncRun.ps1 index b16197fa3183..3200c46782c5 100644 --- a/Modules/CippExtensions/Private/New-GradientServiceSyncRun.ps1 +++ b/Modules/CippExtensions/Private/New-GradientServiceSyncRun.ps1 @@ -21,12 +21,11 @@ function New-GradientServiceSyncRun { if ($NewAccounts) { Invoke-RestMethod -Uri 'https://app.usegradient.com/api/vendor-api/organization/accounts' -Method POST -Headers $GradientToken -Body $NewAccounts -ContentType 'application/json' } #setting the integration to active $ExistingIntegrations = (Invoke-RestMethod -Uri 'https://app.usegradient.com/api/vendor-api/organization' -Method GET -Headers $GradientToken) - if ($ExistingIntegrations.Status -ne "active") { + if ($ExistingIntegrations.Status -ne 'active') { $ActivateRequest = Invoke-RestMethod -Uri 'https://app.usegradient.com/api/vendor-api/organization/status/active' -Method PATCH -Headers $GradientToken } - } - catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to create tenants in Gradient API. Error: $($_.Exception.Message)" -Sev "Error" -tenant "GradientAPI" + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to create tenants in Gradient API. Error: $($_.Exception.Message)" -Sev 'Error' -tenant 'GradientAPI' } @@ -38,7 +37,8 @@ function New-GradientServiceSyncRun { $RawGraphRequest = $Tenants | ForEach-Object -Parallel { $domainName = $_.defaultDomainName - Import-Module '.\GraphHelper.psm1' + Import-Module '.\Modules\AzBobbyTables' + Import-Module '.\Modules\CIPPCore' Write-Host "Doing $domainName" try { $Licrequest = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/subscribedSkus' -tenantid $_.defaultDomainName -ErrorAction Stop @@ -46,13 +46,12 @@ function New-GradientServiceSyncRun { Tenant = $domainName Licenses = $Licrequest } - } - catch { + } catch { [PSCustomObject]@{ Tenant = $domainName Licenses = @{ skuid = "Could not connect to client: $($_.Exception.Message)" - skuPartNumber = "Could not connect to client" + skuPartNumber = 'Could not connect to client' consumedUnits = 0 prepaidUnits = { Enabled = 0 } } @@ -63,11 +62,11 @@ function New-GradientServiceSyncRun { $skuid = $singlereq.Licenses foreach ($sku in $skuid) { try { - if ($sku.skuId -eq "Could not connect to client") { continue } + if ($sku.skuId -eq 'Could not connect to client') { continue } $PrettyName = ($ConvertTable | Where-Object { $_.guid -eq $sku.skuid }).'Product_Display_Name' | Select-Object -Last 1 if (!$PrettyName) { $PrettyName = $sku.skuPartNumber } #Check if serviceID exists by SKUID in gradient - $ExistingService = (Invoke-RestMethod -Uri "https://app.usegradient.com/api/vendor-api" -Method GET -Headers $GradientToken).data.skus | Where-Object name -EQ $PrettyName + $ExistingService = (Invoke-RestMethod -Uri 'https://app.usegradient.com/api/vendor-api' -Method GET -Headers $GradientToken).data.skus | Where-Object name -EQ $PrettyName Write-Host "New service: $($ExistingService.name) ID: $($ExistingService.id)" if (!$ExistingService) { #Create service @@ -85,9 +84,8 @@ function New-GradientServiceSyncRun { unitCount = $sku.prepaidUnits.enabled } | ConvertTo-Json -Depth 10 $Results = Invoke-RestMethod -Uri "https://app.usegradient.com/api/vendor-api/service/$($ExistingService.id)/count" -Method POST -Headers $GradientToken -Body $ServiceBody -ContentType 'application/json' - } - catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to create license in Gradient API. Error: $($_). $results" -Sev "Error" -tenant $singlereq.tenant + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to create license in Gradient API. Error: $($_). $results" -Sev 'Error' -tenant $singlereq.tenant } } diff --git a/Modules/CippExtensions/Private/Set-HaloMapping.ps1 b/Modules/CippExtensions/Private/Set-HaloMapping.ps1 index 5b2d14bec742..14180d14d294 100644 --- a/Modules/CippExtensions/Private/Set-HaloMapping.ps1 +++ b/Modules/CippExtensions/Private/Set-HaloMapping.ps1 @@ -13,7 +13,9 @@ function Set-HaloMapping { 'HaloPSA' = "$($mapping.value.value)" 'HaloPSAName' = "$($mapping.value.label)" } + Add-CIPPAzDataTableEntity @CIPPMapping -Entity $AddObject -Force + Write-LogMessage -API $APINAME -user $request.headers.'x-ms-client-principal' -message "Added mapping for $($mapping.name)." -Sev 'Info' } $Result = [pscustomobject]@{'Results' = "Successfully edited mapping table." } diff --git a/PublicWebhooks/function.json b/PublicWebhooks/function.json index 4ee273331c44..f59adac3eb84 100644 --- a/PublicWebhooks/function.json +++ b/PublicWebhooks/function.json @@ -11,6 +11,12 @@ "type": "http", "direction": "out", "name": "Response" + }, + { + "type": "queue", + "direction": "out", + "name": "QueueWebhook", + "queueName": "webhooksqueue" } ] } diff --git a/PublicWebhooks/run.ps1 b/PublicWebhooks/run.ps1 index c4bbcf27dcf9..232c44458572 100644 --- a/PublicWebhooks/run.ps1 +++ b/PublicWebhooks/run.ps1 @@ -2,6 +2,8 @@ using namespace System.Net # Input bindings are passed in via param block. param($Request, $TriggerMetadata) + + $WebhookTable = Get-CIPPTable -TableName webhookTable $Webhooks = Get-CIPPAzDataTableEntity @WebhookTable Write-Host "Received request" @@ -11,41 +13,17 @@ Write-Host $url if ($Request.CIPPID -in $Webhooks.CIPPID) { Write-Host "Found matching CIPPID" - $Webhookinfo = $Webhooks | Where-Object -Property RowKey -EQ $Request.query.CIPPID - $operations = $Webhookinfo.Operations -split ',' if ($Request.query.ValidationToken -or $Request.body.validationCode) { Write-Host "Validation token received" $body = $request.query.ValidationToken + } else { + Push-OutputBinding -Name QueueWebhook -Value $Request + $Body = 'Webhook Recieved' } - - foreach ($ReceivedItem In ($Request.body)) { - $ReceivedItem = [pscustomobject]$ReceivedItem - $TenantFilter = (Get-Tenants | Where-Object -Property customerId -EQ $ReceivedItem.TenantId).defaultDomainName - Write-Host "TenantFilter: $TenantFilter" - $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" - Write-Host "Data to process found: $(($ReceivedItem.operation).count) items" - Write-Host "Operations to process for this client: $($Webhookinfo.Operations)" - foreach ($Item in $Data) { - Write-Host "Processing $($item.operation)" - if ($item.operation -in $operations) { - Invoke-CippWebhookProcessing -TenantFilter $TenantFilter -Data $Item -CIPPPURL $url -allowedlocations $Webhookinfo.AllowedLocations -Operations $operations - } - if ($item.operation -eq "UserLoggedIn" -and "UserLoggedInFromUnknownLocation" -in $operations) { - Invoke-CippWebhookProcessing -TenantFilter $TenantFilter -Data $Item -CIPPPURL $url -allowedlocations $Webhookinfo.AllowedLocations -Operations $operations - } - if ($item.operation -eq "UserLoggedIn" -and "AdminLoggedIn" -in $operations) { - Invoke-CippWebhookProcessing -TenantFilter $TenantFilter -Data $Item -CIPPPURL $url -allowedlocations $Webhookinfo.AllowedLocations -Operations $operations - } - $body = "OK" - } - } - -} -else { +} else { $body = "This webhook is not authorized." } - # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK diff --git a/ExecGDAPMigrationQueue/function.json b/PublicWebhooksProcess/function.json similarity index 77% rename from ExecGDAPMigrationQueue/function.json rename to PublicWebhooksProcess/function.json index e581d4804e4d..d358059b9e50 100644 --- a/ExecGDAPMigrationQueue/function.json +++ b/PublicWebhooksProcess/function.json @@ -4,7 +4,7 @@ "name": "QueueItem", "type": "queueTrigger", "direction": "in", - "queueName": "gdapqueue" + "queueName": "webhooksqueue" } ] } diff --git a/PublicWebhooksProcess/run.ps1 b/PublicWebhooksProcess/run.ps1 new file mode 100644 index 000000000000..8c5f91227ceb --- /dev/null +++ b/PublicWebhooksProcess/run.ps1 @@ -0,0 +1,51 @@ +using namespace System.Net + +# Input bindings are passed in via param block. +param($QueueItem, $TriggerMetadata) + +$Request = $QueueItem + +$WebhookTable = Get-CIPPTable -TableName webhookTable +$Webhooks = Get-AzDataTableEntity @WebhookTable +Write-Host "Received request" +Write-Host "CIPPID: $($request.Query.CIPPID)" +$url = ($request.headers.'x-ms-original-url').split('/API') | Select-Object -First 1 +Write-Host $url +if ($Request.query.CIPPID -in $Webhooks.RowKey) { + Write-Host "Found matching CIPPID" + $Webhookinfo = $Webhooks | Where-Object -Property RowKey -EQ $Request.query.CIPPID + + if ($Request.Query.Type = 'GraphSubscription') { + # Graph Subscriptions + [pscustomobject]$ReceivedItem = $Request.Body.value + Invoke-CippGraphWebhookProcessing -Data $ReceivedItem -CIPPID $request.Query.CIPPID -WebhookInfo $Webhookinfo + + } else { + # Auditlog Subscriptions + $Webhookinfo = $Webhooks | Where-Object -Property RowKey -EQ $Request.query.CIPPID + $operations = $Webhookinfo.Operations -split ',' + foreach ($ReceivedItem In ($Request.body)) { + $ReceivedItem = [pscustomobject]$ReceivedItem + $TenantFilter = (Get-Tenants | Where-Object -Property customerId -EQ $ReceivedItem.TenantId).defaultDomainName + Write-Host "TenantFilter: $TenantFilter" + $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" + Write-Host "Data to process found: $(($ReceivedItem.operation).count) items" + Write-Host "Operations to process for this client: $($Webhookinfo.Operations)" + foreach ($Item in $Data) { + Write-Host "Processing $($item.operation)" + if ($item.operation -in $operations) { + Invoke-CippWebhookProcessing -TenantFilter $TenantFilter -Data $Item -CIPPPURL $url -allowedlocations $Webhookinfo.AllowedLocations -Operations $operations + } + if ($item.operation -eq "UserLoggedIn" -and "UserLoggedInFromUnknownLocation" -in $operations) { + Invoke-CippWebhookProcessing -TenantFilter $TenantFilter -Data $Item -CIPPPURL $url -allowedlocations $Webhookinfo.AllowedLocations -Operations $operations + } + if ($item.operation -eq "UserLoggedIn" -and "AdminLoggedIn" -in $operations) { + Invoke-CippWebhookProcessing -TenantFilter $TenantFilter -Data $Item -CIPPPURL $url -allowedlocations $Webhookinfo.AllowedLocations -Operations $operations + } + } + } + } + +} else { + Write-Host 'Unauthorised Webhook' +} diff --git a/RemoveAPDevice/function.json b/RemoveAPDevice/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/RemoveAPDevice/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/RemoveAPDevice/run.ps1 b/RemoveAPDevice/run.ps1 deleted file mode 100644 index 945b97b0b071..000000000000 --- a/RemoveAPDevice/run.ps1 +++ /dev/null @@ -1,36 +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." - -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter -$Deviceid = $Request.Query.ID - -try { - if ($TenantFilter -eq $null -or $TenantFilter -eq "null") { - $GraphRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/windowsAutopilotDeviceIdentities/$Deviceid" -type DELETE - } - else { - $GraphRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/windowsAutopilotDeviceIdentities/$Deviceid" -tenantid $TenantFilter -type DELETE - } - Write-LogMessage -user $request.headers.'x-ms-client-principal' -tenant $TenantFilter -API $APINAME -message "Deleted autopilot device $Deviceid" -Sev "Info" - $body = [pscustomobject]@{"Results" = "Successfully deleted the autopilot device" } -} -catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -tenant $TenantFilter -API $APINAME -message "Autopilot Delete API failed for $deviceid. The error is: $($_.Exception.Message)" -Sev "Error" - $body = [pscustomobject]@{"Results" = "Failed to delete device: $($_.Exception.Message)" } -} -#force a sync, this can give "too many requests" if deleleting a bunch of devices though. -$GraphRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/windowsAutopilotSettings/sync" -tenantid $TenantFilter -type POST -body "{}" - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Body - }) \ No newline at end of file diff --git a/RemoveApp/function.json b/RemoveApp/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/RemoveApp/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/RemoveApp/run.ps1 b/RemoveApp/run.ps1 deleted file mode 100644 index f6ec2f9c1e27..000000000000 --- a/RemoveApp/run.ps1 +++ /dev/null @@ -1,31 +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" - -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter -$policyId = $Request.Query.ID -if (!$policyId) { exit } -try { - #$unAssignRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/deviceManagement/configurationPolicies('$($policyId)')/assign" -type POST -Body '{"assignments":[]}' -tenant $TenantFilter - $GraphRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/deviceAppManagement/mobileApps/$($policyId)" -type DELETE -tenant $TenantFilter - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Deleted $policyId" -Sev "Info" -tenant $TenantFilter - $body = [pscustomobject]@{"Results" = "Successfully deleted the application" } -} -catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Could not delete app $policyId. $($_.Exception.Message)" -Sev "Error" -tenant $TenantFilter - $body = [pscustomobject]@{"Results" = "Could not delete this application: $($_.Exception.Message)" } - -} - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $body - }) - -#@{ Name = 'LicJoined'; Expression = { ($_.assignedLicenses | ForEach-Object { convert-skuname -skuID $_.skuid }) -join ", " } }, @{ Name = 'Aliases'; Expression = { $_.Proxyaddresses -join ", " } }, @{ Name = 'primDomain'; Expression = { $_.userPrincipalName -split "@" | Select-Object -Last 1 } } \ No newline at end of file diff --git a/RemoveCAPolicy/function.json b/RemoveCAPolicy/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/RemoveCAPolicy/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/RemoveCAPolicy/run.ps1 b/RemoveCAPolicy/run.ps1 deleted file mode 100644 index 75397a287758..000000000000 --- a/RemoveCAPolicy/run.ps1 +++ /dev/null @@ -1,29 +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" - -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter -$policyId = $Request.Query.GUID -if (!$policyId) { exit } -try { - $GraphRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies/$($policyId)" -type DELETE -tenant $TenantFilter - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Deleted CA Policy $policyId" -Sev "Info" -tenant $TenantFilter - $body = [pscustomobject]@{"Results" = "Successfully deleted the policy" } - -} -catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Could not delete CA policy $policyId. $($_.Exception.Message)" -Sev "Error" -tenant $TenantFilter - $body = [pscustomobject]@{"Results" = "Could not delete policy: $($_.Exception.Message)" } - -} - -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $body - }) - diff --git a/RemoveCATemplate/function.json b/RemoveCATemplate/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/RemoveCATemplate/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/RemoveCATemplate/run.ps1 b/RemoveCATemplate/run.ps1 deleted file mode 100644 index 4d682d715b92..000000000000 --- a/RemoveCATemplate/run.ps1 +++ /dev/null @@ -1,29 +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' - -$ID = $request.query.id -try { - $Table = Get-CippTable -tablename 'templates' - - $Filter = "PartitionKey eq 'CATemplate' and RowKey eq '$id'" - $ClearRow = Get-CIPPAzDataTableEntity @Table -Filter $Filter -Property PartitionKey, RowKey - Remove-AzDataTableEntity @Table -Entity $clearRow - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Removed Conditional Access Template with ID $ID." -Sev 'Info' - $body = [pscustomobject]@{'Results' = 'Successfully removed Conditional Access Template' } -} catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to remove Conditional Access template $ID. $($_.Exception.Message)" -Sev 'Error' - $body = [pscustomobject]@{'Results' = "Failed to remove template: $($_.Exception.Message)" } -} - - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $body - }) - diff --git a/RemoveCippQueue/function.json b/RemoveCippQueue/function.json deleted file mode 100644 index f0af9f1ceba8..000000000000 --- a/RemoveCippQueue/function.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "scriptFile": "../Modules/CippQueue/CippQueue.psm1", - "entryPoint": "Remove-CippQueue", - "bindings": [ - { - "authLevel": "anonymous", - "type": "httpTrigger", - "direction": "in", - "name": "Request", - "methods": ["get", "post"] - }, - { - "type": "http", - "direction": "out", - "name": "Response" - } - ] -} diff --git a/RemoveContact/function.json b/RemoveContact/function.json deleted file mode 100644 index bec6849b58ab..000000000000 --- a/RemoveContact/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/RemoveContact/run.ps1 b/RemoveContact/run.ps1 deleted file mode 100644 index 4e28cb3d1f19..000000000000 --- a/RemoveContact/run.ps1 +++ /dev/null @@ -1,30 +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" -$Tenantfilter = $request.Query.tenantfilter - - -$Params = @{ - Identity = $request.query.guid -} - -try { - $Params = @{ Identity = $request.query.GUID } - - $GraphRequest = New-ExoRequest -tenantid $Tenantfilter -cmdlet "Remove-MailContact" -cmdParams $params -UseSystemMailbox $true - $Result = "Deleted $($Request.query.guid)" - Write-LogMessage -API "TransportRules" -tenant $tenantfilter -message "Deleted contact $($Request.query.guid)" -sev Debug -} -catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception - $Result = $ErrorMessage -} -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @{Results = $Result } - }) diff --git a/RemoveExConnector/function.json b/RemoveExConnector/function.json deleted file mode 100644 index bec6849b58ab..000000000000 --- a/RemoveExConnector/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/RemoveExConnector/run.ps1 b/RemoveExConnector/run.ps1 deleted file mode 100644 index 0e2469eb9b46..000000000000 --- a/RemoveExConnector/run.ps1 +++ /dev/null @@ -1,30 +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" -$Tenantfilter = $request.Query.tenantfilter - - -$Params = @{ - Identity = $request.query.guid -} - -try { - $Params = @{ Identity = $request.query.GUID } - - $GraphRequest = New-ExoRequest -tenantid $Tenantfilter -cmdlet "Remove-$($Request.query.Type)Connector" -cmdParams $params - $Result = "Deleted $($Request.query.guid)" - Write-LogMessage -API "TransportRules" -tenant $tenantfilter -message "Deleted transport rule $($Request.query.guid)" -sev Debug -} -catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception - $Result = $ErrorMessage -} -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @{Results = $Result } - }) diff --git a/RemoveExConnectorTemplate/function.json b/RemoveExConnectorTemplate/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/RemoveExConnectorTemplate/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/RemoveExConnectorTemplate/run.ps1 b/RemoveExConnectorTemplate/run.ps1 deleted file mode 100644 index 718e4e72e403..000000000000 --- a/RemoveExConnectorTemplate/run.ps1 +++ /dev/null @@ -1,28 +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' - -$ID = $request.query.id -try { - $Table = Get-CippTable -tablename 'templates' - $Filter = "PartitionKey eq 'ExConnectorTemplate' and RowKey eq '$id'" - $ClearRow = Get-CIPPAzDataTableEntity @Table -Filter $Filter -Property PartitionKey, RowKey - Remove-AzDataTableEntity @Table -Entity $clearRow - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Removed Exchange Connector Template with ID $ID." -Sev 'Info' - $body = [pscustomobject]@{'Results' = 'Successfully removed Exchange Connector Template' } -} catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to remove Exchange Connector Template $ID. $($_.Exception.Message)" -Sev 'Error' - $body = [pscustomobject]@{'Results' = "Failed to remove template: $($_.Exception.Message)" } -} - - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $body - }) - diff --git a/RemoveGroupTemplate/function.json b/RemoveGroupTemplate/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/RemoveGroupTemplate/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/RemoveGroupTemplate/run.ps1 b/RemoveGroupTemplate/run.ps1 deleted file mode 100644 index d9069b9f7e3c..000000000000 --- a/RemoveGroupTemplate/run.ps1 +++ /dev/null @@ -1,31 +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' - -$ID = $request.query.id -try { - $Table = Get-CippTable -tablename 'templates' - Write-Host $id - - $Filter = "PartitionKey eq 'GroupTemplate' and RowKey eq '$id'" - Write-Host $Filter - $ClearRow = Get-CIPPAzDataTableEntity @Table -Filter $Filter -Property PartitionKey, RowKey - Remove-AzDataTableEntity @Table -Entity $clearRow - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Removed Intune Template with ID $ID." -Sev 'Info' - $body = [pscustomobject]@{'Results' = 'Successfully removed Template' } -} catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to remove intune template $ID. $($_.Exception.Message)" -Sev 'Error' - $body = [pscustomobject]@{'Results' = "Failed to remove template: $($_.Exception.Message)" } -} - - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $body - }) - diff --git a/RemoveIntuneTemplate/function.json b/RemoveIntuneTemplate/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/RemoveIntuneTemplate/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/RemoveIntuneTemplate/run.ps1 b/RemoveIntuneTemplate/run.ps1 deleted file mode 100644 index c4f678b4eef4..000000000000 --- a/RemoveIntuneTemplate/run.ps1 +++ /dev/null @@ -1,31 +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' - -$ID = $request.query.id -try { - $Table = Get-CippTable -tablename 'templates' - Write-Host $id - - $Filter = "PartitionKey eq 'IntuneTemplate' and RowKey eq '$id'" - Write-Host $Filter - $ClearRow = Get-CIPPAzDataTableEntity @Table -Filter $Filter -Property PartitionKey, RowKey - Remove-AzDataTableEntity @Table -Entity $clearRow - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Removed Intune Template with ID $ID." -Sev 'Info' - $body = [pscustomobject]@{'Results' = 'Successfully removed Intune Template' } -} catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to remove intune template $ID. $($_.Exception.Message)" -Sev 'Error' - $body = [pscustomobject]@{'Results' = "Failed to remove template: $($_.Exception.Message)" } -} - - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $body - }) - diff --git a/RemovePolicy/function.json b/RemovePolicy/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/RemovePolicy/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/RemovePolicy/run.ps1 b/RemovePolicy/run.ps1 deleted file mode 100644 index 8b0c01d8b698..000000000000 --- a/RemovePolicy/run.ps1 +++ /dev/null @@ -1,33 +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" - -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter -$policyId = $Request.Query.ID -if (!$policyId) { exit } -try { - - #$unAssignRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/deviceManagement/configurationPolicies('$($policyId)')/assign" -type POST -Body '{"assignments":[]}' -tenant $TenantFilter - $GraphRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$($Request.Query.URLName)('$($policyId)')" -type DELETE -tenant $TenantFilter - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Deleted $policyId" -Sev "Info" -tenant $TenantFilter - $body = [pscustomobject]@{"Results" = "Successfully deleted the policy" } - -} -catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Could not delete policy $policyId. $($_.Exception.Message)" -Sev "Error" -tenant $TenantFilter - $body = [pscustomobject]@{"Results" = "Could not delete policy: $($_.Exception.Message)" } - -} - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $body - }) - -#@{ Name = 'LicJoined'; Expression = { ($_.assignedLicenses | ForEach-Object { convert-skuname -skuID $_.skuid }) -join ", " } }, @{ Name = 'Aliases'; Expression = { $_.Proxyaddresses -join ", " } }, @{ Name = 'primDomain'; Expression = { $_.userPrincipalName -split "@" | Select-Object -Last 1 } } \ No newline at end of file diff --git a/RemoveQueuedAlert/function.json b/RemoveQueuedAlert/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/RemoveQueuedAlert/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/RemoveQueuedAlert/run.ps1 b/RemoveQueuedAlert/run.ps1 deleted file mode 100644 index 81b7a3cb907b..000000000000 --- a/RemoveQueuedAlert/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' -$Table = Get-CIPPTable -TableName 'SchedulerConfig' -$ID = $request.query.id -try { - $Filter = "RowKey eq '{0}' and PartitionKey eq 'Alert'" -f $ID - $Alert = Get-CIPPAzDataTableEntity @Table -Filter $Filter -Property PartitionKey, RowKey - Remove-AzDataTableEntity @Table -Entity $Alert - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Removed application queue for $ID." -Sev 'Info' - $body = [pscustomobject]@{'Results' = 'Successfully removed from queue.' } -} catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to remove from queue $ID. $($_.Exception.Message)" -Sev 'Error' - $body = [pscustomobject]@{'Results' = "Failed to remove alert from queue $($_.Exception.Message)" } -} - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $body - }) - diff --git a/RemoveQueuedApp/function.json b/RemoveQueuedApp/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/RemoveQueuedApp/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/RemoveQueuedApp/run.ps1 b/RemoveQueuedApp/run.ps1 deleted file mode 100644 index 7ce40f7ca3fd..000000000000 --- a/RemoveQueuedApp/run.ps1 +++ /dev/null @@ -1,28 +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' - -$ID = $request.query.id -try { - $Table = Get-CippTable -tablename 'apps' - $Filter = "PartitionKey eq 'apps' and RowKey eq '$id'" - $ClearRow = Get-CIPPAzDataTableEntity @Table -Filter $Filter -Property PartitionKey, RowKey - Remove-AzDataTableEntity @Table -Entity $clearRow - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Removed application queue for $ID." -Sev 'Info' - $body = [pscustomobject]@{'Results' = 'Successfully removed from queue.' } -} catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to remove application queue for $ID. $($_.Exception.Message)" -Sev 'Error' - $body = [pscustomobject]@{'Results' = 'Failed to remove standard)' } -} - - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $body - }) - diff --git a/RemoveScheduledItem/function.json b/RemoveScheduledItem/function.json deleted file mode 100644 index b0ca1676cc0b..000000000000 --- a/RemoveScheduledItem/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/RemoveScheduledItem/run.ps1 b/RemoveScheduledItem/run.ps1 deleted file mode 100644 index 191c95570b0f..000000000000 --- a/RemoveScheduledItem/run.ps1 +++ /dev/null @@ -1,14 +0,0 @@ -using namespace System.Net -param($Request, $TriggerMetadata) -$APIName = $TriggerMetadata.FunctionName -Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' -$task = @{ - RowKey = $Request.Query.ID - PartitionKey = 'ScheduledTask' -} -$Table = Get-CIPPTable -TableName 'ScheduledTasks' -Remove-AzDataTableEntity @Table -Entity $task -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @{ Results = 'Task removed successfully.' } - }) \ No newline at end of file diff --git a/RemoveSpamfilter/function.json b/RemoveSpamfilter/function.json deleted file mode 100644 index bec6849b58ab..000000000000 --- a/RemoveSpamfilter/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/RemoveSpamfilter/run.ps1 b/RemoveSpamfilter/run.ps1 deleted file mode 100644 index 9d8b238e00dc..000000000000 --- a/RemoveSpamfilter/run.ps1 +++ /dev/null @@ -1,31 +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" -$Tenantfilter = $request.Query.tenantfilter - - -$Params = @{ - Identity = $request.query.name -} - -try { - $cmdlet = "Remove-HostedContentFilterRule" - $GraphRequest = New-ExoRequest -tenantid $Tenantfilter -cmdlet $cmdlet -cmdParams $params - $cmdlet = "Remove-HostedContentFilterPolicy" - $GraphRequest = New-ExoRequest -tenantid $Tenantfilter -cmdlet $cmdlet -cmdParams $params - $Result = "Deleted $($Request.query.name)" - Write-LogMessage -API "TransportRules" -tenant $tenantfilter -message "Deleted transport rule $($Request.query.name)" -sev Debug -} -catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception - $Result = $ErrorMessage -} -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @{Results = $Result } - }) diff --git a/RemoveSpamfilterTemplate/function.json b/RemoveSpamfilterTemplate/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/RemoveSpamfilterTemplate/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/RemoveSpamfilterTemplate/run.ps1 b/RemoveSpamfilterTemplate/run.ps1 deleted file mode 100644 index a79169c0995a..000000000000 --- a/RemoveSpamfilterTemplate/run.ps1 +++ /dev/null @@ -1,28 +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' - -$ID = $request.query.id -try { - $Table = Get-CippTable -tablename 'templates' - $Filter = "PartitionKey eq 'SpamfilterTemplate' and RowKey eq '$id'" - $ClearRow = Get-CIPPAzDataTableEntity @Table -Filter $Filter -Property PartitionKey, RowKey - Remove-AzDataTableEntity @Table -Entity $clearRow - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Removed Transport Rule Template with ID $ID." -Sev 'Info' - $body = [pscustomobject]@{'Results' = 'Successfully removed Transport Rule Template' } -} catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to remove Transport Rule template $ID. $($_.Exception.Message)" -Sev 'Error' - $body = [pscustomobject]@{'Results' = "Failed to remove template: $($_.Exception.Message)" } -} - - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $body - }) - diff --git a/RemoveStandard/function.json b/RemoveStandard/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/RemoveStandard/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/RemoveStandard/run.ps1 b/RemoveStandard/run.ps1 deleted file mode 100644 index c38d977111f2..000000000000 --- a/RemoveStandard/run.ps1 +++ /dev/null @@ -1,30 +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' - -$ID = $request.query.id -try { - $Table = Get-CippTable -tablename 'standards' - $Filter = "PartitionKey eq 'standards' and RowKey eq '$id'" - $ClearRow = Get-CIPPAzDataTableEntity @Table -Filter $Filter -Property PartitionKey, RowKey - Remove-AzDataTableEntity @Table -Entity $clearRow - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Removed standards for $ID." -Sev 'Info' - $body = [pscustomobject]@{'Results' = 'Successfully removed standards deployment' } - - -} catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to remove standard for $ID. $($_.Exception.Message)" -Sev 'Error' - $body = [pscustomobject]@{'Results' = 'Failed to remove standard)' } -} - - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $body - }) - diff --git a/RemoveTransportRule/function.json b/RemoveTransportRule/function.json deleted file mode 100644 index bec6849b58ab..000000000000 --- a/RemoveTransportRule/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/RemoveTransportRule/run.ps1 b/RemoveTransportRule/run.ps1 deleted file mode 100644 index 67c0d92b449e..000000000000 --- a/RemoveTransportRule/run.ps1 +++ /dev/null @@ -1,29 +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" -$Tenantfilter = $request.Query.tenantfilter - - -$Params = @{ - Identity = $request.query.guid -} - -try { - $cmdlet = "Remove-TransportRule" - $GraphRequest = New-ExoRequest -tenantid $Tenantfilter -cmdlet $cmdlet -cmdParams $params -UseSystemMailbox $true - $Result = "Deleted $($Request.query.guid)" - Write-LogMessage -API "TransportRules" -tenant $tenantfilter -message "Deleted transport rule $($Request.query.guid)" -sev Debug -} -catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception - $Result = $ErrorMessage -} -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @{Results = $Result } - }) diff --git a/RemoveTransportRuleTemplate/function.json b/RemoveTransportRuleTemplate/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/RemoveTransportRuleTemplate/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/RemoveTransportRuleTemplate/run.ps1 b/RemoveTransportRuleTemplate/run.ps1 deleted file mode 100644 index 7e4b7b6b6548..000000000000 --- a/RemoveTransportRuleTemplate/run.ps1 +++ /dev/null @@ -1,28 +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' - -$ID = $request.query.id -try { - $Table = Get-CippTable -tablename 'templates' - $Filter = "PartitionKey eq 'TransportTemplate' and RowKey eq '$id'" - $ClearRow = Get-CIPPAzDataTableEntity @Table -Filter $Filter -Property PartitionKey, RowKey - Remove-AzDataTableEntity @Table -Entity $clearRow - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Removed Transport Rule Template with ID $ID." -Sev 'Info' - $body = [pscustomobject]@{'Results' = 'Successfully removed Transport Rule Template' } -} catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to remove Transport Rule template $ID. $($_.Exception.Message)" -Sev 'Error' - $body = [pscustomobject]@{'Results' = "Failed to remove template: $($_.Exception.Message)" } -} - - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $body - }) - diff --git a/RemoveUser/function.json b/RemoveUser/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/RemoveUser/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/RemoveUser/run.ps1 b/RemoveUser/run.ps1 deleted file mode 100644 index da7e1952b713..000000000000 --- a/RemoveUser/run.ps1 +++ /dev/null @@ -1,31 +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" - -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter -$userid = $Request.Query.ID -if (!$userid) { exit } -try { - $GraphRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($userid)" -type DELETE -tenant $TenantFilter - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Deleted $userid" -Sev "Info" -tenant $TenantFilter - $body = [pscustomobject]@{"Results" = "Successfully deleted the user." } - -} -catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Could not delete user $userid. $($_.Exception.Message)" -Sev "Error" -tenant $TenantFilter - $body = [pscustomobject]@{"Results" = "Could not delete user: $($_.Exception.Message)" } - -} - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $body - }) - -#@{ Name = 'LicJoined'; Expression = { ($_.assignedLicenses | ForEach-Object { convert-skuname -skuID $_.skuid }) -join ", " } }, @{ Name = 'Aliases'; Expression = { $_.Proxyaddresses -join ", " } }, @{ Name = 'primDomain'; Expression = { $_.userPrincipalName -split "@" | Select-Object -Last 1 } } \ No newline at end of file diff --git a/RemoveWebhookAlert/function.json b/RemoveWebhookAlert/function.json deleted file mode 100644 index 306b0c51e560..000000000000 --- a/RemoveWebhookAlert/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/RemoveWebhookAlert/run.ps1 b/RemoveWebhookAlert/run.ps1 deleted file mode 100644 index dbda93213351..000000000000 --- a/RemoveWebhookAlert/run.ps1 +++ /dev/null @@ -1,24 +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" - -try { - $Results = Remove-CIPPGraphSubscription -TenantFilter $Request.query.TenantFilter -CIPPID $Request.query.CIPPID - $body = [pscustomobject]@{"Results" = $Results } -} -catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to remove webhook alert. $($_.Exception.Message)" -Sev "Error" - $body = [pscustomobject]@{"Results" = "Failed to remove webhook alert: $($_.Exception.Message)" } -} - - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $body - }) - diff --git a/Scheduler_Extensions/function.json b/Scheduler_Extensions/function.json new file mode 100644 index 000000000000..a0b7faadd73d --- /dev/null +++ b/Scheduler_Extensions/function.json @@ -0,0 +1,16 @@ +{ + "bindings": [ + { + "name": "Timer", + "schedule": "0 */15 * * * *", + "direction": "in", + "type": "timerTrigger" + }, + { + "type": "queue", + "direction": "out", + "name": "NinjaProcess", + "queueName": "NinjaOneQueue" + } + ] +} diff --git a/Scheduler_Extensions/run.ps1 b/Scheduler_Extensions/run.ps1 new file mode 100644 index 000000000000..b8d80be6a5bf --- /dev/null +++ b/Scheduler_Extensions/run.ps1 @@ -0,0 +1,65 @@ +using namespace System.Net + +param($Timer) + +$Table = Get-CIPPTable -TableName Extensionsconfig + +$Configuration = ((Get-AzDataTableEntity @Table).config | ConvertFrom-Json) + +Write-Host "Started Scheduler for Extensions" + +# NinjaOne Extension +if ($Configuration.NinjaOne.Enabled -eq $True) { + + $Table = Get-CIPPTable -TableName NinjaOneSettings + $Settings = (Get-AzDataTableEntity @Table) + $TimeSetting = ($Settings | Where-Object { $_.RowKey -eq 'NinjaSyncTime' }).SettingValue + + + + if (($TimeSetting | Measure-Object).count -ne 1) { + [int]$TimeSetting = Get-Random -Minimum 1 -Maximum 95 + $AddObject = @{ + PartitionKey = 'NinjaConfig' + RowKey = 'NinjaSyncTime' + 'SettingValue' = $TimeSetting + } + Add-AzDataTableEntity @Table -Entity $AddObject -Force + } + + Write-Host "Ninja Time Setting: $TimeSetting" + + $LastRunTime = Get-Date(($Settings | Where-Object { $_.RowKey -eq 'NinjaLastRunTime' }).SettingValue) + + Write-Host "Last Run: $LastRunTime" + + $CurrentTime = Get-Date + $CurrentInterval = ($CurrentTime.Hour * 4) + [math]::Floor($CurrentTime.Minute / 15) + + Write-Host "Current Interval: $CurrentInterval" + + if ($Null -eq $LastRunTime -or $LastRunTime -le (Get-Date).addhours(-25) -or $TimeSetting -eq $CurrentInterval) { + Write-Host "Executing" + $CIPPMapping = Get-CIPPTable -TableName CippMapping + $Filter = "PartitionKey eq 'NinjaOrgsMapping'" + $TenantsToProcess = Get-AzDataTableEntity @CIPPMapping -Filter $Filter | Where-Object { $Null -ne $_.NinjaOne -and $_.NinjaOne -ne '' } + + foreach ($Tenant in $TenantsToProcess) { + Push-OutputBinding -Name NinjaProcess -Value @{ + 'NinjaAction' = 'SyncTenant' + 'MappedTenant' = $Tenant + } + + } + + $AddObject = @{ + PartitionKey = 'NinjaConfig' + RowKey = 'NinjaLastRunTime' + 'SettingValue' = (Get-Date).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffK") + } + Add-AzDataTableEntity @Table -Entity $AddObject -Force + + Write-LogMessage -API 'NinjaOneAutoMap_Queue' -user 'CIPP' -message "NinjaOne Synchronization Queued for $(($TenantsToProcess | Measure-Object).count) Tenants" -Sev 'Info' + + } +} \ No newline at end of file diff --git a/Scheduler_RenewGraphSubscriptions/function.json b/Scheduler_RenewGraphSubscriptions/function.json new file mode 100644 index 000000000000..d2e7f34face4 --- /dev/null +++ b/Scheduler_RenewGraphSubscriptions/function.json @@ -0,0 +1,10 @@ +{ + "bindings": [ + { + "name": "Timer", + "type": "timerTrigger", + "direction": "in", + "schedule": "0 0 0 * * *" + } + ] +} diff --git a/Scheduler_RenewGraphSubscriptions/run.ps1 b/Scheduler_RenewGraphSubscriptions/run.ps1 new file mode 100644 index 000000000000..b688e87e8b17 --- /dev/null +++ b/Scheduler_RenewGraphSubscriptions/run.ps1 @@ -0,0 +1,10 @@ +# Input bindings are passed in via param block. +param($Timer) + +# Get the current universal time in the default string format. +try { + Write-LogMessage -API "Scheduler_RenewGraphSubscriptions" -tenant "none" -message "Starting Graph Subscription Renewal" -sev Info + Invoke-CippGraphWebhookRenewal +} catch { + Write-LogMessage -API "Scheduler_RenewGraphSubscriptions" -tenant "none" -message "Failed to renew graph subscriptions" -sev Info +} \ No newline at end of file diff --git a/SendStats/run.ps1 b/SendStats/run.ps1 index 5e86e35e980f..b4427d230338 100644 --- a/SendStats/run.ps1 +++ b/SendStats/run.ps1 @@ -4,13 +4,13 @@ param($Timer) #These stats are sent to a central server to help us understand how many tenants are using the product, and how many are using the latest version, this information allows the CIPP team to make decisions about what features to support, and what features to deprecate. #We will never ship any data that is related to your instance, all we care about is the number of tenants, and the version of the API you are running, and if you completed setup. -if ($ENV:applicationid -ne "LongApplicationID") { +if ($ENV:applicationid -ne 'LongApplicationID') { $SetupComplete = $true } $TenantCount = (Get-Tenants).count Set-Location (Get-Item $PSScriptRoot).Parent.FullName -$APIVersion = Get-Content "version_latest.txt" | Out-String +$APIVersion = Get-Content 'version_latest.txt' | Out-String $SendingObject = [PSCustomObject]@{ rgid = $env:WEBSITE_SITE_NAME diff --git a/Standards_DisableGuests/run.ps1 b/Standards_DisableGuests/run.ps1 index deefc9445601..abf43e7bfb11 100644 --- a/Standards_DisableGuests/run.ps1 +++ b/Standards_DisableGuests/run.ps1 @@ -5,10 +5,10 @@ try { $GraphRequest = New-GraphgetRequest -uri "https://graph.microsoft.com/beta/users?`$filter=(signInActivity/lastSignInDateTime le $lookup)&`$select=id,UserPrincipalName,signInActivity,mail,userType,accountEnabled" -scope "https://graph.microsoft.com/.default" -tenantid $Tenant | Where-Object { $_.userType -EQ 'Guest' -and $_.AccountEnabled -EQ $true } foreach ($guest in $GraphRequest) { New-GraphPostRequest -type Patch -tenantid $tenant -uri "https://graph.microsoft.com/beta/users/$($guest.id)" -body '{"accountEnabled":"false"}' - Write-LogMessage -API "Standards" -tenant $tenant -message "Disabling guest $($guest.UserPrincipalName) ($($guest.id))" -sev Info + Write-LogMessage -API "Standards" -tenant $tenant -message "Disabling guest $($guest.UserPrincipalName) ($($guest.id))" -sev Info } - Write-LogMessage -API "Standards" -tenant $tenant -message "Disabled guests accounts with a login longer than 90 days ago." -sev Info + Write-LogMessage -API "Standards" -tenant $tenant -message "Disabled guests accounts with a login longer than 90 days ago." -sev Info } catch { - Write-LogMessage -API "Standards" -tenant $tenant -message "Failed to disable guests older than 90 days: $($_.exception.message)" -sev Error + Write-LogMessage -API "Standards" -tenant $tenant -message "Failed to disable guests older than 90 days: $($_.exception.message)" -sev Error } \ No newline at end of file diff --git a/Standards_DisableSelfServiceLicenses/run.ps1 b/Standards_DisableSelfServiceLicenses/run.ps1 index 50f3be239b63..3a6960cdd678 100644 --- a/Standards_DisableSelfServiceLicenses/run.ps1 +++ b/Standards_DisableSelfServiceLicenses/run.ps1 @@ -1,9 +1,9 @@ param($tenant) try { - Write-LogMessage "Standards API: $($tenant) failed to disable License Buy Self Service: $($exception.message)" -sev Error - + Write-LogMessage -API "Standards" -tenant $tenant -message "Failed to disable License Buy Self Service: $($_.exception.message)" -sev Error + } catch { - Write-LogMessage "Standards API: $($tenant) failed to disable License Buy Self Service: $($exception.message)" -sev Error + Write-LogMessage -API "Standards" -tenant $tenant -message "Failed to disable License Buy Self Service: $($_.exception.message)" -sev Error } \ No newline at end of file diff --git a/Standards_EnableAppConsentRequests/function.json b/Standards_EnableAppConsentRequests/function.json new file mode 100644 index 000000000000..2d4ea9094b24 --- /dev/null +++ b/Standards_EnableAppConsentRequests/function.json @@ -0,0 +1,9 @@ +{ + "bindings": [ + { + "name": "tenant", + "direction": "in", + "type": "activityTrigger" + } + ] +} \ No newline at end of file diff --git a/Standards_EnableAppConsentRequests/run.ps1 b/Standards_EnableAppConsentRequests/run.ps1 new file mode 100644 index 000000000000..03d3e12bc621 --- /dev/null +++ b/Standards_EnableAppConsentRequests/run.ps1 @@ -0,0 +1,66 @@ +param($tenant) + +try { + + $ConfigTable = Get-CippTable -tablename 'standards' + $Setting = ((Get-CIPPAzDataTableEntity @ConfigTable -Filter "PartitionKey eq 'standards' and RowKey eq '$tenant'").JSON | ConvertFrom-Json).standards.EnableAppConsentRequests + if (!$Setting) { + $Setting = ((Get-CIPPAzDataTableEntity @ConfigTable -Filter "PartitionKey eq 'standards' and RowKey eq 'AllTenants'").JSON | ConvertFrom-Json).standards.EnableAppConsentRequests + } + + # Get current state + $CurrentInfo = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/policies/adminConsentRequestPolicy' -tenantid $Tenant + + # Change state to enabled with default settings + $CurrentInfo.isEnabled = 'true' + $CurrentInfo.notifyReviewers = 'true' + $CurrentInfo.remindersEnabled = 'true' + $CurrentInfo.requestDurationInDays = 30 + + # Roles from standards table + $RolesToAdd = $Setting.ReviewerRoles.value + $RoleNames = $Setting.ReviewerRoles.label -join ', ' + + # Set default if no roles are selected + if (!$RolesToAdd) { + $RolesToAdd = @('62e90394-69f5-4237-9190-012177145e10') + $RoleNames = '(Default) Global Administrator' + } + + $NewReviewers = foreach ($Role in $RolesToAdd) { + @{ + query = "/beta/roleManagement/directory/roleAssignments?`$filter=roleDefinitionId eq '$Role'" + queryType = 'MicrosoftGraph' + queryRoot = 'null' + } + } + + # Add existing reviewers + $Reviewers = [System.Collections.Generic.List[object]]::new() + foreach ($Reviewer in $CurrentInfo.reviewers) { + $RoleFound = $false + foreach ($Role in $RolesToAdd) { + if ($Reviewer.query -match $Role -or $Reviewers.query -contains $Reviewer.query) { + $RoleFound = $true + } + } + if (!$RoleFound) { + $Reviewers.add($Reviewer) + } + } + + # Add new reviewer roles + foreach ($NewReviewer in $NewReviewers) { + $Reviewers.add($NewReviewer) + } + + # Update reviewer list + $CurrentInfo.reviewers = @($Reviewers) + $body = (ConvertTo-Json -Compress -Depth 10 -InputObject $CurrentInfo) + + New-GraphPostRequest -tenantid $tenant -Uri 'https://graph.microsoft.com/beta/policies/adminConsentRequestPolicy' -Type put -Body $body -ContentType 'application/json' + Write-LogMessage -API 'Standards' -tenant $tenant -message "Enabled App consent admin requests for the following roles: $RoleNames" -sev Info + +} catch { + Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to enable App consent admin requests. Error: $($_.exception.message)" -sev Error +} diff --git a/Standards_NudgeMFA/run.ps1 b/Standards_NudgeMFA/run.ps1 index 29fb5b21227e..0ec7b80ef78d 100644 --- a/Standards_NudgeMFA/run.ps1 +++ b/Standards_NudgeMFA/run.ps1 @@ -17,8 +17,8 @@ try { $body.registrationEnforcement.authenticationMethodsRegistrationCampaign.state = $status $body = ConvertTo-Json -Depth 10 -InputObject ($body | Select-Object registrationEnforcement) New-GraphPostRequest -tenantid $tenant -Uri "https://graph.microsoft.com/beta/policies/authenticationMethodsPolicy" -Type patch -Body $body -ContentType "application/json" - Write-LogMessage -API "Standards" -tenant $tenant -message "$status Authenticator App Nudge" -sev Info + Write-LogMessage -API "Standards" -tenant $tenant -message "Authenticator App Nudge/Registration campaign $status." -sev Info } catch { - Write-LogMessage -API "Standards" -tenant $tenant -message "Failed to $status Authenticator App Nudge: $($_.exception.message)" -sev Error + Write-LogMessage -API "Standards" -tenant $tenant -message "Failed to $status Authenticator App Nudge/Registration campaign: $($_.exception.message)" -sev Error } \ No newline at end of file diff --git a/Standards_allowOTPTokens/run.ps1 b/Standards_allowOTPTokens/run.ps1 index c9d138129cce..6344508da742 100644 --- a/Standards_allowOTPTokens/run.ps1 +++ b/Standards_allowOTPTokens/run.ps1 @@ -8,8 +8,8 @@ try { $body = ($CurrentInfo | ConvertTo-Json -Depth 10) (New-GraphPostRequest -tenantid $tenant -Uri "https://graph.microsoft.com/beta/policies/authenticationMethodsPolicy/authenticationMethodConfigurations/microsoftAuthenticator" -Type patch -Body $body -ContentType "application/json") - Write-LogMessage -API "Standards" -tenant $tenant -message "Enabled MS authenticator OTP/oAuth tokens" -sev Info + Write-LogMessage -API "Standards" -tenant $tenant -message "Enabled MS authenticator OTP/oAuth tokens" -sev Info } catch { - Write-LogMessage -API "Standards" -tenant $tenant -message "Failed to enable MS authenticator OTP/oAuth tokens. Error: $($_.exception.message)" -sev "Error" + Write-LogMessage -API "Standards" -tenant $tenant -message "Failed to enable MS authenticator OTP/oAuth tokens. Error: $($_.exception.message)" -sev Error } \ No newline at end of file diff --git a/Standards_calDefault/run.ps1 b/Standards_calDefault/run.ps1 index 49c2b9702549..f2e54d38773a 100644 --- a/Standards_calDefault/run.ps1 +++ b/Standards_calDefault/run.ps1 @@ -10,9 +10,9 @@ if (!$Setting) { $Mailboxes = New-ExoRequest -tenantid $Tenant -cmdlet "get-mailbox" foreach ($Mailbox in $Mailboxes) { try { - New-ExoRequest -tenantid $Tenant -cmdlet "Get-MailboxFolderStatistics" -cmdParams @{identity = $Mailbox.UserPrincipalName; FolderScope = 'Calendar' } -Anchor $Mailbox.UserPrincipalName | ForEach-Object { + New-ExoRequest -tenantid $Tenant -cmdlet "Get-MailboxFolderStatistics" -cmdParams @{identity = $Mailbox.UserPrincipalName; FolderScope = 'Calendar' } -Anchor $Mailbox.UserPrincipalName | Where-Object { $_.FolderType -eq 'Calendar' } | ForEach-Object { New-ExoRequest -tenantid $Tenant -cmdlet "Set-MailboxFolderPermission" -cmdparams @{Identity = "$($Mailbox.UserPrincipalName):$($_.FolderId)"; User = 'Default'; AccessRights = $setting.permissionlevel } -Anchor $Mailbox.UserPrincipalName - Write-LogMessage -API "Standards" -tenant $tenant -message "Set default folder permission for $($Mailbox.UserPrincipalName):\$($_.Name) to $($setting.permissionlevel)" -sev Error + Write-LogMessage -API "Standards" -tenant $tenant -message "Set default folder permission for $($Mailbox.UserPrincipalName):\$($_.Name) to $($setting.permissionlevel)" -sev Info } } catch { diff --git a/Standards_fwdAdminAlerts/run.ps1 b/Standards_fwdAdminAlerts/run.ps1 index b3160913ad5b..fa5add33f029 100644 --- a/Standards_fwdAdminAlerts/run.ps1 +++ b/Standards_fwdAdminAlerts/run.ps1 @@ -11,15 +11,13 @@ $Mailboxes = New-ExoRequest -tenantid $Tenant -cmdlet "get-mailbox" foreach ($Mailbox in $Mailboxes) { try { New-ExoRequest -tenantid $Tenant -cmdlet "Get-MailboxFolderStatistics" -cmdParams @{identity = $Mailbox.UserPrincipalName; FolderScope = 'Calendar' } -Anchor $Mailbox.UserPrincipalName | ForEach-Object { - New-ExoRequest -tenantid $Tenant -cmdlet "Set-MailboxFolderPermission" -cmdparams @{Identity = ($_.identity).replace('\', ':\'); User = 'Default'; AccessRights = $setting.permissionlevel } -Anchor $Mailbox.UserPrincipalName - Write-LogMessage -API "Standards" -tenant $tenant -message "Set default folder permission for $($Mailbox.UserPrincipalName) to $($setting.permissionlevel)" -sev Error - + New-ExoRequest -tenantid $Tenant -cmdlet "Set-MailboxFolderPermission" -cmdparams @{Identity = "$($Mailbox.UserPrincipalName):$($_.FolderId)"; User = 'Default'; AccessRights = $setting.permissionlevel } -Anchor $Mailbox.UserPrincipalName + Write-LogMessage -API "Standards" -tenant $tenant -message "Set default folder permission for $($Mailbox.UserPrincipalName):\$($_.Name) to $($setting.permissionlevel)" -sev Info } } catch { - Write-LogMessage -API "Standards" -tenant $tenant -message "Could not set default calendar permissions. Error: $($_.exception.message)" -sev Error + Write-LogMessage -API "Standards" -tenant $tenant -message "Could not set default calendar permissions for $($Mailbox.UserPrincipalName). Error: $($_.exception.message)" -sev Error } } -Write-LogMessage -API "Standards" -tenant $tenant -message "Done setting default calendar permissions." -sev Info - +Write-LogMessage -API "Standards" -tenant $tenant -message "Done setting default calendar permissions." -sev Info \ No newline at end of file diff --git a/Tools/Initialize-DevEnvironment.ps1 b/Tools/Initialize-DevEnvironment.ps1 index 46d6088ea4ce..4f4f8f55aa58 100644 --- a/Tools/Initialize-DevEnvironment.ps1 +++ b/Tools/Initialize-DevEnvironment.ps1 @@ -9,7 +9,6 @@ ForEach ($Key in $CIPPSettings.PSObject.Properties.Name) { } } -Import-Module "$CippRoot\GraphHelper.psm1" Import-Module "$CippRoot\Modules\AzBobbyTables" Import-Module "$CippRoot\Modules\DNSHealth" Import-Module "$CippRoot\Modules\CippQueue" diff --git a/UpdatePermissionsQueue/run.ps1 b/UpdatePermissionsQueue/run.ps1 index 8756f33019be..9b147478e274 100644 --- a/UpdatePermissionsQueue/run.ps1 +++ b/UpdatePermissionsQueue/run.ps1 @@ -4,7 +4,7 @@ Write-Host "Applying permissions for $($QueueItem.defaultDomainName)" $Table = Get-CIPPTable -TableName cpvtenants $CPVRows = Get-CIPPAzDataTableEntity @Table | Where-Object -Property Tenant -EQ $QueueItem.customerId if (!$CPVRows -or $ENV:ApplicationID -notin $CPVRows.applicationId) { - Write-LogMessage -message "A New tenant has been added, or a new CIPP-SAM Application is in use: $($queueitem.defaultDomainName) with id $($queueitem.customerId)" -Sev "Warn" -API "NewTenant" + Write-LogMessage -tenant $queueitem.defaultDomainName -tenantId $queueitem.customerId -message "A New tenant has been added, or a new CIPP-SAM Application is in use" -Sev "Warn" -API "NewTenant" Write-Host "Adding CPV permissions" Set-CIPPCPVConsent -Tenantfilter $QueueItem.defaultDomainName } @@ -12,4 +12,4 @@ if (!$CPVRows -or $ENV:ApplicationID -notin $CPVRows.applicationId) { Add-CIPPApplicationPermission -RequiredResourceAccess "CippDefaults" -ApplicationId $ENV:ApplicationID -tenantfilter $QueueItem.defaultDomainName Add-CIPPDelegatedPermission -RequiredResourceAccess "CippDefaults" -ApplicationId $ENV:ApplicationID -tenantfilter $QueueItem.defaultDomainName -Write-LogMessage -message "Updated permissions for $QueueItem" -Sev "Info" -tenant $QueueItem.defaultDomainName -API "UpdatePermissionsQueue" +Write-LogMessage -tenant $QueueItem.defaultDomainName -tenantId $queueitem.customerId -message "Updated permissions for $($QueueItem.defaultDomainName)" -Sev "Info" -API "UpdatePermissionsQueue" \ No newline at end of file diff --git a/Z_CIPPHttpTrigger/function.json b/Z_CIPPHttpTrigger/function.json index 8bcb9e5eb526..90c8dc9ea6af 100644 --- a/Z_CIPPHttpTrigger/function.json +++ b/Z_CIPPHttpTrigger/function.json @@ -21,6 +21,90 @@ "name": "QueueItem", "queueName": "CIPPGenericQueue" }, + { + "type": "queue", + "direction": "out", + "name": "Subscription", + "queueName": "AlertSubscriptions" + }, + { + "type": "queue", + "direction": "out", + "name": "LicenseQueue", + "queueName": "licqueue" + }, + { + "type": "queue", + "direction": "out", + "name": "mbxrulequeue", + "queueName": "mbxrulequeue" + }, + { + "type": "queue", + "direction": "out", + "name": "mfaqueue", + "queueName": "mfaqueue" + }, + { + "type": "queue", + "direction": "out", + "name": "mailboxstats", + "queueName": "generalAllTenantQueue" + }, + { + "type": "queue", + "direction": "out", + "name": "listusers", + "queueName": "generalAllTenantQueue" + }, + { + "type": "queue", + "direction": "out", + "name": "gradientqueue", + "queueName": "billqueue" + }, + { + "type": "queue", + "direction": "out", + "name": "NinjaProcess", + "queueName": "NinjaOneQueue" + }, + { + "type": "queue", + "direction": "out", + "name": "alertqueue", + "queueName": "alertqueue" + }, + { + "type": "queue", + "direction": "out", + "name": "gdapinvitequeue", + "queueName": "gdapinvitequeue" + }, + { + "type": "queue", + "direction": "out", + "name": "gdapqueue", + "queueName": "gdapqueue" + }, + { + "type": "queue", + "direction": "out", + "name": "incidentqueue", + "queueName": "incidentqueue" + }, + { + "type": "queue", + "direction": "out", + "name": "offboardingmailbox", + "queueName": "offboardingmailbox" + }, + { + "type": "queue", + "direction": "out", + "name": "QueueWebhook", + "queueName": "webhooksqueue" + }, { "name": "starter", "type": "durableClient", diff --git a/profile.ps1 b/profile.ps1 index 056111747b68..66e78cec4b1c 100644 --- a/profile.ps1 +++ b/profile.ps1 @@ -11,7 +11,8 @@ # Authenticate with Azure PowerShell using MSI. # Remove this if you are not planning on using MSI or Azure PowerShell. -Import-Module .\GraphHelper.psm1 +Import-Module CippCore + try { Import-Module Az.KeyVault -ErrorAction Stop } catch { $_.Exception.Message } @@ -19,7 +20,6 @@ try { Import-Module Az.Accounts } catch { $_.Exception.Message } Import-Module CippExtensions -Import-Module CippCore try { Disable-AzContextAutosave -Scope Process | Out-Null diff --git a/version_latest.txt b/version_latest.txt index f4fa8fcb995d..5ca7df98c441 100644 --- a/version_latest.txt +++ b/version_latest.txt @@ -1 +1 @@ -4.6.1 \ No newline at end of file +4.7.4 \ No newline at end of file