Exemple #1
0
        /// <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);
            }
        }