Blog Stats
  • Posts - 24
  • Articles - 0
  • Comments - 18
  • Trackbacks - 0

 

Running Powershell from within SharePoint

Just because something is a daft idea, doesn't mean it can't be done.

We sometimes need to do some housekeeping - like delete old files or list items or… yes, well, whatever you use Powershell for in a SharePoint world. Or it could be that your solution has "issues" for which you have Powershell solutions, but not the budget to transform into proper bug fixes. So you create a "how to" for the ITPro guys.

Idea: What if we keep the scripts in a list, and have SharePoint execute the scripts on demand? An announcements list (because of the multiline body field).

Warning! Let us be clear. This list needs to be locked down; if somebody creates a malicious script and you run it, I cannot help you.

First; we need to figure out how to start Powershell scripts from C#. Hit teh interwebs and the Googlie, and you may find jpmik's post: http://www.codeproject.com/Articles/18229/How-to-run-PowerShell-scripts-from-C. (Or MS' official answer at http://msdn.microsoft.com/en-us/library/ee706563(v=vs.85).aspx)

        public string RunPowershell(string powershellText, SPWeb web, string param1, string param2)        {
            // Powershell  ~= RunspaceFactory - i.e. Create a powershell context
            var runspace = RunspaceFactory.CreateRunspace();

            var resultString = new StringBuilder();
            try
            {
	// load the SharePoint snapin - Note: you cannot do this in the script itself (i.e. add-pssnapin etc does not work)
	     PSSnapInException snapInError;
                runspace.RunspaceConfiguration.AddPSSnapIn("Microsoft.SharePoint.PowerShell", out snapInError);

                runspace.Open();

                // set a web variable.
                runspace.SessionStateProxy.SetVariable("webContext", web);
// and some user defined parameters
                runspace.SessionStateProxy.SetVariable("param1", param1);
                runspace.SessionStateProxy.SetVariable("param2", param2);

                var pipeline = runspace.CreatePipeline();
                pipeline.Commands.AddScript(powershellText);

		// add a "return" variable
                pipeline.Commands.Add("Out-String");

                // execute!
                var results = pipeline.Invoke();

                // convert the script result into a single string
                foreach (PSObject obj in results)
                {
                    resultString.AppendLine(obj.ToString());
                }
            }
            finally 
            {
                // close the runspace
                runspace.Close();
            }
            // consider logging the result. Or something.
            return resultString.ToString();
        }

Ok. We've written some code. Let us test it.

            var runner = new PowershellRunner();
            runner.RunPowershellScript(@"
                        $web = Get-SPWeb 'http://server/web' # or $webContext
                        $web.Title = $param1
                        $web.Update()
                        $web.Dispose()
                    ", null, "New title", "not used");

Next step: Connect the code to the list, or more specifically, have the code execute on one (or several) list items. As there are more options than readers, I'll leave this as an exercise for the reader. Some alternatives:

  • Create a ribbon button that calls RunPowershell with the body of the selected items
  • Add a layout page
    • Specify list item from query string (possibly coupled with content editor webpart with html that links directly to this page with querystring)
  • Webpart
  • Listing with an "execute" column
  • List with multiselect and an execute button

Etc!


Now that you have the code for executing powershell scripts, you can easily expand this into a timer job, which executes scripts at regular intervals. But if the previous solution was dangerous, this is even worse - the scripts will usually be run with one of the admin accounts, and can do pretty much anything...


One more thing... Note that as this is running "consoleless" calls to Write-Host will fail. Two solutions; remove all output, or check if the script is run in a console-window or not.

 

if ($host.Name -eq "ConsoleHost")
{
	Write-Host 'If I agreed with you we'd both be wrong'
}

Feedback

# re: Running Powershell from within SharePoint

Gravatar I am trying to replicate your code. getting this error when this is getting executed

runspace.RunspaceConfiguration.AddPSSnapIn("Microsoft.SharePoint.PowerShell", out snapInError);

Cannot load Windows PowerShell snap-in Microsoft.SharePoint.PowerShell because of the following error: Could not load file or assembly 'file:///C:\Windows\Microsoft.Net\assembly\GAC_MSIL\Microsoft.SharePoint.PowerShell\v4.0_15.0.0.0__71E9BCE111E9429C\Microsoft.SharePoint.PowerShell.dll' or one of its dependencies. This assembly is built by a runtime newer than the currently loaded runtime and cannot be loaded.

please help my requirement is to create timer job which will run my custom powerShell script 2/28/2014 12:11 PM | Rahul

# re: Running Powershell from within SharePoint

Gravatar I am also getting the same error when i am running through MVC webApp but its running fine when i am trying through console app.Powershell dll is there at "C:\Windows\Microsoft.NET\assembly\GAC_MSIL\Microsoft.SharePoint.PowerShell\v4.0_15.0.0.0__71e9bce111e9429c".Both applications tried on same machine. 4/3/2014 11:35 AM | Avinash

# re: Running Powershell from within SharePoint

Gravatar Nice script, thanks 4/29/2014 4:56 PM | <a href="http://best-onlinecasin

Post A Comment
Title:
Name:
Email:
Comment:
Verification:
 
 

 

 

Copyright © Norgean