I am looking for pointers towards APIs in c# that will allow me to control my Internet connection by turning the connection on and off.
I want to write a little console app that will allow me to turn my access on and off , allowing for productivity to skyrocket :) (as well as learning something in the process)
Thanks !!
If you're using Windows Vista you can use the built-in firewall to block any internet access.
The following code creates a firewall rule that blocks any outgoing connections on all of your network adapters:
using NetFwTypeLib; // Located in FirewallAPI.dll
...
INetFwRule firewallRule = (INetFwRule)Activator.CreateInstance(
Type.GetTypeFromProgID("HNetCfg.FWRule"));
firewallRule.Action = NET_FW_ACTION_.NET_FW_ACTION_BLOCK;
firewallRule.Description = "Used to block all internet access.";
firewallRule.Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_OUT;
firewallRule.Enabled = true;
firewallRule.InterfaceTypes = "All";
firewallRule.Name = "Block Internet";
INetFwPolicy2 firewallPolicy = (INetFwPolicy2)Activator.CreateInstance(
Type.GetTypeFromProgID("HNetCfg.FwPolicy2"));
firewallPolicy.Rules.Add(firewallRule);
Then remove the rule when you want to allow internet access again:
INetFwPolicy2 firewallPolicy = (INetFwPolicy2)Activator.CreateInstance(
Type.GetTypeFromProgID("HNetCfg.FwPolicy2"));
firewallPolicy.Rules.Remove("Block Internet");
This is a slight modification of some other code that I’ve used, so I can’t make any guarantees that it’ll work. Once again, keep in mind that you'll need Windows Vista (or later) and administrative privileges for this to work.
Link to the firewall API documentation.
This is what I am currently using (my idea, not an api):
System.Diagnostics;
void InternetConnection(string str)
{
ProcessStartInfo internet = new ProcessStartInfo()
{
FileName = "cmd.exe",
Arguments = "/C ipconfig /" + str,
WindowStyle = ProcessWindowStyle.Hidden
};
Process.Start(internet);
}
Disconnect from internet: InternetConnection("release");
Connect to internet: InternetConnection("renew");
Disconnecting will just remove the access to internet (it will show a caution icon in the wifi icon).
Connecting might take five seconds or more.
Out of topic:
In any cases you might want to check if you're connected or not (when you use the code above), I better suggest this:
System.Net.NetworkInformation;
public static bool CheckInternetConnection()
{
try
{
Ping myPing = new Ping();
String host = "google.com";
byte[] buffer = new byte[32];
int timeout = 1000;
PingOptions pingOptions = new PingOptions();
PingReply reply = myPing.Send(host, timeout, buffer, pingOptions);
return (reply.Status == IPStatus.Success);
}
catch (Exception)
{
return false;
}
}
There are actually a myriad of ways to turn off (Read: break) your internet access, but I think the simplest one would be to turn of the network interface that connects you to the internet.
Here is a link to get you started:
Identifying active network interface
Here's a sample program that does it using WMI management objects.
In the example, I'm targeting my wireless adapter by looking for network adapters that have "Wireless" in their name. You could figure out some substring that identifies the name of the adapter that you are targeting (you can get the names by doing ipconfig /all at a command line). Not passing a substring would cause this to go through all adapters, which is kinda severe. You'll need to add a reference to System.Management to your project.
using System;
using System.Management;
namespace ConsoleAdapterEnabler
{
public static class NetworkAdapterEnabler
{
public static ManagementObjectSearcher GetWMINetworkAdapters(String filterExpression = "")
{
String queryString = "SELECT * FROM Win32_NetworkAdapter";
if (filterExpression.Length > 0)
{
queryString += String.Format(" WHERE Name LIKE '%{0}%' ", filterExpression);
}
WqlObjectQuery query = new WqlObjectQuery(queryString);
ManagementObjectSearcher objectSearcher = new ManagementObjectSearcher(query);
return objectSearcher;
}
public static void EnableWMINetworkAdapters(String filterExpression = "")
{
foreach (ManagementObject adapter in GetWMINetworkAdapters(filterExpression).Get())
{
//only enable if not already enabled
if (((bool)adapter.Properties["NetEnabled"].Value) != true)
{
adapter.InvokeMethod("Enable", null);
}
}
}
public static void DisableWMINetworkAdapters(String filterExpression = "")
{
foreach (ManagementObject adapter in GetWMINetworkAdapters(filterExpression).Get())
{
//If enabled, then disable
if (((bool)adapter.Properties["NetEnabled"].Value)==true)
{
adapter.InvokeMethod("Disable", null);
}
}
}
}
class Program
{
public static int Main(string[] args)
{
NetworkAdapterEnabler.DisableWMINetworkAdapters("Wireless");
Console.WriteLine("Press any key to continue");
var key = Console.ReadKey();
NetworkAdapterEnabler.EnableWMINetworkAdapters("Wireless");
Console.WriteLine("Press any key to continue");
key = Console.ReadKey();
return 0;
}
}
}
public static void BlockingOfData()
{
INetFwPolicy2 firewallPolicy = (INetFwPolicy2)Activator.CreateInstance(Type.GetTypeFromProgID("HNetCfg.FwPolicy2"));
firewallPolicy.set_DefaultOutboundAction(NET_FW_PROFILE_TYPE2_.NET_FW_PROFILE2_DOMAIN, NET_FW_ACTION_.NET_FW_ACTION_BLOCK);
firewallPolicy.set_DefaultOutboundAction(NET_FW_PROFILE_TYPE2_.NET_FW_PROFILE2_PRIVATE, NET_FW_ACTION_.NET_FW_ACTION_BLOCK);
firewallPolicy.set_DefaultOutboundAction(NET_FW_PROFILE_TYPE2_.NET_FW_PROFILE2_PUBLIC, NET_FW_ACTION_.NET_FW_ACTION_BLOCK);
}
Related
I am new to C# and I am using windows forms, windows 7 and .Net 4.0.
I have 3 printers connected to my computer I want to print windows test page on a specific printer. All printers names are listed in ComboBox as shown in the following code I want to select a printer from ComboBox and print test page.
I had a look Here, Here and Here but nothing helped.
Does anyone know how to do it?
foreach (string printer in System.Drawing.Printing.PrinterSettings.InstalledPrinters)
{
comboBox_Printers.Items.Add(printer);
}
Now, this method might look verbose, but I think it's important, when calling WMI methods, that the Management Options and Scopes are defined correctly.
This gives means to correct/adapt the code to specific contexts, when necessary.
Also, the helper methods here can be reused to initialize any other WMI query.
For example, a wrong Impersonation option, will result in an exception (0x80070005: (E_ACCESSDENIED)) when connecting to the WMI Scope or when the WMI query is executed.
A description of the PrintTestPage method parameters:
string PrinterName: the name of a specific Printer or null to use the default Printer.
string MachineName: the name of a Machine in the Network or null to use the LocalMachine name.
The method returns 0 if successful and throws an exception if the Printer is not found.
Sample call to Print a test page using the default printer in the local machine:
var result = PrintTestPage(null, null);
using System.Linq;
using System.Management;
public static uint PrintTestPage(string PrinterName, string MachineName)
{
ConnectionOptions connOptions = GetConnectionOptions();
EnumerationOptions mOptions = GetEnumerationOptions(false);
string machineName = string.IsNullOrEmpty(MachineName) ? Environment.MachineName : MachineName;
ManagementScope mScope = new ManagementScope($#"\\{machineName}\root\CIMV2", connOptions);
SelectQuery mQuery = new SelectQuery("SELECT * FROM Win32_Printer");
mQuery.QueryString += string.IsNullOrEmpty(PrinterName)
? " WHERE Default = True"
: $" WHERE Name = '{PrinterName}'";
mScope.Connect();
using (ManagementObjectSearcher moSearcher = new ManagementObjectSearcher(mScope, mQuery, mOptions))
{
ManagementObject moPrinter = moSearcher.Get().OfType<ManagementObject>().FirstOrDefault();
if (moPrinter is null) throw new InvalidOperationException("Printer not found");
InvokeMethodOptions moMethodOpt = new InvokeMethodOptions(null, ManagementOptions.InfiniteTimeout);
using (ManagementBaseObject moParams = moPrinter.GetMethodParameters("PrintTestPage"))
using (ManagementBaseObject moResult = moPrinter.InvokeMethod("PrintTestPage", moParams, moMethodOpt))
return (UInt32)moResult["ReturnValue"];
}
}
Helper methods:
private static EnumerationOptions GetEnumerationOptions(bool DeepScan)
{
EnumerationOptions mOptions = new EnumerationOptions()
{
Rewindable = false, //Forward only query => no caching
ReturnImmediately = true, //Pseudo-async result
DirectRead = true, //Skip superclasses
EnumerateDeep = DeepScan //No recursion
};
return mOptions;
}
private static ConnectionOptions GetConnectionOptions()
{
ConnectionOptions connOptions = new ConnectionOptions()
{
EnablePrivileges = true,
Timeout = ManagementOptions.InfiniteTimeout,
Authentication = AuthenticationLevel.PacketPrivacy,
Impersonation = ImpersonationLevel.Impersonate
};
return connOptions;
}
I've seen many ways in powershell to force a computer to do a client action from the configuration manager.
Where I do work, it is not possible because we can't invoke commands on distant computer because it is blocked and the senior IT do not want to unlock it.
I did find a library in c# that allow me to do some action in sccm :
AdminUI.SmsTraceListener.dll
AdminUI.WqlQueryEngine.dll
I can add/remove computer to a collections, make queries and get the data, but I didn't find the way to force a computer to make an action from the configuration manager.
Is there someone here that knows if it is possible and how?
Thanks.
Edit 1: While searching in the MSDN documentation, I did find the TriggerSchedule Method in Class SMS_Client but I don't find the way to use it correctly. I think it might be the way to go, but i'm still stuck on this.
It is possible to trigger an Machine Policy Update via TriggerSchedule like this
ManagementScope scope = new ManagementScope(#"\\.\root\ccm");
ManagementClass cls = new ManagementClass(scope.Path.Path, "SMS_Client", null);
ManagementBaseObject inParams = cls.GetMethodParameters("TriggerSchedule");
inParams["sScheduleID"] = "{00000000-0000-0000-0000-000000000021}";
ManagementBaseObject outMPParams = cls.InvokeMethod("TriggerSchedule", inParams, null);
You already found the other Parameters for the sScheduleID in the link you posted. This uses standard WMI. With WqlQueryEngine you would get access to some WMI wrappers that can basically do the same thing. I do not see many advantages however.
Using the scope like this
\\.\root\ccm
makes the whole thing only work locally which is what you want if I understood you correctly. Otherwise replacing the . With a hostname or IP would make it work remotely. Only thing I found a bit strange is that it needs administrative rights, which should in theory not be necessary for a policy update request.
if someone is having the issue that nothing is happening, it is because WMI required higher rights. To leave triggering the actions also by the user, I switched to use the CPApplet:
TriggerSccmActions("Request & Evaluate", true);
private static List<string> TriggerSccmActions(string stringActions, bool boolContains)
{
List<string> actionName = new List<string>();
try {
const string ProgID = "CPApplet.CPAppletMgr";
Type foo = Type.GetTypeFromProgID(ProgID);
dynamic COMobject = Activator.CreateInstance(foo);
var oClientActions = COMobject.GetClientActions;
foreach (var oClientAction in oClientActions)
{
if (oClientAction.Name.ToString().Contains(stringActions) && boolContains)
{
var result = oClientAction.PerformAction();
actionName.Add(oClientAction.Name.ToString());
}
else if (!(oClientAction.Name.ToString().Contains(stringActions)) && !(boolContains))
{
var result = oClientAction.PerformAction();
actionName.Add(oClientAction.Name.ToString());
}
}
} catch(Exception e)
{
actionName.Add("Error: " + e.Message.ToString());
}
return actionName;
}
For me, EvaluateMachinePolicy Method in Class SMS_Client class worked. Here is the code:
public static void RefreshMachinePolicy(string machineName)
{
ManagementScope scope = new ManagementScope(string.Format(#"\\{0}\root\ccm", machineName));
ManagementClass cls = new ManagementClass(scope.Path.Path, "SMS_Client", null);
ManagementBaseObject inParams = cls.GetMethodParameters("EvaluateMachinePolicy");
ManagementBaseObject outMPParams = cls.InvokeMethod("EvaluateMachinePolicy", inParams, null);
Console.WriteLine("Policy refreshed successfully by EvaluateMachinePolicy method");
}
Here is the MSDN link for method details. Please include below namespace at the top of your source code file:
using System.Management;
I want to programatically enable TCP connections on SQL Server. I believe we can achieve this by modifying registry entries and restarting SQL Server service. What registry should I edit?
Unless you have a good reason for modifying the registry directly, I suggest you consider using WMI. WMI will provide you with a more version agnostic implementation. WMI can be accessed through the System.Management namespace. You could have code that looks something like this.
public void EnableSqlServerTcp(string serverName, string instanceName)
{
ManagementScope scope =
new ManagementScope(#"\\" + serverName +
#"\root\Microsoft\SqlServer\ComputerManagement");
ManagementClass sqlService =
new ManagementClass(scope,
new ManagementPath("SqlService"), null);
ManagementClass serverProtocol =
new ManagementClass(scope,
new ManagementPath("ServerNetworkProtocol"), null);
sqlService.Get();
serverProtocol.Get();
foreach (ManagementObject prot in serverProtocol.GetInstances())
{
prot.Get();
if ((string)prot.GetPropertyValue("ProtocolName") == "Tcp" &&
(string)prot.GetPropertyValue("InstanceName") == instanceName)
{
prot.InvokeMethod("SetEnable", null);
}
}
uint sqlServerService = 1;
uint sqlServiceStopped = 1;
foreach (ManagementObject instance in sqlService.GetInstances())
{
if ((uint)instance.GetPropertyValue("SqlServiceType") == sqlServerService &&
(string)instance.GetPropertyValue("ServiceName") == instanceName)
{
instance.Get();
if ((uint)instance.GetPropertyValue("State") != sqlServiceStopped)
{
instance.InvokeMethod("StopService", null);
}
instance.InvokeMethod("StartService", null);
}
}
}
This code assumes a project reference to System.Management.dll and the following using statement:
using System.Management;
The Sql Protocols blog has an article that goes into some detail as to what the above code is doing.
Note: If a firewall is blocking the port(s) you will still be unable to access the server via TCP.
Take a look at HKLM\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQLServer\SuperSocketNetLib\Tcp hive. There are keys like Enabled, ListenOnAllIPs and a list of IP addresses to listen on.
Is there a way to search for the existence of a given WCF service in any of the computer of a local Network?
For example, I am looking for the Math/Add2Numbers service and I want to know which machines on the LAN provide it, is there any way to do that?
Here is a super simple discovery example. It does not use a config file, it is all c# code, but you can probably port the concepts to a config file.
share this interface between host and client program (copy to each program for now)
[ServiceContract]
public interface IWcfPingTest
{
[OperationContract]
string Ping();
}
put this code in the host program
public class WcfPingTest : IWcfPingTest
{
public const string magicString = "djeut73bch58sb4"; // this is random, just to see if you get the right result
public string Ping() {return magicString;}
}
public void WcfTestHost_Open()
{
string hostname = System.Environment.MachineName;
var baseAddress = new UriBuilder("http", hostname, 7400, "WcfPing");
var h = new ServiceHost(typeof(WcfPingTest), baseAddress.Uri);
// enable processing of discovery messages. use UdpDiscoveryEndpoint to enable listening. use EndpointDiscoveryBehavior for fine control.
h.Description.Behaviors.Add(new ServiceDiscoveryBehavior());
h.AddServiceEndpoint(new UdpDiscoveryEndpoint());
// enable wsdl, so you can use the service from WcfStorm, or other tools.
var smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
h.Description.Behaviors.Add(smb);
// create endpoint
var binding = new BasicHttpBinding(BasicHttpSecurityMode.None);
h.AddServiceEndpoint(typeof(IWcfPingTest) , binding, "");
h.Open();
Console.WriteLine("host open");
}
put this code in the client program
private IWcfPingTest channel;
public Uri WcfTestClient_DiscoverChannel()
{
var dc = new DiscoveryClient(new UdpDiscoveryEndpoint());
FindCriteria fc = new FindCriteria(typeof(IWcfPingTest));
fc.Duration = TimeSpan.FromSeconds(5);
FindResponse fr = dc.Find(fc);
foreach(EndpointDiscoveryMetadata edm in fr.Endpoints)
{
Console.WriteLine("uri found = " + edm.Address.Uri.ToString());
}
// here is the really nasty part
// i am just returning the first channel, but it may not work.
// you have to do some logic to decide which uri to use from the discovered uris
// for example, you may discover "127.0.0.1", but that one is obviously useless.
// also, catch exceptions when no endpoints are found and try again.
return fr.Endpoints[0].Address.Uri;
}
public void WcfTestClient_SetupChannel()
{
var binding = new BasicHttpBinding(BasicHttpSecurityMode.None);
var factory = new ChannelFactory<IWcfPingTest>(binding);
var uri = WcfTestClient_DiscoverChannel();
Console.WriteLine("creating channel to " + uri.ToString());
EndpointAddress ea = new EndpointAddress(uri);
channel = factory.CreateChannel(ea);
Console.WriteLine("channel created");
//Console.WriteLine("pinging host");
//string result = channel.Ping();
//Console.WriteLine("ping result = " + result);
}
public void WcfTestClient_Ping()
{
Console.WriteLine("pinging host");
string result = channel.Ping();
Console.WriteLine("ping result = " + result);
}
on the host, simply call the WcfTestHost_Open() function, then sleep forever or something.
on the client, run these functions. It takes a little while for a host to open, so there are several delays here.
System.Threading.Thread.Sleep(8000);
this.server.WcfTestClient_SetupChannel();
System.Threading.Thread.Sleep(2000);
this.server.WcfTestClient_Ping();
host output should look like
host open
client output should look like
uri found = http://wilkesvmdev:7400/WcfPing
creating channel to http://wilkesvmdev:7400/WcfPing
channel created
pinging host
ping result = djeut73bch58sb4
this is seriously the minimum I could come up with for a discovery example. This stuff gets pretty complex fast.
What you need is WS-Discovery, but unfortunately, this is not included as part of the ws-* extensions in WCF. There are some homegrown implementations of it. Here's a google search for that.
Otherwise, you can implement an enterprise UDDI or registry solution by a third party vendor (like IBM or Microsoft).
You could use UDDI to find it, but if there were multiple instances of the service, how would you decide which instance to use?
I'd like to know if there is any .Net class that allows me to know the SSID of the wireless network I'm connected to.
So far I only found the library linked below. Is the best I can get or should I use something else?
Managed WiFi (http://www.codeplex.com/managedwifi)
The method that exploits WMI works for Windows XP but is it not working anymore with Windows Vista.
I resolved using the library. It resulted to be quite easy to work with the classes provided:
First I had to create a WlanClient object
wlan = new WlanClient();
And then I can get the list of the SSIDs the PC is connected to with this code:
Collection<String> connectedSsids = new Collection<string>();
foreach (WlanClient.WlanInterface wlanInterface in wlan.Interfaces)
{
Wlan.Dot11Ssid ssid = wlanInterface.CurrentConnection.wlanAssociationAttributes.dot11Ssid;
connectedSsids.Add(new String(Encoding.ASCII.GetChars(ssid.SSID,0, (int)ssid.SSIDLength)));
}
We were using the managed wifi library, but it throws exceptions if the network is disconnected during a query.
Try:
var process = new Process
{
StartInfo =
{
FileName = "netsh.exe",
Arguments = "wlan show interfaces",
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true
}
};
process.Start();
var output = process.StandardOutput.ReadToEnd();
var line = output.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries).FirstOrDefault(l => l.Contains("SSID") && !l.Contains("BSSID"));
if (line == null)
{
return string.Empty;
}
var ssid = line.Split(new[] { ":" }, StringSplitOptions.RemoveEmptyEntries)[1].TrimStart();
return ssid;
It looks like this will do what you want:
ManagementObjectSearcher searcher = new ManagementObjectSearcher("root\\WMI",
"SELECT * FROM MSNdis_80211_ServiceSetIdentifier");
foreach (ManagementObject queryObj in searcher.Get())
{
Console.WriteLine("-----------------------------------");
Console.WriteLine("MSNdis_80211_ServiceSetIdentifier instance");
Console.WriteLine("-----------------------------------");
if(queryObj["Ndis80211SsId"] == null)
Console.WriteLine("Ndis80211SsId: {0}",queryObj["Ndis80211SsId"]);
else
{
Byte[] arrNdis80211SsId = (Byte[])
(queryObj["Ndis80211SsId"]);
foreach (Byte arrValue in arrNdis80211SsId)
{
Console.WriteLine("Ndis80211SsId: {0}", arrValue);
}
}
}
from http://bytes.com/groups/net-c/657473-wmi-wifi-discovery
there is some more information in How do I get the available wifi APs and their signal strength in .net?
(cross-posted in How to get currently connected wifi SSID in c# using WMI or System.Net.NetworkInformation windows 10?)
I found a rather old library dating back to 2014:
Microsoft.WindowsAPICodePack-Core version 1.1.0.2
Although it is not conforming to .NET Standard, this library integrates with my .NET Core 3.0 app, but obviously is not cross-platform.
Sample code:
var networks = NetworkListManager.GetNetworks(NetworkConnectivityLevels.Connected);
foreach (var network in networks) {
sConnected = ((network.IsConnected == true) ? " (connected)" : " (disconnected)");
Console.WriteLine("Network : " + network.Name + " - Category : " + network.Category.ToString() + sConnected);
}
You are going to have to use native WLAN API. There is a long discussion about it here. Apparently this is what Managed Wifi API uses, so it will be easier for you to use it if you do not have any restrictions to use LGPL code.
I wanted to do exactly this, and tried using ManagedWifi, as suggested in other answers. But that led to unresolvable Exceptions as per here:
Issues with using Managed WiFi (NativeWiFi API)
I solved this by switching to using SimpleWiFi entirely and ignored the ManagedWifi package.
Glancing at the source code, it looks like SW is a fixed reimplementation of some of the functionality in MW.