MSPatchTuesdayHub.psm1

#Region '.\Private\Group-UpdateByProduct.ps1' 0
<#
.SYNOPSIS
    Groups updates by operating system product.
.DESCRIPTION
    This function groups updates by operating system product.
    The function takes an array of updates and an array of operating
    system names, and returns a hashtable where each key is an
    operating system name and each value is an array of updates that
    match that operating system.
.PARAMETER AllUpdates
    An array of updates to group by operating system product. Each
    update object must have a 'Product' property that contains the name
    of the operating system product (e.g. "Windows 10 Enterprise").
.PARAMETER OSList
    An array of operating system names to group by. Each operating system
    name should be a string that matches the start of the operating system
    product name (e.g. "Windows 10").
.OUTPUTS
    System.Collections.Hashtable
    A hashtable where each key is an operating system name and each
    value is an array of updates that match that operating system.
.EXAMPLE
    $allUpdates = @(
        @{
            Product = "Windows 10 Enterprise"
            Title = "Cumulative Update for Windows 10 Version 21H1"
            KB = "KB5001330"
            ReleaseDate = "04/20/2021"
            Severity = "Critical"
        },
        @{
            Product = "Windows Server 2016"
            Title = "Security Update for Windows Server 2016"
            KB = "KB5003204"
            ReleaseDate = "05/11/2021"
            Severity = "Important"
        }
    )
    $osList = @("Windows 10", "Windows Server")
    $groupedUpdates = Group-UpdateByProduct -AllUpdates $allUpdates -OSList $osList
    $groupedUpdates["Windows 10"]
    $groupedUpdates["Windows Server"]
.NOTES
    Author: DrIOSx
#>

function Group-UpdateByProduct {
    param(
        [Parameter(Mandatory = $true)]
        [System.Collections.ArrayList]$AllUpdates,
        [string[]]$OSList
    )

    $Updates = @{}

    foreach ($OS in $OSList) {
        $Updates[$OS] = $AllUpdates | Where-Object { $_.Product -like "$OS*" }
    }

    return $Updates
}
#EndRegion '.\Private\Group-UpdateByProduct.ps1' 61
#Region '.\Private\Read-FileContent.ps1' 0
<#
.SYNOPSIS
    Reads the contents of a file and returns the content as a single string.
.DESCRIPTION
    This function reads the contents of a file and returns the content as a single string.
.PARAMETER FilePath
    The path to the file to read.
.OUTPUTS
    System.String
    The contents of the file as a single string.
.EXAMPLE
    $fileContent = Read-FileContent -FilePath "C:\example.txt"
    $fileContent
.NOTES
    Author: DrIOSx
#>

function Read-FileContent {
    param(
        [string]$FilePath
    )
    return (Get-Content -Path $FilePath -Raw)
}
#EndRegion '.\Private\Read-FileContent.ps1' 23
#Region '.\Private\Show-OSUpdateSection.ps1' 0
<#
.SYNOPSIS
    Generates HTML code for displaying OS updates in a collapsible table format.
 
.DESCRIPTION
    This function takes an array of OS update objects and generates HTML code to display them in a collapsible table format.
 
.PARAMETER osUpdates
    An array of OS update objects. Each OS update object must have a 'Title' property and an 'Updates' property, where 'Updates' is an array of update objects with the following properties:
    - 'Article': The KB article number of the update.
    - 'Max Severity': The maximum severity of the update.
    - 'ArticleUrl': The URL of the KB article.
    - 'Download': The type of download (e.g. 'Security Update').
    - 'Download Url': The URL of the download.
    - 'Release Date': The release date of the update.
    - 'Impact': The impact of the update.
    - 'Build Number': The build number of the update.
    - 'Details': A description of the update.
    - 'Details Url': The URL of the details page.
 
.OUTPUTS
    System.String
    The generated HTML code for displaying the OS updates in a collapsible table format.
 
.EXAMPLE
    $osUpdates = @(
        @{
            Title = "Windows 10, version 21H1"
            Updates = @(
                @{
                    Article = "KB5001330"
                    'Max Severity' = "Critical"
                    ArticleUrl = "https://support.microsoft.com/en-us/topic/kb5001330-cumulative-update-preview-for-windows-10-version-21h1-april-20-2021-57a87a06-64de-45e7-9d3b-6b8a58a00bc6"
                    Download = "Security Update"
                    'Download Url' = "https://www.microsoft.com/download/details.aspx?id=12345"
                    'Release Date' = "04/20/2021"
                    Impact = "Remote Code Execution"
                    'Build Number' = "19043.928"
                    Details = "This update fixes a vulnerability in blah blah blah."
                    'Details Url' = "https://support.microsoft.com/en-us/topic/kb5001330-cumulative-update-preview-for-windows-10-version-21h1-april-20-2021-57a87a06-64de-45e7-9d3b-6b8a58a00bc6"
                }
            )
        }
    )
    Show-OSUpdateSection -osUpdates $osUpdates
 
.NOTES
    Author: DrIOSx
#>

function Show-OSUpdateSection {
    param(
        $osUpdates
    )
    $sectionHtml = ""
    foreach ($os in $osUpdates) {
        $sectionHtml += @"
<h3>$($os.Title)</h3>
 
"@

        $groupedUpdates = $os.Updates | Group-Object -Property Article

        foreach ($group in $groupedUpdates) {
            $firstUpdate = $group.Group[0]
            $tableId = "table_" + (New-Guid).ToString()
            $arrowId = "arrow_" + (New-Guid).ToString()
            $sectionHtml += @"
<h4 onclick='toggleTable("$tableId", "$arrowId")' style='cursor:pointer;'><span id='$arrowId' class='arrow'>▶</span><span class='kb-number'>KB$($group.Name)</span> - Max Severity: $($firstUpdate.'Max Severity') - <a href='$($firstUpdate.ArticleUrl)' target='_parent'>Article URL</a> | Type: $($firstUpdate.Download) - <a href='$($firstUpdate.'Download Url')' target='_parent'>Download URL</a></h4>
<table id='$tableId' style='display:none;'>
<tr>
    <th onclick='onHeaderClick("$tableId", 0)'>Release Date</th>
    <th onclick='onHeaderClick("$tableId", 1)'>Impact</th>
    <th onclick='onHeaderClick("$tableId", 2)'>Build Number</th>
    <th onclick='onHeaderClick("$tableId", 3)'>Details</th>
    <th onclick='onHeaderClick("$tableId", 4)'>Details URL</th>
    <th onclick='onHeaderClick("$tableId", 5)'>Base Score</th>
</tr>
"@


            foreach ($update in $group.Group) {
                $sectionHtml += @"
<tr>
    <td>$($update.'Release Date')</td>
    <td>$($update.Impact)</td>
    <td>$($update.'Build Number')</td>
    <td>$($update.Details)</td>
    <td><a href='$($update.'Details Url' -replace "(?<=https://)(.*)//", '$1/')' target='_parent'>Link</a></td>
    <td>$($update.'Base Score')</td>
</tr>
"@

            }

            $sectionHtml += @"
</table>
"@

        }
    }
    return $sectionHtml
}
#EndRegion '.\Private\Show-OSUpdateSection.ps1' 99
#Region '.\Public\Get-PatchTuesdayReport.ps1' 0
function Get-PatchTuesdayReport {
    <#
    .SYNOPSIS
    Generates a Patch Tuesday report HTML file based on a CSV input file.
    .DESCRIPTION
    The function generates an HTML report file with the latest Microsoft updates released on Patch Tuesday. The report file includes separate sections for client and server operating systems.
 
    To use this function, follow these steps:
 
    Go to the Microsoft Security Response Center website at https://msrc.microsoft.com/update-guide.
    Select the appropriate filters to display the updates you want to include in the report. For example, select the following options:
        Product:
        Windows Server 2022, Windows Server 2019, Windows Server 2016, Windows Server 2012 R2, Windows 11 Version 22H2 for x64-based Systems, Windows 10 Version 22H2 for x64-based Systems.
        Severity: Critical
        Release Date: Last 30 days
    Click on "Download all as CSV" to download the updates as a CSV file.
    The function will import the CSV file with the appropriate headers:
        Import-Csv -Path $Path -Header 'Release Date','Product','Platform','Impact','Max Severity','Article','ArticleUrl','Download','Download Url','Build Number','Details','Details Url','Base Score'
    Use the Get-PatchTuesdayReport function to generate the HTML report file.
    Future updates will include options to specify the parameters.
    .PARAMETER CsvPath
    The path to the CSV input file containing the Microsoft update information.
    .PARAMETER DateId
    A string value used to identify the date of the Patch Tuesday report.
    .PARAMETER LogoUrl
    A string value representing the URL of the logo to be displayed in the report.
    .PARAMETER ImportHeaderAs
    An array of strings representing the header row of the CSV input file.
    .PARAMETER OSList
    An array of strings representing the list of operating systems to include in the report.
    .EXAMPLE
    PS C:> Get-PatchTuesdayReport -CsvPath "C:\updates.csv" -DateId "2022-Oct" -LogoUrl "https://example.com/logo.png" -OSList @("Windows Server 2012 R2", "Windows Server 2016", "Windows Server 2019", "Windows Server 2022", "Windows 11", "Windows 10")
 
    This example generates a Patch Tuesday report for October 2022 with updates for Windows Server 2012 R2, Windows Server 2016, Windows Server 2019, Windows Server 2022, Windows 11, and Windows 10 operating systems. The report includes a logo displayed at the top of the report.
    .INPUTS
    None.
    .OUTPUTS
    A string value containing the HTML code for the Patch Tuesday report.
    .NOTES
    None.
    .LINK
    https://github.com/CriticalSolutionsNetwork/ADAuditTasks/wiki/Get-PatchTuesdayReport
    .LINK
    https://criticalsolutionsnetwork.github.io/ADAuditTasks/#Get-PatchTuesdayReport
    #>

    [CmdletBinding()]
    param(
        [ValidateNotNull()]
        [string]$CsvPath,
        [ValidateNotNull()]
        [string]$DateId,
        [string]$LogoUrl,
        [string[]]$ImportHeaderAs = @("Release Date", "Product", "Platform", "Impact", "Max Severity", "Article", "ArticleUrl", "Download", "Download Url", "Build Number", "Details", "Details Url", "Base Score"),
        [string[]]$OSList = @('Windows Server 2012 R2', 'Windows Server 2016', 'Windows Server 2019', 'Windows Server 2022', 'Windows 11', 'Windows 10')
    )
    begin {
        $AllUpdates = Import-Csv -Path $CsvPath -Header $ImportHeaderAs
        $Updates = Group-UpdateByProduct -AllUpdates $AllUpdates -OSList $OSList
        # Read CSS, JavaScript, and HTML template
        $moduleBase = (Get-Module MSPATCHTUESDAYHUB).ModuleBase
        $assetsPath = Join-Path $moduleBase "assets"
        $cssContent = Read-FileContent -FilePath (Join-Path $assetsPath "styles.css")
        $jsContent = Read-FileContent -FilePath (Join-Path $assetsPath "scripts.js")
        $htmlTemplate = Read-FileContent -FilePath (Join-Path $assetsPath "template.html")
        # Replace placeholders in the HTML template with the CSS and JavaScript content
        $htmlTemplate = $htmlTemplate -replace '/\* CSS-PLACEHOLDER \*/', $cssContent
        $htmlTemplate = $htmlTemplate -replace '/\* JS-PLACEHOLDER \*/', $jsContent
    }
    Process {
        # Generate the report content using the HTML template
        $html = $htmlTemplate -replace "<!--LOGO-URL-PLACEHOLDER-->", $LogoUrl -replace "<!--DATE-ID-PLACEHOLDER-->", $DateId
        $clientOSList = @('Windows 11', 'Windows 10')
        $serverOSList = $OSList | Where-Object { $_ -notin $clientOSList }
        $clientUpdates = $clientOSList | ForEach-Object {
            @{
                'Title'   = "$_ Updates";
                'Updates' = $Updates[$_]
            }
        }
        $serverUpdates = $serverOSList | ForEach-Object {
            @{
                'Title'   = "$_ Updates";
                'Updates' = $Updates[$_]
            }
        }
        $clientUpdatesHtml = Show-OSUpdateSection $clientUpdates
        $serverUpdatesHtml = Show-OSUpdateSection $serverUpdates
        $html = $html -replace "<!--CLIENT-UPDATES-PLACEHOLDER-->", $clientUpdatesHtml
        $html = $html -replace "<!--SERVER-UPDATES-PLACEHOLDER-->", $serverUpdatesHtml
    }
    End {
        return $html
    }
}
#EndRegion '.\Public\Get-PatchTuesdayReport.ps1' 95