module/AzureFunctions.ps1

function New-AzSystemData
{
    <#
    .SYNOPSIS
    Generates system data for Azure Virtual Machines
 
    .PARAMETER RootPath
    Root path of the Stig Compliance Automation Repository. Initialize by running Initialize-StigRepo
 
    .PARAMETER ResourceGroupName
    Name of the ResourceGroup containing targeted Virtual Machines
 
    .PARAMETER IncludeLcmSettings
    Adds LocalConfigurationManager Settings to the System Data File for each Virtual Machine.
 
    .PARAMETER LcmSettings
    Hashtable of Local Configuration Manager Settings
 
    .EXAMPLE
    New-AzSystemData -RootPath "C:\StigRepo" -ResourceGroupName "My-Azure-ResourceGroup"
 
    #>

    [CmdletBinding()]
    param (
        [Parameter()]
        [string]
        $RootPath = (Get-Location).Path,

        [Parameter()]
        [string]
        $ResourceGroupName,

        [Parameter()]
        [switch]
        $DomainControllers,

        # [Parameter()]
        # [switch]
        # $IncludeFilePaths,

        [Parameter()]
        [switch]
        $IncludeLCMSettings,

        [Parameter()]
        [HashTable]
        $LcmSettings = @{
            actionAfterReboot              = ""
            agentId                        = ""
            allowModuleOverwrite           = $True
            certificateID                  = ""
            configurationDownloadManagers  = ""
            configurationID                = ""
            configurationMode              = "ApplyAndAutoCorrect"
            configurationModeFrequencyMins = "15"
            credential                     = ""
            debugMode                      = ""
            downloadManagerCustomData      = ""
            downloadManagerName            = ""
            lcmStateDetail                 = ""
            maximumDownloadSizeMB          = "500"
            partialConfigurations          = ""
            rebootNodeIfNeeded             = $False
            refreshFrequencyMins           = "30"
            refreshMode                    = "PUSH"
            reportManagers                 = "{}"
            resourceModuleManagers         = "{}"
            signatureValidationPolicy      = ""
            signatureValidations           = "{}"
            statusRetentionTimeInDays      = "10"
        }
    )

    Write-Output "Starting Azure System Data Creation"
    $IncludeFilePaths = $true
    $systemsPath      = (Resolve-Path "$RootPath\Systems").Path
    $resourceGroups   = New-Object System.Collections.ArrayList
    $virtualMachines  = New-Object System.Collections.ArrayList

    Write-Output "`tGetting Virtual Machine Resource Groups"
    if ("" -eq $ResourceGroupName) { Get-AzVM | ForEach-Object { $null = $virtualMachines.Add($_) } }
    else { Get-AzVM -ResourceGroupName $ResourceGroupName | ForEach-Object { $null = $virtualMachines.Add($_) } }

    $virtualMachines.ResourceGroupName | Get-Unique | Foreach-Object { $null = $resourceGroups.Add($_) }

    foreach ($resourceGroup in $ResourceGroups)
    {
        Write-Output "`n`tBeginning ResourceGroup System Data Generation - $ResourceGroup"

        $jobs               = New-Object System.Collections.ArrayList
        $rgFolder           = (New-Item -ItemType Directory -Path "$SystemsPath\$resourceGroup" -Force).FullName
        $resourceGroupVMs   = $virtualMachines | Where-Object ResourceGroupName -eq $resourceGroup

        #region VirtualMachine Jobs
        foreach ($virtualMachine in $resourceGroupVms)
        {
            Write-Output "`t`tStarting Job - $($virtualMachine.name)"
            $osType = $virtualMachine.StorageProfile.ImageReference.Offer
            $osVersion = $virtualMachine.StorageProfile.ImageReference.Sku
            $vmName = $virtualMachine.Name

            $job = Start-Job -ScriptBlock {

                $RootPath           = $using:rootPath
                $resourceGroup      = $using:resourceGroup
                $rgFolder           = $using:rgFolder
                $osType             = $using:osType
                $osVersion          = $using:osVersion
                $vmName             = $using:vmName
                $LcmSettings        = $using:LcmSettings
                $dataFilePath       = New-Item "$rgFolder\$vmName.psd1" -Force
                $applicableStigs    = New-Object System.Collections.ArrayList

                #region STIG Applicability

                switch -wildcard ($osType)
                {
                    "*WindowsServer"
                    {
                        if ($DomainControllers)
                        {
                            $osRole = 'DC'
                            $null = $applicableStigs.add("DomainController")
                        }
                        else
                        {
                            $osRole = 'MS'
                            $null   = $applicableStigs.add("WindowsServer")
                        }

                        $null = $applicableStigs.add("InternetExplorer")
                        $null = $applicableStigs.add("WindowsFirewall")
                        $null = $applicableStigs.add("WindowsDefender")
                        $null = $applicableStigs.add("DotnetFramework")
                    }
                    "Windows-10"
                    {
                        $null = $applicableStigs.add("WindowsClient")
                        $null = $applicableStigs.add("InternetExplorer")
                        $null = $applicableStigs.add("WindowsFirewall")
                        $null = $applicableStigs.add("WindowsDefender")
                        $null = $applicableStigs.add("DotnetFramework")
                    }
                    "RHEL"    {$null = $applicableStigs.add("RHEL")}
                    "CentOS"  {$null = $applicableStigs.add("CentOS")}
                    "Ubuntu*" {$null = $applicableStigs.add("Ubuntu")}
                }
                #endRegion

                #region Get STIG Files
                if ($IncludeFilePaths)
                {
                    Write-Output "`tFinding STIG Data File Paths"
                    switch -Wildcard ($applicableStigs)
                    {
                        "WindowsServer*"
                        {
                            $osStigFiles = @{
                                orgSettings  = Get-StigFiles -Rootpath $RootPath -StigType "WindowsServer" -Version $osVersion -FileType "OrgSettings" -NodeName $vmName
                                xccdfPath    = Get-StigFiles -Rootpath $RootPath -StigType "WindowsServer" -Version $osVersion -FileType "Xccdf" -NodeName $vmName
                                manualChecks = Get-StigFiles -Rootpath $RootPath -StigType "WindowsServer" -Version $osVersion -FileType "ManualChecks" -NodeName $vmName
                            }
                        }
                        "DotNetFramework"
                        {
                            $dotNetStigFiles = @{
                                orgsettings  = Get-StigFiles -Rootpath $Rootpath -StigType "DotNetFramework" -Version 4 -FileType "OrgSettings" -NodeName $vmName
                                xccdfPath    = Get-StigFiles -Rootpath $Rootpath -StigType "DotNetFramework" -Version 4 -FileType "Xccdf" -NodeName $vmName
                                manualChecks = Get-StigFiles -Rootpath $Rootpath -StigType "DotNetFramework" -Version 4 -FileType "ManualChecks" -NodeName $vmName
                            }
                        }
                        "InternetExplorer"
                        {
                            $ieStigFiles = @{
                                xccdfPath      = Get-StigFiles -Rootpath $Rootpath -StigType "InternetExplorer" -Version 11 -FileType "Xccdf" -NodeName $vmName
                                orgSettings    = Get-StigFiles -Rootpath $Rootpath -StigType "InternetExplorer" -Version 11 -FileType "OrgSettings" -NodeName $vmName
                                manualChecks   = Get-StigFiles -Rootpath $Rootpath -StigType "InternetExplorer" -Version 11 -FileType "ManualChecks" -NodeName $vmName
                            }
                        }
                        "WindowsClient"
                        {
                            $Win10StigFiles = @{
                                orgSettings  = Get-StigFiles -Rootpath $RootPath -StigType "WindowsClient" -Version $osVersion -FileType "OrgSettings" -NodeName $vmName
                                xccdfPath    = Get-StigFiles -Rootpath $RootPath -StigType "WindowsClient" -Version $osVersion -FileType "Xccdf" -NodeName $vmName
                                manualChecks = Get-StigFiles -Rootpath $RootPath -StigType "WindowsClient" -Version $osVersion -FileType "ManualChecks" -NodeName $vmName
                            }
                        }
                        "WindowsDefender"
                        {
                            $WinDefenderStigFiles = @{
                                orgSettings  = Get-StigFiles -Rootpath $RootPath -StigType "WindowsDefender" -FileType "OrgSettings" -NodeName $vmName
                                xccdfPath    = Get-StigFiles -Rootpath $RootPath -StigType "WindowsDefender" -FileType "Xccdf" -NodeName $vmName
                                manualChecks = Get-StigFiles -Rootpath $RootPath -StigType "WindowsDefender" -FileType "ManualChecks" -NodeName $vmName
                            }
                        }
                        "WindowsFirewall"
                        {
                            $WinFirewallStigFiles = @{
                                orgSettings  = Get-StigFiles -Rootpath $RootPath -StigType "WindowsFirewall" -FileType "OrgSettings" -NodeName $vmName
                                xccdfPath    = Get-StigFiles -Rootpath $RootPath -StigType "WindowsFirewall" -FileType "Xccdf" -NodeName $vmName
                                manualChecks = Get-StigFiles -Rootpath $RootPath -StigType "WindowsFirewall" -FileType "ManualChecks" -NodeName $vmName
                            }
                        }
                        "WindowsDnsServer"
                        {
                            $WindowsDnsStigFiles = @{
                                orgSettings  = Get-StigFiles -Rootpath $RootPath -StigType "WindowsDnsServer" -FileType "OrgSettings" -NodeName $vmName
                                xccdfPath    = Get-StigFiles -Rootpath $RootPath -StigType "WindowsDnsServer" -FileType "Xccdf" -NodeName $vmName
                                manualChecks = Get-StigFiles -Rootpath $RootPath -StigType "WindowsDnsServer" -FileType "ManualChecks" -NodeName $vmName
                            }
                        }
                        "Office2016"
                        {
                            $word2016xccdfPath          = Get-StigFiles -Rootpath $Rootpath -StigType "Office2016_Word" -Version 16 -FileType "Xccdf" -NodeName $vmName
                            $word2016orgSettings        = Get-StigFiles -Rootpath $Rootpath -StigType "Office2016_Word" -Version 16 -FileType "OrgSettings" -NodeName $vmName
                            $word2016manualChecks       = Get-StigFiles -Rootpath $Rootpath -StigType "Office2016_Word" -Version 16 -FileType "ManualChecks" -NodeName $vmName
                            $powerpoint2016xccdfPath    = Get-StigFiles -Rootpath $Rootpath -StigType "Office2016_PowerPoint" -Version 16 -FileType "Xccdf" -NodeName $vmName
                            $powerpoint2016orgSettings  = Get-StigFiles -Rootpath $Rootpath -StigType "Office2016_PowerPoint" -Version 16 -FileType "OrgSettings" -NodeName $vmName
                            $powerpoint2016manualChecks = Get-StigFiles -Rootpath $Rootpath -StigType "Office2016_PowerPoint" -Version 16 -FileType "ManualChecks" -NodeName $vmName
                            $outlook2016xccdfPath       = Get-StigFiles -Rootpath $Rootpath -StigType "Office2016_Outlook" -Version 16 -FileType "Xccdf" -NodeName $vmName
                            $outlook2016orgSettings     = Get-StigFiles -Rootpath $Rootpath -StigType "Office2016_Outlook" -Version 16 -FileType "OrgSettings" -NodeName $vmName
                            $outlook2016manualChecks    = Get-StigFiles -Rootpath $Rootpath -StigType "Office2016_Outlook" -Version 16 -FileType "ManualChecks" -NodeName $vmName
                            $excel2016xccdfPath         = Get-StigFiles -Rootpath $Rootpath -StigType "Office2016_Excel" -Version 16 -FileType "Xccdf" -NodeName $vmName
                            $excel2016orgSettings       = Get-StigFiles -Rootpath $Rootpath -StigType "Office2016_Excel" -Version 16 -FileType "OrgSettings" -NodeName $vmName
                            $excel2016manualChecks      = Get-StigFiles -Rootpath $Rootpath -StigType "Office2016_Excel" -Version 16 -FileType "ManualChecks" -NodeName $vmName
                        }
                        "Office2013"
                        {
                            $word2013xccdfPath          = Get-StigFiles -Rootpath $Rootpath -StigType "Office2013_word" -Version 15 -FileType "Xccdf" -NodeName $vmName
                            $word2013orgSettings        = Get-StigFiles -Rootpath $Rootpath -StigType "Office2013_word" -Version 15 -FileType "OrgSettings" -NodeName $vmName
                            $word2013manualChecks       = Get-StigFiles -Rootpath $Rootpath -StigType "Office2013_word" -Version 15 -FileType "ManualChecks" -NodeName $vmName
                            $powerpoint2013xccdfPath    = Get-StigFiles -Rootpath $Rootpath -StigType "Office2013_powerpoint" -Version 15 -FileType "Xccdf" -NodeName $vmName
                            $powerpoint2013orgSettings  = Get-StigFiles -Rootpath $Rootpath -StigType "Office2013_powerpoint" -Version 15 -FileType "OrgSettings" -NodeName $vmName
                            $powerpoint2013manualChecks = Get-StigFiles -Rootpath $Rootpath -StigType "Office2013_powerpoint" -Version 15 -FileType "ManualChecks" -NodeName $vmName
                            $outlook2013xccdfPath       = Get-StigFiles -Rootpath $Rootpath -StigType "Office2013_outlook" -Version 15 -FileType "Xccdf" -NodeName $vmName
                            $outlook2013orgSettings     = Get-StigFiles -Rootpath $Rootpath -StigType "Office2013_outlook" -Version 15 -FileType "OrgSettings" -NodeName $vmName
                            $outlook2013manualChecks    = Get-StigFiles -Rootpath $Rootpath -StigType "Office2013_outlook" -Version 15 -FileType "ManualChecks" -NodeName $vmName
                            $excel2013xccdfPath         = Get-StigFiles -Rootpath $Rootpath -StigType "Office2013_excel" -Version 15 -FileType "Xccdf" -NodeName $vmName
                            $excel2013orgSettings       = Get-StigFiles -Rootpath $Rootpath -StigType "Office2013_excel" -Version 15 -FileType "OrgSettings" -NodeName $vmName
                            $excel2013manualChecks      = Get-StigFiles -Rootpath $Rootpath -StigType "Office2013_excel" -Version 15 -FileType "ManualChecks" -NodeName $vmName
                        }
                        "SQLServerInstance"
                        {
                            $version = "2016"
                            $sqlInstanceStigFiles = @{
                                xccdfPath      = Get-StigFiles -Rootpath $Rootpath -Version $Version -StigType "SqlServerInstance" -FileType "Xccdf" -NodeName $vmName
                                orgSettings    = Get-StigFiles -Rootpath $Rootpath -Version $Version -StigType "SqlServerInstance" -FileType "OrgSettings" -NodeName $vmName
                                manualChecks   = Get-StigFiles -Rootpath $Rootpath -Version $Version -StigType "SqlServerInstance" -FileType "ManualChecks" -NodeName $vmName
                            }
                        }
                        "SqlServerDatabase"
                        {
                            $sqlDatabaseStigFiles = @{
                                xccdfPath      = Get-StigFiles -Rootpath $Rootpath -Version $Version -StigType "SqlServerDataBase" -FileType "Xccdf" -NodeName $vmName
                                orgSettings    = Get-StigFiles -Rootpath $Rootpath -Version $Version -StigType "SqlServerDataBase" -FileType "OrgSettings" -NodeName $vmName
                                manualChecks   = Get-StigFiles -Rootpath $Rootpath -Version $Version -StigType "SqlServerDataBase" -FileType "ManualChecks" -NodeName $vmName
                            }
                        }
                        "WebSite*"
                        {
                            $iisVersion = Invoke-Command -ComputerName $vmName -Scriptblock {
                                $iisData = Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\InetStp"
                                $localIisVersion = "$($iisData.MajorVersion).$($iisData.MinorVersion)"
                                return $localiisVersion
                            }
                            $WebsiteStigFiles = @{
                                xccdfPath      = Get-StigFiles -Rootpath $Rootpath -StigType "WebSite" -Version $iisVersion -FileType "Xccdf" -NodeName $vmName
                                orgSettings    = Get-StigFiles -Rootpath $Rootpath -StigType "WebSite" -Version $iisVersion -FileType "OrgSettings" -NodeName $vmName
                                manualChecks   = Get-StigFiles -Rootpath $Rootpath -StigType "WebSite" -Version $iisVersion -FileType "ManualChecks" -NodeName $vmName
                            }
                        }
                        "WebServer*"
                        {
                            [decimal]$iisVersion = Invoke-Command -ComputerName $vmName -Scriptblock {
                                $iisData = Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\InetStp"
                                $localIisVersion = "$($iisData.MajorVersion).$($iisData.MinorVersion)"
                                return $localiisVersion
                            }
                            $webServerStigFiles = @{
                                xccdfPath      = Get-StigFiles -Rootpath $Rootpath -StigType "WebServer" -Version $iisVersion -FileType "Xccdf" -NodeName $vmName
                                orgSettings    = Get-StigFiles -Rootpath $Rootpath -StigType "WebServer" -Version $iisVersion -FileType "OrgSettings" -NodeName $vmName
                                manualChecks   = Get-StigFiles -Rootpath $Rootpath -StigType "WebServer" -Version $iisVersion -FileType "ManualChecks" -NodeName $vmName
                            }
                        }
                        "McAfee"
                        {
                            $mcafeeStigFiles = @{
                                xccdfPath      = Get-StigFiles -Rootpath $Rootpath -StigType "McAfee" -FileType "Xccdf" -NodeName $vmName
                                orgSettings    = Get-StigFiles -Rootpath $Rootpath -StigType "McAfee" -FileType "OrgSettings" -NodeName $vmName
                                manualChecks   = Get-StigFiles -Rootpath $Rootpath -StigType "McAfee" -FileType "ManualChecks" -NodeName $vmName
                            }
                        }
                        "FireFox"
                        {
                            $fireFoxStigFiles = @{
                                xccdfPath      = Get-StigFiles -Rootpath $Rootpath -StigType "FireFox" -FileType "Xccdf" -NodeName $vmName
                                orgSettings    = Get-StigFiles -Rootpath $Rootpath -StigType "FireFox" -FileType "OrgSettings" -NodeName $vmName
                                manualChecks   = Get-StigFiles -Rootpath $Rootpath -StigType "FireFox" -FileType "ManualChecks" -NodeName $vmName
                            }
                        }
                        "Edge"
                        {
                            $edgeStigFiles = @{
                                xccdfPath      = Get-StigFiles -Rootpath $Rootpath -StigType "Edge" -FileType "Xccdf" -NodeName $vmName
                                orgSettings    = Get-StigFiles -Rootpath $Rootpath -StigType "Edge" -FileType "OrgSettings" -NodeName $vmName
                                manualChecks   = Get-StigFiles -Rootpath $Rootpath -StigType "Edge" -FileType "ManualChecks" -NodeName $vmName
                            }
                        }
                        "Chrome"
                        {
                            $chromeStigFiles = @{
                                xccdfPath      = Get-StigFiles -Rootpath $Rootpath -StigType "Chrome" -FileType "Xccdf" -NodeName $vmName
                                orgSettings    = Get-StigFiles -Rootpath $Rootpath -StigType "Chrome" -FileType "OrgSettings" -NodeName $vmName
                                manualChecks   = Get-StigFiles -Rootpath $Rootpath -StigType "Chrome" -FileType "ManualChecks" -NodeName $vmName
                            }
                        }
                        "Adobe"
                        {
                            $adobeStigFiles = @{
                                orgsettings  = Get-StigFiles -Rootpath $Rootpath -StigType "Adobe" -FileType "OrgSettings" -NodeName $vmName
                                xccdfPath    = Get-StigFiles -Rootpath $Rootpath -StigType "Adobe" -FileType "Xccdf" -NodeName $vmName
                                manualChecks = Get-StigFiles -Rootpath $Rootpath -StigType "Adobe" -FileType "ManualChecks" -NodeName $vmName
                            }
                        }
                        "OracleJRE"
                        {
                            $oracleStigFiles = @{
                                xccdfPath      = Get-StigFiles -Rootpath $Rootpath -StigType "OracleJRE" -FileType "Xccdf" -NodeName $vmName
                                orgSettings    = Get-StigFiles -Rootpath $Rootpath -StigType "OracleJRE" -FileType "OrgSettings" -NodeName $vmName
                                manualChecks   = Get-StigFiles -Rootpath $Rootpath -StigType "OracleJRE" -FileType "ManualChecks" -NodeName $vmName
                            }
                        }
                    }
                }
                #endRegion

                #region Build NodeData
                $configContent = New-Object System.Collections.ArrayList
                $null = $configContent.add("@{`n`tNodeName = `"$vmName`"")

                if ($null -ne $applicableSTIGs)
                {
                    $null = $configContent.add("`n`n`tAppliedConfigurations =")
                    $null = $configContent.add("`n`t@{")

                    switch -Wildcard ($applicableSTIGs)
                    {
                        {$_ -like "WindowsServer*" -or $_ -like "DomainController"}
                        {
                            switch -Wildcard ($osVersion)
                            {
                                "*2012*" {$osVersion = "2012R2";break}
                                "*2016*" {$osVersion = "2016";break}
                                "*2019*" {$osVersion = "2019";break}
                            }
                            $null = $configContent.add("`n`n`t`tPowerSTIG_WindowsServer =")
                            $null = $configContent.add("`n`t`t@{")
                            $null = $configContent.add("`n`t`t`tOSRole = `"$osRole`"")
                            $null = $configContent.add("`n`t`t`tOsVersion = `"$osVersion`"")

                            switch -Wildcard ($osVersion)
                            {
                                "*2016*"
                                {
                                    $null = $configContent.add("`n`t`t`tSkipRule = @('V-224866','V-224867','V-224868')")
                                    $null = $configContent.add("`n`t`t`tException = @{")
                                    $null = $configContent.add("`n`t`t`t 'V-225019' = @{Identity = 'Guests'}")
                                    $null = $configContent.add("`n`t`t`t 'V-225016' = @{Identity = 'Guests'}")
                                    $null = $configContent.add("`n`t`t`t 'V-225018' = @{Identity = 'Guests'}")
                                    $null = $configContent.add("`n`t`t`t}")
                                    $null = $configContent.add("`n`t`t`tOrgSettings = @{")
                                    $null = $configContent.add("`n`t`t`t 'V-225015' = @{Identity = 'Guests'}")
                                    $null = $configContent.add("`n`t`t`t 'V-225027' = @{OptionValue = 'xGuest'}")
                                    $null = $configContent.add("`n`t`t`t 'V-225063' = @{ValueData = '2'}")
                                    $null = $configContent.add("`n`t`t`t}")
                                }
                                "*2019*"
                                {
                                    $null = $configContent.add("`n`t`t`tSkipRule = @('V-205737')")
                                    $null = $configContent.add("`n`t`t`tException = @{")
                                    $null = $configContent.add("`n`t`t`t 'V-205733' = @{Identity = 'Guests'}")
                                    $null = $configContent.add("`n`t`t`t 'V-205672' = @{Identity = 'Guests'}")
                                    $null = $configContent.add("`n`t`t`t 'V-205673' = @{Identity = 'Guests'}")
                                    $null = $configContent.add("`n`t`t`t 'V-205675' = @{Identity = 'Guests'}")
                                    $null = $configContent.add("`n`t`t`t}")
                                    $null = $configContent.add("`n`t`t`tOrgSettings = @{")
                                    $null = $configContent.add("`n`t`t`t 'V-205910' = @{OptionValue = 'xGuest'}")
                                    $null = $configContent.add("`n`t`t`t 'V-205717' = @{ValueData = '2'}")
                                    $null = $configContent.add("`n`t`t`t}")
                                }
                            }
                            if ($IncludeFilePaths)
                            {
                                $null = $configContent.add("`n`t`t`txccdfPath = `"$($osStigFiles.xccdfPath)`"")
                                $null = $configContent.add("`n`t`t`tOrgSettings = `"$($osStigFiles.orgSettings)`"")
                                $null = $configContent.add("`n`t`t`tManualChecks = `"$($osStigFiles.manualChecks)`"")
                                $null = $configContent.add("`n`t`t}")
                            }
                            else { $null = $configContent.add("`n`t`t}") }
                        }
                        "WindowsClient"
                        {
                            $null = $configContent.add("`n`n`t`tPowerSTIG_WindowsClient =")
                            $null = $configContent.add("`n`t`t@{")
                            $null = $configContent.add("`n`t`t`tOSVersion = `"10`"")
                            $null = $configContent.add("`n`t`t`tSkipRule = @('V-220740','V-220739','V-220741','V-220908')")
                            $null = $configContent.add("`n`t`t`tOrgSettings = @{")
                            $null = $configContent.add("`n`t`t`t 'V-220912' = @{OptionValue = 'xGuest'}")
                            $null = $configContent.add("`n`t`t`t}")
                            $null = $configContent.add("`n`t`t`tException = @{")
                            $null = $configContent.add("`n`t`t`t 'V-220972' = @{Identity = 'Guests'}")
                            $null = $configContent.add("`n`t`t`t 'V-220968' = @{Identity = 'Guests'}")
                            $null = $configContent.add("`n`t`t`t 'V-220969' = @{Identity = 'Guests'}")
                            $null = $configContent.add("`n`t`t`t 'V-220971' = @{Identity = 'Guests'}")
                            $null = $configContent.add("`n`t`t`t}")

                            if ($IncludeFilePaths)
                            {
                                $null = $configContent.add("`n`t`t`txccdfPath = `"$($win10StigFiles.xccdfPath)`"")
                                $null = $configContent.add("`n`t`t`tOrgSettings = `"$($win10StigFiles.orgSettings)`"")
                                $null = $configContent.add("`n`t`t`tManualChecks = `"$($win10StigFiles.manualChecks)`"")
                                $null = $configContent.add("`n`t`t}")
                            }
                            else { $null = $configContent.add("`n`t`t}") }
                        }
                        "RHEL"
                        {
                            $null = $configContent.add("`n`n`t`tPowerSTIG_RHEL =")
                            $null = $configContent.add("`n`t`t@{")

                            if      ($osVersion -like "7*")
                            {
                                $null = $configContent.add("`n`t`t`tOSVersion = `"7`"")
                                $null = $configContent.add("`n`t`t`tSkipRule = @('V-204623','V-204399.a','V-204399.b','V-204400','V-204403')")
                            }
                            elseif  ($osVersion -like "8*")
                            {
                                $null = $configContent.add("`n`t`t`tOSVersion = `"8`"")
                            }

                            if ($IncludeFilePaths)
                            {
                                $null = $configContent.add("`n`t`t`txccdfPath = `"$($win10StigFiles.xccdfPath)`"")
                                $null = $configContent.add("`n`t`t`tOrgSettings = `"$($win10StigFiles.orgSettings)`"")
                                $null = $configContent.add("`n`t`t`tManualChecks = `"$($win10StigFiles.manualChecks)`"")
                                $null = $configContent.add("`n`t`t}")
                            }
                            else { $null = $configContent.add("`n`t`t}") }
                        }
                        "Ubuntu*"
                        {
                            $null = $configContent.add("`n`n`t`tPowerSTIG_Ubuntu =")
                            $null = $configContent.add("`n`t`t@{")
                            $null = $configContent.add("`n`t`t`tOSVersion = `"18.04`"")
                            $null = $configContent.add("`n`t`t`tSkipRule = @('V-219159','V-219167.a','V-219167.b','V-219167.c')")

                            if ($IncludeFilePaths)
                            {
                                $null = $configContent.add("`n`t`t`txccdfPath = `"$($win10StigFiles.xccdfPath)`"")
                                $null = $configContent.add("`n`t`t`tOrgSettings = `"$($win10StigFiles.orgSettings)`"")
                                $null = $configContent.add("`n`t`t`tManualChecks = `"$($win10StigFiles.manualChecks)`"")
                                $null = $configContent.add("`n`t`t}")
                            }
                            else { $null = $configContent.add("`n`t`t}") }
                        }
                        "CentOS*"
                        {
                            $null = $configContent.add("`n`n`t`tPowerSTIG_RHEL =")
                            $null = $configContent.add("`n`t`t@{")
                            $null = $configContent.add("`n`t`t`tOSVersion = `"7`"")
                            $null = $configContent.add("`n`t`t`tSkipRule = @('V-204623','V-204399.a','V-204399.b','V-204400','V-204403')")
                            if ($IncludeFilePaths)
                            {
                                $null = $configContent.add("`n`t`t`txccdfPath = `"$($win10StigFiles.xccdfPath)`"")
                                $null = $configContent.add("`n`t`t`tOrgSettings = `"$($win10StigFiles.orgSettings)`"")
                                $null = $configContent.add("`n`t`t`tManualChecks = `"$($win10StigFiles.manualChecks)`"")
                                $null = $configContent.add("`n`t`t}")
                            }
                            else { $null = $configContent.add("`n`t`t}") }
                        }
                        "InternetExplorer"
                        {
                            $null = $configContent.add("`n`n`t`tPowerSTIG_InternetExplorer =")
                            $null = $configContent.add("`n`t`t@{")
                            $null = $configContent.add("`n`t`t`tBrowserVersion = `"11`"")
                            $null = $configContent.add("`n`t`t`tSkipRule = `"V-46477`"")

                            if ($IncludeFilePaths)
                            {
                                $null = $configContent.add("`n`t`t`txccdfPath = `"$($ieStigFiles.xccdfPath)`"")
                                $null = $configContent.add("`n`t`t`tOrgSettings = `"$($ieStigFiles.orgSettings)`"")
                                $null = $configContent.add("`n`t`t}")
                            }
                            else { $null = $configContent.add("`n`t`t}") }
                        }
                        "DotnetFrameWork"
                        {
                            $null = $configContent.add("`n`n`t`tPowerSTIG_DotNetFrameWork =")
                            $null = $configContent.add("`n`t`t@{")
                            $null = $configContent.add("`n`t`t`tFrameWorkVersion = `"4`"")

                            if ($IncludeFilePaths)
                            {
                                $null = $configContent.add("`n`t`t`txccdfPath = `"$($dotNetStigFiles.xccdfPath)`"")
                                $null = $configContent.add("`n`t`t`tOrgSettings = `"$($dotNetStigFiles.orgSettings)`"")
                                $null = $configContent.add("`n`t`t`tManualChecks = `"$($dotNetStigFiles.manualChecks)`"")
                                $null = $configContent.add("`n`t`t}")
                            }
                            else { $null = $configContent.add("`n`t`t}") }
                        }
                        "WindowsDefender"
                        {
                            $null = $configContent.add("`n`n`t`tPowerSTIG_WindowsDefender =")
                            $null = $configContent.add("`n`t`t@{")
                            $null = $configContent.add("`n`t`t`tOrgSettings = @{'V-213450' = @{ValueData = '1' }}")
                            if ($IncludeFilePaths)
                            {
                                $null = $configContent.add("`n`t`t`txccdfPath = `"$($winDefenderStigFiles.xccdfPath)`"")
                                $null = $configContent.add("`n`t`t`tOrgSettings = `"$($winDefenderStigFiles.orgSettings)`"")
                                $null = $configContent.add("`n`t`t`tManualChecks = `"$($winDefenderStigFiles.manualChecks)`"")
                                $null = $configContent.add("`n`t`t}")
                            }
                            else { $null = $configContent.add("`n`t`t}") }
                        }
                        "WindowsFirewall"
                        {
                            $null = $configContent.add("`n`n`t`tPowerSTIG_WindowsFirewall =")
                            $null = $configContent.add("`n`t`t@{")
                            $null = $configContent.add("`n`t`t`tSkiprule = @('V-17443', 'V-17442')")
                            if ($IncludeFilePaths)
                            {
                                $null = $configContent.add("`n`t`t`txccdfPath = `"$($winFirewallStigFiles.xccdfPath)`"")
                                $null = $configContent.add("`n`t`t`tOrgSettings = `"$($winFirewallStigFiles.orgSettings)`"")
                                $null = $configContent.add("`n`t`t`tManualChecks = `"$($winFirewallStigFiles.manualChecks)`"")
                                $null = $configContent.add("`n`t`t}")
                            }
                            else { $null = $configContent.add("`n`t`t}") }
                        }
                        "WindowsDnsServer"
                        {
                            $null = $configContent.add("`n`n`t`tPowerSTIG_WindowsDNSServer =")
                            $null = $configContent.add("`n`t`t@{")
                            $null = $configContent.add("`n`t`t`tOsVersion = `"$osVersion`"")

                            if ($IncludeFilePaths)
                            {
                                $null = $configContent.add("`n`t`t`txccdfPath = `"$($WindowsDnsStigFiles.xccdfPath)`"")
                                $null = $configContent.add("`n`t`t`tOrgSettings = `"$($WindowsDnsStigFiles.orgSettings)`"")
                                $null = $configContent.add("`n`t`t`tManualChecks = `"$($WindowsDnsStigFiles.manualChecks)`"")
                                $null = $configContent.add("`n`t`t}")
                            }
                            else { $null = $configContent.add("`n`t`t}") }
                        }
                        "Office2016*"
                        {
                            $null = $configContent.add("`n`n`t`tPowerSTIG_Office2016_Excel =")
                            $null = $configContent.add("`n`t`t@{")

                            if ($IncludeFilePaths)
                            {
                                $null = $configContent.add("`n`t`t`txccdfPath = `"$Excel2016xccdfPath`"")
                                $null = $configContent.add("`n`t`t`tOrgSettings = `"$Excel2016OrgSettings`"")
                                $null = $configContent.add("`n`t`t`tManualChecks = `"$Excel2016ManualChecks`"")
                            }
                            $null = $configContent.add("`n`t`t}")
                            $null = $configContent.add("`n`n`t`tPowerSTIG_Office2016_Outlook =")
                            $null = $configContent.add("`n`t`t@{")

                            if ($IncludeFilePaths)
                            {
                                $null = $configContent.add("`n`t`t`txccdfPath = `"$Outlook2016xccdfPath`"")
                                $null = $configContent.add("`n`t`t`tOrgSettings = `"$Outlook2016OrgSettings`"")
                                $null = $configContent.add("`n`t`t`tManualChecks = `"$Outlook2016ManualChecks`"")
                                $null = $configContent.add("`n`t`t}")
                            }
                            else { $null = $configContent.add("`n`n`t`t}") }

                            $null = $configContent.add("`n`n`t`tPowerSTIG_Office2016_PowerPoint =")
                            $null = $configContent.add("`n`t`t@{")

                            if ($IncludeFilePaths)
                            {
                                $null = $configContent.add("`n`t`t`txccdfPath = `"$PowerPoint2016xccdfPath`"")
                                $null = $configContent.add("`n`t`t`tOrgSettings = `"$PowerPoint2016OrgSettings`"")
                                $null = $configContent.add("`n`t`t`tManualChecks = `"$PowerPoint2016ManualChecks`"")
                                $null = $configContent.add("`n`t`t}")
                            }
                            else { $null = $configContent.add("`n`n`t`t}") }

                            $null = $configContent.add("`n`n`t`tPowerSTIG_Office2016_Word =")
                            $null = $configContent.add("`n`t`t@{")

                            if ($IncludeFilePaths)
                            {
                                $null = $configContent.add("`n`t`t`txccdfPath = `"$Word2016xccdfPath`"")
                                $null = $configContent.add("`n`t`t`tOrgSettings = `"$Word2016OrgSettings`"")
                                $null = $configContent.add("`n`t`t`tManualChecks = `"$Word2016ManualChecks`"")
                                $null = $configContent.add("`n`t`t}")
                            }
                            else { $null = $configContent.add("`n`n`t`t}") }
                        }
                        "Office2013*"
                        {
                            $null = $configContent.add("`n`n`t`tPowerSTIG_Office2013_Excel =")
                            $null = $configContent.add("`n`t`t@{")

                            if ($IncludeFilePaths)
                            {
                                $null = $configContent.add("`n`t`t`txccdfPath = `"$Excel2013xccdfPath`"")
                                $null = $configContent.add("`n`t`t`tOrgSettings = `"$Excel2013OrgSettings`"")
                                $null = $configContent.add("`n`t`t`tManualChecks = `"$Excel2013ManualChecks`"")
                                $null = $configContent.add("`n`t`t}")
                            }
                            else { $null = $configContent.add("`n`n`t`t}") }

                            $null = $configContent.add("`n`n`t`tPowerSTIG_Office2013_Outlook =")
                            $null = $configContent.add("`n`t`t@{")

                            if ($IncludeFilePaths)
                            {
                                $null = $configContent.add("`n`t`t`txccdfPath = `"$Outlook2013xccdfPath`"")
                                $null = $configContent.add("`n`t`t`tOrgSettings = `"$Outlook2013OrgSettings`"")
                                $null = $configContent.add("`n`t`t`tManualChecks = `"$Outlook2013ManualChecks`"")
                                $null = $configContent.add("`n`t`t}")
                            }
                            else { $null = $configContent.add("`n`n`t`t}") }

                            $null = $configContent.add("`n`n`t`tPowerSTIG_Office2013_PowerPoint =")
                            $null = $configContent.add("`n`t`t@{")

                            if ($IncludeFilePaths)
                            {
                                $null = $configContent.add("`n`t`t`txccdfPath = `"$PowerPoint2013xccdfPath`"")
                                $null = $configContent.add("`n`t`t`tOrgSettings = `"$PowerPoint2013OrgSettings`"")
                                $null = $configContent.add("`n`t`t`tManualChecks = `"$PowerPoint2013ManualChecks`"")
                                $null = $configContent.add("`n`t`t}")
                            }
                            else { $null = $configContent.add("`n`n`t`t}") }

                            $null = $configContent.add("`n`n`t`tPowerSTIG_Office2013_Word =")
                            $null = $configContent.add("`n`t`t@{")

                            if ($IncludeFilePaths)
                            {
                                $null = $configContent.add("`n`t`t`txccdfPath = `"$Word2013xccdfPath`"")
                                $null = $configContent.add("`n`t`t`tOrgSettings = `"$Word2013OrgSettings`"")
                                $null = $configContent.add("`n`t`t`tManualChecks = `"$Word2013ManualChecks`"")
                                $null = $configContent.add("`n`t`t}")
                            }
                            else { $null = $configContent.add("`n`n`t`t}") }
                        }
                        "Website*"
                        {
                            $websites = @(Invoke-Command -Computername $vmName -Scriptblock { Import-Module WebAdministration;Return (Get-Childitem "IIS:\Sites").name})
                            $appPools = @(Invoke-Command -Computername $vmName -Scriptblock { Import-Module WebAdministration;Return (Get-Childitem "IIS:\AppPools").name})
                            [string]$allWebSites = ''
                            [string]$allAppPools = ''
                            if ($websites.count -gt 1)
                            {
                                foreach ($site in $websites)
                                {
                                    $allWebsites += "`"$site`","
                                }
                                $websiteString = $allWebsites.TrimEnd(",")
                            }
                            else
                            {
                                $websiteString = "`"$websites`""
                            }

                            if ($appPools.count -gt 1)
                            {
                                foreach ($appPool in $appPools)
                                {
                                    $allAppPools += "`"$appPool`","
                                }
                                $appPoolString = $allAppPools.TrimEnd(",")
                            }
                            else
                            {
                                $appPoolString = "`"$appPools`""
                            }

                            $null = $configContent.add("`n`n`t`tPowerSTIG_WebSite =")
                            $null = $configContent.add("`n`t`t@{")
                            $null = $configContent.add("`n`t`t`tIISVersion = `"$IISVersion`"")
                            $null = $configContent.add("`n`t`t`tWebsiteName = $websiteString")
                            $null = $configContent.add("`n`t`t`tWebAppPool = $appPoolString")

                            if ($IncludeFilePaths)
                            {
                                $null = $configContent.add("`n`t`t`txccdfPath = `"$($webSiteStigFiles.XccdfPath)`"")
                                $null = $configContent.add("`n`t`t`tOrgSettings = `"$($webSiteStigFiles.OrgSettings)`"")
                                $null = $configContent.add("`n`t`t`tManualChecks = `"$($webSiteStigFiles.ManualChecks)`"")
                                $null = $configContent.add("`n`t`t}")
                            }
                            else { $null = $configContent.add("`n`t`t}") }
                        }
                        "WebServer*"
                        {
                            $null = $configContent.add("`n`n`t`tPowerSTIG_WebServer =")
                            $null = $configContent.add("`n`t`t@{")
                            $null = $configContent.add("`n`t`t`tSkipRule = `"V-214429`"")
                            $null = $configContent.add("`n`t`t`tIISVersion = `"$IISVersion`"")
                            $null = $configContent.add("`n`t`t`tLogPath = `"C:\InetPub\Logs`"")

                            if ($IncludeFilePaths)
                            {
                                $null = $configContent.add("`n`t`t`txccdfPath = `"$($webServerStigFiles.XccdfPath)`"")
                                $null = $configContent.add("`n`t`t`tOrgSettings = `"$($webServerStigFiles.OrgSettings)`"")
                                $null = $configContent.add("`n`t`t`tManualChecks = `"$($webServerStigFiles.ManualChecks)`"")
                                $null = $configContent.add("`n`t`t}")
                            }
                            else { $null = $configContent.add("`n`n`t`t}") }
                        }
                        "FireFox"
                        {
                            $null = $configContent.add("`n`n`t`tPowerSTIG_Firefox =")
                            $null = $configContent.add("`n`t`t@{")
                            $null = $configContent.add("`n`t`t`tInstallDirectory = `"C:\Program Files\Mozilla Firefox`"")

                            if ($IncludeFilePaths)
                            {
                                $null = $configContent.add("`n`t`t`txccdfPath = `"$($firefoxStigFiles.XccdfPath)`"")
                                $null = $configContent.add("`n`t`t`tOrgSettings = `"$($firefoxStigFiles.OrgSettings)`"")
                                $null = $configContent.add("`n`t`t`tManualChecks = `"$($firefoxStigFiles.ManualChecks)`"")
                                $null = $configContent.add("`n`t`t}")
                            }
                            else { $null = $configContent.add("`n`t`t}") }
                        }
                        "Edge"
                        {
                            $null = $configContent.add("`n`n`t`tPowerSTIG_Edge =")
                            $null = $configContent.add("`n`t`t@{")

                            if ($IncludeFilePaths)
                            {
                                $null = $configContent.add("`n`t`t`txccdfPath = `"$($edgeStigFiles.xccdfPath)`"")
                                $null = $configContent.add("`n`t`t`tOrgSettings = `"$($edgeStigFiles.orgSettings)`"")
                                $null = $configContent.add("`n`t`t`tManualChecks = `"$($edgeStigFiles.manualChecks)`"")
                                $null = $configContent.add("`n`t`t}")
                            }
                            else { $null = $configContent.add("`n`n`t`t}") }
                        }
                        "Chrome"
                        {
                            $null = $configContent.add("`n`n`t`tPowerSTIG_Chrome =")
                            $null = $configContent.add("`n`t`t@{")
                            if ($IncludeFilePaths)
                            {
                                $null = $configContent.add("`n`t`t`txccdfPath = `"$($chromeStigFiles.xccdfPath)`"")
                                $null = $configContent.add("`n`t`t`tOrgSettings = `"$($chromeStigFiles.orgSettings)`"")
                                $null = $configContent.add("`n`t`t`tManualChecks = `"$($chromeStigFiles.manualChecks)`"")
                                $null = $configContent.add("`n`t`t}")
                            }
                            else { $null = $configContent.add("`n`n`t`t}") }
                        }
                        "Adobe"
                        {
                            $null = $configContent.add("`n`n`t`tPowerSTIG_Adobe =")
                            $null = $configContent.add("`n`t`t@{")
                            $null = $configContent.add("`n`t`t`tAdobeApp = `"AcrobatReader`"")

                            if ($IncludeFilePaths)
                            {
                                $null = $configContent.add("`n`t`t`txccdfPath = `"$($adobeStigFiles.XccdfPath)`"")
                                $null = $configContent.add("`n`t`t`tOrgSettings = `"$($adobeStigFiles.OrgSettings)`"")
                                $null = $configContent.add("`n`t`t`tManualChecks = `"$($adobeStigFiles.ManualChecks)`"")
                                $null = $configContent.add("`n`t`t}")
                            }
                            else { $null = $configContent.add("`n`t`t}") }
                        }
                        "OracleJRE"
                        {
                            $null = $configContent.add("`n`n`t`tPowerSTIG_OracleJRE =")
                            $null = $configContent.add("`n`t`t@{")
                            $null = $configContent.add("`n`t`t`tConfigPath = `"$ConfigPath`"")
                            $null = $configContent.add("`n`t`t`tPropertiesPath = `"$PropertiesPath`"")

                            if ($IncludeFilePaths)
                            {
                                $null = $configContent.add("`n`t`t`txccdfPath = `"$($oracleStigFiles.XccdfPath)`"")
                                $null = $configContent.add("`n`t`t`tOrgSettings = `"$($oracleStigFiles.OrgSettings)`"")
                                $null = $configContent.add("`n`t`t`tManualChecks = `"$($oracleStigFiles.ManualChecks)`"")
                                $null = $configContent.add("`n`t`t}")
                            }
                            else { $null = $configContent.add("`n`n`t`t}") }
                        }
                    }
                    $null = $configContent.add("`n`t}")
                }

                if ($IncludeLcmSettings)
                {
                $null = $configContent.add("`n`n`tLocalConfigurationManager =")
                $null = $configContent.add("`n`t@{")

                    foreach ($setting in $LcmSettings.Keys)
                    {

                            if (($Null -ne $LcmSettings.$setting) -and ("{}" -ne $lcmsettings.$setting) -and ("" -ne $LcmSettings.$setting))
                            {
                                $null = $configContent.add("`n`t`t$($setting)")

                                if ($setting.Length -lt 8)      {$null = $configContent.add("`t`t`t`t`t`t`t= ")}
                                elseif ($setting.Length -lt 12) {$null = $configContent.add("`t`t`t`t`t`t= ")}
                                elseif ($setting.Length -lt 16) {$null = $configContent.add("`t`t`t`t`t= ")}
                                elseif ($setting.Length -lt 20) {$null = $configContent.add("`t`t`t`t= ")}
                                elseif ($setting.Length -lt 24) {$null = $configContent.add("`t`t`t= ")}
                                elseif ($setting.Length -lt 28) {$null = $configContent.add("`t`t= ")}
                                elseif ($setting.Length -lt 32) {$null = $configContent.add("`t= ")}

                                if (($LcmSettings.$setting -eq $true) -or ($LcmSettings.$setting -eq $false))
                                {
                                    $null = $configContent.add("`$$($LcmSettings.$setting)")
                                }
                                else
                                {
                                    $null = $configContent.add("`"$($LcmSettings.$setting)`"")
                                }
                            }
                    }
                    $null = $configContent.add("`n`t}")
                }
                $null = $configContent.add("`n}")

                $null = Set-Content -NoNewLine -Path $dataFilePath.FullName -Value $configContent
                Write-Output "`t`t$vmName - System data successfully generated."
                #endregion Build NodeData
            }
            $null = $jobs.add($job.Id)
        }
        #endregion
        if ($jobs.count -ge 1)
        {
            Write-Output "`t$resourceGroup - System data jobs created. Checking status every 30 seconds until all jobs are complete."

            do
            {
                $completedJobs = (Get-Job -ID $jobs | Where-Object {$_.state -ne "Running"}).count
                $runningjobs   = (Get-Job -ID $jobs | Where-Object {$_.state -eq "Running"}).count
                Write-Output "`t`tSystem Data Build Status:`t$runningJobs Jobs Currently Processing`t$completedJobs/$($jobs.count) Jobs Completed"
                Start-Sleep -Seconds 30
            }
            while ((Get-Job -ID $jobs).State -contains "Running")
            Write-Output "`n`t$($jobs.count) System data jobs completed. Outputting Results."
            Get-Job -ID $jobs | Wait-Job | Receive-Job
        }
        else
        {
            Write-Output "`t`tNo Jobs Generated for $resourceGroup"
        }

        Write-Output "`tResource Group System Data Generation Complete - $resourceGroup"
    }

    Write-Output "`nSystem Data Generation Complete"
}

function Publish-AzAutomationModules
{
    <#
    .SYNOPSIS
    Publishes modules stored in the SCAR repository into an Azure Automation Account
 
    .PARAMETER RootPath
    Root path of the Stig Compliance Automation Repository. Initialize by running Initialize-StigRepo
 
    .PARAMETER ResourceGroupName
    Name of the ResourceGroup containing the targeted Azure Automation Account
 
    .PARAMETER AutomationAccountName
    Name of the Azure Automation Account
 
    .PARAMETER PSGallery
    Switch to install modules directly from the powershell gallary instead of using the modules stored in the local Stig Repository.
 
    .EXAMPLE
    Publish-AzAutomationModules -Rootpath "C:\StigRepo" -ResourceGroupName "My-AzAutomation-ResourceGroup" -AutomationAccountName "MyAutomationAccount"
    #>


    [CmdletBinding()]
    param
    (
        [Parameter()]
        [string]
        $RootPath = (Get-Location).Path,

        [Parameter(Mandatory=$true)]
        [string]
        $ResourceGroupName,

        [Parameter(Mandatory=$true)]
        [string]
        $AutomationAccountName,

        [Parameter()]
        [switch]
        $PSGallery
    )

    Write-Output "Starting Azure Automation Module Sync"

    # Check for Az Context
    $azContext = Get-AzContext -ErrorAction SilentlyContinue
    if ($null -eq $azContext)
    {
        Write-Output "`tAzure Subscription not connected - Follow prompt to login."
        Connect-AzAccount
    }

    # Get local PowerSTIG Module Version
    Import-Module PowerSTIG -ErrorAction SilentlyContinue
    $installedversion = (Get-Module PowerSTIG -ErrorAction SilentlyContinue).version.ToString()

    switch ($PSGallery)
    {
        $false
        {
            # Check for valid Stig-Repo
            Write-Output "`tChecking for valid StigRepo location at $RootPath"
            $modulePath = "$Rootpath\Resources\Modules"

            if (Test-Path "$modulePath")
            {
                Write-Output "`t`tStigRepo Location is valid"
            }
            else
            {
                Write-Output "`t`t$Rootpath is not a SCAR repository. Please point to the SCAR directory or run Initialize-StigRepo to build it."
                exit
            }

            # Sync DSC Modules Locally
            Write-Output "`tValidating local PowerSTIG Modules"

            Import-Module PowerSTIG -ErrorAction SilentlyContinue
            $stigRepoVersion = (Get-Childitem "$modulePath\PowerSTIG" -ErrorAction SilentlyContinue).name
            $installedversion = (Get-Module PowerSTIG -ErrorAction SilentlyContinue).version.ToString()

            if (($installedVersion -ne $stigRepoVersion) -or ($null -eq $installedversion))
            {
                Write-Output "`t`tSyncing PowerSTIG Modules on localhost"
                Sync-DscModules -LocalHost -Force
                Import-Module PowerSTIG
                $installedVersion = (Get-Module PowerSTIG).version.tostring()
            }

            if ($null -ne $installedVersion)
            {
                Write-Output "`t`tPowerSTIG Module is valid."
            }
            else
            {
                Write-Output "`t`tError - Unable to install PowerSTIG module on the local system."
                exit
            }
            break
        }
        $true
        {
            Write-Output "`tValidating local PowerSTIG Modules"
            Import-Module StigRepo -ErrorAction SilentlyContinue
            $stigRepoModule = Get-Module -Name StigRepo -ErrorAction SilentlyContinue

            try
            {
                if ($null -ne $stigRepoModule)
                {
                    Write-Output "`t`tStigRepo module is valid"
                }
                else
                {
                    Write-Output "`t`tStigRepo Module not installed - Downloading from PS Gallery"
                    Save-Module -Name StigRepo -Path "$env:SystemDrive\Program Files\WindowsPowershell\Modules" -Force
                    Import-Module StigRepo -Force
                }

                if ($null -ne $installedVersion)
                {
                    Write-Output "`t`tPowerSTIG Module is valid"
                }
                else
                {
                    Write-Output "PowerSTIG Module not installed - Installing from PowerShell gallery"
                    Save-Module -Name PowerSTIG -Path "$env:SystemDrive\Program Files\WindowsPowershell\Modules" -Force
                    Import-Module PowerSTIG,StigRepo -Force
                }
            }
            catch
            {
                Write-Output "`t`tUnable to install PowerSTIG Module"
                Throw $_
                exit
            }
        }
    }

    # Publish Modules to Azure Automation
    Write-Output "`tPublishing Modules to Azure Automation"

    # Import Modules w/ dependencies
    $keyModules = "PowerSTIG","VMWare.Vim","VMWare.VimAutomation.Common","StigRepo"
    Import-Module $keyModules
    $importedKeyModules = Get-Module $keyModules

    # Add dependent modules to array
    $moduleList = New-Object System.Collections.ArrayList
    (Get-Module VMWare.VimAutomation.Common).RequiredModules | Foreach-Object { $null = $moduleList.Add($_) }
    (Get-Module VMWare.Vim).RequiredModules | Foreach-Object { $null = $moduleList.Add($_) }
    (Get-Module PowerSTIG ).requiredModules | Foreach-Object { $null = $moduleList.Add($_) }

    # Add key modules to array after dependencies
    $importedKeyModules | Foreach-Object { $null = $moduleList.Add($_) }

    foreach ($module in $moduleList)
    {
        $moduleName    = $module.name
        $moduleversion = $module.version.tostring()

        try
        {
            Write-Output "`t`tPublishing $moduleName Version $moduleVersion"
            $null = New-AzAutomationModule -Name $moduleName -ResourceGroupName $ResourceGroupName -AutomationAccountName $AutomationAccountName -ContentLinkUri "https://www.powershellgallery.com/api/v2/package/$moduleName/$moduleVersion" -ErrorAction Stop
        }
        catch
        {
            Write-Output "Publishing $moduleName Failed"
            Throw $_
        }
    }
    Write-Output "`n`n`tAzure Automation Module Sync complete."
}

function Publish-RepoToBlob
{
    <#
    .SYNOPSIS
    Publishes the STIG Compliance Automation Repository to Azure Blob Storage
 
    .PARAMETER RootPath
    Root path of the Stig Compliance Automation Repository. Initialize by running Initialize-StigRepo
 
    .PARAMETER ResourceGroupName
    Name of the ResourceGroup containing the targetted Azure Storage Account
 
    .PARAMETER ContainerName
    Name of the targetted Azure Storage Container
 
    .EXAMPLE
    Publish-RepoToBlob -RootPath "C:\StigRepo" -ResourceGroupName "My-Azure-ResourceGroup" -ContainerName "SCAR"
    #>


    [CmdletBinding()]
    param(
        [Parameter()]
        [string]
        $RootPath = (Get-Location).Path,

        [Parameter(Mandatory=$true)]
        [string]
        $ResourceGroupName,

        [Parameter(Mandatory=$true)]
        [string]
        $StorageAccountName = "stigstorage",

        [Parameter(Mandatory=$true)]
        [string]
        $ContainerName = "Scar"

    )

    try
    {
        $systemsPath  = (Resolve-Path "$rootPath\Systems").Path
        $configPath   = (Resolve-Path "$rootPath\Configurations").Path
        $artifactPath = (Resolve-Path "$rootPath\Artifacts").Path
        $resourcePath = (Resolve-Path "$rootPath\Resources").Path
    }
    catch
    {
        Write-Output "$Rootpath is not a valid SCAR repository. Run Initialize-StigRepo to configure the repo or Set-Location to the path where it exists."
        exit
    }
    $context = (Get-AzStorageAccount -ResourceGroupName $ResourceGroupName -Name $StorageAccountName).Context

    # detect specified container name, create it if it does not exist
    if (-not(Get-AzStorageContainer -Context $context -Prefix $ContainerName))
    {
        Write-Verbose -Message "Specified container does not exist, creating $ContainerName"
        New-AzStorageContainer -Context $context -Name $ContainerName -Permission Off | Out-Null
    }

    $scarFiles = Get-Childitem $RootPath -Recurse
    $scarFiles | ForEach-Object { Set-AzStorageBlobContent -Context $context -Container $ContainerName -Force }

}

function Register-AzAutomationNodes
{
    <#
    .SYNOPSIS
    Registers Virtual Machines with generated System Data in SCAR as Azure Automation Nodes
 
    .PARAMETER ResourceGroupName
    Name of the Azure Resource Group containing the Automation Account
 
    .PARAMETER AutomationAccountName
    Name of the Azure Automation Account
 
    .PARAMETER TargetFolder
    System Data Folder to target for Azure Automation registration
 
    .EXAMPLE
    Register-AzAutomationNodes -ResourceGroupName "AzAutomationRG" -AutomationAccountName "MyAutomationAccount"
 
    #>

    [CmdletBinding()]
    param(
        [Parameter()]
        [string]
        $RootPath = (Get-Location).Path,

        [Parameter(Mandatory=$true)]
        [string]
        $ResourceGroupName,

        [Parameter(Mandatory=$true)]
        [string]
        $AutomationAccountName,

        [Parameter()]
        [string]
        $TargetFolder,

        [Parameter()]
        [string]
        $ConfigurationMode = 'ApplyAndMonitor',

        [Parameter()]
        [string]
        $ConfigurationModeFrequencyMins = '15',

        [Parameter()]
        [string]
        $RefreshFrequencyMins = '30',

        [Parameter()]
        [string]
        $ActionAfterReboot = 'ContinueConfiguration',

        [Parameter()]
        [bool]
        $RebootNodeIfNeeded = $true,

        [Parameter()]
        [bool]
        $AllowModuleOverwrite = $true,

        [Parameter()]
        [switch]
        $Force

    )

    Write-Output "Preparing environment for Azure Automation Registration"
    $virtualMachines = New-Object System.Collections.ArrayList
    $jobs            = New-Object System.Collections.ArrayList

    # Validate Repository
    try
    {
        $null = Resolve-Path "$RootPath\Systems" -ErrorAction 'Stop'
        $null = Resolve-Path "$Rootpath\Configurations" -ErrorAction 'Stop'
        $null = Resolve-Path "$Rootpath\Artifacts" -ErrorAction 'Stop'
        $null = Resolve-Path "$Rootpath\Resources" -ErrorAction 'Stop'
        Write-OutPut "`tSTIG Repository Path is Valid:`t`t$RootPath"
    }
    catch
    {
        Write-Output "`n$Rootpath is not a valid STIG Repository"
        Write-Output "Please provide a valid path or build a new repository using the Initialize-StigRepo function"
    }

    # Validate Connection to Azure Subscription
    $azContext = Get-AzContext
    if ($null -ne $azContext)
    {
        $azSubscription = $azContext.Name.Split(" ")[0]
        Write-Output "`tConnected to Azure Subscription:`t$azSubscription"
    }
    else
    {
        Write-Output "`tPowershell session is not connected to an Azure Subscription. Follow the prompt to login."
        Connect-AzAccount
    }

    # Validate Azure Automation Account
    try
    {
        $null = Get-AzAutomationAccount -ResourceGroupName $ResourceGroupName -AutomationAccountName $AutomationAccountName -ErrorAction 'Stop'
        Write-Output "`tAzure Automation Account is valid:`t$AutomationAccountName"
    }
    catch
    {
        Write-Output "`nAutomation Account is invalid or cannot be found."
        Write-Output "Verify the Automation Account Exists and that your session is connect to the correct Azure Subscription and try again."
        exit
    }

    # Get Azure Virtual Machines
    if ('' -ne $TargetFolder)
    {
        if (Test-Path "$Rootpath\Systems\$TargetFolder")
        {
            Write-Output "`tGetting Virtual Machines from Folder:`t$RootPath\Systems\$TargetFolder"
            $vmNames = (Get-Childitem "$RootPath\Systems\$TargetFolder\*.psd1" -Recurse).BaseName
        }
        else
        {
            Write-Output "`tCould not find path - $RootPath\Systems\$TargetFolder"
            Write-Output "`tPlease Validate RootPath and TargetFolder name and try again"
            Write-Output "`nVirtualMachine Registration Cancelled"
            exit
        }
    }
    else
    {
        Write-Output "`tGetting Virtual Machines from Folder:`t$RootPath\Systems"
        $vmNames = (Get-Childitem "$RootPath\Systems\*.psd1" -Recurse).BaseName
    }

    Write-Output "`tGetting Azure Virtual Machine objects"

    foreach ($vmName in $vmNames)
    {
        $vmObject = Get-AzVM -Name $vmName -Status
        $null = $virtualMachines.Add($vmObject)
    }

    # Check for Linux Machines and generate registration Script
    Write-Output "`tChecking for Linux VMs"

    if ($virtualMachines.StorageProfile.OSDisk.OSType -contains 'linux')
    {
        Write-Output "`tLinux VMs identified - Getting registration data"
        $registrationData = Get-AzAutomationRegistrationInfo -ResourceGroupName $ResourceGroupName -AutomationAccountName $AutomationAccountName
        $registrationKey = $registrationData.PrimaryKey
        $registrationUrl = $registrationData.Endpoint

        Write-Output "`tGenerating Linux Registration Script"
        $linuxRegContent = "/opt/microsoft/dsc/Scripts/Register.py $registrationKey $registrationUrl"
        $linuxRegScript  = (New-Item -ItemType 'File' -Path "$RootPath\LinuxRegistration.sh" -Value $linuxRegContent -Force).FullName
    }
    else
    {
        $linuxRegScript  = $null
    }

    # Register Virtual Machines to Automation Acocunt
    if ($virtualMachines.Count -gt 0)
    {
        Write-Output "`nBeginning Azure Automation Registration for $($virtualMachines.Count) identified Virtual Machine(s)"
    }
    else
    {
        Write-Output "`nNo Virtual Machines were identified for registration."
        Write-Output "Ensure that System Data exists for the targetted Azure VMs and try again."
        exit
    }

    foreach ($virtualMachine in $virtualMachines)
    {
        Write-Output "`tStarting Node Registration Job - $($virtualMachine.Name)"
        [string]$osType = $virtualMachine.StorageProfile.OSDisk.OSType

        $job = Start-Job -ScriptBlock {

            $virtualMachine                 = $using:VirtualMachine
            $linuxRegScript                 = $using:linuxRegScript
            $ResourceGroupName              = $using:ResourceGroupName
            $AutomationAccountName          = $using:AutomationAccountName
            $ConfigurationMode              = $using:ConfigurationMode
            $ConfigurationModeFrequencyMins = $using:ConfigurationModeFrequencyMins
            $RefreshFrequencyMins           = $using:RefreshFrequencyMins
            $RebootNodeIfNeeded             = $using:RebootNodeIfNeeded
            $ActionAfterReboot              = $using:ActionAfterReboot
            $AllowModuleOverwrite           = $using:AllowModuleOverwrite
            $Force                          = $using:Force
            $RootPath                       = $using:RootPath
            $osType                         = $using:osType
            $vmName                         = $virtualMachine.Name
            $vmResourceGroup                = $virtualMachine.ResourceGroupName
            $vmPowerState                   = $virtualMachine.PowerState

            Write-OutPut "`n`tBeginning Registration:`t$($virtualMachine.Name)"

            # Start VM if deallocated
            Write-Output "`t`tChecking VM Running State"

            if ($vmPowerState -ne 'VM running')
            {
                Write-Output "`t`tVM is Deallocated - Starting VM"
                $null = $virtualMachine | Start-AzVM
            }
            else
            {
                Write-Output "`t`tVirtual machine is currently running"
            }

            # Check the VM for existing extensions
            Write-Output "`t`tChecking for Existing DSC Extension"
            $dscExtension = Get-AzVmExtension -ResourceGroupName $vmResourceGroup -VMName $vmName | Where-Object {$_.ExtensionType -like "*DSC*"}

            if ($dscExtension)
            {
                Write-OutPut "`t`tExisting DSC Extension Found"
                $dscExtensionName = $dscExtension.Name

                if ($Force)
                {
                    try
                    {
                        # Remove DSC Extension
                        Write-Output "`t`tRemoving `'$dscExtensionName`' from $vmName"
                        $null = $dscExtension | Remove-AzVMExtension -Force -Confirm:$false -ErrorAction 'Stop'

                        # Reboot VM
                        Write-Output "`t`tRestarting $vmName"
                        $null = $virtualMachine | Restart-AzVM
                    }
                    catch
                    {
                        Write-Output "`t`tRemoving `'$dscExtensionName`' failed - Remove the extension manually via the Azure Portal."
                        continue
                    }
                }
                else
                {
                    Write-OutPut "`t`tDSC Extension Name: $dscExtensionName"
                    Write-OutPut "`t`tRun the Register-AzAutomationNodes command using -Force to forcibly remove existing DSC extensions/Automation Account registration."
                    Write-Output "`t$vmName - Registration Cancelled"
                    continue
                }
            }
            else
            {
                Write-Output "`t`tNo Existing DSC Extensions Found"
            }

            # Register Azure Automation Node
            try
            {

                switch ($osType)
                {
                    'Windows'
                    {
                        Write-Output "`t`tRegistering Windows VM - $vmName"

                        $params = @{
                            AzureVMName                     = $virtualMachine.Name
                            AzureVMLocation                 = $virtualMachine.Location
                            AzureVMResourceGroup            = $virtualMachine.ResourceGroupName
                            ResourceGroupName               = $ResourceGroupName
                            AutomationAccountName           = $AutomationAccountName
                            ConfigurationMode               = $ConfigurationMode
                            ConfigurationModeFrequencyMins  = $ConfigurationModeFrequencyMins
                            RefreshFrequencyMins            = $RefreshFrequencyMins
                            RebootNodeIfNeeded              = $RebootNodeIfNeeded
                            ActionAfterReboot               = $ActionAfterReboot
                            AllowModuleOverwrite            = $AllowModuleOverwrite
                        }
                        Register-AzAutomationDscNode @params -Erroraction 'Stop'
                        Write-Output "`t`tRegistration Status - Succeeded"
                    }
                    'Linux'
                    {
                        Write-Output "`t`tRegistering Linux VM - $vmName"

                        $params = @{
                            ResourceGroupName   = $VirtualMachine.ResourceGroupName
                            VmName              = $vmName
                            ScriptPath          = $linuxRegScript
                            Commandid           = 'runshellscript'
                        }
                        $regResult = (Invoke-AzVmRunCommand @params -ErrorAction 'Stop').Status
                        Write-Output "`t`tRegistration Status - $regResult"
                    }
                }
            }
            catch
            {
                Write-Output "`t`t`tRegistration Status - Failure"
            }

            Write-Output "`t$($VirtualMachine.Name) - Registration Complete"
        }
        $null = $jobs.add($job.Id)
    }

    if ($jobs.count -ge 1)
    {
        Write-Output "`nAzure Automation Node Registration jobs created. Checking status every 30 seconds until all jobs are complete."

        do
        {
            $completedJobs = (Get-Job -ID $jobs | Where-Object {$_.state -ne "Running"}).count
            $runningjobs   = (Get-Job -ID $jobs | Where-Object {$_.state -eq "Running"}).count
            Write-Output "`tNode Registration Job Status:`t$runningJobs Jobs Currently Processing`t$completedJobs/$($jobs.count) Jobs Completed"
            Start-Sleep -Seconds 30
        }
        while ((Get-Job -ID $jobs).State -contains "Running")
        Write-Output "`n$($jobs.count) Azure Automation Node Registration jobs completed. Outputting Results.`n"
        Get-Job -ID $jobs | Wait-Job | Receive-Job
    }

    # Cleanup Linux Registration Script if present
    if (Test-Path -Path $linuxRegScript -ErrorAction SilentlyContinue)
    {
        Remove-Item -Path $linuxRegScript -Force -Confirm:$False
    }
    Write-Output "`nAzure Automation Registration Complete."
}

function Start-AzDscBuild
{
    <#
    .SYNOPSIS
    Generates PowerSTIG Configurations for system data files that are compatible with Azure Automation
 
    .PARAMETER RootPath
    Path to the Stig Compliance Automation Repository
 
    .EXAMPLE
    Export-AzDscConfigurations -RootPath "C:\StigRepo"
    #>


    [CmdletBinding()]
    param(
        [Parameter()]
        [string]
        $RootPath = (Get-Location).Path

    )

    Write-Output "Beginning Azure Automation DSC Configuration Script Creation"

    $systemFiles        = Get-Childitem "$Rootpath\Systems\*.psd1" -Recurse | Where-Object FullName -notlike "*Staging*"
    $azConfigFolderPath = "$RootPath\Artifacts\AzConfigs"

    Write-Output "`tCreating Azure Configuration Folder - $azConfigFolderPath"
    $azConfigPath   = (New-Item -Path $azConfigFolderPath -ItemType Directory -Force).FullName

    foreach ($systemFile in $systemFiles)
    {
        Write-Output "`tGenerating Azure DSC Configuration - $($systemFile.BaseName)"
        $azConfigName   = "STIG_" + $systemFile.BaseName.Replace("-","_")
        $azConfigFile   = New-Item -ItemType File -Path "$azConfigPath\$azConfigName.ps1" -Force
        $systemData     = Invoke-Expression (Get-Content $systemFile | Out-String)
        [array]$configs = $systemData.AppliedConfigurations
        $nodeName       = $systemData.NodeName
        $azConfigString = "Configuration $($azConfigName)`n{"
        $azConfigString += "`n`tImport-DscResource -ModuleName `'PowerSTIG`'`n"
        $azConfigString += "`n`tNode '$nodeName'`n`t{"

        foreach ($resource in $configs.keys)
        {
            $resourceName = $resource.Replace("PowerSTIG_","")
            $azConfigString += "`n`t`t$resourceName STIG_$resourceName`n`t`t{"
            $resourceParams = $configs.$resource.keys
            if ($null -ne $resourceParams)
            {
                foreach ($param in $resourceParams)
                {
                    $name = $param
                    $value = $configs.$resource.$param
                    $dataType = $value.gettype().name

                    switch ($dataType)
                    {
                        'HashTable' {
                            $azConfigString += "`n`t`t`t$name = @{"
                            $keys = $configs.$resource.$param.keys

                            foreach ($vulID in $keys)
                            {
                                $valueTypes = $configs.$resource.$param.$vulID.keys

                                foreach ($valuetype in $valueTypes)
                                {
                                    $valuedata = $configs.$resource.$param.$vulID | Select-Object -expandproperty $valueType
                                }
                                $azConfigString += "`n`t`t`t`t'$vulID' = @{'$valueType' = '$valuedata'}"
                            }
                            $azConfigString += "`n`t`t`t}"
                        }
                        'Object[]'
                        {
                            $arrayString = ""
                            $vulIDs      = $configs.$resource.$param
                            $i           = 0

                            foreach ($vulID in $vulIDs)
                            {
                                $i++

                                if ($i -ne $vulIDs.Count)
                                {
                                    [string]$arrayString += "'$vulID',"
                                }
                                else
                                {
                                    [string]$arrayString += "'$vulID'"
                                }
                            }
                            $arrayString = $arrayString
                            $azConfigString += "`n`t`t`t$name = @($arrayString)"
                        }
                        default
                        {
                            $value = $configs.$resource.$param
                            $azConfigString += "`n`t`t`t$name = `'$value`'"
                        }
                    }

                }
                $azConfigString += "`n`t`t}`n"
            }
            else
            {
                $azConfigString += "}`n"
            }
        }

        $azConfigString += "`t}`n}"
        Set-Content $azConfigFile.FullName -Value $azConfigString -Force
    }
    Write-Output "`tAzure Automation DSC Configuration Generation Complete"
}

function Publish-AzAutomationNodeConfigs
{
    <#
    .SYNOPSIS
    Imports files generated by Export-AzDscConfigurations to an Azure Automation Account
 
    .PARAMETER ResourceGroupName
    Name of the Autmation Account ResourceGroup
 
    .PARAMETER AutomationAccountName
    Name of the Azure Automation Account
 
    .PARAMETER RootPath
    Path to the Stig Compliance Automation Repository
 
    .EXAMPLE
    Import-DscConfigurations -Rootpath "C:\StigRepo" -ResourceGroupName "MyAutomationAccountRG" -AutomationAccountName "MyAutomationAccount"
    #>


    [CmdletBinding()]
    param(
        [Parameter()]
        [string]
        $RootPath = (Get-Location).Path,

        [Parameter(Mandatory=$true)]
        [string]
        $ResourceGroupName,

        [Parameter(Mandatory=$true)]
        [string]
        $AutomationAccountName

    )

    Write-Output "Starting Azure Automation import - $AutomationAccountName"

    # Validate Repository
    try
    {
        $null = Resolve-Path "$RootPath\Systems" -ErrorAction 'Stop'
        $null = Resolve-Path "$Rootpath\Configurations" -ErrorAction 'Stop'
        $null = Resolve-Path "$Rootpath\Artifacts" -ErrorAction 'Stop'
        $null = Resolve-Path "$Rootpath\Resources" -ErrorAction 'Stop'
        Write-Output "`tSTIG Repository Path is valid:`t`t$RootPath"
    }
    catch
    {
        Write-Output "`n$Rootpath is not a valid STIG Repository"
        Write-Output "Please provide a valid path or build a new repository using the Initialize-StigRepo function"
    }

    # Validate Azure Context
    $azContext = Get-AzContext

    if ($null -ne $azContext)
    {
        $azSubscription = $azContext.Name.Split(" ")[0]
        Write-Output "`tConnected to Azure Subscription:`t$azSubscription"
    }
    else
    {
        Write-Output "`tPowershell session is not connected to an Azure Subscription. Follow the prompt to login."
        Connect-AzAccount
    }

    # Validate Azure Automation Account
    try
    {
        $null = Get-AzAutomationAccount -ResourceGroupName $ResourceGroupName -AutomationAccountName $AutomationAccountName -ErrorAction 'Stop'
        Write-Output "`tAzure Automation Account is valid:`t$AutomationAccountName"
    }
    catch
    {
        Write-Output "`nAutomation Account is invalid or cannot be found."
        Write-Output "Verify the Automation Account Exists and that your session is connect to the correct Azure Subscription and try again."
        exit
    }

    # Get DSC Configuration Scripts
    try
    {
        $azConfigPath   = (Resolve-Path -Path "$RootPath\Artifacts\AzConfigs" -ErrorAction 'Stop').Path
        $azConfigFiles  = Get-Childitem "$azConfigPath\*.ps1"
    }
    catch
    {
        Write-Output "`tNo Azure DscConfiguration Files Present. Exporting Azure Automation Configuration Files."
        Export-AzDscConfigurations -RootPath $RootPath
        $azConfigPath   = (Resolve-Path -Path "$RootPath\Artifacts\AzConfigs" -ErrorAction 'Stop').Path
        $azConfigFiles  = Get-Childitem "$azConfigPath\*.ps1"
    }

    Write-Output "`nStarting Jobs to publish STIG configurations to Azure Automation"
    $jobs = New-Object System.Collections.ArrayList

    foreach ($azConfigFile in $azConfigFiles)
    {
        Write-Output "`tStarting Node Configuration Publish Job - $($azConfigFile.BaseName)"

        $job = Start-Job -ScriptBlock {

            $azConfigFile           = $using:azConfigFile
            $ResourceGroupName      = $using:ResourceGroupName
            $AutomationAccountName  = $using:AutomationAccountName
            $azConfigPath           = $azConfigFile.FullName
            $azConfigName           = (Get-Item $azConfigPath).BaseName

            try
            {
                $params = @{
                    Path                    = $azConfigPath
                    ConfigurationName       = $azConfigName
                    ResourceGroupName       = $ResourceGroupName
                    AutomationAccountName   = $AutomationAccountName
                    Force = $true
                }
                $null = Import-AzAutomationDscNodeConfiguration @params -ErrorAction 'Stop'
                Write-Output "`t$azConfigName - Publishing job Succeeded"
            }
            catch
            {
                Write-Output "`t$azConfigName - Publishing Job Failed"
                continue
            }
        }
        $null = $jobs.add($job.ID)
    }

    if ($jobs.count -ge 1)
    {
        Write-Output "Publish Node Configuration Jobs created. Checking status every 30 seconds until all jobs are complete."

        do
        {
            $completedJobs = (Get-Job -ID $jobs | Where-Object {$_.state -ne "Running"}).count
            $runningjobs   = (Get-Job -ID $jobs | Where-Object {$_.state -eq "Running"}).count
            Write-Output "`tPublish Node Configuration Job Status:`t$runningJobs Jobs Currently Processing`t$completedJobs/$($jobs.count) Jobs Completed"
            Start-Sleep -Seconds 30
        }
        while ((Get-Job -ID $jobs).State -contains "Running")
        Write-Output "`n$($jobs.count) Jobs Completed. Outputting Results."
        Get-Job -ID $jobs | Wait-Job | Receive-Job
    }
    else
    {
        Write-Output "`n`tNo Jobs Generated."
    }
    Write-Output "Azure Automation import complete"
}

function Set-AzAutomationNodeConfigs
{
    [CmdletBinding()]
    param(
        [Parameter()]
        [string]
        $RootPath = (Get-Location).Path,

        [Parameter(Mandatory=$true)]
        [string]
        $ResourceGroupName,

        [Parameter(Mandatory=$true)]
        [string]
        $AutomationAccountName,

        [Parameter()]
        [switch]
        $SkipValidation
    )

    if (-not $SkipValidation)
    {

        Write-Output "Validating Environment for DSC Node Configuration Assignments"
        # Validate Repository
        try
        {
            $null = Resolve-Path "$RootPath\Systems" -ErrorAction 'Stop'
            $null = Resolve-Path "$Rootpath\Configurations" -ErrorAction 'Stop'
            $null = Resolve-Path "$Rootpath\Artifacts" -ErrorAction 'Stop'
            $null = Resolve-Path "$Rootpath\Resources" -ErrorAction 'Stop'
            Write-Output "`tSTIG Repository Path is valid:`t`t$RootPath"
        }
        catch
        {
            Write-Output "`n$Rootpath is not a valid STIG Repository"
            Write-Output "Please provide a valid path or build a new repository using the Initialize-StigRepo function"
        }

        # Validate Azure Context
        $azContext = Get-AzContext

        if ($null -ne $azContext)
        {
            $azSubscription = $azContext.Name.Split(" ")[0]
            Write-Output "`tConnected to Azure Subscription:`t$azSubscription"
        }
        else
        {
            Write-Output "`tPowershell session is not connected to an Azure Subscription. Follow the prompt to login."
            Connect-AzAccount
        }

        # Validate Azure Automation Account
        try
        {
            $null = Get-AzAutomationAccount -ResourceGroupName $ResourceGroupName -AutomationAccountName $AutomationAccountName -ErrorAction 'Stop'
            Write-Output "`tAzure Automation Account is valid:`t$AutomationAccountName"
        }
        catch
        {
            Write-Output "`tAutomation Account is invalid or cannot be found."
            Write-Output "`tVerify the Automation Account Exists and that your session is connect to the correct Azure Subscription and try again."
            exit
        }
    }

    # Start Configuration Assignments
    Write-Output "`nStarting DSC Node Configuration Assignments"

    # Get DSC Nodes
    Write-Output "`tGetting Azure Automation DSC Nodes"
    $nodes = Get-AzAutomationDscNode -ResourceGroupName $ResourceGroupName -AutomationAccountName $AutomationAccountName

    if ($nodes.count -eq 0)
    {
        Write-Output "`tNo DSC Nodes Found"
        exit
    }

    # Get DSC Node Configs
    Write-Output "`tGetting Azure Automation DSC Node Configurations"
    $nodeConfigs = Get-AzAutomationDscNodeConfiguration -ResourceGroupName $ResourceGroupName -AutomationAccountName $AutomationAccountName

    if ($nodeConfigs.count -eq 0)
    {
        Write-Output "`tNo DSC Node Configurations Found"
        exit
    }

    foreach ($node in $nodes)
    {
        Write-Output "`tAssiging Node Configuration to $($node.Name)"
        $tryNodeConfig = $false
        $configName = "STIG_" + $node.Name.Replace("-","_")

        try
        {
            $nodeConfig = $nodeConfigs | Where-Object {$_.Name -like "*$configName*"}
            $null = $node | Set-AzAutomationDscNode -NodeConfigurationName $nodeConfig -Force -ErrorAction 'Stop'
        }
        catch
        {
            Write-Output "`t`tDscNodeConfiguration Assignment Failed. Trying DscConfiguration."
            $tryDscConfig = $true
        }

        if ($tryDscConfig)
        {
            try
            {
                $nodeConfig = Get-AzAutomationDscConfiguration -Name $configName -ResourceGroupName $ResourceGroupName -AutomationAccountName $AutomationAccountName -ErrorAction 'Stop'
                $null = $node | Set-AzAutomationDscNode -NodeConfigurationName $nodeConfig.Name -Force
            }
            catch
            {
                Write-Warning "$($node.Name) - Configuration Assignment Failed. Confirm that a DSC configuration has been published and try again.`n"
                continue
            }
        }
    }
    Write-Output "DSC Node Configuration Assignment Complete."
}