├── README.MD ├── armtemplates ├── linux.json ├── linuxwindows.json └── windows.json ├── gallerytemplates ├── linux.json ├── linuxwindows.json └── windows.json └── images ├── 2019-06-26_11-24-50.png ├── 2019-06-26_11-42-17.gif ├── 2019-06-26_12-46-54.png ├── 2020-02-11_11-20-09.png ├── 2020-02-11_11-20-25.png ├── 2020-02-11_11-21-10.png └── 2020-02-11_11-21-36.png /README.MD: -------------------------------------------------------------------------------- 1 | # Azure Monitor Update Management Patch Compliance Workbooks 2 | 3 | The purpose of these Azure Monitor Workbooks is to provide patch compliance reporting for multiple Log Analytics workspaces. 4 | 5 | To use them you need: 6 | - Log Analytics workspace 7 | - Azure Automation account 8 | - Update Management Solution 9 | - Azure Monitor Workbooks 10 | 11 | The Log Analyitcs workspace and Azure Automation account need to be linked together. 12 | 13 | ## Related blog post 14 | https://www.systemcenterautomation.com/2019/06/azure-automation-update-management-workbook/ 15 | 16 | ## Install 17 | You should now be able to drag and drop the workbook into your environment. Because workspace is parameterized to pull in all workspaces from all subscriptions. 18 | 19 | 20 | ## Screen Grabs 21 | Windows example 22 | ![image](./images/2020-02-11_11-20-09.png) 23 | 24 | Linux and Windows example 25 | 26 | ![image](./images/2020-02-11_11-21-10.png) 27 | 28 | ![image](./images/2020-02-11_11-21-36.png) 29 | 30 | 31 | 32 | 33 | ## GIF Output 34 | ![image](./images/2019-06-26_11-42-17.gif) 35 | 36 | ## Improvements 37 | 38 | Below are some improvements I will make when available or as time permits. 39 | 40 | 41 | - Heatmap for ScopedtoSolution, at present you can set a heatmap for boolean value, but it doesn't work unless you change true and false to 1 and 0. 42 | - get LastUpdateAgentseenTime working 43 | - Updates to the linuxwindows gallerytemplate to include two new tabs. One tab for Computers querying all computer related items. One tab for alerts querying all related metrics to the update management solution in the automation account. -------------------------------------------------------------------------------- /armtemplates/linux.json: -------------------------------------------------------------------------------- 1 | { 2 | "contentVersion": "1.0.0.0", 3 | "parameters": { 4 | "workbookDisplayName": { 5 | "type": "string", 6 | "defaultValue": "linux updates", 7 | "metadata": { 8 | "description": "The friendly name for the workbook that is used in the Gallery or Saved List. This name must be unique within a resource group." 9 | } 10 | }, 11 | "workbookType": { 12 | "type": "string", 13 | "defaultValue": "workbook", 14 | "metadata": { 15 | "description": "The gallery that the workbook will been shown under. Supported values include workbook, tsg, etc. Usually, this is 'workbook'" 16 | } 17 | }, 18 | "workbookSourceId": { 19 | "type": "string", 20 | "defaultValue": "Azure Monitor", 21 | "metadata": { 22 | "description": "The id of resource instance to which the workbook will be associated" 23 | } 24 | }, 25 | "workbookId": { 26 | "type": "string", 27 | "defaultValue": "[newGuid()]", 28 | "metadata": { 29 | "description": "The unique guid for this workbook instance" 30 | } 31 | } 32 | }, 33 | "resources": [ 34 | { 35 | "name": "[parameters('workbookId')]", 36 | "type": "microsoft.insights/workbooks", 37 | "location": "[resourceGroup().location]", 38 | "apiVersion": "2018-06-17-preview", 39 | "dependsOn": [], 40 | "kind": "shared", 41 | "properties": { 42 | "displayName": "[parameters('workbookDisplayName')]", 43 | "serializedData": "{\"version\":\"Notebook/1.0\",\"items\":[{\"type\":1,\"content\":\"{\\\"json\\\":\\\"\\\"}\",\"customWidth\":\"100\",\"name\":\"text - 5\"},{\"type\":9,\"content\":\"{\\\"version\\\":\\\"KqlParameterItem/1.0\\\",\\\"crossComponentResources\\\":[\\\"value::all\\\"],\\\"parameters\\\":[{\\\"id\\\":\\\"f8d6705a-e284-4077-8113-aae1038a6b7c\\\",\\\"version\\\":\\\"KqlParameterItem/1.0\\\",\\\"name\\\":\\\"Workspaces\\\",\\\"type\\\":5,\\\"isRequired\\\":true,\\\"multiSelect\\\":true,\\\"quote\\\":\\\"'\\\",\\\"delimiter\\\":\\\",\\\",\\\"query\\\":\\\"where type =~ 'microsoft.operationalinsights/workspaces'\\\\r\\\\n| summarize by id, name\\\",\\\"crossComponentResources\\\":[\\\"value::all\\\"],\\\"value\\\":[\\\"value::all\\\"],\\\"typeSettings\\\":{\\\"additionalResourceOptions\\\":[\\\"value::1\\\",\\\"value::all\\\"]},\\\"queryType\\\":1,\\\"resourceType\\\":\\\"microsoft.resourcegraph/resources\\\"}],\\\"style\\\":\\\"pills\\\",\\\"queryType\\\":1,\\\"resourceType\\\":\\\"microsoft.resourcegraph/resources\\\"}\",\"name\":\"parameters - 11\"},{\"type\":1,\"content\":\"{\\\"json\\\":\\\"# Azure Automation Linux Update Summary for All Subscriptions\\\\r\\\\n\\\\r\\\\nThis workbook can query multiple Log Analytics Workspaces. The Azure Automation Update Management solution needs to be linked to every Log Analytics Workspaces you wish to use it with.\\\"}\",\"name\":\"text - 6\"},{\"type\":3,\"content\":\"{\\\"version\\\":\\\"KqlItem/1.0\\\",\\\"query\\\":\\\"Update\\\\r\\\\n| where TimeGenerated>ago(5h) and OSType==\\\\\\\"Linux\\\\\\\"\\\\r\\\\n| summarize hint.strategy=partitioned arg_max(TimeGenerated, UpdateState, Classification) by Computer, SourceComputerId, Product, ProductArch\\\\r\\\\n| where UpdateState=~\\\\\\\"Needed\\\\\\\"\\\\r\\\\n| summarize by Product, ProductArch, Classification, Computer\\\\r\\\\n| summarize count(Classification) by Computer\\\",\\\"size\\\":2,\\\"queryType\\\":0,\\\"resourceType\\\":\\\"microsoft.operationalinsights/workspaces\\\",\\\"crossComponentResources\\\":[\\\"{Workspaces}\\\"],\\\"visualization\\\":\\\"piechart\\\",\\\"tileSettings\\\":{\\\"showBorder\\\":false,\\\"titleContent\\\":{\\\"columnMatch\\\":\\\"Classification\\\",\\\"formatter\\\":1},\\\"leftContent\\\":{\\\"columnMatch\\\":\\\"UpdatesNeeded\\\",\\\"formatter\\\":12,\\\"formatOptions\\\":{\\\"palette\\\":\\\"auto\\\"},\\\"numberFormat\\\":{\\\"unit\\\":17,\\\"options\\\":{\\\"maximumSignificantDigits\\\":3,\\\"maximumFractionDigits\\\":2}}}}}\",\"customWidth\":\"50\",\"name\":\"query - 0\"},{\"type\":3,\"content\":\"{\\\"version\\\":\\\"KqlItem/1.0\\\",\\\"query\\\":\\\"Update\\\\r\\\\n| where TimeGenerated>ago(5h) and OSType==\\\\\\\"Linux\\\\\\\"\\\\r\\\\n| summarize hint.strategy=partitioned arg_max(TimeGenerated, UpdateState, Classification) by Computer, SourceComputerId, Product, ProductArch\\\\r\\\\n| where UpdateState=~\\\\\\\"Needed\\\\\\\"\\\\r\\\\n| summarize by Product, ProductArch, Classification, Computer\\\\r\\\\n| summarize count(Classification) by Classification\\\",\\\"size\\\":2,\\\"queryType\\\":0,\\\"resourceType\\\":\\\"microsoft.operationalinsights/workspaces\\\",\\\"crossComponentResources\\\":[\\\"{Workspaces}\\\"],\\\"visualization\\\":\\\"piechart\\\",\\\"chartSettings\\\":{\\\"seriesLabelSettings\\\":[{\\\"seriesName\\\":\\\"Others\\\",\\\"color\\\":\\\"purple\\\"},{\\\"seriesName\\\":\\\"Security Updates\\\",\\\"color\\\":\\\"redBright\\\"}]}}\",\"customWidth\":\"50\",\"name\":\"top five Computers Needing Updates\"},{\"type\":1,\"content\":\"{\\\"json\\\":\\\"## Update Count by Classification\\\"}\",\"customWidth\":\"50\",\"name\":\"text - 7\"},{\"type\":1,\"content\":\"{\\\"json\\\":\\\"## Top 5 Linux Machines by Update Count\\\"}\",\"customWidth\":\"50\",\"name\":\"text - 8\"},{\"type\":3,\"content\":\"{\\\"version\\\":\\\"KqlItem/1.0\\\",\\\"query\\\":\\\"Heartbeat\\\\r\\\\n| where TimeGenerated>ago(12h) and OSType==\\\\\\\"Linux\\\\\\\" and notempty(Computer)\\\\r\\\\n| summarize arg_max(TimeGenerated, Solutions, Computer, ResourceId, ComputerEnvironment, VMUUID) by SourceComputerId\\\\r\\\\n| where Solutions has \\\\\\\"updates\\\\\\\"\\\\r\\\\n| extend vmuuId=VMUUID, azureResourceId=ResourceId, osType=1, environment=iff(ComputerEnvironment=~\\\\\\\"Azure\\\\\\\", 1, 2), scopedToUpdatesSolution=true, lastUpdateAgentSeenTime=\\\\\\\"\\\\\\\"\\\\r\\\\n| join kind=leftouter\\\\r\\\\n(\\\\r\\\\n Update\\\\r\\\\n | where TimeGenerated>ago(5h) and OSType==\\\\\\\"Linux\\\\\\\" and SourceComputerId in ((Heartbeat\\\\r\\\\n | where TimeGenerated>ago(12h) and OSType==\\\\\\\"Linux\\\\\\\" and notempty(Computer)\\\\r\\\\n | summarize arg_max(TimeGenerated, Solutions) by SourceComputerId\\\\r\\\\n | where Solutions has \\\\\\\"updates\\\\\\\"\\\\r\\\\n | distinct SourceComputerId))\\\\r\\\\n | summarize hint.strategy=partitioned arg_max(TimeGenerated, UpdateState, Classification, Product, Computer, ComputerEnvironment) by SourceComputerId, Product, ProductArch\\\\r\\\\n | summarize Computer=any(Computer), ComputerEnvironment=any(ComputerEnvironment), missingCriticalUpdatesCount=countif(Classification has \\\\\\\"Critical\\\\\\\" and UpdateState=~\\\\\\\"Needed\\\\\\\"), missingSecurityUpdatesCount=countif(Classification has \\\\\\\"Security\\\\\\\" and UpdateState=~\\\\\\\"Needed\\\\\\\"), missingOtherUpdatesCount=countif(Classification !has \\\\\\\"Critical\\\\\\\" and Classification !has \\\\\\\"Security\\\\\\\" and UpdateState=~\\\\\\\"Needed\\\\\\\"), lastAssessedTime=max(TimeGenerated), lastUpdateAgentSeenTime=\\\\\\\"\\\\\\\" by SourceComputerId\\\\r\\\\n | extend compliance=iff(missingCriticalUpdatesCount > 0 or missingSecurityUpdatesCount > 0, 2, 1)\\\\r\\\\n | extend ComplianceOrder=iff(missingCriticalUpdatesCount > 0 or missingSecurityUpdatesCount > 0 or missingOtherUpdatesCount > 0, 1, 3)\\\\r\\\\n)\\\\r\\\\non SourceComputerId\\\\r\\\\n| project displayName=Computer, scopedToUpdatesSolution=true, CriticalUpdates=coalesce(missingCriticalUpdatesCount, -1), SecurityUpdates=coalesce(missingSecurityUpdatesCount, -1), OtherUpdates=coalesce(missingOtherUpdatesCount, -1), compliance=coalesce(compliance, 4), osType=1, environment=iff(ComputerEnvironment=~\\\\\\\"Azure\\\\\\\", 1, 2), lastAssessedTime, lastUpdateAgentSeenTime\\\\r\\\\n| extend osType = replace(@\\\\\\\"1\\\\\\\", @\\\\\\\"Linux\\\\\\\", tostring(osType))\\\\r\\\\n| extend environment = replace(@\\\\\\\"2\\\\\\\", @\\\\\\\"Non-Azure\\\\\\\", tostring(environment))\\\\r\\\\n| extend environment = replace(@\\\\\\\"1\\\\\\\", @\\\\\\\"Azure\\\\\\\", tostring(environment))\\\",\\\"size\\\":0,\\\"exportFieldName\\\":\\\"displayName\\\",\\\"exportParameterName\\\":\\\"Computer\\\",\\\"queryType\\\":0,\\\"resourceType\\\":\\\"microsoft.operationalinsights/workspaces\\\",\\\"crossComponentResources\\\":[\\\"{Workspaces}\\\"],\\\"visualization\\\":\\\"table\\\",\\\"gridSettings\\\":{\\\"formatters\\\":[{\\\"columnMatch\\\":\\\"displayName\\\",\\\"formatter\\\":0,\\\"formatOptions\\\":{\\\"showIcon\\\":true}},{\\\"columnMatch\\\":\\\"scopedToUpdatesSolution\\\",\\\"formatter\\\":0,\\\"formatOptions\\\":{\\\"showIcon\\\":true}},{\\\"columnMatch\\\":\\\"CriticalUpdates\\\",\\\"formatter\\\":8,\\\"formatOptions\\\":{\\\"min\\\":0,\\\"max\\\":1,\\\"palette\\\":\\\"greenRed\\\",\\\"showIcon\\\":true}},{\\\"columnMatch\\\":\\\"SecurityUpdates\\\",\\\"formatter\\\":8,\\\"formatOptions\\\":{\\\"min\\\":0,\\\"max\\\":5,\\\"palette\\\":\\\"greenRed\\\",\\\"showIcon\\\":true}},{\\\"columnMatch\\\":\\\"OtherUpdates\\\",\\\"formatter\\\":8,\\\"formatOptions\\\":{\\\"min\\\":0,\\\"max\\\":5,\\\"palette\\\":\\\"greenRed\\\",\\\"showIcon\\\":true}},{\\\"columnMatch\\\":\\\"compliance\\\",\\\"formatter\\\":8,\\\"formatOptions\\\":{\\\"min\\\":1,\\\"max\\\":2,\\\"palette\\\":\\\"greenRed\\\",\\\"showIcon\\\":true}},{\\\"columnMatch\\\":\\\"osType\\\",\\\"formatter\\\":0,\\\"formatOptions\\\":{\\\"showIcon\\\":true}},{\\\"columnMatch\\\":\\\"Environment\\\",\\\"formatter\\\":0,\\\"formatOptions\\\":{\\\"showIcon\\\":true}},{\\\"columnMatch\\\":\\\"lastAssessedTime\\\",\\\"formatter\\\":0,\\\"formatOptions\\\":{\\\"showIcon\\\":true}},{\\\"columnMatch\\\":\\\"lastUpdateAgentSeenTime\\\",\\\"formatter\\\":0,\\\"formatOptions\\\":{\\\"showIcon\\\":true}}]}}\",\"name\":\"query - 2\"},{\"type\":9,\"content\":\"{\\\"version\\\":\\\"KqlParameterItem/1.0\\\",\\\"parameters\\\":[],\\\"style\\\":\\\"pills\\\",\\\"queryType\\\":0,\\\"resourceType\\\":\\\"microsoft.insights/components\\\"}\",\"name\":\"parameters - 3\"},{\"type\":3,\"content\":\"{\\\"version\\\":\\\"KqlItem/1.0\\\",\\\"query\\\":\\\"Update\\\\r\\\\n| where TimeGenerated>ago(5h) and OSType==\\\\\\\"Linux\\\\\\\" and Computer == \\\\\\\"{Computer}\\\\\\\"\\\\r\\\\n| summarize hint.strategy=partitioned arg_max(TimeGenerated, UpdateState, Classification, BulletinUrl, BulletinID) by Computer, SourceComputerId, Product, ProductArch\\\\r\\\\n| where UpdateState=~\\\\\\\"Needed\\\\\\\"\\\\r\\\\n| project-away UpdateState, TimeGenerated\\\\r\\\\n| summarize computersCount=dcount(SourceComputerId, 2), ClassificationWeight=max(iff(Classification has \\\\\\\"Critical\\\\\\\", 4, iff(Classification has \\\\\\\"Security\\\\\\\", 2, 1))) by Computer, id=strcat(Product, \\\\\\\"_\\\\\\\", ProductArch), displayName=Product, productArch=ProductArch, classification=Classification, InformationId=BulletinID, InformationUrl=tostring(split(BulletinUrl, \\\\\\\";\\\\\\\", 0)[0]), osType=1\\\\r\\\\n| sort by ClassificationWeight desc, computersCount desc, displayName asc\\\\r\\\\n| extend informationLink=(iff(isnotempty(InformationId) and isnotempty(InformationUrl), toobject(strcat('{ \\\\\\\"uri\\\\\\\": \\\\\\\"', InformationUrl, '\\\\\\\", \\\\\\\"text\\\\\\\": \\\\\\\"', InformationId, '\\\\\\\", \\\\\\\"target\\\\\\\": \\\\\\\"blank\\\\\\\" }')), toobject('')))\\\\r\\\\n| project-away ClassificationWeight, InformationId, InformationUrl\\\",\\\"size\\\":0,\\\"queryType\\\":0,\\\"resourceType\\\":\\\"microsoft.operationalinsights/workspaces\\\",\\\"crossComponentResources\\\":[\\\"{Workspaces}\\\"],\\\"gridSettings\\\":{\\\"formatters\\\":[{\\\"columnMatch\\\":\\\"Computer\\\",\\\"formatter\\\":0,\\\"formatOptions\\\":{\\\"showIcon\\\":true}},{\\\"columnMatch\\\":\\\"id\\\",\\\"formatter\\\":0,\\\"formatOptions\\\":{\\\"showIcon\\\":true}},{\\\"columnMatch\\\":\\\"displayName\\\",\\\"formatter\\\":0,\\\"formatOptions\\\":{\\\"showIcon\\\":true}},{\\\"columnMatch\\\":\\\"productArch\\\",\\\"formatter\\\":0,\\\"formatOptions\\\":{\\\"showIcon\\\":true}},{\\\"columnMatch\\\":\\\"classification\\\",\\\"formatter\\\":18,\\\"formatOptions\\\":{\\\"showIcon\\\":true,\\\"thresholdsOptions\\\":\\\"colors\\\",\\\"thresholdsGrid\\\":[{\\\"operator\\\":\\\"==\\\",\\\"thresholdValue\\\":\\\"Security Updates\\\",\\\"representation\\\":\\\"redBright\\\",\\\"text\\\":\\\"{0}{1}\\\"},{\\\"operator\\\":\\\"==\\\",\\\"thresholdValue\\\":\\\"Others\\\",\\\"representation\\\":\\\"purple\\\",\\\"text\\\":\\\"{0}{1}\\\"},{\\\"operator\\\":\\\"Default\\\",\\\"thresholdValue\\\":null,\\\"representation\\\":\\\"blue\\\",\\\"text\\\":\\\"{0}{1}\\\"}]}},{\\\"columnMatch\\\":\\\"osType\\\",\\\"formatter\\\":0,\\\"formatOptions\\\":{\\\"showIcon\\\":true}},{\\\"columnMatch\\\":\\\"computersCount\\\",\\\"formatter\\\":0,\\\"formatOptions\\\":{\\\"showIcon\\\":true}},{\\\"columnMatch\\\":\\\"informationLink\\\",\\\"formatter\\\":0,\\\"formatOptions\\\":{\\\"showIcon\\\":true}}]}}\",\"name\":\"query - 4\"}],\"isLocked\":false}", 44 | "version": "1.0", 45 | "sourceId": "[parameters('workbookSourceId')]", 46 | "category": "[parameters('workbookType')]" 47 | } 48 | } 49 | ], 50 | "outputs": { 51 | "workbookId": { 52 | "type": "string", 53 | "value": "[resourceId( 'microsoft.insights/workbooks', parameters('workbookId'))]" 54 | } 55 | }, 56 | "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#" 57 | } -------------------------------------------------------------------------------- /armtemplates/linuxwindows.json: -------------------------------------------------------------------------------- 1 | { 2 | "contentVersion": "1.0.0.0", 3 | "parameters": { 4 | "workbookDisplayName": { 5 | "type": "string", 6 | "defaultValue": "Updates", 7 | "metadata": { 8 | "description": "The friendly name for the workbook that is used in the Gallery or Saved List. This name must be unique within a resource group." 9 | } 10 | }, 11 | "workbookType": { 12 | "type": "string", 13 | "defaultValue": "workbook", 14 | "metadata": { 15 | "description": "The gallery that the workbook will been shown under. Supported values include workbook, tsg, etc. Usually, this is 'workbook'" 16 | } 17 | }, 18 | "workbookSourceId": { 19 | "type": "string", 20 | "defaultValue": "Azure Monitor", 21 | "metadata": { 22 | "description": "The id of resource instance to which the workbook will be associated" 23 | } 24 | }, 25 | "workbookId": { 26 | "type": "string", 27 | "defaultValue": "[newGuid()]", 28 | "metadata": { 29 | "description": "The unique guid for this workbook instance" 30 | } 31 | } 32 | }, 33 | "resources": [ 34 | { 35 | "name": "[parameters('workbookId')]", 36 | "type": "microsoft.insights/workbooks", 37 | "location": "[resourceGroup().location]", 38 | "apiVersion": "2018-06-17-preview", 39 | "dependsOn": [], 40 | "kind": "shared", 41 | "properties": { 42 | "displayName": "[parameters('workbookDisplayName')]", 43 | "serializedData": "{\"version\":\"Notebook/1.0\",\"items\":[{\"type\":1,\"content\":\"{\\\"json\\\":\\\"\\\"}\",\"customWidth\":\"100\",\"name\":\"text - 5\"},{\"type\":9,\"content\":\"{\\\"version\\\":\\\"KqlParameterItem/1.0\\\",\\\"crossComponentResources\\\":[\\\"value::all\\\"],\\\"parameters\\\":[{\\\"id\\\":\\\"f8d6705a-e284-4077-8113-aae1038a6b7c\\\",\\\"version\\\":\\\"KqlParameterItem/1.0\\\",\\\"name\\\":\\\"Workspaces\\\",\\\"type\\\":5,\\\"isRequired\\\":true,\\\"multiSelect\\\":true,\\\"quote\\\":\\\"'\\\",\\\"delimiter\\\":\\\",\\\",\\\"query\\\":\\\"where type =~ 'microsoft.operationalinsights/workspaces'\\\\r\\\\n| summarize by id, name\\\",\\\"crossComponentResources\\\":[\\\"value::all\\\"],\\\"value\\\":[\\\"value::all\\\"],\\\"typeSettings\\\":{\\\"additionalResourceOptions\\\":[\\\"value::1\\\",\\\"value::all\\\"]},\\\"queryType\\\":1,\\\"resourceType\\\":\\\"microsoft.resourcegraph/resources\\\"}],\\\"style\\\":\\\"pills\\\",\\\"queryType\\\":1,\\\"resourceType\\\":\\\"microsoft.resourcegraph/resources\\\"}\",\"name\":\"parameters - 11\"},{\"type\":1,\"content\":\"{\\\"json\\\":\\\"# Azure Automation Windows and Linux Update Summary for All Subscriptions\\\\r\\\\n\\\\r\\\\nThis workbook can query multiple Log Analytics Workspaces. The Azure Automation Update Management solution needs to be linked to every Log Analytics Workspaces you wish to use it with.\\\"}\",\"name\":\"text - 6\"},{\"type\":1,\"content\":\"{\\\"json\\\":\\\"## Windows Updates Needed by Classification\\\"}\",\"customWidth\":\"50\",\"name\":\"text - 7\"},{\"type\":1,\"content\":\"{\\\"json\\\":\\\"## Linux Updates Needed by Classification\\\"}\",\"customWidth\":\"50\",\"name\":\"text - 8\"},{\"type\":3,\"content\":\"{\\\"version\\\":\\\"KqlItem/1.0\\\",\\\"query\\\":\\\"Update\\\\r\\\\n| where TimeGenerated>ago(14h) and OSType!=\\\\\\\"Linux\\\\\\\" and (Optional==false or Classification has \\\\\\\"Critical\\\\\\\" or Classification has \\\\\\\"Security\\\\\\\") and SourceComputerId in ((Heartbeat\\\\r\\\\n| where TimeGenerated>ago(12h) and OSType=~\\\\\\\"Windows\\\\\\\" and notempty(Computer)\\\\r\\\\n| summarize arg_max(TimeGenerated, Solutions) by SourceComputerId\\\\r\\\\n| where Solutions has \\\\\\\"updates\\\\\\\" | distinct SourceComputerId))\\\\r\\\\n| summarize hint.strategy=partitioned arg_max(TimeGenerated, *) by Computer, SourceComputerId, UpdateID\\\\r\\\\n| where UpdateState=~\\\\\\\"Needed\\\\\\\" and Approved!=false\\\\r\\\\n| summarize UpdatesNeeded=count(Classification) by Classification\\\",\\\"size\\\":2,\\\"queryType\\\":0,\\\"resourceType\\\":\\\"microsoft.operationalinsights/workspaces\\\",\\\"crossComponentResources\\\":[\\\"{Workspaces}\\\"],\\\"visualization\\\":\\\"piechart\\\",\\\"tileSettings\\\":{\\\"showBorder\\\":false,\\\"titleContent\\\":{\\\"columnMatch\\\":\\\"Classification\\\",\\\"formatter\\\":1},\\\"leftContent\\\":{\\\"columnMatch\\\":\\\"UpdatesNeeded\\\",\\\"formatter\\\":12,\\\"formatOptions\\\":{\\\"palette\\\":\\\"auto\\\"},\\\"numberFormat\\\":{\\\"unit\\\":17,\\\"options\\\":{\\\"maximumSignificantDigits\\\":3,\\\"maximumFractionDigits\\\":2}}}},\\\"chartSettings\\\":{\\\"seriesLabelSettings\\\":[{\\\"seriesName\\\":\\\"Security Updates\\\",\\\"color\\\":\\\"redBright\\\"},{\\\"seriesName\\\":\\\"Updates\\\",\\\"color\\\":\\\"orange\\\"},{\\\"seriesName\\\":\\\"Definition Updates\\\",\\\"color\\\":\\\"yellow\\\"},{\\\"seriesName\\\":\\\"Update Rollups\\\",\\\"color\\\":\\\"purple\\\"},{\\\"seriesName\\\":\\\"Critical Updates\\\",\\\"color\\\":\\\"red\\\"}]}}\",\"customWidth\":\"50\",\"name\":\"query - 0\",\"styleSettings\":{\"maxWidth\":\"50\"}},{\"type\":3,\"content\":\"{\\\"version\\\":\\\"KqlItem/1.0\\\",\\\"query\\\":\\\"Update\\\\r\\\\n| where TimeGenerated>ago(5h) and OSType==\\\\\\\"Linux\\\\\\\"\\\\r\\\\n| summarize hint.strategy=partitioned arg_max(TimeGenerated, UpdateState, Classification) by Computer, SourceComputerId, Product, ProductArch\\\\r\\\\n| where UpdateState=~\\\\\\\"Needed\\\\\\\"\\\\r\\\\n| summarize by Product, ProductArch, Classification, Computer\\\\r\\\\n| summarize count(Classification) by Classification\\\",\\\"size\\\":2,\\\"queryType\\\":0,\\\"resourceType\\\":\\\"microsoft.operationalinsights/workspaces\\\",\\\"crossComponentResources\\\":[\\\"{Workspaces}\\\"],\\\"visualization\\\":\\\"piechart\\\",\\\"chartSettings\\\":{\\\"seriesLabelSettings\\\":[{\\\"seriesName\\\":\\\"Others\\\",\\\"color\\\":\\\"purple\\\"},{\\\"seriesName\\\":\\\"Security Updates\\\",\\\"color\\\":\\\"redBright\\\"}]}}\",\"customWidth\":\"50\",\"name\":\"top five Computers Needing Updates\",\"styleSettings\":{\"maxWidth\":\"50\"}},{\"type\":1,\"content\":\"{\\\"json\\\":\\\"## Heatmap of Update Summary by Computer\\\\r\\\\n\\\\r\\\\nThis section is dynamic, by selecting a row that row's Computer name will be exported to populate Updates needed by Server\\\"}\",\"name\":\"text - 9\"},{\"type\":3,\"content\":\"{\\\"version\\\":\\\"KqlItem/1.0\\\",\\\"query\\\":\\\"Heartbeat\\\\r\\\\n| where TimeGenerated>ago(12h) and OSType==\\\\\\\"Linux\\\\\\\" and notempty(Computer)\\\\r\\\\n| summarize arg_max(TimeGenerated, Solutions, Computer, ResourceId, ComputerEnvironment, VMUUID) by SourceComputerId\\\\r\\\\n| where Solutions has \\\\\\\"updates\\\\\\\"\\\\r\\\\n| extend vmuuId=VMUUID, azureResourceId=ResourceId, osType=1, environment=iff(ComputerEnvironment=~\\\\\\\"Azure\\\\\\\", 1, 2), scopedToUpdatesSolution=true, lastUpdateAgentSeenTime=\\\\\\\"\\\\\\\"\\\\r\\\\n| join kind=leftouter\\\\r\\\\n(\\\\r\\\\n Update\\\\r\\\\n | where TimeGenerated>ago(5h) and OSType==\\\\\\\"Linux\\\\\\\" and SourceComputerId in ((Heartbeat\\\\r\\\\n | where TimeGenerated>ago(12h) and OSType==\\\\\\\"Linux\\\\\\\" and notempty(Computer)\\\\r\\\\n | summarize arg_max(TimeGenerated, Solutions) by SourceComputerId\\\\r\\\\n | where Solutions has \\\\\\\"updates\\\\\\\"\\\\r\\\\n | distinct SourceComputerId))\\\\r\\\\n | summarize hint.strategy=partitioned arg_max(TimeGenerated, UpdateState, Classification, Product, Computer, ComputerEnvironment) by SourceComputerId, Product, ProductArch\\\\r\\\\n | summarize Computer=any(Computer), ComputerEnvironment=any(ComputerEnvironment), missingCriticalUpdatesCount=countif(Classification has \\\\\\\"Critical\\\\\\\" and UpdateState=~\\\\\\\"Needed\\\\\\\"), missingSecurityUpdatesCount=countif(Classification has \\\\\\\"Security\\\\\\\" and UpdateState=~\\\\\\\"Needed\\\\\\\"), missingOtherUpdatesCount=countif(Classification !has \\\\\\\"Critical\\\\\\\" and Classification !has \\\\\\\"Security\\\\\\\" and UpdateState=~\\\\\\\"Needed\\\\\\\"), lastAssessedTime=max(TimeGenerated), lastUpdateAgentSeenTime=\\\\\\\"\\\\\\\" by SourceComputerId\\\\r\\\\n | extend compliance=iff(missingCriticalUpdatesCount > 0 or missingSecurityUpdatesCount > 0, 2, 1)\\\\r\\\\n | extend ComplianceOrder=iff(missingCriticalUpdatesCount > 0 or missingSecurityUpdatesCount > 0 or missingOtherUpdatesCount > 0, 1, 3)\\\\r\\\\n)\\\\r\\\\non SourceComputerId\\\\r\\\\n| project id=SourceComputerId, displayName=Computer, sourceComputerId=SourceComputerId, scopedToUpdatesSolution=true, missingCriticalUpdatesCount=coalesce(missingCriticalUpdatesCount, -1), missingSecurityUpdatesCount=coalesce(missingSecurityUpdatesCount, -1), missingOtherUpdatesCount=coalesce(missingOtherUpdatesCount, -1), compliance=coalesce(compliance, 4), lastAssessedTime, lastUpdateAgentSeenTime, osType=1, environment=iff(ComputerEnvironment=~\\\\\\\"Azure\\\\\\\", 1, 2), ComplianceOrder=coalesce(ComplianceOrder, 2)\\\\r\\\\n| union(Heartbeat\\\\r\\\\n| where TimeGenerated>ago(12h) and OSType=~\\\\\\\"Windows\\\\\\\" and notempty(Computer)\\\\r\\\\n| summarize arg_max(TimeGenerated, Solutions, Computer, ResourceId, ComputerEnvironment, VMUUID) by SourceComputerId\\\\r\\\\n| where Solutions has \\\\\\\"updates\\\\\\\"\\\\r\\\\n| extend vmuuId=VMUUID, azureResourceId=ResourceId, osType=2, environment=iff(ComputerEnvironment=~\\\\\\\"Azure\\\\\\\", 1, 2), scopedToUpdatesSolution=true, lastUpdateAgentSeenTime=\\\\\\\"\\\\\\\"\\\\r\\\\n| join kind=leftouter\\\\r\\\\n(\\\\r\\\\n Update\\\\r\\\\n | where TimeGenerated>ago(14h) and OSType!=\\\\\\\"Linux\\\\\\\" and SourceComputerId in ((Heartbeat\\\\r\\\\n | where TimeGenerated>ago(12h) and OSType=~\\\\\\\"Windows\\\\\\\" and notempty(Computer)\\\\r\\\\n | summarize arg_max(TimeGenerated, Solutions) by SourceComputerId\\\\r\\\\n | where Solutions has \\\\\\\"updates\\\\\\\"\\\\r\\\\n | distinct SourceComputerId))\\\\r\\\\n | summarize hint.strategy=partitioned arg_max(TimeGenerated, UpdateState, Classification, Title, Optional, Approved, Computer, ComputerEnvironment) by Computer, SourceComputerId, UpdateID\\\\r\\\\n | summarize Computer=any(Computer), ComputerEnvironment=any(ComputerEnvironment), missingCriticalUpdatesCount=countif(Classification has \\\\\\\"Critical\\\\\\\" and UpdateState=~\\\\\\\"Needed\\\\\\\" and Approved!=false), missingSecurityUpdatesCount=countif(Classification has \\\\\\\"Security\\\\\\\" and UpdateState=~\\\\\\\"Needed\\\\\\\" and Approved!=false), missingOtherUpdatesCount=countif(Classification !has \\\\\\\"Critical\\\\\\\" and Classification !has \\\\\\\"Security\\\\\\\" and UpdateState=~\\\\\\\"Needed\\\\\\\" and Optional==false and Approved!=false), lastAssessedTime=max(TimeGenerated), lastUpdateAgentSeenTime=\\\\\\\"\\\\\\\" by SourceComputerId\\\\r\\\\n | extend compliance=iff(missingCriticalUpdatesCount > 0 or missingSecurityUpdatesCount > 0, 2, 1)\\\\r\\\\n | extend ComplianceOrder=iff(missingCriticalUpdatesCount > 0 or missingSecurityUpdatesCount > 0 or missingOtherUpdatesCount > 0, 1, 3)\\\\r\\\\n)\\\\r\\\\non SourceComputerId\\\\r\\\\n| project id=SourceComputerId, displayName=Computer, sourceComputerId=SourceComputerId, scopedToUpdatesSolution=true, missingCriticalUpdatesCount=coalesce(missingCriticalUpdatesCount, -1), missingSecurityUpdatesCount=coalesce(missingSecurityUpdatesCount, -1), missingOtherUpdatesCount=coalesce(missingOtherUpdatesCount, -1), compliance=coalesce(compliance, 4), lastAssessedTime, lastUpdateAgentSeenTime, osType=2, environment=iff(ComputerEnvironment=~\\\\\\\"Azure\\\\\\\", 1, 2), ComplianceOrder=coalesce(ComplianceOrder, 2) )\\\\r\\\\n| order by ComplianceOrder asc, missingCriticalUpdatesCount desc, missingSecurityUpdatesCount desc, missingOtherUpdatesCount desc, displayName asc\\\\r\\\\n| project displayName, scopedToUpdatesSolution, CriticalUpdates=missingCriticalUpdatesCount, SecurityUpdates=missingSecurityUpdatesCount, OtherUpdates=missingOtherUpdatesCount, compliance, osType, Environment=environment, lastAssessedTime, lastUpdateAgentSeenTime\\\\r\\\\n| extend osType = replace(@\\\\\\\"2\\\\\\\", @\\\\\\\"Windows\\\\\\\", tostring(osType))\\\\r\\\\n| extend osType = replace(@\\\\\\\"1\\\\\\\", @\\\\\\\"Linux\\\\\\\", tostring(osType))\\\\r\\\\n| extend Environment = replace(@\\\\\\\"2\\\\\\\", @\\\\\\\"Non-Azure\\\\\\\", tostring(Environment))\\\\r\\\\n| extend Environment = replace(@\\\\\\\"1\\\\\\\", @\\\\\\\"Azure\\\\\\\", tostring(Environment))\\\",\\\"size\\\":0,\\\"exportFieldName\\\":\\\"displayName\\\",\\\"exportParameterName\\\":\\\"Computer\\\",\\\"queryType\\\":0,\\\"resourceType\\\":\\\"microsoft.operationalinsights/workspaces\\\",\\\"crossComponentResources\\\":[\\\"{Workspaces}\\\"],\\\"visualization\\\":\\\"table\\\",\\\"gridSettings\\\":{\\\"formatters\\\":[{\\\"columnMatch\\\":\\\"displayName\\\",\\\"formatter\\\":0,\\\"formatOptions\\\":{\\\"showIcon\\\":true}},{\\\"columnMatch\\\":\\\"scopedToUpdatesSolution\\\",\\\"formatter\\\":0,\\\"formatOptions\\\":{\\\"showIcon\\\":true}},{\\\"columnMatch\\\":\\\"CriticalUpdates\\\",\\\"formatter\\\":8,\\\"formatOptions\\\":{\\\"min\\\":0,\\\"max\\\":1,\\\"palette\\\":\\\"greenRed\\\",\\\"showIcon\\\":true}},{\\\"columnMatch\\\":\\\"SecurityUpdates\\\",\\\"formatter\\\":8,\\\"formatOptions\\\":{\\\"min\\\":0,\\\"max\\\":5,\\\"palette\\\":\\\"greenRed\\\",\\\"showIcon\\\":true}},{\\\"columnMatch\\\":\\\"OtherUpdates\\\",\\\"formatter\\\":8,\\\"formatOptions\\\":{\\\"min\\\":0,\\\"max\\\":5,\\\"palette\\\":\\\"greenRed\\\",\\\"showIcon\\\":true}},{\\\"columnMatch\\\":\\\"compliance\\\",\\\"formatter\\\":8,\\\"formatOptions\\\":{\\\"min\\\":1,\\\"max\\\":2,\\\"palette\\\":\\\"greenRed\\\",\\\"showIcon\\\":true}},{\\\"columnMatch\\\":\\\"osType\\\",\\\"formatter\\\":0,\\\"formatOptions\\\":{\\\"showIcon\\\":true}},{\\\"columnMatch\\\":\\\"Environment\\\",\\\"formatter\\\":0,\\\"formatOptions\\\":{\\\"showIcon\\\":true}},{\\\"columnMatch\\\":\\\"lastAssessedTime\\\",\\\"formatter\\\":0,\\\"formatOptions\\\":{\\\"showIcon\\\":true}},{\\\"columnMatch\\\":\\\"lastUpdateAgentSeenTime\\\",\\\"formatter\\\":0,\\\"formatOptions\\\":{\\\"showIcon\\\":true}}]}}\",\"name\":\"query - 2\"},{\"type\":1,\"content\":\"{\\\"json\\\":\\\"## Updates Needed by {Computer}\\\"}\",\"name\":\"text - 10\"},{\"type\":9,\"content\":\"{\\\"version\\\":\\\"KqlParameterItem/1.0\\\",\\\"parameters\\\":[],\\\"style\\\":\\\"pills\\\",\\\"queryType\\\":0,\\\"resourceType\\\":\\\"microsoft.insights/components\\\"}\",\"name\":\"parameters - 3\"},{\"type\":3,\"content\":\"{\\\"version\\\":\\\"KqlItem/1.0\\\",\\\"query\\\":\\\"Update\\\\r\\\\n| where TimeGenerated>ago(14h) and OSType!=\\\\\\\"Linux\\\\\\\" and (Optional==false or Classification has \\\\\\\"Critical\\\\\\\" or Classification has \\\\\\\"Security\\\\\\\") and SourceComputerId in ((Heartbeat\\\\r\\\\n| where TimeGenerated>ago(12h) and OSType=~\\\\\\\"Windows\\\\\\\" and notempty(Computer)\\\\r\\\\n| summarize arg_max(TimeGenerated, Solutions) by SourceComputerId\\\\r\\\\n| where Solutions has \\\\\\\"updates\\\\\\\" | distinct SourceComputerId))\\\\r\\\\n| summarize hint.strategy=partitioned arg_max(TimeGenerated, *) by Computer, SourceComputerId, UpdateID\\\\r\\\\n| where UpdateState=~\\\\\\\"Needed\\\\\\\" and Approved!=false and Computer=='{Computer}'\\\\r\\\\n| project Computer, Title, Classification, PublishedDate, UpdateState, Product\\\\r\\\\n| union( Update\\\\r\\\\n| where TimeGenerated>ago(5h) and OSType==\\\\\\\"Linux\\\\\\\" and Computer == \\\\\\\"{Computer}\\\\\\\"\\\\r\\\\n| summarize hint.strategy=partitioned arg_max(TimeGenerated, UpdateState, Classification, BulletinUrl, BulletinID) by Computer, SourceComputerId, Product, ProductArch\\\\r\\\\n| where UpdateState=~\\\\\\\"Needed\\\\\\\"\\\\r\\\\n| project-away UpdateState, TimeGenerated\\\\r\\\\n| summarize computersCount=dcount(SourceComputerId, 2), ClassificationWeight=max(iff(Classification has \\\\\\\"Critical\\\\\\\", 4, iff(Classification has \\\\\\\"Security\\\\\\\", 2, 1))) by Computer, id=strcat(Product, \\\\\\\"_\\\\\\\", ProductArch), displayName=Product, productArch=ProductArch, classification=Classification, InformationId=BulletinID, InformationUrl=tostring(split(BulletinUrl, \\\\\\\";\\\\\\\", 0)[0]), osType=1\\\\r\\\\n| sort by ClassificationWeight desc, computersCount desc, displayName asc\\\\r\\\\n| extend informationLink=(iff(isnotempty(InformationId) and isnotempty(InformationUrl), toobject(strcat('{ \\\\\\\"uri\\\\\\\": \\\\\\\"', InformationUrl, '\\\\\\\", \\\\\\\"text\\\\\\\": \\\\\\\"', InformationId, '\\\\\\\", \\\\\\\"target\\\\\\\": \\\\\\\"blank\\\\\\\" }')), toobject('')))\\\\r\\\\n| project-away ClassificationWeight, InformationId, InformationUrl)\\\\r\\\\n\\\",\\\"size\\\":0,\\\"queryType\\\":0,\\\"resourceType\\\":\\\"microsoft.operationalinsights/workspaces\\\",\\\"crossComponentResources\\\":[\\\"{Workspaces}\\\"],\\\"gridSettings\\\":{\\\"formatters\\\":[{\\\"columnMatch\\\":\\\"Computer\\\",\\\"formatter\\\":0,\\\"formatOptions\\\":{\\\"showIcon\\\":true}},{\\\"columnMatch\\\":\\\"Title\\\",\\\"formatter\\\":0,\\\"formatOptions\\\":{\\\"showIcon\\\":true}},{\\\"columnMatch\\\":\\\"Classification\\\",\\\"formatter\\\":18,\\\"formatOptions\\\":{\\\"palette\\\":\\\"greenRed\\\",\\\"showIcon\\\":true,\\\"thresholdsOptions\\\":\\\"colors\\\",\\\"thresholdsGrid\\\":[{\\\"operator\\\":\\\"==\\\",\\\"thresholdValue\\\":\\\"Critical Updates\\\",\\\"representation\\\":\\\"redDark\\\",\\\"text\\\":\\\"{0}{1}\\\"},{\\\"operator\\\":\\\"==\\\",\\\"thresholdValue\\\":\\\"Security Updates\\\",\\\"representation\\\":\\\"redBright\\\",\\\"text\\\":\\\"{0}{1}\\\"},{\\\"operator\\\":\\\"==\\\",\\\"thresholdValue\\\":\\\"Definition Updates\\\",\\\"representation\\\":\\\"yellow\\\",\\\"text\\\":\\\"{0}{1}\\\"},{\\\"operator\\\":\\\"==\\\",\\\"thresholdValue\\\":\\\"Update Rollups\\\",\\\"representation\\\":\\\"purple\\\",\\\"text\\\":\\\"{0}{1}\\\"},{\\\"operator\\\":\\\"==\\\",\\\"thresholdValue\\\":\\\"Updates\\\",\\\"representation\\\":\\\"orange\\\",\\\"text\\\":\\\"{0}{1}\\\"},{\\\"operator\\\":\\\"Default\\\",\\\"thresholdValue\\\":null,\\\"representation\\\":\\\"blue\\\",\\\"text\\\":\\\"{0}{1}\\\"}]}},{\\\"columnMatch\\\":\\\"PublishedDate\\\",\\\"formatter\\\":0,\\\"formatOptions\\\":{\\\"showIcon\\\":true}},{\\\"columnMatch\\\":\\\"UpdateState\\\",\\\"formatter\\\":0,\\\"formatOptions\\\":{\\\"showIcon\\\":true}},{\\\"columnMatch\\\":\\\"Product\\\",\\\"formatter\\\":0,\\\"formatOptions\\\":{\\\"showIcon\\\":true}},{\\\"columnMatch\\\":\\\"id\\\",\\\"formatter\\\":0,\\\"formatOptions\\\":{\\\"showIcon\\\":true}},{\\\"columnMatch\\\":\\\"displayName\\\",\\\"formatter\\\":0,\\\"formatOptions\\\":{\\\"showIcon\\\":true}},{\\\"columnMatch\\\":\\\"productArch\\\",\\\"formatter\\\":0,\\\"formatOptions\\\":{\\\"showIcon\\\":true}},{\\\"columnMatch\\\":\\\"classification\\\",\\\"formatter\\\":0,\\\"formatOptions\\\":{\\\"showIcon\\\":true}},{\\\"columnMatch\\\":\\\"osType\\\",\\\"formatter\\\":0,\\\"formatOptions\\\":{\\\"showIcon\\\":true}},{\\\"columnMatch\\\":\\\"computersCount\\\",\\\"formatter\\\":0,\\\"formatOptions\\\":{\\\"showIcon\\\":true}},{\\\"columnMatch\\\":\\\"informationLink\\\",\\\"formatter\\\":0,\\\"formatOptions\\\":{\\\"showIcon\\\":true}}]},\\\"sortBy\\\":[]}\",\"name\":\"query - 4\"}],\"isLocked\":false}", 44 | "version": "1.0", 45 | "sourceId": "[parameters('workbookSourceId')]", 46 | "category": "[parameters('workbookType')]" 47 | } 48 | } 49 | ], 50 | "outputs": { 51 | "workbookId": { 52 | "type": "string", 53 | "value": "[resourceId( 'microsoft.insights/workbooks', parameters('workbookId'))]" 54 | } 55 | }, 56 | "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#" 57 | } -------------------------------------------------------------------------------- /armtemplates/windows.json: -------------------------------------------------------------------------------- 1 | { 2 | "contentVersion": "1.0.0.0", 3 | "parameters": { 4 | "workbookDisplayName": { 5 | "type": "string", 6 | "defaultValue": "Windows Update Summary", 7 | "metadata": { 8 | "description": "The friendly name for the workbook that is used in the Gallery or Saved List. This name must be unique within a resource group." 9 | } 10 | }, 11 | "workbookType": { 12 | "type": "string", 13 | "defaultValue": "workbook", 14 | "metadata": { 15 | "description": "The gallery that the workbook will been shown under. Supported values include workbook, tsg, etc. Usually, this is 'workbook'" 16 | } 17 | }, 18 | "workbookSourceId": { 19 | "type": "string", 20 | "defaultValue": "Azure Monitor", 21 | "metadata": { 22 | "description": "The id of resource instance to which the workbook will be associated" 23 | } 24 | }, 25 | "workbookId": { 26 | "type": "string", 27 | "defaultValue": "[newGuid()]", 28 | "metadata": { 29 | "description": "The unique guid for this workbook instance" 30 | } 31 | } 32 | }, 33 | "resources": [ 34 | { 35 | "name": "[parameters('workbookId')]", 36 | "type": "microsoft.insights/workbooks", 37 | "location": "[resourceGroup().location]", 38 | "apiVersion": "2018-06-17-preview", 39 | "dependsOn": [], 40 | "kind": "shared", 41 | "properties": { 42 | "displayName": "[parameters('workbookDisplayName')]", 43 | "serializedData": "{\"version\":\"Notebook/1.0\",\"items\":[{\"type\":1,\"content\":\"{\\\"json\\\":\\\"\\\"}\",\"customWidth\":\"100\",\"name\":\"text - 5\"},{\"type\":9,\"content\":\"{\\\"version\\\":\\\"KqlParameterItem/1.0\\\",\\\"crossComponentResources\\\":[\\\"value::all\\\"],\\\"parameters\\\":[{\\\"id\\\":\\\"f8d6705a-e284-4077-8113-aae1038a6b7c\\\",\\\"version\\\":\\\"KqlParameterItem/1.0\\\",\\\"name\\\":\\\"Workspaces\\\",\\\"type\\\":5,\\\"isRequired\\\":true,\\\"multiSelect\\\":true,\\\"quote\\\":\\\"'\\\",\\\"delimiter\\\":\\\",\\\",\\\"query\\\":\\\"where type =~ 'microsoft.operationalinsights/workspaces'\\\\r\\\\n| summarize by id, name\\\",\\\"crossComponentResources\\\":[\\\"value::all\\\"],\\\"value\\\":[\\\"value::all\\\"],\\\"typeSettings\\\":{\\\"additionalResourceOptions\\\":[\\\"value::1\\\",\\\"value::all\\\"]},\\\"queryType\\\":1,\\\"resourceType\\\":\\\"microsoft.resourcegraph/resources\\\"}],\\\"style\\\":\\\"pills\\\",\\\"queryType\\\":1,\\\"resourceType\\\":\\\"microsoft.resourcegraph/resources\\\"}\",\"name\":\"parameters - 11\"},{\"type\":1,\"content\":\"{\\\"json\\\":\\\"# Azure Automation Windows Update Summary for All Subscriptions\\\\r\\\\n\\\\r\\\\nThis workbook can query multiple Log Analytics Workspaces. The Azure Automation Update Management solution needs to be linked to every Log Analytics Workspaces you wish to use it with.\\\"}\",\"name\":\"text - 6\"},{\"type\":1,\"content\":\"{\\\"json\\\":\\\"## Windows Updates need by Classification\\\"}\",\"customWidth\":\"50\",\"name\":\"text - 7\"},{\"type\":1,\"content\":\"{\\\"json\\\":\\\"## Top 5 Windows Machines by Update Count\\\"}\",\"customWidth\":\"50\",\"name\":\"text - 8\"},{\"type\":3,\"content\":\"{\\\"version\\\":\\\"KqlItem/1.0\\\",\\\"query\\\":\\\"Update\\\\r\\\\n| where TimeGenerated>ago(14h) and OSType!=\\\\\\\"Linux\\\\\\\" and (Optional==false or Classification has \\\\\\\"Critical\\\\\\\" or Classification has \\\\\\\"Security\\\\\\\") and SourceComputerId in ((Heartbeat\\\\r\\\\n| where TimeGenerated>ago(12h) and OSType=~\\\\\\\"Windows\\\\\\\" and notempty(Computer)\\\\r\\\\n| summarize arg_max(TimeGenerated, Solutions) by SourceComputerId\\\\r\\\\n| where Solutions has \\\\\\\"updates\\\\\\\" | distinct SourceComputerId))\\\\r\\\\n| summarize hint.strategy=partitioned arg_max(TimeGenerated, *) by Computer, SourceComputerId, UpdateID\\\\r\\\\n| where UpdateState=~\\\\\\\"Needed\\\\\\\" and Approved!=false\\\\r\\\\n| summarize UpdatesNeeded=count(Classification) by Classification\\\",\\\"size\\\":2,\\\"queryType\\\":0,\\\"resourceType\\\":\\\"microsoft.operationalinsights/workspaces\\\",\\\"crossComponentResources\\\":[\\\"{Workspaces}\\\"],\\\"visualization\\\":\\\"piechart\\\",\\\"tileSettings\\\":{\\\"showBorder\\\":false,\\\"titleContent\\\":{\\\"columnMatch\\\":\\\"Classification\\\",\\\"formatter\\\":1},\\\"leftContent\\\":{\\\"columnMatch\\\":\\\"UpdatesNeeded\\\",\\\"formatter\\\":12,\\\"formatOptions\\\":{\\\"palette\\\":\\\"auto\\\"},\\\"numberFormat\\\":{\\\"unit\\\":17,\\\"options\\\":{\\\"maximumSignificantDigits\\\":3,\\\"maximumFractionDigits\\\":2}}}},\\\"chartSettings\\\":{\\\"seriesLabelSettings\\\":[{\\\"seriesName\\\":\\\"Definition Updates\\\",\\\"color\\\":\\\"yellow\\\"},{\\\"seriesName\\\":\\\"Updates\\\",\\\"color\\\":\\\"orange\\\"},{\\\"seriesName\\\":\\\"Security Updates\\\",\\\"color\\\":\\\"redBright\\\"},{\\\"seriesName\\\":\\\"Update Rollups\\\",\\\"color\\\":\\\"purple\\\"},{\\\"seriesName\\\":\\\"Critical Updates\\\",\\\"color\\\":\\\"red\\\"}]}}\",\"customWidth\":\"50\",\"name\":\"query - 0\"},{\"type\":3,\"content\":\"{\\\"version\\\":\\\"KqlItem/1.0\\\",\\\"query\\\":\\\"Update\\\\r\\\\n| where TimeGenerated>ago(14h) and OSType!=\\\\\\\"Linux\\\\\\\" and (Optional==false or Classification has \\\\\\\"Critical\\\\\\\" or Classification has \\\\\\\"Security\\\\\\\") and SourceComputerId in ((Heartbeat\\\\r\\\\n| where TimeGenerated>ago(12h) and OSType=~\\\\\\\"Windows\\\\\\\" and notempty(Computer)\\\\r\\\\n| summarize arg_max(TimeGenerated, Solutions) by SourceComputerId\\\\r\\\\n| where Solutions has \\\\\\\"updates\\\\\\\" | distinct SourceComputerId))\\\\r\\\\n| summarize hint.strategy=partitioned arg_max(TimeGenerated, *) by Computer, SourceComputerId, UpdateID\\\\r\\\\n| where UpdateState=~\\\\\\\"Needed\\\\\\\" and Approved!=false\\\\r\\\\n| project Computer, Title, Classification, PublishedDate, UpdateState, Product\\\\r\\\\n| summarize count(Classification) by Computer \\\\r\\\\n| top 5 by count_Classification desc \\\",\\\"size\\\":2,\\\"queryType\\\":0,\\\"resourceType\\\":\\\"microsoft.operationalinsights/workspaces\\\",\\\"crossComponentResources\\\":[\\\"{Workspaces}\\\"],\\\"visualization\\\":\\\"piechart\\\"}\",\"customWidth\":\"50\",\"name\":\"top five Computers Needing Updates\"},{\"type\":1,\"content\":\"{\\\"json\\\":\\\"## Heatmap of Update Summary by Computer\\\\r\\\\n\\\\r\\\\nThis section is dynamic, by selecting a row that row's Computer name will be exported to populate Updates needed by Server\\\"}\",\"name\":\"text - 9\"},{\"type\":3,\"content\":\"{\\\"version\\\":\\\"KqlItem/1.0\\\",\\\"query\\\":\\\"Heartbeat\\\\r\\\\n| where TimeGenerated>ago(12h) and OSType=~\\\\\\\"Windows\\\\\\\" and notempty(Computer)\\\\r\\\\n| summarize arg_max(TimeGenerated, Solutions, Computer, ResourceId, ComputerEnvironment, VMUUID) by SourceComputerId\\\\r\\\\n| where Solutions has \\\\\\\"updates\\\\\\\"\\\\r\\\\n| extend vmuuId=VMUUID, azureResourceId=ResourceId, osType=2, environment=iff(ComputerEnvironment=~\\\\\\\"Azure\\\\\\\", 1, 2), scopedToUpdatesSolution=true, lastUpdateAgentSeenTime=\\\\\\\"\\\\\\\"\\\\r\\\\n| join kind=leftouter\\\\r\\\\n(\\\\r\\\\n Update\\\\r\\\\n | where TimeGenerated>ago(14h) and OSType!=\\\\\\\"Linux\\\\\\\" and SourceComputerId in ((Heartbeat\\\\r\\\\n | where TimeGenerated>ago(12h) and OSType=~\\\\\\\"Windows\\\\\\\" and notempty(Computer)\\\\r\\\\n | summarize arg_max(TimeGenerated, Solutions) by SourceComputerId\\\\r\\\\n | where Solutions has \\\\\\\"updates\\\\\\\"\\\\r\\\\n | distinct SourceComputerId))\\\\r\\\\n | summarize hint.strategy=partitioned arg_max(TimeGenerated, UpdateState, Classification, Title, Optional, Approved, Computer, ComputerEnvironment) by Computer, SourceComputerId, UpdateID\\\\r\\\\n | summarize Computer=any(Computer), ComputerEnvironment=any(ComputerEnvironment), missingCriticalUpdatesCount=countif(Classification has \\\\\\\"Critical\\\\\\\" and UpdateState=~\\\\\\\"Needed\\\\\\\" and Approved!=false), missingSecurityUpdatesCount=countif(Classification has \\\\\\\"Security\\\\\\\" and UpdateState=~\\\\\\\"Needed\\\\\\\" and Approved!=false), missingOtherUpdatesCount=countif(Classification !has \\\\\\\"Critical\\\\\\\" and Classification !has \\\\\\\"Security\\\\\\\" and UpdateState=~\\\\\\\"Needed\\\\\\\" and Optional==false and Approved!=false), lastAssessedTime=max(TimeGenerated), lastUpdateAgentSeenTime=\\\\\\\"\\\\\\\" by SourceComputerId\\\\r\\\\n | extend compliance=iff(missingCriticalUpdatesCount > 0 or missingSecurityUpdatesCount > 0, 2, 1)\\\\r\\\\n | extend ComplianceOrder=iff(missingCriticalUpdatesCount > 0 or missingSecurityUpdatesCount > 0 or missingOtherUpdatesCount > 0, 1, 3)\\\\r\\\\n)\\\\r\\\\non SourceComputerId\\\\r\\\\n| project id=SourceComputerId, displayName=Computer, sourceComputerId=SourceComputerId, scopedToUpdatesSolution=true, missingCriticalUpdatesCount=coalesce(missingCriticalUpdatesCount, -1), missingSecurityUpdatesCount=coalesce(missingSecurityUpdatesCount, -1), missingOtherUpdatesCount=coalesce(missingOtherUpdatesCount, -1), compliance=coalesce(compliance, 4), lastAssessedTime, lastUpdateAgentSeenTime, osType=2, environment=iff(ComputerEnvironment=~\\\\\\\"Azure\\\\\\\", 1, 2), ComplianceOrder=coalesce(ComplianceOrder, 2) \\\\r\\\\n| order by ComplianceOrder asc, missingCriticalUpdatesCount desc, missingSecurityUpdatesCount desc, missingOtherUpdatesCount desc, displayName asc\\\\r\\\\n| project displayName, scopedToUpdatesSolution, CriticalUpdates=missingCriticalUpdatesCount, SecurityUpdates=missingSecurityUpdatesCount, OtherUpdates=missingOtherUpdatesCount, compliance, osType, Environment=environment, lastAssessedTime, lastUpdateAgentSeenTime\\\\r\\\\n| extend osType = replace(@\\\\\\\"2\\\\\\\", @\\\\\\\"Windows\\\\\\\", tostring(osType))\\\\r\\\\n| extend osType = replace(@\\\\\\\"1\\\\\\\", @\\\\\\\"Linux\\\\\\\", tostring(osType))\\\\r\\\\n| extend Environment = replace(@\\\\\\\"2\\\\\\\", @\\\\\\\"Non-Azure\\\\\\\", tostring(Environment))\\\\r\\\\n| extend Environment = replace(@\\\\\\\"1\\\\\\\", @\\\\\\\"Azure\\\\\\\", tostring(Environment))\\\",\\\"size\\\":0,\\\"exportFieldName\\\":\\\"displayName\\\",\\\"exportParameterName\\\":\\\"Computer\\\",\\\"queryType\\\":0,\\\"resourceType\\\":\\\"microsoft.operationalinsights/workspaces\\\",\\\"crossComponentResources\\\":[\\\"{Workspaces}\\\"],\\\"visualization\\\":\\\"table\\\",\\\"gridSettings\\\":{\\\"formatters\\\":[{\\\"columnMatch\\\":\\\"displayName\\\",\\\"formatter\\\":0,\\\"formatOptions\\\":{\\\"showIcon\\\":true}},{\\\"columnMatch\\\":\\\"scopedToUpdatesSolution\\\",\\\"formatter\\\":0,\\\"formatOptions\\\":{\\\"showIcon\\\":true}},{\\\"columnMatch\\\":\\\"CriticalUpdates\\\",\\\"formatter\\\":8,\\\"formatOptions\\\":{\\\"min\\\":0,\\\"max\\\":1,\\\"palette\\\":\\\"greenRed\\\",\\\"showIcon\\\":true}},{\\\"columnMatch\\\":\\\"SecurityUpdates\\\",\\\"formatter\\\":8,\\\"formatOptions\\\":{\\\"min\\\":0,\\\"max\\\":5,\\\"palette\\\":\\\"greenRed\\\",\\\"showIcon\\\":true}},{\\\"columnMatch\\\":\\\"OtherUpdates\\\",\\\"formatter\\\":8,\\\"formatOptions\\\":{\\\"min\\\":0,\\\"max\\\":5,\\\"palette\\\":\\\"greenRed\\\",\\\"showIcon\\\":true}},{\\\"columnMatch\\\":\\\"compliance\\\",\\\"formatter\\\":8,\\\"formatOptions\\\":{\\\"min\\\":1,\\\"max\\\":2,\\\"palette\\\":\\\"greenRed\\\",\\\"showIcon\\\":true}},{\\\"columnMatch\\\":\\\"osType\\\",\\\"formatter\\\":0,\\\"formatOptions\\\":{\\\"showIcon\\\":true}},{\\\"columnMatch\\\":\\\"Environment\\\",\\\"formatter\\\":0,\\\"formatOptions\\\":{\\\"showIcon\\\":true}},{\\\"columnMatch\\\":\\\"lastAssessedTime\\\",\\\"formatter\\\":0,\\\"formatOptions\\\":{\\\"showIcon\\\":true}},{\\\"columnMatch\\\":\\\"lastUpdateAgentSeenTime\\\",\\\"formatter\\\":0,\\\"formatOptions\\\":{\\\"showIcon\\\":true}}]}}\",\"name\":\"query - 2\"},{\"type\":1,\"content\":\"{\\\"json\\\":\\\"## Updates Needed by Server\\\"}\",\"name\":\"text - 10\"},{\"type\":3,\"content\":\"{\\\"version\\\":\\\"KqlItem/1.0\\\",\\\"query\\\":\\\"Update\\\\r\\\\n| where TimeGenerated>ago(14h) and OSType!=\\\\\\\"Linux\\\\\\\" and (Optional==false or Classification has \\\\\\\"Critical\\\\\\\" or Classification has \\\\\\\"Security\\\\\\\") and SourceComputerId in ((Heartbeat\\\\r\\\\n| where TimeGenerated>ago(12h) and OSType=~\\\\\\\"Windows\\\\\\\" and notempty(Computer)\\\\r\\\\n| summarize arg_max(TimeGenerated, Solutions) by SourceComputerId\\\\r\\\\n| where Solutions has \\\\\\\"updates\\\\\\\" | distinct SourceComputerId))\\\\r\\\\n| summarize hint.strategy=partitioned arg_max(TimeGenerated, *) by Computer, SourceComputerId, UpdateID\\\\r\\\\n| where UpdateState=~\\\\\\\"Needed\\\\\\\" and Approved!=false and Computer=='{Computer}'\\\\r\\\\n| project Computer, Title, Classification, PublishedDate, UpdateState, Product\\\",\\\"size\\\":0,\\\"queryType\\\":0,\\\"resourceType\\\":\\\"microsoft.operationalinsights/workspaces\\\",\\\"crossComponentResources\\\":[\\\"{Workspaces}\\\"],\\\"gridSettings\\\":{\\\"formatters\\\":[{\\\"columnMatch\\\":\\\"Computer\\\",\\\"formatter\\\":0,\\\"formatOptions\\\":{\\\"showIcon\\\":true}},{\\\"columnMatch\\\":\\\"Title\\\",\\\"formatter\\\":0,\\\"formatOptions\\\":{\\\"showIcon\\\":true}},{\\\"columnMatch\\\":\\\"Classification\\\",\\\"formatter\\\":18,\\\"formatOptions\\\":{\\\"showIcon\\\":true,\\\"thresholdsOptions\\\":\\\"colors\\\",\\\"thresholdsGrid\\\":[{\\\"operator\\\":\\\"==\\\",\\\"thresholdValue\\\":\\\"Updates\\\",\\\"representation\\\":\\\"orange\\\",\\\"text\\\":\\\"{0}{1}\\\"},{\\\"operator\\\":\\\"==\\\",\\\"thresholdValue\\\":\\\"Security Updates\\\",\\\"representation\\\":\\\"redBright\\\",\\\"text\\\":\\\"{0}{1}\\\"},{\\\"operator\\\":\\\"==\\\",\\\"thresholdValue\\\":\\\"Definition Updates\\\",\\\"representation\\\":\\\"yellow\\\",\\\"text\\\":\\\"{0}{1}\\\"},{\\\"operator\\\":\\\"==\\\",\\\"thresholdValue\\\":\\\"Update Rollups\\\",\\\"representation\\\":\\\"purple\\\",\\\"text\\\":\\\"{0}{1}\\\"},{\\\"operator\\\":\\\"==\\\",\\\"thresholdValue\\\":\\\"Critical Updates\\\",\\\"representation\\\":\\\"red\\\",\\\"text\\\":\\\"{0}{1}\\\"},{\\\"operator\\\":\\\"Default\\\",\\\"thresholdValue\\\":null,\\\"representation\\\":\\\"blue\\\",\\\"text\\\":\\\"{0}{1}\\\"}]}},{\\\"columnMatch\\\":\\\"PublishedDate\\\",\\\"formatter\\\":0,\\\"formatOptions\\\":{\\\"showIcon\\\":true}},{\\\"columnMatch\\\":\\\"UpdateState\\\",\\\"formatter\\\":0,\\\"formatOptions\\\":{\\\"showIcon\\\":true}},{\\\"columnMatch\\\":\\\"Product\\\",\\\"formatter\\\":0,\\\"formatOptions\\\":{\\\"showIcon\\\":true}}]}}\",\"name\":\"query - 4\"}],\"isLocked\":false}", 44 | "version": "1.0", 45 | "sourceId": "[parameters('workbookSourceId')]", 46 | "category": "[parameters('workbookType')]" 47 | } 48 | } 49 | ], 50 | "outputs": { 51 | "workbookId": { 52 | "type": "string", 53 | "value": "[resourceId( 'microsoft.insights/workbooks', parameters('workbookId'))]" 54 | } 55 | }, 56 | "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#" 57 | } -------------------------------------------------------------------------------- /gallerytemplates/linux.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "Notebook/1.0", 3 | "items": [ 4 | { 5 | "type": 1, 6 | "content": { 7 | "json": "" 8 | }, 9 | "customWidth": "100", 10 | "name": "text - 5" 11 | }, 12 | { 13 | "type": 9, 14 | "content": { 15 | "version": "KqlParameterItem/1.0", 16 | "crossComponentResources": [ 17 | "value::all" 18 | ], 19 | "parameters": [ 20 | { 21 | "id": "f8d6705a-e284-4077-8113-aae1038a6b7c", 22 | "version": "KqlParameterItem/1.0", 23 | "name": "Workspaces", 24 | "type": 5, 25 | "isRequired": true, 26 | "multiSelect": true, 27 | "quote": "'", 28 | "delimiter": ",", 29 | "query": "where type =~ 'microsoft.operationalinsights/workspaces'\r\n| summarize by id, name", 30 | "crossComponentResources": [ 31 | "value::all" 32 | ], 33 | "value": [ 34 | "value::all" 35 | ], 36 | "typeSettings": { 37 | "additionalResourceOptions": [ 38 | "value::1", 39 | "value::all" 40 | ] 41 | }, 42 | "queryType": 1, 43 | "resourceType": "microsoft.resourcegraph/resources" 44 | } 45 | ], 46 | "style": "pills", 47 | "queryType": 1, 48 | "resourceType": "microsoft.resourcegraph/resources" 49 | }, 50 | "name": "parameters - 11" 51 | }, 52 | { 53 | "type": 1, 54 | "content": { 55 | "json": "# Azure Automation Linux Update Summary for All Subscriptions\r\n\r\nThis workbook can query multiple Log Analytics Workspaces. The Azure Automation Update Management solution needs to be linked to every Log Analytics Workspaces you wish to use it with." 56 | }, 57 | "name": "text - 6" 58 | }, 59 | { 60 | "type": 3, 61 | "content": { 62 | "version": "KqlItem/1.0", 63 | "query": "Update\r\n| where TimeGenerated>ago(5h) and OSType==\"Linux\"\r\n| summarize hint.strategy=partitioned arg_max(TimeGenerated, UpdateState, Classification) by Computer, SourceComputerId, Product, ProductArch\r\n| where UpdateState=~\"Needed\"\r\n| summarize by Product, ProductArch, Classification, Computer\r\n| summarize count(Classification) by Computer", 64 | "size": 2, 65 | "queryType": 0, 66 | "resourceType": "microsoft.operationalinsights/workspaces", 67 | "crossComponentResources": [ 68 | "{Workspaces}" 69 | ], 70 | "visualization": "piechart", 71 | "tileSettings": { 72 | "showBorder": false, 73 | "titleContent": { 74 | "columnMatch": "Classification", 75 | "formatter": 1 76 | }, 77 | "leftContent": { 78 | "columnMatch": "UpdatesNeeded", 79 | "formatter": 12, 80 | "formatOptions": { 81 | "palette": "auto" 82 | }, 83 | "numberFormat": { 84 | "unit": 17, 85 | "options": { 86 | "maximumSignificantDigits": 3, 87 | "maximumFractionDigits": 2 88 | } 89 | } 90 | } 91 | } 92 | }, 93 | "customWidth": "50", 94 | "name": "query - 0" 95 | }, 96 | { 97 | "type": 3, 98 | "content": { 99 | "version": "KqlItem/1.0", 100 | "query": "Update\r\n| where TimeGenerated>ago(5h) and OSType==\"Linux\"\r\n| summarize hint.strategy=partitioned arg_max(TimeGenerated, UpdateState, Classification) by Computer, SourceComputerId, Product, ProductArch\r\n| where UpdateState=~\"Needed\"\r\n| summarize by Product, ProductArch, Classification, Computer\r\n| summarize count(Classification) by Classification", 101 | "size": 2, 102 | "queryType": 0, 103 | "resourceType": "microsoft.operationalinsights/workspaces", 104 | "crossComponentResources": [ 105 | "{Workspaces}" 106 | ], 107 | "visualization": "piechart", 108 | "chartSettings": { 109 | "seriesLabelSettings": [ 110 | { 111 | "seriesName": "Others", 112 | "color": "purple" 113 | }, 114 | { 115 | "seriesName": "Security Updates", 116 | "color": "redBright" 117 | } 118 | ] 119 | } 120 | }, 121 | "customWidth": "50", 122 | "name": "top five Computers Needing Updates" 123 | }, 124 | { 125 | "type": 1, 126 | "content": { 127 | "json": "## Update Count by Classification" 128 | }, 129 | "customWidth": "50", 130 | "name": "text - 7" 131 | }, 132 | { 133 | "type": 1, 134 | "content": { 135 | "json": "## Top 5 Linux Machines by Update Count" 136 | }, 137 | "customWidth": "50", 138 | "name": "text - 8" 139 | }, 140 | { 141 | "type": 3, 142 | "content": { 143 | "version": "KqlItem/1.0", 144 | "query": "Heartbeat\r\n| where TimeGenerated>ago(12h) and OSType==\"Linux\" and notempty(Computer)\r\n| summarize arg_max(TimeGenerated, Solutions, Computer, ResourceId, ComputerEnvironment, VMUUID) by SourceComputerId\r\n| where Solutions has \"updates\"\r\n| extend vmuuId=VMUUID, azureResourceId=ResourceId, osType=1, environment=iff(ComputerEnvironment=~\"Azure\", 1, 2), scopedToUpdatesSolution=true, lastUpdateAgentSeenTime=\"\"\r\n| join kind=leftouter\r\n(\r\n Update\r\n | where TimeGenerated>ago(5h) and OSType==\"Linux\" and SourceComputerId in ((Heartbeat\r\n | where TimeGenerated>ago(12h) and OSType==\"Linux\" and notempty(Computer)\r\n | summarize arg_max(TimeGenerated, Solutions) by SourceComputerId\r\n | where Solutions has \"updates\"\r\n | distinct SourceComputerId))\r\n | summarize hint.strategy=partitioned arg_max(TimeGenerated, UpdateState, Classification, Product, Computer, ComputerEnvironment) by SourceComputerId, Product, ProductArch\r\n | summarize Computer=any(Computer), ComputerEnvironment=any(ComputerEnvironment), missingCriticalUpdatesCount=countif(Classification has \"Critical\" and UpdateState=~\"Needed\"), missingSecurityUpdatesCount=countif(Classification has \"Security\" and UpdateState=~\"Needed\"), missingOtherUpdatesCount=countif(Classification !has \"Critical\" and Classification !has \"Security\" and UpdateState=~\"Needed\"), lastAssessedTime=max(TimeGenerated), lastUpdateAgentSeenTime=\"\" by SourceComputerId\r\n | extend compliance=iff(missingCriticalUpdatesCount > 0 or missingSecurityUpdatesCount > 0, 2, 1)\r\n | extend ComplianceOrder=iff(missingCriticalUpdatesCount > 0 or missingSecurityUpdatesCount > 0 or missingOtherUpdatesCount > 0, 1, 3)\r\n)\r\non SourceComputerId\r\n| project displayName=Computer, scopedToUpdatesSolution=true, CriticalUpdates=coalesce(missingCriticalUpdatesCount, -1), SecurityUpdates=coalesce(missingSecurityUpdatesCount, -1), OtherUpdates=coalesce(missingOtherUpdatesCount, -1), compliance=coalesce(compliance, 4), osType=1, environment=iff(ComputerEnvironment=~\"Azure\", 1, 2), lastAssessedTime, lastUpdateAgentSeenTime\r\n| extend osType = replace(@\"1\", @\"Linux\", tostring(osType))\r\n| extend environment = replace(@\"2\", @\"Non-Azure\", tostring(environment))\r\n| extend environment = replace(@\"1\", @\"Azure\", tostring(environment))", 145 | "size": 0, 146 | "exportFieldName": "displayName", 147 | "exportParameterName": "Computer", 148 | "queryType": 0, 149 | "resourceType": "microsoft.operationalinsights/workspaces", 150 | "crossComponentResources": [ 151 | "{Workspaces}" 152 | ], 153 | "visualization": "table", 154 | "gridSettings": { 155 | "formatters": [ 156 | { 157 | "columnMatch": "displayName", 158 | "formatter": 0, 159 | "formatOptions": { 160 | "showIcon": true 161 | } 162 | }, 163 | { 164 | "columnMatch": "scopedToUpdatesSolution", 165 | "formatter": 0, 166 | "formatOptions": { 167 | "showIcon": true 168 | } 169 | }, 170 | { 171 | "columnMatch": "CriticalUpdates", 172 | "formatter": 8, 173 | "formatOptions": { 174 | "min": 0, 175 | "max": 1, 176 | "palette": "greenRed", 177 | "showIcon": true 178 | } 179 | }, 180 | { 181 | "columnMatch": "SecurityUpdates", 182 | "formatter": 8, 183 | "formatOptions": { 184 | "min": 0, 185 | "max": 5, 186 | "palette": "greenRed", 187 | "showIcon": true 188 | } 189 | }, 190 | { 191 | "columnMatch": "OtherUpdates", 192 | "formatter": 8, 193 | "formatOptions": { 194 | "min": 0, 195 | "max": 5, 196 | "palette": "greenRed", 197 | "showIcon": true 198 | } 199 | }, 200 | { 201 | "columnMatch": "compliance", 202 | "formatter": 8, 203 | "formatOptions": { 204 | "min": 1, 205 | "max": 2, 206 | "palette": "greenRed", 207 | "showIcon": true 208 | } 209 | }, 210 | { 211 | "columnMatch": "osType", 212 | "formatter": 0, 213 | "formatOptions": { 214 | "showIcon": true 215 | } 216 | }, 217 | { 218 | "columnMatch": "Environment", 219 | "formatter": 0, 220 | "formatOptions": { 221 | "showIcon": true 222 | } 223 | }, 224 | { 225 | "columnMatch": "lastAssessedTime", 226 | "formatter": 0, 227 | "formatOptions": { 228 | "showIcon": true 229 | } 230 | }, 231 | { 232 | "columnMatch": "lastUpdateAgentSeenTime", 233 | "formatter": 0, 234 | "formatOptions": { 235 | "showIcon": true 236 | } 237 | } 238 | ] 239 | } 240 | }, 241 | "name": "query - 2" 242 | }, 243 | { 244 | "type": 9, 245 | "content": { 246 | "version": "KqlParameterItem/1.0", 247 | "parameters": [], 248 | "style": "pills", 249 | "queryType": 0, 250 | "resourceType": "microsoft.insights/components" 251 | }, 252 | "name": "parameters - 3" 253 | }, 254 | { 255 | "type": 3, 256 | "content": { 257 | "version": "KqlItem/1.0", 258 | "query": "Update\r\n| where TimeGenerated>ago(5h) and OSType==\"Linux\" and Computer == \"{Computer}\"\r\n| summarize hint.strategy=partitioned arg_max(TimeGenerated, UpdateState, Classification, BulletinUrl, BulletinID) by Computer, SourceComputerId, Product, ProductArch\r\n| where UpdateState=~\"Needed\"\r\n| project-away UpdateState, TimeGenerated\r\n| summarize computersCount=dcount(SourceComputerId, 2), ClassificationWeight=max(iff(Classification has \"Critical\", 4, iff(Classification has \"Security\", 2, 1))) by Computer, id=strcat(Product, \"_\", ProductArch), displayName=Product, productArch=ProductArch, classification=Classification, InformationId=BulletinID, InformationUrl=tostring(split(BulletinUrl, \";\", 0)[0]), osType=1\r\n| sort by ClassificationWeight desc, computersCount desc, displayName asc\r\n| extend informationLink=(iff(isnotempty(InformationId) and isnotempty(InformationUrl), toobject(strcat('{ \"uri\": \"', InformationUrl, '\", \"text\": \"', InformationId, '\", \"target\": \"blank\" }')), toobject('')))\r\n| project-away ClassificationWeight, InformationId, InformationUrl", 259 | "size": 0, 260 | "queryType": 0, 261 | "resourceType": "microsoft.operationalinsights/workspaces", 262 | "crossComponentResources": [ 263 | "{Workspaces}" 264 | ], 265 | "gridSettings": { 266 | "formatters": [ 267 | { 268 | "columnMatch": "Computer", 269 | "formatter": 0, 270 | "formatOptions": { 271 | "showIcon": true 272 | } 273 | }, 274 | { 275 | "columnMatch": "id", 276 | "formatter": 0, 277 | "formatOptions": { 278 | "showIcon": true 279 | } 280 | }, 281 | { 282 | "columnMatch": "displayName", 283 | "formatter": 0, 284 | "formatOptions": { 285 | "showIcon": true 286 | } 287 | }, 288 | { 289 | "columnMatch": "productArch", 290 | "formatter": 0, 291 | "formatOptions": { 292 | "showIcon": true 293 | } 294 | }, 295 | { 296 | "columnMatch": "classification", 297 | "formatter": 18, 298 | "formatOptions": { 299 | "showIcon": true, 300 | "thresholdsOptions": "colors", 301 | "thresholdsGrid": [ 302 | { 303 | "operator": "==", 304 | "thresholdValue": "Security Updates", 305 | "representation": "redBright", 306 | "text": "{0}{1}" 307 | }, 308 | { 309 | "operator": "==", 310 | "thresholdValue": "Others", 311 | "representation": "purple", 312 | "text": "{0}{1}" 313 | }, 314 | { 315 | "operator": "Default", 316 | "thresholdValue": null, 317 | "representation": "blue", 318 | "text": "{0}{1}" 319 | } 320 | ] 321 | } 322 | }, 323 | { 324 | "columnMatch": "osType", 325 | "formatter": 0, 326 | "formatOptions": { 327 | "showIcon": true 328 | } 329 | }, 330 | { 331 | "columnMatch": "computersCount", 332 | "formatter": 0, 333 | "formatOptions": { 334 | "showIcon": true 335 | } 336 | }, 337 | { 338 | "columnMatch": "informationLink", 339 | "formatter": 0, 340 | "formatOptions": { 341 | "showIcon": true 342 | } 343 | } 344 | ] 345 | } 346 | }, 347 | "name": "query - 4" 348 | } 349 | ], 350 | "$schema": "https://github.com/Microsoft/Application-Insights-Workbooks/blob/master/schema/workbook.json" 351 | } -------------------------------------------------------------------------------- /gallerytemplates/linuxwindows.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "Notebook/1.0", 3 | "items": [ 4 | { 5 | "type": 9, 6 | "content": { 7 | "version": "KqlParameterItem/1.0", 8 | "crossComponentResources": [ 9 | "value::all" 10 | ], 11 | "parameters": [ 12 | { 13 | "id": "f8d6705a-e284-4077-8113-aae1038a6b7c", 14 | "version": "KqlParameterItem/1.0", 15 | "name": "Workspaces", 16 | "type": 5, 17 | "isRequired": true, 18 | "multiSelect": true, 19 | "quote": "'", 20 | "delimiter": ",", 21 | "query": "where type =~ 'microsoft.operationalinsights/workspaces'\r\n| summarize by id, name", 22 | "crossComponentResources": [ 23 | "value::all" 24 | ], 25 | "value": [], 26 | "typeSettings": { 27 | "additionalResourceOptions": [ 28 | "value::1", 29 | "value::all" 30 | ] 31 | }, 32 | "queryType": 1, 33 | "resourceType": "microsoft.resourcegraph/resources" 34 | } 35 | ], 36 | "style": "pills", 37 | "queryType": 1, 38 | "resourceType": "microsoft.resourcegraph/resources" 39 | }, 40 | "name": "parameters - 11" 41 | }, 42 | { 43 | "type": 11, 44 | "content": { 45 | "version": "LinkItem/1.0", 46 | "style": "tabs", 47 | "links": [ 48 | { 49 | "id": "5888fe88-2193-46c3-a6c3-9986a27a5d6c", 50 | "cellValue": "selectedTab", 51 | "linkTarget": "parameter", 52 | "linkLabel": "Updates", 53 | "subTarget": "Updates", 54 | "style": "link" 55 | }, 56 | { 57 | "id": "d169b770-38b9-469f-a21d-3cf56c481674", 58 | "cellValue": "selectedTab", 59 | "linkTarget": "parameter", 60 | "linkLabel": "Computers", 61 | "subTarget": "Computers", 62 | "style": "link" 63 | }, 64 | { 65 | "id": "bf590baf-e734-4169-938f-c23236799026", 66 | "cellValue": "selectedTab", 67 | "linkTarget": "parameter", 68 | "linkLabel": "Alerts", 69 | "subTarget": "Alerts", 70 | "style": "link" 71 | } 72 | ] 73 | }, 74 | "name": "Navigation links", 75 | "styleSettings": { 76 | "margin": "10px 0 0 0" 77 | } 78 | }, 79 | { 80 | "type": 12, 81 | "content": { 82 | "version": "NotebookGroup/1.0", 83 | "groupType": "editable", 84 | "items": [ 85 | { 86 | "type": 1, 87 | "content": { 88 | "json": "# Azure Automation Windows and Linux Update Summary for All Subscriptions\r\n\r\nThis workbook can query multiple Log Analytics Workspaces. The Azure Automation Update Management solution needs to be linked to every Log Analytics Workspaces you wish to use it with." 89 | }, 90 | "name": "text - 6" 91 | }, 92 | { 93 | "type": 1, 94 | "content": { 95 | "json": "## Linux Updates Needed by Classification" 96 | }, 97 | "customWidth": "50", 98 | "name": "text - 8" 99 | }, 100 | { 101 | "type": 1, 102 | "content": { 103 | "json": "## Windows Updates Needed by Classification" 104 | }, 105 | "customWidth": "50", 106 | "name": "text - 7" 107 | }, 108 | { 109 | "type": 3, 110 | "content": { 111 | "version": "KqlItem/1.0", 112 | "query": "Update\r\n| where TimeGenerated>ago(14h) and OSType!=\"Linux\" and (Optional==false or Classification has \"Critical\" or Classification has \"Security\") and SourceComputerId in ((Heartbeat\r\n| where TimeGenerated>ago(12h) and OSType=~\"Windows\" and notempty(Computer)\r\n| summarize arg_max(TimeGenerated, Solutions) by SourceComputerId\r\n| where Solutions has \"updates\" | distinct SourceComputerId))\r\n| summarize hint.strategy=partitioned arg_max(TimeGenerated, *) by Computer, SourceComputerId, UpdateID\r\n| where UpdateState=~\"Needed\" and Approved!=false\r\n| summarize UpdatesNeeded=count(Classification) by Classification", 113 | "size": 3, 114 | "showExportToExcel": true, 115 | "queryType": 0, 116 | "resourceType": "microsoft.operationalinsights/workspaces", 117 | "crossComponentResources": [ 118 | "{Workspaces}" 119 | ], 120 | "visualization": "piechart", 121 | "tileSettings": { 122 | "showBorder": false, 123 | "titleContent": { 124 | "columnMatch": "Classification", 125 | "formatter": 1 126 | }, 127 | "leftContent": { 128 | "columnMatch": "UpdatesNeeded", 129 | "formatter": 12, 130 | "formatOptions": { 131 | "palette": "auto" 132 | }, 133 | "numberFormat": { 134 | "unit": 17, 135 | "options": { 136 | "maximumSignificantDigits": 3, 137 | "maximumFractionDigits": 2 138 | } 139 | } 140 | } 141 | }, 142 | "chartSettings": { 143 | "seriesLabelSettings": [ 144 | { 145 | "seriesName": "Security Updates", 146 | "color": "redBright" 147 | }, 148 | { 149 | "seriesName": "Updates", 150 | "color": "orange" 151 | }, 152 | { 153 | "seriesName": "Definition Updates", 154 | "color": "yellow" 155 | }, 156 | { 157 | "seriesName": "Update Rollups", 158 | "color": "purple" 159 | }, 160 | { 161 | "seriesName": "Critical Updates", 162 | "color": "red" 163 | } 164 | ] 165 | } 166 | }, 167 | "customWidth": "50", 168 | "name": "query - 0", 169 | "styleSettings": { 170 | "maxWidth": "50" 171 | } 172 | }, 173 | { 174 | "type": 3, 175 | "content": { 176 | "version": "KqlItem/1.0", 177 | "query": "Update\r\n| where TimeGenerated>ago(5h) and OSType==\"Linux\"\r\n| summarize hint.strategy=partitioned arg_max(TimeGenerated, UpdateState, Classification) by Computer, SourceComputerId, Product, ProductArch\r\n| where UpdateState=~\"Needed\"\r\n| summarize by Product, ProductArch, Classification, Computer\r\n| summarize count(Classification) by Classification", 178 | "size": 3, 179 | "queryType": 0, 180 | "resourceType": "microsoft.operationalinsights/workspaces", 181 | "crossComponentResources": [ 182 | "{Workspaces}" 183 | ], 184 | "visualization": "piechart", 185 | "chartSettings": { 186 | "seriesLabelSettings": [ 187 | { 188 | "seriesName": "Others", 189 | "color": "purple" 190 | }, 191 | { 192 | "seriesName": "Security Updates", 193 | "color": "redBright" 194 | } 195 | ] 196 | } 197 | }, 198 | "customWidth": "50", 199 | "name": "top five Computers Needing Updates", 200 | "styleSettings": { 201 | "maxWidth": "50" 202 | } 203 | }, 204 | { 205 | "type": 1, 206 | "content": { 207 | "json": "## Heatmap of Update Summary by Computer\r\n\r\nThis section is dynamic, by selecting a row that row's Computer name will be exported to populate Updates needed by Server" 208 | }, 209 | "name": "text - 9" 210 | }, 211 | { 212 | "type": 3, 213 | "content": { 214 | "version": "KqlItem/1.0", 215 | "query": "Heartbeat\r\n| where TimeGenerated>ago(12h) and OSType==\"Linux\" and notempty(Computer)\r\n| summarize arg_max(TimeGenerated, Solutions, Computer, ResourceId, ComputerEnvironment, VMUUID) by SourceComputerId\r\n| where Solutions has \"updates\"\r\n| extend vmuuId=VMUUID, azureResourceId=ResourceId, osType=1, environment=iff(ComputerEnvironment=~\"Azure\", 1, 2), scopedToUpdatesSolution=true, lastUpdateAgentSeenTime=\"\"\r\n| join kind=leftouter\r\n(\r\n Update\r\n | where TimeGenerated>ago(5h) and OSType==\"Linux\" and SourceComputerId in ((Heartbeat\r\n | where TimeGenerated>ago(12h) and OSType==\"Linux\" and notempty(Computer)\r\n | summarize arg_max(TimeGenerated, Solutions) by SourceComputerId\r\n | where Solutions has \"updates\"\r\n | distinct SourceComputerId))\r\n | summarize hint.strategy=partitioned arg_max(TimeGenerated, UpdateState, Classification, Product, Computer, ComputerEnvironment) by SourceComputerId, Product, ProductArch\r\n | summarize Computer=any(Computer), ComputerEnvironment=any(ComputerEnvironment), missingCriticalUpdatesCount=countif(Classification has \"Critical\" and UpdateState=~\"Needed\"), missingSecurityUpdatesCount=countif(Classification has \"Security\" and UpdateState=~\"Needed\"), missingOtherUpdatesCount=countif(Classification !has \"Critical\" and Classification !has \"Security\" and UpdateState=~\"Needed\"), lastAssessedTime=max(TimeGenerated), lastUpdateAgentSeenTime=\"\" by SourceComputerId\r\n | extend compliance=iff(missingCriticalUpdatesCount > 0 or missingSecurityUpdatesCount > 0, 2, 1)\r\n | extend ComplianceOrder=iff(missingCriticalUpdatesCount > 0 or missingSecurityUpdatesCount > 0 or missingOtherUpdatesCount > 0, 1, 3)\r\n)\r\non SourceComputerId\r\n| project id=SourceComputerId, displayName=Computer, sourceComputerId=SourceComputerId, scopedToUpdatesSolution=true, missingCriticalUpdatesCount=coalesce(missingCriticalUpdatesCount, -1), missingSecurityUpdatesCount=coalesce(missingSecurityUpdatesCount, -1), missingOtherUpdatesCount=coalesce(missingOtherUpdatesCount, -1), compliance=coalesce(compliance, 4), lastAssessedTime, lastUpdateAgentSeenTime, osType=1, environment=iff(ComputerEnvironment=~\"Azure\", 1, 2), ComplianceOrder=coalesce(ComplianceOrder, 2)\r\n| union(Heartbeat\r\n| where TimeGenerated>ago(12h) and OSType=~\"Windows\" and notempty(Computer)\r\n| summarize arg_max(TimeGenerated, Solutions, Computer, ResourceId, ComputerEnvironment, VMUUID) by SourceComputerId\r\n| where Solutions has \"updates\"\r\n| extend vmuuId=VMUUID, azureResourceId=ResourceId, osType=2, environment=iff(ComputerEnvironment=~\"Azure\", 1, 2), scopedToUpdatesSolution=true, lastUpdateAgentSeenTime=\"\"\r\n| join kind=leftouter\r\n(\r\n Update\r\n | where TimeGenerated>ago(14h) and OSType!=\"Linux\" and SourceComputerId in ((Heartbeat\r\n | where TimeGenerated>ago(12h) and OSType=~\"Windows\" and notempty(Computer)\r\n | summarize arg_max(TimeGenerated, Solutions) by SourceComputerId\r\n | where Solutions has \"updates\"\r\n | distinct SourceComputerId))\r\n | summarize hint.strategy=partitioned arg_max(TimeGenerated, UpdateState, Classification, Title, Optional, Approved, Computer, ComputerEnvironment) by Computer, SourceComputerId, UpdateID\r\n | summarize Computer=any(Computer), ComputerEnvironment=any(ComputerEnvironment), missingCriticalUpdatesCount=countif(Classification has \"Critical\" and UpdateState=~\"Needed\" and Approved!=false), missingSecurityUpdatesCount=countif(Classification has \"Security\" and UpdateState=~\"Needed\" and Approved!=false), missingOtherUpdatesCount=countif(Classification !has \"Critical\" and Classification !has \"Security\" and UpdateState=~\"Needed\" and Optional==false and Approved!=false), lastAssessedTime=max(TimeGenerated), lastUpdateAgentSeenTime=\"\" by SourceComputerId\r\n | extend compliance=iff(missingCriticalUpdatesCount > 0 or missingSecurityUpdatesCount > 0, 2, 1)\r\n | extend ComplianceOrder=iff(missingCriticalUpdatesCount > 0 or missingSecurityUpdatesCount > 0 or missingOtherUpdatesCount > 0, 1, 3)\r\n)\r\non SourceComputerId\r\n| project id=SourceComputerId, displayName=Computer, sourceComputerId=SourceComputerId, scopedToUpdatesSolution=true, missingCriticalUpdatesCount=coalesce(missingCriticalUpdatesCount, -1), missingSecurityUpdatesCount=coalesce(missingSecurityUpdatesCount, -1), missingOtherUpdatesCount=coalesce(missingOtherUpdatesCount, -1), compliance=coalesce(compliance, 4), lastAssessedTime, lastUpdateAgentSeenTime, osType=2, environment=iff(ComputerEnvironment=~\"Azure\", 1, 2), ComplianceOrder=coalesce(ComplianceOrder, 2) )\r\n| order by ComplianceOrder asc, missingCriticalUpdatesCount desc, missingSecurityUpdatesCount desc, missingOtherUpdatesCount desc, displayName asc\r\n| project displayName, scopedToUpdatesSolution, CriticalUpdates=missingCriticalUpdatesCount, SecurityUpdates=missingSecurityUpdatesCount, OtherUpdates=missingOtherUpdatesCount, compliance, osType, Environment=environment, lastAssessedTime, lastUpdateAgentSeenTime\r\n| extend osType = replace(@\"2\", @\"Windows\", tostring(osType))\r\n| extend osType = replace(@\"1\", @\"Linux\", tostring(osType))\r\n| extend Environment = replace(@\"2\", @\"Non-Azure\", tostring(Environment))\r\n| extend Environment = replace(@\"1\", @\"Azure\", tostring(Environment))", 216 | "size": 0, 217 | "exportFieldName": "displayName", 218 | "exportParameterName": "Computer", 219 | "showExportToExcel": true, 220 | "queryType": 0, 221 | "resourceType": "microsoft.operationalinsights/workspaces", 222 | "crossComponentResources": [ 223 | "{Workspaces}" 224 | ], 225 | "visualization": "table", 226 | "gridSettings": { 227 | "formatters": [ 228 | { 229 | "columnMatch": "CriticalUpdates", 230 | "formatter": 8, 231 | "formatOptions": { 232 | "min": 0, 233 | "max": 1, 234 | "palette": "greenRed", 235 | "showIcon": true 236 | } 237 | }, 238 | { 239 | "columnMatch": "SecurityUpdates", 240 | "formatter": 8, 241 | "formatOptions": { 242 | "min": 0, 243 | "max": 5, 244 | "palette": "greenRed", 245 | "showIcon": true 246 | } 247 | }, 248 | { 249 | "columnMatch": "OtherUpdates", 250 | "formatter": 8, 251 | "formatOptions": { 252 | "min": 0, 253 | "max": 5, 254 | "palette": "greenRed", 255 | "showIcon": true 256 | } 257 | }, 258 | { 259 | "columnMatch": "compliance", 260 | "formatter": 8, 261 | "formatOptions": { 262 | "min": 1, 263 | "max": 2, 264 | "palette": "greenRed", 265 | "showIcon": true 266 | } 267 | } 268 | ] 269 | } 270 | }, 271 | "name": "query - 2" 272 | }, 273 | { 274 | "type": 1, 275 | "content": { 276 | "json": "## Updates Needed by {Computer}" 277 | }, 278 | "name": "text - 10" 279 | }, 280 | { 281 | "type": 3, 282 | "content": { 283 | "version": "KqlItem/1.0", 284 | "query": "Update\r\n| where TimeGenerated>ago(14h) and OSType!=\"Linux\" and (Optional==false or Classification has \"Critical\" or Classification has \"Security\") and SourceComputerId in ((Heartbeat\r\n| where TimeGenerated>ago(12h) and OSType=~\"Windows\" and notempty(Computer)\r\n| summarize arg_max(TimeGenerated, Solutions) by SourceComputerId\r\n| where Solutions has \"updates\" | distinct SourceComputerId))\r\n| summarize hint.strategy=partitioned arg_max(TimeGenerated, *) by Computer, SourceComputerId, UpdateID\r\n| where UpdateState=~\"Needed\" and Approved!=false and Computer=='{Computer}'\r\n| project Computer, Title, Classification, PublishedDate, UpdateState, Product\r\n| union( Update\r\n| where TimeGenerated>ago(5h) and OSType==\"Linux\" and Computer == \"{Computer}\"\r\n| summarize hint.strategy=partitioned arg_max(TimeGenerated, UpdateState, Classification, BulletinUrl, BulletinID) by Computer, SourceComputerId, Product, ProductArch\r\n| where UpdateState=~\"Needed\"\r\n| project-away UpdateState, TimeGenerated\r\n| summarize computersCount=dcount(SourceComputerId, 2), ClassificationWeight=max(iff(Classification has \"Critical\", 4, iff(Classification has \"Security\", 2, 1))) by Computer, id=strcat(Product, \"_\", ProductArch), displayName=Product, productArch=ProductArch, classification=Classification, InformationId=BulletinID, InformationUrl=tostring(split(BulletinUrl, \";\", 0)[0]), osType=1\r\n| sort by ClassificationWeight desc, computersCount desc, displayName asc\r\n| extend informationLink=(iff(isnotempty(InformationId) and isnotempty(InformationUrl), toobject(strcat('{ \"uri\": \"', InformationUrl, '\", \"text\": \"', InformationId, '\", \"target\": \"blank\" }')), toobject('')))\r\n| project-away ClassificationWeight, InformationId, InformationUrl)\r\n", 285 | "size": 0, 286 | "showExportToExcel": true, 287 | "queryType": 0, 288 | "resourceType": "microsoft.operationalinsights/workspaces", 289 | "crossComponentResources": [ 290 | "{Workspaces}" 291 | ], 292 | "gridSettings": { 293 | "formatters": [ 294 | { 295 | "columnMatch": "Classification", 296 | "formatter": 18, 297 | "formatOptions": { 298 | "palette": "greenRed", 299 | "showIcon": true, 300 | "thresholdsOptions": "colors", 301 | "thresholdsGrid": [ 302 | { 303 | "operator": "==", 304 | "thresholdValue": "Critical Updates", 305 | "representation": "redDark", 306 | "text": "{0}{1}" 307 | }, 308 | { 309 | "operator": "==", 310 | "thresholdValue": "Security Updates", 311 | "representation": "redBright", 312 | "text": "{0}{1}" 313 | }, 314 | { 315 | "operator": "==", 316 | "thresholdValue": "Definition Updates", 317 | "representation": "yellow", 318 | "text": "{0}{1}" 319 | }, 320 | { 321 | "operator": "==", 322 | "thresholdValue": "Update Rollups", 323 | "representation": "purple", 324 | "text": "{0}{1}" 325 | }, 326 | { 327 | "operator": "==", 328 | "thresholdValue": "Updates", 329 | "representation": "orange", 330 | "text": "{0}{1}" 331 | }, 332 | { 333 | "operator": "Default", 334 | "thresholdValue": null, 335 | "representation": "blue", 336 | "text": "{0}{1}" 337 | } 338 | ] 339 | } 340 | } 341 | ] 342 | }, 343 | "sortBy": [] 344 | }, 345 | "name": "query - 4" 346 | } 347 | ] 348 | }, 349 | "conditionalVisibility": { 350 | "parameterName": "selectedTab", 351 | "comparison": "isEqualTo", 352 | "value": "Updates" 353 | }, 354 | "name": "Updates" 355 | }, 356 | { 357 | "type": 12, 358 | "content": { 359 | "version": "NotebookGroup/1.0", 360 | "groupType": "editable", 361 | "title": "Computers", 362 | "items": [ 363 | { 364 | "type": 1, 365 | "content": { 366 | "json": "## Computers Connected to Updates and Ready " 367 | }, 368 | "name": "text - 6" 369 | }, 370 | { 371 | "type": 3, 372 | "content": { 373 | "version": "KqlItem/1.0", 374 | "query": "Heartbeat\r\n| where TimeGenerated>ago(12h) and OSType==\"Linux\" and notempty(Computer)\r\n| summarize arg_max(TimeGenerated, Solutions, Computer, ResourceId, ComputerEnvironment, VMUUID) by SourceComputerId\r\n| where Solutions has \"updates\"\r\n| extend vmuuId=VMUUID, azureResourceId=ResourceId, osType=1, environment=iff(ComputerEnvironment=~\"Azure\", 1, 2), scopedToUpdatesSolution=true, lastUpdateAgentSeenTime=\"\"\r\n| join kind=leftouter\r\n(\r\n Update\r\n | where TimeGenerated>ago(5h) and OSType==\"Linux\" and SourceComputerId in ((Heartbeat\r\n | where TimeGenerated>ago(12h) and OSType==\"Linux\" and notempty(Computer)\r\n | summarize arg_max(TimeGenerated, Solutions) by SourceComputerId\r\n | where Solutions has \"updates\"\r\n | distinct SourceComputerId))\r\n | summarize hint.strategy=partitioned arg_max(TimeGenerated, UpdateState, Classification, Product, Computer, ComputerEnvironment) by SourceComputerId, Product, ProductArch\r\n | summarize Computer=any(Computer), ComputerEnvironment=any(ComputerEnvironment), missingCriticalUpdatesCount=countif(Classification has \"Critical\" and UpdateState=~\"Needed\"), missingSecurityUpdatesCount=countif(Classification has \"Security\" and UpdateState=~\"Needed\"), missingOtherUpdatesCount=countif(Classification !has \"Critical\" and Classification !has \"Security\" and UpdateState=~\"Needed\"), lastAssessedTime=max(TimeGenerated), lastUpdateAgentSeenTime=\"\" by SourceComputerId\r\n | extend compliance=iff(missingCriticalUpdatesCount > 0 or missingSecurityUpdatesCount > 0, 2, 1)\r\n | extend ComplianceOrder=iff(missingCriticalUpdatesCount > 0 or missingSecurityUpdatesCount > 0 or missingOtherUpdatesCount > 0, 1, 3)\r\n)\r\non SourceComputerId\r\n| project id=SourceComputerId, displayName=Computer, sourceComputerId=SourceComputerId, scopedToUpdatesSolution=true, missingCriticalUpdatesCount=coalesce(missingCriticalUpdatesCount, -1), missingSecurityUpdatesCount=coalesce(missingSecurityUpdatesCount, -1), missingOtherUpdatesCount=coalesce(missingOtherUpdatesCount, -1), compliance=coalesce(compliance, 4), lastAssessedTime, lastUpdateAgentSeenTime, osType=1, environment=iff(ComputerEnvironment=~\"Azure\", 1, 2), ComplianceOrder=coalesce(ComplianceOrder, 2)\r\n| union(Heartbeat\r\n| where TimeGenerated>ago(12h) and OSType=~\"Windows\" and notempty(Computer)\r\n| summarize arg_max(TimeGenerated, Solutions, Computer, ResourceId, ComputerEnvironment, VMUUID) by SourceComputerId\r\n| where Solutions has \"updates\"\r\n| extend vmuuId=VMUUID, azureResourceId=ResourceId, osType=2, environment=iff(ComputerEnvironment=~\"Azure\", 1, 2), scopedToUpdatesSolution=true, lastUpdateAgentSeenTime=\"\"\r\n| join kind=leftouter\r\n(\r\n Update\r\n | where TimeGenerated>ago(14h) and OSType!=\"Linux\" and SourceComputerId in ((Heartbeat\r\n | where TimeGenerated>ago(12h) and OSType=~\"Windows\" and notempty(Computer)\r\n | summarize arg_max(TimeGenerated, Solutions) by SourceComputerId\r\n | where Solutions has \"updates\"\r\n | distinct SourceComputerId))\r\n | summarize hint.strategy=partitioned arg_max(TimeGenerated, UpdateState, Classification, Title, Optional, Approved, Computer, ComputerEnvironment) by Computer, SourceComputerId, UpdateID\r\n | summarize Computer=any(Computer), ComputerEnvironment=any(ComputerEnvironment), missingCriticalUpdatesCount=countif(Classification has \"Critical\" and UpdateState=~\"Needed\" and Approved!=false), missingSecurityUpdatesCount=countif(Classification has \"Security\" and UpdateState=~\"Needed\" and Approved!=false), missingOtherUpdatesCount=countif(Classification !has \"Critical\" and Classification !has \"Security\" and UpdateState=~\"Needed\" and Optional==false and Approved!=false), lastAssessedTime=max(TimeGenerated), lastUpdateAgentSeenTime=\"\" by SourceComputerId\r\n | extend compliance=iff(missingCriticalUpdatesCount > 0 or missingSecurityUpdatesCount > 0, 2, 1)\r\n | extend ComplianceOrder=iff(missingCriticalUpdatesCount > 0 or missingSecurityUpdatesCount > 0 or missingOtherUpdatesCount > 0, 1, 3)\r\n)\r\non SourceComputerId\r\n| project id=SourceComputerId, displayName=Computer, sourceComputerId=SourceComputerId, scopedToUpdatesSolution=true, missingCriticalUpdatesCount=coalesce(missingCriticalUpdatesCount, -1), missingSecurityUpdatesCount=coalesce(missingSecurityUpdatesCount, -1), missingOtherUpdatesCount=coalesce(missingOtherUpdatesCount, -1), compliance=coalesce(compliance, 4), lastAssessedTime, lastUpdateAgentSeenTime, osType=2, environment=iff(ComputerEnvironment=~\"Azure\", 1, 2), ComplianceOrder=coalesce(ComplianceOrder, 2) )\r\n| order by ComplianceOrder asc, missingCriticalUpdatesCount desc, missingSecurityUpdatesCount desc, missingOtherUpdatesCount desc, displayName asc\r\n| project-away ComplianceOrder\r\n", 375 | "size": 0, 376 | "showAnalytics": true, 377 | "timeContext": { 378 | "durationMs": 86400000 379 | }, 380 | "showExportToExcel": true, 381 | "queryType": 0, 382 | "resourceType": "microsoft.operationalinsights/workspaces", 383 | "crossComponentResources": [ 384 | "{Workspaces}" 385 | ], 386 | "visualization": "table" 387 | }, 388 | "name": "query - 7" 389 | }, 390 | { 391 | "type": 1, 392 | "content": { 393 | "json": "## Confirm that non-Azure machines are enabled for Update Management" 394 | }, 395 | "name": "text - 4" 396 | }, 397 | { 398 | "type": 3, 399 | "content": { 400 | "version": "KqlItem/1.0", 401 | "query": "Heartbeat\r\n| where OSType == \"Windows\" | summarize arg_max(TimeGenerated, *) by SourceComputerId | top 500000 by Computer asc | render table\r\n", 402 | "size": 0, 403 | "showAnalytics": true, 404 | "timeContext": { 405 | "durationMs": 86400000 406 | }, 407 | "showExportToExcel": true, 408 | "queryType": 0, 409 | "resourceType": "microsoft.operationalinsights/workspaces", 410 | "crossComponentResources": [ 411 | "{Workspaces}" 412 | ] 413 | }, 414 | "name": "query - 5" 415 | }, 416 | { 417 | "type": 1, 418 | "content": { 419 | "json": "## All Computers in the Tenant" 420 | }, 421 | "name": "text - 4" 422 | }, 423 | { 424 | "type": 3, 425 | "content": { 426 | "version": "KqlItem/1.0", 427 | "query": "Resources\r\n| where type =~ 'Microsoft.Compute/virtualMachines'", 428 | "size": 0, 429 | "showExportToExcel": true, 430 | "queryType": 1, 431 | "resourceType": "microsoft.resourcegraph/resources", 432 | "crossComponentResources": [ 433 | "value::all" 434 | ], 435 | "gridSettings": { 436 | "rowLimit": 10000 437 | }, 438 | "graphSettings": { 439 | "type": 0 440 | } 441 | }, 442 | "name": "query - 5" 443 | }, 444 | { 445 | "type": 1, 446 | "content": { 447 | "json": "## All Operating Systems in Tenant" 448 | }, 449 | "name": "text - 6" 450 | }, 451 | { 452 | "type": 3, 453 | "content": { 454 | "version": "KqlItem/1.0", 455 | "query": "//Find all possible OS information on Servers\r\nResources\r\n| where type =~ 'Microsoft.Compute/virtualMachines'\r\n| extend\r\n JoinID = toupper(id),\r\n OSName = tostring(name),\r\n OSType = tostring(properties.storageProfile.osDisk.osType),\r\n OSExact = tostring(properties.storageProfile.imageReference.exactVersion),\r\n OSSku = tostring(properties.storageProfile.imageReference.sku),\r\n OSOffer = tostring(properties.storageProfile.imageReference.offer),\r\n RSG = tostring(resourceGroup),\r\n SUB = tostring(subscriptionId),\r\n LOC = tostring(location),\r\n TAGS = tostring(tags)\r\n| project JoinID, OSName, OSType, OSExact, OSSku, OSOffer, RSG, SUB, LOC, TAGS\r\n", 456 | "size": 0, 457 | "showExportToExcel": true, 458 | "queryType": 1, 459 | "resourceType": "microsoft.resourcegraph/resources", 460 | "crossComponentResources": [ 461 | "value::all" 462 | ], 463 | "gridSettings": { 464 | "rowLimit": 10000 465 | } 466 | }, 467 | "name": "query - 7" 468 | } 469 | ] 470 | }, 471 | "conditionalVisibility": { 472 | "parameterName": "selectedTab", 473 | "comparison": "isEqualTo", 474 | "value": "Computers" 475 | }, 476 | "name": "Computers" 477 | }, 478 | { 479 | "type": 12, 480 | "content": { 481 | "version": "NotebookGroup/1.0", 482 | "groupType": "editable", 483 | "title": "Alerts", 484 | "items": [ 485 | { 486 | "type": 9, 487 | "content": { 488 | "version": "KqlParameterItem/1.0", 489 | "parameters": [ 490 | { 491 | "id": "1bcde830-9443-4745-bbe8-3c2a903ab334", 492 | "version": "KqlParameterItem/1.0", 493 | "name": "Subscription", 494 | "type": 6, 495 | "description": "Please select the Automation Account where the Update Management Solutions is enabled", 496 | "isRequired": true, 497 | "multiSelect": true, 498 | "quote": "'", 499 | "delimiter": ",", 500 | "value": [], 501 | "typeSettings": { 502 | "additionalResourceOptions": [], 503 | "includeAll": true, 504 | "showDefault": false 505 | }, 506 | "timeContext": { 507 | "durationMs": 86400000 508 | } 509 | }, 510 | { 511 | "id": "2f7bc10c-8255-47e5-8bae-bd7b4ad4e210", 512 | "version": "KqlParameterItem/1.0", 513 | "name": "AutomationAccount", 514 | "type": 5, 515 | "query": "resources\r\n| where type == \"microsoft.automation/automationaccounts\"", 516 | "crossComponentResources": [ 517 | "{Subscription}" 518 | ], 519 | "typeSettings": { 520 | "additionalResourceOptions": [], 521 | "showDefault": false 522 | }, 523 | "timeContext": { 524 | "durationMs": 86400000 525 | }, 526 | "queryType": 1, 527 | "resourceType": "microsoft.resourcegraph/resources" 528 | }, 529 | { 530 | "id": "98cce4f6-7095-4a2b-b29d-9a116f6eaaef", 531 | "version": "KqlParameterItem/1.0", 532 | "name": "TimePicker", 533 | "type": 4, 534 | "typeSettings": { 535 | "selectableValues": [ 536 | { 537 | "durationMs": 3600000 538 | }, 539 | { 540 | "durationMs": 86400000 541 | }, 542 | { 543 | "durationMs": 604800000 544 | }, 545 | { 546 | "durationMs": 2592000000 547 | }, 548 | { 549 | "durationMs": 5184000000 550 | }, 551 | { 552 | "durationMs": 7776000000 553 | } 554 | ] 555 | } 556 | } 557 | ], 558 | "style": "pills", 559 | "queryType": 0, 560 | "resourceType": "microsoft.resourcegraph/resources" 561 | }, 562 | "name": "parameters - 6" 563 | }, 564 | { 565 | "type": 1, 566 | "content": { 567 | "json": "## Update Management Alerts" 568 | }, 569 | "name": "text - 5" 570 | }, 571 | { 572 | "type": 10, 573 | "content": { 574 | "chartId": "workbookffc4dd6f-61ec-4de4-a714-18321f00b82d", 575 | "version": "MetricsItem/2.0", 576 | "size": 0, 577 | "chartType": 2, 578 | "resourceType": "microsoft.automation/automationaccounts", 579 | "metricScope": 0, 580 | "resourceParameter": "AutomationAccount", 581 | "resourceIds": [ 582 | "{AutomationAccount}" 583 | ], 584 | "timeContextFromParameter": "TimePicker", 585 | "timeContext": { 586 | "durationMs": 0 587 | }, 588 | "metrics": [ 589 | { 590 | "namespace": "microsoft.automation/automationaccounts", 591 | "metric": "microsoft.automation/automationaccounts--TotalUpdateDeploymentRuns", 592 | "aggregation": 1, 593 | "splitBy": null 594 | } 595 | ], 596 | "showOpenInMe": true, 597 | "timeBrushParameterName": "TimeBrush", 598 | "gridSettings": { 599 | "rowLimit": 10000 600 | } 601 | }, 602 | "name": "metric - 5" 603 | }, 604 | { 605 | "type": 10, 606 | "content": { 607 | "chartId": "workbook8b885e96-af1e-4c41-ba4f-0ceda644d734", 608 | "version": "MetricsItem/2.0", 609 | "size": 0, 610 | "chartType": 2, 611 | "resourceType": "microsoft.automation/automationaccounts", 612 | "metricScope": 0, 613 | "resourceParameter": "AutomationAccount", 614 | "resourceIds": [ 615 | "{AutomationAccount}" 616 | ], 617 | "timeContextFromParameter": "TimePicker", 618 | "timeContext": { 619 | "durationMs": 0 620 | }, 621 | "metrics": [ 622 | { 623 | "namespace": "microsoft.automation/automationaccounts", 624 | "metric": "microsoft.automation/automationaccounts--TotalUpdateDeploymentMachineRuns", 625 | "aggregation": 1, 626 | "splitBy": null 627 | } 628 | ], 629 | "showOpenInMe": true, 630 | "timeBrushParameterName": "TimeBrush2", 631 | "gridSettings": { 632 | "rowLimit": 10000 633 | } 634 | }, 635 | "name": "metric - 2" 636 | } 637 | ] 638 | }, 639 | "conditionalVisibility": { 640 | "parameterName": "selectedTab", 641 | "comparison": "isEqualTo", 642 | "value": "Alerts" 643 | }, 644 | "name": "Alerts" 645 | } 646 | ], 647 | "fallbackResourceIds": [ 648 | "azure monitor" 649 | ], 650 | "$schema": "https://github.com/Microsoft/Application-Insights-Workbooks/blob/master/schema/workbook.json" 651 | } -------------------------------------------------------------------------------- /gallerytemplates/windows.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "Notebook/1.0", 3 | "items": [ 4 | { 5 | "type": 1, 6 | "content": { 7 | "json": "" 8 | }, 9 | "customWidth": "100", 10 | "name": "text - 5" 11 | }, 12 | { 13 | "type": 9, 14 | "content": { 15 | "version": "KqlParameterItem/1.0", 16 | "crossComponentResources": [ 17 | "value::all" 18 | ], 19 | "parameters": [ 20 | { 21 | "id": "f8d6705a-e284-4077-8113-aae1038a6b7c", 22 | "version": "KqlParameterItem/1.0", 23 | "name": "Workspaces", 24 | "type": 5, 25 | "isRequired": true, 26 | "multiSelect": true, 27 | "quote": "'", 28 | "delimiter": ",", 29 | "query": "where type =~ 'microsoft.operationalinsights/workspaces'\r\n| summarize by id, name", 30 | "crossComponentResources": [ 31 | "value::all" 32 | ], 33 | "value": [ 34 | "value::all" 35 | ], 36 | "typeSettings": { 37 | "additionalResourceOptions": [ 38 | "value::1", 39 | "value::all" 40 | ] 41 | }, 42 | "queryType": 1, 43 | "resourceType": "microsoft.resourcegraph/resources" 44 | } 45 | ], 46 | "style": "pills", 47 | "queryType": 1, 48 | "resourceType": "microsoft.resourcegraph/resources" 49 | }, 50 | "name": "parameters - 11" 51 | }, 52 | { 53 | "type": 1, 54 | "content": { 55 | "json": "# Azure Automation Windows Update Summary for All Subscriptions\r\n\r\nThis workbook can query multiple Log Analytics Workspaces. The Azure Automation Update Management solution needs to be linked to every Log Analytics Workspaces you wish to use it with." 56 | }, 57 | "name": "text - 6" 58 | }, 59 | { 60 | "type": 1, 61 | "content": { 62 | "json": "## Windows Updates need by Classification" 63 | }, 64 | "customWidth": "50", 65 | "name": "text - 7" 66 | }, 67 | { 68 | "type": 1, 69 | "content": { 70 | "json": "## Top 5 Windows Machines by Update Count" 71 | }, 72 | "customWidth": "50", 73 | "name": "text - 8" 74 | }, 75 | { 76 | "type": 3, 77 | "content": { 78 | "version": "KqlItem/1.0", 79 | "query": "Update\r\n| where TimeGenerated>ago(14h) and OSType!=\"Linux\" and (Optional==false or Classification has \"Critical\" or Classification has \"Security\") and SourceComputerId in ((Heartbeat\r\n| where TimeGenerated>ago(12h) and OSType=~\"Windows\" and notempty(Computer)\r\n| summarize arg_max(TimeGenerated, Solutions) by SourceComputerId\r\n| where Solutions has \"updates\" | distinct SourceComputerId))\r\n| summarize hint.strategy=partitioned arg_max(TimeGenerated, *) by Computer, SourceComputerId, UpdateID\r\n| where UpdateState=~\"Needed\" and Approved!=false\r\n| summarize UpdatesNeeded=count(Classification) by Classification", 80 | "size": 2, 81 | "queryType": 0, 82 | "resourceType": "microsoft.operationalinsights/workspaces", 83 | "crossComponentResources": [ 84 | "{Workspaces}" 85 | ], 86 | "visualization": "piechart", 87 | "tileSettings": { 88 | "showBorder": false, 89 | "titleContent": { 90 | "columnMatch": "Classification", 91 | "formatter": 1 92 | }, 93 | "leftContent": { 94 | "columnMatch": "UpdatesNeeded", 95 | "formatter": 12, 96 | "formatOptions": { 97 | "palette": "auto" 98 | }, 99 | "numberFormat": { 100 | "unit": 17, 101 | "options": { 102 | "maximumSignificantDigits": 3, 103 | "maximumFractionDigits": 2 104 | } 105 | } 106 | } 107 | }, 108 | "chartSettings": { 109 | "seriesLabelSettings": [ 110 | { 111 | "seriesName": "Definition Updates", 112 | "color": "yellow" 113 | }, 114 | { 115 | "seriesName": "Updates", 116 | "color": "orange" 117 | }, 118 | { 119 | "seriesName": "Security Updates", 120 | "color": "redBright" 121 | }, 122 | { 123 | "seriesName": "Update Rollups", 124 | "color": "purple" 125 | }, 126 | { 127 | "seriesName": "Critical Updates", 128 | "color": "red" 129 | } 130 | ] 131 | } 132 | }, 133 | "customWidth": "50", 134 | "name": "query - 0" 135 | }, 136 | { 137 | "type": 3, 138 | "content": { 139 | "version": "KqlItem/1.0", 140 | "query": "Update\r\n| where TimeGenerated>ago(14h) and OSType!=\"Linux\" and (Optional==false or Classification has \"Critical\" or Classification has \"Security\") and SourceComputerId in ((Heartbeat\r\n| where TimeGenerated>ago(12h) and OSType=~\"Windows\" and notempty(Computer)\r\n| summarize arg_max(TimeGenerated, Solutions) by SourceComputerId\r\n| where Solutions has \"updates\" | distinct SourceComputerId))\r\n| summarize hint.strategy=partitioned arg_max(TimeGenerated, *) by Computer, SourceComputerId, UpdateID\r\n| where UpdateState=~\"Needed\" and Approved!=false\r\n| project Computer, Title, Classification, PublishedDate, UpdateState, Product\r\n| summarize count(Classification) by Computer \r\n| top 5 by count_Classification desc ", 141 | "size": 2, 142 | "queryType": 0, 143 | "resourceType": "microsoft.operationalinsights/workspaces", 144 | "crossComponentResources": [ 145 | "{Workspaces}" 146 | ], 147 | "visualization": "piechart" 148 | }, 149 | "customWidth": "50", 150 | "name": "top five Computers Needing Updates" 151 | }, 152 | { 153 | "type": 1, 154 | "content": { 155 | "json": "## Heatmap of Update Summary by Computer\r\n\r\nThis section is dynamic, by selecting a row that row's Computer name will be exported to populate Updates needed by Server" 156 | }, 157 | "name": "text - 9" 158 | }, 159 | { 160 | "type": 3, 161 | "content": { 162 | "version": "KqlItem/1.0", 163 | "query": "Heartbeat\r\n| where TimeGenerated>ago(12h) and OSType=~\"Windows\" and notempty(Computer)\r\n| summarize arg_max(TimeGenerated, Solutions, Computer, ResourceId, ComputerEnvironment, VMUUID) by SourceComputerId\r\n| where Solutions has \"updates\"\r\n| extend vmuuId=VMUUID, azureResourceId=ResourceId, osType=2, environment=iff(ComputerEnvironment=~\"Azure\", 1, 2), scopedToUpdatesSolution=true, lastUpdateAgentSeenTime=\"\"\r\n| join kind=leftouter\r\n(\r\n Update\r\n | where TimeGenerated>ago(14h) and OSType!=\"Linux\" and SourceComputerId in ((Heartbeat\r\n | where TimeGenerated>ago(12h) and OSType=~\"Windows\" and notempty(Computer)\r\n | summarize arg_max(TimeGenerated, Solutions) by SourceComputerId\r\n | where Solutions has \"updates\"\r\n | distinct SourceComputerId))\r\n | summarize hint.strategy=partitioned arg_max(TimeGenerated, UpdateState, Classification, Title, Optional, Approved, Computer, ComputerEnvironment) by Computer, SourceComputerId, UpdateID\r\n | summarize Computer=any(Computer), ComputerEnvironment=any(ComputerEnvironment), missingCriticalUpdatesCount=countif(Classification has \"Critical\" and UpdateState=~\"Needed\" and Approved!=false), missingSecurityUpdatesCount=countif(Classification has \"Security\" and UpdateState=~\"Needed\" and Approved!=false), missingOtherUpdatesCount=countif(Classification !has \"Critical\" and Classification !has \"Security\" and UpdateState=~\"Needed\" and Optional==false and Approved!=false), lastAssessedTime=max(TimeGenerated), lastUpdateAgentSeenTime=\"\" by SourceComputerId\r\n | extend compliance=iff(missingCriticalUpdatesCount > 0 or missingSecurityUpdatesCount > 0, 2, 1)\r\n | extend ComplianceOrder=iff(missingCriticalUpdatesCount > 0 or missingSecurityUpdatesCount > 0 or missingOtherUpdatesCount > 0, 1, 3)\r\n)\r\non SourceComputerId\r\n| project id=SourceComputerId, displayName=Computer, sourceComputerId=SourceComputerId, scopedToUpdatesSolution=true, missingCriticalUpdatesCount=coalesce(missingCriticalUpdatesCount, -1), missingSecurityUpdatesCount=coalesce(missingSecurityUpdatesCount, -1), missingOtherUpdatesCount=coalesce(missingOtherUpdatesCount, -1), compliance=coalesce(compliance, 4), lastAssessedTime, lastUpdateAgentSeenTime, osType=2, environment=iff(ComputerEnvironment=~\"Azure\", 1, 2), ComplianceOrder=coalesce(ComplianceOrder, 2) \r\n| order by ComplianceOrder asc, missingCriticalUpdatesCount desc, missingSecurityUpdatesCount desc, missingOtherUpdatesCount desc, displayName asc\r\n| project displayName, scopedToUpdatesSolution, CriticalUpdates=missingCriticalUpdatesCount, SecurityUpdates=missingSecurityUpdatesCount, OtherUpdates=missingOtherUpdatesCount, compliance, osType, Environment=environment, lastAssessedTime, lastUpdateAgentSeenTime\r\n| extend osType = replace(@\"2\", @\"Windows\", tostring(osType))\r\n| extend osType = replace(@\"1\", @\"Linux\", tostring(osType))\r\n| extend Environment = replace(@\"2\", @\"Non-Azure\", tostring(Environment))\r\n| extend Environment = replace(@\"1\", @\"Azure\", tostring(Environment))", 164 | "size": 0, 165 | "exportFieldName": "displayName", 166 | "exportParameterName": "Computer", 167 | "queryType": 0, 168 | "resourceType": "microsoft.operationalinsights/workspaces", 169 | "crossComponentResources": [ 170 | "{Workspaces}" 171 | ], 172 | "visualization": "table", 173 | "gridSettings": { 174 | "formatters": [ 175 | { 176 | "columnMatch": "displayName", 177 | "formatter": 0, 178 | "formatOptions": { 179 | "showIcon": true 180 | } 181 | }, 182 | { 183 | "columnMatch": "scopedToUpdatesSolution", 184 | "formatter": 0, 185 | "formatOptions": { 186 | "showIcon": true 187 | } 188 | }, 189 | { 190 | "columnMatch": "CriticalUpdates", 191 | "formatter": 8, 192 | "formatOptions": { 193 | "min": 0, 194 | "max": 1, 195 | "palette": "greenRed", 196 | "showIcon": true 197 | } 198 | }, 199 | { 200 | "columnMatch": "SecurityUpdates", 201 | "formatter": 8, 202 | "formatOptions": { 203 | "min": 0, 204 | "max": 5, 205 | "palette": "greenRed", 206 | "showIcon": true 207 | } 208 | }, 209 | { 210 | "columnMatch": "OtherUpdates", 211 | "formatter": 8, 212 | "formatOptions": { 213 | "min": 0, 214 | "max": 5, 215 | "palette": "greenRed", 216 | "showIcon": true 217 | } 218 | }, 219 | { 220 | "columnMatch": "compliance", 221 | "formatter": 8, 222 | "formatOptions": { 223 | "min": 1, 224 | "max": 2, 225 | "palette": "greenRed", 226 | "showIcon": true 227 | } 228 | }, 229 | { 230 | "columnMatch": "osType", 231 | "formatter": 0, 232 | "formatOptions": { 233 | "showIcon": true 234 | } 235 | }, 236 | { 237 | "columnMatch": "Environment", 238 | "formatter": 0, 239 | "formatOptions": { 240 | "showIcon": true 241 | } 242 | }, 243 | { 244 | "columnMatch": "lastAssessedTime", 245 | "formatter": 0, 246 | "formatOptions": { 247 | "showIcon": true 248 | } 249 | }, 250 | { 251 | "columnMatch": "lastUpdateAgentSeenTime", 252 | "formatter": 0, 253 | "formatOptions": { 254 | "showIcon": true 255 | } 256 | } 257 | ] 258 | } 259 | }, 260 | "name": "query - 2" 261 | }, 262 | { 263 | "type": 1, 264 | "content": { 265 | "json": "## Updates Needed by Server" 266 | }, 267 | "name": "text - 10" 268 | }, 269 | { 270 | "type": 3, 271 | "content": { 272 | "version": "KqlItem/1.0", 273 | "query": "Update\r\n| where TimeGenerated>ago(14h) and OSType!=\"Linux\" and (Optional==false or Classification has \"Critical\" or Classification has \"Security\") and SourceComputerId in ((Heartbeat\r\n| where TimeGenerated>ago(12h) and OSType=~\"Windows\" and notempty(Computer)\r\n| summarize arg_max(TimeGenerated, Solutions) by SourceComputerId\r\n| where Solutions has \"updates\" | distinct SourceComputerId))\r\n| summarize hint.strategy=partitioned arg_max(TimeGenerated, *) by Computer, SourceComputerId, UpdateID\r\n| where UpdateState=~\"Needed\" and Approved!=false and Computer=='{Computer}'\r\n| project Computer, Title, Classification, PublishedDate, UpdateState, Product", 274 | "size": 0, 275 | "queryType": 0, 276 | "resourceType": "microsoft.operationalinsights/workspaces", 277 | "crossComponentResources": [ 278 | "{Workspaces}" 279 | ], 280 | "gridSettings": { 281 | "formatters": [ 282 | { 283 | "columnMatch": "Computer", 284 | "formatter": 0, 285 | "formatOptions": { 286 | "showIcon": true 287 | } 288 | }, 289 | { 290 | "columnMatch": "Title", 291 | "formatter": 0, 292 | "formatOptions": { 293 | "showIcon": true 294 | } 295 | }, 296 | { 297 | "columnMatch": "Classification", 298 | "formatter": 18, 299 | "formatOptions": { 300 | "showIcon": true, 301 | "thresholdsOptions": "colors", 302 | "thresholdsGrid": [ 303 | { 304 | "operator": "==", 305 | "thresholdValue": "Updates", 306 | "representation": "orange", 307 | "text": "{0}{1}" 308 | }, 309 | { 310 | "operator": "==", 311 | "thresholdValue": "Security Updates", 312 | "representation": "redBright", 313 | "text": "{0}{1}" 314 | }, 315 | { 316 | "operator": "==", 317 | "thresholdValue": "Definition Updates", 318 | "representation": "yellow", 319 | "text": "{0}{1}" 320 | }, 321 | { 322 | "operator": "==", 323 | "thresholdValue": "Update Rollups", 324 | "representation": "purple", 325 | "text": "{0}{1}" 326 | }, 327 | { 328 | "operator": "==", 329 | "thresholdValue": "Critical Updates", 330 | "representation": "red", 331 | "text": "{0}{1}" 332 | }, 333 | { 334 | "operator": "Default", 335 | "thresholdValue": null, 336 | "representation": "blue", 337 | "text": "{0}{1}" 338 | } 339 | ] 340 | } 341 | }, 342 | { 343 | "columnMatch": "PublishedDate", 344 | "formatter": 0, 345 | "formatOptions": { 346 | "showIcon": true 347 | } 348 | }, 349 | { 350 | "columnMatch": "UpdateState", 351 | "formatter": 0, 352 | "formatOptions": { 353 | "showIcon": true 354 | } 355 | }, 356 | { 357 | "columnMatch": "Product", 358 | "formatter": 0, 359 | "formatOptions": { 360 | "showIcon": true 361 | } 362 | } 363 | ] 364 | } 365 | }, 366 | "name": "query - 4" 367 | } 368 | ], 369 | "$schema": "https://github.com/Microsoft/Application-Insights-Workbooks/blob/master/schema/workbook.json" 370 | } -------------------------------------------------------------------------------- /images/2019-06-26_11-24-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scautomation/Azure-Automation-Update-Management-Workbooks/33a3d2d07de80e5db16197b78173081fe04c0a6d/images/2019-06-26_11-24-50.png -------------------------------------------------------------------------------- /images/2019-06-26_11-42-17.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scautomation/Azure-Automation-Update-Management-Workbooks/33a3d2d07de80e5db16197b78173081fe04c0a6d/images/2019-06-26_11-42-17.gif -------------------------------------------------------------------------------- /images/2019-06-26_12-46-54.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scautomation/Azure-Automation-Update-Management-Workbooks/33a3d2d07de80e5db16197b78173081fe04c0a6d/images/2019-06-26_12-46-54.png -------------------------------------------------------------------------------- /images/2020-02-11_11-20-09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scautomation/Azure-Automation-Update-Management-Workbooks/33a3d2d07de80e5db16197b78173081fe04c0a6d/images/2020-02-11_11-20-09.png -------------------------------------------------------------------------------- /images/2020-02-11_11-20-25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scautomation/Azure-Automation-Update-Management-Workbooks/33a3d2d07de80e5db16197b78173081fe04c0a6d/images/2020-02-11_11-20-25.png -------------------------------------------------------------------------------- /images/2020-02-11_11-21-10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scautomation/Azure-Automation-Update-Management-Workbooks/33a3d2d07de80e5db16197b78173081fe04c0a6d/images/2020-02-11_11-21-10.png -------------------------------------------------------------------------------- /images/2020-02-11_11-21-36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scautomation/Azure-Automation-Update-Management-Workbooks/33a3d2d07de80e5db16197b78173081fe04c0a6d/images/2020-02-11_11-21-36.png --------------------------------------------------------------------------------