Private/Invoke-ADTSubstOperation.ps1

#-----------------------------------------------------------------------------
#
# MARK: Invoke-ADTSubstOperation
#
#-----------------------------------------------------------------------------

function Invoke-ADTSubstOperation
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true, ParameterSetName = 'Create')]
        [Parameter(Mandatory = $true, ParameterSetName = 'Delete')]
        [ValidateScript({
                if ($_ -notmatch '^[A-Z]:$')
                {
                    $PSCmdlet.ThrowTerminatingError((New-ADTValidateScriptErrorRecord -ParameterName Drive -ProvidedValue $_ -ExceptionMessage 'The specified drive is not valid. Please specify a drive in the following format: [A:, B:, etc].'))
                }
                return ![System.String]::IsNullOrWhiteSpace($_)
            })]
        [System.String]$Drive,

        [Parameter(Mandatory = $true, ParameterSetName = 'Create')]
        [ValidateScript({
                if ($null -eq $_)
                {
                    $PSCmdlet.ThrowTerminatingError((New-ADTValidateScriptErrorRecord -ParameterName Path -ProvidedValue $_ -ExceptionMessage 'The specified input is null.'))
                }
                if (!$_.Exists)
                {
                    $PSCmdlet.ThrowTerminatingError((New-ADTValidateScriptErrorRecord -ParameterName Path -ProvidedValue $_ -ExceptionMessage 'The specified image path cannot be found.'))
                }
                if ([System.Uri]::new($_).IsUnc)
                {
                    $PSCmdlet.ThrowTerminatingError((New-ADTValidateScriptErrorRecord -ParameterName Path -ProvidedValue $_ -ExceptionMessage 'The specified image path cannot be a network share.'))
                }
                return !!$_
            })]
        [System.IO.DirectoryInfo]$Path,

        [Parameter(Mandatory = $true, ParameterSetName = 'Delete')]
        [System.Management.Automation.SwitchParameter]$Delete
    )

    # Perform the subst operation. An exit code of 0 is considered successful.
    $substPath = "$([System.Environment]::SystemDirectory)\subst.exe"
    $substResult = if ($Path)
    {
        # Throw if the specified drive letter is in use.
        if ((Get-PSDrive -PSProvider FileSystem).Name -contains $Drive.Substring(0, 1))
        {
            $PSCmdlet.ThrowTerminatingError((New-ADTValidateScriptErrorRecord -ParameterName Drive -ProvidedValue $Drive -ExceptionMessage 'The specified drive is currently in use. Please try again with an unused drive letter.'))
        }
        Write-ADTLogEntry -Message "$(($msg = "Creating substitution drive [$Drive] for [$Path]"))."
        & $substPath $Drive $Path.FullName
    }
    elseif ($Delete)
    {
        Write-ADTLogEntry -Message "$(($msg = "Deleting substitution drive [$Drive]"))."
        & $substPath $Drive /D
    }
    else
    {
        # If we're here, the caller probably did something silly like -Delete:$false.
        $naerParams = @{
            Exception = [System.InvalidOperationException]::new("Unable to determine the required mode of operation.")
            Category = [System.Management.Automation.ErrorCategory]::InvalidOperation
            ErrorId = 'SubstModeIndeterminate'
            TargetObject = $PSBoundParameters
            RecommendedAction = "Please review the result in this error's TargetObject property and try again."
        }
        $PSCmdlet.ThrowTerminatingError((New-ADTErrorRecord @naerParams))
    }
    if ($Global:LASTEXITCODE.Equals(0))
    {
        return
    }

    # If we're here, we had a bad exit code.
    Write-ADTLogEntry -Message ($msg = "$msg failed with exit code [$Global:LASTEXITCODE]: $substResult") -Severity 3
    $naerParams = @{
        Exception = [System.ApplicationException]::new($msg)
        Category = [System.Management.Automation.ErrorCategory]::InvalidResult
        ErrorId = 'SubstUtilityFailure'
        TargetObject = $substResult
        RecommendedAction = "Please review the result in this error's TargetObject property and try again."
    }
    $PSCmdlet.ThrowTerminatingError((New-ADTErrorRecord @naerParams))
}