无法找到" Microsoft.SqlServer.BatchParser.dll"通过MSBuild执行Powershell脚本时

时间:2018-01-30 00:46:56

标签: c# sql-server powershell msbuild

我们有一个MSBuild进程,当前执行一组脚本,其中一个是Powershell脚本,它使用了powershell中的一些SMO工具。如果我将MSBuild打印的行复制并粘贴到命令提示符中,它可以正常工作,但无论何时运行MSBuild都无法找到程序集。

我有打印的环境变量,它们是相同的,所以我假设它是.targets中的属性但是对于我的生活我无法找到一种方法来打印变量&& #39;扫描或知道它的位置。

Could not load file or assembly 'Microsoft.SqlServer.BatchParser, Version=11.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91' or one of its dependencies. The system cannot find the file specified.]

任何想法或解决方案都有帮助,我很难过?

4 个答案:

答案 0 :(得分:5)

我在版本14中遇到了完全相同的问题。我已经编辑了这个答案,因为我发现了我的问题的本质:msbuild正在产生32位PowerShell,就像我从&#34运行PowerShell一样;运行& #34;或快捷方式是64位。

这是手动复制的问题:

PS C:\Windows\SysWOW64\WindowsPowerShell\v1.0> [Environment]::Is64BitProcess
False
PS C:\Windows\SysWOW64\WindowsPowerShell\v1.0> Invoke-Sqlcmd
Invoke-Sqlcmd : Could not load file or assembly 'Microsoft.SqlServer.BatchParser, Version=14.100.0.0, Culture=neutral,
PublicKeyToken=89845dcd8080cc91' or one of its dependencies. The system cannot find the file specified.
At line:1 char:1
+ Invoke-Sqlcmd
+ ~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Invoke-Sqlcmd], FileNotFoundException
    + FullyQualifiedErrorId : System.IO.FileNotFoundException,Microsoft.SqlServer.Management.PowerShell.GetScriptCommand
PS C:\Windows\SysWOW64\WindowsPowerShell\v1.0>

当我运行64位版本时, Invoke-Sqlcmd 正常工作:

PS C:\Windows\System32\WindowsPowerShell\v1.0> [Environment]::Is64BitProcess
True
PS C:\Windows\System32\WindowsPowerShell\v1.0> Invoke-Sqlcmd
PS C:\Windows\System32\WindowsPowerShell\v1.0>

如上所述,调用Invoke-Sqlcmd正在工作(不会导致异常)。 在这个阶段,我不知道为什么Sqlcmd缺少一些32位组件。

这就是我调用我的msbuild项目的方式:

msbuild -version 2>NUL || CALL "C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\Tools\VsDevCmd.bat"
CALL msbuild build-MYPROJECT.proj /Target:Build

我在msbuild项目中的一个目标是通过 Exec 标记调用powershell.exe:

    <Exec ContinueOnError="False" Command="$(PowerShellExe) .\Scripts\upgrade-projects.ps1 $(SqlServer) '$(TempPath)\$(TemplateProjDb)_$(AssemblyVersion).sql' $(AssemblyVersion)" />

$(PowerShellExe)的定义如下:

    <PowerShellExe>powershell.exe -NonInteractive -ExecutionPolicy Bypass</PowerShellExe>

我假设msbuild会产生默认的64位PowerShell。但它没有(出于某种原因)。

整个混乱;整个星期六花费了我的成本;)是msbuild项目,脚本在我的Windows 10笔记本电脑和我使用的其中一台VM机器上运行得非常好。当我试图在不同的开发机器(也是Windows 10,VS2017,相同的扩展包,所有更新等等)上运行时,我确实提出了上述问题。

所以我尝试将PowerShellExe更改为

 <PowerShellExe>C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -NonInteractive -ExecutionPolicy Bypass .\Scripts\concat-scripts.ps1 </PowerShellExe>

但它仍然执行32位版本。

现在我必须找到msbuild在其他机器上产生32位PowerShell的原因,而在我的笔记本电脑和vm上它是默认的64位。

或者只是...... 如何强制32位msbuild产生64位PowerShell?

此时我已尝试运行64位msbuild(我不喜欢完整路径):

C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\MSBuild\15.0\Bin\amd64\msbuild.exe" build-MYPROJECT.proj

它正在产生64位PowerShell。

如果

那将是我的解决方案
VsDevCmd.bat -arch=amd64 -host_arch=amd64

会自动指向msbuild 64bit ...不知怎的,它没有。

问题仍然是为什么在一台机器32bit msbuild产生64位PowerShell而在另一台机器上没有(甚至我提供64位的完整路径)?

答案 1 :(得分:2)

事实证明,微软在两个目录中都意外地包含了32位软件包。

请参阅Microsoft的Charles Gagnon的以下主题,声称这将在更新中尽快修复: https://social.technet.microsoft.com/Forums/office/en-US/7a71121c-83b1-49b4-ad30-3a5f20e7afbf/smo-2017-microsoftsqlserverbatchparserdll-load-error?forum=sqlsmoanddmo

虽然还没有看到修复。这似乎是环保的。这对我的所有环境都没有影响。

答案 2 :(得分:0)

仅供参考:我遇到了同样的问题,但无法通过以下建议步骤进行修复:

  • 重新安装C ++可再发行文件
  • 根据特定架构(x84,x64,默认的AnyCPU)编译

就我而言,我有一台新PC(W7-> W10)和新VS(2017-> 2019),更新了SSMS,同时数据库服务器也进行了更新(2016-> 2019)。因此,我没有尝试摆脱依赖关系的方法,而是手动添加了依赖关系,并放置了以下二进制文件:

  • microsoft.sqlserver.batchparser.dll
  • Microsoft.SqlServer.BatchParserClient.dll

我通过反复尝试迅速找到了正确的文件(在Program Files文件夹中找到的已安装dll中),并且该应用现在可以正常工作。如果它是生产应用程序,那么下一步将是根据工作的dll来源添加适当的引用。

答案 3 :(得分:0)

当尝试从Visual Studio生成后事件在PowerShell脚本内执行Invoke-Sqlcmd时,我们遇到了相同的问题。在脚本中从x86切换到x64解决了问题:

if ($env:PROCESSOR_ARCHITEW6432 -eq "AMD64") {
    Write-Warning "Switching from 32bit to 64bit PowerShell"
    $powershell = Join-Path $PSHOME.ToLower().Replace("syswow64","sysnative").Replace("system32","sysnative") powershell.exe
    if ($myInvocation.Line) {
        &"$powershell" -NonInteractive -NoProfile -ExecutionPolicy Bypass $myInvocation.Line
    } else {
        &"$powershell" -NonInteractive -NoProfile -ExecutionPolicy Bypass -file "$($myInvocation.InvocationName)" $args
    }

    exit $lastexitcode
}

积分转到此blogpost