Has anyone worked with the Citrix 7.6 BrokerSession SDK? I can't figure out how to execute a command like this for example:
GetBrokerSessionCommand getCmd = new GetBrokerSessionCommand();
getCmd.AdminAddress = "citrixServer:80";
var result = getCmd.Invoke();
This gives me an error message saying: "Cmdlets derived from PSCmdlet cannot be invoked directly.
In the earlier 6.5 SDK I could do like this:
string[] servers = new string[] { };
GetXAWorkerGroupByName workerGroup = new GetXAWorkerGroupByName();
workerGroup.WorkerGroupName = new string[] { workerGroupName };
workerGroup.ComputerName = XenAppController;
foreach (XAWorkerGroup _workerGroup in CitrixRunspaceFactory.DefaultRunspace.ExecuteCommand(workerGroup))
{
servers = _workerGroup.ServerNames;
}
return servers;
But now the CitrixRunspaceFactory no longer exists?
I want to avoid executing the command with the Powershell class and Powershell.Create() for the simple reason of handling exceptions in a simpler way.
Citrix 7.6 cmdlets derived not from Cmdlet class but from PSCmdlet. So they much more binded to the PowerShell engine and must be invoked inside it:
Runspace runSpace = RunspaceFactory.CreateRunspace();
runSpace.Open();
PSSnapInException psex;
runSpace.RunspaceConfiguration.AddPSSnapIn("Citrix.Broker.Admin.V2", out psex);
Pipeline pipeline = runSpace.CreatePipeline();
Command getSession = new Command("Get-BrokerSession");
getSession.Parameters.Add("AdminAddress", "SERVERNAME");
pipeline.Commands.Add(getSession);
Collection<PSObject> output = pipeline.Invoke();
AFAIK good times of strongly typed classes in Citrix SDK are gone.
Related
I need to execute a powershell script from my asp.net MVC Web application. My requirement is to create site collections dynamically. I have the script for it and it works perfectly.There are no arguments which are to be passed to the script. The code which I have been using has been displayed below:
RunspaceConfiguration runspaceConfiguration = RunspaceConfiguration.Create();
Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration);
runspace.Open();
RunspaceInvoke scriptInvoker = new RunspaceInvoke(runspace);
Pipeline pipeline = runspace.CreatePipeline();
//Here's how you add a new script with arguments
Command myCommand = new Command(scriptfiellocation);
pipeline.Commands.Add(myCommand);
pipeline.Commands.Add("Out-String");
// Execute PowerShell script
var result = pipeline.Invoke();
On executing the code, when I check the count of variable result it gives the count as 1. However on checking my site, there is no site collection that has been created. I am not able to identify where I am going wrong as there is no run time error and the Invoke command also seems to be running properly.
Could anyone tell me where I might be going haywire ? Considering that the PowerShell script works perfectly when running through Management shell.
I had to forego the pipeline approach as I was not able to figure out what the issue was. Also another problem with that approach is that it threw the error: "Get-SPWbTemplate is not recognized as an cmdlet". The following code worked perfectly fine for me and created the required site collections:
PowerShell powershell = PowerShell.Create();
//RunspaceConfiguration runspaceConfiguration = RunspaceConfiguration.Create();
//Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration)
using (Runspace runspace = RunspaceFactory.CreateRunspace())
{
runspace.Open();
//RunspaceInvoke scriptInvoker = new RunspaceInvoke(runspace);
//scriptInvoker.Invoke("Set-ExecutionPolicy Unrestricted");
powershell.Runspace = runspace;
//powershell.Commands.AddScript("Add-PsSnapin Microsoft.SharePoint.PowerShell");
System.IO.StreamReader sr = new System.IO.StreamReader(scriptfilepath);
powershell.AddScript(sr.ReadToEnd());
//powershell.AddCommand("Out-String");
var results = powershell.Invoke();
if (powershell.Streams.Error.Count > 0)
{
// error records were written to the error stream.
// do something with the items found.
}
}
Also there was no requirement to set the execution policy.
well don't know if its help but i never use pipeline to run Command shell not sure how that work.
But here a quick example
Runspace RS = RunspaceFactory.CreateRunspace(myConnection);
PowerShell PS = PowerShell.Create();
PSCommand PScmd = new PSCommand();
string cmdStr = "Enable-Mailbox -Identity " + username + " -Database DB01 -Alias " + aliasexample;
PScmd.AddScript(cmdStr);
try
{
RS.Open();
PS.Runspace = RS;
PS.Commands = PScmd;
PS.Invoke();
}
catch (Exception ex)
{
ex.ToString();
}
finally
{
RS.Dispose();
RS = null;
PS.Dispose();
PS = null;
}
with the try catch you can catch the error with debugging if something goes wrong.
If i remember correctly i had to put ACL.exe for permission to file system so i can execute the commandshell you can do a quick search on google for it.
Hope this help.
I am trying to restart a VM using powershell in C#.
First i am trying to run the GET-VM command. It is giving an exception at line:
PSSnapInInfo psinfo = runspaceConfig.AddPSSnapIn("System.Management.Automation", out snapEx);
in below given code. Can someone tell me where i am doing it wrong.
Exception Message : No snap-ins have been registered for Windows PowerShell version 2
My Code :
Command command = new Command("Get-VM");
command.Parameters.Add("Name", "PIE01010299");
RunspaceConfiguration runspaceConfig = RunspaceConfiguration.Create();
PSSnapInException snapEx = null;
PSSnapInInfo psinfo = runspaceConfig.AddPSSnapIn("System.Management.Automation", out snapEx);
Runspace runSpace = RunspaceFactory.CreateRunspace(runspaceConfig);
runSpace.Open();
Pipeline pipeline = runSpace.CreatePipeline();
pipeline.Commands.Add(command);
Collection<PSObject> output = pipeline.Invoke();
runSpace.Close();
foreach (PSObject psObject in output)
{
Console.WriteLine(psObject.ToString());
}
System.Management.Automation is not a snapin. It is the core PowerShell engine assembly. It is loaded by default because your C# project needs to reference that assembly. You probably want to import the Hyper-V module e.g.:
pipeline.Commands.AddCommand("Import-Module").AddArgument("Hyper-V");
pipeline.Invoke();
pipeline.Clear();
Or use the InitialSessionState.ImportPSModule method and then associate that with the runspace.
I'm trying to get the lower store from a 2010 Exchange server, and the function will run in a WCF container.
The problem I'm facing is that I'm unable to run multiple PowerShell commands in the pipeline.
I've tried the following (based on this, how to invoke the powershell command with "format-list" and "out-file" pipeline from c#?):
string strCommand = #"Get-MailboxDatabase -Status | select ServerName,Name,DatabaseSize | Sort-Object DatabaseSize";
string CommandLine = string.Format("&{{{0}}}", strCommand);
pipeLine.Commands.AddScript(CommandLine);
But I get:
Unhandled Exception: System.Management.Automation.RemoteException: Script block literals are not allowed in restricted language mode or a Data section.
Also I tried,
Command getMailbox = new Command("Get-MailboxDatabase");
getMailbox.Parameters.Add("Status", null);
Command sort = new Command("Sort-Object");
pipeLine.Commands.Add(getMailbox);
pipeLine.Commands.Add(sort);
Collection<PSObject> commandResults = pipeLine.Invoke();
But not luck:
Unhandled Exception: System.Management.Automation.RemoteException: The term 'Sort-Object' is not recognized as the name of a cmdlet
I wonder if I should use multiple pipelines (one pipeline per cmdlet), but I am not sure.
It sounds like the problem is the runspace. If that's an Exchange server, and you're running that in the remote management session provided by Exchange, the only thing you can do in that session is run the Exchange cmdlets. The Select-Object and Sort-Object cmdlets and other PowerShell language elements just aren't there to use.
Considering that Sort-Object is a command which is not recognized by the schema named 'http://schemas.microsoft.com/powershell/Microsoft.Exchange" then I proceed to develop a function using Snap-Ins and it's working fine.
Notice I'm taking the first database because the default sort mode is ascending. Also I'd like to comment that if you compile on Framework 4.0 you're going to get a "Value cannot be null error message" so you have to change to 3.5.
Keep in mind that it is being used by a WCF Service so no problem with Snap-Ins. If you like to use it on any other application, like a console-based application then you should install EMS 2010 on that computer.
This function basically execute the following PowerShell command, Get-MailboxDatabase -Status | Sort-Object DatabaseSize
private static string getLowServerStoreDN_SnapIn(string ExchangeSite)
{
string strResult = string.Empty;
RunspaceConfiguration rsConfig = RunspaceConfiguration.Create();
PSSnapInException snapInException = null;
PSSnapInInfo info = rsConfig.AddPSSnapIn("Microsoft.Exchange.Management.PowerShell.E2010", out snapInException);
Runspace runspace = RunspaceFactory.CreateRunspace(rsConfig);
try
{
runspace.Open();
Command getMailbox = new Command("Get-MailboxDatabase");
getMailbox.Parameters.Add(new CommandParameter("Status", null));
Command sort = new Command("Sort-Object");
sort.Parameters.Add("Property", "DatabaseSize");
Pipeline commandPipeLine = runspace.CreatePipeline();
commandPipeLine.Commands.Add(getMailbox);
commandPipeLine.Commands.Add(sort);
Collection<PSObject> getmailboxResults = commandPipeLine.Invoke();
if (getmailboxResults.Count > 0)
{
PSObject getMailboxResult = getmailboxResults[0];
strResult = getMailboxResult.Properties["Name"].Value.ToString();
//foreach (PSObject getMailboxResult in getmailboxResults)
//{
// strResult = getMailboxResult.Properties["Name"].Value.ToString();
//}
}
}
catch (ApplicationException e)
{
//Console.WriteLine(e.Message);
throw new FaultException("function getLowServerStoreDN_SnapIn(" + ExchangeSite + "): " + e.Message,
FaultCode.CreateReceiverFaultCode("BadExchangeServer", "http://example.com"));
}
return strResult;
}
I am trying to create a cmdlet in C#. The code looks something like this:
[Cmdlet(VerbsCommon.Get, "HeapSummary")]
public class Get_HeapSummary : Cmdlet
{
protected override void ProcessRecord()
{
RunspaceConfiguration config = RunspaceConfiguration.Create();
Runspace myRs = RunspaceFactory.CreateRunspace(config);
myRs.Open();
RunspaceInvoke scriptInvoker = new RunspaceInvoke(myRs);
scriptInvoker.Invoke("Set-ExecutionPolicy Unrestricted");
Pipeline pipeline = myRs.CreatePipeline();
pipeline.Commands.Add(#"Import-Module G:\PowerShell\PowerDbg.psm1");
//...
pipeline.Invoke();
Collection<PSObject> psObjects = pipeline.Invoke();
foreach (var psObject in psObjects)
{
WriteObject(psObject);
}
}
}
But trying to execute this CmdLet in PowerShell gives me this error: The term Import-Module is not recognized as the name of a cmdlet. The same command in PowerShell doesn't give me this error. If I execute 'Get-Command' instead, I can see that 'Invoke-Module' is listed as a CmdLet.
Is there a way to do an 'Import-Module' in a Runspace?
Thanks!
There are two ways to import modules programmatically, but I'll address your method first. Your line pipeline.Commands.Add("...") should only be adding the command, not the command AND the parameter. The parameter is added separately:
# argument is a positional parameter
pipeline.Commands.Add("Import-Module");
var command = pipeline.Commands[0];
command.Parameters.Add("Name", #"G:\PowerShell\PowerDbg.psm1")
The above pipeline API is a bit clumsy to use and is informally deprecated for many uses although it's at the base of many of the higher level APIs. The best way to do this in powershell v2 or higher is by using the System.Management.Automation.PowerShell Type and its fluent API:
# if Create() is invoked, a runspace is created for you
var ps = PowerShell.Create(myRS);
ps.Commands.AddCommand("Import-Module").AddArgument(#"g:\...\PowerDbg.psm1")
ps.Invoke()
Another way when using the latter method is to preload modules using InitialSessionState, which avoids the need to seed the runspace explictly with Import-Module.
InitialSessionState initial = InitialSessionState.CreateDefault();
initialSession.ImportPSModule(new[] { modulePathOrModuleName1, ... });
Runspace runspace = RunspaceFactory.CreateRunspace(initial);
runspace.Open();
RunspaceInvoke invoker = new RunspaceInvoke(runspace);
Collection<PSObject> results = invoker.Invoke("...");
Hope this helps.
The simplest way that you can do this is by using AddScript() method.
You can do:
pipeline.AddScript("Import-Module moduleName").Invoke();
If you want to add another import in the same line
pipeline.AddScript("Import-Module moduleName \n Import-Module moduleName2").Invoke();
Its not mandatory to .Invoke() right ofter you add the script to the pipeline, you can add more scripts and invoke later.
pipeline.AddScript("Import-Module moduleName");
pipeline.AddCommand("pwd");
pipeline.Invoke();
For more information visit Microsoft Official website
I have created a asp.net web application for internal use that allows certain users to start and stop Virtual machines that are linked to there QA testing environments, the code behind page runs a powershell script that starts the selected server once a button is pressed on an ASP.net page.
I have reserched and implimented alot of the code from this site but i am coming up against a few problems.
everytime i click the button on the main web page the error that is fed back from the powershell script says"You cannot call a method on a null-valued expression." the only problem is if i run it from a powershell prompt like this ". \script\test.ps1 'W7EA9'" it works fine.
This is the class that calls the powershell script.
public String Startserver(String Servername)
{
String scriptText =". \\scripts\\test.ps1 " + Servername + "";
// create Powershell runspace
Runspace runspace = RunspaceFactory.CreateRunspace();
// open it
runspace.Open();
// create a pipeline and feed it the script text
Pipeline pipeline = runspace.CreatePipeline();
pipeline.Commands.AddScript(scriptText);
// execute the script
Collection<PSObject> results = new Collection<PSObject>();
try
{
results = pipeline.Invoke();
}
catch (Exception ex)
{
results.Add(new PSObject((object)ex.Message));
}
// close the runspace
runspace.Close();
// convert the script result into a single string
StringBuilder stringBuilder = new StringBuilder();
foreach (PSObject obj in results)
{
stringBuilder.AppendLine(obj.ToString());
}
return stringBuilder.ToString();
//return scriptText;
}
and here is the powershell script it is trying to run
Param ($server = $arg[0])
$Core = get-wmiobject -namespace root\virtualization -class Msvm_Computersystem -filter "ElementName = '$server'"
$status = $Core.RequestStateChange(2) `
It may be somthing really obvious but im just not seeing it and any help would be great.
thanks
Chris
Here is a best step-by-step guide to running PowerShell from ASP.NET.
http://devinfra-us.blogspot.com/2011/02/using-powershell-20-from-aspnet-part-1.html
HTH
I don't see where you're providing a parameter to the script anywhere.
i am passing the paramater from a button press on an asp.net page the code behind looks like this
Hypervserver Start = new Hypervserver();
String result = Start.Startserver("W7EA9");
Label1.Visible = true;
Label1.Text = result;
Below is how I ended up doing this.
Runspace runspace = RunspaceFactory.CreateRunspace();
runspace.Open();
Pipeline pipeline = runspace.CreatePipeline();
Command myCommand = new Command("C:\\Scripts\\Test.ps1");
//I used full path name here, not sure if you have to or not
CommandParameter myParam1 = new CommandParameter("-ServerName", "myServer");
myCommand.Parameters.Add(myParam1);
//You can add as many parameters as you need to here
pipeline.Commands.Add(myCommand);
Collection<PSObject> results = pipeline.Invoke();
runspace.Close();
StringBuilder stringBuilder = new StringBuilder()
foreach (PSObject obj in results) {
stringBuilder.AppendLine(obj.ToString());
}
string thestring = stringBuilder.ToString();
A few notes. The scripts first line that is not a comment or blank line should be the parameter list formatted like this:
param([string]$ServerName,[string]$User)
You have this, I just wanted to acknowledge the fact that I could not get this working when my script file was a function with parameters.
For certain commands you may need additional privileges, in my case all of my scripts worked this way except for creating a mailbox for which I had to add credentials onto the connection.
Greg
In powershell, the default arguments collection is called $args, with an 's'; I'm pretty sure that's why $server is null when you run it via code, and thus the Get-WmiObject call returns null, causing the error when you attempt to call the RequestStateChange method on it.
I'm guessing it works fine in your normal powershell window because you already have a $server variable in the session.