Forum Discussion
Anil_Guliyaan
Jul 30, 2021Copper Contributor
How to list all resources covered/not covered by Azure Defender using REST API ?
I want to display Defender coverage in custom application like following image:: Please help?
- Jul 30, 2021
There is a query from the "Inventory Blade" in ASC, you can amend it (I made a start below on a recent project). This is using ARG rather than the REST api directly. You should be able to see the api info if you need to use that.
securityresources //| where subscriptionId == "< insert you id here >" | where type =~ "microsoft.security/assessments" or type =~ "microsoft.security/softwareInventories" | extend assessmentStatusCode = case(type =~ "microsoft.security/assessments", tostring(properties.status.code), "") | extend severity = case(assessmentStatusCode =~ "unhealthy", tolower(tostring(properties.metadata.severity)), tolower(assessmentStatusCode)) | extend exemptionType = case(tolower(type) != "microsoft.security/assessments","N/A", case(properties.status.cause =~ "exempt", "Yes", "No")) | extend source = case(type =~ "microsoft.security/assessments", tostring(properties.resourceDetails.Source), "") | extend resourceId = trim(" ", tolower(tostring(case(source =~ "azure", properties.resourceDetails.Id, source =~ "aws", properties.resourceDetails.AzureResourceId, source =~ "gcp", properties.resourceDetails.AzureResourceId, type =~ "microsoft.security/assessments", extract("^(.+)/providers/Microsoft.Security/assessments/.+$",1,id),extract("^(.+)/providers/Microsoft.Security/softwareInventories/.+$",1,id))))) | extend resourceName = extract(@"(.+)/(.+)", 2, resourceId) | extend regexResourceId = extract_all(@"/providers/([^/]+)(?:/([^/]+)/[^/]+(?:/([^/]+)/[^/]+)?)?/([^/]+)/[^/]+$", resourceId) | extend RegexResourceType = regexResourceId[0] | extend mainType = RegexResourceType[1], extendedType = RegexResourceType[2], resourceType = RegexResourceType[3] | extend providerName = RegexResourceType[0], mainType = case(mainType !~ "", strcat("/",mainType), ""), extendedType = case(extendedType!~ "", strcat("/",extendedType), ""), resourceType = case(resourceType!~ "", strcat("/",resourceType), "") | extend array = split(resourceId, '/') | extend typeFullPath = case(array_length(array) == 3, 'subscription', strcat(providerName, mainType, extendedType, resourceType)) | extend typeFullPath = case(array_length(array) == 5, 'resourcegroups', typeFullPath) | extend resourceType = case(typeFullPath =~ 'resourcegroups' or typeFullPath =~ 'subscription', typeFullPath, tolower(trim("/", resourceType))) | extend assessmentKey = case(type =~ "microsoft.security/assessments", tostring(name), "") | extend softwareVendorName = case(type =~ "microsoft.security/softwareInventories", tostring(properties.vendor), "") | extend softwareName = case(type =~ "microsoft.security/softwareInventories", tostring(properties.softwareName), "") | extend softwareNameIdentifier = case(type =~ "microsoft.security/softwareInventories", strcat(softwareVendorName, ",", softwareName), "") | extend environment = case(type =~ "microsoft.security/assessments", properties.resourceDetails["Source"], "") | extend environment = case(environment =~ "onpremise", tolower("Non-Azure"), tolower(environment)) | extend osTypeProperty = properties.additionalData["OS Type"] | extend osType = case(isnotempty(osTypeProperty), osTypeProperty, "") | extend hasAgent = case(assessmentKey == "d1db3318-01ff-16de-29eb-28b344515626" or assessmentKey == "45cfe080-ceb1-a91e-9743-71551ed24e94" or assessmentKey == "720a3e77-0b9a-4fa9-98b6-ddf0fd7e32c1" or assessmentKey == "27ac71b1-75c5-41c2-adc2-858f5db45b08", assessmentStatusCode, "") | extend workspaceAzureResourceId = case(hasAgent !~ "", properties.additionalData["Reporting workspace azure id"], "") | extend workspaceName = case(workspaceAzureResourceId !~ "", extract(@"(.+)/(.+)", 2, workspaceAzureResourceId), "") | extend assessmentDisplayName = case(type =~ "microsoft.security/assessments", case(isnotempty(properties.displayName), properties.displayName, properties.metadata.displayName), "") | extend assessmentIdentifier = case(type =~ "microsoft.security/assessments", strcat(assessmentKey, "," , assessmentDisplayName, ",", severity), "") | summarize assessmentsCount = count() , assessmentsIdentifier = make_list(assessmentIdentifier), softwareNamesIdentifier = make_list(softwareNameIdentifier), hasAgent = max(hasAgent), workspaceName = max(workspaceName), environment = max(environment), osType = max(osType), exemptionType = max(exemptionType) by resourceId, subscriptionId, resourceName, resourceType, typeFullPath, severity | extend packAssessments = pack(severity, assessmentsCount) | summarize assessmentsSummary = make_bag(packAssessments), assessmentsIdentifier = make_set(assessmentsIdentifier), softwareNamesIdentifier = make_set(softwareNamesIdentifier), hasAgent = max(hasAgent), workspaceName= max(workspaceName), environment = max(environment), osType= max(osType), exemptionType = max(exemptionType) by resourceId, subscriptionId, resourceName, resourceType, typeFullPath | extend agentMonitoring = case(hasAgent =~ "NotApplicable" or hasAgent =~ "", '', hasAgent =~ "Unhealthy", "notInstalled", "installed") | join kind=leftouter ( securityresources | where type =~ "microsoft.security/pricings" | project subscriptionId, bundleName = tolower(name), freeTrialRemainingTime = properties.freeTrialRemainingTime, pricingTier = tolower(properties.pricingTier) | extend bundlesPricing = pack(bundleName, pricingTier) | summarize subscriptionPricing = make_bag(bundlesPricing) by subscriptionId ) on subscriptionId | extend hasNoSoftwareData = case(array_length(softwareNamesIdentifier) == 1, case(set_has_element(softwareNamesIdentifier, ""), true, false), false) | extend softwareNamesIdentifier = case(hasNoSoftwareData, softwareNamesIdentifier, set_difference(softwareNamesIdentifier, pack_array(""))) | extend AssessmentsHigh = case(isnull(assessmentsSummary.high), 0 , toint(assessmentsSummary.high)) | extend AssessmentsMedium = case(isnull(assessmentsSummary.medium), 0 , toint(assessmentsSummary.medium)) | extend AssessmentsLow = case(isnull(assessmentsSummary.low), 0 , toint(assessmentsSummary.low)) | extend unhealthyAssessmentsCount = AssessmentsHigh + AssessmentsMedium + AssessmentsLow | extend virtualmachines = case(isnull(subscriptionPricing), '' , subscriptionPricing.virtualmachines) | extend virtualmachines = case(virtualmachines == 'free', 'off', 'on') | extend sqlservers = case(isnull(subscriptionPricing), '' , subscriptionPricing.sqlservers) | extend sqlservers = case(sqlservers == 'free', 'off', 'on') | extend kubernetesservice = case(isnull(subscriptionPricing), '' , subscriptionPricing.kubernetesservice) | extend kubernetesservice = case(kubernetesservice == 'free', 'off', 'on') | extend containerregistry = case(isnull(subscriptionPricing), '' , subscriptionPricing.containerregistry) | extend containerregistry = case(containerregistry == 'free', 'off', 'on') | extend connectedcontainerregistry = case(isnull(subscriptionPricing), '' , subscriptionPricing.connectedcontainerregistry) | extend connectedcontainerregistry = case(connectedcontainerregistry == 'free', 'off', 'on') | extend sqlservervirtualmachines = case(isnull(subscriptionPricing), '' , subscriptionPricing.sqlservervirtualmachines) | extend sqlservervirtualmachines = case(sqlservervirtualmachines == 'free', 'off', 'on') | extend appservices = case(isnull(subscriptionPricing), '' , subscriptionPricing.appservices) | extend appservices = case(appservices == 'free', 'off', 'on') | extend storageaccounts = case(isnull(subscriptionPricing), '' , subscriptionPricing.storageaccounts) | extend storageaccounts = case(storageaccounts == 'free', 'off', 'on') | extend keyvaults = case(isnull(subscriptionPricing), '' , subscriptionPricing.keyvaults) | extend keyvaults = case(keyvaults == 'free', 'off', 'on') | extend opensourcerelationaldatabases = case(isnull(subscriptionPricing), '' , subscriptionPricing.opensourcerelationaldatabases) | extend opensourcerelationaldatabases = case(opensourcerelationaldatabases == 'free', 'off', 'on') | extend calculatedSubscriptionPricing = case(resourceType =~ "subscription" and isempty(subscriptionPricing) == false , iff(subscriptionPricing has "free" and subscriptionPricing has "standard", "partial", iff(subscriptionPricing has "free", "off", "on")), "") | extend resourcePricing = case(typeFullPath =~ "microsoft.classiccompute/virtualmachines", virtualmachines, typeFullPath =~ "microsoft.compute/virtualmachines", virtualmachines, typeFullPath =~ "microsoft.hybridcompute/machines", virtualmachines, typeFullPath =~ "microsoft.sql/servers", sqlservers, typeFullPath =~ "microsoft.containerservice/managedclusters", kubernetesservice, typeFullPath =~ "microsoft.kubernetes/connectedclusters", kubernetesservice, typeFullPath =~ "microsoft.containerregistry/registries", containerregistry, typeFullPath =~ "microsoft.security/connectedcontainerregistries", connectedcontainerregistry, typeFullPath =~ "microsoft.sqlvirtualmachine/sqlvirtualmachines", sqlservervirtualmachines, typeFullPath =~ "microsoft.web/sites", appservices, typeFullPath =~ "microsoft.storage/storageaccounts", storageaccounts, typeFullPath =~ "microsoft.compute/virtualmachinescalesets", virtualmachines, typeFullPath =~ "microsoft.keyvault/vaults", keyvaults, typeFullPath =~ "microsoft.dbforpostgresql/servers", opensourcerelationaldatabases, typeFullPath =~ "microsoft.dbformysql/servers", opensourcerelationaldatabases, typeFullPath =~ "microsoft.dbformariadb/servers", opensourcerelationaldatabases, calculatedSubscriptionPricing) | extend pricing = case(resourceType =~ "subscription" , calculatedSubscriptionPricing , resourcePricing) | project resourceType, exemptionType, typeFullPath, resourceId, resourceName, subscriptionId, environment, osType, workspaceName, agentMonitoring, assessmentsIdentifier, assessmentsSummary, subscriptionPricing, unhealthyAssessmentsCount, pricing, softwareNamesIdentifier | extend resourceGroup = tolower(tostring(split(resourceId, "/")[4])) | order by unhealthyAssessmentsCount, subscriptionId, resourceType, resourceId | where isnotempty(resourceId) | extend resourceType = iff(resourceType == 'servers','SQL Server',resourceType) | extend resourceType = iff(resourceType == 'machines','Hybrid Server',resourceType) | summarize on_=countif(pricing == "on"), off_=countif(isempty(pricing)), part_=countif(pricing == "partial") by resourceType | order by on_ desc
CliveWatson
Jul 30, 2021Former Employee
There is a query from the "Inventory Blade" in ASC, you can amend it (I made a start below on a recent project). This is using ARG rather than the REST api directly. You should be able to see the api info if you need to use that.
securityresources
//| where subscriptionId == "< insert you id here >"
| where type =~ "microsoft.security/assessments" or type =~ "microsoft.security/softwareInventories"
| extend assessmentStatusCode = case(type =~ "microsoft.security/assessments", tostring(properties.status.code), "")
| extend severity = case(assessmentStatusCode =~ "unhealthy", tolower(tostring(properties.metadata.severity)), tolower(assessmentStatusCode))
| extend exemptionType = case(tolower(type) != "microsoft.security/assessments","N/A", case(properties.status.cause =~ "exempt", "Yes", "No"))
| extend source = case(type =~ "microsoft.security/assessments", tostring(properties.resourceDetails.Source), "")
| extend resourceId = trim(" ", tolower(tostring(case(source =~ "azure", properties.resourceDetails.Id,
source =~ "aws", properties.resourceDetails.AzureResourceId,
source =~ "gcp", properties.resourceDetails.AzureResourceId,
type =~ "microsoft.security/assessments", extract("^(.+)/providers/Microsoft.Security/assessments/.+$",1,id),extract("^(.+)/providers/Microsoft.Security/softwareInventories/.+$",1,id)))))
| extend resourceName = extract(@"(.+)/(.+)", 2, resourceId)
| extend regexResourceId = extract_all(@"/providers/([^/]+)(?:/([^/]+)/[^/]+(?:/([^/]+)/[^/]+)?)?/([^/]+)/[^/]+$", resourceId)
| extend RegexResourceType = regexResourceId[0]
| extend mainType = RegexResourceType[1], extendedType = RegexResourceType[2], resourceType = RegexResourceType[3]
| extend providerName = RegexResourceType[0],
mainType = case(mainType !~ "", strcat("/",mainType), ""),
extendedType = case(extendedType!~ "", strcat("/",extendedType), ""),
resourceType = case(resourceType!~ "", strcat("/",resourceType), "")
| extend array = split(resourceId, '/')
| extend typeFullPath = case(array_length(array) == 3, 'subscription', strcat(providerName, mainType, extendedType, resourceType))
| extend typeFullPath = case(array_length(array) == 5, 'resourcegroups', typeFullPath)
| extend resourceType = case(typeFullPath =~ 'resourcegroups' or typeFullPath =~ 'subscription', typeFullPath, tolower(trim("/", resourceType)))
| extend assessmentKey = case(type =~ "microsoft.security/assessments", tostring(name), "")
| extend softwareVendorName = case(type =~ "microsoft.security/softwareInventories", tostring(properties.vendor), "")
| extend softwareName = case(type =~ "microsoft.security/softwareInventories", tostring(properties.softwareName), "")
| extend softwareNameIdentifier = case(type =~ "microsoft.security/softwareInventories", strcat(softwareVendorName, ",", softwareName), "")
| extend environment = case(type =~ "microsoft.security/assessments", properties.resourceDetails["Source"], "")
| extend environment = case(environment =~ "onpremise", tolower("Non-Azure"), tolower(environment))
| extend osTypeProperty = properties.additionalData["OS Type"]
| extend osType = case(isnotempty(osTypeProperty), osTypeProperty, "")
| extend hasAgent = case(assessmentKey == "d1db3318-01ff-16de-29eb-28b344515626" or assessmentKey == "45cfe080-ceb1-a91e-9743-71551ed24e94" or assessmentKey == "720a3e77-0b9a-4fa9-98b6-ddf0fd7e32c1" or assessmentKey == "27ac71b1-75c5-41c2-adc2-858f5db45b08", assessmentStatusCode, "")
| extend workspaceAzureResourceId = case(hasAgent !~ "", properties.additionalData["Reporting workspace azure id"], "")
| extend workspaceName = case(workspaceAzureResourceId !~ "", extract(@"(.+)/(.+)", 2, workspaceAzureResourceId), "")
| extend assessmentDisplayName = case(type =~ "microsoft.security/assessments", case(isnotempty(properties.displayName), properties.displayName, properties.metadata.displayName), "")
| extend assessmentIdentifier = case(type =~ "microsoft.security/assessments", strcat(assessmentKey, "," , assessmentDisplayName, ",", severity), "")
| summarize assessmentsCount = count() , assessmentsIdentifier = make_list(assessmentIdentifier), softwareNamesIdentifier = make_list(softwareNameIdentifier), hasAgent = max(hasAgent), workspaceName = max(workspaceName), environment = max(environment), osType = max(osType), exemptionType = max(exemptionType) by resourceId, subscriptionId, resourceName, resourceType, typeFullPath, severity
| extend packAssessments = pack(severity, assessmentsCount)
| summarize assessmentsSummary = make_bag(packAssessments), assessmentsIdentifier = make_set(assessmentsIdentifier), softwareNamesIdentifier = make_set(softwareNamesIdentifier), hasAgent = max(hasAgent), workspaceName= max(workspaceName), environment = max(environment), osType= max(osType), exemptionType = max(exemptionType) by resourceId, subscriptionId, resourceName, resourceType, typeFullPath
| extend agentMonitoring = case(hasAgent =~ "NotApplicable" or hasAgent =~ "", '',
hasAgent =~ "Unhealthy", "notInstalled",
"installed")
| join kind=leftouter (
securityresources
| where type =~ "microsoft.security/pricings"
| project subscriptionId, bundleName = tolower(name), freeTrialRemainingTime = properties.freeTrialRemainingTime, pricingTier = tolower(properties.pricingTier)
| extend bundlesPricing = pack(bundleName, pricingTier)
| summarize subscriptionPricing = make_bag(bundlesPricing) by subscriptionId
) on subscriptionId
| extend hasNoSoftwareData = case(array_length(softwareNamesIdentifier) == 1, case(set_has_element(softwareNamesIdentifier, ""), true, false), false)
| extend softwareNamesIdentifier = case(hasNoSoftwareData, softwareNamesIdentifier, set_difference(softwareNamesIdentifier, pack_array("")))
| extend AssessmentsHigh = case(isnull(assessmentsSummary.high), 0 , toint(assessmentsSummary.high))
| extend AssessmentsMedium = case(isnull(assessmentsSummary.medium), 0 , toint(assessmentsSummary.medium))
| extend AssessmentsLow = case(isnull(assessmentsSummary.low), 0 , toint(assessmentsSummary.low))
| extend unhealthyAssessmentsCount = AssessmentsHigh + AssessmentsMedium + AssessmentsLow
| extend virtualmachines = case(isnull(subscriptionPricing), '' , subscriptionPricing.virtualmachines)
| extend virtualmachines = case(virtualmachines == 'free', 'off', 'on')
| extend sqlservers = case(isnull(subscriptionPricing), '' , subscriptionPricing.sqlservers)
| extend sqlservers = case(sqlservers == 'free', 'off', 'on')
| extend kubernetesservice = case(isnull(subscriptionPricing), '' , subscriptionPricing.kubernetesservice)
| extend kubernetesservice = case(kubernetesservice == 'free', 'off', 'on')
| extend containerregistry = case(isnull(subscriptionPricing), '' , subscriptionPricing.containerregistry)
| extend containerregistry = case(containerregistry == 'free', 'off', 'on')
| extend connectedcontainerregistry = case(isnull(subscriptionPricing), '' , subscriptionPricing.connectedcontainerregistry)
| extend connectedcontainerregistry = case(connectedcontainerregistry == 'free', 'off', 'on')
| extend sqlservervirtualmachines = case(isnull(subscriptionPricing), '' , subscriptionPricing.sqlservervirtualmachines)
| extend sqlservervirtualmachines = case(sqlservervirtualmachines == 'free', 'off', 'on')
| extend appservices = case(isnull(subscriptionPricing), '' , subscriptionPricing.appservices)
| extend appservices = case(appservices == 'free', 'off', 'on')
| extend storageaccounts = case(isnull(subscriptionPricing), '' , subscriptionPricing.storageaccounts)
| extend storageaccounts = case(storageaccounts == 'free', 'off', 'on')
| extend keyvaults = case(isnull(subscriptionPricing), '' , subscriptionPricing.keyvaults)
| extend keyvaults = case(keyvaults == 'free', 'off', 'on')
| extend opensourcerelationaldatabases = case(isnull(subscriptionPricing), '' , subscriptionPricing.opensourcerelationaldatabases)
| extend opensourcerelationaldatabases = case(opensourcerelationaldatabases == 'free', 'off', 'on')
| extend calculatedSubscriptionPricing = case(resourceType =~ "subscription" and isempty(subscriptionPricing) == false , iff(subscriptionPricing has "free" and subscriptionPricing has "standard", "partial", iff(subscriptionPricing has "free", "off", "on")), "")
| extend resourcePricing = case(typeFullPath =~ "microsoft.classiccompute/virtualmachines", virtualmachines, typeFullPath =~ "microsoft.compute/virtualmachines", virtualmachines, typeFullPath =~ "microsoft.hybridcompute/machines", virtualmachines, typeFullPath =~ "microsoft.sql/servers", sqlservers, typeFullPath =~ "microsoft.containerservice/managedclusters", kubernetesservice, typeFullPath =~ "microsoft.kubernetes/connectedclusters", kubernetesservice, typeFullPath =~ "microsoft.containerregistry/registries", containerregistry, typeFullPath =~ "microsoft.security/connectedcontainerregistries", connectedcontainerregistry, typeFullPath =~ "microsoft.sqlvirtualmachine/sqlvirtualmachines", sqlservervirtualmachines, typeFullPath =~ "microsoft.web/sites", appservices, typeFullPath =~ "microsoft.storage/storageaccounts", storageaccounts, typeFullPath =~ "microsoft.compute/virtualmachinescalesets", virtualmachines, typeFullPath =~ "microsoft.keyvault/vaults", keyvaults, typeFullPath =~ "microsoft.dbforpostgresql/servers", opensourcerelationaldatabases, typeFullPath =~ "microsoft.dbformysql/servers", opensourcerelationaldatabases, typeFullPath =~ "microsoft.dbformariadb/servers", opensourcerelationaldatabases, calculatedSubscriptionPricing)
| extend pricing = case(resourceType =~ "subscription" , calculatedSubscriptionPricing , resourcePricing)
| project resourceType, exemptionType, typeFullPath, resourceId, resourceName, subscriptionId, environment, osType, workspaceName, agentMonitoring, assessmentsIdentifier, assessmentsSummary, subscriptionPricing, unhealthyAssessmentsCount, pricing, softwareNamesIdentifier
| extend resourceGroup = tolower(tostring(split(resourceId, "/")[4]))
| order by unhealthyAssessmentsCount, subscriptionId, resourceType, resourceId
| where isnotempty(resourceId)
| extend resourceType = iff(resourceType == 'servers','SQL Server',resourceType)
| extend resourceType = iff(resourceType == 'machines','Hybrid Server',resourceType)
| summarize on_=countif(pricing == "on"), off_=countif(isempty(pricing)), part_=countif(pricing == "partial") by resourceType | order by on_ desc
Anil_Guliyaan
Aug 04, 2021Copper Contributor
- Anil_GuliyaanAug 05, 2021Copper ContributorThanks CliveWatson ,
I am able to use ARG query through API calls. - CliveWatsonAug 04, 2021Former EmployeeARG is using the REST Api (under the covers), but you are using KQL in Azure Resource Graph(ARG). If you want to use the REST Api, you need to use a tools like Postman or even a Azure Monitor Workbook that can run KQL, ARG and ARM (for REST api queries). ARG supports a subset of the full REST api in Azure, so you may be able to get the data you need with ARG or maybe need to use ARG and api calls.