从Visual Studio运行时PowerShell脚本结果不同

时间:2014-07-03 06:32:47

标签: sql-server visual-studio powershell

我正在从Visual Studio 2013项目的PostBuild事件中运行PowerShell构建脚本 我正在使用的命令是(为了便于阅读而添加了新行):

PowerShell -ExecutionPolicy ByPass -File "$(SolutionDir)..\build\build.ps1" 
  -SolutionFolder "$(SolutionDir)." -ProjectName "$(ProjectName)" 
  -OutputFolder "..\build\output" -ConfigurationName "$(ConfigurationName)"

此脚本的任务之一是查找本地SQL Server实例,以允许用户附加所需的数据库(如果它们不存在)。 我使用以下PowerShell代码检索本地实例:

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SqlWmiManagement") | out-null
$m = New-Object ("Microsoft.SqlServer.Management.Smo.Wmi.ManagedComputer") "."

if ($m.ServerInstances -eq $null -or $m.ServerInstances.Length -eq $null -or $m.ServerInstances.Length -eq 0)
{
    throw New-Object [System.Exception] "No instances found."
}

$instances = $m.ServerInstances | % { ($_.Parent.Name + "\" + $_.Name) }

当我从命令行执行脚本时,这非常正常,但是当我从PostBuild事件$m.ServerInstances运行脚本时,返回$null

首先想到的是用户权限,但我检查了哪个用户正在执行脚本,它在命令行和VS PostBuild中都是相同的。

我还尝试了一种不同的方法,从注册表中检索可用的实例(如here所述),结果相同;它从命令行运行时工作正常,但从VS PostBuild运行时不返回任何实例。

所以问题是,从命令行和VS PostBuild运行导致这种不同行为的区别是什么?

更新
从Visual Studio运行时,脚本的其他部分将停止运行 例如,从cmd.exe运行脚本时创建IIS网站可以正常工作,但从VS PostBuild运行时会抛出异常:

Exception occurred while creating IIS site : 
  Retrieving the COM class factory for component with CLSID {688EEEE5-6A7E-422F-B2E1-6AF00DC944A6} 
  failed due to the following error : 
  80040154 Class not registered (Exception from HRESULT: 0x80040154 (REGDB_E_CLASSNOTREG)).

我尝试了各种疯狂的解决方法,比如使用VS PostBuild中的cmd.exe /C来执行PowerShell,创建一个调用cmd.exe来运行PowerShell的新PowerShell脚本。
都给出了相同的结果;从命令提示符调用时,脚本可以工作,但从Visual Studio PostBuild事件调用时则不行。

Visual Studio本身以提升的权限运行 也尝试了它没有提升权限,导致同样的问题。

更新2:
当我从命令提示符使用MSBuild构建解决方案以触发调用脚本的PostBuild事件时,会出现同样的问题

2 个答案:

答案 0 :(得分:2)

事实证明,Visual Studio总是执行32位PowerShell而不是64位 即使我在PostBuild事件中指定了PowerShell的完整路径,它仍然执行32位版本。

这导致许多命令无法工作 我通过使用以下命令调用PowerShell来解决它:

%WINDIR%\SysNative\WindowsPowerShell\v1.0\PowerShell.exe

在我的机器上执行64位PowerShell并运行该脚本。

答案 1 :(得分:0)

在Ruud van Falier接受的答案的基础上,我不得不使用以下Prebuild事件语法,因此它在我的Dev机器和Visual Studio在线代理上运行:

if exist %WINDIR%\SysNative\WindowsPowerShell\v1.0\PowerShell.exe (
   rem BuildServer
   %WINDIR%\SysNative\WindowsPowerShell\v1.0\PowerShell.exe  $(SolutionDir)scripts\build\Prebuild.ps1
) else (
   rem Dev workstation
    %WINDIR%\System32\WindowsPowerShell\v1.0\PowerShell.exe  $(SolutionDir)scripts\build\Prebuild.ps1
)

它很难看,但它有效。