Sync Microsoft Secure Scores with IT Glue
Update (2nd March 2021)
Microsoft included some special characters in the secure score controls which don’t work well with the IT Glue API. This script has been updated to convert these characters to ASCII-friendly versions.
The Microsoft Secure Score rates how well you’re leveraging security controls for Office 365, Microsoft 365 and Windows 10. While it’s a great tool for determining a Microsoft Cloud tenant’s security standing, checking it for each environment can be a manual task.
This solution imports the secure score report of your own, and your customers’, tenants into IT Glue. You can use it to determine how to increase your customers’ secure scores, educate your customers on their current security standing, and provide justification for additional licensing like Microsoft 365 or Microsoft Cloud App Security.
You can see a quick overview of a tenant’s secure score, including how they compare to the global average, and similar sized businesses.
The report also includes a list of the security controls that make up your customers scores. Each control includes a link to the relevant information or area to address it.
Like our existing Office 365 script, this one will match tenants with IT Glue organisations automatically by comparing the verified domains in the Azure AD tenant against the domains in your IT Glue contacts’ email addresses.
It’ll keep a record of these matches in a SharePoint list in your own root SharePoint site. If you’d prefer that a particular Microsoft Cloud tenant not sync with an IT Glue Organisation, you can disable it from syncing in the ‘Office 365 – IT Glue match register‘ SharePoint list.
Prerequisites
- You’ll need an admin account in an IT Glue subscription with access to the API
- You’ll need an account with global admin permissions in your own tenant
- You’ll need to be a Microsoft Partner with access to your customers environments via delegated administration
- You’ll need to have the Azure Active Directory Powershell module installed. If you don’t have it installed, open PowerShell as an administrator and run the following cmdlet and accept the prompts.
Install-Module AzureAD
How to sync Microsoft Secure Scores with IT Glue
- The first part of this solution is to create an app in your own Azure Active Directory environment with permission to access your own and your customers’ directories. You can easily create this app using the script in this quick guide.
- Once you’ve created the app, retrieve the client ID, client secret and tenant ID from the exported CSV file at C:\temp\AzureADApp.csv.
- Double click on the script at the bottom of this page to select it, then copy and paste it into Visual Studio Code and save it with a .ps1 extension. Install the recommended PowerShell extension if you haven’t already.
- Add the client ID, client secret and tenant ID from your new Azure AD application into the relevant variables under Azure Ad App Details
- Retrieve or create an IT Glue API key from Account, Settings, API Keys
- Add the IT Glue API key into the $ITGkey variable in the script.
- If your tenant is hosted on IT Glues EU infrastructure, you may need to update the $ITGbaseURI value to: https://api.eu.itglue.com
- Press F5 to run the script and wait for it to complete. This is a long running script and may take a while if you have delegated access to many tenants.
- You can confirm that it has created a list called Office 365 – IT Glue match register in SharePoint by navigating to the Site Contents of your root SharePoint site. Eg. https://yourtenant.sharepoint.com. If you don’t want a tenant to sync with a company in IT Glue, you can disable it here, then delete the record from IT Glue.
- Add the new Microsoft Secure Score flexible asset type to your IT Glue menu under Account, Customize Sidebar.
- You can set this up as a scheduled task, or timer triggered PowerShell Azure Function. If you’re using an Azure Function, you can paste this script in as-is, though remember to replace the hardcoded client secret and API keys with Azure Function Environment variables. See the bottom of this article for instructions on this.
Note: In some tenants the combined identity, data, device, apps and infrastructure scores don’t add up to the total secure score. The discrepancy is coming from the data score, and may be due to a disabled or non-scored control contributing to the total.
PowerShell Script to Sync Microsoft Secure Scores with IT Glue companies
# Azure AD App Details $client_id = "EnterClientIDHere" $client_secret = "EnterClientSecretHere=" $tenant_id = "EnterTenantIDHere" $ListName = "Office 365 - IT Glue match register" $graphBaseUri = "https://graph.microsoft.com/v1.0/" $siteid = "root" $TableHeaderColour = "#00a1f1" # IT Glue Details $ITGbaseURI = "https://api.itglue.com" $ITGkey = "EnterITGlueIDHere" $ITGheaders = @{"x-api-key" = $ITGkey} $SecureScoreAssetName = "Microsoft Secure Score" function New-GCITSSharePointColumn($Name, $Type, $Indexed, $lookupListName, $lookupColumnPrimaryName, $lookupColumnName) { $column = [ordered]@{ name = $Name indexed = $Indexed $Type = @{} } if ($lookupListName -and $type -contains "lookup") { $list = Get-GCITSSharePointList -ListName $lookupListName if ($list) { $column.lookup.listId = $list.id $column.lookup.columnName = $lookupColumnName } } return $column } function New-GCITSSharePointList ($Name, $ColumnCollection) { $list = @{ displayName = $Name columns = $columnCollection } | Convertto-json -Depth 10 $newList = Invoke-RestMethod ` -Uri "$graphBaseUri/sites/$siteid/lists/" ` -Headers $SPHeaders ` -ContentType "application/json" ` -Method POST -Body $list return $newList } function New-GCITSSharePointListItem($ItemObject, $ListId) { $itemBody = @{ fields = $ItemObject } | ConvertTo-Json -Depth 10 $listItem = Invoke-RestMethod ` -Uri "$graphBaseUri/sites/$siteid/lists/$listId/items" ` -Headers $SPHeaders ` -ContentType "application/json" ` -Method Post ` -Body $itemBody } function Remove-GCITSITGItem ($Resource,$existingItem){ $item = Invoke-RestMethod -Method DELETE -Uri "$ITGbaseURI/$Resource/$($existingItem.id)" -Headers $ITGheaders } function Get-GCITSSharePointListItem($ListId, $ItemId, $Query) { if ($ItemId) { $listItem = Invoke-RestMethod -Uri $graphBaseUri/sites/$siteid/lists/$listId/items/$ItemId ` -Method Get -headers $SPHeaders ` -ContentType application/json $value = $listItem } elseif ($Query) { $listItems = $null $listItems = Invoke-RestMethod -Uri "$graphBaseUri/sites/$siteid/lists/$listId/items/?expand=fields&`$filter=$Query" ` -Method Get -headers $SPHeaders ` -ContentType application/json $value = @() $value = $listItems.value if ($listitems."@odata.nextLink") { $nextLink = $true } if ($nextLink) { do { $listItems = Invoke-RestMethod -Uri $listitems."@odata.nextLink"` -Method Get -headers $SPHeaders ` -ContentType application/json $value += $listItems.value if (!$listitems."@odata.nextLink") { $nextLink = $false } } until (!$nextLink) } } else { $listItems = $null $listItems = Invoke-RestMethod -Uri $graphBaseUri/sites/$siteid/lists/$listId/items?expand=fields ` -Method Get -headers $SPHeaders ` -ContentType application/json $value = @() $value = $listItems.value if ($listitems."@odata.nextLink") { $nextLink = $true } if ($nextLink) { do { $listItems = Invoke-RestMethod -Uri $listitems."@odata.nextLink"` -Method Get -headers $SPHeaders ` -ContentType application/json $value += $listItems.value if (!$listitems."@odata.nextLink") { $nextLink = $false } } until (!$nextLink) } } return $value } function Get-GCITSSharePointList($ListName) { $list = Invoke-RestMethod ` -Uri "$graphBaseUri/sites/$siteid/lists?expand=columns&`$filter=displayName eq '$ListName'" ` -Headers $SPHeaders ` -ContentType "application/json" ` -Method GET $list = $list.value return $list } function Get-GCITSAccessToken($appCredential, $tenantId) { $client_id = $appCredential.appID $client_secret = $appCredential.secret $tenant_id = $tenantid $resource = "https://graph.microsoft.com" $authority = "https://login.microsoftonline.com/$tenant_id" $tokenEndpointUri = "$authority/oauth2/token" $content = "grant_type=client_credentials&client_id=$client_id&client_secret=$client_secret&username=$UserForDelegatedPermissions&password=$Password&resource=$resource" $response = Invoke-RestMethod -Uri $tokenEndpointUri -Body $content -Method Post -UseBasicParsing $access_token = $response.access_token return $access_token } function Get-GCITSMSGraphResource($Resource) { $graphBaseUri = "https://graph.microsoft.com/beta" $values = @() $result = Invoke-RestMethod -Uri "$graphBaseUri/$resource" -Headers $headers if ($result.value) { $values += $result.value if ($result.'@odata.nextLink') { do { $result = Invoke-RestMethod -Uri $result.'@odata.nextLink' -Headers $headers $values += $result.value } while ($result.'@odata.nextLink') } } else { $values = $result } return $values } function New-GCITSITGTableFromArray($Array, $HeaderColour) { # Remove any empty properties from table $properties = $Array | get-member -ErrorAction SilentlyContinue | Where-Object {$_.memberType -contains "NoteProperty"} foreach ($property in $properties) { try { $members = $Array.$($property.name) | Get-Member -ErrorAction Stop } catch { $Array = $Array | Select-Object -Property * -ExcludeProperty $property.name } } $Table = $Array | ConvertTo-Html -Fragment if ($Table[2] -match "<tr>") { $Table[2] = $Table[2] -replace "<tr>", "<tr style=`"background-color:$HeaderColour`">" } return $Table } function Get-GCITSITGItem($Resource) { $array = @() $body = Invoke-RestMethod -Method get -Uri "$ITGbaseUri/$Resource" -Headers $ITGheaders -ContentType application/vnd.api+json $array += $body.data Write-Host "Retrieved $($array.Count) IT Glue items" if ($body.links.next) { do { $body = Invoke-RestMethod -Method get -Uri $body.links.next -Headers $ITGheaders -ContentType application/vnd.api+json $array += $body.data Write-Host "Retrieved $($array.Count) IT Glue items" } while ($body.links.next) } return $array } function New-GCITSITGItem ($Resource, $Body) { $item = Invoke-RestMethod -Method POST -ContentType application/vnd.api+json -Uri $ITGBaseURI/$Resource -Body $Body -Headers $ITGHeaders return $item } function Set-GCITSITGItem ($Resource, $existingItem, $Body) { $updatedItem = Invoke-RestMethod -Method Patch -Uri "$ITGbaseUri/$Resource/$($existingItem.id)" -Headers $ITGheaders -ContentType application/vnd.api+json -Body $Body return $updatedItem } function Remove-GCITSITGItem ($Resource,$existingItem){ $item = Invoke-RestMethod -Method DELETE -Uri "$ITGbaseURI/$Resource/$($existingItem.id)" -Headers $ITGheaders } function New-GCITSITGSecureScoreFlexibleAsset { $body = @{ data = @{ type = "flexible_asset_types" attributes = @{ name = $SecureScoreAssetName description = "Microsoft Secure Score Summary and Controls" icon = "check" "show-in-menu" = $true } relationships = @{ "flexible-asset-fields" = @{ data = @( @{ type = "flexible_asset_fields" attributes = @{ order = 1 name = "Overview" kind = "Textbox" required = $false "show-in-list" = $false } }, @{ type = "flexible_asset_fields" attributes = @{ order = 2 name = "Identity Controls" kind = "Textbox" required = $false "show-in-list" = $false } }, @{ type = "flexible_asset_fields" attributes = @{ order = 3 name = "Data Controls" kind = "Textbox" required = $false "show-in-list" = $false } }, @{ type = "flexible_asset_fields" attributes = @{ order = 4 name = "Device Controls" kind = "Textbox" required = $false "show-in-list" = $false } }, @{ type = "flexible_asset_fields" attributes = @{ order = 5 name = "Apps Controls" kind = "Textbox" required = $false "show-in-list" = $false } }, @{ type = "flexible_asset_fields" attributes = @{ order = 6 name = "Infrastructure Controls" kind = "Textbox" required = $false "show-in-list" = $false } }, @{ type = "flexible_asset_fields" attributes = @{ order = 7 name = "Tenant Name" kind = "Text" required = $false "show-in-list" = $true "use-for-title" = $true } }, @{ type = "flexible_asset_fields" attributes = @{ order = 8 name = "Secure Score" kind = "Number" required = $false "show-in-list" = $true } }, @{ type = "flexible_asset_fields" attributes = @{ order = 9 name = "Identity Score" kind = "Number" required = $false "show-in-list" = $true } }, @{ type = "flexible_asset_fields" attributes = @{ order = 10 name = "Data Score" kind = "Number" required = $false "show-in-list" = $true } }, @{ type = "flexible_asset_fields" attributes = @{ order = 11 name = "Device Score" kind = "Number" required = $false "show-in-list" = $true } }, @{ type = "flexible_asset_fields" attributes = @{ order = 12 name = "Apps Score" kind = "Number" required = $false "show-in-list" = $true } }, @{ type = "flexible_asset_fields" attributes = @{ order = 13 name = "Infrastructure Score" kind = "Number" required = $false "show-in-list" = $true } }, @{ type = "flexible_asset_fields" attributes = @{ order = 14 name = "Tenant Id" kind = "Text" required = $false "show-in-list" = $true } }, @{ type = "flexible_asset_fields" attributes = @{ order = 15 name = "Default Domain" kind = "Text" required = $false "show-in-list" = $true } } ) } } } } $flexibleAssetType = $body | ConvertTo-Json -Depth 10 return $flexibleAssetType } function Set-GCITSASCIIEncoding($String) { $String = $String.Replace("’", "'") $String = $String.Replace("`“", "`"") $String = $String.Replace("`”", "`"") $String = $String.Replace("?", "\\\\\") $String = $String.Replace("'", "") $String = $String.trim() $String = [system.text.encoding]::UTF8.GetBytes($String) $String = [system.text.encoding]::convert([text.encoding]::UTF8, [text.encoding]::ASCII, $String) $String = -join [system.text.encoding]::ASCII.GetChars($String) $String = $String.Replace("?", "") $String = $String.Replace("\\\\\", "?") return $String } function New-GCITSITGSecureScoreAsset ($OrganizationId, $OverView, $identityControls, ` $DataControls, $DeviceControls, $AppsControls, $InfrastructureControls, $tenantName, ` $secureScore, $identityScore, $dataScore, $deviceScore, $appsScore, $infrastructureScore, ` $tenantid, $defaultDomain) { $body = @{ data = @{ type = "flexible-assets" attributes = @{ "organization-id" = $OrganizationId "flexible-asset-type-id" = $SecureScoreAssetType traits = @{ "overview" = Set-GCITSASCIIEncoding -String $OverView "identity-controls" = Set-GCITSASCIIEncoding -String$identityControls "data-controls" = Set-GCITSASCIIEncoding -String$dataControls "device-controls" = Set-GCITSASCIIEncoding -String$deviceControls "apps-controls" = Set-GCITSASCIIEncoding -String$appsControls "infrastructure-controls" = Set-GCITSASCIIEncoding -String$InfrastructureControls "tenant-name" = Set-GCITSASCIIEncoding -String$tenantName "secure-score" = [int]$secureScore "identity-score" = [int]$identityScore "data-score" = [int]$dataScore "device-score" = [int]$deviceScore "apps-score" = [int]$appsScore "infrastructure-score" = [int]$infrastructureScore "tenant-id" = $tenantId "default-domain" = $defaultDomain } } } } $tenantAsset = $body | ConvertTo-Json -Depth 99 return $tenantAsset } $appCredential = @{ appid = $client_id secret = $client_secret } #<# $access_token = Get-GCITSAccessToken -appCredential $appCredential -tenantId $tenant_id $Headers = @{Authorization = "Bearer $access_token"} $SPHeaders = $Headers $yourTenant = Get-GCITSMSGraphResource -Resource organization [array]$contracts = @{ customerId = $yourTenant.id defaultDomainName = ($yourtenant.verifiedDomains | Where-Object {$_.isdefault}).name displayname = $yourTenant.displayName } $contracts += Get-GCITSMSGraphResource -Resource contracts $reports = @() foreach ($contract in $contracts) { Write-Output "Compiling Secure Score Report for $($contract.displayname)" try { $access_token = Get-GCITSAccessToken -appCredential $appCredential -tenantId $contract.customerid $Headers = @{Authorization = "Bearer $access_token"} [array]$scores = Get-GCITSMSGraphResource -Resource "security/securescores" [array]$domains = (Get-GCITSMSGraphResource -Resource domains | Where-Object {$_.isverified}).id $profiles = Get-GCITSMSGraphResource -Resource "security/secureScoreControlProfiles" $collectionError = $false } catch { $collectionError = $true Write-Output "Could not retrieve scores for $($contract.displayname)" } if ($scores -and !$collectionError) { $latestScore = $scores[0] $HTMLCollection = @() foreach ($control in $latestScore.controlScores) { $controlReport = $null $launchButton = $null $controlProfile = $profiles | Where-Object {$_.id -contains $control.controlname} $controlTitle = "<h2>$($controlProfile.title)</h2>" [int]$controlScoreInt = $control.score [int]$maxScoreInt = $controlProfile.maxScore [string]$controlScore = "<h3>Score: $controlScoreInt/$maxScoreInt</h3>" $assessment = "<strong>Assessment</strong><br>$($control.description)<br>" $remediation = "<strong>Remediation</strong><br>$($controlprofile.remediation)<br>" $remediationImpact = "<strong>Remediation Impact</strong><br>$($controlprofile.remediationImpact)<br>" if ($controlProfile.actionUrl) { $launchButton = "<a class=`"btn btn-primary btn-md`" href=`"$($controlProfile.actionUrl)`">Launch</a><br>" } $userImpact = "<strong>User Impact:</strong> $($controlprofile.userImpact)" $implementationCost = "<strong>Implementation Cost:</strong> $($controlprofile.implementationCost)" $threats = "<strong>Threats:</strong> $($controlprofile.threats -join ", ")" $tier = "<strong>Tier:</strong> $($controlprofile.tier)" $hr = "<hr>" [array]$controlElements = $assessment, $remediation, $remediationImpact if ($launchButton) { $controlElements += $launchButton } $controlReport = "<div>$($controlElements -join "</div><div><br></div><div>")</div><div><br></div>$($userImpact,$implementationCost,$threats,$tier,$hr -join "</div><div>")</div>" $controlReport = "$($controlTitle)$($controlScore)<div><br></div>$($controlReport)" $HTMLCollection += [pscustomobject]@{ category = $controlProfile.controlCategory controlReport = [string]$controlReport rank = $controlProfile.rank deprecated = $controlProfile.deprecated score = $control.score } } $HTMLCollection = $HTMLCollection | Where-Object {!$_.deprecated} | Sort-Object rank $identityControls = $HTMLCollection | Where-Object {$_.category -contains "Identity"} $DataControls = $HTMLCollection | Where-Object {$_.category -contains "Data"} $DeviceControls = $HTMLCollection | Where-Object {$_.category -contains "Device"} $AppsControls = $HTMLCollection | Where-Object {$_.category -contains "Apps"} $InfrastructureControls = $HTMLCollection | Where-Object {$_.category -contains "Infrastructure"} $identityScore = 0 $dataScore = 0 $deviceScore = 0 $appsScore = 0 $infrastructureScore = 0 $identityControls | ForEach-Object {$identityScore += $_.score} $DataControls | ForEach-Object {$dataScore += $_.score} $DeviceControls | ForEach-Object {$deviceScore += $_.score} $AppsControls | ForEach-Object {$appsScore += $_.score} $InfrastructureControls | ForEach-Object {$infrastructureScore += $_.score} [int]$identityScore = $identityScore [int]$dataScore = $dataScore [int]$deviceScore = $deviceScore [int]$appsScore = $appsScore [int]$infrastructureScore = $infrastructureScore $categoryScores = @() $allTenantScores = $latestScore.averageComparativeScores | Where-Object {$_.basis -contains "AllTenants"} $similarCompanyScores = $latestScore.averageComparativeScores | Where-Object {$_.basis -contains "TotalSeats"} [int]$maxScore = $latestScore.maxScore [int]$similarCompanyAverage = $similarCompanyScores.averageScore [int]$globalAverage = $allTenantScores.averageScore $minSeat = $similarCompanyScores.seatSizeRangeLowerValue $maxSeat = $similarCompanyScores.seatSizeRangeUpperValue $categoryScores += [pscustomobject][ordered]@{ Identity = "Tenant score: $($identityScore)" Data = "Tenant score: $($dataScore)" Device = "Tenant score: $($deviceScore)" } $categoryScores += [pscustomobject][ordered]@{ Identity = "Global average: $($allTenantScores.identityScore)" Data = "Global average: $($allTenantScores.dataScore)" Device = "Global average: $($allTenantScores.deviceScore)" } $categoryScores += [pscustomobject][ordered]@{ Identity = "Similar sized company average: $($similarCompanyScores.identityScore)" Data = "Similar sized company average: $($similarCompanyScores.dataScore)" Device = "Similar sized company average: $($similarCompanyScores.deviceScore)" } # Add Apps and Infrastructure scores to the overview table if they exist. if ($allTenantScores) { if (($allTenantScores | get-member).name -contains "appsScore") { $categoryScores[0] | Add-Member Apps "Tenant score: $appsScore" $categoryScores[1] | Add-Member Apps "Global average: $($allTenantScores.appsScore)" $categoryScores[2] | Add-Member Apps "Similar sized company average: $($similarCompanyScores.appsScore)" } if (($allTenantScores | get-member).name -contains "infrastructureScore") { $categoryScores[0] | Add-Member Infrastructure "Tenant score: $infrastructureScore" $categoryScores[1] | Add-Member Infrastructure "Global average: $($allTenantScores.infrastructureScore)" $categoryScores[2] | Add-Member Infrastructure "Similar sized company average: $($similarCompanyScores.infrastructureScore)" } } [int]$currentScore = $($latestScore.currentScore) $scoreheading = "<h1>Microsoft Secure Score: $currentScore</h1>" $maxScoreTitle = "<strong>Maximum attainable score:</strong> $maxScore" $similarCompanyTitle = "<strong>Similar sized company average ($minSeat - $maxSeat users):</strong> $similarCompanyAverage" $globalAverageTitle = "<strong>Global average:</strong> $globalAverage" $scoreBreakDownTitle = "<strong>Score Breakdown:</strong>" $scoreBreakdownTable = New-GCITSITGTableFromArray -Array $categoryScores -HeaderColour $TableHeaderColour $subHeadings = "<div>$($maxScoreTitle,$similarCompanyTitle,$globalAverageTitle -join "</div><div>")</div>" $overviewHTML = "$($scoreheading,$subHeadings,$scoreBreakDownTitle -join "<div><br></div>")$scoreBreakdownTable" $identityHTML = $identityControls.controlReport -join "<div><br></div>" $dataHTML = $dataControls.controlReport -join "<div><br></div>" $deviceHTML = $deviceControls.controlReport -join "<div><br></div>" $appsHTML = $appsControls.controlReport -join "<div><br></div>" $infrastructureHTML = $infrastructureControls.controlReport -join "<div><br></div>" $reports += @{ TenantId = $contract.customerId TenantName = $contract.displayName DefaultDomain = $contract.defaultDomainName Domains = $domains CurrentScore = [int]$latestScore.currentScore IdentityScore = $identityScore DataScore = $dataScore DeviceScore = $deviceScore AppsScore = $AppsScore InstrastructureScore = $InstrastructureScore Overview = $overviewHTML IdentityControls = $identityHTML DataControls = $dataHTML DeviceControls = $deviceHTML AppsControls = $appsHTML InfrastructureControls = $infrastructureHTML } } } Write-Host "Retrieving IT Glue Organisations" $itgOrgs = Get-GCITSITGItem -Resource organizations Write-Host "Retrieving IT Glue Contacts" $itgContacts = Get-GCITSITGItem -Resource contacts $itgEmailRecords = @() foreach ($contact in $itgcontacts) { foreach ($email in $contact.attributes."contact-emails") { $hash = @{ Domain = ($email.value -split "@")[1] OrganizationID = $contact.attributes.'organization-id' } $object = New-Object psobject -Property $hash $itgEmailRecords += $object } } Write-Host "Matching reports with IT Glue Organisations" $allMatches = @() foreach ($report in $reports) { foreach ($domain in $report.domains) { $itgContactMatches = $itgEmailRecords | Where-Object {$_.domain -contains $domain} foreach ($match in $itgContactMatches) { $MatchingOrg = $itgOrgs | Where-Object {$_.id -eq $match.OrganizationID} $MatchedReport = New-Object -TypeName psobject -Property $report $MatchedReport | Add-Member OrganizationID $match.OrganizationID -Force $MatchedReport | Add-Member OrganizationName $MatchingOrg.attributes.name $MatchedReport | Add-Member Key "$($report.TenantId)-$($match.OrganizationID)" $allMatches += $MatchedReport } } } [array]$uniqueMatches = $allMatches | sort-object Key -Unique try { $list = Get-GCITSSharePointList -ListName $ListName } catch { # if SharePoint access token is expired, get a new one. $access_token = Get-GCITSAccessToken -appCredential $appCredential -tenantId $tenant_id $Headers = @{Authorization = "Bearer $access_token"} $SPHeaders = $Headers $list = Get-GCITSSharePointList -ListName $ListName } if (!$list) { Write-Host "SharePoint List not found, creating List" # Initiate Columns $columnCollection = @() $columnCollection += New-GCITSSharePointColumn -Name ITGlueOrg -Type text -Indexed $true $columnCollection += New-GCITSSharePointColumn -Name DisableSync -Type boolean -Indexed $true $columnCollection += New-GCITSSharePointColumn -Name DefaultDomain -Type text -Indexed $true $columnCollection += New-GCITSSharePointColumn -Name TenantId -Type text -Indexed $true $columnCollection += New-GCITSSharePointColumn -Name ITGlueOrgId -Type number -Indexed $true $columnCollection += New-GCITSSharePointColumn -Name Key -Type text -Indexed $true $List = New-GCITSSharePointList -Name $ListName -ColumnCollection $columnCollection } else { Write-Host "SharePoint List Exists, retrieving existing items" $existingItems = Get-GCITSSharePointListItem -ListId $list.id Write-Host "Retrieved $($existingItems.count) existing SharePoint items" } # Check for existing Secure Score flexible asset $SecureScoreAssetType = (Get-GCITSITGItem -Resource "flexible_asset_types?filter[name]=$SecureScoreAssetName").id if (!$SecureScoreAssetType) { Write-Host "Creating IT Glue Flexible Asset for Microsoft Secure Score" $flexibleAssetType = New-GCITSITGSecureScoreFlexibleAsset $SecureScoreAssetType = (New-GCITSITGItem -Resource flexible_asset_types -Body $flexibleAssetType).data.id } foreach ($match in $uniqueMatches) { $sharePointItem = $existingItems | where-object {$_.fields.key -eq $match.key} if (!$sharePointItem) { $sharePointItem = @{ Title = $match.TenantName ITGlueOrg = $match.OrganizationName DisableSync = $false DefaultDomain = $match.defaultDomain TenantId = $match.TenantId ITGlueOrgId = $match.OrganizationId Key = $match.key } $sharePointItem = New-GCITSSharePointListItem -ListId $list.id -ItemObject $sharePointItem } Write-Host "Checking for existing report for $($sharePointItem.fields.Title) in $($sharePointItem.fields.ITGlueOrg)" [array]$existingAssets = Get-GCITSITGItem -Resource "flexible_assets?filter[organization_id]=$($match.OrganizationID)&filter[flexible_asset_type_id]=$SecureScoreAssetType" $matchingAsset = $existingAssets | Where-Object {$_.attributes.traits.'tenant-id' -contains $match.TenantId} $newAsset = New-GCITSITGSecureScoreAsset -OrganizationId $match.organizationId -OverView $match.overview ` -identityControls $match.identityControls -DataControls $match.dataControls -DeviceControls $match.deviceControls ` -AppsControls $match.appsControls -InfrastructureControls $match.infrastructureControls -tenantName $match.tenantName ` -secureScore $match.CurrentScore -identityScore $match.identityScore -dataScore $match.dataScore -deviceScore $match.deviceScore ` -tenantid $match.tenantid -defaultDomain $match.defaultDomain -appsScore $match.AppsScore -infrastructureScore $match.InfrastructureScore if (!$matchingAsset) { if(!$sharePointItem.fields.DisableSync){ Write-Host "No existing report found, creating new report" -foregroundcolor Green New-GCITSITGItem -resource flexible_assets -body $newAsset } } else { if (!$sharePointItem.fields.DisableSync) { Write-Host "Existing report found, updating report" -foregroundcolor Green Set-GCITSITGItem -Resource flexible_assets -existingItem $matchingAsset -Body $newAsset } else { Write-Host "Sync Disabled, removing report" Remove-GCITSITGItem -Resource flexible_assets -ExistingItem $matchingAsset } } }
Leave a Reply
Want to join the discussion?Feel free to contribute!