PowerStigMofToChecklist.psm1

Function PowerStigMofToChecklist {
    [cmdletbinding()]
    Param(
        [Parameter(Position=0,
        Mandatory,
        HelpMessage="Enter the path to MOF file(s)",
        ValueFromPipeline,
        ValueFromPipelineByPropertyName)]
        [ValidateNotNullorEmpty()]
        [ValidateScript({Test-Path $_})]
        [string]$MofLocation,
        [Parameter(Position=1,
        Mandatory,
        HelpMessage="Enter the path to Output folder",
        ValueFromPipeline,
        ValueFromPipelineByPropertyName)]
        [ValidateNotNullorEmpty()]
        [ValidateScript({Test-Path $_})]
        [string]$OutputLocation
    )
    Begin {
        Write-Verbose "Starting $($MyInvocation.Mycommand)"
    }
    Process {
        #Locations for folder structures
        Write-Verbose "Creating output folder structures"
        $ScanResults       = "$OutputLocation\Results"
        $ChecklistLocation = "$OutputLocation\Checklists"
        $ManualExceptions  = "$OutputLocation\ManualExceptions"
        $DISAStigs         = "$OutputLocation\Stigs"

        #Make sure folder structures exist.
        if (!(Test-Path $ScanResults))        {[void](New-Item $ScanResults -itemType Directory)}
        if (!(Test-Path $ChecklistLocation)){[void](New-Item $ChecklistLocation -itemType Directory)}
        if (!(Test-Path $ManualExceptions)) {[void](New-Item $ManualExceptions -itemType Directory)}
        if (!(Test-Path $DISAStigs))        {[void](New-Item $DISAStigs -itemType Directory)}
        # Make sure all XCCDF files are not blocked becuase they were possibly downloaded from the internet.
        Get-ChildItem $DISAStigs -Recurse |Unblock-File

        Write-Verbose "Processing $MofLocation"
        #get the *.mof files to process
        $MofFiles = Get-ChildItem -Path $MofLocation -Filter "*.mof"-Exclude "*.meta.mof"-Recurse -ErrorAction SilentlyContinue| ForEach-Object {$_.FullName}
        Write-Verbose "$($MofFiles.count) MOF File to process"

        #Process MOF files
        Foreach ($file in $MofFiles)
        {
            Write-Verbose"`r`nProcessing $($File)"
            ##Find Target of MOF in file header
            $TargetNode = select-string -Path $file -pattern @TargetNode=
            $TargetNode = $TargetNode.line.split("=")
            $TargetNode = $TargetNode[1].Replace("'","")
            Write-Verbose "Testing to see if $($TargetNode) is online"
            if(Test-Connection -ComputerName $($TargetNode) -Quiet -Count 1)
                {
                Write-Verbose "Running MOF against $($TargetNode)"
                $DscResult = Test-DscConfiguration -ComputerName $TargetNode -path $MofLocation
                If ($DscResult)
                    {
                    Write-Verbose "Test Configuration was successful"
                    $DscResult | Export-Clixml "$($ScanResults)\$($TargetNode).xml"
                    $DscResultRehydrated = Import-Clixml "$($ScanResults)\$($TargetNode).xml"

                    ##Find Stigs in the MOF
                    $Stigs = @()
                    $lines = get-content $file |Where-Object {$_ -match "ResourceID = "}
                    foreach ($line in $lines)
                        {
                        $r = [regex] "\[([^\[]*)\]"
                        $match = $r.match($line.split("::")[2])
                        $Stigs += $match.groups[1].value
                        }
                    $stigs = $stigs  | Where-Object { $_ -match '\S' }| Select-Object -uniq

                    if($Stigs -contains "WindowsServer")
                        {
                        try {
                            $ServerOS = $((Get-CimInstance -Class win32_operatingsystem -ComputerName $($TargetNode)).name)
                            #$DomainController = get-service -name "kdc" -ComputerName "cmdc01" -ErrorAction 0
                            switch -wildcard ($ServerOS) {
                                "*Windows Server 2016*" {$Stigs = $Stigs -replace "WindowsServer","WindowsServer2016"}
                                "*Windows Server 2019*" {$Stigs = $Stigs -replace "WindowsServer","WindowsServer2019"}
                                "*Windows Server 2022*" {$Stigs = $Stigs -replace "WindowsServer","WindowsServer2022"}
                                Default {"---Unable to determine OS"}
                                }
                            }catch {
                                Write-Verbose "---Error Unable to query Operating System on $($TargetNode)"
                            }
                        }

                    if($Stigs -contains "IisServer" -or $Stigs -contains "IisSite")
                        {
                        try {
                            $reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $($TargetNode))
                            $regkey = $reg.OpenSubkey("SOFTWARE\\Microsoft\\InetStp")
                            $IISVersion = $regkey.GetValue("VersionString")
                            $IISVersion

                            switch -wildcard ($IISVersion) {
                                "*8.5*" {$Stigs = $Stigs -replace "IisServer","IisServer85";$Stigs = $Stigs -replace "IisSite","IisSite85"}
                                "*10*" {$Stigs = $Stigs -replace "IisServer","IisServer10";$Stigs = $Stigs -replace "IisSite","IisSite10"}
                                Default {"---Unable to determine IIS Version"}
                                }
                            }catch {
                            Write-Verbose "---Error Unable to query registry on $($TargetNode) to determine IIS Version"
                            }
                        }

                    ##Remove known DSC items that do not contain STiG items.
                    $Stigs = $Stigs | Where-Object { $_ -ne "SharePointServerEnforceTLS12" }

                    ##Find the DISA STiG Files for each Stig
                    $XCCDFPath = @()
                    $ManualCheckFile = @()
                    [void](New-Item -Path '$($ScanResults )\' -Name "$($TargetNode).txt" -ItemType File -Force)
                    foreach ($Stig in $Stigs)
                        {
                            Write-Verbose "MOF has $($Stig) Stig"
                            if (!(Test-Path "$($DISAStigs)\$($Stig)")){[void](New-Item "$($DISAStigs)\$($Stig)" -itemType Directory)}
                            Get-ChildItem "$($DISAStigs)\$($Stig)" -Filter *xccdf.xml |
                            Foreach-Object {
                                Write-Verbose "Adding $($_.FullName) to Stig list"
                                Add-Content -Path "$($ScanResults )\$($TargetNode).txt" -Value "$($_.FullName)"
                            }
                            if(Test-path "$($DISAStigs)\$($Stig)\ManualExceptions.xml")
                                {
                                    Add-Content -Path "$($ScanResults )\$($TargetNode)_Manual.txt" -Value "$($DISAStigs)\$($Stig)\ManualExceptions.xml"
                                }
                        }
                    if (Test-Path "$($ManualExceptions)\$($TargetNode).xml")
                        {
                            Add-Content -Path "$($ScanResults )\$($TargetNode)_Manual.txt" -Value "$($ManualExceptions)\$($TargetNode).xml"
                        }

                    $XccdfPath = Get-Content "$($ScanResults )\$($TargetNode).txt"
                    $ManualCheckFile =  Get-Content "$($ScanResults )\$($TargetNode)_Manual.txt"

                    Write-Verbose "Generating Checklist"
                    if( $ManualCheckFile.Count -ge 1)
                        {
                        New-StigCheckList -DscResult $DscResultRehydrated -XccdfPath $XCCDFPath -ManualChecklistEntriesFile $ManualCheckFile -OutputPath "$($ChecklistLocation)\$($TargetNode).ckl"
                        }
                    else {
                        New-StigCheckList -DscResult $DscResultRehydrated -XccdfPath $XCCDFPath -OutputPath "$($ChecklistLocation)\$($TargetNode).ckl"
                        }
                }
                Else {
                    Write-Verbose "Unable to test configuration"
                }
            }
            Else {
                Write-Verbose "---$($TargetNode) is offline"
            }
            Write-Verbose "Processing $($File) Completed"
        }
    }
    End {
        Write-Verbose "Ending $($MyInvocation.Mycommand)"
    }
}