I'm trying to get Powershell to run my PS script in post built - but somehow it doesn't work like it's supposed to:
Following command in Post-Build:
C:\WINDOWS\system32\windowspowershell\1.0\powershell.exe
-Command "& $(MSBuildProjectDirectory)\CreateSite.ps1 'auto'"
(inserted line break for better reading)
The command executes the powershell script sucessfully, but what it can't do is run the commands within (Output from Build): Rund Post-Build Command:
Add-PSSnapin : No snap-ins have been registered for Windows PowerShell version 2
At C:\path\CreateSite.ps1:4 char:
38
+ Add-PsSnapin <<<< Microsoft.SharePoint.PowerShell}
+ CategoryInfo : InvalidArgument: (Microsoft.SharePoint.PowerShell:String) [Add-PSSnapin], PSArgumentException
+ FullyQualifiedErrorId : AddPSSnapInRead,Microsoft.PowerShell.Commands.AddPSSnapinCommand开发者_如何学Python
And following that are many errors because all subsequent commands need the Sharepoint Snap-In.
- When running powershell C:\path\CreateSite.ps1 auto from cmd - everything works.
- When opening powershell.exe and running C:\path\CreateSite.ps1 auto - everything works.
- When right clicking CreateSite.ps1 --> run with powershell - everything works.
The relevant line in the script is simply Add-PsSnapin Microsoft.SharePoint.PowerShell
.
How can I just run the darn script (and get it to include the PSSnapIn) passing it a parameter in Visual Studio post-build?
(This thread is not new, but I got here from Google, so I thought sharing the solution I found would be interesting to others)
I tried changing the path to powershell.exe to "%WINDIR%\SysNative\WindowsPowerShell\v1.0\powershell.exe" and it worked perfect. The 64 bits version is called from the Post Build event and it successfully adds the SharePoint snapin.
Credits to this article: http://msdn.microsoft.com/en-us/library/ff798298.aspx, "Using Windows PowerShell Scripts to Automate Tasks in Visual Studio".
Because of file system virtualization, you can't really specify the path to the 64-bit version of PowerShell from a 32-bit process (ie Visual Studio - which hosts the msbuild engine). One hack-ish way to work around this is to create a 64-bit launcher that runs as 64-bit and will launch the 64-bit version of PowerShell. Here's a simple C# program that will do this:
using System;
using System.Diagnostics;
class App
{
static int Main(string[] args)
{
Process process = Process.Start("PowerShell.exe", String.Join(" ", args));
process.WaitForExit();
return process.ExitCode;
}
}
Be sure to compile this as 64-bit like so:
csc .\PowerShell64.cs /platform:x64
Then, from your post-build event execute this launcher exe passing it the parameters you want to invoke 64-bit PowerShell with. Also, with PowerShell 2.0 I would recommend using the File
parameter to execute a script e.g.:
c:\path\PowerShell64.exe -File "$(MSBuildProjectDirectory)\CreateSite.ps1" auto
That said, surely there has to be some other way (utility) that launches exes from a 64-bit process.
When you run you script directly, you probably use 32bit PowerShell and in your msbuild script 64bit or vice versa. Also have a look at Error msg: “No snap-ins have been registered for Windows PowerShell version 2.”.
A slightly better variant of the output redirection:
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
namespace ConsoleApplication1
{
class App
{
static int Main(string[] args)
{
Console.WriteLine("sh64 args: " + string.Join(", ", args));
var start = new ProcessStartInfo
{
FileName = args.First(),
Arguments = string.Join(" ", args.Skip(1).ToArray()),
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
RedirectStandardInput = false,
CreateNoWindow = true
};
using (var process = Process.Start(start))
{
while (!process.HasExited)
{
using (var reader = process.StandardOutput)
Drain(reader, false);
using (var reader = process.StandardError)
Drain(reader, true);
}
process.WaitForExit();
return process.ExitCode;
}
}
static void Drain(TextReader reader, bool error)
{
ColourizeError(error, () =>
{
var buf = new char[256];
int read;
while ((read = reader.Read(buf, 0, buf.Length)) != 0)
Console.Write(new string(buf, 0, read));
});
}
static void ColourizeError(bool error, Action a)
{
var prev = Console.ForegroundColor;
Console.ForegroundColor = error ? ConsoleColor.Red : ConsoleColor.White;
var mre = new ManualResetEventSlim(false);
try
{
a();
}
finally
{
Console.ForegroundColor = prev;
mre.Set(); // runs on GC thread on servers and is reentrant/interleaved concurrency in workstations!
}
mre.Wait();
}
}
}
Call with sh64 powershell -File ./buildscripts/deploy.ps1 -Ex RemoteSigned
add cmd-file (e.g. run-script.cmd) with this content:
@echo off set pspath=%windir%\Sysnative\WindowsPowerShell\v1.0 if not exist %pspath%\powershell.exe set pspath=%windir%\System32\WindowsPowerShell\v1.0 %pspath%\powershell.exe -ExecutionPolicy RemoteSigned %*
and call it from build event in a such manner:
$(SolutionDir)scripts\run-script.cmd $(SolutionDir)scripts\restore-default-file.ps1 -source $(ProjectDir)App_Data\Configs\Mip.Security.Sample.config -destination $(ProjectDir)App_Data\Configs\Mip.Security.config
精彩评论