microsoft / azure-pipelines-extensions

Collection of all RM and deployment extensions
http://www.visualstudio.com/explore/release-management-vs
MIT License
275 stars 425 forks source link

Execution fails with "Illegal characters in path" for the package SqlPackageOnTargetMachines.ps1 #1204

Open alovera opened 7 months ago

alovera commented 7 months ago

We've been running the Invoke-DacpacDeployment command successfully for our SQL deployment scenarios in PowerShell 5.x for a while. However, when switching over to using the latest PowerShell 7.3.x version it would fail to execute by throwing an error "Illegal characters in path". Upon investigation, we determined that the error was coming from the ExecuteCommand function in the same PowerShell model where the invoke command was defined (SqlPackageOnTargetMachines.ps1). In that method there is an "if" statement that switches execution based upon the version of PowerShell currently being executed. The else section fails for PowerShell 7.3.x because of a breaking issue with how PowerShell parses arguments (see here). After following the bread crumbs and landing upon this StackOverflow article, we found out that setting the $PSNativeCommandArgumentPassing global variable to 'Legacy' seems to resolve the issue. However, we had to make the change directly to the method in the SqlPackageOnTargetMachines.ps1 - the global variable setting doesn't seem to flow down from our external script.

Here is the change we made in brief:

function ExecuteCommand
{
    param(
        [String][Parameter(Mandatory=$true)] $FileName,
        [String][Parameter(Mandatory=$true)] $Arguments
    )

    if( $psversiontable.PSVersion.Major -lt 4)
    {
        $ErrorActionPreference = 'Continue'
        $command = "`"$FileName`" $Arguments"
        $result = cmd.exe /c "`"$command`""
    }
    else
    {
        $ErrorActionPreference = 'SilentlyContinue'

        # Added the two lines below to change the setting
        $defaultArgPassing = $PSNativeCommandArgumentPassing
        $PSNativeCommandArgumentPassing = 'Legacy'

        $result = ""
        Invoke-Expression "& '$FileName' --% $Arguments"  -ErrorVariable errors | ForEach-Object {
            $result +=  ("$_ " + [Environment]::NewLine)
        }

        foreach($errorMsg in $errors){
            $result +=  "$errorMsg "
        }

        # Added the line below to return the setting to the previous value
        $PSNativeCommandArgumentPassing = $defaultArgPassing
    }

    $ErrorActionPreference = 'Stop'
    if($LASTEXITCODE -ne 0)
    {
         Write-Verbose "Deployment failed with error : $result"
         throw  $result
    }

    return $result
}

Is this something you think should be modified in this library or do you have any reservations about the change impacting other commands?