Sampler.DscPipeline.psm1

#Region '.\Public\Get-DatumNodesRecursive.ps1' -1

using module datum

function Get-DatumNodesRecursive
{
    [CmdletBinding()]
    param
    (
        [Parameter()]
        [object]
        $AllDatumNodes = (Get-Variable -Name Datum -ValueOnly).AllNodes
    )

    $datumContainers = [System.Collections.Queue]::new()

    Write-Verbose -Message "Inspecting [$($AllDatumNodes.PSObject.Properties.Where({$_.MemberType -eq 'ScriptProperty'}).Name -join ', ')]"
    $AllDatumNodes.PSObject.Properties.Where({ $_.MemberType -eq 'ScriptProperty' }).ForEach({
            Write-Verbose -Message "Working on '$($_.Name)'."
            $val = $_.Value | Add-Member -MemberType NoteProperty -Name Name -Value $_.Name -PassThru -ErrorAction Ignore -Force
            if ($val -is [FileProvider])
            {
                Write-Verbose -Message "Adding '$($val.Name)' to the queue."
                $datumContainers.Enqueue($val)
            }
            else
            {
                Write-Verbose -Message "Adding Node '$($_.Name)'."
                $val['Name'] = $_.Name
                $val
            }
        })

    while ($datumContainers.Count -gt 0)
    {
        $currentContainer = $datumContainers.Dequeue()
        Write-Debug -Message "Working on Container '$($currentContainer.Name)'."

        $currentContainer.PSObject.Properties.Where({ $_.MemberType -eq 'ScriptProperty' }).ForEach({
                $val = $currentContainer.($_.Name)
                $val | Add-Member -MemberType NoteProperty -Name Name -Value $_.Name -ErrorAction Ignore
                if ($val -is [FileProvider])
                {
                    Write-Verbose -Message "Found Container '$($_.Name).'"
                    $datumContainers.Enqueue($val)
                }
                else
                {
                    Write-Verbose -Message "Found Node '$($_.Name)'."
                    $val['Name'] = $_.Name
                    $val
                }
            })
    }
}
#EndRegion '.\Public\Get-DatumNodesRecursive.ps1' 54
#Region '.\Public\Get-DscErrorMessage.ps1' -1

function Get-DscErrorMessage
{
    param
    (
        [Parameter()]
        [System.Exception]
        $Exception
    )

    switch ($Exception)
    {
        { $_ -is [System.Management.Automation.ItemNotFoundException] }
        {
            #can be ignored, very likely caused by Get-Item within the PSDesiredStateConfiguration module
            break
        }

        { $_.Message -match "Unable to find repository 'PSGallery" }
        {
            'Error in Package Management'
            break
        }

        { $_.Message -match 'A second CIM class definition' }
        {
            # This happens when several versions of same module are available.
            # Mainly a problem when when $Env:PSModulePath is polluted or
            # DscResources or DSC_Configuration are not clean
            'Multiple version of the same module exist'
            break
        }

        { $_ -is [System.Management.Automation.ParentContainsErrorRecordException] }
        {
            "Compilation Error: $_.Message"
            break
        }

        { $_.Message -match ([regex]::Escape("Cannot find path 'HKLM:\SOFTWARE\Microsoft\Powershell\3\DSC'")) }
        {
            if ($_.InvocationInfo.PositionMessage -match 'PSDscAllowDomainUser')
            {
                # This tend to be repeated for all nodes even if only 1 is affected
                'Domain user credentials are used and PSDscAllowDomainUser is not set'
                break
            }
            elseif ($_.InvocationInfo.PositionMessage -match 'PSDscAllowPlainTextPassword')
            {
                "It is not recommended to use plain text password. Use PSDscAllowPlainTextPassword = `$false"
                break
            }
            else
            {
                #can be ignored
                break
            }
        }
    }
}
#EndRegion '.\Public\Get-DscErrorMessage.ps1' 60
#Region '.\Public\Get-DscMofEnvironment.ps1' -1

function Get-DscMofEnvironment
{
    param
    (
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [string]
        $Path
    )

    process
    {
        if (-not (Test-Path -Path $Path))
        {
            Write-Error -Message "The MOF file '$Path' cannot be found."
            return
        }

        $content = Get-Content -Path $Path

        $xRegistryDscEnvironment = $content | Select-String -Pattern '\[xRegistry\]DscEnvironment' -Context 0, 10
        if (-not $xRegistryDscEnvironment)
        {
            Write-Error -Message "No environment information found in MOF file '$Path'. The environment information must be added using the 'xRegistryx' named 'DscEnvironment'."
            return
        }

        $valueData = $xRegistryDscEnvironment.Context.PostContext | Select-String -Pattern 'ValueData' -Context 0, 1
        if (-not $valueData)
        {
            Write-Error -Message "Found the resource 'xRegistry' named 'DscEnvironment' in '$Path' but no ValueData in the expected range (10 lines after defining '[xRegistry]DscEnvironment'."
            return
        }

        $valueData.Context.PostContext[0].Trim().Replace('"', '')
    }
}
#EndRegion '.\Public\Get-DscMofEnvironment.ps1' 37
#Region '.\Public\Get-DscMofVersion.ps1' -1

function Get-DscMofVersion
{
    [CmdletBinding()]
    [OutputType([string])]
    param
    (
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [string]
        $Path
    )

    process
    {
        if (-not (Test-Path -Path $Path))
        {
            Write-Error -Message  "The MOF file '$Path' cannot be found."
            return
        }

        $content = Get-Content -Path $Path

        $xRegistryDscVersion = $content | Select-String -Pattern '\[xRegistry\]DscVersion' -Context 0, 10

        if (-not $xRegistryDscVersion)
        {
            Write-Error -Message "No version information found in MOF file '$Path'. The version information must be added using the 'xRegistry' named 'DscVersion'."
            return
        }

        $valueData = $xRegistryDscVersion.Context.PostContext | Select-String -Pattern 'ValueData' -Context 0, 1
        if (-not $valueData)
        {
            Write-Error -Message "Found the resource 'xRegistry' named 'DscVersion' in '$Path' but no ValueData in the expected range (10 lines after defining '[xRegistry]DscVersion'."
            return
        }

        try
        {
            $value = $valueData.Context.PostContext[0].Trim().Replace('"', '')
            [String]$value
        }
        catch
        {
            Write-Error -Message  "ValueData could not be converted into 'System.Version'. The value taken from the MOF file was '$value'"
            return
        }
    }
}
#EndRegion '.\Public\Get-DscMofVersion.ps1' 49
#Region '.\Public\Get-FilteredConfigurationData.ps1' -1

function Get-FilteredConfigurationData
{
    [CmdletBinding()]
    [OutputType([hashtable])]
    param
    (
        [Parameter()]
        [ScriptBlock]
        $Filter = {},

        [Parameter()]
        [int]
        $CurrentJobNumber = 1,

        [Parameter()]
        [int]
        $TotalJobCount = 1,

        [Parameter()]
        [Object]
        $Datum = $(Get-Variable -Name Datum -ValueOnly -ErrorAction Stop)
    )

    if ($null -eq $Filter)
    {
        $Filter = {}
    }

    try
    {
        $allDatumNodes = [System.Collections.Hashtable[]]@(Get-DatumNodesRecursive -AllDatumNodes $Datum.AllNodes -ErrorAction Stop)
    }
    catch
    {
        Write-Error -Message "Could not get datum nodes. Pretty likely there is a syntax error in one of the node's yaml definitions." -Exception $_.Exception
    }
    $totalNodeCount = $allDatumNodes.Count

    Write-Verbose -Message "Node count: $($allDatumNodes.Count)"

    if ($Filter.ToString() -ne {}.ToString())
    {
        Write-Verbose -Message "Filter: $($Filter.ToString())"
        $allDatumNodes = [System.Collections.Hashtable[]]$allDatumNodes.Where($Filter)
        Write-Verbose -Message "Node count after applying filter: $($allDatumNodes.Count)"
    }

    if (-not $allDatumNodes.Count)
    {
        Write-Error -Message "No node data found. There are in total $totalNodeCount nodes defined, but no node was selected. You may want to verify the filter: '$Filter'."
    }

    $CurrentJobNumber--
    if ($TotalJobCount -gt 1)
    {
        try
        {
            $allDatumNodes = Split-Array -List $allDatumNodes -ChunkCount $TotalJobCount -ErrorAction Stop
        }
        catch
        {
            Write-Error -Exception $_.Exception -Message "Error calling 'Split-Array': $($_.Exception.Message). Please make sure the 'TotalJobCount' is not greater than the number of nodes." -ErrorAction Stop
        }
        $allDatumNodes = @($allDatumNodes[$CurrentJobNumber].ToArray())
    }

    return @{
        AllNodes = $allDatumNodes
        Datum    = $Datum
    }
}
#EndRegion '.\Public\Get-FilteredConfigurationData.ps1' 72
#Region '.\Public\Split-Array.ps1' -1

function Split-Array
{
    param (
        [Parameter(Mandatory = $true)]
        [System.Collections.IEnumerable]
        $List,

        [Parameter(Mandatory = $true, ParameterSetName = 'MaxChunkSize')]
        [Alias('ChunkSize')]
        [int]
        $MaxChunkSize,

        [Parameter(Mandatory = $true, ParameterSetName = 'ChunkCount')]
        [ValidateRange(2, [long]::MaxValue)]
        [int]
        $ChunkCount,

        [Parameter()]
        [switch]
        $AllowEmptyChunks
    )

    if (-not $AllowEmptyChunks -and ($list.Count -lt $ChunkCount))
    {
        Write-Error "List count ($($List.Count)) is smaller than ChunkCount ($ChunkCount)."
        return
    }

    if ($PSCmdlet.ParameterSetName -eq 'MaxChunkSize')
    {
        $ChunkCount = [Math]::Ceiling($List.Count / $MaxChunkSize)
    }
    $containers = foreach ($i in 1..$ChunkCount)
    {
        New-Object System.Collections.Generic.List[object]
    }

    $iContainer = 0
    foreach ($item in $List)
    {
        $containers[$iContainer].Add($item)
        $iContainer++
        if ($iContainer -ge $ChunkCount)
        {
            $iContainer = 0
        }
    }

    $containers
}
#EndRegion '.\Public\Split-Array.ps1' 51
#Region '.\suffix.ps1' -1

# Inspired from https://github.com/nightroman/Invoke-Build/blob/64f3434e1daa806814852049771f4b7d3ec4d3a3/Tasks/Import/README.md#example-2-import-from-a-module-with-tasks
Get-ChildItem -Path (Join-Path -Path $PSScriptRoot -ChildPath 'tasks\*') -Include '*.build.*' |
    ForEach-Object -Process {
        $ModuleName = ([System.IO.FileInfo] $MyInvocation.MyCommand.Name).BaseName
        $taskFileAliasName = "$($_.BaseName).$ModuleName.ib.tasks"

        Set-Alias -Name $taskFileAliasName -Value $_.FullName

        Export-ModuleMember -Alias $taskFileAliasName
    }
#EndRegion '.\suffix.ps1' 11