private/BootMedia/Resolve-OSDeployBuildProfileTokens.ps1

#Requires -PSEdition Core

#region Tokens
# ${{ OSDeployModulePath }} -- resolves to Get-OSDeployModulePath (OSDeploy module base)
# ${{ OSDCloudModulePath }} -- resolves to Get-OSDCloudModulePath (OSDCloud module base)
# ${{ OSDModulePath }} -- resolves to Get-OSDModulePath (OSD module base)
#endregion

function Expand-OSDeployBuildProfileToken {
    <#
    .SYNOPSIS
        Expands ${{ ... }} tokens in build-profile path strings to absolute filesystem paths.
 
    .DESCRIPTION
        Accepts one or more path strings (or nulls) that may contain the tokens
        ${{ OSDeployModulePath }} or ${{ OSDCloudModulePath }}, and returns the
        same list with each token replaced by the corresponding module base path.
 
        - ${{ OSDeployModulePath }} resolves via Get-OSDeployModulePath.
        - ${{ OSDCloudModulePath }} resolves via Get-OSDCloudModulePath when OSDCloud
          is loaded; paths that still contain the unexpanded token are passed through
          unchanged so that a later Test-Path will surface the missing module.
        - ${{ OSDModulePath }} resolves via Get-OSDModulePath when OSD is loaded;
          paths that still contain the unexpanded token are passed through unchanged.
 
        Null or empty entries are passed through unchanged.
 
    .PARAMETER Path
        One or more path strings, possibly containing tokens. May include null entries.
 
    .OUTPUTS
        System.String[] Same count as input.
    #>

    [CmdletBinding()]
    [OutputType([System.String[]])]
    param (
        [AllowNull()]
        [AllowEmptyCollection()]
        [System.String[]]$Path
    )

    if (-not $Path) { return $Path }

    $osDeployBase = Get-OSDeployModulePath

    $osdCloudBase = $null
    if (Get-Command -Name 'Get-OSDCloudModulePath' -ErrorAction SilentlyContinue) {
        $osdCloudBase = Get-OSDCloudModulePath
    }

    $osdBase = $null
    if (Get-Command -Name 'Get-OSDModulePath' -ErrorAction SilentlyContinue) {
        $osdBase = Get-OSDModulePath
    }

    foreach ($entry in $Path) {
        if (-not $entry) {
            $entry
            continue
        }

        $resolved = $entry

        if ($osDeployBase) {
            $resolved = $resolved -ireplace ([regex]::Escape('${{ OSDeployModulePath }}')), $osDeployBase
        }

        if ($osdCloudBase) {
            $resolved = $resolved -ireplace ([regex]::Escape('${{ OSDCloudModulePath }}')), $osdCloudBase
        }

        if ($osdBase) {
            $resolved = $resolved -ireplace ([regex]::Escape('${{ OSDModulePath }}')), $osdBase
        }

        $resolved
    }
}

function ConvertTo-OSDeployBuildProfileToken {
    <#
    .SYNOPSIS
        Replaces module base paths in build-profile path strings with ${{ ... }} tokens.
 
    .DESCRIPTION
        Accepts one or more path strings (or nulls) and returns the same list with
        any leading segment matching a known module base replaced by the corresponding
        token:
 
        - OSDeploy module base -> ${{ OSDeployModulePath }}
        - OSDCloud module base -> ${{ OSDCloudModulePath }}
        - OSD module base -> ${{ OSDModulePath }}
 
        Replacement is case-insensitive so that path-casing differences on Windows do
        not prevent tokenization.
 
        If a path falls under the OSDCloud module directory but Get-OSDCloudModulePath
        is unavailable (OSDCloud not loaded), a warning is emitted and the path is
        stored as-is.
 
        If a path falls under the OSD module directory but Get-OSDModulePath is
        unavailable (OSD not loaded), a warning is emitted and the path is stored as-is.
 
        Null or empty entries are passed through unchanged.
 
    .PARAMETER Path
        One or more path strings to tokenize. May include null entries.
 
    .OUTPUTS
        System.String[] Same count as input.
    #>

    [CmdletBinding()]
    [OutputType([System.String[]])]
    param (
        [AllowNull()]
        [AllowEmptyCollection()]
        [System.String[]]$Path
    )

    if (-not $Path) { return $Path }

    $osDeployBase = Get-OSDeployModulePath

    $osdCloudBase = $null
    $osdCloudAvailable = $false
    if (Get-Command -Name 'Get-OSDCloudModulePath' -ErrorAction SilentlyContinue) {
        $osdCloudBase = Get-OSDCloudModulePath
        $osdCloudAvailable = $true
    }

    $osdBase = $null
    $osdAvailable = $false
    if (Get-Command -Name 'Get-OSDModulePath' -ErrorAction SilentlyContinue) {
        $osdBase = Get-OSDModulePath
        $osdAvailable = $true
    }

    foreach ($entry in $Path) {
        if (-not $entry) {
            $entry
            continue
        }

        $tokenized = $entry

        # OSDeploy base first (more specific wins if both start match)
        if ($osDeployBase -and $tokenized -imatch ('^' + [regex]::Escape($osDeployBase))) {
            $tokenized = $tokenized -ireplace ('^' + [regex]::Escape($osDeployBase)), '${{ OSDeployModulePath }}'
            $tokenized
            continue
        }

        # OSDCloud base
        if ($osdCloudBase -and $tokenized -imatch ('^' + [regex]::Escape($osdCloudBase))) {
            $tokenized = $tokenized -ireplace ('^' + [regex]::Escape($osdCloudBase)), '${{ OSDCloudModulePath }}'
            $tokenized
            continue
        }

        # OSD base
        if ($osdBase -and $tokenized -imatch ('^' + [regex]::Escape($osdBase))) {
            $tokenized = $tokenized -ireplace ('^' + [regex]::Escape($osdBase)), '${{ OSDModulePath }}'
            $tokenized
            continue
        }

        # Warn if the path looks like it is under OSDCloud but OSDCloud was not available
        if (-not $osdCloudAvailable -and $tokenized -imatch 'OSDCloud') {
            Write-Warning "OSDCloud module is not loaded; path '$tokenized' could not be tokenized and will be saved as an absolute path."
        }

        # Warn if the path looks like it is under OSD but OSD was not available
        if (-not $osdAvailable -and $tokenized -imatch '\\OSD\\') {
            Write-Warning "OSD module is not loaded; path '$tokenized' could not be tokenized and will be saved as an absolute path."
        }

        $tokenized
    }
}