I am trying to run a PowerShell script inside C# using .NET 4.6
I have tried to install the PowerShell NuGet but it doesn´t target .NET 4.6
Is there another way I could execute the PowerShell script?
I needed to specify powershell.exe to be able to run the script. But now I have another problem the PowerShell window closes immediately so I am not able to see the error message. I am using the following command
var s = Process.Start(#"Powershell.exe", $#"-noexit -ExecutionPolicy Bypass -file ""MyScript.ps1; MyFunction"" ""{arguments}""");
s.WaitForExit();
Yes, you can run it as you run any external program. System.Diagnostics.Process will help you out.
Here is a code example from Microsoft community:
using System.Diagnostics;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
Process myProcess = new Process();
myProcess.StartInfo.FileName = #"ConsoleApplication1.exe";
myProcess.StartInfo.UseShellExecute = false;
myProcess.StartInfo.RedirectStandardOutput = true;
myProcess.StartInfo.RedirectStandardInput = true;
myProcess.Start();
string redirectedOutput=string.Empty;
while ((redirectedOutput += (char)myProcess.StandardOutput.Read()) != "Enter File Name:") ;
myProcess.StandardInput.WriteLine("passedFileName.txt");
myProcess.WaitForExit();
//verifying that the job was successfull or not?!
Process.Start("explorer.exe", "passedFileName.txt");
}
}
}
ConsoleApplication1.exe should be replaced with YourApplication.ps1
Why would you ever use System.Diagnostics.Process rather than System.Management.Automation which is recommended? Because powershell is slow and if you ever need to replace it, using System.Diagnostics.Process will allow doing it immediately.
Related
I am using this function below to create powershell script
public static void joinDomain()
{
string path = #"C:\Windows\Temp\Test.ps1";
if(!File.Exists(path))
{
using (StreamWriter sw = File.CreateText(path))
{
sw.WriteLine("add-computer –domainname ad.contoso.com -Credential AD\adminuser -restart –force");
}
}
}
After successfully script creation I run that script using this below code
Classes.Functions.joinDomain();
string strCmdText = #"C:\Windows\Temp\Test.ps1";
System.Diagnostics.Process.Start("C:\\windows\\system32\\windowspowershell\\v1.0\\powershell.exe ", strCmdText);
If i run script from Powershell ISE it prompts for password so the script works.
Even calling it works but i just got blue powershell commandline and then it disseaper it wont ask for password and i dont know why.
Any ideas would be appreciated?
Found solution:
It was cause by windows restricted policy for unsigned scripts.
Solution here:
https://github.com/eapowertools/ReactivateUsers/wiki/Changing-Execution-Signing-Policy-in-Powershell
I am running processes from C# using the following code;
private static void ExecuteShellCMD(string workingDir, string commandWithArgs, bool bWait = true)
{
ProcessStartInfo info = new ProcessStartInfo();
info.Verb = "runas";
info.FileName = "cmd.exe";
info.WorkingDirectory = workingDir;
info.Arguments = "/C " + commandWithArgs;
info.UseShellExecute = false;
using (Process myProcess = Process.Start(info))
{
if (bWait)
{
myProcess.WaitForExit();
}
int ExitCode = myProcess.ExitCode;
//Log exit code here.
}
}
It loads an elevated command window and executes the code/bat file I pass it, but without logging anything to the console. This doesn't appear to be consistent on other machines, and has worked in the past on my machine, and I wondered if anyone had any ideas about how I can consistently make this Process just print logs into the command window the process makes.
I can see logs if I set UseShellExecute = true but then can't use Verb without accepting the elevation prompt which is undesirable.
I have tried looking for solutions around the web, and I am aware that I can redirect the output using other settings. Most of the questions and tutorials on this subject seem to deal with redirecting the ouput to somewhere else but I want to be able to keep track of the progress in the command window itself.
Perhaps I have missed an command line argument or similar?
Turns out this was actually a bug in Unity Hub. The process and output were working fine, however when ran from a Unity instance that was launched from Unity Hub it took control of the output and didn't release it. This was solved by just launching Unity directly and a bug report has been filed against Unity hub.
How can my C# code run git commands when it detects changes in tracked file? I am writing a VisualStudio/C# console project for this purpose.
I am new to the the .NET environment and currently working on integrating automated GIT commits to a folder. I need to automatically commit any change/add/delete on a known folder and push that to a git remote. Any guidance appreciated. Thank you.
Here is what I have and the last one is the one I need some guidance with:
Git repository initially set up on folder with proper ignore file (done).
I am using C# FileSystemWatcher to catch any changes on said folder (done).
Once my project detects a change it needs to commit and push those changes (pending).
Tentative commands the project needs to run:
git add -A
git commit "explanations_of_changes"
git push our_remote
NOTE: This code (with no user interaction) will be the only entity committing to this repo so I am not worried about conflicts and believe this flow will work.
I realize this is an old question but I wanted to add the solution I recently came across to help those in the future.
The PowerShell class provides an easy way to interact with git. This is part of the System.Management.Automation namespace in .NET. Note that System.Management.Automation.dll is available via NuGet.
string directory = ""; // directory of the git repository
using (PowerShell powershell = PowerShell.Create()) {
// this changes from the user folder that PowerShell starts up with to your git repository
powershell.AddScript($"cd {directory}");
powershell.AddScript(#"git init");
powershell.AddScript(#"git add *");
powershell.AddScript(#"git commit -m 'git commit from PowerShell in C#'");
powershell.AddScript(#"git push");
Collection<PSObject> results = powershell.Invoke();
}
In my opinion this is cleaner and nicer than using the Process.Start() approach. You can modify this to your specfic needs by editing the scripts that are added to the powershell object.
As commented by #ArtemIllarionov, powershell.Invoke() does not return errors but the Streams property has output information. Specifically powerShell.Streams.Error for errors.
If you want to do it in C#, you can call the external git command by Process.Start when you detect file change
string gitCommand = "git";
string gitAddArgument = #"add -A";
string gitCommitArgument = #"commit ""explanations_of_changes""";
string gitPushArgument = #"push our_remote";
Process.Start(gitCommand, gitAddArgument);
Process.Start(gitCommand, gitCommitArgument);
Process.Start(gitCommand, gitPushArgument);
Not the best solution but it works in C#
using System.Diagnostics;
using System.Text;
//Console.WriteLine(CommandOutput("git status"));
public static string CommandOutput(string command,
string workingDirectory = null)
{
try
{
ProcessStartInfo procStartInfo = new ProcessStartInfo("cmd", "/c " + command);
procStartInfo.RedirectStandardError = procStartInfo.RedirectStandardInput = procStartInfo.RedirectStandardOutput = true;
procStartInfo.UseShellExecute = false;
procStartInfo.CreateNoWindow = true;
if (null != workingDirectory)
{
procStartInfo.WorkingDirectory = workingDirectory;
}
Process proc = new Process();
proc.StartInfo = procStartInfo;
proc.Start();
StringBuilder sb = new StringBuilder();
proc.OutputDataReceived += delegate (object sender, DataReceivedEventArgs e)
{
sb.AppendLine(e.Data);
};
proc.ErrorDataReceived += delegate (object sender, DataReceivedEventArgs e)
{
sb.AppendLine(e.Data);
};
proc.BeginOutputReadLine();
proc.BeginErrorReadLine();
proc.WaitForExit();
return sb.ToString();
}
catch (Exception objException)
{
return $"Error in command: {command}, {objException.Message}";
}
}
Try LibGit2Sharp, a native implementation of git for .NET:
https://github.com/libgit2/libgit2sharp/
One alternative would be to setup Grunt and TaskRunner with your project.
Grunt should be able to provide the automation of detecting changes to a folder(or folders) in your project and execute the appropriate git commands to commit it.
Task Runner allows you to initialize and run Grunt from within Visual Studio.
The Visual Studio team has indicated that Task Runner is going to become integrated into future releases of Visual Studio, so this could be a long term solution.
Note: It has been mentioned in the comments, but I feel it worth mentioning again that auto-commiting anytime a file is saved to the repository isn't best practice. You want functional / atomic code changes to get pushed in, not simple text changes. Auto-Commit at your own risk.
The Package Manager Console is Powershell console. So you can run your git commands from there.
I have a c# application which uses the following code to shell out a call to a powershell script:
string scriptFileToExecute = "someScript.ps1;
var startInfo = new ProcessStartInfo();
startInfo.FileName = #"powershell.exe";
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
startInfo.UseShellExecute = false;
startInfo.CreateNoWindow = false;
startInfo.Arguments = string.Format(#"& '{0}' '{1}'", scriptFileToExecute, "argument");
var process = new Process { StartInfo = startInfo };
process.Start();
string output = process.StandardOutput.ReadToEnd();
This works ok and runs the script.
However when I include this line in the script:
Import-Module ServerManager
The script fails:
errors occurred during script execution: Import-Module : The specified module 'Servermanager' was not loaded because no valid module file was found in any module directory.
This works fine when I run the script just in powershell on the machine.
Doing a Get-Module : Format-List on the machine results in:
Name : Servermanager
Path : C:\Windows\system32\WindowsPowerShell\v1.0\Modules\Servermanager\ServerManager.psm1
Description :
ModuleType : Script
Version : 2.0.0.0
NestedModules : {Microsoft.Windows.ServerManager.PowerShell}
ExportedFunctions : {Disable-ServerManagerStandardUserRemoting, Enable-ServerManagerStandardUserRemoting}
ExportedCmdlets : {Get-WindowsFeature, Install-WindowsFeature, Uninstall-WindowsFeature}
ExportedVariables :
ExportedAliases : {Add-WindowsFeature, Remove-WindowsFeature}
and including $env:path in the shelled out script results in:
C:\Windows\system32;
C:\Windows;C:\Windows\System32\Wbem;
C:\Windows\System32\WindowsPowerShell\v1.0\;
C:\Program Files\Microsoft\Web Platform Installer\;
C:\Program Files (x86)\Microsoft ASP.NET\ASP.NET Web Pages\v1.0\;
C:\Program Files\Microsoft SQL Server\110\Tools\Binn\
and $env:PSModulePath outputs:
C:\Users\Administrator.PORTAL\Documents\WindowsPowerShell\Modules;
C:\Program Files (x86)\WindowsPowerShell\Modules;
C:\Windows\system32\WindowsPowerShell\v1.0\Modules\
Which seems to imply that it should load the module, as it exists at C:\Windows\system32\WindowsPowerShell\v1.0\Modules\Servermanager\ServerManager.psm1
I've also checked that the script runs as the same user with the same version of powershell when invoked from the app as when run from PS directly.
What could be preventing PS from loading the ServerManager module?
So it turns out to be related to the platform target. Building as AnyCPU (with the 'prefer 32bit' checkbox checked) or building as x86 and we see this issue. Building as x64 and the issue goes away on the 64bit windows I'm installing on.
Could you please try something like this:
Collection<PSObject> psResult = PowerShell.Create().AddScript(YourScriptString).Invoke()
PSObject class allows to get any property value of the object returned by the script.
ok this was working the other day and now it's not... i don't remember changing anything, but i can run this reg.exe command with the arguments below from CMD and it works fine and creates the output file. but running it in VC# it does not create the file test_output.txt???
System.Diagnostics.Process proc_cmd = new System.Diagnostics.Process();
proc_cmd.StartInfo.FileName = #"c:\windows\system32\reg.exe";
proc_cmd.StartInfo.Arguments = #"query ""HKLM\Software\test\test software"" /v BuildNumber >c:\test\test_output.txt";
proc_cmd.StartInfo.CreateNoWindow = true;
proc_cmd.StartInfo.RedirectStandardError = true;
proc_cmd.StartInfo.RedirectStandardOutput = true;
proc_cmd.StartInfo.RedirectStandardInput = true;
proc_cmd.StartInfo.UseShellExecute = false;
proc_cmd.Start();
proc_cmd.Close();
You should use the Registry class instead.
Your >output.txt is an instruction to the command interpreter (cmd.exe). That won't work calling reg.exe. Consider calling cmd.exe instead, or redirecting the stdout and writing it to the file yourself. See this SO answer link.
Of course, if there's no compelling reason to shell out to the Reg.exe, you should use the Registry class.