├── LICENSE ├── README.md ├── SECURITY.md ├── docs ├── README.md ├── swagger.json └── swagger.yaml └── src ├── MsrcSecurityUpdates ├── Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms.dll ├── Microsoft.IdentityModel.Clients.ActiveDirectory.dll ├── MsrcSecurityUpdates.psd1 ├── MsrcSecurityUpdates.psm1 ├── MsrcSecurityUpdates.tests.ps1 ├── Private │ ├── Get-CVRFID.ps1 │ ├── Get-MsrcCvrfProductVulnerability.ps1 │ ├── Get-MsrcThreatExploitStatus.ps1 │ ├── Set-GlobalVariables.ps1 │ └── Test-CVRFID.ps1 └── Public │ ├── CVSS-Descriptions.json │ ├── CVSS-Metrics.json │ ├── Get-KBDownloadUrl.ps1 │ ├── Get-MsrcCvrfAffectedSoftware.ps1 │ ├── Get-MsrcCvrfCVESummary.ps1 │ ├── Get-MsrcCvrfDocument.ps1 │ ├── Get-MsrcCvrfExploitabilityIndex.ps1 │ ├── Get-MsrcSecurityBulletinHtml.ps1 │ ├── Get-MsrcSecurityUpdate.ps1 │ ├── Get-MsrcVulnerabilityReportHtml.ps1 │ ├── Set-MSRCApiKey.ps1 │ └── Set-MsrcAdalAccessToken.ps1 └── README.md /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. All rights reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Welcome 2 | Microsoft provides an API for programmatic access to security update details using [Common Vulnerability Reporting Format](http://www.icasi.org/cvrf/). View our [blog post](https://msrc-blog.microsoft.com/2016/11/08/furthering-our-commitment-to-security-updates/) for more info. 3 | 4 | The Microsoft [Security Update Guide](https://msrc.microsoft.com/update-guide) is the web experience to find security update detail. 5 | 6 | This repository contains sample code and documentation for the Microsoft Security Updates API (https://portal.msrc.microsoft.com/en-us/developer), including: 7 | * source code for the [MsrcSecurityUpdates PowerShell module](https://www.powershellgallery.com/packages/MsrcSecurityUpdates) 8 | * sample code for using the [MsrcSecurityUpdates PowerShell module](https://www.powershellgallery.com/packages/MsrcSecurityUpdates) 9 | * [OpenAPI/Swagger definition](docs) for the Microsoft Security Updates CVRF API 10 | 11 | # Getting the MsrcSecurityUpdates PowerShell Module 12 | Getting started with the MsrcSecurityUpdates module can be done like this: 13 | ```PowerShell 14 | ### Install the module from the PowerShell Gallery 15 | Install-Module -Name MsrcSecurityUpdates -Scope CurrentUser 16 | 17 | ### Load the module if PowerShell is at least version 5.1 18 | if ($PSVersionTable.PSVersion -gt [version]'5.1') { 19 | Import-Module -Name MsrcSecurityUpdates 20 | } 21 | ``` 22 | Once the module is loaded, check out our [PowerShell samples](https://github.com/Microsoft/MSRC-Microsoft-Security-Updates-API/blob/master/src/README.md) 23 | 24 | # Change Log 25 | **_For up to date major changes, please read the psd1 included in the src folder. This can also be seen on [the Microsoft Powershell Gallery](https://www.powershellgallery.com/packages/MsrcSecurityUpdates)._** 26 | 27 | # Support 28 | ## Developer Support 29 | Customers should treat this repository as custom code. Bug fixes or enhancements can be requested by opening a new issue from the Issues tab. 30 | ## Security Update Support 31 | For questions about CVEs, security updates and patches, please visit [Microsoft Support](https://support.microsoft.com) 32 | 33 | # Contributing 34 | 35 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 36 | 37 | It is Microsoft’s mission to empower every person and every organization on the planet to achieve more. We thank you for helping shape that future by keeping the world a more secure place by tooling security into your organization’s practices. We would love to hear your feedback on features to add or bugs to fix. 38 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Documentation 2 | 3 | Documentation for the Microsoft Security Updates CVRF API can be found in the form of Swagger documentation. 4 | 5 | The documentation can be used to help developers who wish to implement their own API requests / response handling to get the correct responses and fields. For more information check out http://swagger.io. It is a great project and has great staff working on it. 6 | 7 | To view the API, you can open the [swagger-ui demo](http://petstore.swagger.io/) and put the link to the raw [swagger.json](swagger.json?raw=1) in the top bar then click explore. Swagger-ui can be downloaded locally and run if you need to integrate this into how you interact with the api. 8 | 9 | As a note about the swagger, there are two response models defined for the CVRF endpoint. one for json and the other for xml. This is because swagger does not currently have a way to return two different schemas for XML and JSON responses. If you are looking at the swagger definitions and want the correct XML response, please change the response ref accordingly. To find the location to change, search the swagger.json or swagger.yaml for the text: `#/definitions/cvrfReturnTypes200` then simply add \_xml to the end (so it reads `#/definitions/cvrfReturnTypes200_xml`). 10 | 11 | For more information on CVRF, please view the following links: 12 | 13 | https://cve.mitre.org/cve/cvrf.html 14 | 15 | http://www.icasi.org/the-common-vulnerability-reporting-framework-cvrf-v1-1/ 16 | -------------------------------------------------------------------------------- /src/MsrcSecurityUpdates/Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/MSRC-Microsoft-Security-Updates-API/549de64a5b35de74f5a3dbeff70541e5697df0c7/src/MsrcSecurityUpdates/Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms.dll -------------------------------------------------------------------------------- /src/MsrcSecurityUpdates/Microsoft.IdentityModel.Clients.ActiveDirectory.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/MSRC-Microsoft-Security-Updates-API/549de64a5b35de74f5a3dbeff70541e5697df0c7/src/MsrcSecurityUpdates/Microsoft.IdentityModel.Clients.ActiveDirectory.dll -------------------------------------------------------------------------------- /src/MsrcSecurityUpdates/MsrcSecurityUpdates.psd1: -------------------------------------------------------------------------------- 1 | # 2 | # Module manifest for module 'MsrcSecurityUpdates' 3 | # 4 | # Generated by: Microsoft Corporation 5 | # 6 | # Generated on: 3/6/2017 7 | # 8 | 9 | @{ 10 | 11 | # Script module or binary module file associated with this manifest. 12 | RootModule = 'MsrcSecurityUpdates.psm1' 13 | 14 | # Version number of this module. 15 | ModuleVersion = '1.9.9' 16 | 17 | # Supported PSEditions 18 | # CompatiblePSEditions = @() 19 | 20 | # ID used to uniquely identify this module 21 | GUID = '4b781977-6369-41c9-97ea-6801229d08da' 22 | 23 | # Author of this module 24 | Author = 'Microsoft Corporation' 25 | 26 | # Company or vendor of this module 27 | CompanyName = 'Microsoft Corporation' 28 | 29 | # Copyright statement for this module 30 | Copyright = '(c) 2017 Microsoft Corporation. All rights reserved.' 31 | 32 | # Description of the functionality provided by this module 33 | Description = @' 34 | The Microsoft Security Response Center module gets Microsoft Security Update details 35 | and CVRF (Common Vulnerability Reporting Format) documents in either JSON or XML. 36 | 37 | This module calls the MSRC API (api.msrc.microsoft.com). 38 | 39 | '@ 40 | 41 | # Minimum version of the Windows PowerShell engine required by this module 42 | PowerShellVersion = '5.1' 43 | 44 | # Name of the Windows PowerShell host required by this module 45 | # PowerShellHostName = '' 46 | 47 | # Minimum version of the Windows PowerShell host required by this module 48 | # PowerShellHostVersion = '' 49 | 50 | # Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only. 51 | # DotNetFrameworkVersion = '' 52 | 53 | # Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only. 54 | # CLRVersion = '' 55 | 56 | # Processor architecture (None, X86, Amd64) required by this module 57 | # ProcessorArchitecture = '' 58 | 59 | # Modules that must be imported into the global environment prior to importing this module 60 | # RequiredModules = @() 61 | 62 | # Assemblies that must be loaded prior to importing this module 63 | RequiredAssemblies = @( 64 | 'Microsoft.IdentityModel.Clients.ActiveDirectory.dll' 65 | 'Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms.dll' 66 | ) 67 | 68 | # Script files (.ps1) that are run in the caller's environment prior to importing this module. 69 | # ScriptsToProcess = @() 70 | 71 | # Type files (.ps1xml) to be loaded when importing this module 72 | # TypesToProcess = @() 73 | 74 | # Format files (.ps1xml) to be loaded when importing this module 75 | # FormatsToProcess = @() 76 | 77 | # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess 78 | # NestedModules = @() 79 | 80 | # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. 81 | # FunctionsToExport = '*' 82 | FunctionsToExport = @( 83 | 'Get-KBDownloadUrl', 84 | 'Get-MsrcCvrfAffectedSoftware', 85 | 'Get-MsrcCvrfCVESummary', 86 | 'Get-MsrcCvrfDocument', 87 | 'Get-MsrcCvrfExploitabilityIndex', 88 | 'Get-MsrcSecurityBulletinHtml', 89 | 'Get-MsrcSecurityUpdate', 90 | 'Get-MsrcVulnerabilityReportHtml', 91 | 'Set-MSRCAdalAccessToken', 92 | 'Set-MSRCApiKey' 93 | ) 94 | 95 | # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. 96 | # CmdletsToExport = '*' 97 | 98 | # Variables to export from this module 99 | # VariablesToExport = '*' 100 | 101 | # Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export. 102 | # AliasesToExport = '*' 103 | 104 | # DSC resources to export from this module 105 | # DscResourcesToExport = @() 106 | 107 | # List of all modules packaged with this module 108 | # ModuleList = @() 109 | 110 | # List of all files packaged with this module 111 | # FileList = @() 112 | 113 | # Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. 114 | PrivateData = @{ 115 | 116 | PSData = @{ 117 | 118 | # Tags applied to this module. These help with module discovery in online galleries. 119 | Tags = @('MSRC','Security', 'Updates','Microsoft', 'CVRF','PSEdition_Core','PSEdition_Desktop') 120 | 121 | # A URL to the license for this module. 122 | LicenseUri = 'https://github.com/Microsoft/MSRC-Microsoft-Security-Updates-API/blob/master/LICENSE.md' 123 | 124 | # A URL to the main website for this project. 125 | ProjectUri = 'https://github.com/Microsoft/MSRC-Microsoft-Security-Updates-API' 126 | 127 | # A URL to an icon representing this module. 128 | # IconUri = '' 129 | 130 | # ReleaseNotes of this module 131 | ReleaseNotes = @' 132 | November 26, 2024 - Small fix to Customer Action Required field 133 | November 25, 2024 - Adding Customer Action Required field 134 | April 16, 2024 - Adding CWE info 135 | April 18, 2023 - Adding compatibility with Linux 136 | April 17, 2023 - Add Exploitability Index Link 137 | April 13, 2023 - Update Exploitability Index Text 138 | Feb 17, 2022 - Update Mitre Urls and fix typo 139 | April 20, 2021 - Update API endpoint 140 | April 7, 2021 - Adding FixedBuild to vulnerability report 141 | March 2, 2021 - Fixing mitigation on vulnerability report 142 | February 19, 2021 - Updating Vulnerability Report HTML Style 143 | February 3, 2021 - Removed Api-key requirement 144 | January 17, 2021 - Added Issuing CNA info to Get-MsrcVulnerabilityReportHtml 145 | December 9, 2020 - Added Executive Summary to Get-MsrcVulnerabilityReportHtml 146 | November 23, 2020 - Added Known Issues to Get-MsrcVulnerabilityReportHtml 147 | October 23, 2020 - Replaced Description with CVSS table in Get-MsrcVulnerabilityReportHtml 148 | February 9, 2017 - Initial release to https://github.com/Microsoft/MSRC-Microsoft-Security-Updates-API 149 | March 8, 2017 - Refactored into a script module and added basic Pester tests 150 | March 14, 2017 - Added some error handling for when fields are not in the returned CVRF api reply 151 | March 28, 2017 - Added Get-MsrcVulnerabilityReportHtml 152 | March 30, 2017 - PR from MVP (https://github.com/p0w3rsh3ll) Split module into public and private functions, etc 153 | April 5, 2017 - Added ability to use Azure AD tokens, the module now supports calling the APIs with an API key or AAD token 154 | April 18, 2017 - Small HTML change to Get-MsrcSecurityBulletinHtml.ps1 155 | April 28, 2017 - Bug fixes and some refactoring 156 | May 3, 2017 - Added Proxy support, Updates to Get-MsrcVulnerabilityReportHtml 157 | May 5, 2017 - Further updates to Get-MsrcVulnerabilityReportHtml 158 | May 9, 2017 - Changed the string from "unknown" to "N/A" when a cvss score is null from the cvrf response 159 | May 10, 2017 - fixed a typo that was causing FAQ to not display correctly 160 | May 30, 2017 - Added tags to the table of contents, as well as changing the KB article text to be hyperlinked, and show the subtype if possible 161 | May 31, 2017 - Removed padding between table of contents cells to reduce wasted space 162 | June 2, 2017 - Added a fix to allow for multiline KB articles 163 | June 19, 2017 - minor: fixed tests to not fail on get-kbDownloadUrl. major: @rsola added a fix for early powershell versions not able to deserialize large json strings 164 | '@ 165 | 166 | } # End of PSData hashtable 167 | 168 | } # End of PrivateData hashtable 169 | 170 | # HelpInfo URI of this module 171 | # HelpInfoURI = '' 172 | 173 | # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. 174 | # DefaultCommandPrefix = '' 175 | 176 | } 177 | -------------------------------------------------------------------------------- /src/MsrcSecurityUpdates/MsrcSecurityUpdates.psm1: -------------------------------------------------------------------------------- 1 |  2 | #Get public and private function definition files. 3 | $Public = @(Get-ChildItem -Path $PSScriptRoot\Public\*.ps1 -ErrorAction SilentlyContinue) 4 | $Private = @(Get-ChildItem -Path $PSScriptRoot\Private\*.ps1 -ErrorAction SilentlyContinue) 5 | 6 | #Dot source the files 7 | Foreach ($import in @($Public + $Private)) 8 | { 9 | Try { 10 | . $import.fullname 11 | } Catch { 12 | Write-Error -Message "Failed to import function $($import.fullname): $_" 13 | } 14 | } 15 | 16 | # Export all the functions 17 | Export-ModuleMember -Function $Public.Basename -Alias * 18 | -------------------------------------------------------------------------------- /src/MsrcSecurityUpdates/MsrcSecurityUpdates.tests.ps1: -------------------------------------------------------------------------------- 1 |  2 | # Import module would only work if the module is found in standard locations 3 | # Import-Module -Name MsrcSecurityUpdates -Force 4 | $Error.Clear() 5 | Get-Module -Name MsrcSecurityUpdates | Remove-Module -Force -Verbose:$false 6 | Import-Module (Join-Path -Path $PSScriptRoot -ChildPath 'MsrcSecurityUpdates.psd1') -Verbose:$false -Force 7 | 8 | Describe 'API version after module loading' { 9 | It '$msrcApiUrl = https://api.msrc.microsoft.com/cvrf/v3.0' { 10 | $msrcApiUrl -eq 'https://api.msrc.microsoft.com/cvrf/v3.0' | Should Be $true 11 | } 12 | It '$msrcApiVersion = api-version=2023-11-01' { 13 | $msrcApiVersion -eq 'api-version=2023-11-01' | Should Be $true 14 | } 15 | Set-MSRCApiKey -APIVersion 2.0 16 | It '$msrcApiUrl = https://api.msrc.microsoft.com/cvrf/v2.0' { 17 | $msrcApiUrl -eq 'https://api.msrc.microsoft.com/cvrf/v2.0' | Should Be $true 18 | } 19 | It '$msrcApiVersion = api-version=2016-08-01' { 20 | $msrcApiVersion -eq 'api-version=2016-08-01' | Should Be $true 21 | } 22 | } 23 | 24 | '2.0','3.0' | 25 | Foreach-Object { 26 | $v = $_ 27 | Set-MSRCApiKey -APIVersion $_ 28 | Describe ('Function: Get-MsrcSecurityUpdate (calls the /Updates API version {0})' -f $v) { 29 | 30 | It 'Get-MsrcSecurityUpdate - all' { 31 | Get-MsrcSecurityUpdate | 32 | Should Not BeNullOrEmpty 33 | } 34 | 35 | It 'Get-MsrcSecurityUpdate - by year' { 36 | Get-MsrcSecurityUpdate -Year 2017 | 37 | Should Not BeNullOrEmpty 38 | } 39 | 40 | It 'Get-MsrcSecurityUpdate - by vulnerability' { 41 | Get-MsrcSecurityUpdate -Vulnerability CVE-2017-0003 | 42 | Should Not BeNullOrEmpty 43 | } 44 | 45 | It 'Get-MsrcSecurityUpdate - by cvrf' { 46 | Get-MsrcSecurityUpdate -Cvrf 2017-Jan | 47 | Should Not BeNullOrEmpty 48 | } 49 | 50 | It 'Get-MsrcSecurityUpdate - by date - before' { 51 | { $w = $null 52 | $w = Get-MsrcSecurityUpdate -Before 2018-01-01 -WarningVariable w -WarningAction SilentlyContinue -ErrorAction SilentlyContinue 53 | $w.Message -eq 'No results returned from the /Update API' } | Should Be $true 54 | } 55 | 56 | It 'Get-MsrcSecurityUpdate - by date - after' { 57 | { $w = $null 58 | Get-MsrcSecurityUpdate -After 2017-01-01 -WarningVariable w -WarningAction SilentlyContinue -ErrorAction SilentlyContinue 59 | $w.Message -eq 'No results returned from the /Update API' } | Should Be $true 60 | } 61 | 62 | It 'Get-MsrcSecurityUpdate - by date - before and after' { 63 | { $w = $null 64 | Get-MsrcSecurityUpdate -Before 2018-01-01 -After 2017-10-01 -WarningVariable w -WarningAction SilentlyContinue -ErrorAction SilentlyContinue 65 | $w.Message -eq 'No results returned from the /Update API' } | Should Be $true 66 | } 67 | } 68 | 69 | Describe ('Function: Get-MsrcCvrfDocument (calls the MSRC /cvrf API version {0})' -f $v) { 70 | 71 | It 'Get-MsrcCvrfDocument - 2016-Nov' { 72 | Get-MsrcCvrfDocument -ID 2016-Nov | 73 | Should Not BeNullOrEmpty 74 | } 75 | 76 | It 'Get-MsrcCvrfDocument - 2016-Nov - as XML' { 77 | Get-MsrcCvrfDocument -ID 2016-Nov -AsXml | 78 | Should Not BeNullOrEmpty 79 | } 80 | 81 | <# 82 | Get-MsrcSecurityUpdate | Where-Object { $_.ID -ne '2017-May-B' } | 83 | Where-Object { $_.ID -eq "$(((Get-Date).AddMonths(-1)).ToString('yyyy-MMM',[System.Globalization.CultureInfo]'en-US'))" } | 84 | Foreach-Object { 85 | It "Get-MsrcCvrfDocument - none shall throw: $($PSItem.ID)" { 86 | { 87 | $null = Get-MsrcCvrfDocument -ID $PSItem.ID 88 | } | 89 | Should Not Throw 90 | } 91 | } 92 | 93 | It 'Get-MsrcCvrfDocument for 2017-May-B with Get-MsrcCvrfDocument should throw' { 94 | { 95 | Get-MsrcSecurityUpdate | Where-Object { $_.ID -eq '2017-May-B' } | 96 | Foreach-Object { 97 | $null = Get-MsrcCvrfDocument -ID $PSItem.ID 98 | } 99 | } | Should Throw 100 | } 101 | #> 102 | } 103 | 104 | Describe 'Function: Set-MSRCApiKey with proxy' { 105 | if (-not ($global:msrcProxy)) { 106 | 107 | Write-Warning -Message 'This test requires you to use Set-MSRCApiKey first to set your API Key and proxy details' 108 | break 109 | } 110 | 111 | It 'Get-MsrcSecurityUpdate - all' { 112 | Get-MsrcSecurityUpdate | 113 | Should Not BeNullOrEmpty 114 | } 115 | 116 | It 'Get-MsrcCvrfDocument - 2016-Nov' { 117 | Get-MsrcCvrfDocument -ID 2016-Nov | 118 | Should Not BeNullOrEmpty 119 | } 120 | } 121 | 122 | # May still work but not ready yet... 123 | # Describe 'Function: Get-MsrcSecurityBulletinHtml (generates the MSRC Security Bulletin HTML Report)' { 124 | # It 'Security Bulletin Report' { 125 | # Get-MsrcCvrfDocument -ID 2016-Nov | 126 | # Get-MsrcSecurityBulletinHtml | 127 | # Should Not BeNullOrEmpty 128 | # } 129 | # } 130 | InModuleScope MsrcSecurityUpdates { 131 | Describe 'Function: Get-MsrcCvrfAffectedSoftware' { 132 | It 'Get-MsrcCvrfAffectedSoftware by pipeline' { 133 | Get-MsrcCvrfDocument -ID 2016-Nov | 134 | Get-MsrcCvrfAffectedSoftware | 135 | Should Not BeNullOrEmpty 136 | } 137 | 138 | It 'Get-MsrcCvrfAffectedSoftware by parameters' { 139 | $cvrfDocument = Get-MsrcCvrfDocument -ID 2016-Nov 140 | Get-MsrcCvrfAffectedSoftware -Vulnerability $cvrfDocument.Vulnerability -ProductTree $cvrfDocument.ProductTree | 141 | Should Not BeNullOrEmpty 142 | } 143 | } 144 | 145 | Describe 'Function: Get-MsrcCvrfProductVulnerability' { 146 | It 'Get-MsrcCvrfProductVulnerability by pipeline' { 147 | Get-MsrcCvrfDocument -ID 2016-Nov | 148 | Get-MsrcCvrfProductVulnerability | 149 | Should Not BeNullOrEmpty 150 | } 151 | 152 | It 'Get-MsrcCvrfProductVulnerability by parameters' { 153 | $cvrfDocument = Get-MsrcCvrfDocument -ID 2016-Nov 154 | Get-MsrcCvrfProductVulnerability -Vulnerability $cvrfDocument.Vulnerability -ProductTree $cvrfDocument.ProductTree -DocumentTracking $cvrfDocument.DocumentTracking -DocumentTitle $cvrfDocument.DocumentTitle | 155 | Should Not BeNullOrEmpty 156 | } 157 | } 158 | } 159 | 160 | Describe ('Function: Get-MsrcVulnerabilityReportHtml (generates the MSRC Vulnerability Summary HTML Report with API version {0})' -f $v) { 161 | It 'Vulnerability Summary Report - does not throw' { 162 | { 163 | $null = Get-MsrcCvrfDocument -ID 2016-Nov | 164 | Get-MsrcVulnerabilityReportHtml -Verbose:$false -ShowNoProgress -WarningAction SilentlyContinue 165 | } | 166 | Should Not Throw 167 | } 168 | <# 169 | Get-MsrcSecurityUpdate | Where-Object { $_.ID -ne '2017-May-B' } | 170 | Where-Object { $_.ID -eq "$(((Get-Date).AddMonths(-1)).ToString('yyyy-MMM',[System.Globalization.CultureInfo]'en-US'))" } | 171 | Foreach-Object { 172 | It "Vulnerability Summary Report - none shall throw: $($PSItem.ID)" { 173 | { 174 | $null = Get-MsrcCvrfDocument -ID $PSItem.ID | 175 | Get-MsrcVulnerabilityReportHtml -ShowNoProgress -WarningAction SilentlyContinue 176 | } | 177 | Should Not Throw 178 | } 179 | } 180 | #> 181 | } 182 | 183 | InModuleScope MsrcSecurityUpdates { 184 | Describe 'Function: Get-KBDownloadUrl (generates the html for KBArticle downloads used in the vulnerability report affected software table)' { 185 | It 'Get-KBDownloadUrl by pipeline' { 186 | { 187 | $doc = Get-MsrcCvrfDocument -ID 2017-May 188 | $af = $doc | Get-MsrcCvrfAffectedSoftware 189 | $af.KBArticle | Get-KBDownloadUrl 190 | } | 191 | Should Not Throw 192 | } 193 | 194 | 195 | It 'Get-KBDownloadUrl by parameters' { 196 | { 197 | $doc = Get-MsrcCvrfDocument -ID 2017-May 198 | $af = $doc | Get-MsrcCvrfAffectedSoftware 199 | Get-KBDownloadUrl -KBArticleObject $af.KBArticle 200 | } | 201 | Should Not Throw 202 | } 203 | } 204 | } 205 | 206 | } 207 | 208 | #When a pester test fails, it writes out to stdout, and sets an error in $Error. When invoking powershell from C# it is a lot easier to read the stderr stream. 209 | if($Error) 210 | { 211 | Write-Error -Message 'A pester test has failed during the validation process' 212 | } 213 | -------------------------------------------------------------------------------- /src/MsrcSecurityUpdates/Private/Get-CVRFID.ps1: -------------------------------------------------------------------------------- 1 | Function Get-CVRFID { 2 | [CmdletBinding()] 3 | Param( 4 | [Parameter()] 5 | [Alias('CVRFID')] 6 | [string]$ID 7 | ) 8 | Begin { 9 | } 10 | Process { 11 | $RestMethod = @{ 12 | uri = '{0}/Updates?{1}' -f $global:msrcApiUrl,$global:msrcApiVersion 13 | Headers = @{ 14 | 'Accept' = 'application/json' 15 | } 16 | ErrorAction = 'Stop' 17 | } 18 | if ($global:msrcProxy){ 19 | 20 | $RestMethod.Add('Proxy' , $global:msrcProxy) 21 | } 22 | if ($global:msrcProxyCredential){ 23 | 24 | $RestMethod.Add('ProxyCredential',$global:msrcProxyCredential) 25 | 26 | } elseif ($global:MSRCAdalAccessToken) { 27 | 28 | $RestMethod.Headers.Add('Authorization',$($global:MSRCAdalAccessToken.CreateAuthorizationHeader())) 29 | 30 | } 31 | 32 | try { 33 | 34 | [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 35 | 36 | if ($ID) { 37 | (Invoke-RestMethod @RestMethod).Value | 38 | Where-Object { $_.ID -eq $ID } | 39 | Where-Object { $_ -ne '2017-May-B' } 40 | } else { 41 | ((Invoke-RestMethod @RestMethod).Value).ID | 42 | Where-Object { $_ -ne '2017-May-B' } 43 | } 44 | 45 | } catch { 46 | 47 | Throw $_ 48 | 49 | } 50 | } 51 | End {} 52 | } -------------------------------------------------------------------------------- /src/MsrcSecurityUpdates/Private/Get-MsrcCvrfProductVulnerability.ps1: -------------------------------------------------------------------------------- 1 | Function Get-MsrcCvrfProductVulnerability { 2 | <# 3 | .SYNOPSIS 4 | Get product vulnerability details from a CVRF document 5 | 6 | .DESCRIPTION 7 | CVRF documents next products into several places, including: 8 | -Vulnerabilities 9 | -Threats 10 | -Remediations 11 | -Product Tree 12 | This function gathers the details for each product identified in a CVRF document. 13 | It provides a list of Threats, Remediations and CVSS Score Sets for each product. 14 | 15 | .PARAMETER Vulnerability 16 | 17 | .PARAMETER ProductTree 18 | 19 | .PARAMETER DocumentTracking 20 | 21 | .PARAMETER DocumentTitle 22 | 23 | .EXAMPLE 24 | Get-MsrcCvrfDocument -ID 2016-Nov | Get-MsrcCvrfProductVulnerability 25 | 26 | Get product vulnerability details from a CVRF document using the pipeline 27 | 28 | .EXAMPLE 29 | $cvrfDocument = Get-MsrcCvrfDocument -ID 2016-Nov 30 | Get-MsrcCvrfProductVulnerability -Vulnerability $cvrfDocument.Vulnerability -ProductTree $cvrfDocument.ProductTree -DocumentTracking $cvrfDocument.DocumentTracking -DocumentTitle $cvrfDocument.DocumentTitle 31 | 32 | Get product vulnerability details from a CVRF document using a variable and parameters 33 | 34 | #> 35 | Param ( 36 | 37 | [Parameter(Mandatory,ValueFromPipelineByPropertyName)] 38 | $Vulnerability, 39 | 40 | [Parameter(Mandatory,ValueFromPipelineByPropertyName)] 41 | $ProductTree, 42 | 43 | [Parameter(Mandatory,ValueFromPipelineByPropertyName)] 44 | $DocumentTracking, 45 | 46 | 47 | [Parameter(Mandatory,ValueFromPipelineByPropertyName)] 48 | $DocumentTitle 49 | ) 50 | Begin { 51 | $MaximumSeverityType = 3 52 | } 53 | Process { 54 | 55 | $ProductTree.Branch.Items | 56 | ForEach-Object { 57 | $b = $_ 58 | 59 | $b.Items | ForEach-Object { 60 | 61 | # $CvrfRelatedProducts += [PSCustomObject]@{ 62 | [PSCustomObject]@{ 63 | CvrfAlias = $DocumentTracking.Identification.Alias.Value ; 64 | CvrfTitle = $DocumentTitle.Value ; 65 | BranchName = $b.Name ; 66 | ProductName = $_.Value ; 67 | ProductID = $_.ProductID ; 68 | } 69 | } 70 | 71 | } | 72 | ForEach-Object { 73 | 74 | $Remediations = $Threats = $CVSSScoreSets = @() 75 | $MaximumSeverity = $RestartRequired = $null 76 | $o = $_ 77 | 78 | $Vulnerability | ForEach-Object { 79 | 80 | $v = $_ 81 | 82 | $v.Remediations | Where-Object {$_.ProductID -Contains $o.ProductID } | ForEach-Object { 83 | 84 | $_ | Add-Member -NotePropertyName VulnerabilityCVE -NotePropertyValue $v.CVE -Force 85 | $_ | Add-Member -NotePropertyName VulnerabilityTitle -NotePropertyValue $v.Title.Value -Force 86 | $Remediations += $_ 87 | } 88 | 89 | $v.Threats | Where-Object { $_.ProductID -Contains $ot.ProductID } | ForEach-Object { 90 | 91 | $_ | Add-Member -NotePropertyName VulnerabilityCVE -NotePropertyValue $v.CVE -Force 92 | $_ | Add-Member -NotePropertyName VulnerabilityTitle -NotePropertyValue $v.Title.Value -Force 93 | $Threats += $_ 94 | } 95 | 96 | $v.CVSSScoreSets | Where-Object {$_.ProductID -Contains $o.ProductID } | ForEach-Object { 97 | $_ | Add-Member -NotePropertyName VulnerabilityCVE -NotePropertyValue $v.CVE -Force 98 | $_ | Add-Member -NotePropertyName VulnerabilityTitle -NotePropertyValue $v.Title.Value -Force 99 | $CVSSScoreSets += $_ 100 | } 101 | 102 | $o | Add-Member -NotePropertyName Remediations -NotePropertyValue $Remediations -Force 103 | $o | Add-Member -NotePropertyName Threats -NotePropertyValue $Threats -Force 104 | $o | Add-Member -NotePropertyName CVSSScoreSets -NotePropertyValue $CVSSScoreSets -Force 105 | 106 | } 107 | 108 | $MaximumSeverity = Switch ( 109 | ( 110 | $v.Threats | 111 | Where-Object {$_.ProductID -Contains $o.ProductID } | 112 | Where-Object {$_.Type -eq $MaximumSeverityType } 113 | ).Description.Value | Select-Object -Unique 114 | ) { 115 | 'Critical' { 'Critical' ; break } 116 | 'Important' { 'Important' ; break } 117 | 'Moderate' { 'Moderate' ; break } 118 | 'Low' { 'Low' ; break } 119 | default { 'Unknown'} 120 | } 121 | 122 | $o | Add-Member -NotePropertyName MaximumSeverity -NotePropertyValue $MaximumSeverity -Force 123 | 124 | $RestartRequired = Switch ($Vulnerability.Remediations.RestartRequired.Value) { 125 | 'Yes' { 'Yes' ; break } 126 | 'Maybe' { 'Maybe' ; break } 127 | default { 'Unknown' } 128 | } 129 | 130 | $o | Add-Member -NotePropertyName RestartRequired -NotePropertyValue $RestartRequired -Force 131 | 132 | $o 133 | } 134 | } 135 | End {} 136 | } 137 | -------------------------------------------------------------------------------- /src/MsrcSecurityUpdates/Private/Get-MsrcThreatExploitStatus.ps1: -------------------------------------------------------------------------------- 1 | Function Get-MsrcThreatExploitStatus { 2 | <# 3 | .SYNOPSIS 4 | Split a semicolon delimited string into a custom object 5 | 6 | .DESCRIPTION 7 | Split a semicolon delimited string into a custom object 8 | 9 | .PARAMETER ExploitStatusString 10 | The Exploit Status string, which is delimited 11 | 12 | .EXAMPLE 13 | "Publicly Disclosed:No;Exploited:No;Latest Software Release:Exploitation More Likely;Older Software Release:N/A;" | Get-MsrcThreatExploitStatus 14 | 15 | .EXAMPLE 16 | Get-MsrcThreatExploitStatus -ExploitStatusString "Publicly Disclosed:No;Exploited:No;Latest Software Release:Exploitation More Likely;Older Software Release:N/A;" 17 | #> 18 | [CmdletBinding()] 19 | Param ( 20 | [Parameter(Mandatory,ValueFromPipeline)] 21 | [string]$ExploitStatusString 22 | ) 23 | Begin {} 24 | Process { 25 | $s = [PSCustomObject]@{ 26 | PubliclyDisclosed = '' 27 | Exploited = '' 28 | LatestSoftwareRelease = '' 29 | OlderSoftwareRelease = '' 30 | DenialOfService = '' 31 | } 32 | $ExploitStatusString -split ';' | ForEach-Object { 33 | $Name,$Value = $_ -split ':' 34 | Switch ($Name) { 35 | 'Publicly Disclosed' { $s.PubliclyDisclosed = $Value ; break } 36 | 'Exploited' { $s.Exploited = $Value ; break } 37 | 'Latest Software Release' { $s.LatestSoftwareRelease = $Value ; break } 38 | 'Older Software Release' { $s.OlderSoftwareRelease = $Value ; break } 39 | 'DOS' { $s.DenialOfService = $Value ; break } 40 | default {} 41 | } 42 | } 43 | 44 | $s 45 | } 46 | End {} 47 | } 48 | -------------------------------------------------------------------------------- /src/MsrcSecurityUpdates/Private/Set-GlobalVariables.ps1: -------------------------------------------------------------------------------- 1 | # we also set other shared variables 2 | $global:msrcApiUrl = 'https://api.msrc.microsoft.com/cvrf/v3.0' 3 | Write-Verbose -Message "Successfully defined a msrcApiUrl global variable that points to $($global:msrcApiUrl)" 4 | 5 | $global:msrcApiVersion = 'api-version=2023-11-01' 6 | Write-Verbose -Message "Successfully defined a msrcApiVersion global variable that points to $($global:msrcApiVersion)" -------------------------------------------------------------------------------- /src/MsrcSecurityUpdates/Private/Test-CVRFID.ps1: -------------------------------------------------------------------------------- 1 | Function Test-CVRFID { 2 | [CmdletBinding()] 3 | [OutputType('System.Boolean')] 4 | Param( 5 | [Parameter(Mandatory)] 6 | [ValidateNotNullorEmpty()] 7 | [Alias('CVRFID')] 8 | [string]$ID 9 | ) 10 | Begin {} 11 | Process { 12 | if (Get-CVRFID -ID $ID) { 13 | $true 14 | } else { 15 | $false 16 | } 17 | } 18 | End {} 19 | } -------------------------------------------------------------------------------- /src/MsrcSecurityUpdates/Public/CVSS-Descriptions.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/MSRC-Microsoft-Security-Updates-API/549de64a5b35de74f5a3dbeff70541e5697df0c7/src/MsrcSecurityUpdates/Public/CVSS-Descriptions.json -------------------------------------------------------------------------------- /src/MsrcSecurityUpdates/Public/CVSS-Metrics.json: -------------------------------------------------------------------------------- 1 | { 2 | "AC:H": "High", 3 | "AC:L": "Low", 4 | "AC": "Attack Complexity", 5 | "AV:A": "Adjacent", 6 | "AV:L": "Local", 7 | "AV:N": "Network", 8 | "AV:P": "Physical", 9 | "AV": "Attack Vector", 10 | "A:H": "High", 11 | "A:L": "Low", 12 | "A:N": "None", 13 | "A": "Availability", 14 | "C:H": "High", 15 | "C:L": "Low", 16 | "C:N": "None", 17 | "C": "Confidentiality", 18 | "E:F": "Functional", 19 | "E:H": "High", 20 | "E:X": "Not Defined", 21 | "E:P": "Proof-of-Concept", 22 | "E:U": "Unproven", 23 | "E": "Exploit Code Maturity", 24 | "I:H": "High", 25 | "I:L": "Low", 26 | "I:N": "None", 27 | "I": "Integrity", 28 | "PR:H": "High", 29 | "PR:L": "Low", 30 | "PR:N": "None", 31 | "PR": "Privileges Required", 32 | "RL:X": "Not Defined", 33 | "RL:T": "Temporary Fix", 34 | "RL:U": "Unavailable", 35 | "RL:W": "Workaround", 36 | "RL": "Remediation Level", 37 | "RL:O": "Official Fix", 38 | "RC:C": "Confirmed", 39 | "RC:X": "Not Defined", 40 | "RC:R": "Reasonable", 41 | "RC:U": "Unknown", 42 | "RC": "Report Confidence", 43 | "S:C": "Changed", 44 | "S:U": "Unchanged", 45 | "S": "Scope", 46 | "UI:N": "None", 47 | "UI:R": "Required", 48 | "UI": "User Interaction" 49 | } 50 | -------------------------------------------------------------------------------- /src/MsrcSecurityUpdates/Public/Get-KBDownloadUrl.ps1: -------------------------------------------------------------------------------- 1 | Function Get-KBDownloadUrl { 2 | <# 3 | .SYNOPSIS 4 | Takes the kb output from Get-MsrcCvrfAffectedSoftware and builds the html to insert into a document. 5 | 6 | .DESCRIPTION 7 | Takes the kb output from Get-MsrcCvrfAffectedSoftware and builds the html to insert into a document. 8 | 9 | .PARAMETER KBArticleObject 10 | The KB Article object that contains the id, url, and subtype. 11 | 12 | .EXAMPLE 13 | [PSCustomObject]@{ID="kb123456"; URL="microsoft.com"; SubType="Required"} | Get-KBDownloadUrl 14 | #> 15 | [CmdletBinding()] 16 | [OutputType([System.String])] 17 | Param ( 18 | [Parameter(Mandatory,ValueFromPipeline)] 19 | [PSCustomObject]$KBArticleObject 20 | ) 21 | Begin { 22 | $HTML_TO_RETURN = @() 23 | } 24 | Process { 25 | if (-not($KBArticleObject)){ 26 | 'None' 27 | } else { 28 | 29 | $KBArticleObject | 30 | ForEach-Object { 31 | $kb = $_ 32 | #In older months, there won't be a subtype. Handle this so there are not empty ()'s 33 | if($kb.SubType){ 34 | $HTML_TO_RETURN += $('{1} ({2})' -f $kb.URL, $kb.ID, $kb.SubType) 35 | } else { 36 | $HTML_TO_RETURN += $('{1}' -f $kb.URL, $kb.ID) 37 | } 38 | } 39 | } 40 | } 41 | End { 42 | $HTML_TO_RETURN -join '
' 43 | } 44 | } -------------------------------------------------------------------------------- /src/MsrcSecurityUpdates/Public/Get-MsrcCvrfAffectedSoftware.ps1: -------------------------------------------------------------------------------- 1 | Function Get-MsrcCvrfAffectedSoftware { 2 | <# 3 | .SYNOPSIS 4 | Get details of products affected by a CVRF document 5 | 6 | .DESCRIPTION 7 | CVRF documents next products into several places, including: 8 | -Vulnerabilities 9 | -Threats 10 | -Remediations 11 | -Product Tree 12 | This function gathers the details for each product identified in a CVRF document. 13 | 14 | .PARAMETER Vulnerability 15 | 16 | .PARAMETER ProductTree 17 | 18 | .EXAMPLE 19 | Get-MsrcCvrfDocument -ID 2016-Nov | Get-MsrcCvrfAffectedSoftware 20 | 21 | Get product details from a CVRF document using the pipeline. 22 | 23 | .EXAMPLE 24 | $cvrfDocument = Get-MsrcCvrfDocument -ID 2016-Nov 25 | Get-MsrcCvrfAffectedSoftware -Vulnerability $cvrfDocument.Vulnerability -ProductTree $cvrfDocument.ProductTree 26 | 27 | Get product details from a CVRF document using a variable and parameters 28 | #> 29 | [CmdletBinding()] 30 | Param ( 31 | [Parameter(Mandatory,ValueFromPipelineByPropertyName)] 32 | $Vulnerability, 33 | 34 | [Parameter(Mandatory,ValueFromPipelineByPropertyName)] 35 | $ProductTree 36 | ) 37 | Begin { 38 | $MaximumSeverityType = 3 39 | $ThreatsImpactType = 0 40 | $RemediationsKBType = 2 41 | $RemediationsKnownIssue = 5 42 | } 43 | Process { 44 | $Vulnerability | ForEach-Object { 45 | 46 | $v = $_ 47 | 48 | $v.ProductStatuses.ProductID | ForEach-Object { 49 | $id = $_ 50 | 51 | [PSCustomObject] @{ 52 | FullProductName = $( 53 | $ProductTree.FullProductName | 54 | Where-Object { $_.ProductID -eq $id} | 55 | Select-Object -ExpandProperty Value 56 | ) ; 57 | KBArticle = $v.Remediations | where-Object {$_.ProductID -contains $id} | Where-Object {$_.Type -eq $RemediationsKBType} | ForEach-Object { 58 | [PSCustomObject]@{ 59 | ID = $_.Description.Value; 60 | URL= $_.URL; 61 | SubType = $_.SubType 62 | } 63 | }; 64 | CVE = $v.CVE 65 | 'Known Issue' = $v.Remediations | where-Object {$_.ProductID -contains $id} | Where-Object {$_.Type -eq $RemediationsKnownIssue} | ForEach-Object { 66 | [PSCustomObject]@{ 67 | ID = $_.Description.Value; 68 | URL= $_.URL; 69 | } 70 | } 71 | Severity = $( 72 | ( 73 | $v.Threats | 74 | Where-Object {$_.Type -eq $MaximumSeverityType } | 75 | Where-Object { $_.ProductID -contains $id } 76 | ).Description.Value 77 | ) ; 78 | Impact = $( 79 | ( 80 | $v.Threats | 81 | Where-Object {$_.Type -eq $ThreatsImpactType } | 82 | Where-Object { $_.ProductID -contains $id } 83 | ).Description.Value 84 | ); 85 | Weakness = $v.CWE.Value ; 86 | 'Customer Action Required' = if ($customerActionNotes = $v.Notes | Where-Object { $_.Title -eq "Customer Action Required" }) { 87 | $customerActionNotes.Value 88 | } else { 89 | 'Yes' 90 | } ; 91 | RestartRequired = $( 92 | ( 93 | $v.Remediations | 94 | Where-Object { $_.ProductID -contains $id } 95 | ).RestartRequired.Value | ForEach-Object { 96 | "$($_)" 97 | } 98 | ); 99 | FixedBuild = $( 100 | ( 101 | $v.Remediations | 102 | Where-Object { $_.ProductID -contains $id } 103 | ).FixedBuild | ForEach-Object { 104 | "$($_)" 105 | } 106 | ); 107 | Supercedence = $( 108 | ( 109 | $v.Remediations | 110 | Where-Object { $_.ProductID -contains $id } 111 | ).Supercedence | ForEach-Object { 112 | "$($_)" 113 | } 114 | ) ; 115 | CvssScoreSet = $( [PSCustomObject]@{ 116 | base= ($v.CVSSScoreSets | Where-Object { $_.ProductID -contains $id } | Select-Object -First 1).BaseScore; 117 | temporal=($v.CVSSScoreSets | Where-Object { $_.ProductID -contains $id } | Select-Object -First 1).TemporalScore; 118 | vector= ($v.CVSSScoreSets | Where-Object { $_.ProductID -contains $id } | Select-Object -First 1).Vector; 119 | } 120 | ) ; 121 | } 122 | } 123 | } 124 | } 125 | End {} 126 | } 127 | -------------------------------------------------------------------------------- /src/MsrcSecurityUpdates/Public/Get-MsrcCvrfCVESummary.ps1: -------------------------------------------------------------------------------- 1 | Function Get-MsrcCvrfCVESummary { 2 | <# 3 | .SYNOPSIS 4 | Get the CVE summary from vulnerabilities found in CVRF document 5 | 6 | .DESCRIPTION 7 | This function gathers the CVE Summary from vulnerabilities in a CVRF document. 8 | 9 | .PARAMETER Vulnerability 10 | A vulnerability object or objects from a CVRF document object 11 | 12 | .EXAMPLE 13 | Get-MsrcCvrfDocument -ID 2016-Nov | Get-MsrcCvrfCVESummary 14 | 15 | Get the CVE summary from a CVRF document using the pipeline. 16 | 17 | .EXAMPLE 18 | $cvrfDocument = Get-MsrcCvrfDocument -ID 2016-Nov 19 | Get-MsrcCvrfCVESummary -Vulnerability $cvrfDocument.Vulnerability 20 | 21 | Get the CVE summary from a CVRF document using a variable and parameters 22 | #> 23 | [CmdletBinding()] 24 | Param ( 25 | [Parameter(Mandatory,ValueFromPipelineByPropertyName)] 26 | $Vulnerability, 27 | 28 | [Parameter(Mandatory,ValueFromPipelineByPropertyName)] 29 | $ProductTree 30 | ) 31 | Begin { 32 | 33 | $MaximumSeverityType = 3 34 | $ThreatsImpactType = 0 35 | 36 | Function Get-MaxSeverity { 37 | [CmdletBinding()] 38 | [OutputType('System.String')] 39 | Param($InputObject) 40 | Begin {} 41 | Process { 42 | if ('Critical' -in $InputObject) { 43 | 'Critical' 44 | } elseif ('Important' -in $InputObject) { 45 | 'Important' 46 | } elseif ('Moderate' -in $InputObject) { 47 | 'Moderate' 48 | } elseif ('Low' -in $InputObject) { 49 | 'Low' 50 | } else { 51 | 'Unknown' 52 | } 53 | } 54 | End {} 55 | } 56 | } 57 | Process { 58 | 59 | $Vulnerability | ForEach-Object { 60 | 61 | $v = $_ 62 | 63 | [PSCustomObject]@{ 64 | CVE = $v.CVE 65 | Weakness = $(if ($v.CWE) { '{0} : {1}' -f "$($v.CWE.ID)","$($v.CWE.Value)"}) 66 | Description = $( 67 | ($v.Notes | Where-Object { $_.Title -eq 'Description' }).Value 68 | ) ; 69 | 'Customer Action Required' = if ($customerActionNotes = $v.Notes | Where-Object { $_.Title -eq "Customer Action Required" }) { 70 | $customerActionNotes.Value 71 | } else { 72 | 'Yes' 73 | } ; 74 | 'Maximum Severity Rating' = $( 75 | Get-MaxSeverity ($v.Threats | Where-Object {$_.Type -eq $MaximumSeverityType } ).Description.Value | Select-Object -Unique 76 | ) ; 77 | 'Vulnerability Impact' = $( 78 | ($v.Threats | Where-Object {$_.Type -eq $ThreatsImpactType }).Description.Value | Select-Object -Unique 79 | ) ; 80 | 'Affected Software' = $( 81 | $v.ProductStatuses.ProductID | ForEach-Object { 82 | $id = $_ 83 | ($ProductTree.FullProductName | Where-Object { $_.ProductID -eq $id}).Value 84 | } 85 | ) ; 86 | } 87 | } 88 | } 89 | End {} 90 | } -------------------------------------------------------------------------------- /src/MsrcSecurityUpdates/Public/Get-MsrcCvrfDocument.ps1: -------------------------------------------------------------------------------- 1 | Function Get-MsrcCvrfDocument { 2 | <# 3 | .SYNOPSIS 4 | Get a MSRC CVRF document 5 | 6 | .DESCRIPTION 7 | Calls the MSRC CVRF API to get a CVRF document by ID 8 | 9 | .PARAMETER ID 10 | Get the CVRF document for the specified CVRF ID (ie. 2016-Aug) 11 | 12 | .PARAMETER AsXml 13 | Get the output as Xml 14 | 15 | .EXAMPLE 16 | Get-MsrcCvrfDocument -ID 2016-Aug 17 | 18 | Get the Cvrf document '2016-Aug' (returns an object converted from the CVRF JSON) 19 | 20 | .EXAMPLE 21 | Get-MsrcCvrfDocument -ID 2016-Aug -AsXml 22 | 23 | Get the Cvrf document '2016-Aug' (returns an object converted from CVRF XML) 24 | 25 | .NOTES 26 | An API Key for the MSRC CVRF API is not required anymore 27 | 28 | #> 29 | [CmdletBinding()] 30 | Param ( 31 | [Parameter(ParameterSetName='XmlOutput')] 32 | [Switch]$AsXml 33 | 34 | ) 35 | DynamicParam { 36 | 37 | $Dictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary 38 | 39 | $ParameterName = 'ID' 40 | $AttribColl1 = New-Object System.Collections.ObjectModel.Collection[System.Attribute] 41 | $Param1Att = New-Object System.Management.Automation.ParameterAttribute 42 | $Param1Att.Mandatory = $true 43 | $AttribColl1.Add($Param1Att) 44 | 45 | try { 46 | $allCVRFID = Get-CVRFID 47 | } catch { 48 | Throw "`nUnable to get online the list of CVRF ID because:`n$($_.Exception.Message)" 49 | } 50 | if ($allCVRFID) { 51 | $AttribColl1.Add((New-Object System.Management.Automation.ValidateSetAttribute($allCVRFID))) 52 | $Dictionary.Add($ParameterName,(New-Object System.Management.Automation.RuntimeDefinedParameter($ParameterName, [string], $AttribColl1))) 53 | 54 | $Dictionary 55 | } 56 | 57 | } 58 | Begin {} 59 | Process { 60 | 61 | # Common 62 | $RestMethod = @{ 63 | uri = '{0}/cvrf/{1}?{2}' -f $msrcApiUrl,$PSBoundParameters['ID'],$msrcApiVersion 64 | Headers = @{ 65 | 'Accept' = if($AsXml){'application/xml'} else {'application/json'} 66 | } 67 | ErrorAction = 'Stop' 68 | } 69 | 70 | # Add proxy and creds if required 71 | if ($global:msrcProxy) { 72 | 73 | $RestMethod.Add('Proxy', $global:msrcProxy) 74 | 75 | } 76 | 77 | if ($global:msrcProxyCredential) { 78 | 79 | $RestMethod.Add('ProxyCredential',$global:msrcProxyCredential) 80 | 81 | } 82 | 83 | if ($global:MSRCAdalAccessToken) { 84 | 85 | $RestMethod.Headers.Add('Authorization', $global:MSRCAdalAccessToken.CreateAuthorizationHeader()) 86 | 87 | } 88 | 89 | try { 90 | [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 91 | Write-Verbose -Message "Calling $($RestMethod.uri)" 92 | 93 | Invoke-RestMethod @RestMethod 94 | 95 | } catch { 96 | Write-Error -Message "HTTP Get failed with status code $($_.Exception.Response.StatusCode): $($_.Exception.Response.StatusDescription)" 97 | } 98 | 99 | } 100 | End {} 101 | } -------------------------------------------------------------------------------- /src/MsrcSecurityUpdates/Public/Get-MsrcCvrfExploitabilityIndex.ps1: -------------------------------------------------------------------------------- 1 | Function Get-MsrcCvrfExploitabilityIndex { 2 | <# 3 | .SYNOPSIS 4 | Get the exploitability index of vulnerabilities found in CVRF document 5 | 6 | .DESCRIPTION 7 | This function gathers the Exploitability Index from vulnerabilities in a CVRF document. 8 | 9 | .PARAMETER Vulnerability 10 | A vulnerability object or objects from a CVRF document object 11 | 12 | .EXAMPLE 13 | Get-MsrcCvrfDocument -ID 2016-Nov | Get-MsrcCvrfExploitabilityIndex 14 | 15 | Get the exploitability index from a CVRF document using the pipeline. 16 | 17 | .EXAMPLE 18 | $cvrfDocument = Get-MsrcCvrfDocument -ID 2016-Nov 19 | Get-MsrcCvrfExploitabilityIndex -Vulnerability $cvrfDocument.Vulnerability 20 | 21 | Get the exploitability index from a CVRF document using a variable and parameters 22 | #> 23 | [CmdletBinding()] 24 | Param ( 25 | [Parameter(Mandatory,ValueFromPipelineByPropertyName)] 26 | $Vulnerability 27 | ) 28 | Begin { 29 | $ThreatsExploitStatusType = 1 30 | } 31 | Process { 32 | $Vulnerability | ForEach-Object { 33 | $v = $_ 34 | 35 | $v.Threats | 36 | Where-Object { $_.Type -eq $ThreatsExploitStatusType } | 37 | ForEach-Object { 38 | 39 | $es = Get-MsrcThreatExploitStatus -ExploitStatusString $_.Description.Value 40 | [PSCustomObject]@{ 41 | CVE = $v.CVE 42 | Title = $v.Title.Value 43 | Weakness = $(if ($v.CWE) { '{0} : {1}' -f "$($v.CWE.ID)","$($v.CWE.Value)"}) 44 | 'Customer Action Required' = if ($customerActionNotes = $v.Notes | Where-Object { $_.Title -eq "Customer Action Required" }) { 45 | $customerActionNotes.Value 46 | } else { 47 | 'Yes' 48 | } ; 49 | PubliclyDisclosed = $es.PubliclyDisclosed 50 | Exploited = $es.Exploited 51 | LatestSoftwareRelease = $es.LatestSoftwareRelease 52 | OlderSoftwareRelease = $es.OlderSoftwareRelease 53 | } 54 | } 55 | } 56 | } 57 | End {} 58 | } -------------------------------------------------------------------------------- /src/MsrcSecurityUpdates/Public/Get-MsrcSecurityBulletinHtml.ps1: -------------------------------------------------------------------------------- 1 | Function Get-MsrcSecurityBulletinHtml { 2 | [CmdletBinding()] 3 | Param( 4 | 5 | [Parameter(Mandatory,ValueFromPipelineByPropertyName)] 6 | $Vulnerability, 7 | 8 | [Parameter(Mandatory,ValueFromPipelineByPropertyName)] 9 | $ProductTree, 10 | 11 | 12 | [Parameter(Mandatory,ValueFromPipelineByPropertyName)] 13 | $DocumentTracking, 14 | 15 | [Parameter(Mandatory,ValueFromPipelineByPropertyName)] 16 | $DocumentTitle 17 | ) 18 | Begin { 19 | $css = @' 20 | body { 21 | background-color: darkgray; 22 | } 23 | 24 | h1 { 25 | color: maroon; 26 | } 27 | table { 28 | font-family: Arial, Helvetica, sans-serif; 29 | border-collapse: collapse; 30 | width: 100%; 31 | } 32 | 33 | table td, th { 34 | border: 1px solid #ddd; 35 | padding: 8px; 36 | } 37 | 38 | table tr:nth-child(even){ 39 | background-color: #ddd; 40 | } 41 | 42 | table tr:hover {background-color: #FAF0E6;} 43 | 44 | table th { 45 | padding-top: 12px; 46 | padding-bottom: 12px; 47 | text-align: left; 48 | background-color: #C0C0C0; 49 | } 50 | '@ 51 | $htmlDocumentTemplate = @' 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 64 | 65 | 66 | 74 | 75 | 76 | 77 | 78 |
79 | 80 |

Microsoft Security Bulletin Summary for {0}

81 | 82 |

This document is a summary for Microsoft security updates released for {0}.

83 | 84 |

Microsoft also provides information to help customers prioritize 85 | monthly security updates with any non-security, high-priority updates that are being 86 | released on the same day as the monthly security updates. Please see the section, 87 | Other Information. 88 |

89 | 90 |

91 | As a reminder, the Security Updates Guide 92 | will be replacing security bulletins. Please see our blog post, 93 | Furthering our commitment to security updates, for more details. 94 |

95 | 96 |

To receive automatic notifications whenever Microsoft Security 97 | Updates are issued, subscribe to Microsoft Technical Security Notifications. 98 |

99 | 100 |

Executive Summaries

101 | 102 |

The following table summarizes the security updates for this month in order of severity. 103 | For details on affected software, see the next section, Affected Software. 104 |

105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | {1} 119 |
CVE IDVulnerability DescriptionWeaknessCustomer Action RequiredMaximum Severity RatingVulnerability ImpactAffected Software
120 | 121 |

Exploitability Index

122 | 123 |

The following table provides an exploitability assessment for this vulnerability at the time of original publication.

124 | 125 |

How do I use this table?

126 | 127 |

Use this table to learn about the likelihood of code execution and denial of service exploits within 30 days of security bulletin release, for each of the security updates that you may need to install. Review each of the assessments below, in accordance with your specific configuration, to prioritize your deployment of this month's updates. For more information about what these ratings mean, and how they are determined, please see Microsoft Exploitability Index. 128 |

129 | 130 |

In the columns below, "Latest Software Release" refers to the subject software, and "Older Software Releases" refers to all older, supported releases of the subject software, as listed in the "Affected Software" and "Non-Affected Software" tables in the bulletin.

131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | {2} 143 |
CVE IDVulnerability TitleExploitability Assessment for Latest Software ReleaseExploitability Assessment for Older Software ReleaseDenial of Service Exploitability Assessment
144 | 145 |

Affected Software

146 | 147 |

The following tables list the bulletins in order of major software category and severity.

148 |

Use these tables to learn about the security updates that you may need to install. You should review each software program or component listed to see whether any security updates pertain to your installation. If a software program or component is listed, then the severity rating of the software update is also listed.

149 |

Note: You may have to install several security updates for a single vulnerability. Review the whole column for each bulletin identifier that is listed to verify the updates that you have to install, based on the programs or components that you have installed on your system.

150 | 151 | 152 | {3} 153 | 154 | 155 |

Detection and Deployment Tools and Guidance

156 | 157 |

Several resources are available to help administrators deploy security updates.

158 | 173 | 174 |

For information about these and other tools that are available, see 175 | Security Tools for IT Pros. 176 |

177 | 178 |

Other Information

179 | 180 |

Microsoft Windows Malicious Software Removal Tool

181 | 182 |

Microsoft will release an updated version of the Microsoft Windows 183 | Malicious Software Removal Tool on Windows Update, Microsoft Update, Windows Server 184 | Update Services, and the Download Center.

185 | 186 |

Microsoft Active Protections Program (MAPP)

187 | 188 |

To improve security protections for customers, Microsoft provides 189 | vulnerability information to major security software providers in advance of each 190 | monthly security update release. Security software providers can then use this vulnerability 191 | information to provide updated protections to customers via their security software 192 | or devices, such as antivirus, network-based intrusion detection systems, or host-based 193 | intrusion prevention systems. To determine whether active protections are available 194 | from security software providers, please visit the active protections websites provided 195 | by program partners, listed in 196 | Microsoft Active Protections Program (MAPP) Partners. 197 |

198 | 199 |

Security Strategies and Community

200 | 201 |

Updates for other security issues are available from the following locations:

202 | 203 | 212 | 213 |

IT Pro Security Community

214 | 215 |

Learn to improve security and optimize your IT infrastructure, 216 | and participate with other IT Pros on security topics in 217 | IT Pro Security Community. 218 |

219 | 220 |

Support

221 | 234 | 235 |

Disclaimer

236 | 237 |

The information provided in the Microsoft Knowledge Base is 238 | provided "as is" without warranty of any kind. Microsoft disclaims all 239 | warranties, either express or implied, including the warranties of merchantability 240 | and fitness for a particular purpose. In no event shall Microsoft Corporation or 241 | its suppliers be liable for any damages whatsoever including direct, indirect, incidental, 242 | consequential, loss of business profits or special damages, even if Microsoft Corporation 243 | or its suppliers have been advised of the possibility of such damages. Some states 244 | do not allow the exclusion or limitation of liability for consequential or incidental 245 | damages so the foregoing limitation may not apply.

246 | 247 |
248 | 249 | 250 | 251 | '@ 252 | 253 | $cveSummaryRowTemplate = @' 254 | 255 | {0} 256 | {1} 257 | {2} 258 | {3} 259 | {4} 260 | {5} 261 | {6} 262 | 263 | '@ 264 | $cveSummaryTableHtml = '' 265 | 266 | $exploitabilityRowTemplate = @' 267 | 268 | {0} 269 | {1} 270 | {2} 271 | {3} 272 | {4} 273 | 274 | '@ 275 | 276 | $exploitabilityIndexTableHtml = '' 277 | 278 | $affectedSoftwareNameHeaderTemplate = @' 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | {1} 293 |
{0}
CVE IDKB ArticleRestart RequiredSeverityImpact
294 | '@ 295 | 296 | $affectedSoftwareRowTemplate = @' 297 | 298 | {0} 299 | {1} 300 | {2} 301 | {3} 302 | {4} 303 | 304 | '@ 305 | 306 | $affectedSoftwareTableHtml = '' 307 | $affectedSoftwareDocumentHtml = '' 308 | } 309 | Process { 310 | 311 | #region CVE Summary Table 312 | $HT = @{ 313 | Vulnerability = $PSBoundParameters['Vulnerability'] 314 | ProductTree = $PSBoundParameters['ProductTree'] 315 | } 316 | 317 | Get-MsrcCvrfCVESummary @HT | 318 | ForEach-Object { 319 | $cveSummaryTableHtml += $cveSummaryRowTemplate -f @( 320 | "$($_.CVE)
MITRE
NVD" 321 | $_.Description 322 | if ($_.Weakness) { $_.Weakness } else { 'N/A'} 323 | $_.'Customer Action Required' 324 | $_.'Maximum Severity Rating' 325 | $_.'Vulnerability Impact' -join ',
' 326 | $_.'Affected Software' -join ',
' 327 | ) 328 | } 329 | #endregion 330 | 331 | #region Exploitability Index Table 332 | 333 | Get-MsrcCvrfExploitabilityIndex -Vulnerability $PSBoundParameters['Vulnerability'] | 334 | ForEach-Object { 335 | $exploitabilityIndexTableHtml += $exploitabilityRowTemplate -f @( 336 | $_.CVE #TODO - make this an href 337 | $_.Title 338 | $_.LatestSoftwareRelease 339 | $_.OlderSoftwareRelease 340 | 'N/A' # was $ExploitStatus.DenialOfService 341 | ) 342 | } 343 | #endregion 344 | 345 | #region Affected Software Table 346 | 347 | $affectedSoftware = Get-MsrcCvrfAffectedSoftware @HT 348 | 349 | $affectedSoftware.FullProductName | 350 | Sort-Object -Unique | 351 | ForEach-Object { 352 | 353 | $PN = $_ 354 | 355 | $affectedSoftwareTableHtml = '' 356 | 357 | $affectedSoftware | 358 | Where-Object { $_.FullProductName -eq $PN } | 359 | Sort-Object -Unique -Property CVE | 360 | ForEach-Object { 361 | $affectedSoftwareTableHtml += $affectedSoftwareRowTemplate -f @( 362 | $_.CVE, 363 | $( 364 | if (-not($_.KBArticle)) { 365 | 'None' 366 | } else { 367 | ($_.KBArticle | ForEach-Object { 368 | '{1}
' -f $_.URL, $_.ID 369 | }) -join '
' 370 | } 371 | ), 372 | $( 373 | if (-not($_.RestartRequired)) { 374 | 'Unknown' 375 | } else{ 376 | ($_.RestartRequired | ForEach-Object { 377 | '{0}
' -f $_ 378 | }) -join '
' 379 | } 380 | ), 381 | $( 382 | if (-not($_.Severity)) { 383 | 'Unknown' 384 | } else { 385 | ($_.Severity | ForEach-Object { 386 | '{0}
' -f $_ 387 | }) -join '
' 388 | } 389 | ), 390 | $( 391 | if (-not($_.Impact)) { 392 | 'Unknown' 393 | } else { 394 | ($_.Impact | ForEach-Object { 395 | '{0}
' -f $_ 396 | }) -join '
' 397 | } 398 | ) 399 | ) 400 | } 401 | $affectedSoftwareDocumentHtml += $affectedSoftwareNameHeaderTemplate -f @( 402 | $PN 403 | $affectedSoftwareTableHtml 404 | ) 405 | } 406 | #endregion 407 | 408 | $htmlDocumentTemplate -f @( 409 | $DocumentTitle.Value, # Title 410 | $cveSummaryTableHtml, # CVE Summary Rows 411 | $exploitabilityIndexTableHtml, # Expoitability Rows 412 | $affectedSoftwareDocumentHtml, # Affected Software Rows 413 | "$($MyInvocation.MyCommand.Version.ToString())", 414 | $css 415 | ) 416 | 417 | } 418 | End {} 419 | } -------------------------------------------------------------------------------- /src/MsrcSecurityUpdates/Public/Get-MsrcSecurityUpdate.ps1: -------------------------------------------------------------------------------- 1 | Function Get-MsrcSecurityUpdate { 2 | <# 3 | .SYNOPSIS 4 | Get MSRC security updates 5 | 6 | .DESCRIPTION 7 | Calls the CVRF Update API to get a list of security updates 8 | 9 | .PARAMETER After 10 | Get security updates released after this date 11 | 12 | .PARAMETER Before 13 | Get security updates released before this date 14 | 15 | .PARAMETER Year 16 | Get security updates for the specified year (ie. 2016) 17 | 18 | .PARAMETER Vulnerability 19 | Get security updates for the specified Vulnerability CVE (ie. CVE-2016-0128) 20 | 21 | .PARAMETER Cvrf 22 | Get security update for the specified CVRF ID (ie. 2016-Aug) 23 | 24 | .EXAMPLE 25 | Get-MsrcSecurityUpdate 26 | 27 | Get all the updates 28 | 29 | .EXAMPLE 30 | Get-MsrcSecurityUpdate -Vulnerability CVE-2017-0003 31 | 32 | Get all the updates containing Vulnerability CVE-2017-003 33 | 34 | .EXAMPLE 35 | Get-MsrcSecurityUpdate -Year 2017 36 | 37 | Get all the updates for the year 2017 38 | 39 | .EXAMPLE 40 | Get-MsrcSecurityUpdate -Cvrf 2017-Jan 41 | 42 | Get all the updates for the CVRF document with ID of 2017-Jan 43 | 44 | .EXAMPLE 45 | Get-MsrcSecurityUpdate -Before 2017-01-01 46 | 47 | Get all the updates before January 1st, 2017 48 | 49 | .EXAMPLE 50 | Get-MsrcSecurityUpdate -After 2017-01-01 51 | 52 | Get all the updates after January 1st, 2017 53 | 54 | .EXAMPLE 55 | Get-MsrcSecurityUpdate -Before 2017-01-01 -After 2016-10-01 56 | 57 | Get all the updates before January 1st, 2017 and after October 1st, 2016 58 | 59 | .EXAMPLE 60 | Get-MsrcSecurityUpdate -After (Get-Date).AddDays(-60) -Before (Get-Date) 61 | 62 | Get all updates between now and the last 60 days 63 | 64 | .NOTES 65 | An API Key for the MSRC CVRF API is not required anymore 66 | 67 | #> 68 | [CmdletBinding(DefaultParameterSetName='All')] 69 | Param ( 70 | 71 | [Parameter(ParameterSetName='ByDate')] 72 | [DateTime]$After, 73 | 74 | [Parameter(ParameterSetName='ByDate')] 75 | [DateTime]$Before, 76 | 77 | [Parameter(Mandatory,ParameterSetName='ByYear')] 78 | [ValidateScript({ 79 | if ($_ -lt 2016 -or $_ -gt [DateTime]::Now.Year) { 80 | throw 'Year must be between 2016 and this year' 81 | } else { 82 | $true 83 | } 84 | })] 85 | [Int]$Year, 86 | 87 | [Parameter(Mandatory,ParameterSetName='ByVulnerability')] 88 | [String]$Vulnerability 89 | ) 90 | DynamicParam { 91 | $Dictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary 92 | 93 | $ParameterName = 'CVRF' 94 | $AttribColl1 = New-Object System.Collections.ObjectModel.Collection[System.Attribute] 95 | $Param1Att = New-Object System.Management.Automation.ParameterAttribute 96 | $Param1Att.Mandatory = $true 97 | # $Param1Att.ValueFromPipeline = $true 98 | $Param1Att.ParameterSetName = 'ByCVRF' 99 | $AttribColl1.Add($Param1Att) 100 | 101 | try { 102 | $allCVRFID = Get-CVRFID 103 | } catch { 104 | Throw "`nUnable to get online the list of CVRF ID because:`n$($_.Exception.Message)" 105 | } 106 | if ($allCVRFID) { 107 | $AttribColl1.Add((New-Object System.Management.Automation.ValidateSetAttribute($allCVRFID))) 108 | $Dictionary.Add($ParameterName,(New-Object System.Management.Automation.RuntimeDefinedParameter($ParameterName, [string], $AttribColl1))) 109 | 110 | $Dictionary 111 | } 112 | } 113 | Begin {} 114 | Process { 115 | 116 | switch ($PSCmdlet.ParameterSetName) { 117 | 118 | ByDate { 119 | 120 | $sb = New-Object System.Text.StringBuilder 121 | 122 | $null = $sb.Append("$($msrcApiUrl)/Updates?`$filter=") 123 | 124 | if ($PSBoundParameters.ContainsKey('Before')) { 125 | 126 | $null = $sb.Append("CurrentReleaseDate lt $($Before.ToString('yyyy-MM-dd'))") 127 | 128 | if ($PSBoundParameters.ContainsKey('After')) { 129 | $null = $sb.Append(' and ') 130 | } 131 | 132 | } 133 | 134 | if ($PSBoundParameters.ContainsKey('After')) { 135 | 136 | $null = $sb.Append("CurrentReleaseDate gt $($After.ToString('yyyy-MM-dd'))") 137 | 138 | } 139 | 140 | $null = $sb.Append("&$($msrcApiVersion)") 141 | 142 | $url = $sb.ToString() 143 | 144 | break 145 | } 146 | ByYear { 147 | $url = "{0}/Updates('{1}')?{2}" -f $msrcApiUrl,$Year,$msrcApiVersion 148 | break 149 | } 150 | ByVulnerability { 151 | $url = "{0}/Updates('{1}')?{2}" -f $msrcApiUrl,$Vulnerability,$msrcApiVersion 152 | break 153 | } 154 | ByCVRF { 155 | $url = "{0}/Updates('{1}')?{2}" -f $msrcApiUrl,$($PSBoundParameters['CVRF']),$msrcApiVersion 156 | break 157 | } 158 | Default { 159 | $url = "{0}/Updates?{1}" -f $msrcApiUrl,$msrcApiVersion 160 | } 161 | } 162 | 163 | $RestMethod = @{ 164 | uri = $url 165 | Headers = @{ 'Accept' = 'application/json' } 166 | ErrorAction = 'Stop' 167 | } 168 | if ($global:msrcProxy){ 169 | $RestMethod.Add('Proxy' , $global:msrcProxy) 170 | } 171 | if ($global:msrcProxyCredential){ 172 | $RestMethod.Add('ProxyCredential' , $global:msrcProxyCredential) 173 | } 174 | if ($global:MSRCAdalAccessToken) 175 | { 176 | $RestMethod.Headers.Add('Authorization' , $global:MSRCAdalAccessToken.CreateAuthorizationHeader()) 177 | } 178 | 179 | try { 180 | 181 | [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 182 | Write-Verbose -Message "Calling $($RestMethod.uri)" 183 | 184 | $r = Invoke-RestMethod @RestMethod 185 | 186 | } catch { 187 | Write-Error -Message "HTTP Get failed with status code $($_.Exception.Response.StatusCode): $($_.Exception.Response.StatusDescription)" 188 | } 189 | 190 | if (-not $r) { 191 | Write-Warning -Message 'No results returned from the /Update API' 192 | } else { 193 | Switch ($global:msrcApiUrl) { 194 | 'https://api.msrc.microsoft.com/cvrf/v2.0' {$r.Value} 195 | 'https://api.msrc.microsoft.com/cvrf/v3.0' {$r} 196 | } 197 | } 198 | 199 | } 200 | End {} 201 | } -------------------------------------------------------------------------------- /src/MsrcSecurityUpdates/Public/Get-MsrcVulnerabilityReportHtml.ps1: -------------------------------------------------------------------------------- 1 | Function Get-MsrcVulnerabilityReportHtml { 2 | <# 3 | 4 | .SYNOPSIS 5 | Use a CVRF document to create a Vulnerability summary 6 | 7 | .DESCRIPTION 8 | Use a CVRF document to create a Vulnerability summary 9 | 10 | .PARAMETER Vulnerability 11 | The Vulnerability node of a CVRF document 12 | 13 | .PARAMETER ProductTree 14 | The ProductTree node of a CVRF document 15 | 16 | .EXAMPLE 17 | Get-MsrcCvrfDocument -ID 2016-Aug | 18 | Get-MsrcVulnerabilityReportHtml | 19 | Out-File -FilePath Cvrf-CVE-Summary.html 20 | 21 | It creates a report with all the Vulnerabilities in a CVRF document 22 | 23 | .EXAMPLE 24 | $cvrfDoc = Get-MsrcCvrfDocument -ID 2016-Nov 25 | $cvrfDoc.Vulnerability | Foreach-Object { 26 | 27 | Write-Verbose "Dealing with CVE: $($_.CVE)" -Verbose 28 | Get-MsrcVulnerabilityReportHtml -Vulnerability $_ -ProductTree $cvrfDoc.ProductTree | 29 | Out-File -FilePath "Cvrf-$($vulnerability.CVE)-Summary.html" 30 | } 31 | 32 | It creates a report for each of the Vulnerabilities in a CVRF document 33 | 34 | .EXAMPLE 35 | $cvrfDoc = Get-MsrcCvrfDocument -ID 2016-Nov 36 | $HT = @{ 37 | Vulnerability = ($cvrfDoc.Vulnerability | Where-Object {$_.CVE -In @('CVE-2016-0026','CVE-2016-7202','CVE-2016-3343')}) 38 | ProductTree = $cvrfDoc.ProductTree 39 | } 40 | Get-MsrcVulnerabilityReportHtml @HT | Out-File -FilePath Cvrf-CVE-Summary.html 41 | 42 | It creates a report for specific Vulnerabilities in a CVRF document 43 | #> 44 | [CmdletBinding()] 45 | [OutputType([string])] 46 | Param( 47 | 48 | [Parameter(Mandatory,ValueFromPipelineByPropertyName)] 49 | $Vulnerability, 50 | 51 | [Parameter(Mandatory,ValueFromPipelineByPropertyName)] 52 | $ProductTree, 53 | 54 | [Switch]$ShowNoProgress 55 | ) 56 | Begin{ 57 | 58 | $HT = @{ ErrorAction = 'Stop'} 59 | 60 | $MaximumSeverityType = 3 61 | $ThreatsImpactType = 0 62 | $ThreatsExploitStatusType = 1 63 | $TagType = 7 64 | $CNAType = 8 65 | $RemediationsMitigationType = 1 66 | $RemediationsWorkaroundType = 0 67 | 68 | try { 69 | $JsonMetrics = Get-Content -Path (Join-Path -Path $PSScriptRoot -ChildPath 'CVSS-Metrics.json' @HT) @HT | 70 | Out-String @HT| ConvertFrom-Json @HT 71 | 72 | $JsonDescriptions = Get-Content -Path (Join-Path -Path $PSScriptRoot -ChildPath 'CVSS-Descriptions.json'@HT) @HT | 73 | Out-String @HT| ConvertFrom-Json @HT 74 | } catch { 75 | Throw "Failed to get required json files content because $($_.Exception.Message)" 76 | } 77 | 78 | $css = @' 79 | body { 80 | background-color: white; 81 | font-family: sans-serif; 82 | } 83 | 84 | h1 { 85 | color: black; 86 | } 87 | table { 88 | font-family: Arial, Helvetica, sans-serif; 89 | border-collapse: collapse; 90 | width: 100%; 91 | } 92 | 93 | table td, th { 94 | border: 1px solid #ddd; 95 | padding: 8px; 96 | } 97 | 98 | table tr:nth-child(even){ 99 | background-color: #ddd; 100 | } 101 | 102 | table tr:hover {background-color: #FAF0E6;} 103 | 104 | table th { 105 | padding-top: 12px; 106 | padding-bottom: 12px; 107 | text-align: left; 108 | background-color: #C0C0C0; 109 | } 110 | '@ 111 | } 112 | Process { 113 | $htmlDocumentTemplate = @' 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 126 | 127 | 128 | 137 | 138 | 139 | 142 | 143 | 146 | 147 | 148 | 149 | 150 |
151 | 152 |

Microsoft CVE Summary

153 | 154 |

This report contains detail for the following vulnerabilities:

155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | {0} 163 |
CVE Issued byTagCVE IDCVE Title
164 | {1} 165 |
166 |
167 | 168 | 169 | '@ 170 | $cveListHtmlObjects = @() 171 | 172 | $cveSectionHtml = '' 173 | 174 | $TotalCVE = $Vulnerability.Count 175 | $count = 0 176 | $Vulnerability | ForEach-Object -Process { 177 | $count++ 178 | $v = $_ 179 | $Progress = @{ 180 | Activity = 'Getting Msrc Vulnerability Html Report' 181 | Status = "$($count)/$($TotalCVE) => $($v.CVE) " 182 | PercentComplete = ($count/$TotalCVE*100) 183 | ErrorAction = 'SilentlyContinue' 184 | } 185 | if (-not($ShowNoProgress)) { Write-Progress @Progress } 186 | Write-Verbose -Message "Dealing with $($_.CVE)" 187 | 188 | #region CVE Summary Table 189 | 190 | $cveSummaryTableHtml = @' 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 |
CVE IDVulnerability DescriptionMaximum Severity RatingVulnerability Impact
{0}{1}{2}{3}
207 | '@ 208 | 209 | $MaximumSeverity = Switch ( 210 | ($_.Threats | Where-Object {$_.Type -eq $MaximumSeverityType}).Description.Value | Select-Object -Unique 211 | ) { 212 | 'Critical' { 'Critical' ; break } 213 | 'Important' { 'Important' ; break } 214 | 'Moderate' { 'Moderate' ; break } 215 | 'Low' { 'Low' ; break } 216 | 'None' { 'None' ; break } 217 | default { 218 | Write-Warning "Could not determine the Maximum Severity from the Threats for $($v.CVE)" 219 | 'Unknown' 220 | } 221 | } 222 | if (-not($MaximumSeverity)) { 223 | $MaximumSeverity = 'Unknown' 224 | } 225 | 226 | 227 | if ($ImpactValues = ($v.Threats | Where-Object { $_.Type -eq $ThreatsImpactType }).Description.Value | Select-Object -Unique) { 228 | $impactColumn = $ImpactValues -join ',
' 229 | } else { 230 | Write-Warning -Message "Could not determine the Impact from the Threats for $($v.CVE)" 231 | $impactColumn = 'Unknown' 232 | } 233 | 234 | $vulnDescriptionColumnTemplate = @' 235 | CVE Title: {0} 236 |
237 | Weakness: {7} 238 |
239 | Customer Action Required: {8} 240 |
241 | CVSS:
{1} 242 |
243 | Executive Summary:
{6} 244 |
245 | FAQ:
{2} 246 |
247 | Mitigations:
{3} 248 |
249 | Workarounds:
{4} 250 |
251 | Revision:
{5} 252 |
253 | '@ 254 | 255 | $vulnDescriptionColumn = $vulnDescriptionColumnTemplate -f @( 256 | # $cveTitle 257 | $( 258 | if ($cveTitle = $v.Title.Value) { 259 | $cveTitle 260 | } else { 261 | Write-Warning -Message "Missing Title for $($v.CVE)" 262 | ($cveTitle = 'Unknown') 263 | } 264 | ), 265 | # $cvssScoreSet 266 | $( 267 | #Scores among the affected products can be different. So, just find the most severe. 268 | $highestBase = 0.0 269 | $highestCvssScore = $null 270 | ForEach($score in $v.CvssScoreSets) { 271 | if ($score.BaseScore -gt $highestBase) { 272 | $highestBase = $score.BaseScore 273 | $highestCvssScore = $score 274 | } 275 | } 276 | 277 | if (($null -ne $highestCvssScore) -and ($null -ne $highestCvssScore.Vector) -and ($highestCvssScore.Vector.Split('/').Length -gt 1)) { 278 | $cvssArray = $highestCvssScore.Vector.Split('/') 279 | 280 | $cvssScoreTemplate = @' 281 |
{0} 282 | 283 | 284 | 285 | 286 | 287 | 288 | {1} 289 |
Base score metrics
290 | 291 | 292 | 293 | 294 | 295 | 296 | {2} 297 |
Temporal score metrics
298 | '@ 299 | $cvssScoreSet = $cvssScoreTemplate -f @( 300 | $rowTemplate = '{1}{3}' 301 | 302 | $baseTags = 'AC', 'AV', 'A', 'C', 'I', 'PR', 'S', 'UI' 303 | $temporalTags = 'E', 'RC', 'RL' 304 | $baseRows = '' 305 | $temporalRows = '' 306 | for($i = 1; $i -lt $cvssArray.Length; $i++) { 307 | 308 | $element = $cvssArray[$i] 309 | $split0 = $element.Split(':')[0] 310 | 311 | $metric = $JsonMetrics.$split0 312 | $value = $JsonMetrics.$element 313 | 314 | $metricDescription = $JsonDescriptions.$split0 315 | $valueDescription = $JsonDescriptions.$element 316 | 317 | 318 | $row = '' + $metric + '' 319 | $row += '' + $value + '' 320 | 321 | if (($null -ne $metricDescription) -and ($null -ne $valueDescription)) { 322 | if ($baseTags.Contains($split0)) { 323 | $baseRows += $rowTemplate -f $metricDescription, $metric, $valueDescription, $value 324 | } else { 325 | if ($temporalTags.Contains($split0)) { 326 | $temporalRows += $rowTemplate -f $metricDescription, $metric, $valueDescription, $value 327 | } 328 | } 329 | } 330 | } 331 | 332 | $formattedScore = '{0} Highest BaseScore:{1}/TemporalScore:{2}' -f $cvssArray[0], $highestCvssScore.BaseScore, $highestCvssScore.TemporalScore 333 | 334 | $formattedScore, $baseRows, $temporalRows 335 | ) 336 | $cvssScoreSet 337 | } else { 338 | 'None' -join '
' 339 | } 340 | ), 341 | # $cveFaq 342 | $( 343 | if ($cveFaq = ($v.Notes | Where-Object {$_.Title -eq 'FAQ'}).Value) { 344 | $cveFaq -join '
' 345 | } else { 346 | 'None' -join '
' 347 | } 348 | ), 349 | # $cveMitigation 350 | $( 351 | if ($cveMitigation = $v.Remediations | Where-Object { $_.Type -eq $RemediationsMitigationType }) { 352 | $cveMitigation.Description.Value -join '
' 353 | 354 | } else { 355 | 'None' -join '
' 356 | } 357 | ), 358 | # $cveWorkaround 359 | $( 360 | if ( $cveWorkaround = ($v.Remediations | Where-Object {$_.Type -eq $RemediationsWorkaroundType }).Description.Value) { 361 | $cveWorkaround -join '
' 362 | } else { 363 | 'None' -join '
' 364 | } 365 | ), 366 | # $Revision 367 | $( 368 | $RevisionStrings = @() 369 | $v.RevisionHistory | 370 | ForEach-Object { 371 | $_ | Add-Member -MemberType NoteProperty -Name RevisionDate -Value ([datetime]$_.Date) -Force -PassThru 372 | } | Sort-Object RevisionDate | 373 | ForEach-Object { 374 | if ( $revision = $($_.Number, $_.RevisionDate.ToString('d'), $_.Description.Value) ) { 375 | $RevisionStrings += $($revision -join '    ') 376 | } 377 | } 378 | if ( $RevisionStrings ) { 379 | $RevisionStrings -join '
' 380 | } else { 381 | 'Unknown' -join '
' 382 | } 383 | ), 384 | # Executive Summary 385 | $( 386 | if ($cveExecSummary = ($v.Notes | Where-Object {$_.Title -eq 'Description'}).Value) { 387 | $cveExecSummary -join '
' 388 | } else { 389 | 'None' -join '
' 390 | } 391 | ) 392 | # CWE Weakness 393 | $( 394 | if ($cveWeakness = $(if ($v.CWE) { '{0} : {1}' -f "$($v.CWE.ID)","$($v.CWE.Value)"})) { 395 | $cveWeakness -join '
' 396 | } else { 397 | 'N/A' -join '
' 398 | } 399 | ) 400 | # Customer Action Required 401 | $( 402 | if ($cveCustomerActionRequired = $v.Notes | Where-Object { $_.Title -eq "Customer Action Required" }) { 403 | $cveCustomerActionRequired.Value -join '
' 404 | } else { 405 | 'Yes' -join '
' 406 | } 407 | ) 408 | 409 | ) 410 | 411 | $cveSectionHtml += '

{0} - {1}

(top)' -f $v.CVE, $cveTitle 412 | 413 | #region CVE Summary List 414 | $cveListHtmlObjects += [PSCustomObject]@{ 415 | Tag = $($v.Notes | Where-Object type -eq $TagType).Value 416 | CNA = $($v.Notes | Where-Object type -eq $CNAType).Value 417 | CVEID = $v.CVE 418 | CVETitle = $cveTitle 419 | } 420 | #endregion 421 | 422 | $cveSectionHtml += $cveSummaryTableHtml -f @( 423 | @" 424 | $($_.CVE) 425 |
426 | MITRE 427 |
428 | NVD 429 |

Issuing CNA: $($($v.Notes | Where-Object type -eq $CNAType).Value)

430 | "@, 431 | $vulnDescriptionColumn, 432 | $MaximumSeverity, 433 | $impactColumn 434 | ) 435 | #endregion 436 | 437 | #region Exploitability Index Table 438 | $exploitabilityIndexTableHtml = @' 439 |

Exploitability Index

440 | 441 |

The following table provides an exploitability assessment for this vulnerability at the time of original publication.

442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 |
Exploitability AssessmentPublicly DisclosedExploited
{0}{1}{2}
457 | '@ 458 | 459 | if ($ExploitStatusThreat = ($v.Threats | Where-Object { $_.Type -eq $ThreatsExploitStatusType } | Select-Object -Last 1).Description.Value) { 460 | $ExploitStatus = Get-MsrcThreatExploitStatus -ExploitStatusString $ExploitStatusThreat 461 | } else { 462 | Write-Warning -Message "Missing ExploitStatus for $($v.CVE)" 463 | } 464 | 465 | $cveSectionHtml += $exploitabilityIndexTableHtml -f @( 466 | # $LatestSoftwareRelease 467 | $( 468 | if ($ExploitStatus.LatestSoftwareRelease) { 469 | $ExploitStatus.LatestSoftwareRelease 470 | } else { 471 | 'Not Found' 472 | } 473 | ), 474 | # $publicly disclosed 475 | $( 476 | if ($ExploitStatus.PubliclyDisclosed) { 477 | $ExploitStatus.PubliclyDisclosed 478 | } else { 479 | 'Not Found' 480 | } 481 | ), 482 | # $Exploited 483 | $( 484 | if ($ExploitStatus.Exploited) { 485 | $ExploitStatus.Exploited 486 | } else { 487 | 'Not Found' 488 | } 489 | ) 490 | ) 491 | #endregion 492 | 493 | #region Affected Software Table 494 | 495 | $affectedSoftwareTableTemplate = @' 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | {1} 514 |
{0}
ProductKB ArticleSeverityImpactSupercedenceCVSS Score SetFixed BuildRestart RequiredKnown Issue
515 |
516 | '@ 517 | 518 | $affectedSoftwareRowTemplate = @' 519 | 520 | {0} 521 | {1} 522 | {2} 523 | {3} 524 | {4} 525 | {5} 526 | {6} 527 | {7} 528 | {8} 529 | 530 | '@ 531 | 532 | $cveSectionHtml += @' 533 |

Affected Software

534 | 535 |

The following tables list the affected software details for the vulnerability.

536 | '@ 537 | $affectedSoftware = Get-MsrcCvrfAffectedSoftware -Vulnerability $v -ProductTree $ProductTree 538 | $affectedSoftwareTableHtml = '' 539 | 540 | 541 | $affectedSoftware.FullProductName | Sort-Object -Unique | ForEach-Object { 542 | 543 | $PN = $_ 544 | 545 | $affectedSoftware | Where-Object {$_.FullProductName -eq $PN} | ForEach-Object { 546 | 547 | $affectedSoftwareTableHtml += $affectedSoftwareRowTemplate -f @( 548 | $PN, 549 | $( 550 | if ($PN -eq 'Microsoft Edge (Chromium-based)') { 551 | @( 552 | '{1} ({2})' -f 'https://learn.microsoft.com/en-us/deployedge/microsoft-edge-relnote-stable-channel', 553 | "$($_.KBArticle.ID)", "$($_.KBArticle.SubType)" 554 | ) 555 | } else { 556 | $_.KBArticle | Get-KBDownloadUrl 557 | } 558 | ), 559 | $( 560 | if (-not($_.Severity)) { 561 | 'Unknown' 562 | } else { 563 | $($_.Severity | Select-Object -Unique) -join '
' 564 | } 565 | ), 566 | $( 567 | if (-not($_.Impact)) { 568 | 'Unknown' 569 | } else { 570 | $($_.Impact | Select-Object -Unique) -join '
' 571 | } 572 | ), 573 | $( 574 | if (-not($_.Supercedence)) { 575 | 'None' 576 | } else { 577 | $($_.Supercedence | Select-Object -Unique) -join '
' 578 | } 579 | ), 580 | $( 581 | 582 | 'Base: {0}
Temporal: {1}
Vector: {2}
' -f ( 583 | $( 584 | if(-not($_.CvssScoreSet.base)) { 585 | 'N/A' 586 | } else{ 587 | $_.CvssScoreSet.base 588 | } 589 | ) 590 | ), 591 | ( 592 | $( 593 | if(-not($_.CvssScoreSet.temporal)) { 594 | 'N/A' 595 | } else { 596 | $_.CvssScoreSet.temporal 597 | } 598 | ) 599 | ), 600 | ( 601 | $( 602 | if(-not($_.CvssScoreSet.vector)) { 603 | 'N/A' 604 | } else { 605 | $_.CvssScoreSet.vector 606 | } 607 | ) 608 | ) 609 | ), 610 | $( 611 | if (-not($_.FixedBuild)) { 612 | 'Unknown' 613 | } else { 614 | $($_.FixedBuild | Select-Object -Unique) -join '
' 615 | } 616 | ), 617 | $( 618 | if (-not($_.RestartRequired)) { 619 | 'Unknown' 620 | } else { 621 | $($_.RestartRequired | Select-Object -Unique) -join '
' 622 | } 623 | ), 624 | $( 625 | if (-not($_.'Known Issue')) { 626 | 'None' 627 | } else { 628 | $_.'Known Issue' | Get-KBDownloadUrl 629 | } 630 | ) 631 | ) 632 | } 633 | } 634 | 635 | $cveSectionHtml += $affectedSoftwareTableTemplate -f @( 636 | $v.CVE, 637 | $affectedSoftwareTableHtml 638 | ) 639 | #endregion 640 | 641 | #region Acknowledgments Table 642 | $acknowledgmentsTableTemplate = @' 643 |

Acknowledgements

644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 |
CVE IDAcknowledgements
{0}{1}
656 | '@ 657 | 658 | if ($v.Acknowledgments) { 659 | $ackVal = '' 660 | $v.Acknowledgments | ForEach-Object { 661 | 662 | if ($_.Name.Value) { 663 | $ackVal += $_.Name.Value 664 | $ackVal += '
' 665 | } 666 | if ($_.URL) { 667 | $ackVal += $_.URL 668 | $ackVal += '
' 669 | } 670 | $ackVal += '

' 671 | } 672 | } else { 673 | Write-Warning -Message "No Acknowledgments for $($v.CVE)" 674 | $ackVal = 'None' 675 | } 676 | 677 | $cveSectionHtml += $acknowledgmentsTableTemplate -f @( 678 | $v.CVE, 679 | $ackVal 680 | ) 681 | } -End { 682 | Write-Progress -Activity 'Getting Msrc Vulnerability Html Report' -Completed 683 | } 684 | #endregion 685 | 686 | ( 687 | $htmlDocumentTemplate -f @( 688 | #sort the objects and put them into the table of contents format before injecting into the document template: 689 | ($( $cveListHtmlObjects | Sort-Object -Property Tag | 690 | ForEach-Object { 691 | '{3}{0}
{1} {2}' -f $_.Tag,$_.CVEID,$_.CVETitle,$_.CNA 692 | }) -join "`n"), 693 | $cveSectionHtml, 694 | "$($MyInvocation.MyCommand.Version.ToString())", 695 | $css,$global:msrcApiUrl 696 | 697 | ) 698 | ) 699 | } 700 | End {} 701 | } 702 | -------------------------------------------------------------------------------- /src/MsrcSecurityUpdates/Public/Set-MSRCApiKey.ps1: -------------------------------------------------------------------------------- 1 | Function Set-MSRCApiKey { 2 | [CmdletBinding(SupportsShouldProcess)] 3 | Param( 4 | [Parameter()] 5 | $ApiKey, 6 | 7 | [Parameter()] 8 | [System.Uri]$Proxy, 9 | 10 | [Parameter()] 11 | [ValidateNotNull()] 12 | [System.Management.Automation.PSCredential] 13 | [System.Management.Automation.Credential()] 14 | $ProxyCredential = [System.Management.Automation.PSCredential]::Empty, 15 | 16 | [Parameter()] 17 | [ValidateSet('3.0','2.0')] 18 | [System.String]$APIVersion='3.0' 19 | ) 20 | Begin {} 21 | Process { 22 | if ($PSCmdlet.ShouldProcess($ApiKey,'Set item')) { 23 | 24 | if ($ApiKey) { 25 | $global:MSRCApiKey = $ApiKey 26 | Write-Verbose -Message "Successfully set your API Key required by cmdlets of this module. Calls to the MSRC APIs will now use your API key." 27 | } 28 | # we also set other shared variables 29 | $global:msrcApiUrl = 'https://api.msrc.microsoft.com/cvrf/v{0}' -f $APIVersion 30 | Write-Verbose -Message "Successfully defined a msrcApiUrl global variable that points to $($global:msrcApiUrl)" 31 | 32 | $global:msrcApiVersion = Switch ($APIVersion) { 33 | '2.0' { 'api-version=2016-08-01'} 34 | '3.0' { 'api-version=2023-11-01'} 35 | } 36 | Write-Verbose -Message "Successfully defined a msrcApiVersion global variable that points to $($global:msrcApiVersion)" 37 | 38 | if ($ProxyCredential -ne [System.Management.Automation.PSCredential]::Empty) { 39 | $global:msrcProxyCredential = $ProxyCredential 40 | Write-Verbose -Message 'Successfully defined a msrcProxyCredential global variable' 41 | } 42 | 43 | if ($Proxy) { 44 | $global:msrcProxy = $Proxy 45 | Write-Verbose -Message "Successfully defined a msrcProxyCredential global variable that points to $($global:msrcProxy)" 46 | } 47 | 48 | if ($global:MSRCAdalAccessToken) 49 | { 50 | Remove-Variable -Name MSRCAdalAccessToken -Scope Global 51 | } 52 | } 53 | } 54 | End {} 55 | } -------------------------------------------------------------------------------- /src/MsrcSecurityUpdates/Public/Set-MsrcAdalAccessToken.ps1: -------------------------------------------------------------------------------- 1 | Function Set-MSRCAdalAccessToken { 2 | [CmdletBinding(SupportsShouldProcess)] 3 | Param() 4 | Begin {} 5 | Process { 6 | if ([AppDomain]::CurrentDomain.SetupInformation.TargetFrameworkName -like "*v5.*") { 7 | throw ".Net Core v5.x is not currently supported" 8 | } 9 | 10 | if ($PSCmdlet.ShouldProcess('Set the MSRCApiKey using MSRCAdalAccessToken')) { 11 | Add-Type -Path "$PSScriptRoot/../Microsoft.IdentityModel.Clients.ActiveDirectory.dll" -ErrorAction SilentlyContinue -WarningAction SilentlyContinue 12 | 13 | $authority = 'https://login.windows.net/microsoft.onmicrosoft.com/' 14 | 15 | $authContext = New-Object Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext($authority) 16 | 17 | $rUri = New-Object System.Uri -ArgumentList 'https://msrc-api-powershell' 18 | 19 | $promptBehavior = [Microsoft.IdentityModel.Clients.ActiveDirectory.PromptBehavior]::Auto 20 | 21 | 22 | $ResourceId = 'https://msrc-api-prod.azurewebsites.net' 23 | 24 | $ClientId = 'c7fe3b9e-4d97-462d-ae1b-c16e679be355' 25 | 26 | $global:MSRCAdalAccessToken = $null 27 | 28 | if ($null -ne $authContext.AcquireToken) { 29 | $global:MSRCAdalAccessToken = $authContext.AcquireToken($ResourceId, $ClientId, $rUri,$promptBehavior) 30 | } elseif ($null -ne $authContext.AcquireTokenAsync) { 31 | $platformParams = New-Object Microsoft.IdentityModel.Clients.ActiveDirectory.PlatformParameters($promptBehavior) 32 | $task = $authContext.AcquireTokenAsync($ResourceId, $ClientId, $rUri,$platformParams) 33 | $task.Wait() 34 | $global:MSRCAdalAccessToken = $task.Result 35 | } 36 | 37 | if ($null -ne $global:MSRCAdalAccessToken) { 38 | Write-Verbose -Message "Successfully set your Access Token required by cmdlets of this module. Calls to the MSRC APIs will now use your access token." 39 | } else { 40 | throw "Failed Acquiring Access Token!" 41 | } 42 | } 43 | } 44 | End {} 45 | } 46 | -------------------------------------------------------------------------------- /src/README.md: -------------------------------------------------------------------------------- 1 | # Sample Code 2 | 3 | The sample code serves as an example on how to interact with the MSRC Security Updates API through Powershell. 4 | 5 | In the PowerShell module, you will see script functions that show how to interact with the API, as well 6 | as functions that organize data from the industry-standard [CVRF document format](http://www.icasi.org/cvrf-v1-1-dictionary-of-elements/#40rem) to show some reporting scenarios. 7 | 8 | You can clone this repo, or download the latest modules directly from the Microsoft Powershell Gallery (Powershell v3 and higher). 9 | 10 | ## Installing directly from Microsoft Powershell Gallery 11 | 12 | **Must be running Powershell v5.1 or higher** 13 | With this solution, you do not need to download code from this Github repository. 14 | Instead, you can download the directly from the Microsoft Powershell Gallery. 15 | The Powershell version can be verified by checking the Major variable in the ``$PSVersionTable.PSVersion`` variable: 16 | 17 | ``` 18 | $PSVersionTable.PSVersion 19 | 20 | Major Minor Build Revision 21 | ----- ----- ----- -------- 22 | 5 1 14393 693 23 | ``` 24 | 25 | If you're running **as an administrator** you can install the module in your program files: 26 | ```Powershell 27 | Install-Module MSRCSecurityUpdates -Force 28 | Import-Module MSRCSecurityUpdates 29 | ```` 30 | 31 | If you're **not running as an administrator**, you can install the module in your profile by providing an additional parameter about the Scope: 32 | ```Powershell 33 | Install-Module MSRCSecurityUpdates -Force -Scope CurrentUser 34 | Import-Module MSRCSecurityUpdates 35 | ```` 36 | 37 | ## Hello, world! 38 | See *MsrcSecurityUpdates.tests.ps1* which exercises all of the functions. 39 | 40 | ## Cmdlets 41 | 42 | ```Powershell 43 | Get-Command -Module MsrcSecurityUpdates 44 | 45 | CommandType Name Version Source 46 | ----------- ---- ------- ------ 47 | Function Get-KBDownloadUrl 1.8.7 MsrcSecurityUpdates 48 | Function Get-MsrcCvrfAffectedSoftware 1.8.7 MsrcSecurityUpdates 49 | Function Get-MsrcCvrfCVESummary 1.8.7 MsrcSecurityUpdates 50 | Function Get-MsrcCvrfDocument 1.8.7 MsrcSecurityUpdates 51 | Function Get-MsrcCvrfExploitabilityIndex 1.8.7 MsrcSecurityUpdates 52 | Function Get-MsrcSecurityBulletinHtml 1.8.7 MsrcSecurityUpdates 53 | Function Get-MsrcSecurityUpdate 1.8.7 MsrcSecurityUpdates 54 | Function Get-MsrcVulnerabilityReportHtml 1.8.7 MsrcSecurityUpdates 55 | Function Set-MSRCAdalAccessToken 1.8.7 MsrcSecurityUpdates 56 | Function Set-MSRCApiKey 1.8.7 MsrcSecurityUpdates 57 | ``` 58 | 59 | ## Generating a HTML document of Monthly Updates 60 | 61 | In this common scenario, the *Get-MsrcCvrfDocument* and *Get-MsrcVulnerabilityReportHtml* can be pipelined together to generate a HTML document with *out-file*: 62 | 63 | ```Powershell 64 | ### Install the module from the PowerShell Gallery (must be run as Admin) 65 | Install-Module -Name msrcsecurityupdates -force 66 | Import-module MsrcSecurityUpdates 67 | $monthOfInterest = '2017-Apr' 68 | 69 | Get-MsrcCvrfDocument -ID $monthOfInterest -Verbose | 70 | Get-MsrcSecurityBulletinHtml -Verbose | 71 | Out-File c:\temp\MSRCAprilSecurityUpdates.html 72 | ``` 73 | You can also build a modified object to pass into *Get-MsrcVulnerabilityReportHtml*. This allows more customization of the report being generated. In this example, the generated report will only have the wanted CVE's included: 74 | 75 | ```Powershell 76 | Install-Module -Name MsrcSecurityUpdates -Force 77 | Import-Module -Name MsrcSecurityUpdates -Force 78 | 79 | $monthOfInterest = "2017-Mar" 80 | 81 | $CVEsWanted = @( 82 | "CVE-2017-0001", 83 | "CVE-2017-0005" 84 | ) 85 | $Output_Location = "C:\your\path\here" 86 | 87 | $CVRFDoc = Get-MsrcCvrfDocument -ID $monthOfInterest -Verbose 88 | $CVRFHtmlProperties = @{ 89 | Vulnerability = $CVRFDoc.Vulnerability | Where-Object {$_.CVE -in $CVEsWanted} 90 | ProductTree = $CVRFDoc.ProductTree 91 | } 92 | 93 | Get-MsrcVulnerabilityReportHtml @CVRFHtmlProperties -Verbose | Out-File $Output_Location 94 | ``` 95 | 96 | An alternate HTML template is also avalible which generates reports which are grouped into catagories rather than by each CVE. This report may be more helpful if you are interested in all the vulnerabilities that affect a certain product and platform. This report can be ran exactly like above, however if you are filtering based on CVE's (or not piping the output from *Get-MsrcCvrfDocument*) two aditional fields are required. the above examples are replicated here for the different report type. 97 | 98 | Building a report that contains all CVE's: 99 | 100 | ```Powershell 101 | ### Install the module from the PowerShell Gallery (must be run as Admin) 102 | Install-Module -Name MsrcSecurityUpdates -Force 103 | Import-module MsrcSecurityUpdates 104 | $monthOfInterest = '2017-Apr' 105 | 106 | Get-MsrcCvrfDocument -ID $monthOfInterest -Verbose | Get-MsrcSecurityBulletinHtml -Verbose | Out-File c:\temp\MSRCAprilSecurityUpdates.html 107 | ``` 108 | 109 | Using powershell to filter the report to your liking: 110 | 111 | ```Powershell 112 | Install-Module -Name MsrcSecurityUpdates -Force 113 | Import-Module -Name MsrcSecurityUpdates -Force 114 | 115 | $monthOfInterest = "2017-Mar" 116 | 117 | $CVEsWanted = @( 118 | "CVE-2017-0001", 119 | "CVE-2017-0005" 120 | ) 121 | $Output_Location = "C:\your\path\here" 122 | 123 | $CVRFDoc = Get-MsrcCvrfDocument -ID $monthOfInterest -Verbose 124 | $CVRFHtmlProperties = @{ 125 | Vulnerability = $CVRFDoc.Vulnerability | Where-Object {$_.CVE -in $CVEsWanted} 126 | ProductTree = $CVRFDoc.ProductTree 127 | DocumentTracking = $CVRFDoc.DocumentTracking 128 | DocumentTitle = $CVRFDoc.DocumentTitle 129 | } 130 | 131 | Get-MsrcSecurityBulletinHtml @CVRFHtmlProperties -Verbose | Out-File $Output_Location 132 | ``` 133 | 134 | ## Finding Mitigations and Workarounds 135 | 136 | In this scenario, you can use the *Get-MsrcCvrfDocument* and extract the migrations & remediations from each vulnerability. 137 | 138 | ```Powershell 139 | ### Install the module from the PowerShell Gallery (must be run as Admin) 140 | Install-Module -Name MsrcSecurityUpdates 141 | 142 | ### Download the March CVRF as an object 143 | $cvrfDoc = Get-MsrcCvrfDocument -ID 2017-Mar 144 | 145 | ### Get the Remediations of Type 'Workaround' (0) 146 | $cvrfDoc.Vulnerability.Remediations | Where Type -EQ 0 147 | 148 | ### Get the Remediations of Type 'Mitigation' (1) 149 | $cvrfDoc.Vulnerability.Remediations | Where Type -EQ 1 150 | 151 | ### Get the Remediations of Type 'VendorFix' (2) 152 | $cvrfDoc.Vulnerability.Remediations | Where Type -EQ 2 153 | ``` 154 | 155 | ## Help! 156 | You'll find help via ``Get-Help`` for each cmdlet: 157 | 158 | ```Powershell 159 | Get-Help Get-MsrcSecurityUpdate 160 | 161 | NAME 162 | Get-MsrcSecurityUpdate 163 | 164 | SYNOPSIS 165 | Get MSRC security updates 166 | 167 | 168 | SYNTAX 169 | Get-MsrcSecurityUpdate [] 170 | 171 | Get-MsrcSecurityUpdate [-After ] [-Before ] [] 172 | 173 | Get-MsrcSecurityUpdate -Year [] 174 | 175 | Get-MsrcSecurityUpdate -Vulnerability [] 176 | 177 | 178 | DESCRIPTION 179 | Calls the CVRF Update API to get a list of security updates 180 | 181 | 182 | RELATED LINKS 183 | 184 | REMARKS 185 | To see the examples, type: "get-help Get-MsrcSecurityUpdate -examples". 186 | For more information, type: "get-help Get-MsrcSecurityUpdate -detailed". 187 | For technical information, type: "get-help Get-MsrcSecurityUpdate -full". 188 | ``` 189 | 190 | ... as well as sample code with ``--examples``: 191 | 192 | ```Powershell 193 | Get-Help Get-MsrcSecurityUpdate -examples 194 | 195 | NAME 196 | Get-MsrcSecurityUpdate 197 | 198 | SYNOPSIS 199 | Get MSRC security updates 200 | 201 | -------------------------- EXAMPLE 1 -------------------------- 202 | 203 | PS C:\>Get-MsrcSecurityUpdate 204 | 205 | 206 | Get all the updates 207 | 208 | 209 | 210 | 211 | -------------------------- EXAMPLE 2 -------------------------- 212 | 213 | PS C:\>Get-MsrcSecurityUpdate -Vulnerability CVE-2017-0003 214 | 215 | 216 | Get all the updates containing Vulnerability CVE-2017-003 217 | 218 | 219 | 220 | 221 | -------------------------- EXAMPLE 3 -------------------------- 222 | 223 | PS C:\>Get-MsrcSecurityUpdate -Year 2017 224 | 225 | 226 | Get all the updates for the year 2017 227 | 228 | 229 | 230 | 231 | -------------------------- EXAMPLE 4 -------------------------- 232 | 233 | PS C:\>Get-MsrcSecurityUpdate -Cvrf 2017-Jan 234 | 235 | 236 | Get all the updates for the CVRF document with ID of 2017-Jan 237 | 238 | 239 | 240 | 241 | -------------------------- EXAMPLE 5 -------------------------- 242 | 243 | PS C:\>Get-MsrcSecurityUpdate -Before 2017-01-01 244 | 245 | 246 | Get all the updates before January 1st, 2017 247 | 248 | 249 | 250 | 251 | -------------------------- EXAMPLE 6 -------------------------- 252 | 253 | PS C:\>Get-MsrcSecurityUpdate -After 2017-01-01 254 | 255 | 256 | Get all the updates after January 1st, 2017 257 | 258 | 259 | 260 | 261 | -------------------------- EXAMPLE 7 -------------------------- 262 | 263 | PS C:\>Get-MsrcSecurityUpdate -Before 2017-01-01 -After 2016-10-01 264 | 265 | 266 | Get all the updates before January 1st, 2017 and after October 1st, 2016 267 | 268 | 269 | 270 | 271 | -------------------------- EXAMPLE 8 -------------------------- 272 | 273 | PS C:\>Get-MsrcSecurityUpdate -After (Get-Date).AddDays(-60) -Before (Get-Date) 274 | 275 | 276 | Get all updates between now and the last 60 days 277 | 278 | ``` 279 | --------------------------------------------------------------------------------