public/Compile-AzureDSCConfig.ps1


function Compile-AzureDSCConfig {

<#
 
.SYNOPSIS
 
Compiles new Azure DSC Configs.
 
.DESCRIPTION
 
Compiles new Azure DSC Configs.
 
Config's and their associated files should be setup this way where the config name is ExampleDSC_config
 
`.\somefolder\ExampleDSC_config.ps1
`.\somefolder\ExampleDSC_configData.psd1
`.\somefolder\ExampleDSC_params.ps1
 
`.\somefolder\ExampleDSC_config.ps1
# This file should contain the DSC configuration:
 
Configuration ExampleDSC_config {
    Import-DscResource –ModuleName 'PSDesiredStateConfiguration'
    Node $AllNodes {
        Registry RegistryExample
        {
            Ensure = "Present" # You can also set Ensure to "Absent"
            Key = "HKEY_LOCAL_MACHINE\SOFTWARE\ExampleKey"
            ValueName = "TestValue"
            ValueData = "TestData"
        }
    }
}
 
`.\somefolder\ExampleDSC_configData.psd1
# This file should contain the Node configuration information
 
@{
    $AllNodes = @{
        @{
            NodeName = "Server-123"
            Role = "management"
            OS = "Windows NT"
            ExampleToPass = "Details"
        },
        @{
            NodeName = "Server-456"
            Role = "Web-Server"
            OS = "Windows NT"
            ExampleToPass = "OtherDetails"
        }
    }
}
 
`.\somefolder\ExampleDSC_params.ps1
# This file should contain a hastable of any parameters to pass into the compile process
# If no params are needed just create an empty params.ps1 file.
 
@{
    Param1 = 'Value1';
    Param2 = 'Value2'
}
 
.PARAMETER ResourceGroupName
Input the Resource Group Name of the Azure Resource Group this DSC config will be published to.
Get-AzureRmResourceGroup
 
.PARAMETER AutomationAccountName
Input the Automation Account Name of the Azure Automation account this DSC config will be published to.
Get-AzureRmAutomationAccount
 
.PARAMETER ConfigFullFilePath
Input the full file path to the main DSC config.
Ex. D:\somefolder\somebin\ExampleDSC_config.ps1
 
.EXAMPLE
 
Compile-AzureDSCConfig -ResourceGroupName DSCExampleGroup -AutomationAccountName DSCExampleAccount -ConfigFullFilePath D:\somefolder\somebin\ExampleDSC_config.ps1
 
#>


    [cmdletbinding()]

    Param (
        [Parameter(Mandatory=$true)]
        [string]$ResourceGroupName,
        
        [Parameter(Mandatory=$true)]
        [string]$AutomationAccountName,
        
        [Parameter(Mandatory=$true)]
        [ValidateScript({Test-path $_})]
        [string]$ConfigFullFilePath
    )

        # check to see if local token exists (ran Login-AzureRMAccount)
        if (($null -eq (Get-AzureRmContext).Account)) {
            Write-Warning "Please run < Login-AzureRMAccount > first to create a session token...exiting."
            break
        } 

        # Create file variables based on $configfilepath
        try {
            #get parent directory
            $ItemInfo = get-item $ConfigFullFilePath -ErrorAction Stop
            $ConfigPath = ($ItemInfo).Directory.FullName
            $ConfigName = ($ItemInfo).Name.Split(".")[0]
            $ConfigFileName = ($ItemInfo).Name
            $ConfigDataFileName = "$ConfigName" + "Data.psd1"
            $ConfigParamsFileName = $ConfigName.Split("_")[0] + "_params.ps1"
            Write-Verbose $ConfigPath
            Write-Verbose $ConfigName
            Write-Verbose $ConfigDataFileName
            Write-Verbose $ConfigParamsFileName
        }
        catch{
            Throw ("Please verify the file name and path $ConfigFullFilePath is correct. This file seems to be inaccesible. `r `n" +
                "The root folder should contain files like this: `r `n" +
                "ExampleDSC_config.ps1 `r `n" +
                "ExampleDSC_configData.psd1 `r `n" +
                "ExampleDSC_params.ps1 `r `n" +
                 $_.Exception.Message)
            break
        }

        #Setup and test vars for each portion of the config file
    
        try {
            if ((Test-Path ($ConfigPath + "\" + $ConfigDataFileName)) -eq $false){
                throw "$($ConfigPath + "\" + $ConfigDataFileName) seems to be missing."
            }
            Write-Verbose ($ConfigPath + "\" + $ConfigDataFileName)
        }
        catch{
            Throw ("Please verify the file name $ConfigDataFileName is correct. This file seems to be missing. `r `n" +
                "The folder $ConfigPath should contain these files based on your config name of $ConfigName : `r `n" +
                "$ConfigName.ps1 `r `n" +
                "$ConfigName" + "Data.psd1 `r `n" +
                 $ConfigName.Split("_")[0] + "_params.ps1 `r `n" +
                 $_.Exception.Message)
        
            break
        } 

        try {
            if ((Test-Path ($ConfigPath + '\' + $ConfigParamsFileName)) -eq $false){
                throw "$($ConfigPath + '\' + $ConfigParamsFileName) seems to be missing."
            }
            $ParamPath = ($ConfigPath + '\' + $ConfigParamsFileName)
            Write-Verbose $ParamPath
            if ((Get-Content $ParamPath).Length -ne 0){
                $ConfigParameters = . $ParamPath
            }else{
                $ConfigParameters = $null
            }
        }
        catch {
            Write-Error ("Please verify the file name $ConfigParamsFileName is correct. This file seems to be missing. `r `n" +
                "The folder $ConfigPath should contain files like this based on your config name of $ConfigName : `r `n" +
                "$ConfigName.ps1 `r `n" +
                "$ConfigName" + "Data.psd1 `r `n" +
                 $ConfigName.Split("_")[0] + "_params.ps1 `r `n" +
                 $_.Exception.Message)
            break
        }


        # build configLiteralPath
        Try {
            $ConfigLiteralPath = Get-ChildItem $ConfigPath -Include $ConfigFileName -Recurse -ErrorAction Stop -Verbose
            $ConfigLiteralPath = $ConfigLiteralPath.FullName
        }
        Catch {
            $error[0].Exception
            break
        }
        
        Try {
        
            $localconfig = Import-LocalizedData -BaseDirectory $ConfigPath -FileName $configdatafilename -ErrorAction Stop -Verbose
        }
        Catch {
            $error[0].Exception
            break
        }
    
        Try {
            Import-AzureRmAutomationDscConfiguration -SourcePath $ConfigLiteralPath -ResourceGroupName $ResourceGroupName -AutomationAccountName $AutomationAccountName -Published -Force -ErrorAction Stop -Verbose
            }
        Catch {
                $error[0].Exception
                break
        }
    
        Try {
            if ($null -eq $ConfigParameters) {
                $compile = Start-AzureRmAutomationDscCompilationJob -ConfigurationName $ConfigName -ConfigurationData $localconfig -ResourceGroupName $ResourceGroupName -AutomationAccountName $AutomationAccountName -Verbose -ErrorAction Stop
            }
            else {
                $compile = Start-AzureRmAutomationDscCompilationJob -ConfigurationName $ConfigName -ConfigurationData $localconfig -ResourceGroupName $ResourceGroupName -AutomationAccountName $AutomationAccountName -Parameters $ConfigParameters -Verbose -ErrorAction Stop
            }
            
        }
        Catch {
            $error[0].Exception
            break
        }

        
        Do {
            
            Try {
                $localcompilejob = Get-AzureRmAutomationDscCompilationJob -ResourceGroupName $ResourceGroupName -AutomationAccountName $AutomationAccountName -Id $compile.Id -ErrorAction Stop -Verbose
                Write-Verbose "Compilation job for $($compile.ConfigurationName) not complete."
                Write-Verbose "Status is $($localcompilejob.Status)"
                Start-Sleep -Seconds 5 -Verbose
            }
        
            Catch {
                $error[0].excetion
                break    
            }
        }
        
        Until (($localcompilejob.Status -eq 'Completed') -or ($localcompilejob.Status -eq 'Suspended'))
        
        if (($localcompilejob.Status -eq 'Completed')) {
            return $localcompilejob
        }
        else {
            Write-Warning "Compilation job did not complete successfully and finished with status $($localcompilejob.Status) $($localcompilejob.Exception)"
            throw $localcompilejob
        }
}