From 42c719a74b6dfe7b42b5d49497883e8ee84cda78 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Sun, 11 Jun 2023 14:42:42 -0400 Subject: [PATCH 01/44] Entrypoint handling Generic entrypoint handler that calls respective function from Modules Break GraphRequests into separate module files --- ListGraphRequest/function.json | 6 +- ListGraphRequestQueue/function.json | 6 +- Modules/CippEntrypoints/CippEntrypoints.psm1 | 42 ++ Modules/GraphRequests/GraphRequests.psm1 | 399 +----------------- .../GraphRequests/Private/Get-StringHash.ps1 | 8 + .../Public/Get-GraphRequestList.ps1 | 218 ++++++++++ .../Public/Get-ListGraphRequest.ps1 | 110 +++++ .../Public/Push-ListGraphRequestQueue.ps1 | 65 +++ profile.ps1 | 2 + 9 files changed, 458 insertions(+), 398 deletions(-) create mode 100644 Modules/CippEntrypoints/CippEntrypoints.psm1 create mode 100644 Modules/GraphRequests/Private/Get-StringHash.ps1 create mode 100644 Modules/GraphRequests/Public/Get-GraphRequestList.ps1 create mode 100644 Modules/GraphRequests/Public/Get-ListGraphRequest.ps1 create mode 100644 Modules/GraphRequests/Public/Push-ListGraphRequestQueue.ps1 diff --git a/ListGraphRequest/function.json b/ListGraphRequest/function.json index 8d0ea74203dd..a58da1def32f 100644 --- a/ListGraphRequest/function.json +++ b/ListGraphRequest/function.json @@ -1,6 +1,6 @@ { - "scriptFile": "../Modules/GraphRequests/GraphRequests.psm1", - "entryPoint": "Get-GraphRequestListHttp", + "scriptFile": "../Modules/CippEntryPoints/CippEntryPoints.psm1", + "entryPoint": "Receive-CippHttpTrigger", "bindings": [ { "authLevel": "anonymous", @@ -17,7 +17,7 @@ { "type": "queue", "direction": "out", - "name": "QueueTenant", + "name": "QueueItem", "queueName": "GraphRequestQueue" } ] diff --git a/ListGraphRequestQueue/function.json b/ListGraphRequestQueue/function.json index 8837488872b1..372b2c5a4b4a 100644 --- a/ListGraphRequestQueue/function.json +++ b/ListGraphRequestQueue/function.json @@ -1,9 +1,9 @@ { - "scriptFile": "../Modules/GraphRequests/GraphRequests.psm1", - "entryPoint": "Push-GraphRequestListQueue", + "scriptFile": "../Modules/CippEntryPoints/CippEntryPoints.psm1", + "entryPoint": "Receive-CippQueueTrigger", "bindings": [ { - "name": "QueueTenant", + "name": "QueueItem", "type": "queueTrigger", "direction": "in", "queueName": "GraphRequestQueue" diff --git a/Modules/CippEntrypoints/CippEntrypoints.psm1 b/Modules/CippEntrypoints/CippEntrypoints.psm1 new file mode 100644 index 000000000000..f2bf64914f1c --- /dev/null +++ b/Modules/CippEntrypoints/CippEntrypoints.psm1 @@ -0,0 +1,42 @@ +function Receive-CippHttpTrigger { + Param($Request, $TriggerMetadata) + + $APIName = $TriggerMetadata.FunctionName + + $FunctionVerbs = @{ + 'Get' = '^(:?Ext)?(?List.+$)' + 'Edit' = '^(:?Ext)?(?Update.+$)' + 'New' = '^(:?Ext)?(?Add.+$)' + 'Invoke' = '^(?Exec.+$)' + } + + foreach ($FunctionVerb in $FunctionVerbs.Keys) { + if ($APIName -match $FunctionVerbs.$FunctionVerb) { + $FunctionName = '{0}-{1}' -f $FunctionVerb, $Matches.APIName + break + } + } + + $HttpTrigger = @{ + Request = $Request + TriggerMetadata = $TriggerMetadata + } + + & $FunctionName @HttpTrigger +} + +function Receive-CippQueueTrigger { + Param($QueueItem, $TriggerMetadata) + $APIName = $TriggerMetadata.FunctionName + + $FunctionName = 'Push-{0}' -f $APIName + $QueueTrigger = @{ + QueueItem = $QueueItem + TriggerMetadata = $TriggerMetadata + } + + & $FunctionName @QueueTrigger +} + +Export-ModuleMember -Function @('Receive-CippHttpTrigger', 'Receive-CippQueueTrigger') + diff --git a/Modules/GraphRequests/GraphRequests.psm1 b/Modules/GraphRequests/GraphRequests.psm1 index 14b1aeab66ae..f584acc34193 100644 --- a/Modules/GraphRequests/GraphRequests.psm1 +++ b/Modules/GraphRequests/GraphRequests.psm1 @@ -1,397 +1,12 @@ -using namespace System.Net - -function Get-StringHash { - Param($String) - $StringBuilder = New-Object System.Text.StringBuilder - [System.Security.Cryptography.HashAlgorithm]::Create('SHA1').ComputeHash([System.Text.Encoding]::UTF8.GetBytes($String)) | ForEach-Object { - [Void]$StringBuilder.Append($_.ToString('x2')) - } - $StringBuilder.ToString() -} -function Get-GraphRequestList { - [CmdletBinding()] - Param( - $Tenant = $env:TenantId, - [Parameter(Mandatory = $true)] - $Endpoint, - $Parameters = @(), - $QueueId, - $CippLink, - [ValidateSet('v1.0', 'beta')] - $Version = 'beta', - $QueueNameOverride, - [switch]$SkipCache, - [switch]$ClearCache, - [switch]$NoPagination, - [switch]$CountOnly, - [switch]$NoAuthCheck, - [switch]$ReverseTenantLookup, - [string]$ReverseTenantLookupProperty = 'tenantId' - ) - - $TableName = ('cache{0}' -f ($Endpoint -replace '[^A-Za-z0-9]'))[0..62] -join '' - Write-Host "Table: $TableName" - $DisplayName = ($Endpoint -split '/')[0] - - if ($QueueNameOverride) { - $QueueName = $QueueNameOverride - } else { - $TextInfo = (Get-Culture).TextInfo - $QueueName = $TextInfo.ToTitleCase($DisplayName -csplit '(?=[A-Z])' -ne '' -join ' ') - } - - $GraphQuery = [System.UriBuilder]('https://graph.microsoft.com/{0}/{1}' -f $Version, $Endpoint) - $ParamCollection = [System.Web.HttpUtility]::ParseQueryString([String]::Empty) - foreach ($Item in ($Parameters.GetEnumerator() | Sort-Object -CaseSensitive -Property Key)) { - $ParamCollection.Add($Item.Key, $Item.Value) - } - $GraphQuery.Query = $ParamCollection.ToString() - $PartitionKey = Get-StringHash -String (@($Endpoint, $ParamCollection.ToString()) -join '-') - Write-Host "PK: $PartitionKey" - - Write-Host ( 'GET [ {0} ]' -f $GraphQuery.ToString()) - - if ($QueueId) { - $Table = Get-CIPPTable -TableName $TableName - $Filter = "QueueId eq '{0}'" -f $QueueId - $Rows = Get-AzDataTableEntity @Table -Filter $Filter - $Type = 'Queue' - } elseif ($Tenant -eq 'AllTenants' -or (!$SkipCache.IsPresent -and !$ClearCache.IsPresent -and !$CountOnly.IsPresent)) { - $Table = Get-CIPPTable -TableName $TableName - if ($Tenant -eq 'AllTenants') { - $Filter = "PartitionKey eq '{0}' and QueueType eq 'AllTenants'" -f $PartitionKey - } else { - $Filter = "PartitionKey eq '{0}' and Tenant eq '{1}'" -f $PartitionKey, $Tenant - } - #Write-Host $Filter - $Rows = Get-AzDataTableEntity @Table -Filter $Filter | Where-Object { $_.Timestamp.DateTime -gt (Get-Date).ToUniversalTime().AddHours(-1) } - $Type = 'Cache' - } else { - $Type = 'None' - $Rows = @() - } - Write-Host "Cached: $(($Rows | Measure-Object).Count) rows (Type: $($Type))" - - $QueueReference = '{0}-{1}' -f $Tenant, $PartitionKey - $RunningQueue = Get-CippQueue | Where-Object { $_.Reference -eq $QueueReference -and $_.Status -ne 'Completed' -and $_.Status -ne 'Failed' } - - if (!$Rows) { - switch ($Tenant) { - 'AllTenants' { - if ($SkipCache) { - Get-Tenants -IncludeErrors | ForEach-Object -Parallel { - Import-Module .\GraphHelper.psm1 - $GraphRequestParams = @{ - Tenant = $_.defaultDomainName - Endpoint = $using:Endpoint - Parameters = $using:Parameters - NoPagination = $using:NoPagination.IsPresent - ReverseTenantLookupProperty = $using:ReverseTenantLookupProperty - ReverseTenantLookup = $using:ReverseTenantLookup.IsPresent - SkipCache = $true - } - - try { - Get-GraphRequestList @GraphRequestParams | Select-Object *, @{l = 'Tenant'; e = { $_.defaultDomainName } }, @{l = 'CippStatus'; e = { 'Good' } } - } catch { - [PSCustomObject]@{ - Tenant = $_.defaultDomainName - CippStatus = "Could not connect to tenant. $($_.Exception.message)" - } - } - } - } else { - - if ($RunningQueue) { - Write-Host 'Queue currently running' - Write-Host ($RunningQueue | ConvertTo-Json) - [PSCustomObject]@{ - Tenant = 'Data still processing, please wait' - QueueId = $RunningQueue.RowKey - } - } else { - $Queue = New-CippQueueEntry -Name "$QueueName (All Tenants)" -Link $CippLink -Reference $QueueReference - [PSCustomObject]@{ - QueueMessage = 'Loading data for all tenants. Please check back after the job completes' - Queued = $true - QueueId = $Queue.RowKey - } - Write-Host 'Pushing output bindings' - try { - Get-Tenants -IncludeErrors | ForEach-Object { - $Tenant = $_.defaultDomainName - $QueueTenant = @{ - Tenant = $Tenant - Endpoint = $Endpoint - QueueId = $Queue.RowKey - QueueName = $QueueName - QueueType = 'AllTenants' - Parameters = $Parameters - PartitionKey = $PartitionKey - NoPagination = $NoPagination.IsPresent - NoAuthCheck = $NoAuthCheck.IsPresent - ReverseTenantLookupProperty = $ReverseTenantLookupProperty - ReverseTenantLookup = $ReverseTenantLookup.IsPresent - } | ConvertTo-Json -Depth 5 -Compress - - Push-OutputBinding -Name QueueTenant -Value $QueueTenant - } - } catch { - Write-Host "QUEUE ERROR: $($_.Exception.Message)" - } - } - } - } - default { - $GraphRequest = @{ - uri = $GraphQuery.ToString() - tenantid = $Tenant - ComplexFilter = $true - } - - if ($NoPagination.IsPresent) { - $GraphRequest.noPagination = $NoPagination.IsPresent - } - - if ($CountOnly.IsPresent) { - $GraphRequest.CountOnly = $CountOnly.IsPresent - } - - if ($NoAuthCheck.IsPresent) { - $GraphRequest.noauthcheck = $NoAuthCheck.IsPresent - } - - try { - $QueueThresholdExceeded = $false - if ($Parameters.'$count' -and !$SkipCache -and !$NoPagination) { - $Count = New-GraphGetRequest @GraphRequest -CountOnly -ErrorAction Stop - Write-Host "Total results (`$count): $Count" - if ($Count -gt 8000) { - $QueueThresholdExceeded = $true - if ($RunningQueue) { - Write-Host 'Queue currently running' - Write-Host ($RunningQueue | ConvertTo-Json) - [PSCustomObject]@{ - QueueMessage = 'Data still processing, please wait' - QueueId = $RunningQueue.RowKey - Queued = $true - } - } else { - $Queue = New-CippQueueEntry -Name $QueueName -Link $CippLink -Reference $QueueReference - $QueueTenant = @{ - Tenant = $Tenant - Endpoint = $Endpoint - QueueId = $Queue.RowKey - QueueName = $QueueName - QueueType = 'SingleTenant' - Parameters = $Parameters - PartitionKey = $PartitionKey - NoAuthCheck = $NoAuthCheck.IsPresent - ReverseTenantLookupProperty = $ReverseTenantLookupProperty - ReverseTenantLookup = $ReverseTenantLookup.IsPresent - } | ConvertTo-Json -Depth 5 -Compress - - Push-OutputBinding -Name QueueTenant -Value $QueueTenant - [PSCustomObject]@{ - QueueMessage = ('Loading {0} rows for {1}. Please check back after the job completes' -f $Count, $Tenant) - QueueId = $Queue.RowKey - Queued = $true - } - } - } - } - - if (!$QueueThresholdExceeded) { - $GraphRequestResults = New-GraphGetRequest @GraphRequest -ErrorAction Stop - if ($ReverseTenantLookup -and $GraphRequestResults) { - $TenantInfo = $GraphRequestResults.$ReverseTenantLookupProperty | Sort-Object -Unique | ForEach-Object { - New-GraphGetRequest -uri "https://graph.microsoft.com/beta/tenantRelationships/findTenantInformationByTenantId(tenantId='$_')" -noauthcheck $true - } - foreach ($Result in $GraphRequestResults) { - $Result | Select-Object @{n = 'TenantInfo'; e = { $TenantInfo | Where-Object { $Result.$ReverseTenantLookupProperty -eq $_.tenantId } } }, * - } - } else { - $GraphRequestResults - } - } - - } catch { - throw $_.Exception - } - } - } - } else { - $Rows | ForEach-Object { - $_.Data | ConvertFrom-Json - } - } -} - -function Push-GraphRequestListQueue { - # Input bindings are passed in via param block. - param($QueueTenant, $TriggerMetadata) - - # Write out the queue message and metadata to the information log. - Write-Host "PowerShell queue trigger function processed work item: $($QueueTenant.Endpoint) - $($QueueTenant.Tenant)" - - #Write-Host ($QueueTenant | ConvertTo-Json -Depth 5) - - $TenantQueueName = '{0} - {1}' -f $QueueTenant.QueueName, $QueueTenant.Tenant - Update-CippQueueEntry -RowKey $QueueTenant.QueueId -Status 'Processing' -Name $TenantQueueName - - $ParamCollection = [System.Web.HttpUtility]::ParseQueryString([String]::Empty) - foreach ($Item in ($QueueTenant.Parameters.GetEnumerator() | Sort-Object -CaseSensitive -Property Key)) { - $ParamCollection.Add($Item.Key, $Item.Value) - } - - $PartitionKey = $QueueTenant.PartitionKey - - $TableName = ('cache{0}' -f ($QueueTenant.Endpoint -replace '[^A-Za-z0-9]'))[0..63] -join '' - Write-Host $TableName - $Table = Get-CIPPTable -TableName $TableName - - $Filter = "PartitionKey eq '{0}' and Tenant eq '{1}'" -f $PartitionKey, $QueueTenant.Tenant - Write-Host $Filter - Get-AzDataTableEntity @Table -Filter $Filter | Remove-AzDataTableEntity @Table - - $GraphRequestParams = @{ - Tenant = $QueueTenant.Tenant - Endpoint = $QueueTenant.Endpoint - Parameters = $QueueTenant.Parameters - NoPagination = $QueueTenant.NoPagination - ReverseTenantLookupProperty = $QueueTenant.ReverseTenantLookupProperty - ReverseTenantLookup = $QueueTenant.ReverseTenantLookup - SkipCache = $true - } - - $RawGraphRequest = try { - Get-GraphRequestList @GraphRequestParams | Select-Object *, @{l = 'Tenant'; e = { $QueueTenant.Tenant } }, @{l = 'CippStatus'; e = { 'Good' } } - } catch { - [PSCustomObject]@{ - Tenant = $QueueTenant.Tenant - CippStatus = "Could not connect to tenant. $($_.Exception.message)" - } - } - - $GraphResults = foreach ($Request in $RawGraphRequest) { - $Json = ConvertTo-Json -Depth 5 -Compress -InputObject $Request - [PSCustomObject]@{ - Tenant = [string]$QueueTenant.Tenant - QueueId = [string]$QueueTenant.QueueId - QueueType = [string]$QueueTenant.QueueType - RowKey = [string](New-Guid) - PartitionKey = [string]$PartitionKey - Data = [string]$Json - } - } +$Public = @(Get-ChildItem -Path $PSScriptRoot\Public\*.ps1 -ErrorAction SilentlyContinue) +$Private = @(Get-ChildItem -Path $PSScriptRoot\private\*.ps1 -ErrorAction SilentlyContinue) +$Functions = $Public + $Private +foreach ($import in @($Functions)) { try { - Add-AzDataTableEntity @Table -Entity $GraphResults -Force | Out-Null - Update-CippQueueEntry -RowKey $QueueTenant.QueueId -Status 'Completed' + . $import.FullName } catch { - Write-Host "Queue Error: $($_.Exception.Message)" - Update-CippQueueEntry -RowKey $QueueTenant.QueueId -Status 'Failed' + Write-Error -Message "Failed to import function $($import.FullName): $_" } } -function Get-GraphRequestListHttp { - # Input bindings are passed in via param block. - param($Request, $TriggerMetadata) - - $APIName = $TriggerMetadata.FunctionName - - $Message = 'Accessed this API | Endpoint: {0}' -f $Request.Query.Endpoint - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message $Message -Sev 'Debug' - - $CippLink = ([System.Uri]$TriggerMetadata.Headers.referer).PathAndQuery - - $Parameters = @{} - if ($Request.Query.'$filter') { - $Parameters.'$filter' = $Request.Query.'$filter' - } - - if (!$Request.Query.'$filter' -and $Request.Query.graphFilter) { - $Parameters.'$filter' = $Request.Query.graphFilter - } - - if ($Request.Query.'$select') { - $Parameters.'$select' = $Request.Query.'$select' - } - - if ($Request.Query.'$expand') { - $Parameters.'$expand' = $Request.Query.'$expand' - } - - if ($Request.Query.'$top') { - $Parameters.'$top' = $Request.Query.'$top' - } - - if ($Request.Query.'$count') { - $Parameters.'$count' = ([string]([System.Boolean]$Request.Query.'$count')).ToLower() - } - - if ($Request.Query.'$orderby') { - $Parameters.'$orderby' = $Request.Query.'$orderby' - } - - if ($Request.Query.'$search') { - $Parameters.'$search' = $Request.Query.'$search' - } - - $GraphRequestParams = @{ - Endpoint = $Request.Query.Endpoint - Parameters = $Parameters - CippLink = $CippLink - } - - if ($Request.Query.TenantFilter) { - $GraphRequestParams.Tenant = $Request.Query.TenantFilter - } - - if ($Request.Query.QueueId) { - $GraphRequestParams.QueueId = $Request.Query.QueueId - } - - if ($Request.Query.Version) { - $GraphRequestParams.Version = $Request.Query.Version - } - - if ($Request.Query.NoPagination) { - $GraphRequestParams.NoPagination = [System.Boolean]$Request.Query.NoPagination - } - - if ($Request.Query.CountOnly) { - $GraphRequestParams.CountOnly = [System.Boolean]$Request.Query.CountOnly - } - - if ($Request.Query.QueueNameOverride) { - $GraphRequestParams.QueueNameOverride = [System.Boolean]$Request.Query.QueueNameOverride - } - - if ($Request.Query.ReverseTenantLookup) { - $GraphRequestParams.ReverseTenantLookup = [System.Boolean]$Request.Query.ReverseTenantLookup - } - - if ($Request.Query.ReverseTenantLookupProperty) { - $GraphRequestParams.ReverseTenantLookupProperty = $Request.Query.ReverseTenantLookupProperty - } - - if ($Request.Query.SkipCache) { - $GraphRequestParams.SkipCache = [System.Boolean]$Request.Query.SkipCache - } - - Write-Host ($GraphRequestParams | ConvertTo-Json) - try { - $GraphRequestData = Get-GraphRequestList @GraphRequestParams - $StatusCode = [HttpStatusCode]::OK - } catch { - $GraphRequestData = "Graph Error: $($_.Exception.Message)" - $StatusCode = [HttpStatusCode]::BadRequest - } - - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = @($GraphRequestData) - }) -} - -Export-ModuleMember -Function @('Get-GraphRequestList', 'Get-GraphRequestListHttp', 'Push-GraphRequestListQueue') +Export-ModuleMember -Function $Public.BaseName -Alias * diff --git a/Modules/GraphRequests/Private/Get-StringHash.ps1 b/Modules/GraphRequests/Private/Get-StringHash.ps1 new file mode 100644 index 000000000000..a5c94f62b511 --- /dev/null +++ b/Modules/GraphRequests/Private/Get-StringHash.ps1 @@ -0,0 +1,8 @@ +function Get-StringHash { + Param($String) + $StringBuilder = New-Object System.Text.StringBuilder + [System.Security.Cryptography.HashAlgorithm]::Create('SHA1').ComputeHash([System.Text.Encoding]::UTF8.GetBytes($String)) | ForEach-Object { + [Void]$StringBuilder.Append($_.ToString('x2')) + } + $StringBuilder.ToString() +} \ No newline at end of file diff --git a/Modules/GraphRequests/Public/Get-GraphRequestList.ps1 b/Modules/GraphRequests/Public/Get-GraphRequestList.ps1 new file mode 100644 index 000000000000..abff34116e3f --- /dev/null +++ b/Modules/GraphRequests/Public/Get-GraphRequestList.ps1 @@ -0,0 +1,218 @@ +function Get-GraphRequestList { + [CmdletBinding()] + Param( + $Tenant = $env:TenantId, + [Parameter(Mandatory = $true)] + $Endpoint, + $Parameters = @(), + $QueueId, + $CippLink, + [ValidateSet('v1.0', 'beta')] + $Version = 'beta', + $QueueNameOverride, + [switch]$SkipCache, + [switch]$ClearCache, + [switch]$NoPagination, + [switch]$CountOnly, + [switch]$NoAuthCheck, + [switch]$ReverseTenantLookup, + [string]$ReverseTenantLookupProperty = 'tenantId' + ) + + $TableName = ('cache{0}' -f ($Endpoint -replace '[^A-Za-z0-9]'))[0..62] -join '' + Write-Host "Table: $TableName" + $DisplayName = ($Endpoint -split '/')[0] + + if ($QueueNameOverride) { + $QueueName = $QueueNameOverride + } else { + $TextInfo = (Get-Culture).TextInfo + $QueueName = $TextInfo.ToTitleCase($DisplayName -csplit '(?=[A-Z])' -ne '' -join ' ') + } + + $GraphQuery = [System.UriBuilder]('https://graph.microsoft.com/{0}/{1}' -f $Version, $Endpoint) + $ParamCollection = [System.Web.HttpUtility]::ParseQueryString([String]::Empty) + foreach ($Item in ($Parameters.GetEnumerator() | Sort-Object -CaseSensitive -Property Key)) { + $ParamCollection.Add($Item.Key, $Item.Value) + } + $GraphQuery.Query = $ParamCollection.ToString() + $PartitionKey = Get-StringHash -String (@($Endpoint, $ParamCollection.ToString()) -join '-') + Write-Host "PK: $PartitionKey" + + Write-Host ( 'GET [ {0} ]' -f $GraphQuery.ToString()) + + if ($QueueId) { + $Table = Get-CIPPTable -TableName $TableName + $Filter = "QueueId eq '{0}'" -f $QueueId + $Rows = Get-AzDataTableEntity @Table -Filter $Filter + $Type = 'Queue' + } elseif ($Tenant -eq 'AllTenants' -or (!$SkipCache.IsPresent -and !$ClearCache.IsPresent -and !$CountOnly.IsPresent)) { + $Table = Get-CIPPTable -TableName $TableName + if ($Tenant -eq 'AllTenants') { + $Filter = "PartitionKey eq '{0}' and QueueType eq 'AllTenants'" -f $PartitionKey + } else { + $Filter = "PartitionKey eq '{0}' and Tenant eq '{1}'" -f $PartitionKey, $Tenant + } + #Write-Host $Filter + $Rows = Get-AzDataTableEntity @Table -Filter $Filter | Where-Object { $_.Timestamp.DateTime -gt (Get-Date).ToUniversalTime().AddHours(-1) } + $Type = 'Cache' + } else { + $Type = 'None' + $Rows = @() + } + Write-Host "Cached: $(($Rows | Measure-Object).Count) rows (Type: $($Type))" + + $QueueReference = '{0}-{1}' -f $Tenant, $PartitionKey + $RunningQueue = Get-CippQueue | Where-Object { $_.Reference -eq $QueueReference -and $_.Status -ne 'Completed' -and $_.Status -ne 'Failed' } + + if (!$Rows) { + switch ($Tenant) { + 'AllTenants' { + if ($SkipCache) { + Get-Tenants -IncludeErrors | ForEach-Object -Parallel { + Import-Module .\GraphHelper.psm1 + $GraphRequestParams = @{ + Tenant = $_.defaultDomainName + Endpoint = $using:Endpoint + Parameters = $using:Parameters + NoPagination = $using:NoPagination.IsPresent + ReverseTenantLookupProperty = $using:ReverseTenantLookupProperty + ReverseTenantLookup = $using:ReverseTenantLookup.IsPresent + SkipCache = $true + } + + try { + Get-GraphRequestList @GraphRequestParams | Select-Object *, @{l = 'Tenant'; e = { $_.defaultDomainName } }, @{l = 'CippStatus'; e = { 'Good' } } + } catch { + [PSCustomObject]@{ + Tenant = $_.defaultDomainName + CippStatus = "Could not connect to tenant. $($_.Exception.message)" + } + } + } + } else { + + if ($RunningQueue) { + Write-Host 'Queue currently running' + Write-Host ($RunningQueue | ConvertTo-Json) + [PSCustomObject]@{ + Tenant = 'Data still processing, please wait' + QueueId = $RunningQueue.RowKey + } + } else { + $Queue = New-CippQueueEntry -Name "$QueueName (All Tenants)" -Link $CippLink -Reference $QueueReference + [PSCustomObject]@{ + QueueMessage = 'Loading data for all tenants. Please check back after the job completes' + Queued = $true + QueueId = $Queue.RowKey + } + Write-Host 'Pushing output bindings' + try { + Get-Tenants -IncludeErrors | ForEach-Object { + $Tenant = $_.defaultDomainName + $QueueTenant = @{ + Tenant = $Tenant + Endpoint = $Endpoint + QueueId = $Queue.RowKey + QueueName = $QueueName + QueueType = 'AllTenants' + Parameters = $Parameters + PartitionKey = $PartitionKey + NoPagination = $NoPagination.IsPresent + NoAuthCheck = $NoAuthCheck.IsPresent + ReverseTenantLookupProperty = $ReverseTenantLookupProperty + ReverseTenantLookup = $ReverseTenantLookup.IsPresent + } | ConvertTo-Json -Depth 5 -Compress + + Push-OutputBinding -Name QueueItem -Value $QueueTenant + } + } catch { + Write-Host "QUEUE ERROR: $($_.Exception.Message)" + } + } + } + } + default { + $GraphRequest = @{ + uri = $GraphQuery.ToString() + tenantid = $Tenant + ComplexFilter = $true + } + + if ($NoPagination.IsPresent) { + $GraphRequest.noPagination = $NoPagination.IsPresent + } + + if ($CountOnly.IsPresent) { + $GraphRequest.CountOnly = $CountOnly.IsPresent + } + + if ($NoAuthCheck.IsPresent) { + $GraphRequest.noauthcheck = $NoAuthCheck.IsPresent + } + + try { + $QueueThresholdExceeded = $false + if ($Parameters.'$count' -and !$SkipCache -and !$NoPagination) { + $Count = New-GraphGetRequest @GraphRequest -CountOnly -ErrorAction Stop + Write-Host "Total results (`$count): $Count" + if ($Count -gt 8000) { + $QueueThresholdExceeded = $true + if ($RunningQueue) { + Write-Host 'Queue currently running' + Write-Host ($RunningQueue | ConvertTo-Json) + [PSCustomObject]@{ + QueueMessage = 'Data still processing, please wait' + QueueId = $RunningQueue.RowKey + Queued = $true + } + } else { + $Queue = New-CippQueueEntry -Name $QueueName -Link $CippLink -Reference $QueueReference + $QueueTenant = @{ + Tenant = $Tenant + Endpoint = $Endpoint + QueueId = $Queue.RowKey + QueueName = $QueueName + QueueType = 'SingleTenant' + Parameters = $Parameters + PartitionKey = $PartitionKey + NoAuthCheck = $NoAuthCheck.IsPresent + ReverseTenantLookupProperty = $ReverseTenantLookupProperty + ReverseTenantLookup = $ReverseTenantLookup.IsPresent + } | ConvertTo-Json -Depth 5 -Compress + + Push-OutputBinding -Name QueueItem -Value $QueueTenant + [PSCustomObject]@{ + QueueMessage = ('Loading {0} rows for {1}. Please check back after the job completes' -f $Count, $Tenant) + QueueId = $Queue.RowKey + Queued = $true + } + } + } + } + + if (!$QueueThresholdExceeded) { + $GraphRequestResults = New-GraphGetRequest @GraphRequest -ErrorAction Stop + if ($ReverseTenantLookup -and $GraphRequestResults) { + $TenantInfo = $GraphRequestResults.$ReverseTenantLookupProperty | Sort-Object -Unique | ForEach-Object { + New-GraphGetRequest -uri "https://graph.microsoft.com/beta/tenantRelationships/findTenantInformationByTenantId(tenantId='$_')" -noauthcheck $true + } + foreach ($Result in $GraphRequestResults) { + $Result | Select-Object @{n = 'TenantInfo'; e = { $TenantInfo | Where-Object { $Result.$ReverseTenantLookupProperty -eq $_.tenantId } } }, * + } + } else { + $GraphRequestResults + } + } + + } catch { + throw $_.Exception + } + } + } + } else { + $Rows | ForEach-Object { + $_.Data | ConvertFrom-Json + } + } +} \ No newline at end of file diff --git a/Modules/GraphRequests/Public/Get-ListGraphRequest.ps1 b/Modules/GraphRequests/Public/Get-ListGraphRequest.ps1 new file mode 100644 index 000000000000..8ae912423514 --- /dev/null +++ b/Modules/GraphRequests/Public/Get-ListGraphRequest.ps1 @@ -0,0 +1,110 @@ +using namespace System.Net +function Get-ListGraphRequest { + # Input bindings are passed in via param block. + param($Request, $TriggerMetadata) + + $APIName = $TriggerMetadata.FunctionName + + if ($APIName -match '^Ext') { + $AccessResult = Confirm-CippApiAccess -Request $Request + Write-Host ($AccessResult | ConvertTo-Json) + if (!$AccessResult.Authorized) { return } + + $Message = 'Accessed this API | Endpoint: {0}' -f $Request.Query.Endpoint + Write-LogMessage -user $AccessResult.ClientId -API $APINAME -message $Message -Sev 'Debug' + } else { + $Message = 'Accessed this API | Endpoint: {0}' -f $Request.Query.Endpoint + Write-LogMessage -API $APINAME -message $Message -Sev 'Debug' + } + + $CippLink = ([System.Uri]$TriggerMetadata.Headers.referer).PathAndQuery + + $Parameters = @{} + if ($Request.Query.'$filter') { + $Parameters.'$filter' = $Request.Query.'$filter' + } + + if (!$Request.Query.'$filter' -and $Request.Query.graphFilter) { + $Parameters.'$filter' = $Request.Query.graphFilter + } + + if ($Request.Query.'$select') { + $Parameters.'$select' = $Request.Query.'$select' + } + + if ($Request.Query.'$expand') { + $Parameters.'$expand' = $Request.Query.'$expand' + } + + if ($Request.Query.'$top') { + $Parameters.'$top' = $Request.Query.'$top' + } + + if ($Request.Query.'$count') { + $Parameters.'$count' = ([string]([System.Boolean]$Request.Query.'$count')).ToLower() + } + + if ($Request.Query.'$orderby') { + $Parameters.'$orderby' = $Request.Query.'$orderby' + } + + if ($Request.Query.'$search') { + $Parameters.'$search' = $Request.Query.'$search' + } + + $GraphRequestParams = @{ + Endpoint = $Request.Query.Endpoint + Parameters = $Parameters + CippLink = $CippLink + } + + if ($Request.Query.TenantFilter) { + $GraphRequestParams.Tenant = $Request.Query.TenantFilter + } + + if ($Request.Query.QueueId) { + $GraphRequestParams.QueueId = $Request.Query.QueueId + } + + if ($Request.Query.Version) { + $GraphRequestParams.Version = $Request.Query.Version + } + + if ($Request.Query.NoPagination) { + $GraphRequestParams.NoPagination = [System.Boolean]$Request.Query.NoPagination + } + + if ($Request.Query.CountOnly) { + $GraphRequestParams.CountOnly = [System.Boolean]$Request.Query.CountOnly + } + + if ($Request.Query.QueueNameOverride) { + $GraphRequestParams.QueueNameOverride = [System.Boolean]$Request.Query.QueueNameOverride + } + + if ($Request.Query.ReverseTenantLookup) { + $GraphRequestParams.ReverseTenantLookup = [System.Boolean]$Request.Query.ReverseTenantLookup + } + + if ($Request.Query.ReverseTenantLookupProperty) { + $GraphRequestParams.ReverseTenantLookupProperty = $Request.Query.ReverseTenantLookupProperty + } + + if ($Request.Query.SkipCache) { + $GraphRequestParams.SkipCache = [System.Boolean]$Request.Query.SkipCache + } + + Write-Host ($GraphRequestParams | ConvertTo-Json) + try { + $GraphRequestData = Get-GraphRequestList @GraphRequestParams + $StatusCode = [HttpStatusCode]::OK + } catch { + $GraphRequestData = "Graph Error: $($_.Exception.Message)" + $StatusCode = [HttpStatusCode]::BadRequest + } + + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @($GraphRequestData) + }) +} \ No newline at end of file diff --git a/Modules/GraphRequests/Public/Push-ListGraphRequestQueue.ps1 b/Modules/GraphRequests/Public/Push-ListGraphRequestQueue.ps1 new file mode 100644 index 000000000000..a193fcf9a9f4 --- /dev/null +++ b/Modules/GraphRequests/Public/Push-ListGraphRequestQueue.ps1 @@ -0,0 +1,65 @@ +function Push-ListGraphRequestQueue { + # 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 queue trigger function processed work item: $($QueueItem.Endpoint) - $($QueueItem.Tenant)" + + #Write-Host ($QueueItem | ConvertTo-Json -Depth 5) + + $TenantQueueName = '{0} - {1}' -f $QueueItem.QueueName, $QueueItem.Tenant + Update-CippQueueEntry -RowKey $QueueItem.QueueId -Status 'Processing' -Name $TenantQueueName + + $ParamCollection = [System.Web.HttpUtility]::ParseQueryString([String]::Empty) + foreach ($Item in ($QueueItem.Parameters.GetEnumerator() | Sort-Object -CaseSensitive -Property Key)) { + $ParamCollection.Add($Item.Key, $Item.Value) + } + + $PartitionKey = $QueueItem.PartitionKey + + $TableName = ('cache{0}' -f ($QueueItem.Endpoint -replace '[^A-Za-z0-9]'))[0..63] -join '' + Write-Host $TableName + $Table = Get-CIPPTable -TableName $TableName + + $Filter = "PartitionKey eq '{0}' and Tenant eq '{1}'" -f $PartitionKey, $QueueItem.Tenant + Write-Host $Filter + Get-AzDataTableEntity @Table -Filter $Filter | Remove-AzDataTableEntity @Table + + $GraphRequestParams = @{ + Tenant = $QueueItem.Tenant + Endpoint = $QueueItem.Endpoint + Parameters = $QueueItem.Parameters + NoPagination = $QueueItem.NoPagination + ReverseTenantLookupProperty = $QueueItem.ReverseTenantLookupProperty + ReverseTenantLookup = $QueueItem.ReverseTenantLookup + SkipCache = $true + } + + $RawGraphRequest = try { + Get-GraphRequestList @GraphRequestParams | Select-Object *, @{l = 'Tenant'; e = { $QueueItem.Tenant } }, @{l = 'CippStatus'; e = { 'Good' } } + } catch { + [PSCustomObject]@{ + Tenant = $QueueItem.Tenant + CippStatus = "Could not connect to tenant. $($_.Exception.message)" + } + } + + $GraphResults = foreach ($Request in $RawGraphRequest) { + $Json = ConvertTo-Json -Depth 5 -Compress -InputObject $Request + [PSCustomObject]@{ + Tenant = [string]$QueueItem.Tenant + QueueId = [string]$QueueItem.QueueId + QueueType = [string]$QueueItem.QueueType + RowKey = [string](New-Guid) + PartitionKey = [string]$PartitionKey + Data = [string]$Json + } + } + try { + Add-AzDataTableEntity @Table -Entity $GraphResults -Force | Out-Null + Update-CippQueueEntry -RowKey $QueueItem.QueueId -Status 'Completed' + } catch { + Write-Host "Queue Error: $($_.Exception.Message)" + Update-CippQueueEntry -RowKey $QueueItem.QueueId -Status 'Failed' + } +} \ No newline at end of file diff --git a/profile.ps1 b/profile.ps1 index 069460965fdd..9114a98ff5f8 100644 --- a/profile.ps1 +++ b/profile.ps1 @@ -14,6 +14,8 @@ Import-Module .\GraphHelper.psm1 Import-Module Az.KeyVault Import-Module Az.Accounts +Import-Module GraphRequests +Import-Module CippExtensions try { Disable-AzContextAutosave -Scope Process | Out-Null From 38be30e2a04ada15028137c5c75f2d972e090b9c Mon Sep 17 00:00:00 2001 From: John Duprey Date: Sun, 11 Jun 2023 14:51:58 -0400 Subject: [PATCH 02/44] Extension API Tokens --- Modules/CippExtensions/CippExtensions.psd1 | Bin 10120 -> 10254 bytes Modules/CippExtensions/CippExtensions.psm1 | 18 +++---- .../Private/Get-ApiSecretHash.ps1 | 8 +++ .../CippExtensions/Private/New-CippApiKey.ps1 | 27 ++++++++++ .../Public/Confirm-CippApiAccess.ps1 | 46 ++++++++++++++++++ .../Public/Invoke-ExecAddCippApiKey.ps1 | 26 ++++++++++ 6 files changed, 116 insertions(+), 9 deletions(-) create mode 100644 Modules/CippExtensions/Private/Get-ApiSecretHash.ps1 create mode 100644 Modules/CippExtensions/Private/New-CippApiKey.ps1 create mode 100644 Modules/CippExtensions/Public/Confirm-CippApiAccess.ps1 create mode 100644 Modules/CippExtensions/Public/Invoke-ExecAddCippApiKey.ps1 diff --git a/Modules/CippExtensions/CippExtensions.psd1 b/Modules/CippExtensions/CippExtensions.psd1 index 3b3a16f620c0dad8cf4a88011a0f852182cb1ccf..29102a2610bc48ebf80cd2a526fe6c8ce8429ba5 100644 GIT binary patch delta 179 zcmeD1?+e)QN^J5fQ3-8NhCGHchJ1!>hExV!21kYzAarKPWGDbaM.+)$') { + try { + $ClientId, $ClientSecret = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($Matches.Creds)) -split ':' + $AuthRequest.ClientId = $ClientId + $Filter = "PartitionKey eq 'ApiToken' and RowKey eq '{0}' and ClientSecretHash eq '{1}'" -f $ClientId, (Get-ApiSecretHash -Secret $ClientSecret) + $Table = Get-CippTable -TableName CippApiCredentials + $Entity = Get-AzDataTableEntity @Table -Filter $Filter + + if ($Entity.RowKey -and $PermissionMap[$Entity.AccessLevel] -contains $AccessLevel) { + $AuthRequest.Authorized = $true + } + } catch { + Write-Host "API key validation exception: $($_.Exception.Message)" + } + } + + if (!$AuthRequest.Authorized) { + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::Unauthorized + Body = 'Unauthorized' + }) + } + + $AuthRequest +} diff --git a/Modules/CippExtensions/Public/Invoke-ExecAddCippApiKey.ps1 b/Modules/CippExtensions/Public/Invoke-ExecAddCippApiKey.ps1 new file mode 100644 index 000000000000..a9b286f2d0fa --- /dev/null +++ b/Modules/CippExtensions/Public/Invoke-ExecAddCippApiKey.ps1 @@ -0,0 +1,26 @@ +function Add-CippApiKey { + # Input bindings are passed in via param block. + param($Request = $null, $TriggerMetadata) + + if ($Request) { + $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.' + } + + try { + $ApiKey = New-CippApiKey -Description $Request.Query.Description -AccessLevel $Request.Query.AccessLevel + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $ApiKey + }) + } catch { + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::BadRequest + Body = @{Results = $_.Exception.Message } + }) + } + +} From 664f423e82e4221d1fca1693f6ffb0e1ba66f0b2 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Sun, 11 Jun 2023 14:52:35 -0400 Subject: [PATCH 03/44] Extension API - ListGraphRequest --- ExtListGraphRequest/function.json | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 ExtListGraphRequest/function.json diff --git a/ExtListGraphRequest/function.json b/ExtListGraphRequest/function.json new file mode 100644 index 000000000000..db6842a7b1a6 --- /dev/null +++ b/ExtListGraphRequest/function.json @@ -0,0 +1,24 @@ +{ + "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" + }, + { + "type": "queue", + "direction": "out", + "name": "QueueTenant", + "queueName": "GraphRequestQueue" + } + ] +} From 2917f93907c75118c90a252bea19a18deec62782 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Sun, 11 Jun 2023 21:38:20 -0400 Subject: [PATCH 04/44] Move API auth handling --- Modules/CippEntrypoints/CippEntrypoints.psm1 | 24 ++++++++++++++++++- .../Public/Get-ListGraphRequest.ps1 | 6 +---- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/Modules/CippEntrypoints/CippEntrypoints.psm1 b/Modules/CippEntrypoints/CippEntrypoints.psm1 index f2bf64914f1c..b62858046169 100644 --- a/Modules/CippEntrypoints/CippEntrypoints.psm1 +++ b/Modules/CippEntrypoints/CippEntrypoints.psm1 @@ -1,3 +1,5 @@ +using namespace System.Net + function Receive-CippHttpTrigger { Param($Request, $TriggerMetadata) @@ -5,18 +7,38 @@ function Receive-CippHttpTrigger { $FunctionVerbs = @{ 'Get' = '^(:?Ext)?(?List.+$)' - 'Edit' = '^(:?Ext)?(?Update.+$)' + 'Update' = '^(:?Ext)?(?Edit.+$)' 'New' = '^(:?Ext)?(?Add.+$)' 'Invoke' = '^(?Exec.+$)' } + $PermissionActions = @{ + 'List' = 'readonly' + 'Edit' = 'editor' + 'Add' = 'editor' + 'Exec' = 'admin' + } + foreach ($FunctionVerb in $FunctionVerbs.Keys) { if ($APIName -match $FunctionVerbs.$FunctionVerb) { $FunctionName = '{0}-{1}' -f $FunctionVerb, $Matches.APIName + $ApiFunction = $Matches.APIName + + foreach ($Action in $PermissionActions.Keys) { + if ($ApiFunction -match "^$Action") { + $ApiPermission = $PermissionActions.$Action + break + } + } break } } + if ($APIName -match '^Ext') { + $AccessResult = Confirm-CippApiAccess -Request $Request -AccessLevel $ApiPermission + if (!$AccessResult.Authorized) { return } + } + $HttpTrigger = @{ Request = $Request TriggerMetadata = $TriggerMetadata diff --git a/Modules/GraphRequests/Public/Get-ListGraphRequest.ps1 b/Modules/GraphRequests/Public/Get-ListGraphRequest.ps1 index 8ae912423514..9ce20cc140f2 100644 --- a/Modules/GraphRequests/Public/Get-ListGraphRequest.ps1 +++ b/Modules/GraphRequests/Public/Get-ListGraphRequest.ps1 @@ -1,4 +1,4 @@ -using namespace System.Net + function Get-ListGraphRequest { # Input bindings are passed in via param block. param($Request, $TriggerMetadata) @@ -6,10 +6,6 @@ function Get-ListGraphRequest { $APIName = $TriggerMetadata.FunctionName if ($APIName -match '^Ext') { - $AccessResult = Confirm-CippApiAccess -Request $Request - Write-Host ($AccessResult | ConvertTo-Json) - if (!$AccessResult.Authorized) { return } - $Message = 'Accessed this API | Endpoint: {0}' -f $Request.Query.Endpoint Write-LogMessage -user $AccessResult.ClientId -API $APINAME -message $Message -Sev 'Debug' } else { From 7910fe1d237e1f17cb25670d3d3f341a9f2666ca Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 12 Jun 2023 07:41:07 -0400 Subject: [PATCH 05/44] Fix reverse tenant lookup --- Modules/GraphRequests/Public/Get-GraphRequestList.ps1 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Modules/GraphRequests/Public/Get-GraphRequestList.ps1 b/Modules/GraphRequests/Public/Get-GraphRequestList.ps1 index abff34116e3f..7793fed428e5 100644 --- a/Modules/GraphRequests/Public/Get-GraphRequestList.ps1 +++ b/Modules/GraphRequests/Public/Get-GraphRequestList.ps1 @@ -91,7 +91,6 @@ function Get-GraphRequestList { } } } else { - if ($RunningQueue) { Write-Host 'Queue currently running' Write-Host ($RunningQueue | ConvertTo-Json) @@ -195,7 +194,7 @@ function Get-GraphRequestList { $GraphRequestResults = New-GraphGetRequest @GraphRequest -ErrorAction Stop if ($ReverseTenantLookup -and $GraphRequestResults) { $TenantInfo = $GraphRequestResults.$ReverseTenantLookupProperty | Sort-Object -Unique | ForEach-Object { - New-GraphGetRequest -uri "https://graph.microsoft.com/beta/tenantRelationships/findTenantInformationByTenantId(tenantId='$_')" -noauthcheck $true + New-GraphGetRequest -uri "https://graph.microsoft.com/beta/tenantRelationships/findTenantInformationByTenantId(tenantId='$_')" -noauthcheck $true -asApp:$true } foreach ($Result in $GraphRequestResults) { $Result | Select-Object @{n = 'TenantInfo'; e = { $TenantInfo | Where-Object { $Result.$ReverseTenantLookupProperty -eq $_.tenantId } } }, * From 9b8ea24e80b2dbd6572a7792a0ef41154e8183d0 Mon Sep 17 00:00:00 2001 From: Roel van der Wegen Date: Wed, 14 Jun 2023 22:18:03 +0200 Subject: [PATCH 06/44] Missing colon in error --- ExecAccessChecks/run.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ExecAccessChecks/run.ps1 b/ExecAccessChecks/run.ps1 index 42b0d2e6fbe8..a07a4f7cfb5b 100644 --- a/ExecAccessChecks/run.ps1 +++ b/ExecAccessChecks/run.ps1 @@ -137,7 +137,7 @@ if ($Request.query.Tenants -eq 'true') { catch { @{ TenantName = "$($tenant)" - Status = "Failed to connect to $(Get-NormalizedError -message $_.Exception.Message)" + Status = "Failed to connect to: $(Get-NormalizedError -message $_.Exception.Message)" } Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $tenant -message "Tenant access check failed: $(Get-NormalizedError -message $_) " -Sev 'Error' From 653b22bad6b0d2b09eed1b898138818b47784db0 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 15 Jun 2023 08:11:36 -0400 Subject: [PATCH 07/44] Update DNSHealth to 1.0.6 --- .../DNSHealth/{1.0.5 => 1.0.6}/DNSHealth.psd1 | 4 +- .../DNSHealth/{1.0.5 => 1.0.6}/DNSHealth.psm1 | 5 +- .../MailProviders/AppRiver.json | 0 .../MailProviders/BarracudaESS.json | 0 .../MailProviders/Google.json | 0 .../MailProviders/Intermedia.json | 0 .../MailProviders/Microsoft365.json | 0 .../MailProviders/Mimecast.json | 0 .../{1.0.5 => 1.0.6}/MailProviders/Null.json | 0 .../MailProviders/Proofpoint.json | 0 .../MailProviders/Reflexion.json | 0 .../MailProviders/Sophos.json | 0 .../MailProviders/SpamTitan.json | 0 .../MailProviders/_template.json | 0 .../{1.0.5 => 1.0.6}/PSGetModuleInfo.xml | 66 +++++++++---------- 15 files changed, 38 insertions(+), 37 deletions(-) rename Modules/DNSHealth/{1.0.5 => 1.0.6}/DNSHealth.psd1 (98%) rename Modules/DNSHealth/{1.0.5 => 1.0.6}/DNSHealth.psm1 (99%) rename Modules/DNSHealth/{1.0.5 => 1.0.6}/MailProviders/AppRiver.json (100%) rename Modules/DNSHealth/{1.0.5 => 1.0.6}/MailProviders/BarracudaESS.json (100%) rename Modules/DNSHealth/{1.0.5 => 1.0.6}/MailProviders/Google.json (100%) rename Modules/DNSHealth/{1.0.5 => 1.0.6}/MailProviders/Intermedia.json (100%) rename Modules/DNSHealth/{1.0.5 => 1.0.6}/MailProviders/Microsoft365.json (100%) rename Modules/DNSHealth/{1.0.5 => 1.0.6}/MailProviders/Mimecast.json (100%) rename Modules/DNSHealth/{1.0.5 => 1.0.6}/MailProviders/Null.json (100%) rename Modules/DNSHealth/{1.0.5 => 1.0.6}/MailProviders/Proofpoint.json (100%) rename Modules/DNSHealth/{1.0.5 => 1.0.6}/MailProviders/Reflexion.json (100%) rename Modules/DNSHealth/{1.0.5 => 1.0.6}/MailProviders/Sophos.json (100%) rename Modules/DNSHealth/{1.0.5 => 1.0.6}/MailProviders/SpamTitan.json (100%) rename Modules/DNSHealth/{1.0.5 => 1.0.6}/MailProviders/_template.json (100%) rename Modules/DNSHealth/{1.0.5 => 1.0.6}/PSGetModuleInfo.xml (82%) diff --git a/Modules/DNSHealth/1.0.5/DNSHealth.psd1 b/Modules/DNSHealth/1.0.6/DNSHealth.psd1 similarity index 98% rename from Modules/DNSHealth/1.0.5/DNSHealth.psd1 rename to Modules/DNSHealth/1.0.6/DNSHealth.psd1 index e0e645f60e48..257d08264fb1 100644 --- a/Modules/DNSHealth/1.0.5/DNSHealth.psd1 +++ b/Modules/DNSHealth/1.0.6/DNSHealth.psd1 @@ -3,7 +3,7 @@ # # Generated by: John Duprey # -# Generated on: 04/12/2023 +# Generated on: 06/15/2023 # @{ @@ -12,7 +12,7 @@ RootModule = 'DNSHealth.psm1' # Version number of this module. -ModuleVersion = '1.0.5' +ModuleVersion = '1.0.6' # Supported PSEditions # CompatiblePSEditions = @() diff --git a/Modules/DNSHealth/1.0.5/DNSHealth.psm1 b/Modules/DNSHealth/1.0.6/DNSHealth.psm1 similarity index 99% rename from Modules/DNSHealth/1.0.5/DNSHealth.psm1 rename to Modules/DNSHealth/1.0.6/DNSHealth.psm1 index 9e955dddbd54..253a66b1d0be 100644 --- a/Modules/DNSHealth/1.0.5/DNSHealth.psm1 +++ b/Modules/DNSHealth/1.0.6/DNSHealth.psm1 @@ -2050,6 +2050,7 @@ function Read-WhoisRecord { # Whois parser, generic Property: Value format with some multi-line support and comment handlers $WhoisRegex = '^(?!(?:%|>>>|-+|#|[*]))[^\S\n]*(?.+?):(?:[\r\n]+)?(:?(?!([0-9]|[/]{2}))[^\S\r\n]*(?.+))?$' + Write-Verbose "Querying WHOIS Server: $Server" # TCP Client for Whois $Client = New-Object System.Net.Sockets.TcpClient($Server, 43) try { @@ -2125,7 +2126,7 @@ function Read-WhoisRecord { $LastResult = $Results try { $Results = Read-WhoisRecord -Query $Query -Server $ReferralServer -Port $Port - if ($Results._Raw -Match '(No match|Not Found|No Data|The queried object does not exist)' -and $TopLevelReferrers -notcontains $Server) { + if ([string]::IsNullOrEmpty($Results._Raw) -or ($Results._Raw -Match '(No match|Not Found|No Data|The queried object does not exist)' -and $TopLevelReferrers -notcontains $Server)) { $Results = $LastResult } else { foreach ($s in $Results._ReferralServers) { @@ -2172,7 +2173,7 @@ function Read-WhoisRecord { # Return Whois results as PSObject $WhoisResults } -#EndRegion './Public/Records/Read-WhoisRecord.ps1' 174 +#EndRegion './Public/Records/Read-WhoisRecord.ps1' 175 #Region './Public/Resolver/Resolve-DnsHttpsQuery.ps1' 0 function Resolve-DnsHttpsQuery { <# diff --git a/Modules/DNSHealth/1.0.5/MailProviders/AppRiver.json b/Modules/DNSHealth/1.0.6/MailProviders/AppRiver.json similarity index 100% rename from Modules/DNSHealth/1.0.5/MailProviders/AppRiver.json rename to Modules/DNSHealth/1.0.6/MailProviders/AppRiver.json diff --git a/Modules/DNSHealth/1.0.5/MailProviders/BarracudaESS.json b/Modules/DNSHealth/1.0.6/MailProviders/BarracudaESS.json similarity index 100% rename from Modules/DNSHealth/1.0.5/MailProviders/BarracudaESS.json rename to Modules/DNSHealth/1.0.6/MailProviders/BarracudaESS.json diff --git a/Modules/DNSHealth/1.0.5/MailProviders/Google.json b/Modules/DNSHealth/1.0.6/MailProviders/Google.json similarity index 100% rename from Modules/DNSHealth/1.0.5/MailProviders/Google.json rename to Modules/DNSHealth/1.0.6/MailProviders/Google.json diff --git a/Modules/DNSHealth/1.0.5/MailProviders/Intermedia.json b/Modules/DNSHealth/1.0.6/MailProviders/Intermedia.json similarity index 100% rename from Modules/DNSHealth/1.0.5/MailProviders/Intermedia.json rename to Modules/DNSHealth/1.0.6/MailProviders/Intermedia.json diff --git a/Modules/DNSHealth/1.0.5/MailProviders/Microsoft365.json b/Modules/DNSHealth/1.0.6/MailProviders/Microsoft365.json similarity index 100% rename from Modules/DNSHealth/1.0.5/MailProviders/Microsoft365.json rename to Modules/DNSHealth/1.0.6/MailProviders/Microsoft365.json diff --git a/Modules/DNSHealth/1.0.5/MailProviders/Mimecast.json b/Modules/DNSHealth/1.0.6/MailProviders/Mimecast.json similarity index 100% rename from Modules/DNSHealth/1.0.5/MailProviders/Mimecast.json rename to Modules/DNSHealth/1.0.6/MailProviders/Mimecast.json diff --git a/Modules/DNSHealth/1.0.5/MailProviders/Null.json b/Modules/DNSHealth/1.0.6/MailProviders/Null.json similarity index 100% rename from Modules/DNSHealth/1.0.5/MailProviders/Null.json rename to Modules/DNSHealth/1.0.6/MailProviders/Null.json diff --git a/Modules/DNSHealth/1.0.5/MailProviders/Proofpoint.json b/Modules/DNSHealth/1.0.6/MailProviders/Proofpoint.json similarity index 100% rename from Modules/DNSHealth/1.0.5/MailProviders/Proofpoint.json rename to Modules/DNSHealth/1.0.6/MailProviders/Proofpoint.json diff --git a/Modules/DNSHealth/1.0.5/MailProviders/Reflexion.json b/Modules/DNSHealth/1.0.6/MailProviders/Reflexion.json similarity index 100% rename from Modules/DNSHealth/1.0.5/MailProviders/Reflexion.json rename to Modules/DNSHealth/1.0.6/MailProviders/Reflexion.json diff --git a/Modules/DNSHealth/1.0.5/MailProviders/Sophos.json b/Modules/DNSHealth/1.0.6/MailProviders/Sophos.json similarity index 100% rename from Modules/DNSHealth/1.0.5/MailProviders/Sophos.json rename to Modules/DNSHealth/1.0.6/MailProviders/Sophos.json diff --git a/Modules/DNSHealth/1.0.5/MailProviders/SpamTitan.json b/Modules/DNSHealth/1.0.6/MailProviders/SpamTitan.json similarity index 100% rename from Modules/DNSHealth/1.0.5/MailProviders/SpamTitan.json rename to Modules/DNSHealth/1.0.6/MailProviders/SpamTitan.json diff --git a/Modules/DNSHealth/1.0.5/MailProviders/_template.json b/Modules/DNSHealth/1.0.6/MailProviders/_template.json similarity index 100% rename from Modules/DNSHealth/1.0.5/MailProviders/_template.json rename to Modules/DNSHealth/1.0.6/MailProviders/_template.json diff --git a/Modules/DNSHealth/1.0.5/PSGetModuleInfo.xml b/Modules/DNSHealth/1.0.6/PSGetModuleInfo.xml similarity index 82% rename from Modules/DNSHealth/1.0.5/PSGetModuleInfo.xml rename to Modules/DNSHealth/1.0.6/PSGetModuleInfo.xml index 9a8a5290bd27..3ef782dbd75c 100644 --- a/Modules/DNSHealth/1.0.5/PSGetModuleInfo.xml +++ b/Modules/DNSHealth/1.0.6/PSGetModuleInfo.xml @@ -7,13 +7,13 @@ DNSHealth - 1.0.5 + 1.0.6 Module CIPP DNS Health Check Module John Duprey johnduprey 2023 John Duprey -
2023-04-12T19:41:15-04:00
+
2023-06-15T12:02:08-04:00
@@ -36,19 +36,8 @@ - Workflow + Function - - - - - - Cmdlet - - - - Command - Read-DmarcPolicy @@ -69,16 +58,8 @@ - RoleCapability - - - - DscResource - - - - Function - + Command + Read-DmarcPolicy @@ -98,6 +79,25 @@ + + Workflow + + + + + + + RoleCapability + + + + Cmdlet + + + + DscResource + + @@ -121,25 +121,25 @@ True True 0 - 23 - 27716 - 4/12/2023 7:41:15 PM -04:00 - 4/12/2023 7:41:15 PM -04:00 - 4/12/2023 7:41:15 PM -04:00 + 39 + 27746 + 6/15/2023 12:02:08 PM -04:00 + 6/15/2023 12:02:08 PM -04:00 + 6/15/2023 12:02:08 PM -04:00 PSModule PSFunction_Read-DmarcPolicy PSCommand_Read-DmarcPolicy PSFunction_Read-MtaStsPolicy PSCommand_Read-MtaStsPolicy PSFunction_Read-DkimRecord PSCommand_Read-DkimRecord PSFunction_Read-MtaStsRecord PSCommand_Read-MtaStsRecord PSFunction_Read-MXRecord PSCommand_Read-MXRecord PSFunction_Read-NSRecord PSCommand_Read-NSRecord PSFunction_Read-SPFRecord PSCommand_Read-SPFRecord PSFunction_Read-TlsRptRecord PSCommand_Read-TlsRptRecord PSFunction_Read-WhoisRecord PSCommand_Read-WhoisRecord PSFunction_Resolve-DnsHttpsQuery PSCommand_Resolve-DnsHttpsQuery PSFunction_Set-DnsResolver PSCommand_Set-DnsResolver PSFunction_Test-DNSSEC PSCommand_Test-DNSSEC PSFunction_Test-HttpsCertificate PSCommand_Test-HttpsCertificate PSFunction_Test-MtaSts PSCommand_Test-MtaSts PSIncludes_Function False - 2023-04-12T19:41:15Z - 1.0.5 + 2023-06-15T12:02:08Z + 1.0.6 John Duprey false Module - DNSHealth.nuspec|DNSHealth.psm1|MailProviders\Microsoft365.json|DNSHealth.psd1|MailProviders\Intermedia.json|MailProviders\Proofpoint.json|MailProviders\BarracudaESS.json|MailProviders\Mimecast.json|MailProviders\_template.json|MailProviders\Null.json|MailProviders\Sophos.json|MailProviders\Reflexion.json|MailProviders\SpamTitan.json|MailProviders\AppRiver.json|MailProviders\Google.json + DNSHealth.nuspec|MailProviders\SpamTitan.json|DNSHealth.psd1|MailProviders\Null.json|DNSHealth.psm1|MailProviders\BarracudaESS.json|MailProviders\Microsoft365.json|MailProviders\AppRiver.json|MailProviders\Google.json|MailProviders\Sophos.json|MailProviders\_template.json|MailProviders\Reflexion.json|MailProviders\Intermedia.json|MailProviders\Proofpoint.json|MailProviders\Mimecast.json a300d2b0-d468-46d1-88a3-e442a76b655b 7.0 Unknown
- C:\Users\jduprey.CNS\Documents\GitHub\CIPP-API\Modules\DNSHealth\1.0.5 + C:\Users\JDDoS\Documents\GitHub\CIPP-API\Modules\DNSHealth\1.0.6 From 8b1dea6c4ecbc8371563ea713e58b13006ecf2a5 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 15 Jun 2023 10:20:02 -0400 Subject: [PATCH 08/44] Add endpoint to graph error message --- Modules/GraphRequests/Public/Get-ListGraphRequest.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/GraphRequests/Public/Get-ListGraphRequest.ps1 b/Modules/GraphRequests/Public/Get-ListGraphRequest.ps1 index 9ce20cc140f2..fa237c482d9a 100644 --- a/Modules/GraphRequests/Public/Get-ListGraphRequest.ps1 +++ b/Modules/GraphRequests/Public/Get-ListGraphRequest.ps1 @@ -95,7 +95,7 @@ function Get-ListGraphRequest { $GraphRequestData = Get-GraphRequestList @GraphRequestParams $StatusCode = [HttpStatusCode]::OK } catch { - $GraphRequestData = "Graph Error: $($_.Exception.Message)" + $GraphRequestData = "Graph Error: $($_.Exception.Message) - Endpoint: $($Request.Query.Endpoint)" $StatusCode = [HttpStatusCode]::BadRequest } From 6a5bb24d32482bf37f5a58e60223c71ce8ca3f96 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Fri, 16 Jun 2023 12:58:35 +0200 Subject: [PATCH 09/44] fixes --- GraphHelper.psm1 | 104 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 71 insertions(+), 33 deletions(-) diff --git a/GraphHelper.psm1 b/GraphHelper.psm1 index c9a4db6e3e84..b6bf96a9b58d 100644 --- a/GraphHelper.psm1 +++ b/GraphHelper.psm1 @@ -70,7 +70,8 @@ function Get-GraphToken($tenantid, $scope, $AsApp, $AppID, $refreshToken, $Retur if ($script:AccessTokens.$TokenKey -and [int](Get-Date -UFormat %s -Millisecond 0) -lt $script:AccessTokens.$TokenKey.expires_on) { Write-Host 'Graph: cached token' $AccessToken = $script:AccessTokens.$TokenKey - } else { + } + 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 @@ -82,7 +83,8 @@ function Get-GraphToken($tenantid, $scope, $AsApp, $AppID, $refreshToken, $Retur if ($ReturnRefresh) { $header = $AccessToken } else { $header = @{ Authorization = "Bearer $($AccessToken.access_token)" } } return $header #Write-Host $header['Authorization'] - } catch { + } + 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 @@ -100,7 +102,8 @@ function Get-GraphToken($tenantid, $scope, $AsApp, $AppID, $refreshToken, $Retur $Tenant.LastGraphError = if ( $_.ErrorDetails.Message) { $msg = $_.ErrorDetails.Message | ConvertFrom-Json "$($msg.error):$($msg.error_description)" - } else { + } + else { $_.Exception.message } $Tenant.GraphErrorCount++ @@ -113,7 +116,8 @@ function Get-GraphToken($tenantid, $scope, $AsApp, $AppID, $refreshToken, $Retur function Write-LogMessage ($message, $tenant = 'None', $API = 'None', $user, $sev) { try { $username = ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($user)) | ConvertFrom-Json).userDetails - } catch { + } + catch { $username = $user } @@ -155,7 +159,8 @@ function New-GraphGetRequest { if ($scope -eq 'ExchangeOnline') { $AccessToken = Get-ClassicAPIToken -resource 'https://outlook.office365.com' -Tenantid $tenantid $headers = @{ Authorization = "Bearer $($AccessToken.access_token)" } - } else { + } + else { $headers = Get-GraphToken -tenantid $tenantid -scope $scope -AsApp $asapp } @@ -184,11 +189,13 @@ function New-GraphGetRequest { if ($CountOnly) { $Data.'@odata.count' $nextURL = $null - } else { + } + else { if ($data.value) { $data.value } else { ($Data) } if ($noPagination) { $nextURL = $null } else { $nextURL = $data.'@odata.nextLink' } } - } catch { + } + 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.') { @@ -202,7 +209,8 @@ function New-GraphGetRequest { $Tenant.LastGraphError = '' Update-AzDataTableEntity @TenantsTable -Entity $Tenant return $ReturnedData - } else { + } + else { Write-Error 'Not allowed. You cannot manage your own tenant or tenants not under your scope' } } @@ -218,13 +226,22 @@ function New-GraphPOSTRequest ($uri, $tenantid, $body, $type, $scope, $AsApp, $N if ((Get-AuthorisedRequest -Uri $uri -TenantID $tenantid) -or $NoAuthCheck) { try { $ReturnedData = (Invoke-RestMethod -Uri $($uri) -Method $TYPE -Body $body -Headers $headers -ContentType 'application/json; charset=utf-8') - } catch { - $Message = ($_.ErrorDetails.Message | ConvertFrom-Json -ErrorAction SilentlyContinue).error.message - if ($Message -eq $null) { $Message = $($_.Exception.Message) } + } + catch { + #setting ErrorMess because the error from a failed json conversion overwrites the exception. + $ErrorMess = $($_.Exception.Message) + try { + $Message = ($_.ErrorDetails.Message | ConvertFrom-Json -ErrorAction SilentlyContinue).error.message + } + catch { + $Message = $ErrorMess + } + throw $Message } return $ReturnedData - } else { + } + else { Write-Error 'Not allowed. You cannot manage your own tenant or tenants not under your scope' } } @@ -242,7 +259,8 @@ function Get-ClassicAPIToken($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 { + } + else { Write-Host 'Using classic' $uri = "https://login.microsoftonline.com/$($TenantID)/oauth2/token" $Body = @{ @@ -256,7 +274,8 @@ function Get-ClassicAPIToken($tenantID, $Resource) { 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 { + } + 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 @@ -297,12 +316,14 @@ function New-TeamsAPIGetRequest($Uri, $tenantID, $Method = 'GET', $Resource = '4 } $Data if ($noPagination) { $nextURL = $null } else { $nextURL = $data.NextLink } - } catch { + } + catch { throw "Failed to make Teams API Get Request $_" } } until ($null -eq $NextURL) return $ReturnedData - } else { + } + else { Write-Error 'Not allowed. You cannot manage your own tenant or tenants not under your scope' } } @@ -324,12 +345,14 @@ function New-ClassicAPIGetRequest($TenantID, $Uri, $Method = 'GET', $Resource = } $Data if ($noPagination) { $nextURL = $null } else { $nextURL = $data.NextLink } - } catch { + } + catch { throw "Failed to make Classic Get Request $_" } } until ($null -eq $NextURL) return $ReturnedData - } else { + } + else { Write-Error 'Not allowed. You cannot manage your own tenant or tenants not under your scope' } } @@ -350,11 +373,13 @@ function New-ClassicAPIPostRequest($TenantID, $Uri, $Method = 'POST', $Resource } - } catch { + } + catch { throw "Failed to make Classic Get Request $_" } return $ReturnedData - } else { + } + else { Write-Error 'Not allowed. You cannot manage your own tenant or tenants not under your scope' } } @@ -365,7 +390,8 @@ function Get-AuthorisedRequest($TenantID, $Uri) { } if (($TenantID -ne $env:TenantId -or $env:PartnerTenantAvailable) -and (Get-Tenants -SkipList).defaultDomainName -notcontains $TenantID) { return $true - } else { + } + else { return $false } } @@ -389,9 +415,11 @@ function Get-Tenants { if ($IncludeAll.IsPresent) { $Filter = "PartitionKey eq 'Tenants'" - } elseif ($IncludeErrors.IsPresent) { + } + elseif ($IncludeErrors.IsPresent) { $Filter = "PartitionKey eq 'Tenants' and Excluded eq false" - } else { + } + else { $Filter = "PartitionKey eq 'Tenants' and Excluded eq false and GraphErrorCount lt 50" } $IncludedTenantsCache = Get-AzDataTableEntity @TenantsTable -Filter $Filter @@ -401,7 +429,8 @@ function Get-Tenants { 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, tenantStatusInformation | Where-Object -Property defaultDomainName -NotIn $SkipListCache.defaultDomainName - } catch { + } + catch { Write-Host 'probably no license for Lighthouse. Using old API.' } if (!$TenantList.customerId) { @@ -488,7 +517,8 @@ function New-ExoRequest ($tenantid, $cmdlet, $cmdParams, $useSystemMailbox, $Anc $tenant = (get-tenants | Where-Object -Property defaultDomainName -EQ $tenantid).customerId if ($cmdParams) { $Params = $cmdParams - } else { + } + else { $Params = @{} } $ExoBody = ConvertTo-Json -Depth 5 -InputObject @{ @@ -517,14 +547,17 @@ function New-ExoRequest ($tenantid, $cmdlet, $cmdParams, $useSystemMailbox, $Anc } try { $ReturnedData = Invoke-RestMethod "https://outlook.office365.com/adminapi/beta/$($tenant)/InvokeCommand" -Method POST -Body $ExoBody -Headers $Headers -ContentType 'application/json; charset=utf-8' - } catch { + } + catch { + $ErrorMess = $($_.Exception.Message) $ReportedError = ($_.ErrorDetails | ConvertFrom-Json -ErrorAction SilentlyContinue) $Message = if ($ReportedError.error.details.message) { $ReportedError.error.details.message } else { $ReportedError.error.innererror.internalException.message } - if ($Message -eq $null) { $Message = $($_.Exception.Message) } + if ($null -eq $Message) { $Message = $ErrorMess } throw $Message } return $ReturnedData.value - } else { + } + else { Write-Error 'Not allowed. You cannot manage your own tenant or tenants not under your scope' } } @@ -607,7 +640,8 @@ function Get-CIPPMSolUsers { 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 { + } + 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 } @@ -632,14 +666,17 @@ function New-DeviceLogin { 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 { + } + 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 { + } + 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 { + } + else { $returncode = $Checking.error } } @@ -657,7 +694,8 @@ function New-passwordString { if ($PasswordType -eq 'Correct-Battery-Horse') { $Words = Get-Content .\words.txt (Get-Random -InputObject $words -Count 4) -join '-' - } else { + } + else { -join ('abcdefghkmnrstuvwxyzABCDEFGHKLMNPRSTUVWXYZ23456789$%&*#'.ToCharArray() | Get-Random -Count $count) } } From 1eb1bc83040bfc1888f82211fe13867ed50a6a3a Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Mon, 19 Jun 2023 19:42:37 +0200 Subject: [PATCH 10/44] update cpv permissions --- ExecCPVPermissions/run.ps1 | 28 +++++++++++++++++ GraphHelper.psm1 | 2 +- ListGenericTestFunction/run.ps1 | 55 +++++++++++++++++++++++---------- UpdatePermissionsQueue/run.ps1 | 27 ++++++++++++++++ 4 files changed, 95 insertions(+), 17 deletions(-) diff --git a/ExecCPVPermissions/run.ps1 b/ExecCPVPermissions/run.ps1 index b91fa7ba63ab..a8fe85f5973c 100644 --- a/ExecCPVPermissions/run.ps1 +++ b/ExecCPVPermissions/run.ps1 @@ -58,6 +58,34 @@ $GraphRequest = $ExpectedPermissions.requiredResourceAccess | ForEach-Object { } } + +$ourSVCPrincipal = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/servicePrincipals(appId='$($ENV:applicationid)')" -tenantid $Tenantfilter + +# if the app svc principal exists, consent app permissions +$apps = $ExpectedPermissions +$Grants = foreach ($App in $apps.requiredResourceAccess) { + try { + $svcPrincipalId = New-GraphGETRequest -uri "https://graph.microsoft.com/v1.0/servicePrincipals(appId='$($app.resourceAppId)')" -tenantid $tenantfilter + } + catch { + continue + } + foreach ($SingleResource in $app.ResourceAccess | Where-Object -Property Type -EQ "Role") { + [pscustomobject]@{ + principalId = $($ourSVCPrincipal.id) + resourceId = $($svcPrincipalId.id) + appRoleId = "$($SingleResource.Id)" + } + } +} +foreach ($Grant in $grants) { + try { + $SettingsRequest = New-GraphPOSTRequest -body ($grant | ConvertTo-Json) -uri "https://graph.microsoft.com/beta/servicePrincipals/$($ourSVCPrincipal.id)/appRoleAssignedTo" -tenantid $tenantfilter -type POST + } + catch { + "Failed to grant $($grant.appRoleId) to $($grant.resourceId): $($_.Exception.Message). " + } +} $StatusCode = [HttpStatusCode]::OK # Associate values to output bindings by calling 'Push-OutputBinding'. diff --git a/GraphHelper.psm1 b/GraphHelper.psm1 index b6bf96a9b58d..cca10afed730 100644 --- a/GraphHelper.psm1 +++ b/GraphHelper.psm1 @@ -64,7 +64,7 @@ function Get-GraphToken($tenantid, $scope, $AsApp, $AppID, $refreshToken, $Retur if (!$tenantid) { $tenantid = $env:TenantID } - $TokenKey = '{0}-{1}' -f $tenantid, $scope + $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) { diff --git a/ListGenericTestFunction/run.ps1 b/ListGenericTestFunction/run.ps1 index 7eee05f40a2f..c098160f5d1f 100644 --- a/ListGenericTestFunction/run.ps1 +++ b/ListGenericTestFunction/run.ps1 @@ -7,24 +7,47 @@ $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-AzDataTableEntity @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 + $svcPrincipalGraphAPI = Invoke-RestMethod -Method GET -Headers $Graphheader -Uri "https://graph.microsoft.com/v1.0/servicePrincipals(appId='00000003-0000-0000-c000-000000000000')" + $svcPrincipalSharepointAPI = Invoke-RestMethod -Method GET -Headers $Graphheader -Uri "https://graph.microsoft.com/v1.0/servicePrincipals(appId='00000003-0000-0ff1-ce00-000000000000')" + + # If the Sharepoint management app service principal does not yet exist then create it + + $svcPrincipalSPmgmt = Invoke-RestMethod -Method POST -Headers $Graphheader -Uri "https://graph.microsoft.com/v1.0/servicePrincipals" -Body '{ "appId": "5d961ae3-af69-4598-873f-3caa27d58a46" }' -ContentType "application/Json" + + # if the app svc principal exists, consent app permissions + if ($svcPrincipalSPmgmt) { + $grants = @( + [pscustomobject]@{ + principalId = $($svcPrincipalSPmgmt.id) + resourceId = $($svcPrincipalGraphAPI.id) + appRoleId = "a82116e5-55eb-4c41-a434-62fe8a61c773" + } # Graph Sites.FullControl.All + [pscustomobject]@{ + principalId = $($svcPrincipalSPmgmt.id) + resourceId = $($svcPrincipalGraphAPI.id) + appRoleId = "f12eb8d6-28e3-46e6-b2c0-b7e4dc69fc95" + } # Graph TermStore.ReadWrite.All + [pscustomobject]@{ + principalId = $($svcPrincipalSPmgmt.id) + resourceId = $($svcPrincipalSharepointAPI.id) + appRoleId = "678536fe-1083-478a-9c59-b99265e6b0d3" + } # Sharepoint API Sites.FullControl.All + [pscustomobject]@{ + principalId = $($svcPrincipalSPmgmt.id) + resourceId = $($svcPrincipalSharepointAPI.id) + appRoleId = "c8e3537c-ec53-43b9-bed3-b2bd3617ae97" + } # Sharepoint API TermStore.ReadWrite.All + ) + + foreach ($grant in $grants) { + try { + Invoke-RestMethod -Method POST -Headers $Graphheader -Uri "https://graph.microsoft.com/v1.0/servicePrincipals/$($svcPrincipalSPmgmt.id)/appRoleAssignedTo" -Body ($grant | ConvertTo-Json) -ContentType "application/Json" + } catch { + } - } } - } -} -catch { - Write-LogMessage -API "Scheduler_Billing" -tenant "none" -message "Could not start billing processing $($_.Exception.Message)" -sev Error -} + Write-Output "Tenant has been consented: $($Tenant.defaultDomainName) | $($tenant.TenantId)" + } Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK diff --git a/UpdatePermissionsQueue/run.ps1 b/UpdatePermissionsQueue/run.ps1 index a31c4d6776d6..c4a5426405fc 100644 --- a/UpdatePermissionsQueue/run.ps1 +++ b/UpdatePermissionsQueue/run.ps1 @@ -53,6 +53,33 @@ $GraphRequest = $ExpectedPermissions.requiredResourceAccess | ForEach-Object { "Could not set CPV permissions for $PermissionsName. Does the Tenant have a license for this API? Error: $($_.Exception.message)" } } +$ourSVCPrincipal = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/servicePrincipals(appId='$($ENV:applicationid)')" -tenantid $Tenantfilter + +# if the app svc principal exists, consent app permissions +$apps = $ExpectedPermissions +$Grants = foreach ($App in $apps.requiredResourceAccess) { + try { + $svcPrincipalId = New-GraphGETRequest -uri "https://graph.microsoft.com/v1.0/servicePrincipals(appId='$($app.resourceAppId)')" -tenantid $tenantfilter + } + catch { + continue + } + foreach ($SingleResource in $app.ResourceAccess | Where-Object -Property Type -EQ "Role") { + [pscustomobject]@{ + principalId = $($ourSVCPrincipal.id) + resourceId = $($svcPrincipalId.id) + appRoleId = "$($SingleResource.Id)" + } + } +} +foreach ($Grant in $grants) { + try { + $SettingsRequest = New-GraphPOSTRequest -body ($grant | ConvertTo-Json) -uri "https://graph.microsoft.com/beta/servicePrincipals/$($ourSVCPrincipal.id)/appRoleAssignedTo" -tenantid $tenantfilter -type POST + } + catch { + "Failed to grant $($grant.appRoleId) to $($grant.resourceId): $($_.Exception.Message). " + } +} $GraphRequest = @{ LastApply = "$((Get-Date).ToString())" From 411ca04b88153cb6aba4610fcaa5835ecf93ae85 Mon Sep 17 00:00:00 2001 From: Roel van der Wegen Date: Tue, 20 Jun 2023 00:29:33 +0200 Subject: [PATCH 11/44] Add files via upload --- ListSharepointQuota/function.json | 19 ++++++++++++++ ListSharepointQuota/run.ps1 | 42 +++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 ListSharepointQuota/function.json create mode 100644 ListSharepointQuota/run.ps1 diff --git a/ListSharepointQuota/function.json b/ListSharepointQuota/function.json new file mode 100644 index 000000000000..925eab5aeae1 --- /dev/null +++ b/ListSharepointQuota/function.json @@ -0,0 +1,19 @@ +{ + "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/ListSharepointQuota/run.ps1 b/ListSharepointQuota/run.ps1 new file mode 100644 index 000000000000..f4ec77408445 --- /dev/null +++ b/ListSharepointQuota/run.ps1 @@ -0,0 +1,42 @@ +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 + 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 From 914a58dde7cecd2de5fa802a06d8f5ad3b18b1ef Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Thu, 22 Jun 2023 20:24:49 +0200 Subject: [PATCH 12/44] added permissions --- Cache_SAMSetup/PermissionsTranslator.json | 7 +++++++ Cache_SAMSetup/SAMManifest.json | 5 ++++- Standards_AnonReportDisable/run.ps1 | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/Cache_SAMSetup/PermissionsTranslator.json b/Cache_SAMSetup/PermissionsTranslator.json index 4d31a2c37dae..7d55a10a9a31 100644 --- a/Cache_SAMSetup/PermissionsTranslator.json +++ b/Cache_SAMSetup/PermissionsTranslator.json @@ -1,4 +1,11 @@ [ + { + "description": "Allows Exchange Management as app", + "displayName": "Manage Exchange As Application", + "id": "dc50a0fb-09a3-484d-be87-e023b12c6440", + "origin": "Application", + "value": "Exchange.ManageAsApp" + }, { "description": "Allows the app to read a basic set of profile properties of other users in your organization without a signed-in user. Includes display name, first and last name, email address, open extensions, and photo.", "displayName": "Read all users' basic profiles", diff --git a/Cache_SAMSetup/SAMManifest.json b/Cache_SAMSetup/SAMManifest.json index 478ae7f6b135..d91d319312e0 100644 --- a/Cache_SAMSetup/SAMManifest.json +++ b/Cache_SAMSetup/SAMManifest.json @@ -146,7 +146,9 @@ { "id": "34bf0e97-1971-4929-b999-9e2442d941d7", "type": "Role" }, { "id": "45cc0394-e837-488b-a098-1918f48d186c", "type": "Role" }, { "id": "be74164b-cff1-491c-8741-e671cb536e13", "type": "Role" }, + { "id": "2a60023f-3219-47ad-baa4-40e17cd02a1d", "type": "Role" }, { "id": "b27a61ec-b99c-4d6a-b126-c4375d08ae30", "type": "Scope" }, + { "id": "84bccea3-f856-4a8a-967b-dbe0a3d53a64", "type": "Scope" }, { "id": "280b3b69-0437-44b1-bc20-3b2fca1ee3e9", "type": "Scope" }, { "id": "885f682f-a990-4bad-a642-36736a74b0c7", @@ -172,7 +174,8 @@ { "resourceAppId": "00000002-0000-0ff1-ce00-000000000000", "resourceAccess": [ - { "id": "ab4f2b77-0b06-4fc1-a9de-02113fc2ab7c", "type": "Scope" } + { "id": "ab4f2b77-0b06-4fc1-a9de-02113fc2ab7c", "type": "Scope" }, + { "id": "dc50a0fb-09a3-484d-be87-e023b12c6440", "type": "Role" } ] }, { diff --git a/Standards_AnonReportDisable/run.ps1 b/Standards_AnonReportDisable/run.ps1 index a2525675eb6b..6c01cc4f3a8a 100644 --- a/Standards_AnonReportDisable/run.ps1 +++ b/Standards_AnonReportDisable/run.ps1 @@ -1,7 +1,7 @@ param($tenant) try { - New-GraphPostRequest -tenantid $tenant -Uri "https://graph.microsoft.com/beta/admin/reportSettings" -Type patch -Body '{"displayConcealedNames": false}' -ContentType "application/json" + New-GraphPostRequest -tenantid $tenant -Uri "https://graph.microsoft.com/beta/admin/reportSettings" -Type patch -Body '{"displayConcealedNames": false}' -ContentType "application/json" -AsApp $true Write-LogMessage -API "Standards" -tenant $tenant -message "Anonymous Reports Disabled." -sev Info } catch { From 8656e093c28bdfc69bc5111f1382ea2c3e6842f4 Mon Sep 17 00:00:00 2001 From: Chris Brannon Date: Thu, 22 Jun 2023 17:10:49 -0400 Subject: [PATCH 13/44] Limit admin password change to user objects only. --- Scheduler_Alert/run.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scheduler_Alert/run.ps1 b/Scheduler_Alert/run.ps1 index 3ddaccfe256e..d56c42678c04 100644 --- a/Scheduler_Alert/run.ps1 +++ b/Scheduler_Alert/run.ps1 @@ -17,7 +17,7 @@ try { $ShippedAlerts = switch ($Alerts) { { $_.'AdminPassword' -eq $true } { try { - New-GraphGETRequest -uri "https://graph.microsoft.com/beta/roleManagement/directory/roleAssignments?`$filter=roleDefinitionId eq '62e90394-69f5-4237-9190-012177145e10'" -tenantid $($tenant.tenant) | Where-Object -Property 'principalOrganizationId' -EQ $tenant.tenantid | ForEach-Object { + New-GraphGETRequest -uri "https://graph.microsoft.com/beta/roleManagement/directory/roleAssignments?`$filter=roleDefinitionId eq '62e90394-69f5-4237-9190-012177145e10'&`$expand=principal" -tenantid $($tenant.tenant) | Where-Object {($_.principalOrganizationId -EQ $tenant.tenantid) -and ($_.principal.'@odata.type' -eq '#microsoft.graph.user')} | ForEach-Object { $LastChanges = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/users/$($_.principalId)?`$select=UserPrincipalName,lastPasswordChangeDateTime" -tenant $($tenant.tenant) if ($LastChanges.LastPasswordChangeDateTime -gt (Get-Date).AddDays(-1)) { "Admin password has been changed for $($LastChanges.UserPrincipalName) in last 24 hours" } } From e91040636a4c2d5a3f522c2448738ccd1f1b3882 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Thu, 29 Jun 2023 11:41:41 +0200 Subject: [PATCH 14/44] updated adhoc license standard --- GetCippAlerts/run.ps1 | 8 +------- Standards_DisableSelfServiceLicenses/run.ps1 | 13 +------------ 2 files changed, 2 insertions(+), 19 deletions(-) diff --git a/GetCippAlerts/run.ps1 b/GetCippAlerts/run.ps1 index 1c1e0d11b657..c26917f79185 100644 --- a/GetCippAlerts/run.ps1 +++ b/GetCippAlerts/run.ps1 @@ -24,13 +24,7 @@ if ($env:WEBSITE_RUN_FROM_PACKAGE -ne '1') { }) } if ($Rows) { $Rows | ForEach-Object { $alerts.add($_) } } -if (!$env:WEBSITE_NAME) { - #Running locally, no alerts. :) - $Alerts = $null -} -else { - $Alerts = @($Alerts) -} +$Alerts = @($Alerts) $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' diff --git a/Standards_DisableSelfServiceLicenses/run.ps1 b/Standards_DisableSelfServiceLicenses/run.ps1 index 55d3b2e82799..50f3be239b63 100644 --- a/Standards_DisableSelfServiceLicenses/run.ps1 +++ b/Standards_DisableSelfServiceLicenses/run.ps1 @@ -1,18 +1,7 @@ param($tenant) 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' - $DisableSelfServiceBody = @" -http://provisioning.microsoftonline.com/IProvisioningWebService/SetCompanySettingsurn: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.svcVersion16false -"@ - $DisableSelfService = (Invoke-RestMethod -Uri 'https://provisioningapi.microsoftonline.com/provisioningwebservice.svc' -Method post -Body $DisableSelfServiceBody -ContentType 'application/soap+xml; charset=utf-8') - Write-LogMessage "Standards API: $($tenant) Disabled Self Service for licenses" -sev Info + Write-LogMessage "Standards API: $($tenant) failed to disable License Buy Self Service: $($exception.message)" -sev Error } catch { From cdccfd7f19cc61bf1a8dcd1c2bc3ae505d7a6417 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Thu, 29 Jun 2023 14:11:07 +0200 Subject: [PATCH 15/44] null graph request on dashboard --- ListOrg/run.ps1 | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/ListOrg/run.ps1 b/ListOrg/run.ps1 index f31f18f9d9b5..92ee467c194f 100644 --- a/ListOrg/run.ps1 +++ b/ListOrg/run.ps1 @@ -12,12 +12,15 @@ Write-Host "PowerShell HTTP trigger function processed a request." # Interact with query parameters or the body of the request. $TenantFilter = $Request.Query.TenantFilter -$GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/organization" -tenantid $TenantFilter -$StatusCode = [HttpStatusCode]::OK - +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 = $StatusCode + StatusCode = [HttpStatusCode]::OK Body = $GraphRequest }) From fc06ff3854ca40e76f033d214655e72010d4a6ab Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Thu, 29 Jun 2023 14:23:05 +0200 Subject: [PATCH 16/44] remove displayname from cpv --- ExecCPVPermissions/run.ps1 | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ExecCPVPermissions/run.ps1 b/ExecCPVPermissions/run.ps1 index a8fe85f5973c..7494a1b54f99 100644 --- a/ExecCPVPermissions/run.ps1 +++ b/ExecCPVPermissions/run.ps1 @@ -43,9 +43,7 @@ $GraphRequest = $ExpectedPermissions.requiredResourceAccess | ForEach-Object { $AppBody = @" { "ApplicationGrants":[ $(ConvertTo-Json -InputObject $RequiredCPVPerms -Compress -Depth 10)], - "ApplicationId": "$($env:ApplicationID)", - "DisplayName": "CIPP-SAM" -} + "ApplicationId": "$($env:ApplicationID)"} "@ $CPVConsent = New-GraphpostRequest -body $AppBody -Type POST -noauthcheck $true -uri "https://api.partnercenter.microsoft.com/v1/customers/$($TenantFilter)/applicationconsents" -scope "https://api.partnercenter.microsoft.com/.default" -tenantid $env:TenantID "Succesfully set CPV permissions for $Permissionsname" From a4e6c4748c25c009a74856d9c617ba41a7c26b33 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Thu, 29 Jun 2023 14:30:27 +0200 Subject: [PATCH 17/44] removed displayname cpv --- UpdatePermissionsQueue/run.ps1 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/UpdatePermissionsQueue/run.ps1 b/UpdatePermissionsQueue/run.ps1 index c4a5426405fc..4853558dde82 100644 --- a/UpdatePermissionsQueue/run.ps1 +++ b/UpdatePermissionsQueue/run.ps1 @@ -37,8 +37,7 @@ $GraphRequest = $ExpectedPermissions.requiredResourceAccess | ForEach-Object { $AppBody = @" { "ApplicationGrants":[ $(ConvertTo-Json -InputObject $RequiredCPVPerms -Compress -Depth 10)], - "ApplicationId": "$($env:ApplicationID)", - "DisplayName": "CIPP-SAM" + "ApplicationId": "$($env:ApplicationID)" } "@ $CPVConsent = New-GraphpostRequest -body $AppBody -Type POST -noauthcheck $true -uri "https://api.partnercenter.microsoft.com/v1/customers/$($TenantFilter.customerId)/applicationconsents" -scope "https://api.partnercenter.microsoft.com/.default" -tenantid $env:TenantID From 8b62097a269f921ddcf7483db847d9f2c9b9904a Mon Sep 17 00:00:00 2001 From: BNWEIN Date: Thu, 29 Jun 2023 14:18:02 +0100 Subject: [PATCH 18/44] Fixed AnonReportingDisabling error not showing in log Fixed AnonReportingDisabling error not showing in log --- Standards_AnonReportDisable/run.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Standards_AnonReportDisable/run.ps1 b/Standards_AnonReportDisable/run.ps1 index 6c01cc4f3a8a..c04f87b957d3 100644 --- a/Standards_AnonReportDisable/run.ps1 +++ b/Standards_AnonReportDisable/run.ps1 @@ -5,5 +5,5 @@ try { Write-LogMessage -API "Standards" -tenant $tenant -message "Anonymous Reports Disabled." -sev Info } catch { - Write-LogMessage -API "Standards" -tenant $tenant -message "Failed to disable anonymous reports. Error: $($_.exception.message)" + Write-LogMessage -API "Standards" -tenant $tenant -message "Failed to disable anonymous reports. Error: $($_.exception.message)" -sev Error } \ No newline at end of file From 2bd173b11ac1670fc4b69bc0d6d723521a3470c8 Mon Sep 17 00:00:00 2001 From: Brandon Martinez Date: Thu, 29 Jun 2023 19:45:47 -0700 Subject: [PATCH 19/44] Corrected tenatid var in OneDrive MEM template, removed unrelated settings for Outlook --- Config/7b41924e-3051-4a23-b0d0-8cdeadc2c05a.IntuneTemplate.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Config/7b41924e-3051-4a23-b0d0-8cdeadc2c05a.IntuneTemplate.json b/Config/7b41924e-3051-4a23-b0d0-8cdeadc2c05a.IntuneTemplate.json index 9e29aee25935..b7e696cc9b81 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": "{\"added\":[{\"enabled\":true,\"presentationValues\":[],\"definition@odata.bind\":\"https://graph.microsoft.com/beta/deviceManagement/groupPolicyDefinitions('9a4db949-29e4-4e31-a129-bf2b88d8fa1b')\"},{\"enabled\":true,\"presentationValues\":[{\"@odata.type\":\"#microsoft.graph.groupPolicyPresentationValueText\",\"value\":\"$($tenant.customerId)\",\"presentation@odata.bind\":\"https://graph.microsoft.com/beta/deviceManagement/groupPolicyDefinitions('39147fa2-6c5e-437b-8264-19b50b891709')/presentations('fbefbbdf-5382-477c-8b6c-71f4a06e2805')\"},{\"@odata.type\":\"#microsoft.graph.groupPolicyPresentationValueText\",\"value\":\"0\",\"presentation@odata.bind\":\"https://graph.microsoft.com/beta/deviceManagement/groupPolicyDefinitions('39147fa2-6c5e-437b-8264-19b50b891709')/presentations('35c82072-a93b-4022-be14-8684c2f6fcc2')\"}],\"definition@odata.bind\":\"https://graph.microsoft.com/beta/deviceManagement/groupPolicyDefinitions('39147fa2-6c5e-437b-8264-19b50b891709')\"},{\"enabled\":true,\"presentationValues\":[],\"definition@odata.bind\":\"https://graph.microsoft.com/beta/deviceManagement/groupPolicyDefinitions('81c07ba0-7512-402d-b1f6-00856975cfab')\"},{\"enabled\":true,\"presentationValues\":[],\"definition@odata.bind\":\"https://graph.microsoft.com/beta/deviceManagement/groupPolicyDefinitions('61b07a01-7e60-4127-b086-f6b32458a5c5')\"},{\"enabled\":true,\"presentationValues\":[],\"definition@odata.bind\":\"https://graph.microsoft.com/beta/deviceManagement/groupPolicyDefinitions('8866d7bd-42fb-4695-b6f2-80e0a90b1ac3')\"},{\"enabled\":true,\"presentationValues\":[],\"definition@odata.bind\":\"https://graph.microsoft.com/beta/deviceManagement/groupPolicyDefinitions('f974758d-1fab-42fe-ad36-3a6cd25c49c1')\"}],\"updated\":[],\"deletedIds\":[]}\r\n", + "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" } From 421ad3c62cea58f7a18ca03d8bec788298c9dcf0 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Fri, 30 Jun 2023 14:36:43 +0200 Subject: [PATCH 20/44] fixes duplicate policies --- ListGenericTestFunction/run.ps1 | 51 ++++----------------------------- ListIntunePolicy/run.ps1 | 2 +- 2 files changed, 6 insertions(+), 47 deletions(-) diff --git a/ListGenericTestFunction/run.ps1 b/ListGenericTestFunction/run.ps1 index c098160f5d1f..c764f4a7f8a2 100644 --- a/ListGenericTestFunction/run.ps1 +++ b/ListGenericTestFunction/run.ps1 @@ -5,51 +5,10 @@ param($Request, $TriggerMetadata) $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - - - $svcPrincipalGraphAPI = Invoke-RestMethod -Method GET -Headers $Graphheader -Uri "https://graph.microsoft.com/v1.0/servicePrincipals(appId='00000003-0000-0000-c000-000000000000')" - $svcPrincipalSharepointAPI = Invoke-RestMethod -Method GET -Headers $Graphheader -Uri "https://graph.microsoft.com/v1.0/servicePrincipals(appId='00000003-0000-0ff1-ce00-000000000000')" - - # If the Sharepoint management app service principal does not yet exist then create it - - $svcPrincipalSPmgmt = Invoke-RestMethod -Method POST -Headers $Graphheader -Uri "https://graph.microsoft.com/v1.0/servicePrincipals" -Body '{ "appId": "5d961ae3-af69-4598-873f-3caa27d58a46" }' -ContentType "application/Json" - - # if the app svc principal exists, consent app permissions - if ($svcPrincipalSPmgmt) { - $grants = @( - [pscustomobject]@{ - principalId = $($svcPrincipalSPmgmt.id) - resourceId = $($svcPrincipalGraphAPI.id) - appRoleId = "a82116e5-55eb-4c41-a434-62fe8a61c773" - } # Graph Sites.FullControl.All - [pscustomobject]@{ - principalId = $($svcPrincipalSPmgmt.id) - resourceId = $($svcPrincipalGraphAPI.id) - appRoleId = "f12eb8d6-28e3-46e6-b2c0-b7e4dc69fc95" - } # Graph TermStore.ReadWrite.All - [pscustomobject]@{ - principalId = $($svcPrincipalSPmgmt.id) - resourceId = $($svcPrincipalSharepointAPI.id) - appRoleId = "678536fe-1083-478a-9c59-b99265e6b0d3" - } # Sharepoint API Sites.FullControl.All - [pscustomobject]@{ - principalId = $($svcPrincipalSPmgmt.id) - resourceId = $($svcPrincipalSharepointAPI.id) - appRoleId = "c8e3537c-ec53-43b9-bed3-b2bd3617ae97" - } # Sharepoint API TermStore.ReadWrite.All - ) - - foreach ($grant in $grants) { - try { - Invoke-RestMethod -Method POST -Headers $Graphheader -Uri "https://graph.microsoft.com/v1.0/servicePrincipals/$($svcPrincipalSPmgmt.id)/appRoleAssignedTo" -Body ($grant | ConvertTo-Json) -ContentType "application/Json" - } catch { - - } - } - Write-Output "Tenant has been consented: $($Tenant.defaultDomainName) | $($tenant.TenantId)" - } +$body = '{"userPreferredMethodForSecondaryAuthentication": "push"}' +$graphRequest = New-GraphPOSTRequest -body $body -type PATCH -uri 'https://graph.microsoft.com/beta/users/b4156a0c-91c5-4195-bb1b-41b96d0806a7/authentication/signInPreferences' -tenantid $TenantFilter Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @("Executed") - }) -clobber \ No newline at end of file + StatusCode = [HttpStatusCode]::OK + Body = @($graphRequest) + }) -clobber \ No newline at end of file diff --git a/ListIntunePolicy/run.ps1 b/ListIntunePolicy/run.ps1 index 50438eac61db..048d6f60f50b 100644 --- a/ListIntunePolicy/run.ps1 +++ b/ListIntunePolicy/run.ps1 @@ -24,7 +24,7 @@ try { "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" - "https://graph.microsoft.com/beta/deviceManagement/configurationPolicies?`$select=id,name,description,platforms,technologies,lastModifiedDateTime,settingCount,roleScopeTagIds,isAssigned&`$top=100&`$filter=(platforms%20eq%20%27windows10%27%20or%20platforms%20eq%20%27macOS%27)%20and%20(technologies%20eq%20%27mdm%27%20or%20technologies%20eq%20%27windows10XManagement%27)%20and%20(templateReference/templateFamily%20eq%20%27none%27)&`$expand=assignments") + ) $GraphRequest = $GraphURLS | ForEach-Object { $URLName = (($_).split('?') | Select-Object -First 1) -replace 'https://graph.microsoft.com/beta/deviceManagement/', '' From e7e62c250e4edc4e92c5596de22d04213f60718c Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Fri, 30 Jun 2023 16:50:19 +0200 Subject: [PATCH 21/44] fixes to auth endpoint for tenants --- GraphHelper.psm1 | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/GraphHelper.psm1 b/GraphHelper.psm1 index cca10afed730..dcdc94831471 100644 --- a/GraphHelper.psm1 +++ b/GraphHelper.psm1 @@ -167,7 +167,6 @@ function New-GraphGetRequest { if ($ComplexFilter) { $headers['ConsistencyLevel'] = 'eventual' } - Write-Verbose "Using $($uri) as url" $nextURL = $uri # Track consecutive Graph API failures @@ -384,8 +383,17 @@ function New-ClassicAPIPostRequest($TenantID, $Uri, $Method = 'POST', $Resource } } -function Get-AuthorisedRequest($TenantID, $Uri) { - 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/*') { +function Get-AuthorisedRequest { + [CmdletBinding()] + Param( + [string]$TenantID, + [Parameter(Mandatory = $true)] + [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 } if (($TenantID -ne $env:TenantId -or $env:PartnerTenantAvailable) -and (Get-Tenants -SkipList).defaultDomainName -notcontains $TenantID) { @@ -396,6 +404,7 @@ function Get-AuthorisedRequest($TenantID, $Uri) { } } + function Get-Tenants { param ( [Parameter( ParameterSetName = 'Skip', Mandatory = $True )] From e6a3b90cf8d91648962d8fab3cb80461e6ec7e81 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Fri, 30 Jun 2023 16:52:09 +0200 Subject: [PATCH 22/44] uri not mandatory --- GraphHelper.psm1 | 1 - 1 file changed, 1 deletion(-) diff --git a/GraphHelper.psm1 b/GraphHelper.psm1 index dcdc94831471..b67439970994 100644 --- a/GraphHelper.psm1 +++ b/GraphHelper.psm1 @@ -387,7 +387,6 @@ function Get-AuthorisedRequest { [CmdletBinding()] Param( [string]$TenantID, - [Parameter(Mandatory = $true)] [string]$Uri ) if (!$TenantID) { From 12dbf29b75e6f0cfb8053731a27eca789ddf746d Mon Sep 17 00:00:00 2001 From: lwhitelock <79275328+lwhitelock@users.noreply.github.com> Date: Sun, 2 Jul 2023 17:56:01 +0100 Subject: [PATCH 23/44] Added Bulk Options and Device Details --- GraphHelper.psm1 | 65 +++++++++++++++++++++++++++ ListDeviceDetails/run.ps1 | 92 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 157 insertions(+) create mode 100644 ListDeviceDetails/run.ps1 diff --git a/GraphHelper.psm1 b/GraphHelper.psm1 index b67439970994..47ec58fd8a2e 100644 --- a/GraphHelper.psm1 +++ b/GraphHelper.psm1 @@ -707,3 +707,68 @@ function New-passwordString { -join ('abcdefghkmnrstuvwxyzABCDEFGHKLMNPRSTUVWXYZ23456789$%&*#'.ToCharArray() | Get-Random -Count $count) } } + +function New-GraphBulkRequest { + Param( + $tenantid, + $NoAuthCheck, + $scope, + $asapp, + $Requests + ) + + $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-AzDataTableEntity @TenantsTable -Filter $Filter + if (!$Tenant) { + $Tenant = @{ + GraphErrorCount = 0 + LastGraphError = $null + PartitionKey = 'TenantFailed' + RowKey = 'Failed' + } + } + if ((Get-AuthorisedRequest -Uri $uri -TenantID $tenantid) -or $NoAuthCheck) { + $ReturnedData = do { + 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' }) { + $AdditionalValues = New-GraphGetRequest -ComplexFilter -uri $MoreData.body.'@odata.nextLink' -tenantid $TenantFilter + $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 + } + } until ($null -eq $NextURL) + $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) { + ($Results | Where-Object { $_.id -eq $ID }).body.value +} diff --git a/ListDeviceDetails/run.ps1 b/ListDeviceDetails/run.ps1 new file mode 100644 index 000000000000..eb5c2fb5cdc5 --- /dev/null +++ b/ListDeviceDetails/run.ps1 @@ -0,0 +1,92 @@ +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' + $CompliancePolicies = Get-GraphBulkResultByID -Results $BulkResults -ID 'CompliancePolicies' + $DetectedApps = Get-GraphBulkResultByID -Results $BulkResults -ID 'DetectedApps' + + $Null = $GraphRequest | Add-Member -NotePropertyName 'DetectedApps' -NotePropertyValue $DetectedApps + $Null = $GraphRequest | Add-Member -NotePropertyName 'CompliancePolicies' -NotePropertyValue $CompliancePolicies + $Null = $GraphRequest | Add-Member -NotePropertyName 'DeviceGroups' -NotePropertyValue $DeviceGroups + + } + + $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),$($BulkResults)" + }) From effff30fa91eaf320047f06b215de8fd1c462f26 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Sun, 2 Jul 2023 19:15:32 +0200 Subject: [PATCH 24/44] Functionizing v1 --- Modules/CIPPCore/CIPPCore.psm1 | 13 ++++++ Modules/CIPPCore/CippCore.psd1 | Bin 0 -> 9600 bytes Modules/CIPPCore/Public/Remove-CIPPGroups.ps1 | 39 ++++++++++++++++++ .../CIPPCore/Public/Remove-CIPPLicense.ps1 | 23 +++++++++++ .../Public/Remove-CIPPMobileDevice.ps1 | 28 +++++++++++++ Modules/CIPPCore/Public/Remove-CIPPRules.ps1 | 28 +++++++++++++ Modules/CIPPCore/Public/Remove-CIPPUser.ps1 | 21 ++++++++++ .../CIPPCore/Public/Revoke-CIPPSessions.ps1 | 20 +++++++++ .../CIPPCore/Public/Set-CIPPHideFromGAL.ps1 | 22 ++++++++++ .../CIPPCore/Public/Set-CIPPMailboxType.ps1 | 21 ++++++++++ .../Public/Set-CIPPOneDriveAccess.ps1 | 39 ++++++++++++++++++ .../CIPPCore/Public/Set-CIPPOutOfoffice.ps1 | 19 +++++++++ .../CIPPCore/Public/Set-CIPPResetPassword.ps1 | 28 +++++++++++++ .../Public/Set-CIPPSharedMailboxAccess.ps1 | 28 +++++++++++++ .../CIPPCore/Public/Set-CIPPSignInState.ps1 | 22 ++++++++++ profile.ps1 | 1 + 16 files changed, 352 insertions(+) create mode 100644 Modules/CIPPCore/CIPPCore.psm1 create mode 100644 Modules/CIPPCore/CippCore.psd1 create mode 100644 Modules/CIPPCore/Public/Remove-CIPPGroups.ps1 create mode 100644 Modules/CIPPCore/Public/Remove-CIPPLicense.ps1 create mode 100644 Modules/CIPPCore/Public/Remove-CIPPMobileDevice.ps1 create mode 100644 Modules/CIPPCore/Public/Remove-CIPPRules.ps1 create mode 100644 Modules/CIPPCore/Public/Remove-CIPPUser.ps1 create mode 100644 Modules/CIPPCore/Public/Revoke-CIPPSessions.ps1 create mode 100644 Modules/CIPPCore/Public/Set-CIPPHideFromGAL.ps1 create mode 100644 Modules/CIPPCore/Public/Set-CIPPMailboxType.ps1 create mode 100644 Modules/CIPPCore/Public/Set-CIPPOneDriveAccess.ps1 create mode 100644 Modules/CIPPCore/Public/Set-CIPPOutOfoffice.ps1 create mode 100644 Modules/CIPPCore/Public/Set-CIPPResetPassword.ps1 create mode 100644 Modules/CIPPCore/Public/Set-CIPPSharedMailboxAccess.ps1 create mode 100644 Modules/CIPPCore/Public/Set-CIPPSignInState.ps1 diff --git a/Modules/CIPPCore/CIPPCore.psm1 b/Modules/CIPPCore/CIPPCore.psm1 new file mode 100644 index 000000000000..34e402aa7101 --- /dev/null +++ b/Modules/CIPPCore/CIPPCore.psm1 @@ -0,0 +1,13 @@ +$Public = @(Get-ChildItem -Path $PSScriptRoot\Public\*.ps1 -ErrorAction SilentlyContinue) +$Private = @(Get-ChildItem -Path $PSScriptRoot\private\*.ps1 -ErrorAction SilentlyContinue) +$Functions = $Public + $Private +foreach ($import in @($Functions)) { + try { + . $import.FullName + } + catch { + Write-Error -Message "Failed to import function $($import.FullName): $_" + } +} + +Export-ModuleMember -Function $Public.BaseName -Alias * diff --git a/Modules/CIPPCore/CippCore.psd1 b/Modules/CIPPCore/CippCore.psd1 new file mode 100644 index 0000000000000000000000000000000000000000..71c567254d51643ef8609db6c52b814a95798ab6 GIT binary patch literal 9600 zcmeI2TTh!u5Qg`@5HMJr}+W--Nl)2+u=5w8L5Gg^r$%Lo=L&ZaCD_FpTu( zP~QjfOFnKsY-rS}ex8I68rRXRq2Bc4b$(3U*LWJgcSNTd$F@c9AY6opy8fbXz3^Uh zPxQ2}r=$3$sj;lPSQ_(4qr2jh6+5DK9{GEx)tB_9_X#V*BP-txKZND55+3O9U0wNY zgjGF1)ZI!(2{|5xzv3J28{;4Jw-;LC6J4OKh+n;u zMV{ymy}3V@r9j$a%|p*!agPP+<~0I5JPHfpPOUb!!=}EUNguZMNOXB7g8tMM&&K9m z@q@pz+F^W?TQlh>=ksZJ9gM!~qk1(B-3|A`TDUK1R-*SV>b|9?mSX3g?$_kmi}LCR z^7ppxn)=KAkGihu?|uEQ>bc(H>yiU*&6lTHIOo1NtI9cVjQg98|9UBs#ZRLCO`7-7 zD(!2^R;2Yp`UH)NGMa1~TFYW%Qy$us^-tu@t>}G|`8?Gu5amc(2UEadLj*&;9F?#3 zBe*S7Eb{7>SP*A-v|hr(>)U3U#Er17c<5<`BprAL?hru(WdY)7X@Vzi#&HR49fOij zVuiyPf2|m6AbnFSf(69ksn+PnTths17Aj(EeKby5JJ+Pyd_TkKM5__`=xOzH$=VP% zeeuc4AO;?RW;(jVy5|}_&=0xTILC7=6O*AG*^m~Ajy0#L-{Z085aEu-p-E}lyN4=ae zO!I3~GDV8gS!4nItQwkKjyY+ePL^k5+KEGx=JqUg8`9NV>~mzqXTbt2gH4H>rSL+z ze_wZ7`eL~3_2G4Wa7k2BEQ1_)xO*`b5ETcxop^q))xa4%+bd?UnGtnXZ>Vwr_1=jJ z_)NUyH4D*8HG3hM^1O-{ZR*=dl2ZLv<-B=KyBwCcsBo#&dy<$4Khu?p9sN@IfK8SU z7gSyDgx#1^lIFO(D*nG--J3+$(eW$kg{mHFWsT}>9no;doyUW>_1hG)+h2a9g9+aBL?sjaua!onwUGPA7X@RJFn8oXO{ci zyN={heT^rMEPJpgM0Y3ApBQf$oVol+AAd<%X-)qZ+TA2_aw-J?2~K% z^=QwIcw_(26|LzyKsxfWc|UmarR1pRY`QeXU99g)k!V2(#GY_9dS0?IKAfT+8-ogN zP4*vF(F|10L5F(arY%~<#$1k}@VhVc&ExMXtL_VNPorG*I`|-a_r{u_ax?!f+V(u+ zKH8YwH=U1JWY~)FVRa(e$T|!~Ti%u&IWM!wQjW=L%!8)L24;de7GGp3?`rY2SoP&! z*W$sb;m;ID?v$UGRox2_*Kim_Do=o87kyTP6WKWa-)M1EUT(EN$+$}_+?_A*u< zIU-p9gB}=bSkJ^LfDPma+vz}^+RgeV-cPdH%Q7dZ19wP8#c`E}3?<5T+0dHpF`xfy zwyfFKmD(v{Z&8~>1%2V zb48`rjXP<}9BpZZ&Zk=zj@U!_vuBnsnaztkQSu~t32Wkg*12P6V!d6y*a^g@?u>W# zL__6eo($P?8?z(G_x(^VdI?YDQbsz>bmG7%T78G17^;lmx%^K+| zo<7pa)JuJ>o{G6%{5mIXuj}`1v*&92MTd6uZJLcJ|)Jgu3W1p|!S5PL=dM!@7 zqR0<6nvW4UlJ5<5y1T3&def|Prl|BYndQQ1^uBn?&!U%WJ9%y$@70q#yzUul9b%ro z#V}*Xf#sw(VKYMgKtScz?30Q+f~m@Q23XH`6`e zcF#WcYtibg+QLTc%0US3h$*yT2xGm=X&t2Ly23)+W7@7M^Sw{w7tdkegqL(;9}r(5 z-=*Dab$2%{CMHufz8;G{2vt4tF?{qBo|`|dA|^(eY{gox?gY@|;G?)j(@$hU>Lt@n zF*j9nE?UYpHHk`Ifuvk_H9a_bCT;fQPut>*s58{tzT~kU)pD-N6hKYp=RamS>WSM& zv#K8>Hzyf~@*@6+$a}QB>1qd+WyAKn%gJ4P=S`Z@f+5t!%v7bCtZ?S|}p9FZMw%x8MuNjm#@`9CE80+?^? A3jhEB literal 0 HcmV?d00001 diff --git a/Modules/CIPPCore/Public/Remove-CIPPGroups.ps1 b/Modules/CIPPCore/Public/Remove-CIPPGroups.ps1 new file mode 100644 index 000000000000..e55ff5fe0792 --- /dev/null +++ b/Modules/CIPPCore/Public/Remove-CIPPGroups.ps1 @@ -0,0 +1,39 @@ +function Remove-CIPPGroups { + [CmdletBinding()] + param( + $userid, + $tenantFilter, + $ExecutingUser + ) + + $AllGroups = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/groups/?$select=DisplayName,mailEnabled" -tenantid $tenantFilter) + + (New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($userid)/GetMemberGroups" -tenantid $tenantFilter -type POST -body '{"securityEnabledOnly": false}').value | ForEach-Object -Parallel { + Import-Module '.\GraphHelper.psm1' + $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 + + 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) { + $RemoveRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/groups/$_/members/$($using:userid)/`$ref" -tenantid $using:tenantFilter -type DELETE -body '' -Verbose + } + elseif ($IsMailEnabled) { + $Params = @{ Identity = $Groupname; Member = $using:userid ; BypassSecurityGroupManagerCheck = $true } + New-ExoRequest -tenantid $using:tenantFilter -cmdlet "Remove-DistributionGroupMember" -cmdParams $params -UseSystemMailbox $true + } + + Write-LogMessage -user $using:ExecutingUser -API "Remove From Groups" -message "Removed $($using:userid) from $groupname" -Sev "Info" -tenant $using:TenantFilter + return "Successfully removed user from group $Groupname" + } + catch { + Write-LogMessage -user $using:ExecutingUser -API "Remove From Groups" -message "Could not remove $($using:userid) from group $groupname" -Sev "Error" -tenant $using:TenantFilter + return "Could not remove user 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 new file mode 100644 index 000000000000..221b39470dff --- /dev/null +++ b/Modules/CIPPCore/Public/Remove-CIPPLicense.ps1 @@ -0,0 +1,23 @@ +function Remove-CIPPLicense { + [CmdletBinding()] + param ( + $ExecutingUser, + $userid, + $username, + $TenantFilter + ) + + try { + $CurrentLicenses = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($userid)" -tenantid $tenantFilter).assignedlicenses.skuid + $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 "Remove License" -message "Removed license for $($username)" -Sev "Info" -tenant $TenantFilter + Return "Removed current licenses: $(($ConvertTable | Where-Object { $_.guid -in $CurrentLicenses }).'Product_Display_Name' -join ',')" + + } + catch { + Write-LogMessage -user $ExecutingUser -API "Remove License" -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-CIPPMobileDevice.ps1 b/Modules/CIPPCore/Public/Remove-CIPPMobileDevice.ps1 new file mode 100644 index 000000000000..a5e173097279 --- /dev/null +++ b/Modules/CIPPCore/Public/Remove-CIPPMobileDevice.ps1 @@ -0,0 +1,28 @@ +function Remove-CIPPMobileDevice { + [CmdletBinding()] + param( + $userid, + $tenantFilter, + $username, + $ExecutingUser + ) + + try { + $devices = New-ExoRequest -tenantid $tenantFilter -cmdlet "Get-MobileDevice" -Anchor $username -cmdParams @{mailbox = $userid } | ForEach-Object { + try { + New-ExoRequest -tenantid $tenantFilter -cmdlet "Remove-MobileDevice" -Anchor $username -cmdParams @{Identity = $_.Identity } + "Removed device: $($_.FriendlyName)" + } + catch { + "Could not remove device: $($_.FriendlyName)" + continue + } + } + + Write-LogMessage -user $ExecutingUser -API "Remove Mobile" -message "Deleted mobile devices for $($username)" -Sev "Info" -tenant $tenantFilter + } + catch { + Write-LogMessage -user $ExecutingUser -API "Remove Mobile" -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/Remove-CIPPRules.ps1 b/Modules/CIPPCore/Public/Remove-CIPPRules.ps1 new file mode 100644 index 000000000000..41c6858bf29a --- /dev/null +++ b/Modules/CIPPCore/Public/Remove-CIPPRules.ps1 @@ -0,0 +1,28 @@ +function Remove-CIPPRules { + [CmdletBinding()] + param ( + $userid, + $username, + $TenantFilter, + $ExecutingUser + ) + + try { + $rules = New-ExoRequest -tenantid $TenantFilter -cmdlet "Get-InboxRule" -cmdParams @{mailbox = $userid } + if ($rules -eq $null) { + Write-LogMessage -user $ExecutingUser -API "Rules Removal" -message "No Rules for $($userid) to delete" -Sev "Info" -tenant $TenantFilter + return "No rules for $($userid) to delete" + } + else { + ForEach ($rule in $rules) { + New-ExoRequest -tenantid $TenantFilter -cmdlet "Remove-InboxRule" -Anchor $userid -cmdParams @{Identity = $rule.Identity } + } + Write-LogMessage -user $ExecutingUser -API "Rules Removal" -message "Deleted Rules for $($userid)" -Sev "Info" -tenant $TenantFilter + return "Deleted Rules for $($userid)" + } + } + catch { + Write-LogMessage -user $ExecutingUser -API "Rules Removal" -message "Could not delete rules for $($userid): $($_.Exception.Message)" -Sev "Error" -tenant $TenantFilter + return "Could not delete rules for $($userid). Error: $($_.Exception.Message)" + } +} diff --git a/Modules/CIPPCore/Public/Remove-CIPPUser.ps1 b/Modules/CIPPCore/Public/Remove-CIPPUser.ps1 new file mode 100644 index 000000000000..c9b5ee477e16 --- /dev/null +++ b/Modules/CIPPCore/Public/Remove-CIPPUser.ps1 @@ -0,0 +1,21 @@ +function Remove-CIPPUser { + [CmdletBinding()] + param ( + $ExecutingUser, + $userid, + $username, + $TenantFilter + ) + + try { + $DeleteRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($userid)" -type DELETE -tenant $TenantFilter + Write-LogMessage -user $ExecutingUser, -API "Remove User" -message "Deleted account $username" -Sev "Info" -tenant $TenantFilter + return "Deleted the user account $username" + + } + catch { + Write-LogMessage -user $ExecutingUser, -API "Remove User" -message "Could not delete $username" -Sev "Error" -tenant $TenantFilter + return "Could not delete $username. Error: $($_.Exception.Message)" + } +} + diff --git a/Modules/CIPPCore/Public/Revoke-CIPPSessions.ps1 b/Modules/CIPPCore/Public/Revoke-CIPPSessions.ps1 new file mode 100644 index 000000000000..700aa58c9fad --- /dev/null +++ b/Modules/CIPPCore/Public/Revoke-CIPPSessions.ps1 @@ -0,0 +1,20 @@ +function Revoke-CIPPSessions { + [CmdletBinding()] + param ( + $ExecutingUser, + $userid, + $username, + $TenantFilter + ) + + try { + $GraphRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($userid)/invalidateAllRefreshTokens" -tenantid $TenantFilter -type POST -body '{}' -verbose + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API "Revoke Sessions" -message "Revoked sessions for $($username)" -Sev "Info" -tenant $TenantFilter + return "Success. All sessions by $username have been revoked" + + } + catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API "Revoke Sessions" -message "Revoked sessions for $($username)" -Sev "Info" -tenant $TenantFilter + return "Revoke Session Failed: $($_.Exception.Message)" + } +} diff --git a/Modules/CIPPCore/Public/Set-CIPPHideFromGAL.ps1 b/Modules/CIPPCore/Public/Set-CIPPHideFromGAL.ps1 new file mode 100644 index 000000000000..801425b60574 --- /dev/null +++ b/Modules/CIPPCore/Public/Set-CIPPHideFromGAL.ps1 @@ -0,0 +1,22 @@ +function Set-CIPPHideFromGAL { + [CmdletBinding()] + param ( + $userid, + $tenantFilter, + [bool]$HideFromGAL, + $ExecutingUser + ) + + try { + $body = @{ + showInAddressList = [bool]$HideFromGAL + } | ConvertTo-Json -Compress -Depth 1 + $HideRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/v1.0/users/$($userid)" -tenantid $tenantFilter -type PATCH -body $body -verbose + Write-LogMessage -user $ExecutingUser -API "Hide From Address List" -message "Hid $($userid) from address list" -Sev "Info" -tenant $TenantFilter + return "Hidden $($userid) from address list" + } + catch { + Write-LogMessage -user $ExecutingUser -API "Hide From Address List" -message "Could not hide $($userid) from address list" -Sev "Error" -tenant $TenantFilter + return "Could not hide $($userid) from address list. Error: $($_.Exception.Message)" + } +} diff --git a/Modules/CIPPCore/Public/Set-CIPPMailboxType.ps1 b/Modules/CIPPCore/Public/Set-CIPPMailboxType.ps1 new file mode 100644 index 000000000000..b632e3f92a53 --- /dev/null +++ b/Modules/CIPPCore/Public/Set-CIPPMailboxType.ps1 @@ -0,0 +1,21 @@ +function Set-CIPPMailboxType { + [CmdletBinding()] + param ( + $ExecutingUser, + $userid, + $username, + $TenantFlter, + [Parameter()] + [ValidateSet('shared', 'Regular', 'Room', 'Equipment')]$MailboxType + ) + + try { + $Mailbox = New-ExoRequest -tenantid $TenantFilter -cmdlet "Set-mailbox" -cmdParams @{Identity = $userid; type = $MailboxType } -Anchor $username + Write-LogMessage -user $ExecutingUser -API "Mailbox Conversion" -message "Converted $($username) to a $MailboxType mailbox" -Sev "Info" -tenant $TenantFilter + return "Converted $($username) to a $MailboxType mailbox" + } + catch { + Write-LogMessage -user $ExecutingUser -API "Mailbox Conversion" -message "Could not convert $username to $MailboxType mailbox" -Sev "Error" -tenant $TenantFilter + return "Could not convert $($username) to a $MailboxType mailbox. Error: $($_.Exception.Message)" + } +} diff --git a/Modules/CIPPCore/Public/Set-CIPPOneDriveAccess.ps1 b/Modules/CIPPCore/Public/Set-CIPPOneDriveAccess.ps1 new file mode 100644 index 000000000000..e8f0ce1947ea --- /dev/null +++ b/Modules/CIPPCore/Public/Set-CIPPOneDriveAccess.ps1 @@ -0,0 +1,39 @@ +function Set-CIPPOnedriveAccess { + [CmdletBinding()] + param ( + $userid, + $OnedriveAccessUser, + $TenantFilter, + $ExecutingUser + ) + + try { + $URL = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/reports/getOneDriveUsageAccountDetail(period='D7')?`$format=application/json" -tenantid $TenantFilter | Where-Object -Property 'OwnerPrincipalName' -EQ $userid).siteUrl + $OnMicrosoft = (New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/domains?$top=999' -tenantid $TenantFilter | Where-Object -Property isInitial -EQ $true).id.split('.') | Select-Object -First 1 + $AdminUrl = "https://$($OnMicrosoft)-admin.sharepoint.com" + $XML = @" + + + + + + + + $URL + $OnedriveAccessUser + true + + + + + +"@ + $request = New-GraphPostRequest -scope "$AdminURL/.default" -tenantid $TenantFilter -Uri "$AdminURL/_vti_bin/client.svc/ProcessQuery" -Type POST -Body $XML -ContentType 'text/xml' + Write-LogMessage -user $ExecutingUser -API "Manage OneDrive Access" -message "Gave $($OnedriveAccessUser) access to $($userid) OneDrive" -Sev "Info" -tenant $TenantFilter + return "User's OneDrive URL is $URL. Access has been given to $($OnedriveAccessUser)" + } + catch { + Write-LogMessage -user $ExecutingUser -API "Manage OneDrive Access" -message "Could not add new owner to OneDrive $($OnedriveAccessUser) on $($userid)" -Sev "Error" -tenant $TenantFilter + return "Could not add owner to OneDrive for $($userid). Error: $($_.Exception.Message)" + } +} diff --git a/Modules/CIPPCore/Public/Set-CIPPOutOfoffice.ps1 b/Modules/CIPPCore/Public/Set-CIPPOutOfoffice.ps1 new file mode 100644 index 000000000000..018b3a921f7a --- /dev/null +++ b/Modules/CIPPCore/Public/Set-CIPPOutOfoffice.ps1 @@ -0,0 +1,19 @@ +function Set-CIPPOutOfOffice { + [CmdletBinding()] + param ( + $userid, + $OOO, + $TenantFilter, + $ExecutingUser + ) + + try { + $permissions = New-ExoRequest -tenantid $TenantFilter -cmdlet "Set-MailboxAutoReplyConfiguration" -cmdParams @{Identity = $userid; AutoReplyState = "Enabled"; InternalMessage = $OOO; ExternalMessage = $OOO } -Anchor $userid + Write-LogMessage -user $ExecutingUser -API "Set Out of Office" -message "Set Out-of-office for $($userid)" -Sev "Info" -tenant $TenantFilter + return "added Out-of-office to $($userid)" + } + catch { + Write-LogMessage -user $ExecutingUser -API "Set Out of Office" -message "Could not add OOO for $($userid)" -Sev "Error" -tenant $TenantFilter + return "Could not add out of office message for $($userid). Error: $($_.Exception.Message)" + } +} diff --git a/Modules/CIPPCore/Public/Set-CIPPResetPassword.ps1 b/Modules/CIPPCore/Public/Set-CIPPResetPassword.ps1 new file mode 100644 index 000000000000..440d66d6d55b --- /dev/null +++ b/Modules/CIPPCore/Public/Set-CIPPResetPassword.ps1 @@ -0,0 +1,28 @@ +function Set-CIPPResetPassword { + [CmdletBinding()] + param( + $userid, + $tenantFilter, + $ExecutingUser, + [bool]$forceChangePasswordNextSignIn = $true + ) + + try { + $password = New-passwordString + $passwordProfile = @{ + "passwordProfile" = @{ + "forceChangePasswordNextSignIn" = $forceChangePasswordNextSignIn + "password" = $password + } + } | ConvertTo-Json -Compress + + $GraphRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/v1.0/users/$($userid)" -tenantid $TenantFilter -type PATCH -body $passwordProfile -verbose + + Write-LogMessage -user $ExecutingUser -API "Reset Password" -message "Reset the password for $($userid)" -Sev "Info" -tenant $TenantFilter + return "The new password is $password" + } + catch { + Write-LogMessage -user $ExecutingUser -API "Reset Password" -message "Could not reset password for $($userid)" -Sev "Error" -tenant $TenantFilter + return "Could not reset password for $($userid). Error: $($_.Exception.Message)" + } +} diff --git a/Modules/CIPPCore/Public/Set-CIPPSharedMailboxAccess.ps1 b/Modules/CIPPCore/Public/Set-CIPPSharedMailboxAccess.ps1 new file mode 100644 index 000000000000..29b4f70fe5bb --- /dev/null +++ b/Modules/CIPPCore/Public/Set-CIPPSharedMailboxAccess.ps1 @@ -0,0 +1,28 @@ +function Set-CIPPSharedMailboxAccess { + [CmdletBinding()] + param ( + $userid, + $AccessUser, + [bool]$Automap, + $TenantFilter, + $ExecutingUser, + [array]$AccessRights + ) + + try { + $permissions = New-ExoRequest -tenantid $TenantFilter -cmdlet "Add-MailboxPermission" -cmdParams @{Identity = $userid; user = $AccessUser; automapping = $Automap; accessRights = $AccessRights; InheritanceType = "all" } -Anchor $userid + + if ($Automap) { + Write-LogMessage -user $ExecutingUser -API "Manage Shared Mailbox Access" -message "Gave $AccessRights permissions to $($AccessUser) on $($userid) with automapping" -Sev "Info" -tenant $TenantFilter + return "added $($AccessUser) to $($userid) Shared Mailbox with automapping, with the following permissions: $AccessRights" + } + else { + Write-LogMessage -user $ExecutingUser -API "Manage Shared Mailbox Access" -message "Gave $AccessRights permissions to $($AccessUser) on $($userid) without automapping" -Sev "Info" -tenant $TenantFilter + return "added $($AccessUser) to $($userid) Shared Mailbox without automapping, with the following permissions: $AccessRights" + } + } + catch { + Write-LogMessage -user $ExecutingUser -API "Manage Shared Mailbox Access" -message "Could not add mailbox permissions for $($AccessUser) on $($userid)" -Sev "Error" -tenant $TenantFilter + return "Could not add shared mailbox permissions for $($userid). Error: $($_.Exception.Message)" + } +} diff --git a/Modules/CIPPCore/Public/Set-CIPPSignInState.ps1 b/Modules/CIPPCore/Public/Set-CIPPSignInState.ps1 new file mode 100644 index 000000000000..2493563e5902 --- /dev/null +++ b/Modules/CIPPCore/Public/Set-CIPPSignInState.ps1 @@ -0,0 +1,22 @@ +function Set-CIPPSignInState { + [CmdletBinding()] + param ( + $userid, + [bool]$AccountEnabled, + $TenantFilter, + $ExecutingUser + ) + + try { + $body = @{ + accountEnabled = [bool]$AccountEnabled + } | ConvertTo-Json -Compress -Depth 1 + $SignInState = New-GraphPostRequest -uri "https://graph.microsoft.com/v1.0/users/$($userid)" -tenantid $TenantFilter -type PATCH -body $body -verbose + Write-LogMessage -user $ExecutingUser -API "Disable User Sign-in" -message "Disabled $($userid)" -Sev "Info" -tenant $TenantFilter + return "Disabled user account for $userid" + } + catch { + Write-LogMessage -user $ExecutingUser -API "Disable User Sign-in" -message "Could not disable sign in for $($userid)" -Sev "Error" -tenant $TenantFilter + return "Could not disable $($userid). Error: $($_.Exception.Message)" + } +} diff --git a/profile.ps1 b/profile.ps1 index 9114a98ff5f8..7e80bf71358f 100644 --- a/profile.ps1 +++ b/profile.ps1 @@ -16,6 +16,7 @@ Import-Module Az.KeyVault Import-Module Az.Accounts Import-Module GraphRequests Import-Module CippExtensions +Import-module CippCore try { Disable-AzContextAutosave -Scope Process | Out-Null From 25bdf557f30dcf9d9a60cc671cd52e9230072abc Mon Sep 17 00:00:00 2001 From: lwhitelock <79275328+lwhitelock@users.noreply.github.com> Date: Sun, 2 Jul 2023 21:52:22 +0100 Subject: [PATCH 25/44] Added Bulk Helper functions and Device Details Endpoint --- GraphHelper.psm1 | 147 +++++++++++++------------------- ListDeviceDetails/function.json | 22 +++++ ListDeviceDetails/run.ps1 | 15 ++-- 3 files changed, 90 insertions(+), 94 deletions(-) create mode 100644 ListDeviceDetails/function.json diff --git a/GraphHelper.psm1 b/GraphHelper.psm1 index 47ec58fd8a2e..659d93ff305a 100644 --- a/GraphHelper.psm1 +++ b/GraphHelper.psm1 @@ -70,8 +70,7 @@ function Get-GraphToken($tenantid, $scope, $AsApp, $AppID, $refreshToken, $Retur if ($script:AccessTokens.$TokenKey -and [int](Get-Date -UFormat %s -Millisecond 0) -lt $script:AccessTokens.$TokenKey.expires_on) { Write-Host 'Graph: cached token' $AccessToken = $script:AccessTokens.$TokenKey - } - else { + } 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 @@ -83,8 +82,7 @@ function Get-GraphToken($tenantid, $scope, $AsApp, $AppID, $refreshToken, $Retur if ($ReturnRefresh) { $header = $AccessToken } else { $header = @{ Authorization = "Bearer $($AccessToken.access_token)" } } return $header #Write-Host $header['Authorization'] - } - catch { + } 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 @@ -102,8 +100,7 @@ function Get-GraphToken($tenantid, $scope, $AsApp, $AppID, $refreshToken, $Retur $Tenant.LastGraphError = if ( $_.ErrorDetails.Message) { $msg = $_.ErrorDetails.Message | ConvertFrom-Json "$($msg.error):$($msg.error_description)" - } - else { + } else { $_.Exception.message } $Tenant.GraphErrorCount++ @@ -116,8 +113,7 @@ function Get-GraphToken($tenantid, $scope, $AsApp, $AppID, $refreshToken, $Retur function Write-LogMessage ($message, $tenant = 'None', $API = 'None', $user, $sev) { try { $username = ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($user)) | ConvertFrom-Json).userDetails - } - catch { + } catch { $username = $user } @@ -159,8 +155,7 @@ function New-GraphGetRequest { if ($scope -eq 'ExchangeOnline') { $AccessToken = Get-ClassicAPIToken -resource 'https://outlook.office365.com' -Tenantid $tenantid $headers = @{ Authorization = "Bearer $($AccessToken.access_token)" } - } - else { + } else { $headers = Get-GraphToken -tenantid $tenantid -scope $scope -AsApp $asapp } @@ -188,13 +183,11 @@ function New-GraphGetRequest { if ($CountOnly) { $Data.'@odata.count' $nextURL = $null - } - else { + } else { if ($data.value) { $data.value } else { ($Data) } if ($noPagination) { $nextURL = $null } else { $nextURL = $data.'@odata.nextLink' } } - } - catch { + } 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.') { @@ -208,8 +201,7 @@ function New-GraphGetRequest { $Tenant.LastGraphError = '' Update-AzDataTableEntity @TenantsTable -Entity $Tenant return $ReturnedData - } - else { + } else { Write-Error 'Not allowed. You cannot manage your own tenant or tenants not under your scope' } } @@ -225,22 +217,19 @@ function New-GraphPOSTRequest ($uri, $tenantid, $body, $type, $scope, $AsApp, $N if ((Get-AuthorisedRequest -Uri $uri -TenantID $tenantid) -or $NoAuthCheck) { try { $ReturnedData = (Invoke-RestMethod -Uri $($uri) -Method $TYPE -Body $body -Headers $headers -ContentType 'application/json; charset=utf-8') - } - catch { + } catch { #setting ErrorMess because the error from a failed json conversion overwrites the exception. $ErrorMess = $($_.Exception.Message) try { $Message = ($_.ErrorDetails.Message | ConvertFrom-Json -ErrorAction SilentlyContinue).error.message - } - catch { + } catch { $Message = $ErrorMess } throw $Message } return $ReturnedData - } - else { + } else { Write-Error 'Not allowed. You cannot manage your own tenant or tenants not under your scope' } } @@ -258,8 +247,7 @@ function Get-ClassicAPIToken($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 { + } else { Write-Host 'Using classic' $uri = "https://login.microsoftonline.com/$($TenantID)/oauth2/token" $Body = @{ @@ -273,8 +261,7 @@ function Get-ClassicAPIToken($tenantID, $Resource) { 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 { + } 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 @@ -315,14 +302,12 @@ function New-TeamsAPIGetRequest($Uri, $tenantID, $Method = 'GET', $Resource = '4 } $Data if ($noPagination) { $nextURL = $null } else { $nextURL = $data.NextLink } - } - catch { + } catch { throw "Failed to make Teams API Get Request $_" } } until ($null -eq $NextURL) return $ReturnedData - } - else { + } else { Write-Error 'Not allowed. You cannot manage your own tenant or tenants not under your scope' } } @@ -344,14 +329,12 @@ function New-ClassicAPIGetRequest($TenantID, $Uri, $Method = 'GET', $Resource = } $Data if ($noPagination) { $nextURL = $null } else { $nextURL = $data.NextLink } - } - catch { + } catch { throw "Failed to make Classic Get Request $_" } } until ($null -eq $NextURL) return $ReturnedData - } - else { + } else { Write-Error 'Not allowed. You cannot manage your own tenant or tenants not under your scope' } } @@ -372,13 +355,11 @@ function New-ClassicAPIPostRequest($TenantID, $Uri, $Method = 'POST', $Resource } - } - catch { + } catch { throw "Failed to make Classic Get Request $_" } return $ReturnedData - } - else { + } else { Write-Error 'Not allowed. You cannot manage your own tenant or tenants not under your scope' } } @@ -397,8 +378,7 @@ function Get-AuthorisedRequest { } if (($TenantID -ne $env:TenantId -or $env:PartnerTenantAvailable) -and (Get-Tenants -SkipList).defaultDomainName -notcontains $TenantID) { return $true - } - else { + } else { return $false } } @@ -423,11 +403,9 @@ function Get-Tenants { if ($IncludeAll.IsPresent) { $Filter = "PartitionKey eq 'Tenants'" - } - elseif ($IncludeErrors.IsPresent) { + } elseif ($IncludeErrors.IsPresent) { $Filter = "PartitionKey eq 'Tenants' and Excluded eq false" - } - else { + } else { $Filter = "PartitionKey eq 'Tenants' and Excluded eq false and GraphErrorCount lt 50" } $IncludedTenantsCache = Get-AzDataTableEntity @TenantsTable -Filter $Filter @@ -437,8 +415,7 @@ function Get-Tenants { 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, tenantStatusInformation | Where-Object -Property defaultDomainName -NotIn $SkipListCache.defaultDomainName - } - catch { + } catch { Write-Host 'probably no license for Lighthouse. Using old API.' } if (!$TenantList.customerId) { @@ -525,8 +502,7 @@ function New-ExoRequest ($tenantid, $cmdlet, $cmdParams, $useSystemMailbox, $Anc $tenant = (get-tenants | Where-Object -Property defaultDomainName -EQ $tenantid).customerId if ($cmdParams) { $Params = $cmdParams - } - else { + } else { $Params = @{} } $ExoBody = ConvertTo-Json -Depth 5 -InputObject @{ @@ -555,8 +531,7 @@ function New-ExoRequest ($tenantid, $cmdlet, $cmdParams, $useSystemMailbox, $Anc } try { $ReturnedData = Invoke-RestMethod "https://outlook.office365.com/adminapi/beta/$($tenant)/InvokeCommand" -Method POST -Body $ExoBody -Headers $Headers -ContentType 'application/json; charset=utf-8' - } - catch { + } catch { $ErrorMess = $($_.Exception.Message) $ReportedError = ($_.ErrorDetails | ConvertFrom-Json -ErrorAction SilentlyContinue) $Message = if ($ReportedError.error.details.message) { $ReportedError.error.details.message } else { $ReportedError.error.innererror.internalException.message } @@ -564,8 +539,7 @@ function New-ExoRequest ($tenantid, $cmdlet, $cmdParams, $useSystemMailbox, $Anc throw $Message } return $ReturnedData.value - } - else { + } else { Write-Error 'Not allowed. You cannot manage your own tenant or tenants not under your scope' } } @@ -648,8 +622,7 @@ function Get-CIPPMSolUsers { 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 { + } 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 } @@ -674,17 +647,14 @@ function New-DeviceLogin { 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 { + } 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 { + } 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 { + } else { $returncode = $Checking.error } } @@ -702,8 +672,7 @@ function New-passwordString { if ($PasswordType -eq 'Correct-Battery-Horse') { $Words = Get-Content .\words.txt (Get-Random -InputObject $words -Count 4) -join '-' - } - else { + } else { -join ('abcdefghkmnrstuvwxyzABCDEFGHKLMNPRSTUVWXYZ23456789$%&*#'.ToCharArray() | Get-Random -Count $count) } } @@ -734,41 +703,45 @@ function New-GraphBulkRequest { } } if ((Get-AuthorisedRequest -Uri $uri -TenantID $tenantid) -or $NoAuthCheck) { - $ReturnedData = do { - 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) - } + 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' }) { - $AdditionalValues = New-GraphGetRequest -ComplexFilter -uri $MoreData.body.'@odata.nextLink' -tenantid $TenantFilter - $NewValues = [System.Collections.Generic.List[PSCustomObject]]$MoreData.body.value - $AdditionalValues | ForEach-Object { $NewValues.add($_) } - $MoreData.body.value = $NewValues - } + foreach ($MoreData in $ReturnedData.Responses | Where-Object { $_.body.'@odata.nextLink' }) { + $AdditionalValues = New-GraphGetRequest -ComplexFilter -uri $MoreData.body.'@odata.nextLink' -tenantid $TenantFilter + $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 + } 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 } - } until ($null -eq $NextURL) + 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) { +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/ListDeviceDetails/function.json b/ListDeviceDetails/function.json new file mode 100644 index 000000000000..3d31416065c2 --- /dev/null +++ b/ListDeviceDetails/function.json @@ -0,0 +1,22 @@ +{ + "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 index eb5c2fb5cdc5..14e97fb6a155 100644 --- a/ListDeviceDetails/run.ps1 +++ b/ListDeviceDetails/run.ps1 @@ -68,13 +68,14 @@ try { $BulkResults = New-GraphBulkRequest -Requests $BulkRequests -tenantid $TenantFilter - $DeviceGroups = Get-GraphBulkResultByID -Results $BulkResults -ID 'DeviceGroups' - $CompliancePolicies = Get-GraphBulkResultByID -Results $BulkResults -ID 'CompliancePolicies' - $DetectedApps = Get-GraphBulkResultByID -Results $BulkResults -ID 'DetectedApps' + $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) - $Null = $GraphRequest | Add-Member -NotePropertyName 'DetectedApps' -NotePropertyValue $DetectedApps - $Null = $GraphRequest | Add-Member -NotePropertyName 'CompliancePolicies' -NotePropertyValue $CompliancePolicies - $Null = $GraphRequest | Add-Member -NotePropertyName 'DeviceGroups' -NotePropertyValue $DeviceGroups } @@ -88,5 +89,5 @@ try { # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = $StatusCode - Body = "@($GraphRequest),$($BulkResults)" + Body = $GraphRequest }) From 6fa4fbb2f022cd43251630e9fddbdf5a6e674fb3 Mon Sep 17 00:00:00 2001 From: BNWEIN Date: Mon, 3 Jul 2023 20:49:47 +0100 Subject: [PATCH 26/44] Fixed Missing Severity's of several logging items Fixed Missing Severity's of several logging items --- Applications_Upload/run.ps1 | 2 +- DomainAnalyser_GetTenantDomains/run.ps1 | 2 +- Standards_DisableGuestDirectory/run.ps1 | 2 +- Standards_DisableM365GroupUsers/run.ps1 | 2 +- Standards_DisableSecurityGroupUsers/run.ps1 | 2 +- Standards_DisableTenantCreation/run.ps1 | 2 +- Standards_LegacyMFA/run.ps1 | 2 +- Standards_LegacyMFACleanup/run.ps1 | 4 ++-- Standards_PWdisplayAppInformationRequiredState/run.ps1 | 2 +- Standards_PWnumberMatchingRequiredState/run.ps1 | 2 +- Standards_SSPR/run.ps1 | 2 +- Standards_SecurityDefaults/run.ps1 | 4 ++-- standards_GroupTemplate/run.ps1 | 2 +- standards_IntuneTemplate/run.ps1 | 4 ++-- standards_TransportRuleTemplate/run.ps1 | 8 ++++---- 15 files changed, 21 insertions(+), 21 deletions(-) diff --git a/Applications_Upload/run.ps1 b/Applications_Upload/run.ps1 index 12abc83e0b40..31566b015b8d 100644 --- a/Applications_Upload/run.ps1 +++ b/Applications_Upload/run.ps1 @@ -112,7 +112,7 @@ foreach ($tenant in $tenants) { $assign = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceAppManagement/mobileApps/$($NewApp.id)/assign" -tenantid $tenant -type POST -body $AssignBody Write-LogMessage -api "AppUpload" -tenant $($Tenant) -message "Assigned application $($chocoApp.ApplicationName) to $AssignTo" -Sev "Info" } - Write-LogMessage -api "AppUpload" -tenant $($Tenant) -message "Successfully added Application" + Write-LogMessage -api "AppUpload" -tenant $($Tenant) -message "Successfully added Application" -Sev "Info" } catch { "Failed to add Application for $($Tenant): $($_.Exception.Message)" diff --git a/DomainAnalyser_GetTenantDomains/run.ps1 b/DomainAnalyser_GetTenantDomains/run.ps1 index a2717df70d17..def86a78461b 100644 --- a/DomainAnalyser_GetTenantDomains/run.ps1 +++ b/DomainAnalyser_GetTenantDomains/run.ps1 @@ -93,5 +93,5 @@ if ($TenantCount -gt 0) { } catch { Write-LogMessage -API 'DomainAnalyser' -message "Domain Analyser GetTenantDomains Error $($_.Exception.Message)" -sev info } } - catch { Write-LogMessage -API 'DomainAnalyser' -message "GetTenantDomains loop exception: $($_.Exception.Message) line $($_.InvocationInfo.ScriptLineNumber)" } + catch { Write-LogMessage -API 'DomainAnalyser' -message "GetTenantDomains loop exception: $($_.Exception.Message) line $($_.InvocationInfo.ScriptLineNumber)" -sev "Error"} } diff --git a/Standards_DisableGuestDirectory/run.ps1 b/Standards_DisableGuestDirectory/run.ps1 index c347598e212a..cc81ded587a3 100644 --- a/Standards_DisableGuestDirectory/run.ps1 +++ b/Standards_DisableGuestDirectory/run.ps1 @@ -7,5 +7,5 @@ try { Write-LogMessage -API "Standards" -tenant $tenant -message "Disabled Guest access to directory information." -sev Info } catch { - Write-LogMessage -API "Standards" -tenant $tenant -message "Failed to disable Guest access to directory information.: $($_.exception.message)" + Write-LogMessage -API "Standards" -tenant $tenant -message "Failed to disable Guest access to directory information.: $($_.exception.message)" -sev "Error" } diff --git a/Standards_DisableM365GroupUsers/run.ps1 b/Standards_DisableM365GroupUsers/run.ps1 index 08758135b0b2..b4808a0b466a 100644 --- a/Standards_DisableM365GroupUsers/run.ps1 +++ b/Standards_DisableM365GroupUsers/run.ps1 @@ -8,5 +8,5 @@ try { Write-LogMessage -API "Standards" -tenant $tenant -message "Standards API: Disabled users from creating Security Groups." -sev Info } catch { - Write-LogMessage -API "Standards" -tenant $tenant -message "Failed to disable users from creating Security Groups: $($_.exception.message)" + Write-LogMessage -API "Standards" -tenant $tenant -message "Failed to disable users from creating Security Groups: $($_.exception.message)" -sev "Error" } diff --git a/Standards_DisableSecurityGroupUsers/run.ps1 b/Standards_DisableSecurityGroupUsers/run.ps1 index bfc3fd3aa395..459c82c2d72a 100644 --- a/Standards_DisableSecurityGroupUsers/run.ps1 +++ b/Standards_DisableSecurityGroupUsers/run.ps1 @@ -7,5 +7,5 @@ try { Write-LogMessage -API "Standards" -tenant $tenant -message "Standards API: Disabled users from creating Security Groups." -sev Info } catch { - Write-LogMessage -API "Standards" -tenant $tenant -message "Failed to disable users from creating Security Groups: $($_.exception.message)" + Write-LogMessage -API "Standards" -tenant $tenant -message "Failed to disable users from creating Security Groups: $($_.exception.message)" -sev "Error" } diff --git a/Standards_DisableTenantCreation/run.ps1 b/Standards_DisableTenantCreation/run.ps1 index accfc0c6a96c..39e4057fea98 100644 --- a/Standards_DisableTenantCreation/run.ps1 +++ b/Standards_DisableTenantCreation/run.ps1 @@ -6,5 +6,5 @@ try { Write-LogMessage -API "Standards" -tenant $tenant -message "Standards API: Disabled users from creating tenants." -sev Info } catch { - Write-LogMessage -API "Standards" -tenant $tenant -message "Failed to disable users from creating tenants: $($_.exception.message)" + Write-LogMessage -API "Standards" -tenant $tenant -message "Failed to disable users from creating tenants: $($_.exception.message)" -sev "Error" } diff --git a/Standards_LegacyMFA/run.ps1 b/Standards_LegacyMFA/run.ps1 index 3ab557973f42..2347a529547d 100644 --- a/Standards_LegacyMFA/run.ps1 +++ b/Standards_LegacyMFA/run.ps1 @@ -20,5 +20,5 @@ try { } catch { - Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to enable (legacy) per user MFA: $($_.exception.message)" + Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to enable (legacy) per user MFA: $($_.exception.message)" -sev "Error" } \ No newline at end of file diff --git a/Standards_LegacyMFACleanup/run.ps1 b/Standards_LegacyMFACleanup/run.ps1 index b6c1f4a84855..ba87338262d1 100644 --- a/Standards_LegacyMFACleanup/run.ps1 +++ b/Standards_LegacyMFACleanup/run.ps1 @@ -59,5 +59,5 @@ try { } } catch { - Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to clean up (legacy) per user MFA: $($_.exception.message)" -} + Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to clean up (legacy) per user MFA: $($_.exception.message)" -sev "Error" +} \ No newline at end of file diff --git a/Standards_PWdisplayAppInformationRequiredState/run.ps1 b/Standards_PWdisplayAppInformationRequiredState/run.ps1 index 449c10737ef3..e8dc974cf7d1 100644 --- a/Standards_PWdisplayAppInformationRequiredState/run.ps1 +++ b/Standards_PWdisplayAppInformationRequiredState/run.ps1 @@ -9,5 +9,5 @@ try { Write-LogMessage -API "Standards" -tenant $tenant -message "Enabled passwordless with Information and Number Matching." -sev Info } catch { - Write-LogMessage -API "Standards" -tenant $tenant -message "Failed to enable passwordless with Information and Number Matching. Error: $($_.exception.message)" + Write-LogMessage -API "Standards" -tenant $tenant -message "Failed to enable passwordless with Information and Number Matching. Error: $($_.exception.message)" -sev "Error" } \ No newline at end of file diff --git a/Standards_PWnumberMatchingRequiredState/run.ps1 b/Standards_PWnumberMatchingRequiredState/run.ps1 index 1656aaaaeb06..18aa87eef461 100644 --- a/Standards_PWnumberMatchingRequiredState/run.ps1 +++ b/Standards_PWnumberMatchingRequiredState/run.ps1 @@ -9,5 +9,5 @@ try { Write-LogMessage -API "Standards" -tenant $tenant -message "Enabled passwordless with Number Matching." -sev Info } catch { - Write-LogMessage -API "Standards" -tenant $tenant -message "Failed to enable passwordless with Number Matching. Error: $($_.exception.message)" + Write-LogMessage -API "Standards" -tenant $tenant -message "Failed to enable passwordless with Number Matching. Error: $($_.exception.message)" -sev "Error" } \ No newline at end of file diff --git a/Standards_SSPR/run.ps1 b/Standards_SSPR/run.ps1 index 4f3165913a56..3b0bbb7da943 100644 --- a/Standards_SSPR/run.ps1 +++ b/Standards_SSPR/run.ps1 @@ -3,5 +3,5 @@ try { Write-LogMessage -API "Standards" -tenant $tenant -message "SSPR standard is no longer available" -sev Error } catch { - Write-LogMessage -API "Standards" -tenant $tenant -message "Failed to enable SSPR $($_.exception.message)" + Write-LogMessage -API "Standards" -tenant $tenant -message "Failed to enable SSPR $($_.exception.message)" -sev "Error" } \ No newline at end of file diff --git a/Standards_SecurityDefaults/run.ps1 b/Standards_SecurityDefaults/run.ps1 index e3ed1c5476e6..09bb20f772e7 100644 --- a/Standards_SecurityDefaults/run.ps1 +++ b/Standards_SecurityDefaults/run.ps1 @@ -11,5 +11,5 @@ try { Write-LogMessage -API "Standards" -tenant $tenant -message "Standards API: Security Defaults Enabled." -sev Info } catch { - Write-LogMessage -API "Standards" -tenant $tenant -message "Failed to enable Security Defaults Error: $($_.exception.message)" -} + Write-LogMessage -API "Standards" -tenant $tenant -message "Failed to enable Security Defaults Error: $($_.exception.message)" -sev "Error" +} \ No newline at end of file diff --git a/standards_GroupTemplate/run.ps1 b/standards_GroupTemplate/run.ps1 index 5fded6c895b6..86f2154e1e08 100644 --- a/standards_GroupTemplate/run.ps1 +++ b/standards_GroupTemplate/run.ps1 @@ -54,7 +54,7 @@ foreach ($Template in $Setting.TemplateList) { } } catch { - Write-LogMessage -API "Standards" -tenant $tenant -message "Failed to create group: $($_.exception.message)" + Write-LogMessage -API "Standards" -tenant $tenant -message "Failed to create group: $($_.exception.message)" -sev "Error" } } diff --git a/standards_IntuneTemplate/run.ps1 b/standards_IntuneTemplate/run.ps1 index 8639e23d014f..9ead260460c6 100644 --- a/standards_IntuneTemplate/run.ps1 +++ b/standards_IntuneTemplate/run.ps1 @@ -80,9 +80,9 @@ foreach ($Template in $Setting.TemplateList) { $assign = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL('$($CreateRequest.id)')/assign" -tenantid $tenant -type POST -body $AssignBody Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($Tenant) -message "Assigned policy $($Displayname) to $AssignTo" -Sev "Info" } - Write-LogMessage -API "Standards" -tenant $tenant -message "Successfully added Intune Template policy for $($Tenant)" + Write-LogMessage -API "Standards" -tenant $tenant -message "Successfully added Intune Template policy for $($Tenant)" -sev "Info" } catch { - Write-LogMessage -API "Standards" -tenant $tenant -message "Failed to create or update Intune Template: $($_.exception.message)" + Write-LogMessage -API "Standards" -tenant $tenant -message "Failed to create or update Intune Template: $($_.exception.message)" -sev "Error" } } \ No newline at end of file diff --git a/standards_TransportRuleTemplate/run.ps1 b/standards_TransportRuleTemplate/run.ps1 index 636a51c656df..41212eb09b4e 100644 --- a/standards_TransportRuleTemplate/run.ps1 +++ b/standards_TransportRuleTemplate/run.ps1 @@ -19,17 +19,17 @@ foreach ($Template in $Setting.TemplateList) { Write-Host "Found existing" $RequestParams | Add-Member -NotePropertyValue $RequestParams.name -NotePropertyName Identity $GraphRequest = New-ExoRequest -tenantid $Tenant -cmdlet "Set-TransportRule" -cmdParams ($RequestParams | Select-Object -Property * -ExcludeProperty UseLegacyRegex) -useSystemMailbox $true - Write-LogMessage -API "Standards" -tenant $tenant -message "Successfully set transport rule for $tenant" + Write-LogMessage -API "Standards" -tenant $tenant -message "Successfully set transport rule for $tenant" -sev "Info" } else { Write-Host "Creating new" $GraphRequest = New-ExoRequest -tenantid $Tenant -cmdlet "New-TransportRule" -cmdParams $RequestParams -useSystemMailbox $true - Write-LogMessage -API "Standards" -tenant $tenant -message "Successfully created transport rule for $tenant" + Write-LogMessage -API "Standards" -tenant $tenant -message "Successfully created transport rule for $tenant" -sev "Info" } - Write-LogMessage -API $APINAME -tenant $Tenant -message "Created transport rule for $($tenantfilter)" -sev Debug + Write-LogMessage -API $APINAME -tenant $Tenant -message "Created transport rule for $($tenantfilter)" -sev "Debug" } catch { - Write-LogMessage -API "Standards" -tenant $tenant -message "Could not create transport rule for $($tenantfilter): $($_.Exception.message)" + Write-LogMessage -API "Standards" -tenant $tenant -message "Could not create transport rule for $($tenantfilter): $($_.Exception.message)" -sev "Error" } } \ No newline at end of file From 62d681ba9ac017a2c5fa4b539e3b35e60fa4ae99 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Tue, 4 Jul 2023 00:51:53 +0200 Subject: [PATCH 27/44] prepped offboarding to functionize --- ExecOffboardUser/run.ps1 | 261 +----------------- .../CIPPCore/Public/Set-CIPPForwarding.ps1 | 21 ++ ...oxAccess.ps1 => Set-CIPPMailboxAccess.ps1} | 2 +- .../CIPPCore/Public/Set-CIPPMailboxType.ps1 | 2 +- .../Public/Set-CIPPOneDriveAccess.ps1 | 42 +-- 5 files changed, 62 insertions(+), 266 deletions(-) create mode 100644 Modules/CIPPCore/Public/Set-CIPPForwarding.ps1 rename Modules/CIPPCore/Public/{Set-CIPPSharedMailboxAccess.ps1 => Set-CIPPMailboxAccess.ps1} (97%) diff --git a/ExecOffboardUser/run.ps1 b/ExecOffboardUser/run.ps1 index 9b8665b4b796..f805b30dd042 100644 --- a/ExecOffboardUser/run.ps1 +++ b/ExecOffboardUser/run.ps1 @@ -14,286 +14,55 @@ try { Write-Host ($request.body | ConvertTo-Json) $results = switch ($request.body) { { $_."ConvertToShared" -eq 'true' } { - try { - $SharedMailbox = New-ExoRequest -tenantid $TenantFilter -cmdlet "Set-mailbox" -cmdParams @{Identity = $userid; type = "Shared" } -Anchor $username - $ConvertedMailbox = New-ExoRequest -tenantid $TenantFilter -cmdlet "Get-mailbox" -cmdParams @{Identity = $userid } - $counter = 0 - while ($ConvertedMailbox.RecipientTypeDetails -eq 'UserMailbox' -and $counter -le 3) { - $counter ++ - $ConvertedMailbox = New-ExoRequest -tenantid $TenantFilter -cmdlet "Get-mailbox" -cmdParams @{Identity = $userid } - Write-Host "Waiting on convert" - - if ($ConvertedMailbox.RecipientTypeDetails -eq "UserMailbox" -and $counter -eq 3) { - $LicenseUnAssignAllowed = $false - "Conversion to Shared Mailbox is in progress. We might not be able to make changes to the licenses." - } - elseif ($ConvertedMailbox.RecipientTypeDetails -ne "UserMailbox" -and $counter -eq 3) { - $LicenseUnAssignAllowed = $true - "Converted $($username) to Shared Mailbox" - } - Start-Sleep -Milliseconds 500 - } - - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Converted $($username) to a shared mailbox" -Sev "Info" -tenant $TenantFilter - - } - catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Could not convert $username to shared mailbox" -Sev "Error" -tenant $TenantFilter - "Could not convert $($username) to a shared mailbox. Error: $($_.Exception.Message)" - } + Set-CIPPMailboxType -ExecutingUser $request.headers.'x-ms-client-principal' -tenantFilter $tenantFilter -userid $username -MailboxType "Shared" } { $_.RevokeSessions -eq 'true' } { - try { - $GraphRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($userid)/invalidateAllRefreshTokens" -tenantid $TenantFilter -type POST -body '{}' -verbose - "Success. All sessions by $username have been revoked" - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Revoked sessions for $($username)" -Sev "Info" -tenant $TenantFilter - - } - catch { - "Revoke Session Failed: $($_.Exception.Message)" - } + Revoke-CIPPSessions -tenantFilter $tenantFilter -username $username -userid $userid -ExecutingUser $request.headers.'x-ms-client-principal' } { $_.ResetPass -eq 'true' } { - try { - $password = New-passwordString - $passwordProfile = @" - {"passwordProfile": { "forceChangePasswordNextSignIn": true, "password": "$password" }}' -"@ - $GraphRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/v1.0/users/$($userid)" -tenantid $TenantFilter -type PATCH -body $passwordProfile -verbose - "The new password is $password" - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Reset the password for $($username)" -Sev "Info" -tenant $TenantFilter - - } - catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Could not reset password for $($username)" -Sev "Error" -tenant $TenantFilter - - "Could not reset password for $($username). Error: $($_.Exception.Message)" - } + Set-CIPPResetPassword -tenantFilter $tenantFilter -userid $username -ExecutingUser $request.headers.'x-ms-client-principal' } { $_.RemoveGroups -eq 'true' } { - $AllGroups = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/groups/?$select=DisplayName,mailEnabled" -tenantid $tenantFilter) - (New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($userid)/GetMemberGroups" -tenantid $tenantFilter -type POST -body '{"securityEnabledOnly": false}').value | ForEach-Object -parallel { - Import-Module '.\GraphHelper.psm1' - $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 - 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) { - $RemoveRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/groups/$_/members/$($using:userid)/`$ref" -tenantid $using:tenantFilter -type DELETE -body '' -Verbose - } - elseif ($IsMailEnabled) { - $Params = @{ Identity = $Groupname; Member = $using:userid ; BypassSecurityGroupManagerCheck = $true } - New-ExoRequest -tenantid $using:tenantFilter -cmdlet "Remove-DistributionGroupMember" -cmdParams $params -UseSystemMailbox $true - } - "Successfully removed user from group $Groupname" - Write-LogMessage -user $using:request.headers.'x-ms-client-principal' -API $using:APINAME -message "Removed $($using:username) from $groupname" -Sev "Info" -tenant $using:TenantFilter - } - catch { - Write-LogMessage -user $using:request.headers.'x-ms-client-principal' -API $using:APINAME -message "Could not remove $($using:username) from group $groupname" -Sev "Error" -tenant $using:TenantFilter - - "Could not remove user from group $($Groupname): $($_.Exception.Message). This is likely because its a Dynamic Group or synched with active directory" - } - - } + Remove-CIPPGroups -userid $userid -tenantFilter $Tenantfilter -ExecutingUser $request.headers.'x-ms-client-principal' } { $_."HideFromGAL" -eq 'true' } { - try { - $HideRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/v1.0/users/$($userid)" -tenantid $tenantFilter -type PATCH -body '{"showInAddressList": false}' -verbose - "Hidden from address list" - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Hid $($username) from address list" -Sev "Info" -tenant $TenantFilter - - } - catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Could not hide $($username) from address list" -Sev "Error" -tenant $TenantFilter - - "Could not hide $($username) from address list. Error: $($_.Exception.Message)" - } + Set-CIPPHideFromGAL -tenantFilter $tenantFilter -userid $username -HideFromGAL $true -ExecutingUser $request.headers.'x-ms-client-principal' } { $_."DisableSignIn" -eq 'true' } { - try { - $DisableUser = New-GraphPostRequest -uri "https://graph.microsoft.com/v1.0/users/$($userid)" -tenantid $TenantFilter -type PATCH -body '{"accountEnabled":false}' -verbose - "Disabled user account for $username" - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Disabled $($username)" -Sev "Info" -tenant $TenantFilter - - } - catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Could not disable sign in for $($username)" -Sev "Error" -tenant $TenantFilter - - "Could not disable $($username). Error: $($_.Exception.Message)" - } - + Set-CIPPSignInState -TenantFilter $tenantFilter -userid $username -AccountEnabled $false -ExecutingUser $request.headers.'x-ms-client-principal' } { $_."OnedriveAccess" -ne "" } { - try { - $URL = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/reports/getOneDriveUsageAccountDetail(period='D7')?`$format=application/json" -tenantid $tenantFilter | Where-Object -Property 'OwnerPrincipalName' -EQ $username).siteUrl - $OnMicrosoft = (New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/domains?$top=999' -tenantid $tenantFilter | Where-Object -Property isInitial -EQ $true).id.split('.') | Select-Object -First 1 - $AdminUrl = "https://$($onmicrosoft)-admin.sharepoint.com" - Write-Host ($OnMicrosoft) - $XML = @" - - - - - - - - $URL - $($request.body.OnedriveAccess) - true - - - - - -"@ - $request = New-GraphPostRequest -scope "$AdminURL/.default" -tenantid $tenantFilter -Uri "$AdminURL/_vti_bin/client.svc/ProcessQuery" -Type POST -Body $XML -ContentType 'text/xml' - - "Users Onedrive url is $URL. Access has been given to $($request.body.OnedriveAccess)" - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Gave $($Request.body.onedriveaccess) access to $($username) onedrive" -Sev "Info" -tenant $TenantFilter - - } - catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Could not add new owner to Onedrive $($request.body.AccessAutomap) on $($username)" -Sev "Error" -tenant $TenantFilter - - "Could not add owner to Onedrive for $($username). Error: $($_.Exception.Message)" - } + Set-CIPPOnedriveAccess -tenantFilter $tenantFilter -userid $username -OnedriveAccessUser $request.body.OnedriveAccess -ExecutingUser $request.headers.'x-ms-client-principal' } { $_."AccessNoAutomap" -ne "" } { - try { - $permissions = New-ExoRequest -tenantid $TenantFilter -cmdlet "Add-MailboxPermission" -cmdParams @{Identity = $userid; user = $Request.body.AccessNoAutomap; automapping = $false; accessRights = @("FullAccess"); InheritanceType = "all" } -Anchor $username - "added $($Request.body.AccessNoAutomap) to $($username) Shared Mailbox without automapping" - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Gave full permissions to $($request.body.AccessNoAutomap) on $($username)" -Sev "Info" -tenant $TenantFilter - - } - catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Could not add mailbox permissions for $($request.body.AccessAutomap) on $($username)" -Sev "Error" -tenant $TenantFilter - - "Could not add shared mailbox permissions with no auto-mapping for $($username). Error: $($_.Exception.Message)" - } + Set-CIPPMailboxAccess -tenantFilter $tenantFilter -username $username -AccessUser $request.body.AccessNoAutomap -Automap $true -AccessRights @("FullAccess") -ExecutingUser $request.headers.'x-ms-client-principal' } { $_."AccessAutomap" -ne "" } { - try { - $permissions = New-ExoRequest -tenantid $TenantFilter -cmdlet "Add-MailboxPermission" -cmdParams @{Identity = $userid; user = $Request.body.AccessAutomap; automapping = $true; accessRights = @("FullAccess"); InheritanceType = "all" } -Anchor $username - "added $($Request.body.AccessAutomap) to $($username) Shared Mailbox with automapping" - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Gave full permissions to $($request.body.AccessAutomap) on $($username)" -Sev "Info" -tenant $TenantFilter - - } - catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Could not add mailbox permissions for $($request.body.AccessAutomap) on $($username)" -Sev "Error" -tenant $TenantFilter - - "Could not add shared mailbox permissions with automapping for $($username). Error: $($_.Exception.Message)" - } + Set-CIPPMailboxAccess -tenantFilter $tenantFilter -username $username -AccessUser $request.body.AccessNoAutomap -Automap $false -AccessRights @("FullAccess") -ExecutingUser $request.headers.'x-ms-client-principal' } { $_."OOO" -ne "" } { - try { - $permissions = New-ExoRequest -tenantid $TenantFilter -cmdlet "Set-MailboxAutoReplyConfiguration" -cmdParams @{Identity = $userid; AutoReplyState = "Enabled"; InternalMessage = $_."OOO"; ExternalMessage = $_."OOO" } -Anchor $username - "added Out-of-office to $username" - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Set Out-of-office for $($username)" -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)" - } + Set-CIPPOutOfOffice -tenantFilter $tenantFilter -userid $username -OOO $request.body.OOO -ExecutingUser $request.headers.'x-ms-client-principal' } { $_."forward" -ne "" } { - try { - $permissions = New-ExoRequest -tenantid $TenantFilter -cmdlet "Set-mailbox" -cmdParams @{Identity = $userid; ForwardingAddress = $_.forward ; DeliverToMailboxAndForward = [bool]$request.body.keepCopy } -Anchor $username - "Forwarding all email for $username to $($_.Forward)" - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Set Forwarding for $($username) to $($_.Forward)" -Sev "Info" -tenant $TenantFilter - - } - catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Could not add forwarding for $($username)" -Sev "Error" -tenant $TenantFilter - - "Could not add forwarding for $($username). Error: $($_.Exception.Message)" - } + Set-CIPPForwarding -userid $userid -username $username -tenantFilter $Tenantfilter -Forward $request.body.forward -KeepCopy [bool]$request.body.keepCopy -ExecutingUser $request.headers.'x-ms-client-principal' } { $_."RemoveLicenses" -eq 'true' } { - try { - if ($LicenseUnAssignAllowed -eq $false) { - "Could not remove license as the users mailbox is still being converted to a shared mailbox." - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Could not remove license as the users mailbox is still being converted to a shared mailbox" -Sev "Info" -tenant $TenantFilter - } - else { - $CurrentLicenses = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($userid)" -tenantid $tenantFilter).assignedlicenses.skuid - $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 - "Removed current licenses: $(($ConvertTable | Where-Object { $_.guid -in $CurrentLicenses }).'Product_Display_Name' -join ',')" - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Removed all licenses for $($username)" -Sev "Info" -tenant $TenantFilter - } - - } - catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Could not remove licenses for $($username)" -Sev "Error" -tenant $TenantFilter - - "Could not remove licenses for $($username). Error: $($_.Exception.Message)" - } + Remove-CIPPLicense -userid $userid -username $Username -tenantFilter $Tenantfilter -ExecutingUser $request.headers.'x-ms-client-principal' } { $_."Deleteuser" -eq 'true' } { - try { - $DeleteRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($userid)" -type DELETE -tenant $TenantFilter - "Deleted the user account" - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Deleted account $($username)" -Sev "Info" -tenant $TenantFilter - - } - catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Could not delete $($username)" -Sev "Error" -tenant $TenantFilter - "Could not delete $($username). Error: $($_.Exception.Message)" - } + Remove-CIPPUser -userid $userid -username $Username -tenantFilter $Tenantfilter -ExecutingUser $request.headers.'x-ms-client-principal' } { $_."RemoveRules" -eq 'true' } { - try { - $rules = New-ExoRequest -tenantid $TenantFilter -cmdlet "Get-InboxRule" -cmdParams @{mailbox = $userid } - if ($rules -eq $null) { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "No Rules for $($username) to delete" -Sev "Info" -tenant $TenantFilter - "No rules for $($username) to delete" - } - else { - ForEach ($rule in $rules) { - New-ExoRequest -tenantid $TenantFilter -cmdlet "Remove-InboxRule" -Anchor $username -cmdParams @{Identity = $rule.Identity } - } - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Deleted Rules for $($username)" -Sev "Info" -tenant $TenantFilter - "Deleted Rules for $($username)" - } - } - catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Could not delete rules for $($username): $($_.Exception.Message)" -Sev "Error" -tenant $TenantFilter - "Could not delete rules for $($username). Error: $($_.Exception.Message)" - } + Remove-CIPPRules -userid $userid -username $Username -tenantFilter $Tenantfilter -ExecutingUser $request.headers.'x-ms-client-principal' } { $_."RemoveMobile" -eq 'true' } { - try { - $devices = New-ExoRequest -tenantid $TenantFilter -cmdlet "Get-MobileDevice" -Anchor $username -cmdParams @{mailbox = $userid } | ForEach-Object { - try { - New-ExoRequest -tenantid $TenantFilter -cmdlet "Remove-MobileDevice" -Anchor $username -cmdParams @{Identity = $_.Identity } - "Removed device: $($_.FriendlyName)" - } - catch { - "Could not remove device: $($_.FriendlyName)" - continue - } - } - - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Deleted mobile devices for $($username)" -Sev "Info" -tenant $TenantFilter - - } - catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Could not delete mobile devices for $($username): $($_.Exception.Message)" -Sev "Error" -tenant $TenantFilter - "Could not delete mobile devices for $($username). Error: $($_.Exception.Message)" - } + Remove-CIPPMobileDevice -userid $userid -username $Username -tenantFilter $Tenantfilter -ExecutingUser $request.headers.'x-ms-client-principal' } } diff --git a/Modules/CIPPCore/Public/Set-CIPPForwarding.ps1 b/Modules/CIPPCore/Public/Set-CIPPForwarding.ps1 new file mode 100644 index 000000000000..e875579b7a3f --- /dev/null +++ b/Modules/CIPPCore/Public/Set-CIPPForwarding.ps1 @@ -0,0 +1,21 @@ +function Set-CIPPForwarding { + [CmdletBinding()] + param( + $userid, + $tenantFilter, + $username, + $ExecutingUser, + $Forward, + $KeepCopy + ) + + try { + $permissions = New-ExoRequest -tenantid $tenantFilter -cmdlet "Set-mailbox" -cmdParams @{Identity = $userid; ForwardingAddress = $Forward ; DeliverToMailboxAndForward = [bool]$KeepCopy } -Anchor $username + "Forwarding all email for $username to $Forward" + Write-LogMessage -user $ExecutingUser -API "Forwarding" -message "Set Forwarding for $($username) to $Forward" -Sev "Info" -tenant $TenantFilter + } + catch { + Write-LogMessage -user $ExecutingUser -API "Forwarding" -message "Could not add forwarding for $($username)" -Sev "Error" -tenant $TenantFilter + return "Could not add forwarding for $($username). Error: $($_.Exception.Message)" + } +} diff --git a/Modules/CIPPCore/Public/Set-CIPPSharedMailboxAccess.ps1 b/Modules/CIPPCore/Public/Set-CIPPMailboxAccess.ps1 similarity index 97% rename from Modules/CIPPCore/Public/Set-CIPPSharedMailboxAccess.ps1 rename to Modules/CIPPCore/Public/Set-CIPPMailboxAccess.ps1 index 29b4f70fe5bb..bdc851537e3b 100644 --- a/Modules/CIPPCore/Public/Set-CIPPSharedMailboxAccess.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPMailboxAccess.ps1 @@ -1,4 +1,4 @@ -function Set-CIPPSharedMailboxAccess { +function Set-CIPPMailboxAccess { [CmdletBinding()] param ( $userid, diff --git a/Modules/CIPPCore/Public/Set-CIPPMailboxType.ps1 b/Modules/CIPPCore/Public/Set-CIPPMailboxType.ps1 index b632e3f92a53..4c18aec459c3 100644 --- a/Modules/CIPPCore/Public/Set-CIPPMailboxType.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPMailboxType.ps1 @@ -4,7 +4,7 @@ function Set-CIPPMailboxType { $ExecutingUser, $userid, $username, - $TenantFlter, + $TenantFilter, [Parameter()] [ValidateSet('shared', 'Regular', 'Room', 'Equipment')]$MailboxType ) diff --git a/Modules/CIPPCore/Public/Set-CIPPOneDriveAccess.ps1 b/Modules/CIPPCore/Public/Set-CIPPOneDriveAccess.ps1 index e8f0ce1947ea..7543da2f4281 100644 --- a/Modules/CIPPCore/Public/Set-CIPPOneDriveAccess.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPOneDriveAccess.ps1 @@ -1,17 +1,17 @@ function Set-CIPPOnedriveAccess { - [CmdletBinding()] - param ( - $userid, - $OnedriveAccessUser, - $TenantFilter, - $ExecutingUser - ) + [CmdletBinding()] + param ( + $userid, + $OnedriveAccessUser, + $TenantFilter, + $ExecutingUser + ) - try { - $URL = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/reports/getOneDriveUsageAccountDetail(period='D7')?`$format=application/json" -tenantid $TenantFilter | Where-Object -Property 'OwnerPrincipalName' -EQ $userid).siteUrl - $OnMicrosoft = (New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/domains?$top=999' -tenantid $TenantFilter | Where-Object -Property isInitial -EQ $true).id.split('.') | Select-Object -First 1 - $AdminUrl = "https://$($OnMicrosoft)-admin.sharepoint.com" - $XML = @" + try { + $URL = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/reports/getOneDriveUsageAccountDetail(period='D7')?`$format=application/json" -tenantid $TenantFilter | Where-Object -Property 'OwnerPrincipalName' -EQ $userid).siteUrl + $OnMicrosoft = (New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/domains?$top=999' -tenantid $TenantFilter | Where-Object -Property isInitial -EQ $true).id.split('.') | Select-Object -First 1 + $AdminUrl = "https://$($OnMicrosoft)-admin.sharepoint.com" + $XML = @" @@ -28,12 +28,18 @@ function Set-CIPPOnedriveAccess { "@ - $request = New-GraphPostRequest -scope "$AdminURL/.default" -tenantid $TenantFilter -Uri "$AdminURL/_vti_bin/client.svc/ProcessQuery" -Type POST -Body $XML -ContentType 'text/xml' - Write-LogMessage -user $ExecutingUser -API "Manage OneDrive Access" -message "Gave $($OnedriveAccessUser) access to $($userid) OneDrive" -Sev "Info" -tenant $TenantFilter - return "User's OneDrive URL is $URL. Access has been given to $($OnedriveAccessUser)" + $request = New-GraphPostRequest -scope "$AdminURL/.default" -tenantid $TenantFilter -Uri "$AdminURL/_vti_bin/client.svc/ProcessQuery" -Type POST -Body $XML -ContentType 'text/xml' + if (!$request.ErrorInfo.ErrorMessage) { + Write-LogMessage -user $ExecutingUser -API "Manage OneDrive Access" -message "Gave $($OnedriveAccessUser) access to $($userid) OneDrive" -Sev "Info" -tenant $TenantFilter + return "User's OneDrive URL is $URL. Access has been given to $($OnedriveAccessUser)" } - catch { - Write-LogMessage -user $ExecutingUser -API "Manage OneDrive Access" -message "Could not add new owner to OneDrive $($OnedriveAccessUser) on $($userid)" -Sev "Error" -tenant $TenantFilter - return "Could not add owner to OneDrive for $($userid). Error: $($_.Exception.Message)" + else { + Write-LogMessage -user $ExecutingUser -API "Manage OneDrive Access" -message "Failed to give OneDrive Access: $($request.ErrorInfo.ErrorMessage)" -Sev "Info" -tenant $TenantFilter + return "Failed to give OneDrive Access: $($request.ErrorInfo.ErrorMessage)" } + } + catch { + Write-LogMessage -user $ExecutingUser -API "Manage OneDrive Access" -message "Could not add new owner to OneDrive $($OnedriveAccessUser) on $($userid)" -Sev "Error" -tenant $TenantFilter + return "Could not add owner to OneDrive for $($userid). Error: $($_.Exception.Message)" + } } From 17d4d560171027e7eed373639494310afe038bbb Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Tue, 4 Jul 2023 00:58:38 +0200 Subject: [PATCH 28/44] update --- LICENSE.CustomLicenses | 1 + 1 file changed, 1 insertion(+) create mode 100644 LICENSE.CustomLicenses diff --git a/LICENSE.CustomLicenses b/LICENSE.CustomLicenses new file mode 100644 index 000000000000..058ce0a6cd3b --- /dev/null +++ b/LICENSE.CustomLicenses @@ -0,0 +1 @@ +Custom licenses are available upon agreement via Github Sponsorships. Custom licenses will not ahve to be published in this repository. All contributors automatically agree with this provision. \ No newline at end of file From d76e24017af8ed656bdc678807ef3c4e08c2c84e Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Tue, 4 Jul 2023 01:00:20 +0200 Subject: [PATCH 29/44] fix offboard user --- ExecOffboardUser/run.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ExecOffboardUser/run.ps1 b/ExecOffboardUser/run.ps1 index f805b30dd042..b51cc1088e7c 100644 --- a/ExecOffboardUser/run.ps1 +++ b/ExecOffboardUser/run.ps1 @@ -14,7 +14,7 @@ try { Write-Host ($request.body | ConvertTo-Json) $results = switch ($request.body) { { $_."ConvertToShared" -eq 'true' } { - Set-CIPPMailboxType -ExecutingUser $request.headers.'x-ms-client-principal' -tenantFilter $tenantFilter -userid $username -MailboxType "Shared" + Set-CIPPMailboxType -ExecutingUser $request.headers.'x-ms-client-principal' -tenantFilter $tenantFilter -userid $username -username $username -MailboxType "Shared" } { $_.RevokeSessions -eq 'true' } { Revoke-CIPPSessions -tenantFilter $tenantFilter -username $username -userid $userid -ExecutingUser $request.headers.'x-ms-client-principal' From 28a0ed3195b16c431ad4a3bd52dfefd9850ea315 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Tue, 4 Jul 2023 01:04:38 +0200 Subject: [PATCH 30/44] upped version --- version_latest.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version_latest.txt b/version_latest.txt index d1428a7e96ac..240bba90696a 100644 --- a/version_latest.txt +++ b/version_latest.txt @@ -1 +1 @@ -3.6.1 \ No newline at end of file +3.7.0 \ No newline at end of file From 91e2a89bc538e996e629391c0b6d64853044b2d6 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Tue, 4 Jul 2023 01:25:28 +0200 Subject: [PATCH 31/44] UserID --- ExecOffboardUser/run.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ExecOffboardUser/run.ps1 b/ExecOffboardUser/run.ps1 index b51cc1088e7c..f4d76fc53513 100644 --- a/ExecOffboardUser/run.ps1 +++ b/ExecOffboardUser/run.ps1 @@ -37,10 +37,10 @@ try { Set-CIPPOnedriveAccess -tenantFilter $tenantFilter -userid $username -OnedriveAccessUser $request.body.OnedriveAccess -ExecutingUser $request.headers.'x-ms-client-principal' } { $_."AccessNoAutomap" -ne "" } { - Set-CIPPMailboxAccess -tenantFilter $tenantFilter -username $username -AccessUser $request.body.AccessNoAutomap -Automap $true -AccessRights @("FullAccess") -ExecutingUser $request.headers.'x-ms-client-principal' + Set-CIPPMailboxAccess -tenantFilter $tenantFilter -userid $username -AccessUser $request.body.AccessNoAutomap -Automap $true -AccessRights @("FullAccess") -ExecutingUser $request.headers.'x-ms-client-principal' } { $_."AccessAutomap" -ne "" } { - Set-CIPPMailboxAccess -tenantFilter $tenantFilter -username $username -AccessUser $request.body.AccessNoAutomap -Automap $false -AccessRights @("FullAccess") -ExecutingUser $request.headers.'x-ms-client-principal' + Set-CIPPMailboxAccess -tenantFilter $tenantFilter -userid $username -AccessUser $request.body.AccessNoAutomap -Automap $false -AccessRights @("FullAccess") -ExecutingUser $request.headers.'x-ms-client-principal' } { $_."OOO" -ne "" } { From 5e31b28c5f5165e642c4e8d47e35847769a7c92b Mon Sep 17 00:00:00 2001 From: BNWEIN Date: Tue, 4 Jul 2023 09:24:12 +0100 Subject: [PATCH 32/44] Fixed Offboarding Logging Fixed Offboarding Logging --- ExecOffboardUser/run.ps1 | 30 +++++++++---------- Modules/CIPPCore/Public/Remove-CIPPGroups.ps1 | 5 ++-- .../CIPPCore/Public/Remove-CIPPLicense.ps1 | 5 ++-- .../Public/Remove-CIPPMobileDevice.ps1 | 5 ++-- Modules/CIPPCore/Public/Remove-CIPPRules.ps1 | 7 +++-- Modules/CIPPCore/Public/Remove-CIPPUser.ps1 | 5 ++-- .../CIPPCore/Public/Revoke-CIPPSessions.ps1 | 5 ++-- .../CIPPCore/Public/Set-CIPPForwarding.ps1 | 5 ++-- .../CIPPCore/Public/Set-CIPPHideFromGAL.ps1 | 5 ++-- .../CIPPCore/Public/Set-CIPPMailboxAccess.ps1 | 7 +++-- .../CIPPCore/Public/Set-CIPPMailboxType.ps1 | 5 ++-- .../Public/Set-CIPPOneDriveAccess.ps1 | 7 +++-- .../CIPPCore/Public/Set-CIPPOutOfoffice.ps1 | 5 ++-- .../CIPPCore/Public/Set-CIPPResetPassword.ps1 | 5 ++-- .../CIPPCore/Public/Set-CIPPSignInState.ps1 | 5 ++-- 15 files changed, 60 insertions(+), 46 deletions(-) diff --git a/ExecOffboardUser/run.ps1 b/ExecOffboardUser/run.ps1 index f4d76fc53513..8a78bd45e49c 100644 --- a/ExecOffboardUser/run.ps1 +++ b/ExecOffboardUser/run.ps1 @@ -14,55 +14,55 @@ try { Write-Host ($request.body | ConvertTo-Json) $results = switch ($request.body) { { $_."ConvertToShared" -eq 'true' } { - Set-CIPPMailboxType -ExecutingUser $request.headers.'x-ms-client-principal' -tenantFilter $tenantFilter -userid $username -username $username -MailboxType "Shared" + Set-CIPPMailboxType -ExecutingUser $request.headers.'x-ms-client-principal' -tenantFilter $tenantFilter -userid $username -username $username -MailboxType "Shared" -APIName "ExecOffboardUser" } { $_.RevokeSessions -eq 'true' } { - Revoke-CIPPSessions -tenantFilter $tenantFilter -username $username -userid $userid -ExecutingUser $request.headers.'x-ms-client-principal' + Revoke-CIPPSessions -tenantFilter $tenantFilter -username $username -userid $userid -ExecutingUser $request.headers.'x-ms-client-principal' -APIName "ExecOffboardUser" } { $_.ResetPass -eq 'true' } { - Set-CIPPResetPassword -tenantFilter $tenantFilter -userid $username -ExecutingUser $request.headers.'x-ms-client-principal' + Set-CIPPResetPassword -tenantFilter $tenantFilter -userid $username -ExecutingUser $request.headers.'x-ms-client-principal' -APIName "ExecOffboardUser" } { $_.RemoveGroups -eq 'true' } { - Remove-CIPPGroups -userid $userid -tenantFilter $Tenantfilter -ExecutingUser $request.headers.'x-ms-client-principal' + Remove-CIPPGroups -userid $userid -tenantFilter $Tenantfilter -ExecutingUser $request.headers.'x-ms-client-principal' -APIName "ExecOffboardUser" } { $_."HideFromGAL" -eq 'true' } { - Set-CIPPHideFromGAL -tenantFilter $tenantFilter -userid $username -HideFromGAL $true -ExecutingUser $request.headers.'x-ms-client-principal' + Set-CIPPHideFromGAL -tenantFilter $tenantFilter -userid $username -HideFromGAL $true -ExecutingUser $request.headers.'x-ms-client-principal' -APIName "ExecOffboardUser" } { $_."DisableSignIn" -eq 'true' } { - Set-CIPPSignInState -TenantFilter $tenantFilter -userid $username -AccountEnabled $false -ExecutingUser $request.headers.'x-ms-client-principal' + Set-CIPPSignInState -TenantFilter $tenantFilter -userid $username -AccountEnabled $false -ExecutingUser $request.headers.'x-ms-client-principal' -APIName "ExecOffboardUser" } { $_."OnedriveAccess" -ne "" } { - Set-CIPPOnedriveAccess -tenantFilter $tenantFilter -userid $username -OnedriveAccessUser $request.body.OnedriveAccess -ExecutingUser $request.headers.'x-ms-client-principal' + Set-CIPPOnedriveAccess -tenantFilter $tenantFilter -userid $username -OnedriveAccessUser $request.body.OnedriveAccess -ExecutingUser $request.headers.'x-ms-client-principal' -APIName "ExecOffboardUser" } { $_."AccessNoAutomap" -ne "" } { - Set-CIPPMailboxAccess -tenantFilter $tenantFilter -userid $username -AccessUser $request.body.AccessNoAutomap -Automap $true -AccessRights @("FullAccess") -ExecutingUser $request.headers.'x-ms-client-principal' + Set-CIPPMailboxAccess -tenantFilter $tenantFilter -userid $username -AccessUser $request.body.AccessNoAutomap -Automap $true -AccessRights @("FullAccess") -ExecutingUser $request.headers.'x-ms-client-principal' -APIName "ExecOffboardUser" } { $_."AccessAutomap" -ne "" } { - Set-CIPPMailboxAccess -tenantFilter $tenantFilter -userid $username -AccessUser $request.body.AccessNoAutomap -Automap $false -AccessRights @("FullAccess") -ExecutingUser $request.headers.'x-ms-client-principal' + Set-CIPPMailboxAccess -tenantFilter $tenantFilter -userid $username -AccessUser $request.body.AccessNoAutomap -Automap $false -AccessRights @("FullAccess") -ExecutingUser $request.headers.'x-ms-client-principal' -APIName "ExecOffboardUser" } { $_."OOO" -ne "" } { - Set-CIPPOutOfOffice -tenantFilter $tenantFilter -userid $username -OOO $request.body.OOO -ExecutingUser $request.headers.'x-ms-client-principal' + Set-CIPPOutOfOffice -tenantFilter $tenantFilter -userid $username -OOO $request.body.OOO -ExecutingUser $request.headers.'x-ms-client-principal' -APIName "ExecOffboardUser" } { $_."forward" -ne "" } { - Set-CIPPForwarding -userid $userid -username $username -tenantFilter $Tenantfilter -Forward $request.body.forward -KeepCopy [bool]$request.body.keepCopy -ExecutingUser $request.headers.'x-ms-client-principal' + Set-CIPPForwarding -userid $userid -username $username -tenantFilter $Tenantfilter -Forward $request.body.forward -KeepCopy [bool]$request.body.keepCopy -ExecutingUser $request.headers.'x-ms-client-principal' -APIName "ExecOffboardUser" } { $_."RemoveLicenses" -eq 'true' } { - Remove-CIPPLicense -userid $userid -username $Username -tenantFilter $Tenantfilter -ExecutingUser $request.headers.'x-ms-client-principal' + Remove-CIPPLicense -userid $userid -username $Username -tenantFilter $Tenantfilter -ExecutingUser $request.headers.'x-ms-client-principal' -APIName "ExecOffboardUser" } { $_."Deleteuser" -eq 'true' } { - Remove-CIPPUser -userid $userid -username $Username -tenantFilter $Tenantfilter -ExecutingUser $request.headers.'x-ms-client-principal' + Remove-CIPPUser -userid $userid -username $Username -tenantFilter $Tenantfilter -ExecutingUser $request.headers.'x-ms-client-principal' -APIName "ExecOffboardUser" } { $_."RemoveRules" -eq 'true' } { - Remove-CIPPRules -userid $userid -username $Username -tenantFilter $Tenantfilter -ExecutingUser $request.headers.'x-ms-client-principal' + Remove-CIPPRules -userid $userid -username $Username -tenantFilter $Tenantfilter -ExecutingUser $request.headers.'x-ms-client-principal' -APIName "ExecOffboardUser" } { $_."RemoveMobile" -eq 'true' } { - Remove-CIPPMobileDevice -userid $userid -username $Username -tenantFilter $Tenantfilter -ExecutingUser $request.headers.'x-ms-client-principal' + Remove-CIPPMobileDevice -userid $userid -username $Username -tenantFilter $Tenantfilter -ExecutingUser $request.headers.'x-ms-client-principal' -APIName "ExecOffboardUser" } } diff --git a/Modules/CIPPCore/Public/Remove-CIPPGroups.ps1 b/Modules/CIPPCore/Public/Remove-CIPPGroups.ps1 index e55ff5fe0792..26a3961b9d74 100644 --- a/Modules/CIPPCore/Public/Remove-CIPPGroups.ps1 +++ b/Modules/CIPPCore/Public/Remove-CIPPGroups.ps1 @@ -3,6 +3,7 @@ function Remove-CIPPGroups { param( $userid, $tenantFilter, + $APIName = "Remove From Groups", $ExecutingUser ) @@ -28,11 +29,11 @@ function Remove-CIPPGroups { New-ExoRequest -tenantid $using:tenantFilter -cmdlet "Remove-DistributionGroupMember" -cmdParams $params -UseSystemMailbox $true } - Write-LogMessage -user $using:ExecutingUser -API "Remove From Groups" -message "Removed $($using:userid) from $groupname" -Sev "Info" -tenant $using:TenantFilter + Write-LogMessage -user $using:ExecutingUser -API $($using:APIName) -message "Removed $($using:userid) from $groupname" -Sev "Info" -tenant $using:TenantFilter return "Successfully removed user from group $Groupname" } catch { - Write-LogMessage -user $using:ExecutingUser -API "Remove From Groups" -message "Could not remove $($using:userid) from group $groupname" -Sev "Error" -tenant $using:TenantFilter + Write-LogMessage -user $using:ExecutingUser -API $($using:APIName) -message "Could not remove $($using:userid) from group $groupname" -Sev "Error" -tenant $using:TenantFilter return "Could not remove user 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 221b39470dff..a0c8ae94091c 100644 --- a/Modules/CIPPCore/Public/Remove-CIPPLicense.ps1 +++ b/Modules/CIPPCore/Public/Remove-CIPPLicense.ps1 @@ -4,6 +4,7 @@ function Remove-CIPPLicense { $ExecutingUser, $userid, $username, + $APIName = "Remove License", $TenantFilter ) @@ -12,12 +13,12 @@ function Remove-CIPPLicense { $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 "Remove License" -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: $(($ConvertTable | Where-Object { $_.guid -in $CurrentLicenses }).'Product_Display_Name' -join ',')" } catch { - Write-LogMessage -user $ExecutingUser -API "Remove License" -message "Could not remove license for $username" -Sev "Error" -tenant $TenantFilter + 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-CIPPMobileDevice.ps1 b/Modules/CIPPCore/Public/Remove-CIPPMobileDevice.ps1 index a5e173097279..78625e367fbd 100644 --- a/Modules/CIPPCore/Public/Remove-CIPPMobileDevice.ps1 +++ b/Modules/CIPPCore/Public/Remove-CIPPMobileDevice.ps1 @@ -4,6 +4,7 @@ function Remove-CIPPMobileDevice { $userid, $tenantFilter, $username, + $APIName = "Remove Mobile", $ExecutingUser ) @@ -19,10 +20,10 @@ function Remove-CIPPMobileDevice { } } - Write-LogMessage -user $ExecutingUser -API "Remove Mobile" -message "Deleted mobile devices for $($username)" -Sev "Info" -tenant $tenantFilter + Write-LogMessage -user $ExecutingUser -API $APIName -message "Deleted mobile devices for $($username)" -Sev "Info" -tenant $tenantFilter } catch { - Write-LogMessage -user $ExecutingUser -API "Remove Mobile" -message "Could not delete mobile devices for $($username): $($_.Exception.Message)" -Sev "Error" -tenant $tenantFilter + 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/Remove-CIPPRules.ps1 b/Modules/CIPPCore/Public/Remove-CIPPRules.ps1 index 41c6858bf29a..207e122fac47 100644 --- a/Modules/CIPPCore/Public/Remove-CIPPRules.ps1 +++ b/Modules/CIPPCore/Public/Remove-CIPPRules.ps1 @@ -4,25 +4,26 @@ function Remove-CIPPRules { $userid, $username, $TenantFilter, + $APIName = "Rules Removal", $ExecutingUser ) try { $rules = New-ExoRequest -tenantid $TenantFilter -cmdlet "Get-InboxRule" -cmdParams @{mailbox = $userid } if ($rules -eq $null) { - Write-LogMessage -user $ExecutingUser -API "Rules Removal" -message "No Rules for $($userid) to delete" -Sev "Info" -tenant $TenantFilter + Write-LogMessage -user $ExecutingUser -API $APIName -message "No Rules for $($userid) to delete" -Sev "Info" -tenant $TenantFilter return "No rules for $($userid) to delete" } else { ForEach ($rule in $rules) { New-ExoRequest -tenantid $TenantFilter -cmdlet "Remove-InboxRule" -Anchor $userid -cmdParams @{Identity = $rule.Identity } } - Write-LogMessage -user $ExecutingUser -API "Rules Removal" -message "Deleted Rules for $($userid)" -Sev "Info" -tenant $TenantFilter + Write-LogMessage -user $ExecutingUser -API $APIName -message "Deleted Rules for $($userid)" -Sev "Info" -tenant $TenantFilter return "Deleted Rules for $($userid)" } } catch { - Write-LogMessage -user $ExecutingUser -API "Rules Removal" -message "Could not delete rules for $($userid): $($_.Exception.Message)" -Sev "Error" -tenant $TenantFilter + Write-LogMessage -user $ExecutingUser -API $APIName -message "Could not delete rules for $($userid): $($_.Exception.Message)" -Sev "Error" -tenant $TenantFilter return "Could not delete rules for $($userid). Error: $($_.Exception.Message)" } } diff --git a/Modules/CIPPCore/Public/Remove-CIPPUser.ps1 b/Modules/CIPPCore/Public/Remove-CIPPUser.ps1 index c9b5ee477e16..788a4e3332d3 100644 --- a/Modules/CIPPCore/Public/Remove-CIPPUser.ps1 +++ b/Modules/CIPPCore/Public/Remove-CIPPUser.ps1 @@ -4,17 +4,18 @@ function Remove-CIPPUser { $ExecutingUser, $userid, $username, + $APIName = "Remove User", $TenantFilter ) try { $DeleteRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($userid)" -type DELETE -tenant $TenantFilter - Write-LogMessage -user $ExecutingUser, -API "Remove User" -message "Deleted account $username" -Sev "Info" -tenant $TenantFilter + Write-LogMessage -user $ExecutingUser, -API $APIName -message "Deleted account $username" -Sev "Info" -tenant $TenantFilter return "Deleted the user account $username" } catch { - Write-LogMessage -user $ExecutingUser, -API "Remove User" -message "Could not delete $username" -Sev "Error" -tenant $TenantFilter + Write-LogMessage -user $ExecutingUser, -API $APIName -message "Could not delete $username" -Sev "Error" -tenant $TenantFilter return "Could not delete $username. Error: $($_.Exception.Message)" } } diff --git a/Modules/CIPPCore/Public/Revoke-CIPPSessions.ps1 b/Modules/CIPPCore/Public/Revoke-CIPPSessions.ps1 index 700aa58c9fad..6ee7b05d5686 100644 --- a/Modules/CIPPCore/Public/Revoke-CIPPSessions.ps1 +++ b/Modules/CIPPCore/Public/Revoke-CIPPSessions.ps1 @@ -4,17 +4,18 @@ function Revoke-CIPPSessions { $ExecutingUser, $userid, $username, + $APIName = "Revoke Sessions", $TenantFilter ) try { $GraphRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($userid)/invalidateAllRefreshTokens" -tenantid $TenantFilter -type POST -body '{}' -verbose - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API "Revoke Sessions" -message "Revoked sessions for $($username)" -Sev "Info" -tenant $TenantFilter + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APIName -message "Revoked sessions for $($username)" -Sev "Info" -tenant $TenantFilter return "Success. All sessions by $username have been revoked" } catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API "Revoke Sessions" -message "Revoked sessions for $($username)" -Sev "Info" -tenant $TenantFilter + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APIName -message "Revoked sessions for $($username)" -Sev "Info" -tenant $TenantFilter return "Revoke Session Failed: $($_.Exception.Message)" } } diff --git a/Modules/CIPPCore/Public/Set-CIPPForwarding.ps1 b/Modules/CIPPCore/Public/Set-CIPPForwarding.ps1 index e875579b7a3f..909240cdd596 100644 --- a/Modules/CIPPCore/Public/Set-CIPPForwarding.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPForwarding.ps1 @@ -5,6 +5,7 @@ function Set-CIPPForwarding { $tenantFilter, $username, $ExecutingUser, + $APIName = "Forwarding", $Forward, $KeepCopy ) @@ -12,10 +13,10 @@ function Set-CIPPForwarding { try { $permissions = New-ExoRequest -tenantid $tenantFilter -cmdlet "Set-mailbox" -cmdParams @{Identity = $userid; ForwardingAddress = $Forward ; DeliverToMailboxAndForward = [bool]$KeepCopy } -Anchor $username "Forwarding all email for $username to $Forward" - Write-LogMessage -user $ExecutingUser -API "Forwarding" -message "Set Forwarding for $($username) to $Forward" -Sev "Info" -tenant $TenantFilter + Write-LogMessage -user $ExecutingUser -API $APIName -message "Set Forwarding for $($username) to $Forward" -Sev "Info" -tenant $TenantFilter } catch { - Write-LogMessage -user $ExecutingUser -API "Forwarding" -message "Could not add forwarding for $($username)" -Sev "Error" -tenant $TenantFilter + Write-LogMessage -user $ExecutingUser -API $APIName -message "Could not add forwarding for $($username)" -Sev "Error" -tenant $TenantFilter return "Could not add forwarding for $($username). Error: $($_.Exception.Message)" } } diff --git a/Modules/CIPPCore/Public/Set-CIPPHideFromGAL.ps1 b/Modules/CIPPCore/Public/Set-CIPPHideFromGAL.ps1 index 801425b60574..601288f97dd4 100644 --- a/Modules/CIPPCore/Public/Set-CIPPHideFromGAL.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPHideFromGAL.ps1 @@ -3,6 +3,7 @@ function Set-CIPPHideFromGAL { param ( $userid, $tenantFilter, + $APIName = "Hide From Address List", [bool]$HideFromGAL, $ExecutingUser ) @@ -12,11 +13,11 @@ function Set-CIPPHideFromGAL { showInAddressList = [bool]$HideFromGAL } | ConvertTo-Json -Compress -Depth 1 $HideRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/v1.0/users/$($userid)" -tenantid $tenantFilter -type PATCH -body $body -verbose - Write-LogMessage -user $ExecutingUser -API "Hide From Address List" -message "Hid $($userid) from address list" -Sev "Info" -tenant $TenantFilter + Write-LogMessage -user $ExecutingUser -API $APIName -message "Hid $($userid) from address list" -Sev "Info" -tenant $TenantFilter return "Hidden $($userid) from address list" } catch { - Write-LogMessage -user $ExecutingUser -API "Hide From Address List" -message "Could not hide $($userid) from address list" -Sev "Error" -tenant $TenantFilter + Write-LogMessage -user $ExecutingUser -API $APIName -message "Could not hide $($userid) from address list" -Sev "Error" -tenant $TenantFilter return "Could not hide $($userid) from address list. Error: $($_.Exception.Message)" } } diff --git a/Modules/CIPPCore/Public/Set-CIPPMailboxAccess.ps1 b/Modules/CIPPCore/Public/Set-CIPPMailboxAccess.ps1 index bdc851537e3b..f19762545ac1 100644 --- a/Modules/CIPPCore/Public/Set-CIPPMailboxAccess.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPMailboxAccess.ps1 @@ -5,6 +5,7 @@ function Set-CIPPMailboxAccess { $AccessUser, [bool]$Automap, $TenantFilter, + $APIName = "Manage Shared Mailbox Access", $ExecutingUser, [array]$AccessRights ) @@ -13,16 +14,16 @@ function Set-CIPPMailboxAccess { $permissions = New-ExoRequest -tenantid $TenantFilter -cmdlet "Add-MailboxPermission" -cmdParams @{Identity = $userid; user = $AccessUser; automapping = $Automap; accessRights = $AccessRights; InheritanceType = "all" } -Anchor $userid if ($Automap) { - Write-LogMessage -user $ExecutingUser -API "Manage Shared Mailbox Access" -message "Gave $AccessRights permissions to $($AccessUser) on $($userid) with automapping" -Sev "Info" -tenant $TenantFilter + Write-LogMessage -user $ExecutingUser -API $APIName -message "Gave $AccessRights permissions to $($AccessUser) on $($userid) with automapping" -Sev "Info" -tenant $TenantFilter return "added $($AccessUser) to $($userid) Shared Mailbox with automapping, with the following permissions: $AccessRights" } else { - Write-LogMessage -user $ExecutingUser -API "Manage Shared Mailbox Access" -message "Gave $AccessRights permissions to $($AccessUser) on $($userid) without automapping" -Sev "Info" -tenant $TenantFilter + Write-LogMessage -user $ExecutingUser -API $APIName -message "Gave $AccessRights permissions to $($AccessUser) on $($userid) without automapping" -Sev "Info" -tenant $TenantFilter return "added $($AccessUser) to $($userid) Shared Mailbox without automapping, with the following permissions: $AccessRights" } } catch { - Write-LogMessage -user $ExecutingUser -API "Manage Shared Mailbox Access" -message "Could not add mailbox permissions for $($AccessUser) on $($userid)" -Sev "Error" -tenant $TenantFilter + Write-LogMessage -user $ExecutingUser -API $APIName -message "Could not add mailbox permissions for $($AccessUser) on $($userid)" -Sev "Error" -tenant $TenantFilter return "Could not add shared mailbox permissions for $($userid). Error: $($_.Exception.Message)" } } diff --git a/Modules/CIPPCore/Public/Set-CIPPMailboxType.ps1 b/Modules/CIPPCore/Public/Set-CIPPMailboxType.ps1 index 4c18aec459c3..e559c4557711 100644 --- a/Modules/CIPPCore/Public/Set-CIPPMailboxType.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPMailboxType.ps1 @@ -4,6 +4,7 @@ function Set-CIPPMailboxType { $ExecutingUser, $userid, $username, + $APIName = "Mailbox Conversion", $TenantFilter, [Parameter()] [ValidateSet('shared', 'Regular', 'Room', 'Equipment')]$MailboxType @@ -11,11 +12,11 @@ function Set-CIPPMailboxType { try { $Mailbox = New-ExoRequest -tenantid $TenantFilter -cmdlet "Set-mailbox" -cmdParams @{Identity = $userid; type = $MailboxType } -Anchor $username - Write-LogMessage -user $ExecutingUser -API "Mailbox Conversion" -message "Converted $($username) to a $MailboxType mailbox" -Sev "Info" -tenant $TenantFilter + Write-LogMessage -user $ExecutingUser -API $APIName -message "Converted $($username) to a $MailboxType mailbox" -Sev "Info" -tenant $TenantFilter return "Converted $($username) to a $MailboxType mailbox" } catch { - Write-LogMessage -user $ExecutingUser -API "Mailbox Conversion" -message "Could not convert $username to $MailboxType mailbox" -Sev "Error" -tenant $TenantFilter + Write-LogMessage -user $ExecutingUser -API $APIName -message "Could not convert $username to $MailboxType mailbox" -Sev "Error" -tenant $TenantFilter return "Could not convert $($username) to a $MailboxType mailbox. Error: $($_.Exception.Message)" } } diff --git a/Modules/CIPPCore/Public/Set-CIPPOneDriveAccess.ps1 b/Modules/CIPPCore/Public/Set-CIPPOneDriveAccess.ps1 index 7543da2f4281..a576f0b8257c 100644 --- a/Modules/CIPPCore/Public/Set-CIPPOneDriveAccess.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPOneDriveAccess.ps1 @@ -4,6 +4,7 @@ function Set-CIPPOnedriveAccess { $userid, $OnedriveAccessUser, $TenantFilter, + $APIName = "Manage OneDrive Access", $ExecutingUser ) @@ -30,16 +31,16 @@ function Set-CIPPOnedriveAccess { "@ $request = New-GraphPostRequest -scope "$AdminURL/.default" -tenantid $TenantFilter -Uri "$AdminURL/_vti_bin/client.svc/ProcessQuery" -Type POST -Body $XML -ContentType 'text/xml' if (!$request.ErrorInfo.ErrorMessage) { - Write-LogMessage -user $ExecutingUser -API "Manage OneDrive Access" -message "Gave $($OnedriveAccessUser) access to $($userid) OneDrive" -Sev "Info" -tenant $TenantFilter + Write-LogMessage -user $ExecutingUser -API $APIName -message "Gave $($OnedriveAccessUser) access to $($userid) OneDrive" -Sev "Info" -tenant $TenantFilter return "User's OneDrive URL is $URL. Access has been given to $($OnedriveAccessUser)" } else { - Write-LogMessage -user $ExecutingUser -API "Manage OneDrive Access" -message "Failed to give OneDrive Access: $($request.ErrorInfo.ErrorMessage)" -Sev "Info" -tenant $TenantFilter + Write-LogMessage -user $ExecutingUser -API $APIName -message "Failed to give OneDrive Access: $($request.ErrorInfo.ErrorMessage)" -Sev "Info" -tenant $TenantFilter return "Failed to give OneDrive Access: $($request.ErrorInfo.ErrorMessage)" } } catch { - Write-LogMessage -user $ExecutingUser -API "Manage OneDrive Access" -message "Could not add new owner to OneDrive $($OnedriveAccessUser) on $($userid)" -Sev "Error" -tenant $TenantFilter + Write-LogMessage -user $ExecutingUser -API $APIName -message "Could not add new owner to OneDrive $($OnedriveAccessUser) on $($userid)" -Sev "Error" -tenant $TenantFilter return "Could not add owner to OneDrive for $($userid). Error: $($_.Exception.Message)" } } diff --git a/Modules/CIPPCore/Public/Set-CIPPOutOfoffice.ps1 b/Modules/CIPPCore/Public/Set-CIPPOutOfoffice.ps1 index 018b3a921f7a..5413ec5261e9 100644 --- a/Modules/CIPPCore/Public/Set-CIPPOutOfoffice.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPOutOfoffice.ps1 @@ -4,16 +4,17 @@ function Set-CIPPOutOfOffice { $userid, $OOO, $TenantFilter, + $APIName = "Set Out of Office", $ExecutingUser ) try { $permissions = New-ExoRequest -tenantid $TenantFilter -cmdlet "Set-MailboxAutoReplyConfiguration" -cmdParams @{Identity = $userid; AutoReplyState = "Enabled"; InternalMessage = $OOO; ExternalMessage = $OOO } -Anchor $userid - Write-LogMessage -user $ExecutingUser -API "Set Out of Office" -message "Set Out-of-office for $($userid)" -Sev "Info" -tenant $TenantFilter + Write-LogMessage -user $ExecutingUser -API $APIName -message "Set Out-of-office for $($userid)" -Sev "Info" -tenant $TenantFilter return "added Out-of-office to $($userid)" } catch { - Write-LogMessage -user $ExecutingUser -API "Set Out of Office" -message "Could not add OOO for $($userid)" -Sev "Error" -tenant $TenantFilter + Write-LogMessage -user $ExecutingUser -API $APIName -message "Could not add OOO for $($userid)" -Sev "Error" -tenant $TenantFilter return "Could not add out of office message for $($userid). Error: $($_.Exception.Message)" } } diff --git a/Modules/CIPPCore/Public/Set-CIPPResetPassword.ps1 b/Modules/CIPPCore/Public/Set-CIPPResetPassword.ps1 index 440d66d6d55b..1d9c06c2d859 100644 --- a/Modules/CIPPCore/Public/Set-CIPPResetPassword.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPResetPassword.ps1 @@ -3,6 +3,7 @@ function Set-CIPPResetPassword { param( $userid, $tenantFilter, + $APIName = "Reset Password", $ExecutingUser, [bool]$forceChangePasswordNextSignIn = $true ) @@ -18,11 +19,11 @@ function Set-CIPPResetPassword { $GraphRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/v1.0/users/$($userid)" -tenantid $TenantFilter -type PATCH -body $passwordProfile -verbose - Write-LogMessage -user $ExecutingUser -API "Reset Password" -message "Reset the password for $($userid)" -Sev "Info" -tenant $TenantFilter + Write-LogMessage -user $ExecutingUser -API $APIName -message "Reset the password for $($userid)" -Sev "Info" -tenant $TenantFilter return "The new password is $password" } catch { - Write-LogMessage -user $ExecutingUser -API "Reset Password" -message "Could not reset password for $($userid)" -Sev "Error" -tenant $TenantFilter + Write-LogMessage -user $ExecutingUser -API $APIName -message "Could not reset password for $($userid)" -Sev "Error" -tenant $TenantFilter return "Could not reset password for $($userid). Error: $($_.Exception.Message)" } } diff --git a/Modules/CIPPCore/Public/Set-CIPPSignInState.ps1 b/Modules/CIPPCore/Public/Set-CIPPSignInState.ps1 index 2493563e5902..bc45d8588979 100644 --- a/Modules/CIPPCore/Public/Set-CIPPSignInState.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPSignInState.ps1 @@ -4,6 +4,7 @@ function Set-CIPPSignInState { $userid, [bool]$AccountEnabled, $TenantFilter, + $APIName = "Disable User Sign-in", $ExecutingUser ) @@ -12,11 +13,11 @@ function Set-CIPPSignInState { accountEnabled = [bool]$AccountEnabled } | ConvertTo-Json -Compress -Depth 1 $SignInState = New-GraphPostRequest -uri "https://graph.microsoft.com/v1.0/users/$($userid)" -tenantid $TenantFilter -type PATCH -body $body -verbose - Write-LogMessage -user $ExecutingUser -API "Disable User Sign-in" -message "Disabled $($userid)" -Sev "Info" -tenant $TenantFilter + Write-LogMessage -user $ExecutingUser -API $APIName -message "Disabled $($userid)" -Sev "Info" -tenant $TenantFilter return "Disabled user account for $userid" } catch { - Write-LogMessage -user $ExecutingUser -API "Disable User Sign-in" -message "Could not disable sign in for $($userid)" -Sev "Error" -tenant $TenantFilter + Write-LogMessage -user $ExecutingUser -API $APIName -message "Could not disable sign in for $($userid)" -Sev "Error" -tenant $TenantFilter return "Could not disable $($userid). Error: $($_.Exception.Message)" } } From 08b5c9a45cda63aa41e5c597d6814220514e7c6c Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Tue, 4 Jul 2023 10:31:43 +0200 Subject: [PATCH 33/44] text update for docs --- Cache_SAMSetup/PermissionsTranslator.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cache_SAMSetup/PermissionsTranslator.json b/Cache_SAMSetup/PermissionsTranslator.json index 7d55a10a9a31..f7ce2cf3235a 100644 --- a/Cache_SAMSetup/PermissionsTranslator.json +++ b/Cache_SAMSetup/PermissionsTranslator.json @@ -1,9 +1,9 @@ [ { "description": "Allows Exchange Management as app", - "displayName": "Manage Exchange As Application", + "displayName": "Manage Exchange As Application ", "id": "dc50a0fb-09a3-484d-be87-e023b12c6440", - "origin": "Application", + "origin": "Application (Office 365 Exchange Online)", "value": "Exchange.ManageAsApp" }, { From 85c86fc80d7d130e830fa01cff3d82667651bab0 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Tue, 4 Jul 2023 10:34:54 +0200 Subject: [PATCH 34/44] offboarding update --- version_latest.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version_latest.txt b/version_latest.txt index 240bba90696a..5cdb444f3d41 100644 --- a/version_latest.txt +++ b/version_latest.txt @@ -1 +1 @@ -3.7.0 \ No newline at end of file +3.7.1 \ No newline at end of file From ae5241cba9027cd78d5d899693400d9a4904de4f Mon Sep 17 00:00:00 2001 From: Ashley Cooper <122837620+ashley-mspgeek@users.noreply.github.com> Date: Tue, 4 Jul 2023 16:13:24 -0400 Subject: [PATCH 35/44] added functions for add/list/remove functions for scheduler. --- AddScheduledItems/function.json | 19 +++++++++++++++++++ AddScheduledItems/run.ps1 | 18 ++++++++++++++++++ ListScheduledItems/junction.json | 19 +++++++++++++++++++ ListScheduledItems/run.ps1 | 15 +++++++++++++++ RemoveScheduledItems/function.json | 19 +++++++++++++++++++ RemoveScheduledItems/run.ps1 | 11 +++++++++++ 6 files changed, 101 insertions(+) create mode 100644 AddScheduledItems/function.json create mode 100644 AddScheduledItems/run.ps1 create mode 100644 ListScheduledItems/junction.json create mode 100644 ListScheduledItems/run.ps1 create mode 100644 RemoveScheduledItems/function.json create mode 100644 RemoveScheduledItems/run.ps1 diff --git a/AddScheduledItems/function.json b/AddScheduledItems/function.json new file mode 100644 index 000000000000..925eab5aeae1 --- /dev/null +++ b/AddScheduledItems/function.json @@ -0,0 +1,19 @@ +{ + "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/AddScheduledItems/run.ps1 b/AddScheduledItems/run.ps1 new file mode 100644 index 000000000000..a9d7655e1081 --- /dev/null +++ b/AddScheduledItems/run.ps1 @@ -0,0 +1,18 @@ +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 = $Request.Body | ConvertFrom-Json +$Table = Get-CIPPTable -TableName 'ScheduledTasks' +Add-AzDataTableEntity @Table -Entity @{ + PartitionKey = 'ScheduledTask' + RowKey = $task.TaskID + Command = $task.Command + Parameters = $task.Parameters + ScheduledTime = $task.ScheduledTime + # add more properties here based on what properties your tasks have +} +Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = 'Task added successfully.' +}) \ No newline at end of file diff --git a/ListScheduledItems/junction.json b/ListScheduledItems/junction.json new file mode 100644 index 000000000000..925eab5aeae1 --- /dev/null +++ b/ListScheduledItems/junction.json @@ -0,0 +1,19 @@ +{ + "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 new file mode 100644 index 000000000000..3b76fb77b212 --- /dev/null +++ b/ListScheduledItems/run.ps1 @@ -0,0 +1,15 @@ +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-AzDataTableEntity @Table -Filter "PartitionKey eq 'ScheduledTask'" + +# 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/RemoveScheduledItems/function.json b/RemoveScheduledItems/function.json new file mode 100644 index 000000000000..925eab5aeae1 --- /dev/null +++ b/RemoveScheduledItems/function.json @@ -0,0 +1,19 @@ +{ + "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/RemoveScheduledItems/run.ps1 b/RemoveScheduledItems/run.ps1 new file mode 100644 index 000000000000..ce7c0a0dcd9c --- /dev/null +++ b/RemoveScheduledItems/run.ps1 @@ -0,0 +1,11 @@ +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 = $Request.Body | ConvertFrom-Json +$Table = Get-CIPPTable -TableName 'ScheduledTasks' +Remove-AzDataTableEntity @Table -PartitionKey 'ScheduledTask' -RowKey $task.TaskID -force +Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = 'Task removed successfully.' +}) \ No newline at end of file From 7c5edc1c2826d3de135da4d9b356b94c6c41c731 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Tue, 4 Jul 2023 22:19:17 +0200 Subject: [PATCH 36/44] fixed --- .../{junction.json => function.json} | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) rename ListScheduledItems/{junction.json => function.json} (94%) diff --git a/ListScheduledItems/junction.json b/ListScheduledItems/function.json similarity index 94% rename from ListScheduledItems/junction.json rename to ListScheduledItems/function.json index 925eab5aeae1..b0ca1676cc0b 100644 --- a/ListScheduledItems/junction.json +++ b/ListScheduledItems/function.json @@ -1,19 +1,19 @@ -{ - "bindings": [ - { - "authLevel": "anonymous", - "type": "httpTrigger", - "direction": "in", - "name": "Request", - "methods": [ - "get", - "post" - ] - }, - { - "type": "http", - "direction": "out", - "name": "Response" - } - ] +{ + "bindings": [ + { + "authLevel": "anonymous", + "type": "httpTrigger", + "direction": "in", + "name": "Request", + "methods": [ + "get", + "post" + ] + }, + { + "type": "http", + "direction": "out", + "name": "Response" + } + ] } \ No newline at end of file From a6c5c4f8758a36e0f2b6f36cf430c5eb87dba214 Mon Sep 17 00:00:00 2001 From: Ashley Cooper <122837620+ashley-mspgeek@users.noreply.github.com> Date: Tue, 4 Jul 2023 17:04:38 -0400 Subject: [PATCH 37/44] added function for storing the users scheduled tasks and updated add function to include additional properties. --- AddScheduledItems/run.ps1 | 2 ++ Scheduler_UserTasks/_functions.json | 15 ++++++++++ Scheduler_UserTasks/run.ps1 | 44 +++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+) create mode 100644 Scheduler_UserTasks/_functions.json create mode 100644 Scheduler_UserTasks/run.ps1 diff --git a/AddScheduledItems/run.ps1 b/AddScheduledItems/run.ps1 index a9d7655e1081..b8dbc7843324 100644 --- a/AddScheduledItems/run.ps1 +++ b/AddScheduledItems/run.ps1 @@ -6,10 +6,12 @@ $task = $Request.Body | ConvertFrom-Json $Table = Get-CIPPTable -TableName 'ScheduledTasks' Add-AzDataTableEntity @Table -Entity @{ PartitionKey = 'ScheduledTask' + TaskState = 'Scheduled' RowKey = $task.TaskID Command = $task.Command Parameters = $task.Parameters ScheduledTime = $task.ScheduledTime + Results = 'Not Executed' # add more properties here based on what properties your tasks have } Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ diff --git a/Scheduler_UserTasks/_functions.json b/Scheduler_UserTasks/_functions.json new file mode 100644 index 000000000000..a4e981dd588d --- /dev/null +++ b/Scheduler_UserTasks/_functions.json @@ -0,0 +1,15 @@ +{ + "bindings": [ + { + "name": "Timer", + "schedule": "0 */15 * * * *", + "direction": "in", + "type": "timerTrigger" + }, + { + "name": "starter", + "type": "durableClient", + "direction": "in" + } + ] + } \ No newline at end of file diff --git a/Scheduler_UserTasks/run.ps1 b/Scheduler_UserTasks/run.ps1 new file mode 100644 index 000000000000..91432822b602 --- /dev/null +++ b/Scheduler_UserTasks/run.ps1 @@ -0,0 +1,44 @@ +param($Timer) + +$Table = Get-CippTable -tablename 'ScheduledTasks' +$Filter = "Results eq 'Not Executed'" +$tasks = Get-AzDataTableEntity @Table -Filter $Filter + +foreach ($task in $tasks) { + # Check if task has not been executed yet (i.e., 'Results' is 'Not Executed') + if ((Get-Date) -ge $task.ExpectedRunTime) { + try { + Update-AzDataTableEntity @Table -Entity @{ + PartitionKey = $task.PartitionKey + RowKey = $task.RowKey + TaskState = 'Running' + # Update other properties as needed + } + + $results = Invoke-Command -ScriptBlock ([ScriptBlock]::Create($task.Command)) -ArgumentList $task.Parameters + + Update-AzDataTableEntity @Table -Entity @{ + PartitionKey = $task.PartitionKey + RowKey = $task.RowKey + Results = "$results" + TaskState = 'Completed' + # Update other properties as needed + } + + Write-LogMessage -API "Scheduler_UserTasks" -tenant $tenant -message "Successfully executed task: $($task.RowKey)" -sev Info + } + catch { + $errorMessage = $_.Exception.Message + + Update-AzDataTableEntity @Table -Entity @{ + PartitionKey = $task.PartitionKey + RowKey = $task.RowKey + Results = "$errorMessage" + TaskState = 'Failed' + # Update other properties as needed + } + + Write-LogMessage -API "Scheduler_UserTasks" -tenant $tenant -message "Failed to execute task: $errorMessage" -sev Error + } + } +} \ No newline at end of file From 5c749e5c8d448df4807fcd21048073795299cfa7 Mon Sep 17 00:00:00 2001 From: BNWEIN Date: Thu, 6 Jul 2023 13:41:33 +0100 Subject: [PATCH 38/44] Rename run.ps1 to run.ps1 Changed Folder name to uppercase S --- {standards_IntuneTemplate => Standards_IntuneTemplate}/run.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename {standards_IntuneTemplate => Standards_IntuneTemplate}/run.ps1 (99%) diff --git a/standards_IntuneTemplate/run.ps1 b/Standards_IntuneTemplate/run.ps1 similarity index 99% rename from standards_IntuneTemplate/run.ps1 rename to Standards_IntuneTemplate/run.ps1 index 9ead260460c6..1db59ef6e28e 100644 --- a/standards_IntuneTemplate/run.ps1 +++ b/Standards_IntuneTemplate/run.ps1 @@ -85,4 +85,4 @@ foreach ($Template in $Setting.TemplateList) { catch { Write-LogMessage -API "Standards" -tenant $tenant -message "Failed to create or update Intune Template: $($_.exception.message)" -sev "Error" } -} \ No newline at end of file +} From b9168ad003a1661ae79bb23f43a291b619aa5c81 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Thu, 6 Jul 2023 16:26:29 +0200 Subject: [PATCH 39/44] renames --- .../function.json | 0 .../run.ps1 | 0 {standards_ExConnector => Standards_ExConnector_}/function.json | 0 {standards_ExConnector => Standards_ExConnector_}/run.ps1 | 0 .../function.json | 0 {standards_GroupTemplate => Standards_GroupTemplate_}/run.ps1 | 0 .../function.json | 0 {Standards_IntuneTemplate => Standards_IntuneTemplate_}/run.ps1 | 0 .../function.json | 0 .../run.ps1 | 0 10 files changed, 0 insertions(+), 0 deletions(-) rename {standards_ConditionalAccess => Standards_ConditionalAccess_}/function.json (100%) rename {standards_ConditionalAccess => Standards_ConditionalAccess_}/run.ps1 (100%) rename {standards_ExConnector => Standards_ExConnector_}/function.json (100%) rename {standards_ExConnector => Standards_ExConnector_}/run.ps1 (100%) rename {standards_GroupTemplate => Standards_GroupTemplate_}/function.json (100%) rename {standards_GroupTemplate => Standards_GroupTemplate_}/run.ps1 (100%) rename {standards_IntuneTemplate => Standards_IntuneTemplate_}/function.json (100%) rename {Standards_IntuneTemplate => Standards_IntuneTemplate_}/run.ps1 (100%) rename {standards_TransportRuleTemplate => Standards_TransportRuleTemplate_}/function.json (100%) rename {standards_TransportRuleTemplate => Standards_TransportRuleTemplate_}/run.ps1 (100%) diff --git a/standards_ConditionalAccess/function.json b/Standards_ConditionalAccess_/function.json similarity index 100% rename from standards_ConditionalAccess/function.json rename to Standards_ConditionalAccess_/function.json diff --git a/standards_ConditionalAccess/run.ps1 b/Standards_ConditionalAccess_/run.ps1 similarity index 100% rename from standards_ConditionalAccess/run.ps1 rename to Standards_ConditionalAccess_/run.ps1 diff --git a/standards_ExConnector/function.json b/Standards_ExConnector_/function.json similarity index 100% rename from standards_ExConnector/function.json rename to Standards_ExConnector_/function.json diff --git a/standards_ExConnector/run.ps1 b/Standards_ExConnector_/run.ps1 similarity index 100% rename from standards_ExConnector/run.ps1 rename to Standards_ExConnector_/run.ps1 diff --git a/standards_GroupTemplate/function.json b/Standards_GroupTemplate_/function.json similarity index 100% rename from standards_GroupTemplate/function.json rename to Standards_GroupTemplate_/function.json diff --git a/standards_GroupTemplate/run.ps1 b/Standards_GroupTemplate_/run.ps1 similarity index 100% rename from standards_GroupTemplate/run.ps1 rename to Standards_GroupTemplate_/run.ps1 diff --git a/standards_IntuneTemplate/function.json b/Standards_IntuneTemplate_/function.json similarity index 100% rename from standards_IntuneTemplate/function.json rename to Standards_IntuneTemplate_/function.json diff --git a/Standards_IntuneTemplate/run.ps1 b/Standards_IntuneTemplate_/run.ps1 similarity index 100% rename from Standards_IntuneTemplate/run.ps1 rename to Standards_IntuneTemplate_/run.ps1 diff --git a/standards_TransportRuleTemplate/function.json b/Standards_TransportRuleTemplate_/function.json similarity index 100% rename from standards_TransportRuleTemplate/function.json rename to Standards_TransportRuleTemplate_/function.json diff --git a/standards_TransportRuleTemplate/run.ps1 b/Standards_TransportRuleTemplate_/run.ps1 similarity index 100% rename from standards_TransportRuleTemplate/run.ps1 rename to Standards_TransportRuleTemplate_/run.ps1 From ba931de1e5d6eb611f4ba33fb36f822d976e3825 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Thu, 6 Jul 2023 16:27:46 +0200 Subject: [PATCH 40/44] fix for names standards --- .../function.json | 0 .../run.ps1 | 0 {Standards_ExConnector_ => Standards_ExConnector}/function.json | 0 {Standards_ExConnector_ => Standards_ExConnector}/run.ps1 | 0 .../function.json | 0 {Standards_GroupTemplate_ => Standards_GroupTemplate}/run.ps1 | 0 .../function.json | 0 {Standards_IntuneTemplate_ => Standards_IntuneTemplate}/run.ps1 | 0 .../function.json | 0 .../run.ps1 | 0 10 files changed, 0 insertions(+), 0 deletions(-) rename {Standards_ConditionalAccess_ => Standards_ConditionalAccess}/function.json (100%) rename {Standards_ConditionalAccess_ => Standards_ConditionalAccess}/run.ps1 (100%) rename {Standards_ExConnector_ => Standards_ExConnector}/function.json (100%) rename {Standards_ExConnector_ => Standards_ExConnector}/run.ps1 (100%) rename {Standards_GroupTemplate_ => Standards_GroupTemplate}/function.json (100%) rename {Standards_GroupTemplate_ => Standards_GroupTemplate}/run.ps1 (100%) rename {Standards_IntuneTemplate_ => Standards_IntuneTemplate}/function.json (100%) rename {Standards_IntuneTemplate_ => Standards_IntuneTemplate}/run.ps1 (100%) rename {Standards_TransportRuleTemplate_ => Standards_TransportRuleTemplate}/function.json (100%) rename {Standards_TransportRuleTemplate_ => Standards_TransportRuleTemplate}/run.ps1 (100%) diff --git a/Standards_ConditionalAccess_/function.json b/Standards_ConditionalAccess/function.json similarity index 100% rename from Standards_ConditionalAccess_/function.json rename to Standards_ConditionalAccess/function.json diff --git a/Standards_ConditionalAccess_/run.ps1 b/Standards_ConditionalAccess/run.ps1 similarity index 100% rename from Standards_ConditionalAccess_/run.ps1 rename to Standards_ConditionalAccess/run.ps1 diff --git a/Standards_ExConnector_/function.json b/Standards_ExConnector/function.json similarity index 100% rename from Standards_ExConnector_/function.json rename to Standards_ExConnector/function.json diff --git a/Standards_ExConnector_/run.ps1 b/Standards_ExConnector/run.ps1 similarity index 100% rename from Standards_ExConnector_/run.ps1 rename to Standards_ExConnector/run.ps1 diff --git a/Standards_GroupTemplate_/function.json b/Standards_GroupTemplate/function.json similarity index 100% rename from Standards_GroupTemplate_/function.json rename to Standards_GroupTemplate/function.json diff --git a/Standards_GroupTemplate_/run.ps1 b/Standards_GroupTemplate/run.ps1 similarity index 100% rename from Standards_GroupTemplate_/run.ps1 rename to Standards_GroupTemplate/run.ps1 diff --git a/Standards_IntuneTemplate_/function.json b/Standards_IntuneTemplate/function.json similarity index 100% rename from Standards_IntuneTemplate_/function.json rename to Standards_IntuneTemplate/function.json diff --git a/Standards_IntuneTemplate_/run.ps1 b/Standards_IntuneTemplate/run.ps1 similarity index 100% rename from Standards_IntuneTemplate_/run.ps1 rename to Standards_IntuneTemplate/run.ps1 diff --git a/Standards_TransportRuleTemplate_/function.json b/Standards_TransportRuleTemplate/function.json similarity index 100% rename from Standards_TransportRuleTemplate_/function.json rename to Standards_TransportRuleTemplate/function.json diff --git a/Standards_TransportRuleTemplate_/run.ps1 b/Standards_TransportRuleTemplate/run.ps1 similarity index 100% rename from Standards_TransportRuleTemplate_/run.ps1 rename to Standards_TransportRuleTemplate/run.ps1 From b4c51bd1942e2a32fa5cd074c8c477a4625034b4 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Thu, 6 Jul 2023 16:32:02 +0200 Subject: [PATCH 41/44] log mistake --- BestPracticeAnalyser_All/run.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BestPracticeAnalyser_All/run.ps1 b/BestPracticeAnalyser_All/run.ps1 index 08003efa32af..741da28b8eaa 100644 --- a/BestPracticeAnalyser_All/run.ps1 +++ b/BestPracticeAnalyser_All/run.ps1 @@ -48,7 +48,7 @@ try { $Result.TAPEnabled = $TAPEnabled.State } catch { - Write-LogMessage -API 'BestPracticeAnalyser' -tenant $tenant -message "Security Defaults State on $($tenant) Error: $($_.exception.message)" -sev 'Error' + Write-LogMessage -API 'BestPracticeAnalyser' -tenant $tenant -message "Retrieving TAP state failed: $($tenant) Error: $($_.exception.message)" -sev 'Error' } # Get the nudge State try { From 5b41faf735f453ba10a33296d4972a7da900ebf7 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Thu, 6 Jul 2023 16:41:00 +0200 Subject: [PATCH 42/44] adds crosstenantpolicy --- Cache_SAMSetup/SAMManifest.json | 1 + 1 file changed, 1 insertion(+) diff --git a/Cache_SAMSetup/SAMManifest.json b/Cache_SAMSetup/SAMManifest.json index d91d319312e0..5812c477906c 100644 --- a/Cache_SAMSetup/SAMManifest.json +++ b/Cache_SAMSetup/SAMManifest.json @@ -147,6 +147,7 @@ { "id": "45cc0394-e837-488b-a098-1918f48d186c", "type": "Role" }, { "id": "be74164b-cff1-491c-8741-e671cb536e13", "type": "Role" }, { "id": "2a60023f-3219-47ad-baa4-40e17cd02a1d", "type": "Role" }, + { "id": "338163d7-f101-4c92-94ba-ca46fe52447c", "type": "Role" }, { "id": "b27a61ec-b99c-4d6a-b126-c4375d08ae30", "type": "Scope" }, { "id": "84bccea3-f856-4a8a-967b-dbe0a3d53a64", "type": "Scope" }, { "id": "280b3b69-0437-44b1-bc20-3b2fca1ee3e9", "type": "Scope" }, From 0fe10b1158dca6a87d06937b6bd02828d16a1f43 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Thu, 6 Jul 2023 16:46:25 +0200 Subject: [PATCH 43/44] add permissions, clean up graph request --- Cache_SAMSetup/SAMManifest.json | 1 + Modules/GraphRequests/Public/Get-GraphRequestList.ps1 | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Cache_SAMSetup/SAMManifest.json b/Cache_SAMSetup/SAMManifest.json index 5812c477906c..3f458048fda0 100644 --- a/Cache_SAMSetup/SAMManifest.json +++ b/Cache_SAMSetup/SAMManifest.json @@ -148,6 +148,7 @@ { "id": "be74164b-cff1-491c-8741-e671cb536e13", "type": "Role" }, { "id": "2a60023f-3219-47ad-baa4-40e17cd02a1d", "type": "Role" }, { "id": "338163d7-f101-4c92-94ba-ca46fe52447c", "type": "Role" }, + { "id": "cac88765-0581-4025-9725-5ebc13f729ee", "type": "Role" }, { "id": "b27a61ec-b99c-4d6a-b126-c4375d08ae30", "type": "Scope" }, { "id": "84bccea3-f856-4a8a-967b-dbe0a3d53a64", "type": "Scope" }, { "id": "280b3b69-0437-44b1-bc20-3b2fca1ee3e9", "type": "Scope" }, diff --git a/Modules/GraphRequests/Public/Get-GraphRequestList.ps1 b/Modules/GraphRequests/Public/Get-GraphRequestList.ps1 index 7793fed428e5..59873b095b44 100644 --- a/Modules/GraphRequests/Public/Get-GraphRequestList.ps1 +++ b/Modules/GraphRequests/Public/Get-GraphRequestList.ps1 @@ -194,7 +194,7 @@ function Get-GraphRequestList { $GraphRequestResults = New-GraphGetRequest @GraphRequest -ErrorAction Stop if ($ReverseTenantLookup -and $GraphRequestResults) { $TenantInfo = $GraphRequestResults.$ReverseTenantLookupProperty | Sort-Object -Unique | ForEach-Object { - New-GraphGetRequest -uri "https://graph.microsoft.com/beta/tenantRelationships/findTenantInformationByTenantId(tenantId='$_')" -noauthcheck $true -asApp:$true + New-GraphGetRequest -uri "https://graph.microsoft.com/beta/tenantRelationships/findTenantInformationByTenantId(tenantId='$_')" -noauthcheck $true -asApp:$true -tenant $env:TenantId } foreach ($Result in $GraphRequestResults) { $Result | Select-Object @{n = 'TenantInfo'; e = { $TenantInfo | Where-Object { $Result.$ReverseTenantLookupProperty -eq $_.tenantId } } }, * From af607fc34b668cca758390f34a78324429f1130e Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Thu, 6 Jul 2023 16:47:28 +0200 Subject: [PATCH 44/44] Hotfix --- version_latest.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version_latest.txt b/version_latest.txt index 5cdb444f3d41..47b6be3fafec 100644 --- a/version_latest.txt +++ b/version_latest.txt @@ -1 +1 @@ -3.7.1 \ No newline at end of file +3.7.2 \ No newline at end of file