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
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?
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.
(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".
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
来源:https://stackoverflow.com/questions/5006619/call-powershell-script-in-post-built-with-parameters