Execute Powershell script in C# without UserName and Password - c#

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`

Related

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.

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

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

powershell script unable to locate certain files when executed from a windows service

I have a powershell script which spits out file information for a given file. The script is executed in a process from a windows service like so:
Process p = new Process();
ProcessStartInfo s = new ProcessStartInfo();
s.FileName = "powershell.exe";
s.Arguments = "./script.ps1";
s.RedirectStandardOutput = true;
s.RedirectStandardError = true;
s.UseShellExecute = false;
s.CreateNoWindow = true;
p.StartInfo = s;
p.EnableRaisingEvents = true;
/* ... defined output handlers ... */
p.Start();
p.BeginOutputReadLine();
p.BeginErrorReadLine();
The powershell script is as follows:
function ChangeDir($dir)
{
try
{
echo ("Attempting to change directory: {0}" -f ($dir))
Set-Location -Path $dir -ErrorAction Stop
}
catch
{
echo $error[0].Exception
}
}
function OutputFileInfo($filePath)
{
try
{
echo ("Attempting to read file: {0}" -f ($filePath))
$file = #(Get-ChildItem $filePath -ErrorAction Stop)
for ($i = 0; $i -lt $file.Count; $i++)
{
echo ("{0},{1}" -f ($file[$i].Name, $file[$i].Length))
}
}
catch
{
echo $error[0].Exception
}
}
ChangeDir "/Windows/System32/drivers"
OutputFileInfo "tcpip.sys"
The output when running the powershell script from the command line is as I expect it to be:
Attempting to change directory: /Windows/System32/drivers
Attempting to read file: tcpip.sys
tcpip.sys,2773400
When the script executes via the windows service the output is this:
Attempting to change directory: /Windows/System32/drivers
Attempting to read file: tcpip.sys
Cannot find path 'C:\Windows\System32\drivers\tcpip.sys' because it does not exist.
For other files it works perfectly fine from the command line and the service. Could it have something to do with the service running the powershell script as SYSTEM which somehow doesn't have access to that file? Although if that were the case I would expect a permissions error instead of a file not found error.
Ok.... this was because system32/drivers is not accessible for 32bit applications that run on 64bit machines and I didn't realize I had my application set to the default in visual studio which I guess is 32bit. I changed it to 64bit and it works from the service now.

Running powershell from process acts different then from PowerShell ISE

I've got PowerShell script that acts like expected if I run it from PowerShell ISE.
$ol = #()
$ProcessActive = Get-Process outlook -ErrorAction SilentlyContinue
if($ProcessActive -eq $null)
{
$ol = New-Object -comObject Outlook.Application
}
else
{
$ol = [Runtime.InteropServices.Marshal]::GetActiveObject("Outlook.Application")
}
$file = "c:\testfile.pdf"
$mail = $ol.CreateItem(0)
$Mail.Recipients.Add("test#test.nl")
$mail.Subject = "This is a subject"
$mail.HTMLBody = "<html><body><h3>Hello world</h3></body></html>"
$mail.Attachments.Add($file)
$inspector = $mail.GetInspector
$inspector.Display()
However ... if I start a process in C# to execute the script it will only work if the Outlook process is not running.
var filename = "script.ps1";
var fullname = path + filename;
if (System.IO.File.Exists(fullname))
{
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = #"powershell.exe";
startInfo.Arguments = string.Format(#"& '{0}'", fullname);
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
startInfo.UseShellExecute = false;
startInfo.CreateNoWindow = true;
Process process = new Process();
process.StartInfo = startInfo;
process.Start();
process.WaitForExit();
System.IO.File.Delete(fullname);
}
The process eventually ends execution and the file is deleted in both cases (outlook running or not).
What do I need to change in order to let the script execute properly when started from a C# process (even if Outlook is running)?
Thanks in advance.
In order to answer what the difference was between script and process I've created a log of the process that was running the script. To create the log i've used
System.IO.File.WriteAllText(#"c:\log.txt",process.StandardError.ReadToEnd())
First the exception was: missing references. After fixing the missing reference by adding at the top of the powershell script :
Add-Type -Path 'Dir\To\Dll'
After that I received another error:
Exception calling "GetActiveObject" with "1" argument(s): "Operation unavailabl
e (Exception from HRESULT: 0x800401E3 (MK_E_UNAVAILABLE))"
I've read some articles and this has to do with that Outlook does not allow different users 'using' the running instance (current user vs admin-like current user running script). I'm now using the Microsoft.Office.Interop.Outlook dll to open a new email window and the console application that executes it can run as current user without the need of admin rights. This solved my problem: i'm now able to open a new email window even if outlook is already running.

wraping powershell script from C#

i'm trying to wrap an already made powershell script with C# GUI client.
the script acts according to inputs from the user, and it has also outputs according to them.
i would like to get the powershell outputs, display them to my C# client and
and then to enter the input according to his choice.
this is my script, and the code below is what i came up to but it doesn't work.
(i can only get the output at the end, and only if i don't have Read-Host in my powershell script). hope that it helps some how.
Write-Host
Write-Host 'Hello World!'
Write-Host "Good-bye World! `n"
$option = Read-Host "Please enter your number"
switch ($option){
"1"
{
Write-Host "jack"
}
"2"
{
Write-Host "john"
}
"3"
{
Write-Host "joe"
}
}
public void WrapPowerShell()
{
string directory = Directory.GetCurrentDirectory();
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = #"powershell.exe";
startInfo.Arguments = string.Format(#"& '{0}'", directory + #"\hello.ps1");
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
startInfo.UseShellExecute = false;
startInfo.CreateNoWindow = false;
Process process = new Process();
process.StartInfo = startInfo;
process.Start();
string output = process.StandardOutput.ReadToEnd();
// Assert.IsTrue(output.Contains("StringToBeVerifiedInAUnitTest"));
string errors = process.StandardError.ReadToEnd();
}
Big Thanks in advance For your answers!!
This is a helper class that I wrote to help me create an ASP.NET web app that allowed people to run powershell scripts.
PSHelper.cs
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.Text;
namespace admin_scripts {
public class PSHelper {
// See the _ps_user_lookup method for demonstration of using this method
public static Runspace new_runspace() {
InitialSessionState init_state = InitialSessionState.CreateDefault();
init_state.ThreadOptions = PSThreadOptions.UseCurrentThread;
init_state.ImportPSModule(new[] { "ActiveDirectory", "C:\\ps_modules\\disable_user.psm1" });
// Custom PS module containing functions related
// to disabling AD accounts at work.
// You would use your own module here, obviously.
return RunspaceFactory.CreateRunspace(init_state);
}
// This method is for dead-simple scripts that you only want text output from
// Not as flexible as the previous method, but it's good for the really simple cases
public static string run_simple_script( string body ) {
Runspace runspace = new_runspace();
runspace.Open();
Pipeline pipeline = runspace.CreatePipeline();
pipeline.Commands.AddScript(body);
pipeline.Commands.Add("Out-String");
Collection<PSObject> output = pipeline.Invoke();
runspace.Close();
StringBuilder sb = new StringBuilder();
foreach( PSObject line in output ) {
sb.AppendLine(line.ToString());
}
return sb.ToString();
}
}
}
I would invoke a script from an ASP.NET handler like so:
private PSObject _ps_user_lookup( string id_param ) {
Runspace runspace = PSHelper.new_runspace();
runspace.Open();
using( Pipeline pipe = runspace.CreatePipeline() ) {
Command cmd = new Command("Get-ADUser");
cmd.Parameters.Add(new CommandParameter("Identity", id_param));
cmd.Parameters.Add(new CommandParameter("Properties", "*"));
cmd.Parameters.Add(new CommandParameter("Server", "REDACTED"));
pipe.Commands.Add(cmd);
return pipe.Invoke().FirstOrDefault();
}
}
The real beauty of this arrangement is that the web application would run the script using the credentials of the web user's domain account. I hope you find it useful.

Categories

Resources