private/stigData.psm1

#region Header
using module .\organizationSettings.psm1
using module .\exceptions.psm1
#endregion Header
#region Main Functions
function Get-StigDataRootPath 
{
    [cmdletbinding()]
    Param()

    # The path needs to take into account the version folder that changes with each release
    $rootPath = (Resolve-Path -Path $PSScriptRoot\..).Path

    return (Get-ChildItem -Path $rootPath -Filter 'StigData' -Directory -Recurse).FullName
}

function Get-StigParameterSet
{
    [cmdletbinding(DefaultParameterSetName = '1')]
    [outputtype([string[]])]
    param
    (
        [string]
        $Path,

        [parameter(Mandatory = $false, ParameterSetName = '1')]
        [parameter(Mandatory = $true, ParameterSetName = '2')]
        [AllowEmptyString()]
        [AllowNull()]
        [string]
        $TechnologyVersion,

        [parameter(Mandatory = $true, ParameterSetName = '2')]
        [AllowEmptyString()]
        [AllowNull()]
        [string]
        $TechnologyRole 
    )
    
    switch ($PSCmdlet.ParameterSetName)
    {
        1 {$include = "*" }
        2 {$include = "$TechnologyVersion-$TechnologyRole-*" }
    }

    (Get-ChildItem -Path $Path -Include $include -Exclude "*.org.*" -Recurse).BaseName | 
        ForEach-Object {($PSItem -Split "-")[-1]}
}

function Get-CommonStigParameters
{
    [cmdletbinding(DefaultParameterSetName = '1')]
    param
    (
        [Parameter(Mandatory = $true)]
        [string]
        $Technology,

        [parameter(Mandatory = $false, ParameterSetName = '1')]
        [parameter(Mandatory = $true, ParameterSetName = '2')]
        [string]
        $TechnologyVersion,

        [parameter(Mandatory = $false, ParameterSetName = '2')]
        [string]
        $TechnologyRole
    )

    begin 
    {
        $PSBoundParameters.Remove('Technology') | Out-Null
        $PSBoundParameters.Add('Path', "$(Get-StigDataRootPath)\$Technology") | Out-Null
    }

    process
    {
        # Create a dictionary that will contain the parameters
        $runtimeParameterDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
         
        ################################### StigVersion ####################################
        # Set the dynamic parameters' name
        $parameterName = 'StigVersion'

        # Create the collection of attributes
        $attributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
            
        # Create and set the parameters' attributes
        $parameterAttribute = New-Object System.Management.Automation.ParameterAttribute
        $parameterAttribute.Mandatory = $true

        # Add the attributes to the attributes collection
        $attributeCollection.Add($parameterAttribute)

        # Generate and set the ValidateSet
        $arrSet = Get-StigParameterSet @PSBoundParameters
        $ValidateSetAttribute = New-Object System.Management.Automation.ValidateSetAttribute($arrSet)

        # Add the ValidateSet to the attributes collection
        $attributeCollection.Add($ValidateSetAttribute)

        # Create the dynamic parameter and add it to the dictionary
        $runtimeParameter = New-Object System.Management.Automation.RuntimeDefinedParameter(
            $parameterName, [string], $attributeCollection)
        $runtimeParameterDictionary.Add($parameterName, $runtimeParameter)
        ################################### StigVersion ####################################
        ################################### All Others ####################################
        # List the dynamic parameters with their types
        $parameterList = @{
            'StigException'            = 'psobject';
            'StigTitlePrefix'          = 'string';
            'StigTitleSufix'           = 'string';
            'OrganizationSettingsPath' = 'string'
        }
        
        foreach ($parameter in $parameterList.GetEnumerator())
        {
            # Set the dynamic parameters' name
            $parameterName = $parameter.Name
            
            # Create the collection of attributes
            $attributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
            
            # Create and set the parameters' attributes
            $parameterAttribute = New-Object System.Management.Automation.ParameterAttribute
            $parameterAttribute.Mandatory = $false
        
            # Add the attributes to the attributes collection
            $attributeCollection.Add($parameterAttribute)
            
            # Create and return the dynamic parameter with the correct type
            switch ($parameter.Value)
            {
                'psobject'
                {
                    $type = [PSobject] ; continue
                }
                'string'
                {
                    $type = [string]   ; continue
                }
            }
            $runtimeParameter = New-Object System.Management.Automation.RuntimeDefinedParameter(
                $parameterName, $type, $attributeCollection)

            $runtimeParameterDictionary.Add($parameterName, $runtimeParameter)
        }
        ################################### All Others ####################################
        return $runtimeParameterDictionary
    }
}

<#
    .SYNOPSIS
    Used to validate an xml file against a specified schema
 
    .PARAMETER XmlFile
    Path and file name of the XML file to be validated
 
    .PARAMETER Xml
    An already loaded System.Xml.XmlDocument
 
    .PARAMETER SchemaFile
    Path of XML schema used to validate the XML document
 
    .PARAMETER ValidationEventHandler
    Script block that is run when an error occurs while validating XML
 
    .EXAMPLE
    Test-XML -XmlFile C:\source\test.xml -SchemaFile C:\Source\test.xsd
 
    .EXAMPLE
    $xmlobject = Get-StigData -OsVersion 2012R2 -OsRole MemberServer
    Test-XML -Xml $xmlobject -SchemaFile C:\Source\test.xsd
#>

Function Test-XmlSchema
{
    [cmdletbinding()]
    [outputtype([bool])]
    param 
    (     
        [Parameter(ValueFromPipeline = $true, Mandatory = $true, ParameterSetName = 'File')]
        [string] 
        $XmlFile,

        [Parameter(ValueFromPipeline = $true, Mandatory = $true, ParameterSetName = 'Object')]
        [xml] 
        $Xml,

        [Parameter()]
        [string] 
        $SchemaFile = "$(Get-StigDataRootPath)\PowerStig.xsd",

        [scriptblock] 
        $ValidationEventHandler = { Throw $_.Exception }
    )

    If ( -not ( Test-Path -Path $SchemaFile ) )
    {
        Throw "Schema file not found"
    }

    $schemaReader = New-Object System.Xml.XmlTextReader $SchemaFile
    $schema = [System.Xml.Schema.XmlSchema]::Read( $schemaReader, $ValidationEventHandler )

    If ( $PsCmdlet.ParameterSetName -eq "File" )
    {
        $xml = New-Object System.Xml.XmlDocument
        try 
        {
            $xml.Load($XmlFile)
        }
        catch [System.Management.Automation.MethodInvocationException]
        {
            return $false
        }
    }

    $xml.Schemas.Add( $schema ) | Out-Null

    try 
    {
        $xml.Validate( $ValidationEventHandler )
        return $true
    }
    catch
    {
        Write-Error 'Xml Schema Validation failed.'
        return $false
    }
}

<#
 .SYNOPSIS
    Get-StigData retrieves the DscStigXml file from the path provided along with the OS and STIG
    version to return.
 
 .DESCRIPTION
    This function is the heart of the data retieval process of the composite resource. It will pull
    the stig file using the provided parameters, merge in the data from the local settings file,
    and overwrite any settings that are provided in the exception list.
 
 .PARAMETER StigDataPath
    The root directoury to look for the DscStigXml files. This parameter us used to build the path
    to the translated DscStigXml file
 
 .PARAMETER OsVersion
    The version of the operating system STIG to lookup. This parameter us used to build the path
    to the translated DscStigXml file
 
  .PARAMETER StigVersion
    The version number to look up and return. This parameter us used to build the path
    to the translated DscStigXml file
 
 .PARAMETER StigException
    A hashtable os exceptions to overwrite STIG settings.
 
 .PARAMETER StigExceptionFile
    A XML file that contains a list of exceptions to overwrite the STIG settings.
 
 .EXAMPLE
    Get the 2.8 version of the Windows Server 2012 R2 STIG from the C:\Stigs directory.
 
    Get-StigData -OsVersion 2012R2 -StigVersion 2.8 -StigDataPath c:\Stigs
 
 .EXAMPLE
    Get the 2.8 version of the Windows Server 2012 R2 STIG from the C:\Stigs directory and overwrites
    the STIG setting for V-1079 with 0 before returnign the data.
     
    Get-StigData -OsVersion 2012R2 -StigVersion 2.8 -StigDataPath c:\Stigs -StigException @{id=V-1079,value=0}
 
 .NOTES
    General notes
#>

function Get-StigData
{
    [outputtype([xml])]
    [cmdletbinding(DefaultParameterSetName = 'Default')]
    param
    (
        [Parameter(Mandatory = $true)]
        [string]
        $Path,

        [Parameter()]
        [psobject] 
        $StigException,

        [Parameter()]
        [string] 
        $OrganizationSettingsPath,

        [Parameter()]
        [string] 
        $StigTitlePrefix,

        [Parameter()]
        [string] 
        $StigTitleSuffix = '[Exception]'
    )

    [xml] $stigContent = Get-Content -Path $Path

    ################################### OrganizationSettings ###################################
    $OrganizationSettingsParameters = @{
        stigContent     = ([ref] $stigContent) 
        StigContentPath = $Path 
    }
    
    if ( $OrganizationSettingsPath )
    {
        if ( Test-XmlSchema -XmlFile $OrganizationSettingsPath )
        {
            $OrganizationSettingsParameters.add(
                'OrganizationSettingsPath', $OrganizationSettingsPath)
        }
        else
        {
            throw "The file $OrganizationSettingsPath failed schema validation.
            "
 +
            "Please run New-OrganizationSettingsFile to obtain a template file."
        }
    }

    Merge-OrganizationSettingsFile @OrganizationSettingsParameters
    ################################### OrganizationSettings ###################################
    ################################### StigExceptions ###################################
    if ( $StigException )
    {
        $StigExceptionsParameters = @{
            stigContent    = ([ref] $stigContent) 
            StigExceptions = $StigException 
        }

        Merge-StigExceptions @StigExceptionsParameters
    }
    ################################### StigExceptions ###################################
    return $stigContent
}


function Get-HigestStigVersion
{
    [CmdletBinding()]
    [outputtype([version])]
    Param
    (
        [Parameter(Mandatory = $true)]
        [string]
        $StigDataRootPath
    )

    $HigestStigVersionInTarget = ((Get-ChildItem -Path $stigDataRootPath -Exclude "*org*").BaseName |
        Foreach-Object {($PsItem -split "-")[2]} | 
            Select-Object -unique | 
                Sort-Object -descending)[0]

    return $HigestStigVersionInTarget
}
#endregion Main Functions