NeoGenesis521
NeoGenesis521

Reputation: 43

How to collect network stats using powershell or class from remote machine in c#?

I am trying to explore and find an approach that will provide me with an outputs that looks into the network statistics per each connection. I know that powershell provides the overall statistics of the network like

(using WSMan)
pipeline.AddCommand("Get-NetTCPConnection");
pipeline.AddCommand("Select-Object").AddArgument("LocalAddress, LocalPort, RemoteAddress, RemotePort, State, OwningProcess");

pipeline.AddCommand("Get-NetAdapterStatistics");
pipeline.AddCommand("Select-Object").AddArgument("InterfaceAlias, OutgoingBytes, IncomingBytes");
LocalAddress  LocalPort  RemoteAddress  RemotePort  State       OwningProcess
-----------------------------------------------------------------------------------------------------
192.168.1.10  49242      93.184.216.34  80         ESTABLISHED  1234
192.168.1.10  49243      93.184.216.34  443        ESTABLISHED  1235

InterfaceAlias  OutgoingBytes  IncomingBytes
-------------------------------------------------
Ethernet        1000000         2000000
Wi-Fi           500000          1500000

Is there a class that I can use that will provide this information?

What I am expecting the output would be similar to the one below

--------------------------------------------------------
Local Address: 192.168.1.10
Local Port: 443
Remote Address: 203.0.113.5
Remote Port: 12345
State: Established
Bytes Sent: 1048576
Bytes Received: 2048000
Packets Sent: 512
Packets Received: 768
Owning Process ID: 1234
--------------------------------------------------------

My approach on Getting the IPv4Address and other parameters:

using System;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.Collections.ObjectModel;

class Program
{
    static void Main()
    {
        string remoteMachine = "RemoteMachine"; 
        string username = "user";               
        string password = "password";               

        // WSMan connection info
        PSCredential credentials = new PSCredential(username, new System.Security.SecureString());
        foreach (char c in password) credentials.Password.AppendChar(c);

        WSManConnectionInfo connectionInfo = new WSManConnectionInfo(
            new Uri($"http://{remoteMachine}:5985/wsman"),
            "http://schemas.microsoft.com/powershell/Microsoft.PowerShell",
            credentials
        );

        // Create a runspace
        Runspace runspace = RunspaceFactory.CreateRunspace(connectionInfo);
        runspace.Open();

        // Create the pipeline 
        using (PowerShell pipeline = PowerShell.Create())
        {
            // Execute remotely
            pipeline.Runspace = runspace;
            // Add the Get-NetIPConfiguration command to the pipeline
            pipeline.AddCommand("Get-NetIPConfiguration");
            pipeline.AddCommand("Select-Object").AddParameter("Property", new string[] { "InterfaceAlias", "IPv4Address", "InterfaceIndex", "InterfaceDescription", "NetProfile", "IPv4DefaultGateway", "DNSServer" });


            try
            {
                // Results
                Collection<PSObject> results = pipeline.Invoke();

                if (results.Count > 0)
                {

                    foreach (PSObject result in results)
                    {
                        Console.WriteLine("InterfaceAlias     : " + result.Members["InterfaceAlias"]?.Value);
                        Console.WriteLine("InterfaceIndex     : " + result.Members["InterfaceIndex"]?.Value);
                        Console.WriteLine("InterfaceDescription: " + result.Members["InterfaceDescription"]?.Value);
                        Console.WriteLine("NetProfile Name    : " + result.Members["NetProfile"]?.Value);
                        Console.WriteLine("IPv4Address        : " + result.Members["IPv4Address"]?.Value);
                        Console.WriteLine("IPv4 DefaultGateway: " + result.Members["IPv4DefaultGateway"]?.Value);
                        Console.WriteLine("DNSServer          : " + result.Members["DNSServer"]?.Value);
                        Console.WriteLine();
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error executing the pipeline: " + ex.Message);
            }
        }

        // Close the runspace
        runspace.Close();
    }
}

my outcome are the following:

InterfaceAlias     : Ethernet1
InterfaceIndex     :
InterfaceDescription:
NetProfile Name    :
IPv4Address        : MSFT_NetIPAddress (Name = ";P?9;!K5???9F66F66;99;", CreationClassName = "", SystemCreationClassName = "", SystemName = "")
IPv4 DefaultGateway:
DNSServer          :

I tried to follow like this structure:

enter image description here

WQL Queries

Upvotes: 1

Views: 59

Answers (2)

NeoGenesis521
NeoGenesis521

Reputation: 43

Thanks to Charlieface, I was able to create the following:

using System;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.Collections.ObjectModel;

class Program
{
    static void Main()
    {
        string remoteMachine = "RemoteMachine"; 
        string username = "user";               
        string password = "password";               

        // WSMan connection info
        PSCredential credentials = new PSCredential(username, new System.Security.SecureString());
        foreach (char c in password) credentials.Password.AppendChar(c);

        WSManConnectionInfo connectionInfo = new WSManConnectionInfo(
            new Uri($"http://{remoteMachine}:5985/wsman"),
            "http://schemas.microsoft.com/powershell/Microsoft.PowerShell",
            credentials
        );
        // Create a runspace with the WSMan connection
        Runspace runspace = RunspaceFactory.CreateRunspace(connectionInfo);
        runspace.Open();

        // Create the pipeline to execute the PowerShell command
        using (PowerShell pipeline = PowerShell.Create())
        {
            // Command to execute remotely
            pipeline.Runspace = runspace;
            // Add the Get-NetIPConfiguration command to the pipeline
            pipeline.AddCommand("Get-NetIPConfiguration");
            pipeline.AddCommand("Select-Object").AddParameter("Property", new string[] { "InterfaceAlias", "IPv4Address", "InterfaceIndex", "InterfaceDescription", "NetProfile", "IPv4DefaultGateway", "DNSServer" });

            try
            {
                Collection<PSObject> results = pipeline.Invoke();

                // Process results
                foreach (PSObject result in results)
                {
                    string interfaceAlias = result.Members["InterfaceAlias"]?.Value.ToString();

                    string ipv4Address = string.Empty;
                    string ipv4PrefixLength = string.Empty;
                    string ipv4Gateway = string.Empty;
                    string dnsServers = string.Empty;

                    var ipv4AddressObject = result.Members["IPv4Address"]?.Value as PSObject;
                    if (ipv4AddressObject != null)
                    {
                        var baseObject = ipv4AddressObject.BaseObject as dynamic;
                        ipv4Address = baseObject[0]?.IPAddress;
                        ipv4PrefixLength = baseObject[0]?.PrefixLength.ToString();
                    }

                    // Accessing Default Gateway
                    var ipv4GatewayObject = result.Members["IPv4DefaultGateway"]?.Value as PSObject;
                    if (ipv4GatewayObject != null)
                    {
                        var baseGatewayObject = ipv4GatewayObject.BaseObject as dynamic;
                        ipv4Gateway = baseGatewayObject[0]?.NextHop;
                    }

                    // Accessing DNS Servers
                    StringBuilder DNSServers = new StringBuilder();

                    var dnsServersObject = result.Members["DNSServer"]?.Value as PSObject;
                    if (dnsServersObject != null)
                    {
                        var baseDNSServersObject = dnsServersObject.BaseObject as dynamic;

                        if(baseDNSServersObject.Count > 1)
                        {
                            foreach(var DnsServerObject in baseDNSServersObject)
                            {
                                var baseDNSServers = DnsServerObject?.ServerAddresses;

                                if (baseDNSServers is object[] DnsServers)
                                {
                                    int? cnt = 1;
                                    foreach (var DnsServer in DnsServers)
                                    {
                                        string? DNS = null;

                                        if (cnt < DnsServers.Length)
                                        {
                                            DNS = DnsServer.ToString();
                                            DNS = DNS + ";";
                                        }
                                        else
                                        {
                                            DNS = DnsServer.ToString();
                                        }

                                        DNSServers.Append(DNS);
                                        cnt++;
                                    }
                                }
                            }
                        }
                        else
                        {
                            var baseDNSServers = baseDNSServersObject[0]?.ServerAddresses;

                            if (baseDNSServers is object[] DnsServers)
                            {
                                foreach (var DnsServer in DnsServers)
                                {
                                    string? DNS = DnsServer.ToString();
                                    DNSServers.Append(DNS);
                                }
                            }
                        }
                    }

                    // Convert CIDR to Subnet Mask
                    string subnetMask = CidrToMask(Convert.ToInt32(ipv4PrefixLength));

                    // Output results
                    Console.WriteLine($"InterfaceAlias     : {interfaceAlias}");
                    Console.WriteLine($"IPv4 Address       : {ipv4Address}");
                    Console.WriteLine($"Subnet Mask        : {subnetMask}");
                    Console.WriteLine($"Default Gateway    : {ipv4Gateway}");
                    Console.WriteLine($"DNSServer          : {DNSServers.ToString()}");
                    Console.WriteLine();
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error executing the pipeline: " + ex);
            }
        }

        // Clean up and close the runspace
        runspace.Close();
    }
    public static string CidrToMask(int cidr)
    {
        var mask = (cidr == 0) ? 0 : uint.MaxValue << (32 - cidr);
        var bytes = BitConverter.GetBytes(mask).Reverse().ToArray();
        return new IPAddress(bytes).ToString();
    }

Upvotes: 0

Charlieface
Charlieface

Reputation: 72194

Rather than using Select-Object, you can cast it to dynamic and access the properties late-bound.

// Add only the Get-NetIPConfiguration command to the pipeline
pipeline.AddCommand("Get-NetIPConfiguration");
try
{
    // Results
    var results = pipeline.Invoke<dynamic>();
    foreach (var result in results)
    {
        Console.WriteLine($"InterfaceAlias     : {result.InterfaceAlias}");
        Console.WriteLine($"InterfaceIndex     : {result.InterfaceIndex}");
        Console.WriteLine($"InterfaceDescription: {result.InterfaceDescription}");
        Console.WriteLine($"NetProfile Name    : {result.NetProfile}");
        Console.WriteLine($"IPv4Address        : {result.IPv4Address}");
        Console.WriteLine($"IPv4 DefaultGateway: {result.IPv4DefaultGateway}");
        Console.WriteLine($"DNSServer          : {result.DNSServer}");
        Console.WriteLine();
    }
}
catch (Exception ex)
{
    Console.WriteLine("Error executing the pipeline: " + ex.Message);
}

Or you can import the NetTCP library and statically cast to the correct type.

Upvotes: 1

Related Questions