Beispiel #1
0
        /// Execute action
        public override object Execute()
        {
            TimeSpan?ts = Utils.ToTimeSpan(Context.TransformStr(Timeout, Transform));

            if (!ts.HasValue || ts.Value.TotalMilliseconds == 0)
            {
                return(null);
            }

            VerboseMessage("Sleeping for {0}", ts);


            Stopwatch w       = Stopwatch.StartNew();
            var       totalMs = ts.Value.TotalMilliseconds;

            using (var s = new WaitableTimer(ts))
            {
                while (!s.WaitHandle.WaitOne(200, false))
                {
                    Context.OnProgress((int)(w.ElapsedMilliseconds / totalMs * 100));
                }
            }

            return(null);
        }
Beispiel #2
0
        /// Execute action
        public override object Execute()
        {
            string args = (GetTransformedValueStr() ?? string.Empty).Trim();

            ShellMode t = this.Mode;

            if (t == ShellMode.Auto)
            {
                if (string.IsNullOrEmpty(Verb))
                {
                    t = ShellMode.Comspec;
                }
                else
                {
                    t = ShellMode.ShellExecute;
                }
            }

            string outp   = Context.TransformStr(OutTo, Transform);
            string errorp = Context.TransformStr(ErrorTo, Transform);
            string enc    = Context.TransformStr(Encoding, Transform);
            object input  = Context.Transform(Input, Transform);

            bool redirectError  = !string.IsNullOrEmpty(errorp);
            bool redirectOutput = !string.IsNullOrEmpty(outp);

            ProcessStartInfo pi = new ProcessStartInfo();

            if (!string.IsNullOrEmpty(enc))
            {
                pi.StandardOutputEncoding = pi.StandardErrorEncoding = Utils.GetEncoding(enc);
            }
            pi.CreateNoWindow = CreateNoWindow;
            pi.WindowStyle    = WindowStyle;
            pi.ErrorDialog    = false;

            pi.WorkingDirectory = Context.TransformStr(Directory, Transform);
            if (string.IsNullOrEmpty(pi.WorkingDirectory))
            {
                pi.WorkingDirectory = Environment.CurrentDirectory;
            }


            string fileToDelete = null;


            // do a bit of clean up occasionally by deleting older xsh-batch-*.cmd files
            if (Utils.GenRandom(0, 5) == 3)
            {
                try
                {
                    VerboseMessage("Cleaning up older batch files in temp directory");
                    var dt = DateTime.UtcNow.AddDays(-1);
                    foreach (var file in new DirectoryInfo(Path.GetTempPath()).GetFileSystemInfos("xsh-batch-*.cmd"))
                    {
                        if (file.LastWriteTimeUtc < dt)
                        {
                            file.Delete();
                        }
                    }
                }
                catch
                {
                }
            }
            try
            {
                switch (t)
                {
                case ShellMode.Batch:
                    fileToDelete = Path.Combine(Path.GetTempPath(), "xsh-batch-" + Utils.GenRandom(0, int.MaxValue) + "-" + Utils.GenRandom(0, int.MaxValue) + ".cmd");
                    File.WriteAllText(fileToDelete, args, System.Text.Encoding.Default);
                    args = Utils.QuoteArg(fileToDelete);
                    if (!Wait)
                    {
                        fileToDelete = null;     // don't delete the batch if we're not waiting for it to complete
                    }
                    goto default;

                default:
                    string cmd = Utils.QuoteArg(Environment.ExpandEnvironmentVariables("%COMSPEC%"));
                    if (!string.IsNullOrEmpty(args))
                    {
                        cmd += " " + args;
                    }
                    fillFilenameAndArguments(pi, cmd);
                    pi.Arguments              = " /C \"" + pi.Arguments + "\"";
                    pi.UseShellExecute        = false;
                    pi.RedirectStandardError  = redirectError && Wait;
                    pi.RedirectStandardOutput = redirectOutput && Wait;
                    pi.RedirectStandardInput  = (input != null) && Wait;
                    break;

                case ShellMode.Direct:
                    fillFilenameAndArguments(pi, args);
                    pi.UseShellExecute        = false;
                    pi.RedirectStandardError  = redirectError && Wait;
                    pi.RedirectStandardOutput = redirectOutput && Wait;
                    pi.RedirectStandardInput  = (input != null) && Wait;
                    break;

                case ShellMode.ShellExecute:
                    pi.UseShellExecute = true;
                    fillFilenameAndArguments(pi, args);
                    if (!string.IsNullOrEmpty(Verb))
                    {
                        pi.Verb = Verb;
                    }
                    break;
                }


                TimeSpan?ts = null;
                if (!string.IsNullOrEmpty(Timeout))
                {
                    ts = Utils.ToTimeSpan(Context.TransformStr(Timeout, Transform));
                }
                VerboseMessage("Executing " + Utils.QuoteArg(pi.FileName) + " " + pi.Arguments);

                if (!string.IsNullOrEmpty(pi.UserName))
                {
                    pi.UserName = Context.TransformStr(Username, Transform);
                    var ss = new SecureString();
                    foreach (var c in (Context.TransformStr(Password, Transform) ?? string.Empty))
                    {
                        ss.AppendChar(c);
                    }
                    pi.Password        = ss;
                    pi.LoadUserProfile = LoadUserProfile;
                }

                using (ManualResetEvent terminated = new ManualResetEvent(false))
                    using (WaitableTimer timeout = new WaitableTimer(ts))
                    {
                        ExitedWithContext ect = new ExitedWithContext(terminated);
                        using (Process p = Process.Start(pi))
                        {
                            if (!string.IsNullOrEmpty(ProcessIdTo))
                            {
                                Context.OutTo(Context.TransformStr(ProcessIdTo, Transform), p.Id);
                            }
                            if (Wait && p != null)
                            {
                                Redir[] r = new Redir[2] {
                                    new Redir(Context, outp), new Redir(Context, errorp)
                                };

                                p.Exited += ect.onExited;
                                p.EnableRaisingEvents = true;


                                AsyncWriter asyncWriter = null;
                                try
                                {
                                    if (pi.RedirectStandardInput)
                                    {
                                        byte[] data;
                                        if (input is byte[])
                                        {
                                            data = ((byte[])input);
                                        }
                                        else
                                        {
                                            Encoding en = System.Text.Encoding.Default;
                                            if (string.IsNullOrEmpty(enc))
                                            {
                                                en = Utils.GetEncoding(enc);
                                            }
                                            if (en == null)
                                            {
                                                en = System.Text.Encoding.Default;
                                            }
                                            data = en.GetBytes(Utils.To <string>(input));
                                        }
                                        asyncWriter = new AsyncWriter(p.StandardInput, data);
                                    }

                                    if (pi.RedirectStandardOutput)
                                    {
                                        if (BinaryOutput)
                                        {
                                            r[0].StartRedirect(p.StandardOutput.BaseStream);
                                        }
                                        else
                                        {
                                            r[0].StartRedirect(p.StandardOutput.BaseStream, p.StandardOutput.CurrentEncoding);
                                        }
                                    }
                                    if (pi.RedirectStandardError)
                                    {
                                        r[1].StartRedirect(p.StandardError.BaseStream, p.StandardError.CurrentEncoding);
                                    }


                                    var wh = new WaitHandle[] { r[0].Event, r[1].Event, terminated, timeout.WaitHandle };
                                    do
                                    {
                                        Context.OnProgress(1);
                                        int n = WaitHandle.WaitAny(wh, 500, true);

                                        switch (n)
                                        {
                                        case 0:
                                        case 1:
                                            r[n].Flush(false);
                                            break;

                                        case 2:
                                            break; // Exit

                                        case 3:
                                            throw new TimeoutException("Command execution timed out");
                                        }
                                    } while (!p.HasExited);

                                    // must wait to ensure that all output is flushed
                                    p.WaitForExit();
                                }
                                finally
                                {
                                    try
                                    {
                                        if (!p.HasExited && !p.WaitForExit(1000))
                                        {
                                            VerboseMessage("Process didn't terminate as expected. TASKKILL will be used.");
                                            Shell sh = new Shell(Utils.BackslashAdd(Environment.GetFolderPath(Environment.SpecialFolder.System)) + "TASKKILL.EXE /T /F /pid " + p.Id);
                                            sh.CreateNoWindow = true;
                                            sh.Mode           = ShellMode.Comspec;
                                            sh.IgnoreExitCode = true;
                                            Context.InitializeAndExecute(sh);
                                            VerboseMessage("TASKKILL completed");
                                        }

                                        VerboseMessage("Waiting for process to terminate completely.");
                                        p.WaitForExit();
                                    }
                                    catch
                                    {
                                        VerboseMessage("Failed to wait until the process is terminated");
                                    }

                                    try
                                    {
                                        if (!p.HasExited)
                                        {
                                            p.Kill();
                                        }
                                    }
                                    catch
                                    {
                                        VerboseMessage("Kill failed");
                                    }
                                    r[0].Flush(true);
                                    r[1].Flush(true);
                                    r[0].Dispose();
                                    r[1].Dispose();

                                    terminated.WaitOne(1000, false);

                                    // Restore
                                    p.Exited -= ect.onExited;
                                }

                                int exitCode = p.ExitCode;
                                if (!string.IsNullOrEmpty(ExitCodeTo))
                                {
                                    Context.OutTo(Context.TransformStr(ExitCodeTo, Transform), exitCode);
                                }

                                VerboseMessage("Execution completed with exit code={0}", exitCode);
                                if (exitCode != 0 && !IgnoreExitCode)
                                {
                                    string a = Utils.QuoteArg(pi.FileName);
                                    if (!string.IsNullOrEmpty(pi.Arguments))
                                    {
                                        if (!ExtendedErrors)
                                        {
                                            a += " ... arguments ...";
                                        }
                                        else
                                        {
                                            a += " " + pi.Arguments;
                                        }
                                    }
                                    throw new ScriptRuntimeException(string.Format("Command [{0}] failed with exit code = {1}", a, p.ExitCode));
                                }
                            }
                        }
                    }
            }
            finally
            {
                if (fileToDelete != null)
                {
                    try
                    {
                        File.Delete(fileToDelete);
                    }
                    catch
                    {
                    }
                }
            }
            return(null);
        }
Beispiel #3
0
        /// Execute action
        public override object Execute()
        {
            TimeSpan? ts = Utils.ToTimeSpan(Context.TransformStr(Timeout, Transform));

            if (!ts.HasValue || ts.Value.TotalMilliseconds==0)
                return null;

            VerboseMessage("Sleeping for {0}", ts);

            Stopwatch w=Stopwatch.StartNew();
            var totalMs = ts.Value.TotalMilliseconds;
            using (var s=new WaitableTimer(ts))
            {
                while (!s.WaitHandle.WaitOne(200, false))
                    Context.OnProgress((int)(w.ElapsedMilliseconds / totalMs * 100));
            }

            return null;
        }
Beispiel #4
0
        /// Execute action
        public override object Execute()
        {
            string args = (GetTransformedValueStr()??string.Empty).Trim();

            ShellMode t = this.Mode;
            if (t == ShellMode.Auto)
            {
                if (string.IsNullOrEmpty(Verb))
                    t = ShellMode.Comspec;
                else
                    t=ShellMode.ShellExecute;
            }

            string outp = Context.TransformStr(OutTo, Transform);
            string errorp = Context.TransformStr(ErrorTo, Transform);
            string enc = Context.TransformStr(Encoding, Transform);
            object input = Context.Transform(Input, Transform);

            bool redirectError = !string.IsNullOrEmpty(errorp);
            bool redirectOutput = !string.IsNullOrEmpty(outp);

            ProcessStartInfo pi = new ProcessStartInfo();
            if (!string.IsNullOrEmpty(enc))
                pi.StandardOutputEncoding = pi.StandardErrorEncoding = Utils.GetEncoding(enc);
            pi.CreateNoWindow = CreateNoWindow;
            pi.WindowStyle = WindowStyle;
            pi.ErrorDialog = false;

            pi.WorkingDirectory = Context.TransformStr(Directory, Transform);
            if (string.IsNullOrEmpty(pi.WorkingDirectory))
                pi.WorkingDirectory = Environment.CurrentDirectory;

            string fileToDelete = null;

            // do a bit of clean up occasionally by deleting older xsh-batch-*.cmd files
            if (Utils.GenRandom(0,5)==3)
            {
                try
                {
                    VerboseMessage("Cleaning up older batch files in temp directory");
                    var dt = DateTime.UtcNow.AddDays(-1);
                    foreach (var file in new DirectoryInfo(Path.GetTempPath()).GetFileSystemInfos("xsh-batch-*.cmd"))
                    {
                        if (file.LastWriteTimeUtc<dt)
                            file.Delete();
                    }
                }
                catch
                {

                }
            }
            try
            {
                switch (t)
                {
                    case ShellMode.Batch:
                        fileToDelete = Path.Combine(Path.GetTempPath(), "xsh-batch-" +Utils.GenRandom(0, int.MaxValue) + "-" + Utils.GenRandom(0, int.MaxValue) + ".cmd");
                        File.WriteAllText(fileToDelete, args, System.Text.Encoding.Default);
                        args = Utils.QuoteArg(fileToDelete);
                        if (!Wait)
                            fileToDelete = null; // don't delete the batch if we're not waiting for it to complete
                        goto default;
                    default:
                        string cmd = Utils.QuoteArg(Environment.ExpandEnvironmentVariables("%COMSPEC%")) ;
                        if (!string.IsNullOrEmpty(args))
                            cmd += " " + args;
                        fillFilenameAndArguments(pi, cmd);
                        pi.Arguments = " /C \"" + pi.Arguments + "\"";
                        pi.UseShellExecute = false;
                        pi.RedirectStandardError = redirectError && Wait;
                        pi.RedirectStandardOutput = redirectOutput && Wait;
                        pi.RedirectStandardInput = (input != null) && Wait;
                        break;
                    case ShellMode.Direct:
                        fillFilenameAndArguments(pi, args);
                        pi.UseShellExecute = false;
                        pi.RedirectStandardError = redirectError && Wait;
                        pi.RedirectStandardOutput = redirectOutput && Wait;
                        pi.RedirectStandardInput = (input != null) && Wait;
                        break;
                    case ShellMode.ShellExecute:
                        pi.UseShellExecute = true;
                        fillFilenameAndArguments(pi, args);
                        if (!string.IsNullOrEmpty(Verb))
                            pi.Verb = Verb;
                        break;
                }

                TimeSpan? ts = null;
                if (!string.IsNullOrEmpty(Timeout))
                    ts = Utils.ToTimeSpan(Context.TransformStr(Timeout, Transform));
                VerboseMessage("Executing " + Utils.QuoteArg(pi.FileName) + " " + pi.Arguments);

                if (!string.IsNullOrEmpty(pi.UserName))
                {
                    pi.UserName = Context.TransformStr(Username, Transform);
                    var ss = new SecureString();
                    foreach (var c in (Context.TransformStr(Password, Transform) ?? string.Empty))
                        ss.AppendChar(c);
                    pi.Password = ss;
                    pi.LoadUserProfile = LoadUserProfile;
                }

                using (ManualResetEvent terminated = new ManualResetEvent(false))
                using (WaitableTimer timeout = new WaitableTimer(ts))
                {
                    ExitedWithContext ect = new ExitedWithContext(terminated);
                    using (Process p = Process.Start(pi))
                    {
                        if (!string.IsNullOrEmpty(ProcessIdTo))
                            Context.OutTo(Context.TransformStr(ProcessIdTo, Transform), p.Id);
                        if (Wait && p != null)
                        {
                            Redir[] r = new Redir[2] {new Redir(Context, outp), new Redir(Context, errorp)};

                            p.Exited += ect.onExited;
                            p.EnableRaisingEvents = true;

                            AsyncWriter asyncWriter = null;
                            try
                            {
                                if (pi.RedirectStandardInput)
                                {
                                    byte[] data;
                                    if (input is byte[])
                                        data = ((byte[]) input);
                                    else
                                    {
                                        Encoding en = System.Text.Encoding.Default;
                                        if (string.IsNullOrEmpty(enc))
                                            en = Utils.GetEncoding(enc);
                                        if (en == null)
                                            en = System.Text.Encoding.Default;
                                        data = en.GetBytes(Utils.To<string>(input));
                                    }
                                    asyncWriter = new AsyncWriter(p.StandardInput, data);

                                }

                                if (pi.RedirectStandardOutput)
                                    if (BinaryOutput)
                                        r[0].StartRedirect(p.StandardOutput.BaseStream);
                                    else
                                        r[0].StartRedirect(p.StandardOutput.BaseStream, p.StandardOutput.CurrentEncoding);
                                if (pi.RedirectStandardError)
                                    r[1].StartRedirect(p.StandardError.BaseStream, p.StandardError.CurrentEncoding);

                                var wh = new WaitHandle[] {r[0].Event, r[1].Event, terminated, timeout.WaitHandle};
                                do
                                {
                                    Context.OnProgress(1);
                                    int n = WaitHandle.WaitAny(wh, 500,true);

                                    switch (n)
                                    {
                                        case 0:
                                        case 1:
                                            r[n].Flush(false);
                                            break;
                                        case 2:
                                            break; // Exit
                                        case 3:
                                            throw new TimeoutException("Command execution timed out");
                                    }
                                } while (!p.HasExited);

                                // must wait to ensure that all output is flushed
                                p.WaitForExit();

                            }
                            finally
                            {

                                try
                                {
                                    if (!p.HasExited && !p.WaitForExit(1000))
                                    {
                                        VerboseMessage("Process didn't terminate as expected. TASKKILL will be used.");
                                        Shell sh = new Shell(Utils.BackslashAdd(Environment.GetFolderPath(Environment.SpecialFolder.System)) + "TASKKILL.EXE /T /F /pid " + p.Id);
                                        sh.CreateNoWindow = true;
                                        sh.Mode = ShellMode.Comspec;
                                        sh.IgnoreExitCode = true;
                                        Context.InitializeAndExecute(sh);
                                        VerboseMessage("TASKKILL completed");
                                    }

                                    VerboseMessage("Waiting for process to terminate completely.");
                                    p.WaitForExit();
                                }
                                catch
                                {
                                    VerboseMessage("Failed to wait until the process is terminated");
                                }

                                try
                                {
                                    if (!p.HasExited)
                                        p.Kill();
                                }
                                catch
                                {
                                    VerboseMessage("Kill failed");
                                }
                                r[0].Flush(true);
                                r[1].Flush(true);
                                r[0].Dispose();
                                r[1].Dispose();

                                terminated.WaitOne(1000, false);

                                // Restore
                                p.Exited -= ect.onExited;
                            }

                            int exitCode = p.ExitCode;
                            if (!string.IsNullOrEmpty(ExitCodeTo))
                                Context.OutTo(Context.TransformStr(ExitCodeTo, Transform), exitCode);

                            VerboseMessage("Execution completed with exit code={0}", exitCode);
                            if (exitCode != 0 && !IgnoreExitCode)
                            {
                                string a = Utils.QuoteArg(pi.FileName);
                                if (!string.IsNullOrEmpty(pi.Arguments))
                                {
                                    if (!ExtendedErrors)
                                        a += " ... arguments ...";
                                    else
                                        a += " " + pi.Arguments;
                                }
                                throw new ScriptRuntimeException(string.Format("Command [{0}] failed with exit code = {1}", a, p.ExitCode));
                            }
                        }
                    }
                }
            }
            finally
            {
                if (fileToDelete!=null)
                {
                    try
                    {
                        File.Delete(fileToDelete);
                    }
                    catch
                    {

                    }
                }
            }
            return null;
        }