How to EnableDHCP and delete IP from adapter via WMI - c#

Im making some kind of IP setting tool and i have a problem with EnableDHCP method via WMI (Win32_NetworkAdapterConfiguration). Adapter was set to DHCP but there is still IP and gateway. So i am using netsh function which works to me but i want to use only WMI. Any advice?
I try some methods like Lease and send null to static but it doesnt work.
s//THIS ONE I WANT TO USE BUT ITS LET IP AT ADAPTER EVEN DHCP IS ENABLED
public void button1_Click(object sender, EventArgs e)
{
ManagementClass objMC = new ManagementClass("Win32_NetworkAdapterConfiguration");
ManagementObjectCollection objMOC = objMC.GetInstances();
//check numbe of aktive ports
foreach (ManagementObject objMO in objMOC)
{
if ((bool)objMO["IPEnabled"])
{
try
{
// write parameters to active port
ManagementBaseObject setIP;
setIP = objMO.InvokeMethod("EnableDHCP", null, null);
}
catch (Exception x)
{
}
}
}
}
Process p = new Process();//netsh work well but i dont want to use
ProcessStartInfo psi = new ProcessStartInfo("netsh", "interface ip set address \"" + adapter.Name + "\" dhcp");
p.StartInfo = psi;
p.Start();
I expect using EnableDHCP over WMI and IP adress was cleared, but IP adress is still there
This(Picture)

public Collection<PSObject> Invoke(string Query)
{
Collection<PSObject> ps = new Collection<PSObject>();
try
{
using (PowerShell PSI = PowerShell.Create())
{
PSI.AddScript(Query);
ps = PSI.Invoke();
}
}
catch (Exception ex)
{
ps = null;
throw;
}
return ps;
}
Create a class to invoke PS Query
public List<YourObjectList> GetInfo(string ParametersIFYouWant)
{
List<YourObjectList> ListInfo = new List<YourObjectList>();
InvokePowerShellQuery powerShellQuery = new InvokePowerShellQuery();
string PSQuery = "Query Here as a string";
try
{
var PSOutput = powerShellQuery.Invoke(PSQuery);
//In your case you wont need unless in you PS Query you return a message or some other object you want to report back for success or failure.
foreach (var item in PSOutput)
{
//Fill ListInfo
}
}
catch (Exception ex)
{
Listinfo = null;
//handle however you want here
}
return Listinfo;
}
Send the query to your class
Quick Google search on PS Queries you may use
https://www.pdq.com/blog/using-powershell-to-set-static-and-dhcp-ip-addresses-part-1/
https://4sysops.com/archives/set-an-ip-address-and-configure-dhcp-with-powershell

Related

How to kill remote desktop session for local computer only

I'm using the following code to kill a remote desktop session and the application running in it. It works fine, the only problem is that it kills the specified application for all users.
How do I keep this to just the local machine running a session?
We have multiple users logging in and running this application from a server on their local machines. Most are running using work resources, but some use remote desktop.
No matter how they are logged in when I run my code all users loose their sessions.
private void btnCloseSession_Click(object sender, EventArgs e)
{
if (!runningExclusiveProcess)
{
runningExclusiveProcess = true;
btnCloseSession.Enabled = false;
//check and close Labware if running
if (chkCloseLabware.Checked == true)
{
if (chkExit.Checked == true)
{
KillLabWare();
Close();
}
else
{
KillLabWare();
}
}
Process[] my = Process.GetProcessesByName("mstsc");
//loop thru list to get selected item(s)
ListBox.SelectedObjectCollection selectedItems = new ListBox.SelectedObjectCollection(lstOpenSessions);
selectedItems = lstOpenSessions.SelectedItems;
try
{
//remove credentials
string szTestx = "/delete:GOJO.NET/" + cboServer.Text;
ProcessStartInfo infox = new ProcessStartInfo("cmdkey.exe", szTestx);
Process procx = new Process();
procx.StartInfo = infox;
procx.Start();
if (lstOpenSessions.SelectedIndex != -1)
{
for (int i = selectedItems.Count - 1; i >= 0; i--)
{
//loop thru process to match process vs. list selection(s)
foreach (Process remote in my)
{
if (remote.MainWindowTitle == selectedItems[i].ToString())
{
KillRS(remote.MainWindowTitle);
lstOpenSessions.Items.Remove(selectedItems[i]);
}
}
if (lstOpenSessions.Items.Contains(selectedItems[i].ToString()))
{
lstOpenSessions.Items.Remove(selectedItems[i]);
}
}
}
}
catch (Exception ex)
{
Console.WriteLine("{0} Exception caught.", ex);
}
// If your task is synchronous, then undo your flag here:
runningExclusiveProcess = false;
btnCloseSession.Enabled = true;
}
}
public void KillLabWare()
{
ConnectionOptions con = new ConnectionOptions();
con.Username = cboUserName.Text;
con.Password = txtPassWord.Text;
string strIPAddress = cboServer.Text;
ManagementScope scope = new
ManagementScope(#"\\" + strIPAddress + #"\root\cimv2", con);
scope.Connect();
ObjectQuery query = new ObjectQuery("SELECT * FROM Win32_Process WHERE Name='Labware.exe'");
ManagementObjectSearcher searcher = new
ManagementObjectSearcher(scope, query);
ManagementObjectCollection objectCollection = searcher.Get();
foreach (ManagementObject managementObject in objectCollection)
{
managementObject.InvokeMethod("Terminate", null);
}
}
private void KillRS(string rwt)
{
foreach (Process p in Process.GetProcesses())
{
if (p.MainWindowTitle == rwt)
{
p.Kill();
}
}
}
public static void KillRemoteProcess(Process p, string user, string password)
{
new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "TaskKill.exe",
Arguments = string.Format("/pid {0} /s {1} /u {2} /p {3}", p.Id, p.MachineName, user, password),
WindowStyle = ProcessWindowStyle.Hidden,
CreateNoWindow = true
}
}.Start();
}
It sounds like you are trying to force a specific user to log out? Is this because you find that users are forgetting to log out and constantly consuming licenses?
LabWare Application allows for a time out interval (in minutes) to be set on each user where after the interval has passed, the user will be logged out (licence no longer consumed).
For more information see page 204 of the LabWare 7 Technical Manual.
Alternativley if this is for a scheduler (service or cluster instance) session, this can also be controlled by the application. You can either manually change the shutdown and keep alive flags on the instance record on the Services table (if using Service Manager) or you can write a LIMS Basic event trigger/automation script or scheduled subroutine (or have this as a button on a Visual workflow) to do this for you.
HTH.
If you wanna kill remote desktop session or disconnect current RDP session, please read this article:
WTSDisconnectSession function
but if you logout current user, it also disconnect RDP session, here is the code:
using System;
using System.Runtime.InteropServices;
using System.ComponentModel;
class Program
{
[DllImport("wtsapi32.dll", SetLastError = true)]
static extern bool WTSDisconnectSession(IntPtr hServer, int sessionId, bool bWait);
const int WTS_CURRENT_SESSION = -1;
static readonly IntPtr WTS_CURRENT_SERVER_HANDLE = IntPtr.Zero;
static void Main(string[] args)
{
if (!WTSDisconnectSession(WTS_CURRENT_SERVER_HANDLE,
WTS_CURRENT_SESSION, false))
throw new Win32Exception();
}
}
I hope it works, fill free for further info, comment plz
Happy Coding 😎

Power up Hyper_V client in C# using WMI

I am new to coding the Hyper-V within WMI, and always welcome to a learning opportunity in this area.
There is a need for me to create a winform application that lists all VMs available within a computer. When a user clicks on one VM, it will launch the Hyper-V client window.
My codes below could pretty much start or stop any specific VM. However, it doesn't launch the hyper-v client window.
Here are my prototype codes (in command lines for now):
using System;
using System.Management;
namespace HyperVSamples
{
public class RequestStateChangeClass
{
public static void RequestStateChange(string vmName, string action)
{
ManagementScope scope = new ManagementScope(#"\\.\root\virtualization\v2", null);
ManagementObject vm = Utility.GetTargetComputer(vmName, scope);
if (null == vm)
{
throw new ArgumentException(
string.Format(
"The virtual machine '{0}' could not be found.",
vmName));
}
ManagementBaseObject inParams = vm.GetMethodParameters("RequestStateChange");
const int Enabled = 2;
const int Disabled = 3;
if (action.ToLower() == "start")
{
inParams["RequestedState"] = Enabled;
}
else if (action.ToLower() == "stop")
{
inParams["RequestedState"] = Disabled;
}
else
{
throw new Exception("Wrong action is specified");
}
ManagementBaseObject outParams = vm.InvokeMethod(
"RequestStateChange",
inParams,
null);
if ((UInt32)outParams["ReturnValue"] == ReturnCode.Started)
{
if (Utility.JobCompleted(outParams, scope))
{
Console.WriteLine(
"{0} state was changed successfully.",
vmName);
}
else
{
Console.WriteLine("Failed to change virtual system state");
}
}
else if ((UInt32)outParams["ReturnValue"] == ReturnCode.Completed)
{
Console.WriteLine(
"{0} state was changed successfully.",
vmName);
}
else
{
Console.WriteLine(
"Change virtual system state failed with error {0}",
outParams["ReturnValue"]);
}
}
public static void Main(string[] args)
{
if (args != null && args.Length != 2)
{
Console.WriteLine("Usage: <application> vmName action");
Console.WriteLine("action: start|stop");
return;
}
RequestStateChange(args[0], args[1]);
}
}
}
Given:
The computer has Hyper-V manager installed with several pre-populated VMs.
Question:
How would I fire up the hyper-v client window from a winform?
Thanks
After taking some research, it appears firing up the hyper-v client is quite simple.... Below is the full function just in case anyone looks for it in the future...
public static string ConnectVM(string VMName)
{
var error = string.Empty;
var runspace = RunspaceFactory.CreateRunspace();
runspace.Open();
//create a pipeline
var path = ConfigurationManager.AppSettings["VMConnectPath"];
var pipeline = runspace.CreatePipeline();
pipeline.Commands.AddScript($"& \"{path}\" localhost '{VMName}'");
try
{
pipeline.Invoke();
}
catch (Exception e)
{
error = e.Message;
}
runspace.Close();
return error;
}

How to find Windows PCs in an IP range

I want to scan a network and enumerate hostname of all windows machines. There is an interface method that takes an ip range as input and returns hostnames. I have to implement it. So, here is my code:
public ICollection<string> EnumerateWindowsComputers(ICollection<string> ipList)
{
ICollection<string> hostNames = new List<string>();
foreach (var ip in ipList)
{
var hostName = GetHostName(ip);
if (string.IsNullOrEmpty(hostName) == false)
{
hostNames.Add(hostName)
}
}
return hostNames;
}
private static string GetHostName(string ipAddress)
{
try
{
IPHostEntry entry = Dns.GetHostEntry(ipAddress);
if (entry != null)
{
return entry.HostName;
}
}
catch (SocketException ex)
{
System.Console.WriteLine(ex.Message + " - " + ipAddress);
}
return null;
}
This method enumerates all windows machines successfully, but there are network printers in it. I can easily ignore my printers' hostname, but it will not be a good solution. I have to make sure that only the devices with the Windows operating system returned.
Any idea how to do it without a third party library? If there is a better way, we don't have to use GetHostName method.
P.S. Linux, MacOS, Android and IOS devices are not found as expected.
Service detection would not be true as there may be linux or other box emulating Windows FileSharing
Use systeminfo /s IPADDRESS shell command from Windows Machine to reliably fetch remote Windows OS details. You code will be like following:
string IPADDRESS = "192.168.1.1";
Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
p.startInfo.FileName = "cmd.exe";
p.startInfo.Arguments = "/C systeminfo /s IPADDRESS";
p.Start();
p.WaitForExit();
string output = p.StandardOutput.ReadToEnd();
string error = p.StandardError.ReadToEnd();
p.WaitForExit();
if(output.Contains("Microsoft Windows")) { Console.WriteLine("Windows OS"); }
One way you can attempt to detect the OS in a remote machine is through the use of ping. Ping each IP address and get the TTL. That should give you an idea of the OS you're dealing with. A table matching TTL to OS can be found here: http://www.kellyodonnell.com/content/determining-os-type-ping
According to #Jeroen van Langen's comment, I changed my GetHostName method with GetWindowsHostName.
private string GetWindowsHostName(string ipAddress)
{
try
{
IPHostEntry entry = Dns.GetHostEntry(ipAddress);
if (entry != null)
{
try
{
using (TcpClient tcpClient = new TcpClient())
{
// 445 is default TCP SMB port
tcpClient.Connect(ipAddress, 445);
}
using (TcpClient tcpClient = new TcpClient())
{
// 139 is default TCP NetBIOS port.
tcpClient.Connect(ipAddress, 139);
}
return entry.HostName;
}
catch (Exception ex)
{
System.Console.WriteLine(ex.Message);
}
}
}
catch (SocketException ex)
{
System.Console.WriteLine(ex.Message + " - " + ipAddress);
}
return null;
}
There can be false positive, but this is unlikely and acceptable for me.

The fastest way to ping a large list of IP adresses?

I have a large list of IP addresses in a datatable and i have to ping them so quickly,
I used this code :
public bool PingIP(string IP)
{
bool result = false;
try
{
Ping ping = new Ping();
PingReply pingReply = ping.Send(IP);
if (pingReply.Status == IPStatus.Success)
result = true;
}
catch
{
result = false;
}
return result;
}
then i call it in while loop :
private void CheckNetworkState()
{
while (rowindexping > -1)
{
if (rowindexping == tbl_ClientInfo.Rows.Count)
{
rowindexping = -1;
return;
}
string ip = tbl_ClientInfo.Rows[rowindexping]["clientip"].ToString();
if (!PingIP(ip))
{
do something
}
rowindexping++;
Thread.Sleep(100);
}
}
Since i want to do this work at the background of my project i call the class in a thread:
threadping = new Thread(CheckNetworkState);
threadping.IsBackground = true;
threadping.Start();
my problem is that it takes so many time and does not work at the background. i mean the system is busy till all ip addresses in tbl_clientinfo go through the ping class.
i want that system check all rows since i'm working with other part of my project.
Did i do correctly?
Your code is running all the code on a single thread; you're not using multiple threads. Also, why do you have a Thread.Sleep in there?
Try the following:
Query the database and get all the IPs
In a loop, spin up a new thread that will run PingIP for each IP address
Note: You can also spin up a new thread every time you get a new row from the database
Sample:
static void Main(string[] args)
{
// get the IPs from the database so you can iterate over them
List<string> ips = new List<string>()
{
"google.com",
"127.0.0.1",
"stackoverflow.com"
};
foreach (var ip in ips)
{
// See http://stackoverflow.com/questions/4744630/unexpected-behaviour-for-threadpool-queueuserworkitem
// for reason to use another variable in the loop
string loopIp = ip;
WaitCallback func = delegate(object state)
{
if (PingIP(loopIp))
{
Console.WriteLine("Ping Success");
}
else
{
Console.WriteLine("Ping Failed");
}
};
ThreadPool.QueueUserWorkItem(func);
}
Console.ReadLine();
}
public static bool PingIP(string IP)
{
bool result = false;
try
{
Ping ping = new Ping();
PingReply pingReply = ping.Send(IP);
if (pingReply.Status == IPStatus.Success)
result = true;
}
catch
{
result = false;
}
return result;
}
What I would do is have a separate multi-threaded daemon running in the background, doing the pings, and putting the results in a database. Have a page that loads results via AJAX later.
Consider making a system call to the fping utility. Granted, it's not managed code, but fping is very well optimized for your specific task and would simplify your problem down to a single call followed by the processing of a text-based list of results.
you can use powershell
private string resultat(string s)
{
Runspace space = RunspaceFactory.CreateRunspace();
space.Open();
Pipeline pipeline = space.CreatePipeline();
pipeline.Commands.AddScript(s);
pipeline.Commands.Add("Out-String");
Collection<PSObject> results = pipeline.Invoke();
StringBuilder stringBuilder = new StringBuilder();
foreach (PSObject obj in results)
{
stringBuilder.AppendLine(obj.ToString());
}
return stringBuilder.ToString();
}
and then use resultat("ping -l 10 -n 2 " + your_ip);

Problems using the WMI EnableStatic method

I'm trying to create a tool that converts the dynamic DHCP-provided IPv4 address, gateway and dns-settings into static configuration. I've tried to use WMI to solve this puzzle, but I have a problem I can't figure out.
The application completes, DNS and Gateway is configured, but the EnableStatic method (to set the IP address and subnet) has been unsuccesful which means that the IP is still received from DHCP (with greyed out fields) even though the default gateway has been set. How do I fix this?
The ReturnValue from EnableStatic is 70 (Invalid IP address). The weird thing is that the input parameters are the same that I extracted from the NIC 2 seconds earlier.
Here is the code (except GUI), http://pastebin.com/AE3dGhUz:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Management;
namespace Static_NIC_Settings_Creator
{
public partial class Form1 : Form
{
private ManagementObjectCollection queryCollection;
private string[] networkInterfaces;
private int currentNIC;
private string[] ipAddress;
private string[] subnetMask;
private string[] defaultIPGateway;
private string[] dnsServerSearchOrder;
public Form1()
{
InitializeComponent();
getNICs();
}
private void convertButton_Click(object sender, EventArgs e)
{
if (networkInterfaces.Count() > 0)
{
//Get current NIC settings
if (!getNICSettings())
{
MessageBox.Show("Retrieving current NIC settings failed.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
//Convert to static NIC settings
if (!setNICStatic())
{
MessageBox.Show("Setting NIC settings to static failed.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
}
}
private void nicSelecter_SelectedIndexChanged(object sender, EventArgs e)
{
currentNIC = nicSelecter.SelectedIndex;
}
private void getNICs()
{
//Get NICS
ManagementObjectSearcher query = new ManagementObjectSearcher("SELECT * FROM Win32_NetworkAdapterConfiguration WHERE IPEnabled = 'TRUE'");
queryCollection = query.Get();
//Make nic string array
int i = queryCollection.Count;
networkInterfaces = new string[i];
//Fill nic string array
i = 0;
foreach (ManagementObject mo in queryCollection)
{
networkInterfaces[i] = (String)mo["Description"];
i++;
}
//Fill dropbox with arraylist-data
nicSelecter.DataSource = networkInterfaces;
}
private Boolean getNICSettings()
{
//Get selected NIC
int i = 0;
foreach (ManagementObject mo in queryCollection)
{
//Get settings for specific NIC
if (i == currentNIC)
{
try
{
ipAddress = (String[])mo["IPAddress"];
subnetMask = (String[])mo["IPSubnet"];
defaultIPGateway = (String[])mo["DefaultIPGateway"];
dnsServerSearchOrder = (String[])mo["DNSServerSearchOrder"];
return true;
}
catch (Exception e)
{
System.Windows.Forms.MessageBox.Show(e.ToString(), "Critical: Unhandled error");
return false;
}
}
i++;
}
return false;
}
private Boolean setNICStatic()
{
//Get selected NIC
int i = 0;
foreach (ManagementObject mo in queryCollection)
{
//Get settings for specific NIC
if (i == currentNIC)
{
try
{
//Set static IP and subnet mask
ManagementBaseObject setIP;
ManagementBaseObject newIP = mo.GetMethodParameters("EnableStatic");
newIP["IPAddress"] = ipAddress;
newIP["SubnetMask"] = subnetMask;
setIP = mo.InvokeMethod("EnableStatic", newIP, null);
//Set default gateway
ManagementBaseObject setGateway;
ManagementBaseObject newGateway = mo.GetMethodParameters("SetGateways");
newGateway["DefaultIPGateway"] = defaultIPGateway;
newGateway["GatewayCostMetric"] = new int[] { 1 };
setGateway = mo.InvokeMethod("SetGateways", newGateway, null);
//Set dns servers
ManagementBaseObject setDNS;
ManagementBaseObject newDNS = mo.GetMethodParameters("SetDNSServerSearchOrder");
newDNS["DNSServerSearchOrder"] = dnsServerSearchOrder;
setDNS = mo.InvokeMethod("SetDNSServerSearchOrder", newDNS, null);
System.Windows.Forms.MessageBox.Show("Setting NIC settings returned: " + setDNS);
return true;
}
catch (Exception e)
{
System.Windows.Forms.MessageBox.Show(e.ToString(), "Critical: Unhandled error");
return false;
}
}
i++;
}
//No NICs
return false;
}
} //End class
}
Any ideas?
Could it be that you are inputting IPv6 addresses as well? Just playing around with PowerShell it seems not to like them. Perhaps you can post actual values that are being inputted whilst debugging, it would help a lot. Also maybe try statically inputting some values like:
new string[]{"192.168.0.1"}, new string[] {"255.255.255.255"}
Also unless you really, really need C# and a GUI you may want to consider using PowerShell (requirement is it being installed of course) as WMI is really much simpler to manipulate there (sadly you still have that learning curve though).
This is just an example of how to use PowerShell, you can at the very least use it for some testing:
Get-WmiObject Win32_NetworkAdapterConfiguration
Then get the index of your adapter then run, but replace your index number:
$obj = Get-WmiObject Win32_NetworkAdapterConfiguration | where {$_.Index -eq 1}
$obj.EnableStatic("192.168.0.1", "255.255.255.0")
To get method parameters just run:
$obj.EnableStatic
It will return:
MemberType : Method
OverloadDefinitions : {System.Management.ManagementBaseObject EnableStatic(System.String[]IPAddress, System.String[] SubnetMask)}
TypeNameOfValue : System.Management.Automation.PSMethod
Value : System.Management.ManagementBaseObject EnableStatic(System.String[]IPAddress, System.String[] SubnetMask)
Name : EnableStatic
IsInstance : True
Another tip for those who might stumble across this on search...
If your current IP address is DHCP assigned, and EnableStatic() is returning 2147944122 or 2147944117 error codes, verify the dhcp service (DHCP Client) in Windows is enabled and started.
I found that switching from one static address to another using EnableStatic() works OK. But if you have a dynamic address, and the DHCP service is disabled (possibly due to security reasons), then EnableStatic() will not work.
Adding this solution to the internet, in case it saves someone time in the future.

Categories