C# unable to execute the powershell script - c#

using (Runspace runspace = System.Management.Automation.Runspaces.RunspaceFactory.CreateRunspace())
{
runspace.Open();
using (PowerShell powershell = PowerShell.Create())
{
Command lic1 = new Command("Out-String");
var script1 = "$s = Get-LocalUser -Name test2";
var script2 = "Remove-LocalUser -InputObject $s";
string accessScriptPath = $"{script1} ;\n {script2}";
powershell.Commands.AddCommand(lic1);
powershell.Commands.AddCommand(new Command(accessScriptPath));
var results = powershell.Invoke();
PowerShellErrorCheck(powershell, results);
powershell.Commands.Clear();
}
}
I wants to execute the command and it was assigned to a variable and trying to access in next line but system throw exception. '$s = Get-LocalUser -Name test2 ;
Remove-LocalUser -InputObject $s' 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.
Mainly I was trying the above code was to simulate the below powershell code to c#
$x = Get-CsRgsAgentGroup -Identity service:ApplicationServer:atl-cs-001.litwareinc.com -Name "Help Desk"
$x.AgentsByUri.Add("sip:kenmyer#litwareinc.com")
Set-CsRgsAgentGroup -Instance $x

Related

C# Powershell not returning any Get-ChildItem results

When I run powershell from my MVC application, i get no results from the Get-ChildItem –Path IIS:\AppPools command.
If i run it directly in powershell it works fine. I have set the site to run on administrator account, thinking that maybe it cant "see" the pools, but no luck.
This is just a test too, accessing the pools, as what i was origionally struggling with was turning off an application pool, as it "could not be found". with Get-WebAppPoolState -name $service
public static string test()
{
using (var powershell = PowerShell.Create())
{
using (Runspace runspace = RunspaceFactory.CreateRunspace())
{
using (RunspaceInvoke invoker = new RunspaceInvoke())
{
invoker.Invoke("Set-ExecutionPolicy Unrestricted");
invoker.Invoke("Import-Module WebAdministration");
runspace.Open();
powershell.Runspace = runspace;
powershell.AddScript(#"Import-Module WebAdministration
Get-ChildItem –Path IIS:\AppPools");
var results = powershell.Invoke();
var result = "";
result += ResultsToString(results); // results is a blank list
result += String.Join(",", powershell.Streams.Error.ToList().Select(x => x.Exception.Message));
return result;
}
}
}
}
Any ideas where the issue lies? code, permissions?

Passing and invoking System.Action<> from powershell to c#

I am working on a c# program using System.Speech.Recognition to recognize speech and run PowerShell commands according to what is said.
I have the following powershell script that represents a macro for creating a speech command:
Add-Type -Path ".\GAVPI.Lib.dll"
Add-Type -Path ".\GAVPI.Lib.Logging.dll"
[Action[GAVPI.Lib.Logging.Parameter]]$speechRecognized = {
param($i)
[System.Windows.MessageBox]::Show("test")
}
$parameter = New-Object -TypeName GAVPI.Lib.Logging.Parameter -ArgumentList
("parameter", "value")
$phrase = New-Object -TypeName GAVPI.Lib.Core.Triggers.Phrase -ArgumentList
("default","test", $speechRecognized, $parameter)
return $phrase
This phrase object is used to tell what commands can be said and recognized. It successfully is passed to c# like this:
var list = new List<Phrase>();
var ps = PowerShell.Create();
var run = RunspaceFactory.CreateRunspace();
ps.Runspace = run;
run.Open();
var script = ps.AddScript(".\\PowershellTemplate.ps1", true);
var result = ps.Invoke();
foreach (var psObject in result)
{
if (psObject.BaseObject is Phrase)
{
list.Add((Phrase)psObject.BaseObject);
}
}
return list;
When a command is recognized,the Phrase class invokes the Action:
public override void Run(Parameter selectedparameter)
{
if (parAction != null)
{
parAction.Invoke(selectedparameter);
}
}
private Action<Parameter> parAction;
When the program is run, if you say "test parameter" it invokes the action<parameter> in the phrase class, which invokes the script block in powershell.
I get the following exception at the parAction.Invoke(selectedparameter); line:
There is no Runspace available to run scripts in this thread. You can
provide one in the DefaultRunspace property of the
System.Management.Automation.Runspaces.Runspace type. The script block
you attempted to invoke was:
param($i)...w("test")
How do I pass the runspace to the Sysem.Action<Parameter> so that it can run the PowerShell script block?

Powershell script working on Console app but not working on ASP.NET

I Have a powershell script to connect on Skype for Business Online and it is working on powershell also on Console application but when I call from ASP.NET not working
The exception when I run through ASP.NET:
"The term 'Get-CsPowerShellEndpoint' 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"
string command = #"$PlainPassword ='****';
$UserName = '****';
$SecurePassword = $PlainPassword | ConvertTo-SecureString-AsPlainText -Force;
$SkypeOnlineCred = New - Object - TypeName System.Management.Automation.PSCredential -ArgumentList $UserName, $SecurePassword;
Remove-Variable -Name PlainPassword;
Remove-Variable -Name SecurePassword;
Remove-Variable -Name UserName;
$SkypeOnlineSession = New-CsOnlineSession Credential $SkypeOnlineCred;
Import-PSSession -Session $SkypeOnlineSession | Out-Null;";
var initial = InitialSessionState.CreateDefault();
initial.ImportPSModule(new string[] {
"C:\\Program Files\\Common Files\\Skype for Business Online\\Modules\\SkypeOnlineConnector\\SkypeOnlineConnectorStartup.psm1"
});
using (Runspace runspace = RunspaceFactory.CreateRunspace(initial))
{
// Open runspace
runspace.Open();
// Initialize PowerShell engine
using (PowerShell shell = PowerShell.Create())
{
shell.Runspace = runspace;
// Add the script to the PowerShell object
shell.Commands.AddScript(command);
try
{
// Execute the script
var results = shell.Invoke();
if (shell.Streams.Error.Count > 0)
{
throw new Exception(shell.Streams.Error[0].Exception.Message);
}
// display results, with BaseObject converted to string
// Note : use |out-string for console-like output
return results;
}
catch (Exception e)
{
throw new Exception("On Invoke" + e.Message);
}
}
}

Error when running powershell command remotely

I want to run Powershell command on remote machine. This is method that I am using (localhost:131 is because I use tunnel to remote machine's port 5985):
public string RunRemotePowerShellCommand(string command)
{
System.Security.SecureString password = new System.Security.SecureString();
foreach (char c in _password.ToCharArray())
{
password.AppendChar(c);
}
string schema = "http://schemas.microsoft.com/powershell/Microsoft.Powershell";
WSManConnectionInfo connectionInfo = new WSManConnectionInfo(false,
"localhost", 131, "/wsman", schema, new PSCredential(_domain + #"\" + _userName, password));
using (Runspace remoteRunspace = RunspaceFactory.CreateRunspace(connectionInfo))
{
remoteRunspace.Open();
using (PowerShell powershell = PowerShell.Create())
{
powershell.Runspace = remoteRunspace;
powershell.AddCommand(command);
powershell.Invoke();
Collection<PSObject> results = powershell.Invoke();
// convert the script result into a single string
StringBuilder stringBuilder = new StringBuilder();
foreach (PSObject obj in results)
{
stringBuilder.AppendLine(obj.ToString());
}
return stringBuilder.ToString();
}
}
}
I'm trying to run following command:
D:\FolderName\scriptName.ps1 -action editbinding -component "comp1","comp2","comp3","comp4"
Like this:
RunRemotePowerShellCommand(#"D:\FolderName\scriptName.ps1 -action editbinding -component ""comp1"",""comp2"",""comp3"",""comp4""");
but I get:
Error: System.Management.Automation.RemoteException: The term 'D:\FolderName\scriptName.ps1 -action editbinding -component "comp1","comp2","comp3","comp4"' is not recognized as a name of cmdlet, function, script file, or operable program. Check the spelling of the name, or if the path is included, verify that the path is correct and try again.
The method works fine with simple commands, and the command that I want to run is ok when I run it on remote machine.
Thanks in advance.
Regards,
Dusan
You need to use the powershell.AddParameter() method to add the parameters for your command. The AddCommand() call should name just the command: cmdlet name, function name, path to script, etc. From the docs:
PowerShell ps = PowerShell.Create();
ps.AddCommand("Get-Process");
ps.AddArgument("wmi*");
ps.AddCommand("Sort-Object");
ps.AddParameter("descending");
ps.AddArgument("id");
I has a similar requirement.
My solution was to create a powershell function in C# code and use it over the powershell remote session like.
using System;
using System.Management.Automation;
namespace PowerShellTest
{
class Program
{
static void Main(string[] args)
{
string func = #"function Test { Write-Host 'hello' };";
PowerShell ps = PowerShell.Create();
ps.AddScript(func);
ps.Invoke();
ps.AddCommand("Test");
ps.Invoke();
Console.WriteLine("Successfully executed function");
Console.ReadLine();
}
}
}

What is the command to access Exchange Management Tools from C# code in Exchange 2010

In Exchange 2007 this line of code is used to load the Exchange Poweshell commands snapin:
PSSnapInInfo info = rsConfig.AddPSSnapIn(
"Microsoft.Exchange.Management.PowerShell.Admin",
out snapInException);
However, this does not exist in Exchange 2010 and I am pulling my hair out trying to find out how to access the Exchange Powershell commands from C# code. Microsoft.Exchange.Management.PowerShell.Admin does not exist anywhere on the Exchange Server and I can find nothing on Google that talks about an equivalent line of code.
How do I access Exchange Management Tools from C# code in Exchange 2010?
Below is my complete code for reference, it all works until I add the line of code:
//Creating and Opening a Runspace
RunspaceConfiguration rsConfig = RunspaceConfiguration.Create();
PSSnapInException snapInException = null;
PSSnapInInfo info = rsConfig.AddPSSnapIn(
"Microsoft.Exchange.Management.PowerShell.Admin",
out snapInException);
Runspace myRunSpace = RunspaceFactory.CreateRunspace(rsConfig);
myRunSpace.Open();
//How Do I Run a Cmdlet?
//create a new instance of the Pipeline class
Pipeline pipeLine = myRunSpace.CreatePipeline();
//create an instance of the Command class
// by using the name of the cmdlet that you want to run
Command myCommand = new Command(txtCommand.Text);
//add the command to the Commands collection of the pipeline
pipeLine.Commands.Add(myCommand);
Collection<PSObject> commandResults = pipeLine.Invoke();
// iterate through the commandResults collection
// and get the name of each cmdlet
txtResult.Text = "start ....";
foreach (PSObject cmdlet in commandResults)
{
string cmdletName = cmdlet.Properties["Name"].Value.ToString();
System.Diagnostics.Debug.Print(cmdletName);
txtResult.Text += "cmdletName: " + cmdletName;
}
txtResult.Text += ".... end";
I don't know for sure, but Exchange 2010 powershell might be implemented as a powershell 2.0 module, which is loaded in a different manner. To find out, go to a system with the exchange management shell on it, and fire it up. Next, run:
ps> get-module
This will list the loaded v2 modules. I would expect the exchange one to appear if you have started the dedicated exchange management shell. If you loaded the regular powershell console, try:
ps> get-module -list
This will list all modules available to load. If you spot the right one, then you'll need to build your code against the v2 system.management.automation dll. For reasons beyond the scope of this reply, v2 powershell's assembly has the same strong name as v1's, so you cannot easily have both versions of powershell on the same machine. Build this from a machine with v2 powershell installed:
InitialSessionState initial = InitialSessionState.CreateDefault();
initialSession.ImportPSModule(new[] { *modulePathOrModuleName* });
Runspace runspace = RunspaceFactory.CreateRunspace(initial);
runspace.Open();
RunspaceInvoke invoker = new RunspaceInvoke(runspace);
Collection<PSObject> results = invoker.Invoke(*myScript*);
Hope this helps,
-Oisin
After a lot of trial and error, I finally figured this out. The problem with the code above is it works great when run against Exchange 2007 but things have changed in Exchange 2010. Instead of the snapin called "Microsoft.Exchange.Management.PowerShell.Admin", use this snapin, "Microsoft.Exchange.Management.PowerShell.E2010".
The complete code to run a Powershell command from C# looks like this. Hope this helps someone else trying to do this.
You will need references to System.Management.Automation.Runspaces, System.Collections.ObjectModel and System.Management.Automation also.
I found that the reference to System.Management.Automation had to be manually added to the csproj file itself in the ItemGroup section using notepad like this:
<Reference Include="System.Management.Automation" />
code below:
private class z_test
{
//set up
private RunspaceConfiguration rsConfig = RunspaceConfiguration.Create();
private PSSnapInException snapInException = null;
private Runspace runSpace;
private void RunPowerShell()
{
//create the runspace
runSpace = RunspaceFactory.CreateRunspace(rsConfig);
runSpace.Open();
rsConfig.AddPSSnapIn("Microsoft.Exchange.Management.PowerShell.E2010", out snapInException);
//set up the pipeline to run the powershell command
Pipeline pipeLine = runSpace.CreatePipeline();
//create the script to run
String sScript = "get-mailbox -identity 'rj'";
//invoke the command
pipeLine.Commands.AddScript(sScript);
Collection<PSObject> commandResults = pipeLine.Invoke();
//loop through the results of the command and load the SamAccountName into the list
foreach (PSObject results in commandResults)
{
Console.WriteLine(results.Properties["SamAccountName"].Value.ToString());
}
pipeLine.Dispose();
runSpace.Close();
}
}
This is what I am doing:
$sessionOptionsTimeout=180000
$sessionOptionsTimeout=180000
$so = New-PSSessionOption -OperationTimeout $sessionOptionsTimeout -IdleTimeout $sessionOptionsTimeout -OpenTimeout $sessionOptionsTimeout
$connectionUri="http://$fqdn/powershell?serializationLevel=Full;ExchClientVer=14.3.91.1"
$s = New-PSSession -ConnectionURI "$connectionUri" -ConfigurationName Microsoft.Exchange -SessionOption $so
$s | Enter-PSSession
PS>get-mailboxserver
EncryptionRequired AutoDatabaseMountDial DatabaseCopyAutoActivationPo
licy
------------------ --------------------- ----------------------------
e GoodAvailability Unrestricted
e GoodAvailability Unrestricted
Now, converting above to .net (c#) should be easy...
Essentially an exerpt from: "C:\Program Files\Microsoft\Exchange Server\V14\Bin\ConnectFunctions.ps1"
Please refer to the following function:
function _NewExchangeRunspace([String]$fqdn,
[System.Management.Automation.PSCredential]
$credential=$null,
[bool]$UseWIA=$true,
[bool]$SuppressError=$false,
$ClientApplication=$null,
$AllowRedirection=$false)
{
$hostFQDN = _GetHostFqdn
if (($fqdn -ne $null) -and ($hostFQDN -ne $null) -and ($hostFQDN.ToLower() -eq $fqdn.ToLower()))
{
$ServicesRunning = _CheckServicesStarted
if ($ServicesRunning -eq $false)
{
return
}
}
Write-Verbose ($ConnectFunctions_LocalizedStrings.res_0005 -f $fqdn)
$so = New-PSSessionOption -OperationTimeout $sessionOptionsTimeout -IdleTimeout $sessionOptionsTimeout -OpenTimeout $sessionOptionsTimeout;
$setupRegistryEntry = get-itemproperty HKLM:\SOFTWARE\Microsoft\ExchangeServer\v14\Setup -erroraction:silentlycontinue
if ( $setupRegistryEntry -ne $null)
{
$clientVersion = "{0}.{1}.{2}.{3}" -f $setupRegistryEntry.MsiProductMajor, $setupRegistryEntry.MsiProductMinor, $setupRegistryEntry.MsiBuildMajor, $setupRegistryEntry.MsiBuildMinor
$connectionUri = "http://$fqdn/powershell?serializationLevel=Full;ExchClientVer=$clientVersion"
}
else
{
$connectionUri = "http://$fqdn/powershell?serializationLevel=Full"
}
if ($ClientApplication -ne $null)
{
$connectionUri = $connectionUri + ";clientApplication=$ClientApplication"
}
write-host -fore Yellow ("connectionUri: " + $connectionUri)
$contents = 'New-PSSession -ConnectionURI "$connectionUri" -ConfigurationName Microsoft.Exchange -SessionOption $so'
if (-not $UseWIA)
{
$contents = $contents + ' -Authentication Kerberos -Credential $credential'
}
if ($SuppressError)
{
$contents = $contents + ' -erroraction silentlycontinue'
}
if ($AllowRedirection)
{
$contents = $contents + ' -AllowRedirection'
}
write-host -fore Yellow ("contents: " + $contents)
write-host -fore Yellow ("join n contents: " + [string]::join("`n", $contents))
[ScriptBlock] $command = $executioncontext.InvokeCommand.NewScriptBlock([string]::join("`n", $contents))
$session=invoke-command -Scriptblock $command
if (!$?)
{
# ERROR_ACCESS_DENIED = 5
# ERROR_LOGON_FAILURE = 1326
if (!(5 -eq $error[0].exception.errorcode) -and
!(1326 -eq $error[0].exception.errorcode))
{
#Write-Verbose ($ConnectFunctions_LocalizedStrings.res_0006 -f $fqdn)
return
}
else
{
# no retries if we get 5 (access denied) or 1326 (logon failure)
#$REVIEW$ connectedFqdn is not set. Is it okay?
break connectScope
}
}
$session
}

Categories

Resources