Tuesday, July 8, 2014

C# Using PSTool PsExec to execute programs on remote systems.

Download PSTool here
Usefull information about PSExec.exe

Class I used to execute a program (FME + extra parameters) on a remote server.

public class TrackValidator
    {
        public string DestinationDirectoryPathFromClient { get; private set; }
        public string DestinationDirectoryPathFromServer { get; private set; }

        public string TrackUploadBatchName { get; private set; }
        public FileInfo SourceFile { get; set; }
        public string CopiedSourceFileName { get; private set; }
        public string OutputSourceFileName { get; private set; }
        public string FmeExePath { get; private set; }
        public string WorkbenchPath { get; private set; }

        public string WorkbenchName { get; private set; }

        public FileInfo PsExec { get; private set; }

        public string ServerName { get; private set; }

        public string UserName { get; private set; }
        public string Password { get; private set; }

        public TrackValidator()
        {
            DestinationDirectoryPathFromClient = @"\\hictblockap022\FME\TrackUpload\";
            DestinationDirectoryPathFromServer = @"E:\FME\TrackUpload\";
            TrackUploadBatchName = "trackupload.bat";
            CopiedSourceFileName = "source.sdf";
            OutputSourceFileName = "output.sdf";

            PsExec = new FileInfo(@"c:\data\fme\PsTools\PsExec.exe");
            ServerName = @"\\hictblockap022";
            UserName = "CXP8200";
            Password = "password";

            FmeExePath = @"C:\Program Files\FME\fme.exe";

            WorkbenchPath = @"E:\FME\Workbenches\TrackUpload\";
            WorkbenchName = "trackupload.fmw";
        }

        private void CreateBatch()
        {
            if(SourceFile == null)
                throw new Exception("Undefined Sourcefile.");
            if(!SourceFile.Exists)
                throw  new Exception("Sourcefile doesn't exist.");

            const char c = '"';

            using (var sw = new StreamWriter(DestinationDirectoryPathFromClient + TrackUploadBatchName))
            {
                sw.WriteLine(c + FmeExePath + c + " " + WorkbenchPath + WorkbenchName);
                sw.WriteLine(@"--SourceDataset_SDF3 " + DestinationDirectoryPathFromServer + CopiedSourceFileName);
                sw.WriteLine(@"--TOLERANCE_VAL 0.01");
                sw.WriteLine(@"--DestDataset_SDF3 " + DestinationDirectoryPathFromServer + OutputSourceFileName);
            }
        }

        private void CreateSource()
        {
            File.Copy(SourceFile.FullName, DestinationDirectoryPathFromClient + CopiedSourceFileName);
        }

        private void RemoveBatch()
        {
            if(File.Exists(DestinationDirectoryPathFromClient + TrackUploadBatchName))
                File.Delete(DestinationDirectoryPathFromClient + TrackUploadBatchName);
        }

        private void RemoveOutput()
        {
            if(File.Exists(DestinationDirectoryPathFromClient + OutputSourceFileName))
                File.Delete(DestinationDirectoryPathFromClient + OutputSourceFileName);
        }

        private void RemoveSource()
        {
            if (File.Exists(DestinationDirectoryPathFromClient + CopiedSourceFileName))
                File.Delete(DestinationDirectoryPathFromClient + CopiedSourceFileName);
        }

        public void Upload()
        {
            RemoveBatch();
            RemoveSource();
            RemoveOutput();

            CreateSource();
            CreateBatch();

            string arg = ServerName + @" cmd.exe -u " + UserName + @" -p " + Password + @" /c " + DestinationDirectoryPathFromServer + TrackUploadBatchName;

            var p = new Process
            {
                StartInfo =
                {
                    UseShellExecute = false,
                    RedirectStandardOutput = true,
                    RedirectStandardError = true,
                    RedirectStandardInput = true,
                    FileName = PsExec.FullName,
                    Arguments =  arg,
                    CreateNoWindow = true
                }
            };
            p.Start();

            string output = p.StandardOutput.ReadToEnd();
            string errormessage = p.StandardError.ReadToEnd();

            p.WaitForExit();

            RemoveSource();
            RemoveBatch();
        }

    }

3 comments:

  1. As a rule of thumb: if something implements IDisposable, You really should call Dispose/Close or use using(...) on it. Note that calling Close on a process does not cause the process to exit.

    ReplyDelete
  2. Also when waiting for a process to exit, u should really check it with a valid timeout, if it gets blocked by anything, then you can decide what to do with it:

    It could look something like this... (btw, have no idea how to format code here so ill show it here: http://nopaste.info/5587abfded.html )

    ReplyDelete
  3. I'll look into it. Thanks for the head up.

    ReplyDelete