How to pass arguments to the power shell script from c#?/ [duplicate] - c#

This question already has answers here:
Execute PowerShell Script from C# with Commandline Arguments
(9 answers)
Closed 4 years ago.
How can i call the below PowerShell script from c# .. by passing arguments to Powershell script from c# (my arguments are string and list types)
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = #"powershell.exe";
//provide powershell script full path
**startInfo.Arguments = #"& 'C:\powershell-scripts\call-from-c-sharp.ps1'";**
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
startInfo.UseShellExecute = false;
startInfo.CreateNoWindow = true;
Process process = new Process();
process.StartInfo = startInfo;
// execute script call start process
process.Start();
// get output information
string output = process.StandardOutput.ReadToEnd();
// catch error information
string errors = process.StandardError.ReadToEnd();
------------------------------------------------------------------------------
Function Server($x,[string]$lsstr)
{
Remove-Item -Path D:\vamc\Powershell_scripts\di.txt
$server=$x
#Invoke-WmiMethod -ComputerName $server
foreach($act in $lsstr)
{
If( $act -eq 1 )
{
Remove-Item -Path D:\vamc\Powershell_scripts\di1.txt
}
ElseIf($act -eq 2)
{
Remove-Item -Path D:\vamc\Powershell_scripts\di2.txt
}
ElseIf($act -eq 3)
{
Remove-Item -Path D:\vamc\Powershell_scripts\di3.txt
}
ElseIf($act -eq 4)
{
Remove-Item -Path D:\vamc\Powershell_scripts\di4.txt
}
Else
{
Write-Host "Invalid selection"
}
}
}
Server
Can you please give me the detail code explanation.
I want to call the below PowerShell script from c# by using the same code.

PowerShell powerShell = PowerShell.Create();
// Add and invoke your PS script
powerShell.AddCommand("Import-Module").AddParameter("Name", "path\yourPSScript.ps1");
powerShell.Invoke();
powerShell.Commands.Clear();
//Add your function
powerShell.AddCommand("Server");
//Add attributes
powerShell.AddParameter("parameter1", value);
powerShell.AddParameter("parameter2", value);
//invoke
powerShell.Invoke();

Related

Powershell read the output of the process is already running

I have a powershell script which runs an exe and get its output which is working fine, but the issue that i am facing is that if the process is already running then it is not able to capture the output.
Below is my code
$pinfo = New-Object System.Diagnostics.ProcessStartInfo
$pinfo.FileName = "E:\Program Files (x86)\Consul_Ent\Bin\consul.exe"
$pinfo.Arguments = "agent -config-dir E:\Consul_Ent\Configuration\Client"
$pinfo.UseShellExecute = $false
$pinfo.CreateNoWindow = $false
$pinfo.RedirectStandardInput = $true
$pinfo.RedirectStandardOutput = $true
$pinfo.RedirectStandardError = $true
$pinfo.EnvironmentVariables["GOMAXPROCS"] = (Get-WmiObject Win32_Processor | measure -p NumberOfLogicalProcessors -sum).Sum
$process = New-Object System.Diagnostics.Process
$process.StartInfo = $pinfo
[Void]$process.Start()
$process.BeginOutputReadLine()
$process.BeginErrorReadLine()
try
{
while (!$process.WaitForExit(1))
{
}
Write-Host "WaitForExit(1)"
}
finally
{
# give the thread gracefully shutdown
Start-Sleep -s 3
}
so as the process is not terminated yet and hence it is not able to read the output as it tries to create a new instance, i want it to create a new instance only if process is not running but if it is running i just want to capture the output.

How to execute "Set-ProcessMitigation -Name myapplication.exe -Enable PreferSystem32" PowerShell command from WPF application

I am trying to execute a PowerShell command Set-ProcessMitigation -Name myapplication.exe -Enable PreferSystem32 from my WPF application. But the PowerShell window just opens and then closes, without the script being executed.
The code
C# file MainWindow.xaml.cs
public void Run_scripts()
{
var ps1File = #"-NoExit C:\pwsh.ps1";
var startInfo = new ProcessStartInfo()
{
FileName = "powershell.exe",
Arguments = $"-ExecutionPolicy Bypass -WindowStyle Hidden -NoProfile -file \"{ps1File}\""
UseShellExecute = true
RedirectStandardOutput = true
};
try
{
var proc = Process.Start(startInfo);
MessageBox.Show("Powershell Command Executed");
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
PowerShell script pwsh.ps1
Write-Output "power shell executed";
Set-ProcessMitigation -Name Wireless#SGx.exe -Enable PreferSystem32;

How to call Powershell script using web API (cs or asp.net)

Below is the function to keep server in SCOM maintenance mode and I would like to call this function through cs or asp.net as API call by passing variables.
function set-scomderegister {
param(
[Parameter( Mandatory = $True, ValueFromPipeline = $true)][string]
$SCOMServer,
[Parameter( Mandatory = $True, ValueFromPipeline = $true)]
$Computername
)
ForEach($Comp in $Computername)
{
New-SCManagementGroupConnection -ComputerName $SCOMServer
$numberOfMin = 100
$ReasonComment = "Server got docomissioned "
$Instance = Get-SCOMClassInstance -Name $Comp
$Time = ((Get-Date).AddMinutes($numberOfMin))
Start-SCOMMaintenanceMode -Instance $Instance -EndTime $Time -Comment $ReasonComment -Reason PlannedOther;
}
}
System.Management.Automation namespace would be useful for you.
You can install a nuget package "System.Management.Automation".
Once this is installed you will have this namespace available.
You can invoke a script with parameter as shown below:
public void RunWithParameters()
{
// create empty pipeline
PowerShell ps = PowerShell.Create();
// add command
ps.AddCommand("test-path").AddParameter("Path", Environment.CurrentDirectory); ;
var obj = ps.Invoke();
}
private string RunScript(string scriptText)
{
// 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);
// add an extra command to transform the script
// output objects into nicely formatted strings
// remove this line to get the actual objects
// that the script returns. For example, the script
// "Get-Process" returns a collection
// of System.Diagnostics.Process instances.
pipeline.Commands.Add("Out-String");
// execute the script
Collection<psobject /> results = pipeline.Invoke();
// 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();
}
There is another option to use Process.Start to start the powershell prompt. Then pass the file path to the process.
public static int RunPowershellScript(string ps)
{
int errorLevel;
ProcessStartInfo processInfo;
Process process;
processInfo = new ProcessStartInfo("powershell.exe", "-File " + ps);
processInfo.CreateNoWindow = true;
processInfo.UseShellExecute = false;
process = Process.Start(processInfo);
process.WaitForExit();
errorLevel = process.ExitCode;
process.Close();
return errorLevel;
}
Hope this helps.

Execute Powershell script in C# without UserName and Password

How I will execute the Powershell script in C# without use of UserName and Password?
Powershell Script:
#Script:This Script generate the Package (Zip file) dynamically for unittest
#DirectoryName is Out Directory of Unittest execution
#location is Out\Resource Directory
#locationdetail is Array of files Directory for generate the Package
#FileName is name of Package generated through this script
#option is use for switch case implementation,currently not implemented
param(
[string]$DirectoryName="."
, [string]$location=""
, [string]$FileName="Test.zip"
, [int] $option
)
[System.Reflection.Assembly]::LoadFrom($DirectoryName+"\\"+"Ionic.Zip.dll");
$locationdetail = "Package\\Resource", "Package\\ResourceBad", "Package\\ResourceEmptymetada","Package\\ResourceEmptydatafile","Package\\EmptyTest"
$directoryToZip=""
foreach ($element in $locationdetail)
{
If($element -eq "Package\\Resource")
{
$directoryToZip= $location+"\\"+"Package\\Resource"
$FileName ="Package (Good Data).zip"
}
If($element -eq "Package\\ResourceBad")
{
$directoryToZip= $location+"\\"+"Package\\ResourceBad"
$FileName ="Package (Bad Data).zip"
}
If($element -eq "Package\\ResourceEmptymetada")
{
$directoryToZip= $location+"\\"+"Package\\ResourceEmptymetada"
$FileName ="Package (Bad with ManifestEmpty).zip"
}
If($element -eq "Package\\ResourceEmptydatafile")
{
$directoryToZip= $location+"\\"+"Package\\ResourceEmptydatafile"
$FileName ="Package (Bad with Datafile Empty).zip"
}
If($element -eq "Package\\EmptyTest")
{
$directoryToZip= $location+"\\"+"Package\\EmptyTest"
$FileName ="EmptyTest.zip"
}
$zipfile = new-object Ionic.Zip.ZipFile
$e= $zipfile.AddDirectory($directoryToZip)
$zipfile.Save( $location+"\\"+$FileName)
$zipfile.Dispose()
$directoryToZip=""
}
and My C# code
private static void StartPowerShell(string args,string TempScript)
{
string powerShellPath ="C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe";
string commandLine = #" -Sta -Command ""& {{ try {{ {0} }} catch {{throw}} }} """.InvariantCultureFormat(args);
var info = new ProcessStartInfo();
info.FileName = powerShellPath;
info.Arguments = commandLine;
info.WorkingDirectory = Environment.CurrentDirectory;
info.UseShellExecute = false;
info.CreateNoWindow = false;
info.RedirectStandardError = true;
info.RedirectStandardOutput = true;
//Pass the Username and Password here in ProcessStartInfo
info.UserName = "Saroop";
string pw = "saroop";
System.Security.SecureString password = new System.Security.SecureString();
foreach (var item in pw)
{
password.AppendChar(item);
}
info.Password = password;
info.RedirectStandardError = true;
info.RedirectStandardOutput = true;
Process p = new Process();
p.StartInfo = info;
bool flag = p.Start();
string error = p.StandardError.ReadToEnd();
p.WaitForExit();
}
Please guide me anyone. I try to use runas command to start my Powershell.exe as a User(Administrator) but it's also ask for Username and Password.
I try for System.Management.Automation. dll but it's no more existed in .Net4.0
Reference link :
http://msdn.microsoft.com/en-us/library/system.management.automation(v=vs.85).aspx
Please help me.
What you wrote in the comment will works, but i'd like to give you another direction to run powershell scripts from C# code.
You can use System.Management.Automation.Runspaces namespace which expose really easy and more elegant way to run powershell commands and retrieve the results from C# (and using the returned objects and not just the output textual stream). Try to read about it.
I found the answer of my query .
FOR EXECUTE THE POWERSHELL SCRIPT MUST EXECUTE THE POLICY COMMAND FOR
SYSTEM32
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
AND IF YOUR SYSTEM IS 64BIT THEN ALSO EXECUTE SAME POLICY FOR 64BIT POWERSHELL.EXE TOO.
C:\Windows\SysWOW64\WindowsPowerShell\v1.0\POWERSHELL.EXE
/// COMMAND : `Set-ExecutionPolicy Unrestricted`

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