private/OSDeployBuildProfileToken.ps1

#Requires -PSEdition Core

#region Tokens
# ${{ OSDeployCore }} -- resolves to the OSDeployCore data root
# ${{ 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 portable tokens in build-profile paths
 
    .DESCRIPTION
        Replaces OSDeployCore, OSDeployModulePath, OSDCloudModulePath, and OSDModulePath
        tokens with the corresponding data or module base paths. Leading legacy repository
        and OSDRepo paths are normalized to Boot-Assets. Replacement is case-insensitive.
        OSDCloud and OSD tokens remain unchanged when their module path commands are
        unavailable. Null and empty entries are returned unchanged.
 
    .PARAMETER Path
        Specifies zero or more path strings that may contain portable tokens. The parameter
        permits null and empty collections and does not accept pipeline input.
 
    .EXAMPLE
        PS> Expand-OSDeployBuildProfileToken -Path '${{ OSDeployCore }}\boot-assets\boot-winpescript'
 
        Replaces the OSDeployCore token with the configured OSDeployCore data path.
 
    .INPUTS
        None. This function does not accept pipeline input.
 
    .OUTPUTS
        System.String[]. Returns one expanded or unchanged string for each input entry.
 
    .NOTES
        Author: David Segura
        Company: Recast Software
        Version: 1.0.0
        Date: 2026-08-28
 
        Get-OSDCloudModulePath and Get-OSDModulePath are optional.
 
    .LINK
        ConvertTo-OSDeployBuildProfileToken
    #>

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

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

    $osDeployCoreBase = $script:OSDeployCorePath
    $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 ($osDeployCoreBase) {
            $resolved = $resolved -ireplace ([regex]::Escape('${{ OSDeployCore }}')), $osDeployCoreBase
        }

        if ($script:OSDeployBootAssetsPath -and $osDeployCoreBase) {
            foreach ($legacyFolderName in @('repository', 'OSDRepo')) {
                $legacyPath = Join-Path $osDeployCoreBase $legacyFolderName
                if ($resolved.StartsWith($legacyPath, [System.StringComparison]::OrdinalIgnoreCase) -and
                    ($resolved.Length -eq $legacyPath.Length -or $resolved[$legacyPath.Length] -in @('\', '/'))) {
                    $resolved = $script:OSDeployBootAssetsPath + $resolved.Substring($legacyPath.Length)
                    break
                }
            }
        }

        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
        Converts data and module base paths to build-profile tokens
 
    .DESCRIPTION
        Replaces a leading OSDeployCore data path or OSDeploy, OSDCloud, or OSD module base
        path with its portable build-profile token. Leading legacy repository and OSDRepo
        paths are normalized to Boot-Assets. Matching and replacement are case-insensitive,
        and more specific paths are checked first. Null and empty entries are returned
        unchanged.
 
        OSDCloud and OSD paths remain absolute when their module path commands are
        unavailable. A warning is written when an unresolved path appears to reference
        either unavailable module.
 
    .PARAMETER Path
        Specifies zero or more absolute path strings to tokenize. The parameter permits
        null and empty collections and does not accept pipeline input.
 
    .EXAMPLE
        PS> ConvertTo-OSDeployBuildProfileToken -Path (Join-Path $env:ProgramData 'OSDeployCore\boot-assets\boot-winpescript')
 
        Replaces the leading OSDeployCore data path with the OSDeployCore token.
 
    .INPUTS
        None. This function does not accept pipeline input.
 
    .OUTPUTS
        System.String[]. Returns one tokenized or unchanged string for each input entry.
 
    .NOTES
        Author: David Segura
        Company: Recast Software
        Version: 1.0.0
        Date: 2026-08-28
 
        Get-OSDCloudModulePath and Get-OSDModulePath are optional.
 
    .LINK
        Expand-OSDeployBuildProfileToken
    #>

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

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

    $osDeployCoreBase = $script:OSDeployCorePath
    $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

        if ($script:OSDeployBootAssetsPath -and $osDeployCoreBase) {
            foreach ($legacyFolderName in @('repository', 'OSDRepo')) {
                $legacyPath = Join-Path $osDeployCoreBase $legacyFolderName
                if ($tokenized.StartsWith($legacyPath, [System.StringComparison]::OrdinalIgnoreCase) -and
                    ($tokenized.Length -eq $legacyPath.Length -or $tokenized[$legacyPath.Length] -in @('\', '/'))) {
                    $tokenized = $script:OSDeployBootAssetsPath + $tokenized.Substring($legacyPath.Length)
                    break
                }
            }
        }

        # OSDeployCore data root
        if ($osDeployCoreBase -and
            $tokenized.StartsWith($osDeployCoreBase, [System.StringComparison]::OrdinalIgnoreCase) -and
            ($tokenized.Length -eq $osDeployCoreBase.Length -or $tokenized[$osDeployCoreBase.Length] -in @('\', '/'))) {
            $tokenized = '${{ OSDeployCore }}' + $tokenized.Substring($osDeployCoreBase.Length)
            $tokenized
            continue
        }

        # 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 "[$(Get-Date -Format s)] 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 "[$(Get-Date -Format s)] OSD module is not loaded; path '$tokenized' could not be tokenized and will be saved as an absolute path."
        }

        $tokenized
    }
}