WMI for quering active networks and associate connections - c#

I need to change Network settings like described in this article. That works good so far. However I also need to know on what active network I make the changes.
(For a better understanding please open Control Panel\Network and Internet\ Network and Sharing Center. Unfortunately all picture hosting sites are blocked by my company so I can't post a screenshot.)
Any help on how I can query what connection is associated with what network with WMI (or other technology)?
UPDATE:
I need to query a remote machine.

You can use the NetworkListManager COM component, either with dynamic as shown below or using the Windows API Code Pack which contains all the COM wrappers.
dynamic networkListManager = Activator.CreateInstance(
Type.GetTypeFromCLSID(new Guid("{DCB00C01-570F-4A9B-8D69-199FDBA5723B}")));
var connections = networkListManager.GetNetworkConnections();
foreach (var connection in connections)
{
var network = connection.GetNetwork();
Console.WriteLine("Network Name: " + network.GetName());
Console.WriteLine("Network Category " +
network.GetCategory()+ " (0 public / 1 private / 2 Authenticated AD)" );
}
PowerShell:
$networkType = [Type]::GetTypeFromCLSID('DCB00C01-570F-4A9B-8D69-199FDBA5723B')
$networkListManager = [Activator]::CreateInstance($networkType)
$netWorks = $networkListManager.GetNetworkConnections()
foreach ($network in $netWorks)
{
$name = $network.GetName()
$category = $network.GetCategory()
write-host "Network Name: $name"
write-host "Network Category: $category"
}

Related

How do i reset the system cache of WLAN info?

I am trying to write a WLAN fingerprinting program using NativeWifi in C#. To do this i run a loop to get the wlan information many times and then later use matlab to average / analyze the data.
The problem is that i get all the same values, even as i move about the house, when the program is running. From the internet i've seen that there is a cache that stores the data of available networks. I was wondering if there is a system call which resets this cache.
I have also seen this using the cmd call
netsh wlan show networks mode=bssid
this gives me the same values until i open the available wifi networks in my OS and if i run it again after, it will give different values.
edit: This system will be for my use only, so i would be comfortable starting over on a linux platform if there is a known library that can handle this for me. I don't even know what to google to even get the information, though. Anything related to "network cache" takes me to help threads of unrelated topics...
I will provide the relevant part of my code below:
public void get_info_instance(StreamWriter file)
{
try
{
foreach (WlanClient.WlanInterface wlanIface in client.Interfaces)
{
Wlan.WlanBssEntry[] wlanBssEntries = wlanIface.GetNetworkBssList();
foreach (Wlan.WlanBssEntry network in wlanBssEntries)
{
int rss = network.rssi;
byte[] macAddr = network.dot11Bssid;
string tMac = "";
for (int i = 0; i < macAddr.Length; i++)
{
tMac += macAddr[i].ToString("x2").PadLeft(2, '0').ToUpper();
}
file.WriteLine("Found network: " + System.Text.ASCIIEncoding.ASCII.GetString(network.dot11Ssid.SSID).ToString());
file.WriteLine("Signal: " + network.linkQuality + "%");
file.WriteLine("BSS Type: " + network.dot11BssType + ".");
file.WriteLine("RSSID: " + rss.ToString());
file.WriteLine("BSSID: " + tMac);
file.WriteLine(" ");
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Internally, netsh is powered by this API. What this means, is that calling netsh wlan show networks mode=bssid just returns the cache of the networks that showed up during the last scan. This is what you've discovered.
This means that in order to refresh this cache, you need to trigger a scan. If your C# library you are using includes it, you could make this happen on demand with a call to WlanScan. I am not sure which C# wrapper you are using, but it probably includes this function. When you get a scan complete notification (register with source WLAN_NOTIFICATION_SOURCE_ACM and look out for wlan_notification_acm_scan_list_refresh), the cache should be updated.
If you let me know which C# library you are using, maybe I can point you to the relevant functions.
You mentioned that opening the available networks causes the cache to refresh. This is because opening the available networks triggers a call to WlanScan.
Profiles are not relevant to the available network list -- profiles are what the Wlan service uses to keep track of which networks are configured on your machine -- deleting them does not make WlanSvc scan again. It may be a coincidence that deleting them happens to coincide with a scan, but it is more of a side effect than the designed usage.
edit: to subscribe to notifications using the Managed Wifi API you are using, this snippet should work:
wlanIface.WlanNotification += wlanIface_WlanNotification;
And the callback:
static void wlanIface_WlanNotification(Wlan.WlanNotificationData notifyData)
{
if (notifyData.notificationCode == (int)Wlan.WlanNotificationCodeAcm.ScanComplete)
{
Console.WriteLine("Scan Complete!");
}
}
You can test this by running this, then opening the available networks on Windows. You should see "Scan Complete" shortly after you open it each time. You can use a messagebox instead of Console.WriteLine if you prefer.
To trigger a scan yourself:
wlanIface.Scan();
for all
netsh wlan delete profile name=* i=*
you might not want to do it on all interfaces, and hard code the interface in there for faster result

Reset Network Connections

What's the best way to reset network connections using C#/.NET?
My company has several machines out with customers that connect by various means (3G, wifi, ethernet cable) and sometimes (especially with 3G) are reporting to Windows that they're still connected when they're not. I have a way to check if the connection is really live, but I'm struggling to reset them. Here's one problem:
var searcher = new ManagementObjectSearcher("select * from Win32_NetworkAdapter");
var managementObject = searcher.Get();
foreach (ManagementObject obj in managementObject)
{
var name = obj.Properties["Name"].Value.ToString();
Console.WriteLine(name);
obj.InvokeMethod("Disable", null);
obj.InvokeMethod("Enable", null);
}
As you can see, that will go through ALL network adapters and reset them, which I don't want to do. Furthermore, some adapters won't accept the null parameter.
I can get the NetworkInterface objects I want with this:
var interfaces = NetworkInterface.GetAllNetworkInterfaces().Where(ni => ni.IsReceiveOnly == false &&
ni.OperationalStatus == OperationalStatus.Up && ni.NetworkInterfaceType != NetworkInterfaceType.Loopback);
But the NetworkInterface class seems to have no Start(), Stop(), Reset() etc methods. Where do I go from here?
After some searching and experimentation, I found this blog post:
Disable/Enable Network Connections Under Vista
It is a much better approach.
The just of it, is to use a utility called mgmtclassgen.exe to generate a wrapper class around the WMI Win32_NetworkAdapter class. Use the following command in a developer command prompt at the folder of your choosing:
mgmtclassgen Win32_NetworkAdapter -p NetworkAdapter.cs
After you've generated NetworkAdapter.cs you can import it into a new project, add System.Management.dll to your project references, and use the following code to disable or enable an adapter of your choosing:
SelectQuery query = new SelectQuery("Win32_NetworkAdapter", "NetConnectionStatus=2");
ManagementObjectSearcher search = new ManagementObjectSearcher(query);
foreach(ManagementObject result in search.Get())
{
NetworkAdapter adapter = new NetworkAdapter(result);
// Identify the adapter you wish to disable here.
// In particular, check the AdapterType and
// Description properties.
// Here, we're selecting the LAN adapters.
if (adapter.AdapterType.Equals("Ethernet 802.3"))
{
adapter.Disable();
}
}
Also keep in mind, your program will have to be run as an administrator on any systems where UAC is enabled - to do this it is recommended to create an application manifest. You can do that by changing the requestedExecutionLevel entry in your manifest file to this:
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
Might be a bit simplistic, but could you call ipconfig /renew from a new process?
Process.Start("ipconfig", "/renew");
Alternatively, this similar question talks about using netsh, which I guess you could call from a process too How to disable (or reset) a network adapter programmatically in C#
You need Win32 API :
GetExtendedTcpTable : Get all exists tcp connection.
SetTcpEntry : Change tcp connection state.
Example code:
MIB_TCPROW row = new MIB_TCPROW();
row.dwState = TcpState.DeleteTcb;
row.dwLocalAddr = ...;
row.dwLocalPort = ...;
row.dwRemoteAddr = ...;
row.dwRemotePort = ...;
SetTcpEntry(ref row);

Using System.Management to Query a VMware Server

Summary: is it possible to specify a port to use when querying WMI using System.Management;
I have a python script under Linux that queries, using WBEM, classes on a number of ESXi servers to check for warnings or errors on various subsystems. Previously, separately, I have written a WPF application that queries a number of WinTel boxes for their disk consumption etc. using WMI.
I am wanting to write a new WPF application that will perform the same function as the script and I thought I would be able to do this with WMI. Below is my testing code with the error handling removed for brevity, SetOptions is a private function that provides the username and password:
foreach (string hostname in Properties.Settings.Default.Hosts)
foreach (string WMIclass in Properties.Settings.Default.Classes)
{
ObjectQuery Query = new ObjectQuery("SELECT * FROM " + WMIclass);
ManagementObjectSearcher mos = GetMos(Query, hostname);
foreach (ManagementObject mo in mos.Get())
foreach (PropertyData pdc in mo.Properties)
Debug.WriteLine(pdc.Name + " \t\t: " + pdc.Value);
}
private ManagementObjectSearcher GetMos(ObjectQuery Query, string Hostname)
{
ConnectionOptions Options = SetOptions();
ManagementScope Scope = new ManagementScope("\\\\" + Hostname + "\\root\\cimv2", Options);
return new ManagementObjectSearcher(Scope, Query);
}
The trouble is I get a RPC unavailable on the remote server. I think that is because I am first trying to establish a RPC call on 135 which is not hosted by an ESX server. My question is how can one specify the port 5989 or is there something straightforward I can use in .net to perform what I need to do. Naively I'm thinking the class structure looks the same between WMI/WBEM surely it can be done :-/
System.Management can only be used to connect to other Windows machines running WMI, and doesn't support WBEM. The only C# WBEM client library I seen is http://code.google.com/p/wbemtools/, but it doesn't look very mature.
As said WMI Classes in .net don't support WBEM. In the end I ended up writing some code around the VMware.Vim.dll which has some good documentation on what I needed to do.

Convert SID's to usernames/groups?

I'm looping through a network directory and trying to output the user/group names (permissions) associated with each file/folder. I'm getting the SID's back but I want the names like "group_test" and not "S-1-5-32-544". Here's my code -
var files = Directory.GetFiles(path, "*.*", SearchOption.TopDirectoryOnly);
foreach (var f in files2)
{
var fileInfo = new FileInfo(f);
var fs = fileInfo.GetAccessControl(AccessControlSections.Access);
foreach (FileSystemAccessRule rule in fs.GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount)))
{
var value = rule.IdentityReference.Value;
Response.Write(string.Format("File: {0} \t Usergroup: {1} <br/>", fileInfo.Name, value));
} }
I get SID's from the above code but in the foreach loop, if I use this instead -
(NTAccount)((SecurityIdentifier)rule.IdentityReference).Translate(typeof(NTAccount)).Value
I get this exception -
Some or all identity references could not be translated.
It appears that the Translate method does not work on remote shares. How do I retrieve the real names of the SID's? The remote server does not have LDAP.
Thank you.
The problem is that you are trying to resolve a SID that is local to a remote machine. As the answer to this question states:
The SecurityReference object's Translate method does work on non-local SIDs but only for domain accounts...
This link provides an example for remotely resolving a SID using WMI which is probably the best method for accomplishing your task.
If you can use WMI you should be able to do it via the Win32_UserAccount class I think. It has a Name property and a SID property.
Or the Win32_Group class for the groups.
Here's an article for connecting to a remote pc using WMI that has C# code: How To: Connect to a Remote Computer

Granting remote user (non admin) the ability to enumerate services in Win32_Service in namespace cimv2 using WMI & C#

I'm creating a watch dog service that will be monitoring other services on various remote servers (all in the same domain). The user that I'm using to connect to the remote servers is not an admin. When I try to enumerate the services in the Win32_Service class, I get an access denied error.
I've given the user 'Remote Enable' & 'Enable Account' persmissions to the Root\CIMV2 namespace in the WMI Control.
I am able to connect to the server with the following code. The object ServiceListItem is just a simple class that contains the server name and the service name:
SecureString secureString = new SecureString();
foreach ( char c in "password" )
{
secureString.AppendChar( c );
}
ConnectionOptions connectionOptions = new ConnectionOptions();
connectionOptions.Username = "domain\\user";
connectionOptions.SecurePassword = secureString;
foreach ( ServiceListItem service in _serviceList )
{
ManagementScope managementScope = new ManagementScope();
managementScope = new ManagementScope( String.Format( #"\\{0}\root\cimv2", service.ServerName ), connectionOptions );
managementScope.Connect();
//RelatedObjectQuery relatedObjectQuery = new RelatedObjectQuery( String.Format( "Win32_Service.Name='{0}'", service.ServiceName ) );
//ManagementObjectSearcher objectSearcher = new ManagementObjectSearcher( managementScope, relatedObjectQuery );
ObjectQuery objectQuery = new ObjectQuery( "SELECT * FROM Win32_Service WHERE Name = '" + service.ServiceName + "'" );
ManagementObjectSearcher objectSearcher = new ManagementObjectSearcher( managementScope, objectQuery );
ManagementObjectCollection objectCollection = objectSearcher.Get();
foreach ( ManagementObject managementObject in objectCollection )
{
serviceStatus = managementObject.Properties["State"].Value.ToString();
Debug.Print(service.ServiceName + " - " + serviceStatus);
//break;
}
}
The managementScope.Connect() runs fine, which means the wmi security on cimv2 is set up correctly. However, when I try to enumerate the objectCollection, I get the 'Access Denied' exception. This tells me (I think) that the user doesn't have permissions to enumerate the Win32_Service class (SC_MANAGER_ENUMERATE_SERVICE).
I just haven't been able to find any good examples on how to enable that permission for a remote user. I'm not very experienced when it comes to coding with Windows api's, so please be as detailed as possible in your answers :)
Trying to find the same answer myself today, I've been doing a lot of googling. After a good half hour of incantations, I found this MSDN article (907460) which uses sc sdet. It seems to work so far, even though the security descriptor is for Windows Server 2003. I've found you can do sc sdshow SCMANAGER to get the current value so when back in the office tomorrow I'll be comparing an contrasting to make sure I've not locked something out I shouldn't have :-)
For completeness, the notes in KB907460 (in case it moves/goes away):
Symptoms: After you install Microsoft Windows Server 2003 Service Pack 1 (SP1), non-administrators cannot remotely access the Service Control Manager.
Cause: Windows Server 2003 SP1 changes the Service Control Manager default security settings.
Resolution:
To resolve this issue, use version 5.2.3790.1830 of the Sc.exe tool.
This tool is located in the %windir%\System32 folder. To do this,
follow these steps:
Click Start, click Run, type cmd, and then click OK.
Type the following command at the command prompt, and then press ENTER:
sc sdset SCMANAGER D:(A;;CCLCRPRC;;;AU)(A;;CCLCRPWPRC;;;SY)(A;;KA;;;BA)S:(AU;FA;KA;;;WD)(AU;OIIOFA;GA;;;WD)
I found myself stuck into a similar problem. In my case it had nothing to do with permissions, which I did set by following this link: http://www.poweradmin.com/help/enableWMI.aspx
So, After hours of wondering lost I found this article that tells how UAC interfere with your set of permissions and how can you fix that:
http://www.solarwinds.com/documentation/apm/docs/APMWMITroubleshooting.pdf
In my case, the registry key didn't existed, so I created it.
Hope this helps also, cheers!

Categories