├── 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 |
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 | CVE ID |
136 | Vulnerability Title |
137 | Exploitability Assessment for Latest Software Release |
138 | Exploitability Assessment for Older Software Release |
139 | Denial of Service Exploitability Assessment |
140 |
141 |
142 | {2}
143 |
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 |
159 | -
160 | Microsoft Baseline Security Analyzer (MBSA) lets
161 | administrators scan local and remote systems for missing security updates and common
162 | security misconfigurations.
163 |
164 | -
165 | Windows Server Update Services (WSUS), Systems Management Server (SMS),
166 | and System Center Configuration Manager help administrators distribute security updates.
167 |
168 | -
169 | The Update Compatibility Evaluator components included with Application Compatibility
170 | Toolkit aid in streamlining the testing and validation of Windows updates against installed applications.
171 |
172 |
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 |
204 | -
205 | Non-Window Security updates are available from Microsoft Download Center.
206 | You can find them most easily by doing a keyword search for "security update".
207 |
208 | -
209 | All Updates are available from Microsoft Update.
210 |
211 |
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 |
222 | -
223 | The affected software listed has been tested to determine
224 | which versions are affected. Other versions are past their support life cycle. To
225 | determine the support life cycle for your software version, visit
226 | Microsoft Support Lifecycle.
227 |
228 | -
229 | Help protect your computer that is running Windows
230 | from viruses and malware:
231 | Virus and Security Solution Center
232 |
233 |
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 | {0} |
283 |
284 |
285 |
286 | CVE ID |
287 | KB Article |
288 | Restart Required |
289 | Severity |
290 | Impact |
291 |
292 | {1}
293 |
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 | CVE Issued by |
158 | Tag |
159 | CVE ID |
160 | CVE Title |
161 |
162 | {0}
163 |
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 |
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 | Base score metrics |
286 |
287 |
288 | {1}
289 |
290 |
291 |
292 |
293 | Temporal score metrics |
294 |
295 |
296 | {2}
297 |
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 | Exploitability Assessment |
447 | Publicly Disclosed |
448 | Exploited |
449 |
450 |
451 |
452 | {0} |
453 | {1} |
454 | {2} |
455 |
456 |
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 | {0} |
500 |
501 |
502 |
503 | Product |
504 | KB Article |
505 | Severity |
506 | Impact |
507 | Supercedence |
508 | CVSS Score Set |
509 | Fixed Build |
510 | Restart Required |
511 | Known Issue |
512 |
513 | {1}
514 |
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 | CVE ID |
648 | Acknowledgements |
649 |
650 |
651 |
652 | {0} |
653 | {1} |
654 |
655 |
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 |
--------------------------------------------------------------------------------