/// <summary> /// Initializes a new instance of the <see cref="Process"/> class to execute /// system commands using the system command prompt ("cmd.exe"). /// <para> /// This can be useful for an unprivileged application as a simple way to /// execute a command with the highest user permissions, for example. /// </para> /// </summary> /// <param name="command"> /// The command to execute. /// </param> /// <param name="runAsAdmin"> /// <see langword="true"/> to start the application with administrator /// privileges; otherwise, <see langword="false"/>. /// </param> /// <param name="processWindowStyle"> /// The window state to use when the process is started. /// </param> /// <param name="dispose"> /// <see langword="true"/> to release all resources used by the /// <see cref="Process"/> component, if the process has been started; /// otherwise, <see langword="false"/>. /// </param> public static Process Send(string command, bool runAsAdmin = false, ProcessWindowStyle processWindowStyle = ProcessWindowStyle.Hidden, bool dispose = true) { try { var trimChars = new[] { '\t', '\n', '\r', ' ', '&', '|' }; var cmd = command?.Trim(trimChars) ?? throw new ArgumentNullException(nameof(command)); if (processWindowStyle == ProcessWindowStyle.Hidden && cmd.StartsWithEx("/K ")) { cmd = cmd.Substring(3).TrimStart(); } if (!cmd.StartsWithEx("/C ", "/K ")) { cmd = $"/C {cmd}"; } if (cmd.Length < 16) { throw new ArgumentInvalidException(nameof(command)); } #if any || x86 var path = ComSpec.SysNativePath; #else var path = ComSpec.DefaultPath; #endif var anyLineSeparator = cmd.Any(TextEx.IsLineSeparator); if (anyLineSeparator || (path + cmd).Length + 4 > 8192) { var sb = new StringBuilder(); var file = FileEx.GetUniqueTempPath("tmp", ".cmd"); var content = cmd.Substring(2).TrimStart(trimChars); if (content.StartsWithEx("@ECHO ON", "@ECHO OFF")) { var start = content.StartsWithEx("@ECHO ON") ? 8 : 9; content = content.Substring(start).TrimStart(trimChars); sb.AppendLine(processWindowStyle == ProcessWindowStyle.Hidden || start == 9 ? "@ECHO OFF" : "@ECHO ON"); } var loopVars = Regex.Matches(content, @"((\s|\""|\'|\=)(?<var>(%[A-Za-z]{1,32}))(\s|\""|\'|\)))").Cast <Match>().ToArray(); if (loopVars.Any()) { var indicator = 0; content = loopVars.Select(m => m.Groups["var"].Index + ++indicator) .Aggregate(content, (s, i) => $"{s.Substring(0, i)}%{s.Substring(i)}"); } var exit = content.EndsWithEx("EXIT /B %ERRORLEVEL%", "EXIT /B !ERRORLEVEL!", "EXIT /B", "EXIT %ERRORLEVEL%", "EXIT !ERRORLEVEL!", "EXIT"); if (exit) { if (content.EndsWithEx("%ERRORLEVEL%", "!ERRORLEVEL!")) { content = content.Substring(0, content.Length - 12).TrimEnd(trimChars); } content = content.Substring(0, content.Length - (content.EndsWithEx("EXIT") ? 4 : 7)).TrimEnd(trimChars); } sb.AppendLine(content); sb.AppendFormatCurrent("DEL /F /Q \"{0}\"", file); File.WriteAllText(file, sb.ToStringThenClear()); cmd = $"/C CALL \"{file}\" & EXIT"; } var psi = new ProcessStartInfo { Arguments = cmd, FileName = path, UseShellExecute = runAsAdmin, Verb = runAsAdmin ? "runas" : string.Empty, WindowStyle = processWindowStyle }; var p = ProcessEx.Start(psi, dispose); if (Log.DebugMode > 1) { Log.Write($"COMMAND EXECUTED: {cmd.Substring(3)}"); } return(p); } catch (Exception ex) when(ex.IsCaught()) { Log.Write(ex); return(null); } }