Passing Variables from C# to Powershell - c#

I am working on a C# project that that is supposed to grab a string variable (file path) and pass it to PowerShell script to have further commands done with it. I have been looking around online and through Stack and have not been able to find something that works for me...
Here is my C# code as it stands right now:
string script = System.IO.File.ReadAllText(#"C:\my\script\path\script.ps1");
using (Runspace runspace = RunspaceFactory.CreateRunspace())
{
runspace.Open();
PowerShell ps = PowerShell.Create();
ps.Runspace = runspace;
ps.AddScript(script);
ps.Invoke();
ps.AddCommand("LocalCopy");
foreach (PSObject result in ps.Invoke())
{
Console.WriteLine(result);
}
}
Here is my PowerShell script:
Function LocalCopy
{
Get-ChildItem -path "C:\Users\file1\file2\file3\" -Filter *.tib -Recurse |
Copy-Item -Destination "C:\Users\file1\file2\local\"
}
What I want to do is have the first part of the the script: "C:\Users\file1\file2\file3\" replaced with (what i am assuming would be) a variable that I could pass from the C# code to the PowerShell script. I am very new to working with PowerShell and am not quite sure how I would go about doing something like this.
---EDIT---
I am still having issues with my code, but i am not getting any errors. I believe that it is because the variable is still not being passed through...
C# code:
string script = System.IO.File.ReadAllText(#"C:\my\script\path\script.ps1");
using (Runspace runspace = RunspaceFactory.CreateRunspace())
{
runspace.Open();
PowerShell ps = PowerShell.Create();
ps.Runspace = runspace;
ps.AddScript(script);
ps.Invoke();
ps.AddArgument(FilePathVariable);
ps.AddCommand("LocalCopy");
foreach (PSObject result in ps.Invoke())
{
Console.WriteLine(result);
}
}
PowerShell code:
Function LocalCopy
{
$path = $args[0]
Get-ChildItem -path $path -Filter *.tib -Recurse |
Copy-Item -Destination "C:\Users\file1\file2\local\"
}
Any help would be much appreciated. Thanks!

I would go the route Anand has shown to pass a path into your script. But to answer the question posed by your title, here's how you pass variable from C#. Well this is really how you set the variable in the PowerShell engine.
ps.Runspace.SessionStateProxy.SetVariable("Path", #"C:\Users\file1\file2\file3\");
Note: in C# for file paths you really want to use verbatim # strings.
Update: based on your comments, try this:
runspace.Open();
PowerShell ps = PowerShell.Create();
ps.Runspace = runspace;
ps.AddScript(script, false); // Use false to tell PowerShell to run script in current
// scope otherwise LocalCopy function won't be available
// later when we try to invoke it.
ps.Invoke();
ps.Commands.Clear();
ps.AddCommand("LocalCopy").AddArgument(FilePathVariable);
ps.Invoke();

ps.AddArgument("C:\Users\file1\file2\file3\");
you can use args to fetch the argument in powershell.
$path = $args[0]
MSDN

Related

How to run PowerShell comands in C#

In cmd I write this and it works (this command removes N first lines from file):
powershell.exe
$file = "C:\Test\file.txt"
$content = Get-Content $file
$content[10..($content.length-1)]|Out-File $file -Force
I want to write this code on C# but my way isn't correct. Can you explain why?
using (PowerShell ps = PowerShell.Create())
{
ps.AddCommand($"$file = \"{fullPathToTxt}\"")
.AddCommand("$content = Get-Content $file")
.AddCommand($"$content[{numLine}..($content.length-1)]|Out-File $file -Force")
.Invoke();
}
Instead of AddCommand, i have to use AddScript method.
You can use this command for execute powershell script
PowerShell ps = PowerShell.Create();
ps.AddScript(File.ReadAllText(#"D:\PSScripts\MyScript.ps1")).Invoke();

Powershell return different results running the same script from c#

I am trying to run a simple script for getting file attributes.
string script = #"$path = 'C:\Temp\Indexing\Asm1.asm'
$shell = New-Object -COMObject Shell.Application
$folder = Split-Path $path
$file = Split-Path $path -Leaf
$shellfolder = $shell.Namespace($folder)
$shellfile = $shellfolder.ParseName($file)
0..500 | Foreach-Object { '{0} = {1}' -f $shellfolder.GetDetailsOf($null, $_), $shellfolder.GetDetailsOf($shellfile, $_).toString()}";
Runspace runspace = RunspaceFactory.CreateRunspace();
runspace.Open();
Pipeline pipeline = runspace.CreatePipeline();
pipeline.Commands.AddScript(script);
pipeline.Commands.Add("Out-String");
Collection<PSObject> results = pipeline.Invoke();
runspace.Close();
When running within powershell I get more attribute results which are empty when running it through the code.
It seems like an access issue.
any help will be much appreciated!
Try adding #!/usr/bin/env pwsh as first line of the script.

powershell cmdlet C#?

I'm tired to search about way to use powershell in C#, this first time to use Powershell and I don't know how to add it in C#, i have my codes working in Powershell any help to add in C#?
New-Item -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\SpecialAccounts"
New-Item -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\SpecialAccounts\UserList"
New-ItemProperty -path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\SpecialAccounts\UserList" -name BigBear -value "0" -propertyType DWord
(BigBear) it's name and I want to change it with textbox
i tried this
private void Shell()
{
using (var runspace = RunspaceFactory.CreateRunspace())
{
// using (var powerShell = PowerShell.Create())
// {
// powerShell.Runspace = runspace;
// powerShell.AddScript(#"Hidden.ps1");
// //powerShell.AddParameter("UserName", UserName.Text);
// powerShell.Invoke();
// }
using (var powerShell = PowerShell.Create())
{
powerShell.Runspace = runspace;
powerShell.AddCommand("New-Item -Path \"HKLM:\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\SpecialAccounts\"");
powerShell.AddCommand("New-Item -Path \"HKLM:\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\SpecialAccounts\\UserList\"");
powerShell.AddCommand("New-ItemProperty -path \"HKLM:\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\SpecialAccounts\\UserList\" -name " + UserName.Text + " -value \"0\" -propertyType DWord");
//powerShell.AddParameter("ParamA", varA);
var results = powerShell.Invoke();
// Do whatever with results
}
}
What have you tried?
Here are some links that describes how it can be done. But your question is not very detailed on your requirements... The last one have code you can download and try/modify!
https://blogs.msdn.microsoft.com/kebab/2014/04/28/executing-powershell-scripts-from-c/
http://www.codeproject.com/Articles/18229/How-to-run-PowerShell-scripts-from-C

Return powershell variable value to c# application

I am running powershell script from c#.
string scriptPath = "/script/myscript.ps1";
Runspace runspace = RunspaceFactory.CreateRunspace();
runspace.Open();
Pipeline pipeline = runspace.CreatePipeline();
pipeline.Commands.AddScript(scriptPath);
Collection<PSObject> results = pipeline.Invoke();
for example if my myscript.ps1 file below;
$test=4
$test++
$test
How to get the variable test value after executing the script. I need to get that value to my c# program.
I know I am late to this, but in your script, you need to add global: in front of the variable you want to return in the Powershell script, so for example:
$global:test = 4
in Powershell script. In C# after you open the runspace, invoke the policy changer, set up the pipline, you do
var result = runspace.SessionStateProxy.PSVariable.GetValue("test");
string variable_to_return_from_ps_script = "test";
// create Powershell runspace
Runspace runspace = RunspaceFactory.CreateRunspace();
runspace.Open();
//
// here you write the code to invoke the PS script, pipeline, pass parameters etc...
// just like the code you already have
//
// and here's how you retrieve a variable test from PS
var out_var = runspace.SessionStateProxy.PSVariable.GetValue(variable_to_return_from_ps_script);
Console.WriteLine("Variable ${0} value is: ", variable_to_return_from_ps_script);
Console.WriteLine(out_var.ToString());

Running powershell in C#, not having much luck!

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.

Categories