SAM.DoDCyberExchange.psm1

function Get-CECompilation {

    <#
        .SYNOPSIS
            Get current STIG Compilation from public.cyber.mil

        .DESCRIPTION
            Get current STIG Compilation from public.cyber.mil. If you need the CUI Compilation you will need to log into the website to download.

        .EXAMPLE
            PS C:\> Get-CECompilation

            This example demonstrates how to pull the STIG compilations for DoD Cyber Exchange.
    #>


    [CmdletBinding()]
    [OutputType([System.Management.Automation.PSCustomObject])]
    param ()

    end {
        Get-CEItem -Section Compilations | Where-Object { $_.FileName -and $_.FileType -eq "zip" }
    }

}
function Get-CEComplianceChecker {

    <#
        .SYNOPSIS
            Retrieve list of available downloads for SCAP Compliance Checker (SCC)

        .DESCRIPTION
            Retrieve list of available downloads for SCAP Compliance Checker (SCC).

        .EXAMPLE
            PS C:\> Get-CEComplianceChecker -Type Windows

            This example demonstrates how to pull the Windows SCC files from DoD Cyber Exchange.

        .EXAMPLE
            PS C:\> Get-CEComplianceChecker -Type Windows -OtherFiles Checksums

            This example demonstrates how to pull the Windows SCC files and the Checksums from DoD Cyber Exchange.

        .EXAMPLE
            PS C:\> Get-CEComplianceChecker -Type All -OtherFiles All

            This example demonstrates how to pull All SCC Installs and Support Files from DoD Cyber Exchange.
    #>


    [CmdletBinding()]
    [OutputType([System.Management.Automation.PSCustomObject])]
    param (

        # Specify the SCAP Compliance Checker (SCC) Type to download. Options are All, Windows, Redhat, Ubuntu, Mac, Solaris, and Raspbian
        [Parameter()]
        [ValidateSet('Windows', 'Redhat', 'Ubuntu', 'Mac', 'Solaris', 'Raspbian', 'All')]
        [String[]]
        $Type,

        # Specify additional support files to download. Options are Unlocker Bundle, Checksums, UnixRemoteScanningPlugin, ReleaseNotes, Readme, RPM-GPG-KEY.
        [Parameter()]
        [ValidateSet('UnlockerBundle', 'Checksums', 'UnixRemoteScanningPlugin', 'ReleaseNotes', 'Readme', 'RPM-GPG-KEY', 'All')]
        [String[]]
        $OtherFiles

    )

    begin {

        $items = @()
        $files = Get-CEItem -Section SCAPs

    }

    process {

        $items += $Type | ForEach-Object {

            switch ($_) {
                'Windows' { $files | Where-Object { $_.FileName.ToLower() -match "^scc-\d.\d_windows" } }
                'Redhat' { $files | Where-Object { $_.FileName.ToLower() -match "^scc-\d.\d_rhel" } }
                'Ubuntu' { $files | Where-Object { $_.FileName.ToLower() -match "^scc-\d.\d_ubuntu" } }
                'Mac' { $files | Where-Object { $_.FileName.ToLower() -match "^scc-\d.\d_mac" } }
                'Solaris' { $files | Where-Object { $_.FileName.ToLower() -match "^scc-\d.\d_solaris" } }
                'Raspbian' { $files | Where-Object { $_.FileName.ToLower() -match "^scc-\d.\d_raspbian" } }
                'All' { $files | Where-Object { $_.FileName.ToLower() -match "^scc-\d.\d_(windows|ubuntu|rhel|mac|raspbian|sol)" } }
            }

        }

    }

    end {

        $items += $OtherFiles | ForEach-Object {

            switch ($_) {
                'UnlockerBundle' { $files | Where-Object { $_.FileName.ToLower() -match "^scc(-|_)\d.\d_unlocker" } }
                'Checksums' { $files | Where-Object { $_.FileName.ToLower() -match "^scc(-|_)\d.\d_checksums" } }
                'UnixRemoteScanningPlugin' { $files | Where-Object { $_.FileName.ToLower() -match "^scc(-|_)\d.\d_unix_remote" } }
                'ReleaseNotes' { $files | Where-Object { $_.FileName.ToLower() -match "^scc(-|_)\d.\d_releasenotes" } }
                'Readme' { $files | Where-Object { $_.FileName.ToLower() -match "^scc(-|_)\d.\d_readme" } }
                'RPM-GPG-KEY' { $files | Where-Object { $_.FileName.ToLower() -match "^rpm-gpg-key-scc" } }
                'All' { $files | Where-Object { $_.FileName.ToLower() -match "^rpm-gpg-key-scc|^scc(-|_)\d.\d_(unlocker|checksums|unix_remote|releasenotes|readme)" } }
            }

        }

        Write-Output $items

    }

}
function Get-CEItem {

    <#
        .SYNOPSIS
            Retrieve list of all files from a specific Cyber Exchange URL.

        .DESCRIPTION
            Retrieve list of all files from a specific Cyber Exchange URL. The function calls the URL and looks for any tables on the page that would list files. This function only works with the public.cyber.mil website, for items that require a CAC to download you will have to log in via the web browser and download manually.

            Useful URLS
            Document Library: https://public.cyber.mil/stigs/downloads/
            SCAPs: https://public.cyber.mil/stigs/scap/
            STIG/SRG Tools: https://public.cyber.mil/stigs/srg-stig-tools/
            Compilations: https://public.cyber.mil/stigs/compilations/
            GPOs: https://public.cyber.mil/stigs/gpo/
            Automation: https://public.cyber.mil/stigs/supplemental-automation-content/
            CCI: https://public.cyber.mil/stigs/cci/
            Sunset: https://public.cyber.mil/stigs/sunset-products/c=

        .EXAMPLE
            PS C:\> Get-CEItem

            This example demonstrates how to call the function in its default configuration. When called by itself, the function will query the downloads section of DoD Cyber Exchange.

        .EXAMPLE
            PS C:\> Get-CEItem -Section compilations

            This example demonstrates how to pull the STIG compilations for DoD Cyber Exchange.

    #>


    [CmdletBinding()]
    [OutputType([System.Management.Automation.PSCustomObject])]
    param (

        # Specify the Cyber.Mil Site Section to retrieve file list from. The default value is 'DocumentLibrary' which is the main list of items to download. Other options are "SCAPs","STIGTools","Compilations","GPOs","Automation","CCI","Sunset".
        [Parameter()]
        [ValidateSet(
            "DocumentLibrary",
            "SCAPs",
            "STIGTools",
            "Compilations",
            "GPOs",
            "Automation",
            "CCI",
            "Sunset"
        )]
        [String]
        $Section = 'DocumentLibrary'

    )

    begin {

        Import-HtmlAgilityPack

    }

    end {

        $url = $DoDCyberExchangeUrls.$Section

        $response = Invoke-WebRequest -Uri $url -ErrorAction Stop -SkipCertificateCheck

        if ($response.StatusCode -eq '200') {

            $htmlDoc = New-Object HtmlAgilityPack.HtmlDocument

            $htmlDoc.LoadHtml($response.rawcontent)

            $htmlDoc.DocumentNode.SelectNodes('//tr[@class="file"]') | ForEach-Object {

                [XML]$list = $($_.OuterHtml -replace "&mdash;|&nbsp;")
                [String]$uri = ""
                [String]$fileType = ""
                [String]$fileName = ""
                [String]$msg = ""

                $link = $list.SelectNodes("//td[@class='title_column']").A.href
                $size = $list.SelectNodes("//td[@class='size_column']").'#Text'

                # When looking through list it was found that some items that dont have downloads, have a message nested in the title.
                if ($link) {
                    $uri = $link.Trim()
                    $fileType = $($link -split "/")[-1].Split('.')[-1]
                    $fileName = $($link -split "/")[-1]
                }
                else {
                    $msg = $list.SelectNodes("//td[@class='title_column']").div."#text".Trim()
                }

                [PSCustomObject]@{
                    Name      = $list.SelectNodes("//td[@class='title_column']/span[@style='display:none;']").'#text'.Trim()
                    URI       = $uri
                    FileName  = $fileName
                    FileType  = $fileType
                    Size      = $(If ($size.Length -gt "0") { $size.trim() }else { "---" })
                    Published = $list.SelectNodes("//td[@class='updated_column']").div."#text"
                    Message   = $msg
                }

            }

        }
        else {

            Throw $response.StatusCode

        }

    }

}
function Get-CEScapBenchmark {

    <#
        .SYNOPSIS
            Retrieves a list of SCAP Benchmarks from Cyber.mil

        .DESCRIPTION
            Retrieves a list of SCAP Benchmarks from Cyber.mil using the Get-CEItem function.

        .EXAMPLE
            PS C:\> Get-CEScapBenchmark | Save-CEItem -Destination C:\Temp\SCAPS

            This example shows the default method to call the function. It pipes the output to Save-CEItem to download the file.

    #>


    [CmdletBinding()]
    [OutputType([System.Management.Automation.PSCustomObject])]
    param ()

    end {

        Get-CEItem -Section DocumentLibrary |
            Where-Object { $_.FileType -eq "zip" -and $_.FileName -Like "*_Benchmark.zip" }

    }

}
function Get-CEStig {

    <#
        .SYNOPSIS
            Retrieves a list of STIG/SRG List from public.cyber.mil.

        .DESCRIPTION
            Retrieves a list of STIG/SRG List from public.cyber.mil using the Get-CEItem function. This function also includes all the Sunset STIGs.

        .EXAMPLE
            PS C:\> Get-CEStig | Save-CEItem -Destination C:\Temp\STIGs

            This example shows the default method to call Get-CEStig. It pipes the output to Save-CEItem to download the file.
    #>


    [CmdletBinding()]
    [OutputType([System.Management.Automation.PSCustomObject])]
    param ()

    begin {

        $exclude = "UNIX_Remote_Scanning|RPM-GPG-KEY|scc-|Draft|Overview|BENCHMARK|STIGViewer|STIGApplicabilityGuide|CCI|Library|Ansible|GPO|Configuration_Files|Audit|Chef|Test"

    }

    end {

        Get-CEItem -Section DocumentLibrary |
            Where-Object { $_.FileName -and $_.FileName.ToLower() -notmatch $exclude.ToLower() -and $_.FileType -eq "zip" }

    }

}
function Get-CEStigViewer {

    <#
        .SYNOPSIS
            Get Current STIGViewer Published.

        .DESCRIPTION
            Get-Current STIGViewer Published. DISA has produced standalone versions of STIG Viewer for the Windows, Linux, and macOS platforms on 64-bit x86 processors. With the end of free support for Java 8 in early 2019, Oracle Corporation changed the licensing and distribution model for Java software. Users without supported Java 8 SE environments should use the standalone versions of STIG Viewer. Users with supported Java 8 SE environments may still use the current JAR file.


        .EXAMPLE
            PS C:\> Get-CEStigViewer

            This example demonstrates how to pull the current STIGViewer for DoD Cyber Exchange.

            Name : STIG Viewer 2.14
            URI : https://dl.dod.cyber.mil/wp-content/uploads/stigs/zip/U_STIGViewer_2-14.zip
            FileName : U_STIGViewer_2-14.zip
            FileType : zip
            Size : 712.99 KB
            Published : 22 Apr 2021
            Message :

        .EXAMPLE
            PS C:\> Get-CEStigViewer -Type All -IncludeUserGuide | Save-CEItem -Destination C:\Temp

            This example demonstrates how to pull all types along with the StigViewer User Guide. Once the list is pulled its passed to Save-CEItem to download the files.
    #>


    [CmdletBinding()]
    [OutputType([System.Management.Automation.PSCustomObject])]
    param (

        # Specify the STIGViewer Type to download. Default is the Java version. If Java is not installed on the end devices then select either Windows, Mac, or Linux. These distributions have java packaged with them so there is not need to install java. If you require all versions select all.
        [Parameter()]
        [ValidateSet('Windows', 'Linux', 'Mac', 'All', "Java")]
        [String]
        $Type = "Java",

        # Specify if the user guides should be downloaded as well.
        [Parameter()]
        [Switch]
        $IncludeUserGuide

    )

    end {

        $items = @()
        $files = Get-CEItem -Section STIGTools

        switch ($Type) {
            "Java"    { $items += $files | Where-Object { $_.FileName -match "U_STIGViewer_\d{1,2}-\d{1,2}.zip" }}
            "Windows" { $items += $files | Where-Object { $_.FileName -match "U_STIGViewer_\d{1,2}-\d{1,2}_Win64.zip" }}
            "Mac"     { $items += $files | Where-Object { $_.FileName -match "U_STIGViewer_\d{1,2}-\d{1,2}_Mac.zip" }}
            "Linux"   { $items += $files | Where-Object { $_.FileName -match "U_STIGViewer_\d{1,2}-\d{1,2}_Linux.zip" }}
            "All"     { $items += $files | Where-Object { $_.FileName -match "U_STIGViewer_\d{1,2}-\d{1,2}(|_Linux|_Mac|_Win64).zip"}}
        }

        if ($IncludeUserGuide) {
            $items += $files | Where-Object { $_.FileName -match "U_STIG_Viewer_2-x_User_Guide_V\d{1,2}R\d{1,2}.pdf" }
        }

        Write-Output $items

    }

}
function Save-CEItem {

    <#
        .SYNOPSIS
            Save a file from Cyber Exchange

        .DESCRIPTION
            Takes the object from Get-CEItem and saves it to a location specified.

        .EXAMPLE
            PS C:\> Save-CEItem -Destination "C:\Temp" -URI "https://dl.dod.cyber.mil/wp-content/uploads/stigs/zip/U_STIGViewer_2-14.zip"

            This example shows how to call Save-CEItem and Save a file.

        .EXAMPLE
            PS C:\> Get-CEItem -Section GPOs | Save-CEItem -Destination "C:\Temp"

            This example shows the Get-CEItem function pulling a list of GPOs and it pipes the output to Save-CEItem to download the files.
    #>


    [CmdletBinding()]
    [OutputType([System.Void])]
    param (

        # Specifies the destination to save the file to.
        [Parameter(Mandatory, Position = 0)]
        [String]
        $Destination,

        # Specifies the URL for the file to download from public.cyber.mil
        [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
        [string[]]
        $URI

    )

    begin {

        $currentProgressPreference = $ProgressPreference
        $ProgressPreference = 'SilentlyContinue'

        if (-not (Test-Path $Destination)) { New-Item -Path $Destination -ItemType Directory | Out-Null }

    }

    process {

        $URI | ForEach-Object {

            $fileName = ($_ -split "/")[-1]
            $saveTo = Join-Path -Path $Destination -ChildPath $fileName

            Invoke-WebRequest -Uri $_ -OutFile $saveTo -SkipCertificateCheck

        }

    }

    end {

        $ProgressPreference = $currentProgressPreference

    }

}
function Import-HtmlAgilityPack {

    <#
        .SYNOPSIS
            Imports HtmlAgilityPack Assembly

        .DESCRIPTION
            Checks to see if HtmlAgilityPack is loaded and if not it imports the Assembly. This function is not ment to be call by a user, its best to call this function in the begin block.

        .LINK
            https://html-agility-pack.net

        .EXAMPLE

            Begin{
                Import-HtmlAgilityPack
            }

            This example shows how the private function can be used within functions that require the HtmlAgilityPack.

    #>


    [CmdletBinding()]
    [OutputType([System.Void])]
    param ()

    # Added to support Pester Testing of Private functions
    if ($MyInvocation.MyCommand.Module) {
        $dllPath = $SAMHtmlAgilityPackDllPath
    }
    else {

        $rootPath = Split-Path -Path $PSScriptRoot -Parent
        $dllPath = [IO.Path]::Combine("$rootPath", 'Libraries', 'HTMLAgilityPack', 'Net45', 'HtmlAgilityPack.dll')
    }

    $assemblies = [System.AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.Location }

    if ($assemblies.locations -notcontains $dllPath) { Add-Type -Path $dllPath }

}