使用技術
言語: C#
スクリプト: cmd.exe とコマンド
フロントエンド:WIN UI、Xaml
フレームワーク: .Net 5
- C# から自動化されたプロセスとして 10 個のソフトウェアをインストールしたいと考えています。
- 現在、ソフトウェアをインストールするために、C# Process クラスを使用して cmd.exe をプロセスとして使用しています。これは管理者として実行する必要があります。そうしないと、管理者権限のためにインストールが失敗します。
- ここでの問題は、自動化が開始されると、システムが常にすべてのソフトウェアをインストールするために UAC (ユーザー アカウント制御) ポップアップを要求することです (常に UAC ポップをスキップしたい)。
クエリ: C# プロセス クラスから cmd.exe を管理者として使用するときに、この UAC ポップを回避する方法。
他の人から提案された解決策:私のアプリケーション (WIN UI) の起動時に、cmd.exe/powershell.exe を管理者として昇格させてシングルトン プロセスを作成し、このプロセスを使用してすべてのソフトウェアをインストールします (この場合、1 回限りの UAC を取得します)。ポップアップし、これで問題ありません)。したがって、このプロセス/サービスを呼び出してすべてのコマンドを実行し、このプロセスが管理者として実行されているため、UAC ポップアップを回避できます。
提案されたソリューションのために試みられたアプローチ:
public class CmdService : IDisposable
{
private Process _cmdProcess;
private StreamWriter _streamWriter;
private AutoResetEvent _outputWaitHandle;
private string _cmdOutput;
public CmdService(string cmdPath)
{
_cmdProcess = new Process();
_outputWaitHandle = new AutoResetEvent(false);
_cmdOutput = String.Empty;
ProcessStartInfo processStartInfo = new ProcessStartInfo();
processStartInfo.FileName = cmdPath;
processStartInfo.UseShellExecute = false;
processStartInfo.RedirectStandardOutput = true;
processStartInfo.RedirectStandardInput = true;
processStartInfo.Verb = "runas";
processStartInfo.CreateNoWindow = true;
_cmdProcess.OutputDataReceived += _cmdProcess_OutputDataReceived;
_cmdProcess.StartInfo = processStartInfo;
_cmdProcess.Start();
_streamWriter = _cmdProcess.StandardInput;
_cmdProcess.BeginOutputReadLine();
}
public string ExecuteCommand(string command)
{
_cmdOutput = String.Empty;
_streamWriter.WriteLine(command);
_streamWriter.WriteLine("echo end");
_outputWaitHandle.WaitOne();
return _cmdOutput;
}
private void _cmdProcess_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
if (e.Data == null || e.Data == "end")
_outputWaitHandle.Set();
else
_cmdOutput += e.Data + Environment.NewLine;
}
public void Dispose()
{
_cmdProcess.Close();
_cmdProcess.Dispose();
_streamWriter.Close();
_streamWriter.Dispose();
}
}
}
- このアプローチでは、useShellExecute が false に設定されているため、cmd.exe プロセスは管理者として実行されません。
- useShellExecute を false に設定すると、プロセスが非管理者モードで実行されているため、ソフトウェアのインストールに失敗します。
クエリ: この場合、cmd.exe を管理者として実行する方法
アプローチ 2 : useShellExecute = true; を設定して、管理者として cmd.exe を開くプロセスを作成しました。
startInfo.FileName = "cmd.exe"; startInfo.Verb = "runas"; startInfo.UseShellExecute = true; startInfo.RedirectStandardInput = false; startInfo.Arguments = @"msiexec.exe /qn /norestart /i C:\Temp\somesoftware.msi INSTALLDIR=c:\tep\somesoftware ALLUSERS=1 REBOOT=ReallySupress /log C:\Logs\somesoftwarelog.txt"; var pro = new Process(); pro.StartInfo = startInfo; pro.Start();
問題:このアプローチでは、UseShellExecute プロパティが true になっているため、標準入力経由でコマンドを実行できません。UseShellExecute を true にすると制限があるため、標準入出力をプロセスにリダイレクトできません。
クエリ: UseShellExecute を true に設定したときに cmd.exe に入力コマンドを提供する方法
注 : WIN UI ( https://github.com/microsoft/microsoft-ui-xaml/issues/3046 )の問題により、WIN UI アプリケーションを管理者として実行できません。