PowerShell script result different when ran from V

2019-07-16 09:26发布

I'm running a PowerShell build script from the PostBuild event of a Visual Studio 2013 project.
The command I'm using for that is (new-lines added only for readability):

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

One of the tasks of this script is to find local SQL Server instances to allow the user to attach required databases if they don't exist.
I'm using the following PowerShell code to retrieve the local instances:

[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) }

This is working perfectly fine when I execute the script from the command-line, but when I run the script from the PostBuild event $m.ServerInstances returns $null.

First thing that came to mind was user rights, but I checked which user is executing the script and it's the same in both command-line and VS PostBuild.

I've also tried a different approach that retrieves the available instances from the registry (as described here), with the same result; it works fine when running from command-line, but returns no instances when running from VS PostBuild.

So the question is, what's the difference between running from command-line and VS PostBuild that is causing this different behaviour?

UPDATE:
There are other parts of the script that stop functioning when running from Visual Studio.
For example creating an IIS website works fine when running the script from cmd.exe but throws an exception when ran from 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)).

I've tried all kinds of crazy workaround, like using cmd.exe /C from VS PostBuild to execute PowerShell create a new PowerShell script that calls cmd.exe to run PowerShell.
All give the same result; the script works when called from a command prompt, but not when called from a Visual Studio PostBuild event.

Visual Studio itself is running with elevated permissions.
Also tried it without elevated permissions and that results in the same issue.

UPDATE 2:
The same problem occurs when I build the solution with MSBuild from a command prompt to trigger the PostBuild event that calls the script

2条回答
Evening l夕情丶
2楼-- · 2019-07-16 09:44

It turns out that Visual Studio always executes the 32-bit PowerShell instead of the 64-bit.
Even when I specified the full path to PowerShell in the PostBuild event, it still executed the 32-bit version.

That caused a lot of the commands not to work.
I solved it by calling PowerShell with this command:

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

That executes the 64-bit PowerShell on my machine and runs the script fine.

查看更多
三岁会撩人
3楼-- · 2019-07-16 10:05

Building upon the accepted answer by Ruud van Falier, I had to use the following Prebuild event syntax so it ran on both my Dev machine AND on the Visual Studio Online Agent:

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
)

It's ugly, but it works.

查看更多
登录 后发表回答