Backup IIS settings with Windows Process - c#

I can backup the settings of IIS with the following commands
//sites
C:\Windows\system32\inetsrv\appcmd.exe list site /config /xml > C:\Temp\iis_config_sites.xml
//apppools
C:\Windows\system32\inetsrv\appcmd.exe list apppool /config /xml > C:\Temp\iis_config_apppool.xml
When I run these commands from the Command Prompt it works fine. The XML files are created. But I wanted to automate this process by executing this command from C# code with System.Diagnostics.Process. For that I use the following code
using (Process process = new Process())
{
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.FileName = #"C:\Windows\system32\inetsrv\appcmd.exe";
startInfo.Arguments = #"list site /config /xml > C:\Temp\iis_config_sites.xml";
process.StartInfo = startInfo;
process.Start();
process.WaitForExit();
}
But when I run this code nothing happens. The XML file is not created. But there are no errors and no warnings also. The program that executes this command runs under the Administrator account with Windows Server 2019 and IIS 10. I also tried adding WorkingDirectory, but that did not help either.
I use Process to generate a zipped folders with WinRar and that also works fine.
So if anyone knows what could be the problem that would be great.

The problem is that you are using '>' in the parameters, which is a CMD command to instruct it to write the output of command (appcmd.exe in this case) to specified file path (C:\Temp\iis_config_sites.xml). Which of course doesn't work as the parameter of appcmd.exe.
You have two options:
To use it the following way, which is equivalent of executing the command in CMD:
startInfo.FileName = #"C:\Windows\system32\cmd.exe";
startInfo.Arguments = "/c \"C:\\Windows\\system32\\inetsrv\\appcmd.exe\" list site /config /xml > C:\\Temp\\iis_config_sites.xml";
Note that the /c is a command line option of cmd.exe to execute the rest of parameters as a "command", just as if you entered it into command line window. The rest is just the same command which you typed in the cmd normally.
Use another option provided by appcmd.exe for backing up IIS that avoids the need to redirect output to file. The command is appcmd.exe add backup %backupname%. This command adds a backup of the IIS config and later you can restore it by restore backup $backupname%.

Related

Running un-elevated command from an elevated C# exe or vice versa

I have an elevated C# exe file that can run elevated commands using System.Diagnostics.Process just fine, however I need to run a specifically unelevated command - that being subst. I am not sure whether I should (or respectively could) make a secondary .exe file or .bat or something?
There is an alternative, as there is only one command that requires admin privileges to run - that being a WSL mount command. Can I make the C# script unelevated and just elevate that one specific command, or vice versa?
I've tried using runas /trustlevel:0x20000, but that throws an access denied (even though the directory being accessed by the SUBST command is \\WSL$\
As for the alternative solution I've tried the following code:
startInfo startInfo = new ProcessStartInfo();
startInfo.FileName = "cmd.exe";
startInfo.Arguments = $"/c powershell -command wsl --mount \\.\PHYSICALDRIVE1 --partition 2;pause"
startInfo.Verb = "runas";
Process proc = Process.Start(startInfo)
proc.WaitForExit();
That opens up an UAC prompt, opens up an elevated powershell Window, but for some reason doesn't recognize "WSL" as a command, even when using it's absolute path.
Fixing either method would fix the issue.

Process.Start() results in Access Denied exception despite Full Control for Everyone group

My project output contains an executable called key_gen.exe that I'm trying to run. The executable is not built by the project, but copied in after the fact. With the code below I receive an Access Denied exception.
string key_gen_dir = Environment.CurrentDirectory.Substring(0, Environment.CurrentDirectory.LastIndexOf("\\")) + #"\Scripts\key_gen\";
Process process = new Process();
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = key_gen_dir + "key_gen.exe";
startInfo.Arguments = String.Format(". {0}", password);
process.StartInfo = startInfo;
process.Start();
The FileName value is correct and works when tested in Command Prompt. I do not want to run the program as an administrator. I have tried enabling UseShellExecute, but I receive a PlatformNotSupportedException. The key_gen_dir and all subfiles and folders have FullControl permissions for the Everyone group. If it's relevant, my project is targetted for .NET Standard 2.0.
I was able to resolve the access denied error by editing the file properties in Windows and adding the ALL APPLICATION PACKAGES group to the file permissions with Read & Execute allowed.

PSEXEC runs successfully via command prompt but fails in ASP .Net/C#

I'm trying to run a command on remote machine using PSEXEC tool, it runs successfully using command prompt but it fails in an asp.net project showing the following output error.
PsExec v2.11 - Execute processes remotely Copyright (C) 2001-2014 Mark
Russinovich Sysinternals - www.sysinternals.com
The handle is invalid.
Connecting to lnxdevx...
Starting PSEXESVC service on lnxdevx...
Connecting with PsExec service on lnxdevx...
Error deriving session key:.
Here is my sample c# code.
Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.RedirectStandardInput = true;
p.StartInfo.FileName = #"C:\Windows\System32\PsExec.exe";
p.StartInfo.Arguments = "-u xxxxxx -p xxxxxxxxxx \\\\lnxdevx -i -d -w \"C:\\DIRECTORY\" cmd.exe /C dir";
p.Start();
string output = p.StandardOutput.ReadToEnd();
string errormessage = p.StandardError.ReadToEnd();
p.WaitForExit();
The problem is that you don't have to open psexec, but cmd and from there you run psexec.
The code you're trying to do is wrong too, you need to use
System.Diagnostics.Process process = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
startInfo.FileName = "cmd.exe"; \\if it is in System32
startInfo.Arguments = "psexec -u xxxxxx -p xxxxxxxxxx \\machine *your stuff*";
process.StartInfo = startInfo;
process.Start();
I'm not testing, but I'm quite sure this will work :)
Although the accepted answer is solving the problem, there is a better solution (at least without involving cmd).
Go to the app pool -> Advanced Settings -> Section "Process Model" -> "Load User Profile".
The default is false. When you change it to true, everything should work.
A bit more of what there is (more of an interpretation, further research is needed).
psexec and all tools from SysInternals require EULA to be accepted. This can be solved by calling them with -accepteula see psexec at ss64
this should be saved in the registry. You have to have a profile for this to be read.
Based on https://nigglingaspirations.blogspot.com/2015/04/psexec-error-deriving-session-key.html

run command line (cmd) that require "Security Message"

I want to run the command line pnputil in c# program. The program needs to install USB driver.
I know how to run cmd in c# program, but I have a different problem:
The driver that I want to install does't have permission of windows.
If I Install the driver via the "device manager->update driver" and choose the path of the driver, I get "Security Message" from windows that "windows can't verify the publisher of this drive software" and let me choose if install the driver or not (of course, if I choose to install - the installing succeeds).
If I run the command from the cmd pnputil -a <path_name_inf> I get this message too and I can install the driver.
But when I try to run the command via c# program - the program runs but the driver is not installed (I also don't get this message).
my code in c#:
System.Diagnostics.Process process = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
startInfo.FileName = "cmd.exe";
startInfo.Arguments = #"/C Pnputil -a <path_name_inf>";
process.StartInfo = startInfo;
process.Start();
How can I do that?
You could try to run the cmd using the runas verb:
startInfo.Verb = "runas";
startInfo.UseShellExecute = true;
This parameter causes a privileges elevation. The same thing could be reached when you use "Run as administrator" in explorer.
Your questions is more towards installing unsigned drivers.
Can you please try following steps:
Open a command prompt as an admin and type:
bcdedit -set TESTSIGNING ON
Please refer MSDN link for more infromation on Test Signing. Making Test signing may put a watermark as TEST in desktop waterpaper
I know this is old, but I wanted to share my solution in case it can help someone else.
My specific scenario is that I wanted to add an unsigned driver package to the driver store on Windows 7 Home Premium 64-bit.
Like the OP, this worked as expected (meaning I received the security warning and the driver package was added to the driver store) if I executed pnputil -a <path_to_inf> using a command prompt using "Run as administrator".
However, if I tried to call pnputil from within C#, I was never able to get the security warning and the driver package was not added to the driver store. I had tried using various options (i.e. Verb = "runas", UseShellExecute = true, etc) with the FileName set as "pnputil" or "cmd".
Ultimately, what worked for me was to create a simple batch file that contained the following:
%windir%\sysnative\pnputil /a <path_to_inf>
My C# app would then call this batch file as follows:
Process proc = new Process();
proc.StartInfo.FileName = "<path_to_bat_file>";
proc.StartInfo.Verb = "runas";
proc.StartInfo.UseShellExecute = true;
proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
proc.StartInfo.CreateNoWindow = true;
proc.Start();
The user would first be prompted because I asked to run with elevated permission followed by the expected security warning. The driver package would then be added to the driver store as expected.
If this does not work as expected, you can add "pause" (without quotes) on a new line after the last command in the batch file and remove the WindowStyle and CreateNoWindow lines from the C# code to see what is happening on the command prompt.

Executing a batch file from Windows Forms application

I have written a small batch file that copies an exe from solution to the system32 folder.
copy "blah.exe" "%systemroot%/System32"
The batch file works fine and copies the exe if ran from the desktop by double clikcing (placed exe on the desktop as well)
However, I tried doing that from Windows Application by:
Process.Start("sample.bat");
(EXE file and batfile -> Properties -> Output to Copy Always)
The cmd window does come up, but the .exe file is not there in the destination directory. What am I missing here?
in your batch file change path to that particular folder where you have blah.exe, change to the particular drive and then to particular folderlets say your source folder is C:\test then type cd\test in the batch file, it should be something like:
C:
cd\test
copy "blah.exe" "%systemroot%/System32"
or use copy with complete path e.g
copy "C:\test\blah.exe" "%systemroot%/System32"
EDIT:
To copy using CMD try:
System.Diagnostics.Process process = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
startInfo.FileName = "cmd.exe";
startInfo.Arguments = "/C copy /b blah.exe %systemroot%/System32";
process.StartInfo = startInfo;
process.Start();
Edit 2: Or for batch file
System.Diagnostics.Process.Start("cmd", "/c sample.bat");

Categories