在 C# 中为远程安装程序应用程序创建准确的进度条

Creating an accurate progress bar for remote installer application in C#

这里是 C# 的新手,我在学习的过程中学到了很多东西。

我正在创建一个远程安装补丁的 Winforms 应用程序。基本上,您给它一个文件(.msi 或 .exe)和一个计算机列表,它会在列表中向下移动,直到安装了所有补丁。它似乎正在为我想要它做的事情工作。只需点击一下即可进行 vuln/patch 管理。作为记录,我使用 PSexec 和 powershell 来完成相同的任务,它们非常棒。自己摆弄一下,希望能在这个过程中有所学习。

我想为应用程序创建一个准确的进度条,以便管理员可以大致了解当时正在处理哪些进程。可能需要修补的系统数量范围很广,从 10 个系统到 1000 个以上不等。

我看过进度条实现的教程,但大部分都是基于代码编写者估计特定作业的任务完成时间。由于每个补丁大小、安装时间和计算机数量都不同,这似乎对我没有太大帮助。

private void Start_Click(object sender, EventArgs e)
    {
        string complist = openFileDialog2.FileName;
        string patch = textBox2.Text;
        string fileName = patch;
        string patchfile = Path.GetFileName(fileName);

        foreach (string line in File.ReadLines(complist))
        {
            //Checks if C:\PatchUpdates exists on remote machine. If not, a folder is created.
            if (!Directory.Exists(@"\" + line + @"\C$\PatchUpdates"))
            {
                Directory.CreateDirectory(@"\" + line + @"\C$\PatchUpdates");
            }

            //XCOPY patch to every computer
            System.Diagnostics.Process processCopy = new System.Diagnostics.Process();
            ProcessStartInfo StartInfo = new ProcessStartInfo();
            StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
            StartInfo.FileName = "cmd";
            StartInfo.Arguments = string.Format("/c xcopy " + patch + " " + @"\{0}\C$\PatchUpdates /K /Y", line);
            processCopy.StartInfo = StartInfo;
            processCopy.Start();
            processCopy.WaitForExit();


            //Checks filename and installs according to file type.
            if (patch.Contains(".msi"))
            {
                //Uses WMI to execute a remote command to install using msiexec.
                ConnectionOptions options = new ConnectionOptions();
                options.Impersonation = System.Management.ImpersonationLevel.Impersonate;
                ManagementScope WMIscope = new ManagementScope(
                string.Format("\\{0}\root\cimv2", line));
                WMIscope.Connect();
                ManagementClass WMIprocess = new ManagementClass(
                    WMIscope, new ManagementPath("Win32_Process"), new ObjectGetOptions());
                object[] processmsi = { @"cmd.exe /c msiexec /qn /i " + @"C:\PatchUpdates\" + patchfile + @" /norestart" };
                object result = WMIprocess.InvokeMethod("Create", processmsi);
            }

            else if (patch.Contains(".exe"))
            {
                //Uses WMI to execute a remote command to install using commandline.
                ConnectionOptions options = new ConnectionOptions();
                options.Impersonation = System.Management.ImpersonationLevel.Impersonate;
                ManagementScope WMIscope = new ManagementScope(
                    string.Format("\\{0}\root\cimv2", line));
                WMIscope.Connect();
                ManagementClass WMIprocess = new ManagementClass(
                    WMIscope, new ManagementPath("Win32_Process"), new ObjectGetOptions());
                object[] processexe = { @"cmd.exe /c C:\PatchUpdates\" + patchfile + @" /silent /norestart" };
                object result = WMIprocess.InvokeMethod("Create", processexe);
            }

            else if (patch.Contains(".msu"))
            {
                //Uses WMI to execute a remote command to install using WUSA.
                ConnectionOptions options = new ConnectionOptions();
                options.Impersonation = System.Management.ImpersonationLevel.Impersonate;
                ManagementScope WMIscope = new ManagementScope(
                    string.Format("\\{0}\root\cimv2", line));
                WMIscope.Connect();
                ManagementClass WMIprocess = new ManagementClass(
                    WMIscope, new ManagementPath("Win32_Process"), new ObjectGetOptions());
                object[] processmsu = { @"wusa " + patchfile + " /quiet /norestart" };
                object result = WMIprocess.InvokeMethod("Create", processmsu);
            }
        }
    }

上面的代码完成了大部分工作。当用户单击 "Start" 时,补丁将复制到每台计算机上的 C:\PatchUpdates 并使用 WMI 安装。

我如何制作一个进度条,该进度条基于计算完成每项任务所花费的时间,并在最后一台计算机安装补丁时以 100% 完成? 我假设需要做很多工作才能做到这一点。

感谢任何帮助。

您需要先获取行数(您的系统计数)。

如果您使用的是 .Net 4.0 或更高版本,您可以使用

var lineCount = File.ReadLines(@"C:\file.txt").Count();

否则你可以先做

var lineCount = 0;
using (var reader = File.OpenText(@"C:\file.txt"))
{
    while (reader.ReadLine() != null)
    {
        lineCount++;
    }
}

之后,您将进度条的最小值设置为 0,将最大值设置为此系统数。在 foreach 中你只需要做一个 progressbar.PerformStep.

public void loadFiles()
{
   // Sets the progress bar's minimum value to a number representing
   // no operations complete -- in this case, no files read.
   progressBar1.Minimum = 0;
   // Sets the progress bar's maximum value to a number representing
   // all operations complete -- in this case, all five files read.
   progressBar1.Maximum = Convert.ToInt(lineCount); // in our case to the number of systems
   // Sets the Step property to amount to increase with each iteration.
   // In this case, it will increase by one with every file read.
   progressBar1.Step = 1;

   // Uses a for loop to iterate through the operations to be
   // completed. In this case, five files are to be copied into memory,
   // so the loop will execute 5 times.
   for (int i = 0; i <= 4; i++)
   {
      // Inserts code to copy a file
      progressBar1.PerformStep();
      // Updates the label to show that a file was read.
      label1.Text = "# of Files Read = " + progressBar1.Value.ToString();
   }
}