HOW TO: Call .PS1 script from Managed code using Remote Powershell(Exchange 2010)

As promised below is the code to call a .PS1 script and pass parameters to it. Most of the code is very similar to my previous post that showed how to call Exchange & PowerShell cmdlet.

 using System;
using System.Collections.Generic;
using System.Text;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.Management.Automation.Remoting;
using System.Collections.ObjectModel;
using System.Security;

namespace CallingScriptPS
{
    class Program
    {
        static void Main(string[] args)
        {
            string password = "Password";
            string userName = "Domain\\Administrator";
            System.Uri uri = new Uri("https://CAS-SERVER/powershell?serializationLevel=Full");
            System.Security.SecureString securePassword = String2SecureString(password);

            System.Management.Automation.PSCredential creds = new System.Management.Automation.PSCredential(userName, securePassword);

            Runspace runspace = System.Management.Automation.Runspaces.RunspaceFactory.CreateRunspace();

            PowerShell powershell = PowerShell.Create();
            PSCommand command = new PSCommand();
            command.AddCommand("New-PSSession");
            command.AddParameter("ConfigurationName", "Microsoft.Exchange");
            command.AddParameter("ConnectionUri", uri);
            command.AddParameter("Credential", creds);
            command.AddParameter("Authentication", "Default");
            PSSessionOption sessionOption = new PSSessionOption();
            sessionOption.SkipCACheck = true;
            sessionOption.SkipCNCheck = true;
            sessionOption.SkipRevocationCheck = true;
            command.AddParameter("SessionOption", sessionOption);

            powershell.Commands = command;

            try
            {
                // open the remote runspace
                runspace.Open();

                // associate the runspace with powershell
                powershell.Runspace = runspace;

                // invoke the powershell to obtain the results
                Collection<PSSession> result = powershell.Invoke<PSSession>();

                foreach (ErrorRecord current in powershell.Streams.Error)
                {
                    Console.WriteLine("Exception: " + current.Exception.ToString());
                    Console.WriteLine("Inner Exception: " + current.Exception.InnerException);
                }

                if (result.Count != 1)
                    throw new Exception("Unexpected number of Remote Runspace connections returned.");

                
                // Set the runspace as a local variable on the runspace
                powershell = PowerShell.Create();

                command = new PSCommand();
                command.AddCommand("Set-Variable");
                command.AddParameter("Name", "ra");
                command.AddParameter("Value", result[0]);
                powershell.Commands = command;
                powershell.Runspace = runspace;
                powershell.Invoke();


                
                // First import the cmdlets in the current runspace (using Import-PSSession)
                powershell = PowerShell.Create();
                command = new PSCommand();
                command.AddScript("Import-PSSession -Session $ra");
                powershell.Commands = command;
                powershell.Runspace = runspace;
                powershell.Invoke();


                
                // Now run get-ExchangeServer
                System.Collections.ObjectModel.Collection<PSObject> results = new System.Collections.ObjectModel.Collection<PSObject>();

                powershell = PowerShell.Create();
                powershell.Runspace = runspace;



                //Change the Path to the Script to suit your needs
                System.IO.StreamReader sr = new System.IO.StreamReader("..\\..\\Script.ps1");
                powershell.AddScript(sr.ReadToEnd());
                powershell.Runspace.SessionStateProxy.SetVariable("proc", "C*");
                powershell.Runspace.SessionStateProxy.SetVariable("mbx", "*MBX");

                results = powershell.Invoke();

                if (powershell.Streams.Error.Count > 1)
                {
                    foreach (ErrorRecord er in powershell.Streams.Error)
                        Console.WriteLine(er.ErrorDetails);
                }
                else
                {
                    foreach (PSObject ps in results)
                    {
                        Console.WriteLine(ps.Properties["Name"].Value.ToString());
                    }
                }
            }
            finally
            {
                // dispose the runspace and enable garbage collection
                runspace.Dispose();
                runspace = null;

                // Finally dispose the powershell and set all variables to null to free
                // up any resources.
                powershell.Dispose();
                powershell = null;
            }
        }
        
        private static SecureString String2SecureString(string password)
        {
            SecureString remotePassword = new SecureString();
            for (int i = 0; i < password.Length; i++)
                remotePassword.AppendChar(password[i]);

            return remotePassword;
        }

    }
}

Below is what the Script.PS1 looks like:

 get-process |where {$_.Name -like $proc}
get-exchangeserver | Where {$_.Name -like $mbx}

The two parameters that we pass in are called “proc” & “mbx”.

Note:This code will not work if we do not call the New-PSSession & the Import-PSSession cmdlet’s for reasons explained in my previous post .

Enjoy!