How to call PowerShell script with azure commands in C# windows application - c#

Below is my event, where, if I pass, simple powershell script it runs fine, but if I pass script contains any Azure commands, output is blank. (That azure command script is running fine from powershell command prompt)
private void RunScript_Click(object sender, EventArgs e)
{
string result = "";
PSDataCollection<PSObject> myOutPut = new PSDataCollection<PSObject>();
try
{
InitialSessionState initial = InitialSessionState.CreateDefault();
initial.ImportPSModule(new string[] {
#"C:\Program Files\WindowsPowerShell\Modules\AzureRM\5.2.0\AzureRM.psd1",
});
using (Runspace objRunSpace = RunspaceFactory.CreateRunspace(initial))
{
objRunSpace.Open();
using (PowerShell objPowerShell = PowerShell.Create())
{
objPowerShell.Runspace = objRunSpace;
string Script = textBoxURL.Text;
objPowerShell.AddScript(Script);
objPowerShell.AddCommand("Out-String");
IAsyncResult IvokeResult = objPowerShell.BeginInvoke<PSObject, PSObject>(null, myOutPut);
while (IvokeResult.IsCompleted == false)
{
System.Threading.Thread.Sleep(100);
}
foreach (PSObject outitem in myOutPut)
{
result += outitem.ToString();
}
}
}
textBoxOutPut.Text = result;
}
catch (Exception ex)
{
}
}

Based on my test, there is no issue with you mentioned code. I can get empty output if input a wrong command. So please make sure that your command is correct.
Another import thing is that make sure that the command it has ouput. I test the azure command Add-AzureRmAccount.

Where is you connection to Azure?
You load the module, but you have nothing establishing a connection to Azure to use the cmdlets.
In your native PoSH instance/session, you'd to have this to work:
# Set creds
$AdminCreds = Get-Credential -Credential 'admin#domain.com'
# Connect to Azure AD
Connect-AzureAD -Credential $Admincreds
Account Environment TenantId TenantDomain AccountType
------- ----------- -------- ------------ -----------
admin#contoso.onmicrosoft.com AzureCloud 11... contoso.onmicrosoft.com User
If not, you'd end up with errors like this...
Get-AzureADApplication
Get-AzureADApplication : You must call the Connect-AzureAD cmdlet before calling any other cmdlets.
At line:1 char:1
+ Get-AzureADApplication
+ ~~~~~~~~~~~~~~~~~~~~~~

Related

Force reboot a remote computer using c# powershell

I'm trying to create a powershell script inside c# that will allow my company to paste a computer name in the field, click restart, and then force a restart on a remote computer.
Here's what I have:
private void button1_Click(object sender, EventArgs e) {
string pcName = textBox1.Text;
Runspace runspace = RunspaceFactory.CreateRunspace();
runspace.Open();
Pipeline pipeline = runspace.CreatePipeline();
runspace.SessionStateProxy.SetVariable("Computer", pcName);
var script = string.Format("Restart-Computer -ComputerName " + pcName + " -Credential Get-Credential GLMC\\Admin -Force");
pipeline.Commands.AddScript(script);
Collection<PSObject> results = pipeline.Invoke();
runspace.Close();
StringBuilder sB = new StringBuilder();
foreach (PSObject pSObject in results)
sB.AppendLine(pSObject.ToString());
textBox2.Text = sB.ToString();
}
Taken from this powershell script (that works):
$Computer = Read-Host 'Enter computer name' -Verbose
$Creds = Get-Credential GLMC\Admin
Write-Host -ForegroundColor Yellow "Starting process..."
Restart-Computer -ComputerName $Computer -Credential $Creds -Force
$End= Read-Host 'Finished, press enter to continue' -Verbose
I keep getting an error in the credentials part that says A command that prompts the user failed because the host program or the command type does not support user interaction.
Instead of adding a text script to the pipeline, pass it properly as a Command with parameters. You should also add -Confirm $false.
You also need to find a way to get credentials without using Get-Credential. You could just prompt the user and create a PSCredential from that.
var creds = new PSCredential("GLMC\Admin", AskForSecurePassword());
pipeline.Commands
.AddCommand("Restart-Computer")
.AddParameter("ComputerName", pcname)
.AddParameter("Credential", creds)
.AddParameter("Force")
.AddParameter("Confirm", false);
Collection<PSObject> results = pipeline.Invoke();
I suggest you find a better way of passing credentials. Ideally you would require the whole application to be launched with admin rights, then you wouldn't need to pass the credentials separately, just rely on what it has already.

Invoke-Command on Hyper-V VM Powershell C#

I am trying but failing in every way to invoke a command on Hyper-V managed VM via C# / Powershell. I can run various other PS commands without any issue, plus I can also run the Invoke-Command directly in Powershell cmd.
My main aim will be to run / execute remote processes on the VMs. I am currently using a script block to {Get-Childitem C:\Windows} to list the directories, just to get some output for testing.
In Powershell if I run:
Invoke-Command -VMName Windows10 -ScriptBlock {Get-Childitem C:\\Windows}
It works after being prompted with credentials.
My C# code that fails and I have tried numerous ways to get this working with no avail.
public static void Test()
{
var scBlock = ScriptBlock.Create("{Get-Childitem C:\\Windows}");
// Create a PSCredential
var cred = CreateCredential("test", "test");
using (var ps = PowerShell.Create())
{
var initial = InitialSessionState.CreateDefault();
var runspace = RunspaceFactory.CreateRunspace(initial);
runspace.Open();
ps.Runspace = runspace;
ps.AddCommand("Invoke-Command");
ps.AddParameter("VMName", "Windows10");
ps.AddParameter("ScriptBlock", scBlock);
ps.AddParameter("Credential", cred);
ps.Streams.Progress.DataAdded += (sender, ev) =>
{
var progressRecords = (PSDataCollection<ProgressRecord>)sender;
Console.WriteLine("Progress is {0} percent complete",
progressRecords[ev.Index].PercentComplete);
};
ps.Streams.Warning.DataAdded += (sender, ev) =>
{
var warnings = (PSDataCollection<WarningRecord>)sender;
var message = warnings[ev.Index].Message;
Console.WriteLine($"WARNING - {message}");
};
ps.Streams.Error.DataAdded += (sender, ev) =>
{
var error = (PSDataCollection<ErrorRecord>)sender;
var message = error[ev.Index].Exception?.Message;
Console.WriteLine($"ERROR - {message}");
};
try
{
var results = ps.Connect();
foreach (var tPsObject in results)
{
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
I get the following errors in the console:
ERROR - Configuration system failed to initialize
ERROR - The input VMName Windows10 does not resolve to a single virtual machine.
I am only using Powershell within C# as it seems to be the easiest/most common way to manage Hyper-V virtual machines.
A side question, is there a way to run all of the above from a non-elevated process. E.g I don't want to run my application as Administrator.

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();
}
}
}

how to invoke the powershell command with "format-list" and "out-file" pipeline from c#?

Hi I'm working on a C# program to call exchange 2010 powershell cmdlets in remote runspace. The ps command is:
"Get-MailboxDatabase -Server EX2010SVR1 -Status | Format-List
Identity,Guid,mounted,CircularLoggingEnabled,Recovery | Out-File
'C:\db.txt' -Encoding UTF8 -Width 8192".
My code is similar to:
static int Main(string[] args)
{
const string SHELL_URI = "http://schemas.microsoft.com/powershell/Microsoft.Exchange";
const string COMMAND = "Get-MailboxDatabase -Server EX2010SVR1 -Status | Format-List Identity,Guid,mounted,CircularLoggingEnabled,Recovery | Out-File 'C:\db.txt' -Encoding UTF8 -Width 8192";
System.Uri serverUri = new Uri("http://EX2010SVR1/powershell?serializationLevel=Full");
PSCredential creds = (PSCredential)null; // Use Windows Authentication
WSManConnectionInfo connectionInfo = new WSManConnectionInfo(serverUri, SHELL_URI, creds);
try
{
using (Runspace rs = RunspaceFactory.CreateRunspace(connectionInfo))
{
rs.Open();
PowerShell psh = PowerShell.Create();
psh.Runspace = rs;
psh.AddCommand(COMMAND);
Collection results = psh.Invoke();
rs.Close();
}
}
catch (Exception ex)
{
System.Console.WriteLine("exception: {0}", ex.ToString());
}
return 0;
}
When I run the c# program on Win2008 R2 which is hosting exchange 2010 server, I always get exception:
System.Management.Automation.RemoteException: The term 'Format-List' 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.
at System.Management.Automation.PowerShell.CoreInvoke[TOutput](IEnumerable input, PSDataCollection`1 output, PSInvocationSettings settings)
at System.Management.Automation.PowerShell.Invoke(IEnumerable input, PSInvocationSettings settings)
at System.Management.Automation.PowerShell.Invoke()
at RemotePS.Program.Main(String[] args)
The program is working fine without "Format-List" and "Out-File" pipelines. The entire command is also working fine in exchange 2010 management shell. I also confirmed it's powershell 2.0 on the system.
Could any one help to figure out what's going on? Any help is much appreciated.
Tom
I've got the same problem with the first embeded PowerShell I wrote. I look for a trace, but I can't find it anymore.
Here is something working for me that I adapt to your code :
static void Main(string[] args)
{
const string SHELL_URI = "http://schemas.microsoft.com/powershell/Microsoft.PowerShell";
const string COMMAND = #"get-process | format-List | Out-File -file c:\temp\jpb.txt";
System.Uri serverUri = new Uri("http://WM2008R2ENT/powershell?serializationLevel=Full");
PSCredential creds = (PSCredential)null; // Use Windows Authentication
WSManConnectionInfo connectionInfo = new WSManConnectionInfo(false,
"WM2008R2ENT",
5985,
"/wsman",
SHELL_URI,
creds);
try
{
using (Runspace rs = RunspaceFactory.CreateRunspace(connectionInfo))
{
rs.Open();
Pipeline pipeline = rs.CreatePipeline();
string cmdLine;
cmdLine = string.Format("&{{{0}}}", COMMAND);
pipeline.Commands.AddScript(cmdLine);
Collection<PSObject> results = pipeline.Invoke();
rs.Close();
}
}
catch (Exception ex)
{
System.Console.WriteLine("exception: {0}", ex.ToString());
}
return;
}
Be carefull, I'am not using Exchange PowerShell
In the example I use pipeline, perhaps your problem comes from the way you pass the command.
You can try to work with the 'Command'-Object.
Runspace rs = RunspaceFactory.CreateRunspace();
PowerShell ps = PowerShell.Create();
Pipeline pipeline = rs.CreatePipeline();
Command cmd1 = new Command("Get-MailboxDatabase");
cmd1.Parameters.Add("Server", "EX2010SVR1");
cmd1.Parameters.Add("Status");
pipeline.Commands.Add(cmd1);
Command cmd2 = new Command("Format-List");
cmd2.Parameters.Add("Property", "Identity, Guid, mounted, CircularLoggingEnabled, Recovery");
pipeline.Commands.Add(cmd2);
Command cmd3 = new Command("Format-List");
cmd3.Parameters.Add("FilePath", "C:\db.txt");
cmd3.Parameters.Add("Encoding", "UTF8");
cmd3.Parameters.Add("Width", "8192");
pipeline.Commands.Add(cmd3);
Collection<PSObject> output = pipeline.Invoke();
See also here: Invoking powershell cmdlets from C#
I realize this is an old thread, but I wanted to present my findings, however short they are.
I ran into this same problem just recently with a colleague of mine. We managed to track the problem down to the missing runspaces. We also had to connect to the Microsoft.Exchange runspace and when we do it, the Format-List commandlet becomes unavailable. If we don't use the runspace, the commandlet works just fine.
We didn't get to solving it yet, but I intend to explore the possibility of using the RunspacePool instead of just Runspace, thus allowing the execution of both commandlets in the pipeline.

Categories

Resources