2 Pluspunkte 0 Minuspunkte

Ich lese Daten von einem Powershell Prozess aus und lade das Ergebnis in einen Gridview. Um den UI Thread nicht zu blockieren habe ich einen asynchronen Task daraus gemacht.

using System;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace AKM_Patcher_Server
{
    public partial class Programs64 : Form
    {
        public Programs64()
        {
            InitializeComponent();
            InitializeDataGridView();
            dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;

            if (Form1.Instance.currentAgent != String.Empty)
            {
                FetchProcesses(Form1.Instance.currentAgent);
                textBoxServerName.Text = Form1.Instance.currentAgent;
            }
        }

        private void InitializeDataGridView()
        {
            dataGridView1.Columns.Clear();
            dataGridView1.Columns.Add("Name", "Name");
            dataGridView1.Columns.Add("Version", "Version");
            dataGridView1.Columns.Add("Vendor", "Hersteller");
            dataGridView1.Columns.Add("Uninstaller", "Uninstaller");
        }

        private async void btnFetchProcesses_Click(object sender, EventArgs e)
        {
            string serverName = textBoxServerName.Text.Trim();
            if (string.IsNullOrEmpty(serverName))
            {
                MessageBox.Show("Bitte geben Sie einen Servernamen ein.", "Fehler", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }

            await FetchProcesses(serverName);
        }

        private async Task FetchProcesses(string serverName)
        {
            try
            {
                dataGridView1.Rows.Clear();

                ProcessStartInfo psi = new ProcessStartInfo
                {
                    FileName = "powershell.exe",
                    Arguments = "-ExecutionPolicy Bypass -NoProfile -Command \"Invoke-Command -ComputerName " + serverName + " -ScriptBlock { Get-ItemProperty HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\* | select DisplayName,DisplayVersion,Publisher,UninstallString | ConvertTo-Csv -Delimiter ';' -NoTypeInformation }\"",
                    RedirectStandardOutput = true,
                    UseShellExecute = false,
                    CreateNoWindow = true
                };

                using (Process process = new Process { StartInfo = psi })
                {
                    process.Start();
                    string output = process.StandardOutput.ReadToEnd();
                    process.WaitForExit();

                    string[] lines = output.Split('\n');
                    foreach (var line in lines.Skip(1)) // Erste Zeile ist die Kopfzeile von CSV
                    {
                        var values = line.Split(';');
                        if (values.Length >= 4 && values[0].Trim() != "")
                        {

                            dataGridView1.Rows.Add(
                                values[0].Trim(), // Name
                                values[1].Trim(), // Process ID
                                values[2].Trim(), // CPU
                                values[3].Trim()  // Arbeitsspeicher
                            );
                        }
                    }
                }

            }
            catch (Exception ex)
            {
                MessageBox.Show("Fehler beim Abrufen der Prozessinformationen: " + ex.Message, "Fehler", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
    }
}

Kann ich das Programm so ändern das sobald eine Zeile vom Ergebnis gelesen wurde die Row gleich in den Gridview eingefügt wird und nicht erst nachdem alle fertig geladen wurden?

von  

1 Antwort

1 Pluspunkt 0 Minuspunkte

Du kannst das OutputDataReceived Ereignis von Process überschreiben. Dadurch wird direkt die von dir überschriebene Funktion aufgerufen, sobald eine neue Zeile verfügbar ist.

using System;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace AKM_Patcher_Server
{
    public partial class Programs64 : Form
    {
        public Programs64()
        {
            InitializeComponent();
            InitializeDataGridView();
            dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;

            if (Form1.Instance.currentAgent != String.Empty)
            {
                FetchProcesses(Form1.Instance.currentAgent);
                textBoxServerName.Text = Form1.Instance.currentAgent;
            }
        }

        private void InitializeDataGridView()
        {
            dataGridView1.Columns.Clear();
            dataGridView1.Columns.Add("Name", "Name");
            dataGridView1.Columns.Add("Version", "Version");
            dataGridView1.Columns.Add("Vendor", "Hersteller");
            dataGridView1.Columns.Add("Uninstaller", "Uninstaller");
        }

        private async void btnFetchProcesses_Click(object sender, EventArgs e)
        {
            string serverName = textBoxServerName.Text.Trim();
            if (string.IsNullOrEmpty(serverName))
            {
                MessageBox.Show("Bitte geben Sie einen Servernamen ein.", "Fehler", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }

            await FetchProcesses(serverName);
        }

        private async Task FetchProcesses(string serverName)
        {
            try
            {
                dataGridView1.Rows.Clear();

                ProcessStartInfo psi = new ProcessStartInfo
                {
                    FileName = "powershell.exe",
                    Arguments = "-ExecutionPolicy Bypass -NoProfile -Command \"Invoke-Command -ComputerName " + serverName + " -ScriptBlock { Get-ItemProperty HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\* | select DisplayName,DisplayVersion,Publisher,UninstallString | ConvertTo-Csv -Delimiter ';' -NoTypeInformation }\"",
                    RedirectStandardOutput = true,
                    UseShellExecute = false,
                    CreateNoWindow = true
                };

                Process process = new Process { StartInfo = psi };

                // Hier sagst du dem prozess das er für empfangene Daten deine Methode aufruft
                process.OutputDataReceived += Process_OutputDataReceived;

                process.Start();
                process.BeginOutputReadLine();
                await Task.Run(() => process.WaitForExit());
            }
            catch (Exception ex)
            {
                MessageBox.Show("Fehler beim Abrufen der Prozessinformationen: " + ex.Message, "Fehler", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        // Diese Methode behandelt neue Daten und trägt sie in Echtzeit in den DataGridView ein
        private void Process_OutputDataReceived(object sender, DataReceivedEventArgs e)
        {
            if (!string.IsNullOrEmpty(e.Data))
            {
                string[] values = e.Data.Split(';');
                if (values.Length >= 4 && !string.IsNullOrWhiteSpace(values[0]))
                {
                    Invoke(new Action(() =>
                    {
                        dataGridView1.Rows.Add(
                            values[0].Trim(), // Name
                            values[1].Trim(), // Version
                            values[2].Trim(), // Hersteller
                            values[3].Trim()  // Uninstaller
                        );
                    }));
                }
            }
        }
    }
}
von (1.3k Punkte)