执行命令不会导致脚本异常

Executing command doesn't result in script exception

我们有一个部署数据库脚本的 powershell 脚本。但是,如果数据库脚本失败,输出不会向 powershell 脚本抛出异常。

下面是 .ps1 文件的示例:

function Publish-DatabaseProject 
{
    sqlcmd -S . -b -v DatabaseName=Integration -q "alter table xx add test Varchar(10)"
}

function Add-Timestamp {
    process {
        if ($_.GetType() -eq [string]) {
            "[$(Get-Date -Format o)] $_"
        } else {
            $_
        }
    }
}

function Write-LogFile {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)] [string] $Path,
        [Parameter(Mandatory=$true, ValueFromPipeline=$true)] [object[]] $InputObject
    )

    begin {
        $root = Split-Path -Path $Path -Parent
        if ($root -and !(Test-Path -Path $root)) { New-Item -Path $root -Type Directory 
                              | Out-Null }
    }

    process {
        $InputObject |
            Add-Timestamp |
            Tee-Object -File $Path -Append
    }
}

Publish-DatabaseProject -ErrorVariable DeployError 2>&1 |
    Write-LogFile -Path "C:\output.log"

if ($DeployError -and $DeployError.Count -ne 0) 
{
    Write-Output "Failed"
} else 
{
    Write-Output "Succeeded"
}

有问题的查询正在针对不存在的 table 执行。文本输出显示:

[2015-12-11T14:42:45.1973944+00:00] Msg 4902, Level 16, State 1, Server ABDN-DEV-PC1, Line 1

[2015-12-11T14:42:45.2053944+00:00] Cannot find the object "xx" because it does not exist or you do not have permission s.

Succeeded

我希望最后一行显示为:失败。

如果您单独 运行 sqlcmd 行,然后使用 $LastExitCode 跟进它,它会吐出一个非零退出代码。

> sqlcmd -S . -b -v DatabaseName=Integration -q "alter table xx add test Varchar(10)"
Msg 4902, Level 16, State 1, Server ABDN-DEV-PC1, Line 1
Cannot find the object "xx" because it does not exist or you do not have permissions.
> $LastExitCode
1

由于种种原因,我们无法使用Invoke-SqlCmd,需要坚持使用SQLCMD.exe。

我们如何才能使 SQLCMD 中的异常正确地冒出到调用脚本?

您的 -ErrorVariable DeployError 语句只有在 Publish-DatabaseProject cmdlet 本身无法执行时才会被触发。由于该函数主要是 sqlcmd.exe 的包装器,因此没有任何智能可以引发此错误。我们可以使用 $LastExitCode 自动变量包装它。

function Publish-DatabaseProject 
{
    sqlcmd -S . -b -v DatabaseName=Integration -q "alter table xx add test Varchar(10)"
    if ($LastExitCode -ne 0)
       {
    Write-error $LastExitCode

    throw $LastExitCode
      }
}

现在,PowerShell 将从 .exe 中捕获此错误,您可以使用 -ErrorVariable.

更新

所以,既然你想保留 运行 而不是在遇到错误时弃船,我们需要用 try{}catch{} 块包装你的 Publish-DataBaseProject 函数,以捕获错误我们正在生成,不会停止执行。

try {Publish-DatabaseProject -ErrorAction STOP -ErrorVariable DeployError 2>&1 |
    Write-LogFile -Path "C:\output.log" }


 catch{
      Write-Output "Current job $($_), failed"
      Write-Output "Exception $($Error.ExceptionID)"
      }

现在我们正确地从 CMD 生成异常,通过我们的函数将其冒泡,并像处理普通函数一样处理它,所有这些都使用 Native PowerShell。我相信这就是您想要做的。如果没有,post 整个脚本的要点,我会以更有针对性的方式帮助您。