Embed SharePoint PowerShell with a C# Web Application - c#

I am running a C# web application in 3.5 framework with Any CPU as target.
My Machine Config:
Windows 7 with 64bit OS
Visual Studio 2010
SharePoint 2010
I am trying to call a SharePoint PowerShell script from my web application. But failed. Below is my code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.IO;
using System.Collections.ObjectModel;
using System.Text;
namespace WebApplication3
{
public partial class test : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Button1_Click(object sender, EventArgs e)
{
try
{
string scriptText = ReadPowerShellScript("D:\\SiteHierarchy_project\\scriptSC.ps1");
RunspaceConfiguration rsConfig = RunspaceConfiguration.Create();
PSSnapInException snapInException = null;
Runspace runspace = RunspaceFactory.CreateRunspace();
runspace.Open();
PSSnapInInfo info = rsConfig.AddPSSnapIn("Microsoft.SharePoint.Powershell", out snapInException);
Pipeline pipeline = runspace.CreatePipeline();
string scriptSnapIn = "Get-PsSnapin -Registered";
pipeline.Commands.AddScript(scriptSnapIn);
Runspace RunSpace = RunspaceFactory.CreateRunspace(rsConfig);
RunSpace.Open();
Pipeline pipeLine = RunSpace.CreatePipeline();
Command scriptCommand = new Command(scriptText);
pipeLine.Commands.AddScript(scriptText);
// execute the script
// Collection<PSObject> commandResults = pipeLine.Invoke();
pipeLine.Invoke();
// close the runspace
RunSpace.Close();
}
catch (Exception ex)
{ }
}
public string ReadPowerShellScript(string Script)
{
//Read script
//StreamReader objReader = new StreamReader(Server.MapPath(Script));
StreamReader objReader = new StreamReader(Script);
string strContent = objReader.ReadToEnd();
objReader.Close();
return strContent;
}
}
}
and getting the below error.
"The Windows PowerShell snap-in 'Microsoft.SharePoint.Powershell' is not installed on this machine."
Please let me know , where i am doing wrong
Thanks ,
Sandeep

Do you have sharepoint installed on the web server in which you are running this code? The error message is pretty straight forward.

Just an idea;
Create batch file to call .ps1 file. And instead of calling .ps1 file directly from code, you can call batch file using System.Diagnostics.ProcessStartInfo ;

The Solution is call the 64 bit powershell than only it works from the VS 2010.
I had called the Powershell script from the batch file and my batch file is calling the 64 bit poweshell.
In my batch file i wrote
%windir%\sysnative\windowspowershell\v1.0\powershell -File "C:\filepath\Poweshellfile.ps1" auto
Now application is working fine.
Sandeep Tiwari
MCTS SharePoint 2010

Related

Executing embeded .ps1 scripts in C# application

I'm attempting to create a function which will take in specified .ps1 file which is embedded within my project, but I'm not quite sure how to change my code around to cater for this.
I've written this in my new .NET 6 C# WPF application based on a VB.net legacy application that does similar stuff:
using System;
using System.Linq;
using System.Management.Automation.Runspaces;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Windows;
public class PowerShellStuff
{
private readonly string PS_UserName = "";
private readonly string PS_Password = "";
private Runspace? runspace;
private PowerShell? pipeline;
public void ConnectToExchange()
{
System.Security.SecureString securePassword = new System.Security.SecureString();
foreach (char c in PS_Password)
{
securePassword.AppendChar(c);
}
PSCredential? credential = new(PS_UserName, securePassword);
WSManConnectionInfo? connectionInfo = new(new Uri("https://outlook.office365.com/powershell-liveid/"), "http://schemas.microsoft.com/powershell/Microsoft.Exchange", credential)
{
AuthenticationMechanism = AuthenticationMechanism.Basic,
MaximumConnectionRedirectionCount = 2
};
using (runspace = RunspaceFactory.CreateRunspace(connectionInfo))
{
using (pipeline = PowerShell.Create())
{
runspace.Open();
pipeline.Runspace = runspace;
}
}
}
public Collection<PSObject> RunScript(PSCommand command)
{
if (runspace == null)
{
try
{
ConnectToExchange();
pipeline = PowerShell.Create();
pipeline.Runspace = runspace;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "User Information", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
if (runspace.RunspaceStateInfo.State != RunspaceState.Opened)
runspace.Open();
pipeline.Commands.Clear();
Command comand = new Command(command.Commands[0].ToString());
for (int i = 0; i <= command.Commands[0].Parameters.Count - 1; i++)
comand.Parameters.Add(command.Commands[0].Parameters[i]);
pipeline.Commands.AddCommand(comand);
Collection<PSObject> results;
try
{
results = pipeline.Invoke();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "User Information", MessageBoxButton.OK, MessageBoxImage.Error);
}
return results;
}
}
This is how its used in VB.net:
Dim command As New PSCommand
command.AddCommand("").AddParameter("", "")...
RunScript(command)
The issue I am having is that I can't even get the above working in C# as it fails with Non-invocable member 'PSCommand.Commands' cannot be used like a method.
My goal is to have a function which I can use to populate a DataTable with results from the .ps1 script, e.g. DataTable dt = new DataTable(RunScript(Resources.MyScript.ps1)) and a function which will not return any data and just execute a SET command with few parameters, which I imagine would follow the same criteria as the VB.net code with command.AddCommand("").AddParameter("", "")...
Its my first time starting PowerShell in C# from scratch as in the past I only carried out simple changes in existing VB.net code, which I used as base to write this...
EDIT 1:
Clearly C# newbie... thanks to first two commenters the issue of executing the above code is resolved, but still unsure how to execute a .ps1 file using my existing runspace & pipeline and populate a DataTable.
I was supposed to give you an example here yesterday but ended up necroing another thread that was several years old. Here goes again hehe :)
I struggled getting PS scripts to work through my app as well and made it work just a like a week ago.
Here I launch a script on a remote computer to make a Windows Toast Notification to pop up.
I didn't get this script to fully work until I downloaded and installed the PowerShell SDK package through NuGet. Hopefully some of this can get you on the right track.
In the screenshot below you can see I also get the output generated from the script in the Debug window.
For some reason Verbose output was not captured even though verbose preference was set in the script. I had to capture the output by putting the statements in the script with quotation marks like this:
"OS Version Display Name: $OsVersion"
using System;
using System.Diagnostics;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.Collections.ObjectModel;
using System.Net;
using System.Net.NetworkInformation;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace WindowsToasts
{
public class WindowsToast
{
public void Send_WindwsUpdateToast(string computerName)
{
InitialSessionState initialSessionState = InitialSessionState.CreateDefault();
initialSessionState.ExecutionPolicy = Microsoft.PowerShell.ExecutionPolicy.Unrestricted;
using Runspace runspace = RunspaceFactory.CreateRunspace(initialSessionState);
runspace.Open();
using PowerShell powerShell = PowerShell.Create(runspace);
string PSPath = #"C:\temp\ToastText.ps1";
powerShell.AddCommand("Invoke-Command");
powerShell.AddParameter("ComputerName", computerName);
powerShell.AddParameter("File", PSPath);
Collection<PSObject> PSOutput = powerShell.Invoke();
foreach (PSObject outputItem in PSOutput)
{
// if null object was dumped to the pipeline during the script then a null object may be present here
if (outputItem != null)
{
Debug.WriteLine($"Output line: [{outputItem}]");
}
}
}
}
}

Calling dll from c# code using powershell script not working

I am using System.Management.Automation.dll to execute powershell script from c# code.
Following is my c# code
public void Execute()
{
using (var runspace = RunspaceFactory.CreateRunspace())
{
try
{
var script = File.ReadAllText("script.ps1");
runspace.Open();
var ps = PowerShell.Create();
ps.Runspace = runspace;
ps.Commands.AddScript(script);
//ps.Ad
ps.Invoke();
foreach (var result in ps.Invoke())
{
Console.WriteLine(result);
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
}
powershell script is
logparser "SELECT top 1 *,null INTO iisLogs FROM 'D:\u_ex200621\*.log' where date >= '2020-01-01' " -i:iisw3c -o:SQL -server:172.29.182.160 -database:DBA_Work -username:azuredev -password:cybage#123 -transactionRowCount:10000 -createTable: OFF
I have added logparser.dll path to Environment Variable so I can execute it from anywhere on machine.
But I tried to execute above code it did not execute anything.Same script I tried using Power shell then it works perfectly.
Please let me know correct way to execute powershell script using C# code.I tried multiple solutions on stackoverflow but no luck.

Running PowerShell cmdlets in C#

I need to run powershell cmdlets using C# in Visual Studio Console.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Management.Automation;
using System.Threading;
using System.Management.Automation.Runspaces;
using System.Collections.ObjectModel;
using System.Collections;
namespace ConsoleApp1
{
class Program
{
private static string RunScript()
{
Runspace runSpace = RunspaceFactory.CreateRunspace();
runSpace.Open();
Pipeline pipeline = runSpace.CreatePipeline();
Command cmd = new Command("Connect-MsolService");
pipeline.Commands.Add(cmd);
ICollection results = pipeline.Invoke(); // Here exception occurs
runSpace.Close();
StringBuilder stringBuilder = new StringBuilder();
foreach (PSObject obj in results)
{
stringBuilder.AppendLine(obj.ToString());
}
return stringBuilder.ToString();
}
static void Main(string[] args)
{
using (PowerShell PowerShellInstance = PowerShell.Create())
{
Console.WriteLine(RunScript());
Console.ReadKey();
}
}
}
}
When I run the code an Exception occurs:
The term 'Connect-MsolService' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
Even though it works when I run the commands in Powershell.
Try to use PowerShell instance, like this:
InitialSessionState iss = InitialSessionState.CreateDefault();
iss.ImportPSModule(new[] { "MSOnline" });
iss.LanguageMode = PSLanguageMode.FullLanguage;
var _o365Runspace = RunspaceFactory.CreateRunspace(iss);
_o365Runspace.Open();
var _o365Shell = PowerShell.Create();
_o365Shell.Runspace = _o365Runspace;
var connect = new Command("Connect-MsolService");
connect.Parameters.Add("Credential", new PSCredential("logon#name",
GetSecureString("Password"));
_o365Shell.Commands.AddCommand(connect);
// add some msol commands to _o365Shell.Commands as well
_o365Shell.Invoke();
You are executing it as a CMD command, not as a powershell command.
You have to execute it over an Powershell instance.
Check executing-powershell-scripts-from-c.

Run a Powershell command as an Administrator - Commands themself won't load

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Diagnostics;
namespace WindowsFormsApplication
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
var newProcessInfo = new System.Diagnostics.ProcessStartInfo();
newProcessInfo.FileName = #"C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe";
newProcessInfo.Verb = "runas";
System.Diagnostics.Process.Start(newProcessInfo);
newProcessInfo.Arguments = #"sfc /scannow";
}
}
}
So my code works up to a point. you click the windows form application button and it will run windows Powershell in 64bit as an administrator but won't run a .ps1 script "c:\path\script.ps1" or the command directly written out like the "sfc /scannow" above.
I was reading that the powershell commands won't work sometimes if the "Set-ExecutionPolicy Unrestricted" isn't loaded somewhere in the beginning of the code.
Please help! I have been looking everywhere for an answer.
First of all, you need to specify the Arguments property before you start the process:
var newProcessInfo = new System.Diagnostics.ProcessStartInfo();
newProcessInfo.FileName = #"C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe";
newProcessInfo.Verb = "runas";
newProcessInfo.Arguments = #"sfc /scannow";
System.Diagnostics.Process.Start(newProcessInfo);
Second, you'll need to tell PowerShell that sfc /scannow is a command, and not command line switches.
On the command line you would do powershell.exe -Command "sfc /scannow", so the correct Arguments value in your case would be
newProcessInfo.Arguments = #"-Command ""sfc /scannow""";
("" is the escape sequence for " in verbatim string literals)
For .ps1 files, use the -File switch:
newProcessInfo.Arguments = #"-File ""C:\my\script.ps1""";
If you don't know the execution policy on the target system, you can bypass it without affecting the machine-wide policy with -ExecutionPolicy Bypass:
newProcessInfo.Arguments = #"–ExecutionPolicy Bypass -File ""C:\my\script.ps1""";

System.InvalidProgramException when trying to run Powershell commands in C#

I have ran a debug stepping through the program and it crashes at the following line
Runspace runspace = RunspaceFactory.CreateRunspace();
It gives the following error
An unhandled exception of type 'System.InvalidProgramException' occurred in PrimarySMTP_Fix.exe
Additional information: Common Language Runtime detected an invalid program.
This is my first time working with Power Shell through C# and I'm having trouble getting some simple code execution. The point of the project is to automate a simple fix for a common issue with our company's exchange server.
The complete code is below.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Management.Automation;
using System.Collections.ObjectModel;
using System.Management.Automation.Runspaces;
namespace PrimarySMTP_Fix
{
public partial class MainWindow : Window
{
//Variable Declarations
string userName = "";
string confirmUser = "";
string primarySMTP = "";
string confirmSMTP = "";
public MainWindow()
{
InitializeComponent();
}
private string RunScript(string scriptText)
{
Runspace runspace = RunspaceFactory.CreateRunspace();
runspace.Open();
Pipeline pipeline = runspace.CreatePipeline();
pipeline.Commands.AddScript(scriptText);
pipeline.Commands.Add("Out-String");
Collection<PSObject> results = pipeline.Invoke();
runspace.Close();
StringBuilder stringBuilder = new StringBuilder();
foreach (PSObject obj in results)
{
stringBuilder.AppendLine(obj.ToString());
}
return stringBuilder.ToString();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
userName = adUser.Text;
confirmUser = confirmAD.Text;
primarySMTP = mail.Text;
confirmSMTP = confirmMail.Text;
outPut.Text = RunScript(userName);
}
}
}
The above is just setup to test. For now it's taking just the username information and running it directly as a command. If I can get that to work and output information then I can re-write it to do what I want it to do.
After playing around for a while I found that I needed to reinstall the Windows Management Framework to get it to work. Figured that out when I put the debug build on the server and ran the test there and it worked.

Categories