Call powershell script in post-built with parameters

元气小坏坏 提交于 2019-11-30 19:50:58

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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!