I am writing an application to change the IP addresses of local and remote machines using WMI. This code successfully changes the gateway and DNS of the remote machine and the same code (in a different class and minus the management scope part) changes all of the data (the two IPs, gateway, DNS) locally. The problem is it doesn't change the remote IP address. Please can someone advise as I have looked everywhere for this answer?
I have tested on windows 7 and xp with no firewalls and with .net 4 installed on remote machines
class remoteIPChange
{
public string setTillIP(string IPAddress1, string IPAddress2, string SubnetMask, string Gateway)
{
ConnectionOptions connection = new ConnectionOptions();
connection.Username = "username";
connection.Password = "password";
connection.Authority = "ntlmdomain:DOMAIN";
ManagementScope scope = new ManagementScope(
"\\\\"+IPAddress1+"\\root\\CIMV2", connection);
scope.Connect();
ObjectGetOptions o = new ObjectGetOptions();
ManagementPath p = new ManagementPath("Win32_NetworkAdapterConfiguration");
ManagementClass objMC = new ManagementClass(scope,p,o);
ManagementObjectCollection objMOC = objMC.GetInstances();
foreach (ManagementObject objMO in objMOC)
{
if (!(bool)objMO["IPEnabled"])
continue;
try
{
ManagementBaseObject objNewIP = null;
ManagementBaseObject objSetIP = null;
ManagementBaseObject objNewGate = null;
ManagementBaseObject objNewDNS = null;
objNewIP = objMO.GetMethodParameters("EnableStatic");
objNewGate = objMO.GetMethodParameters("SetGateways");
objNewDNS = objMO.GetMethodParameters("SetDNSServerSearchOrder");
//Set DefaultGateway
objNewGate["DefaultIPGateway"] = new string[] { Gateway };
objNewGate["GatewayCostMetric"] = new int[] { 1 };
//Set IPAddress and Subnet Mask
objNewIP["IPAddress"] = new string[] { IPAddress1, IPAddress2 };
objNewIP["SubnetMask"] = new string[] { SubnetMask, SubnetMask };
//Set DNS servers
objNewDNS["DNSServerSearchOrder"] = new string[] {Gateway };
//Invoke all changes
objSetIP = objMO.InvokeMethod("EnableStatic", objNewIP, null);
objSetIP = objMO.InvokeMethod("SetGateways", objNewGate, null);
objSetIP = objMO.InvokeMethod("SetDNSServerSearchOrder", objNewDNS, null);
return ("Updated IPAddress to " + IPAddress + ", \nSubnetMask to " + SubnetMask + " \nand Default Gateway to " + Gateway + "!");
}
catch (Exception ex)
{
return ("Unable to Set IP : " + ex.Message);
}
}
return "code has not run";
}
}
I would check the ReturnValue from the invokemethod on EnableStatic. I am pretty sure passing in a null for your subnet is your problem. Provide a valid array of subnets that match your ip addresses instead of that null.
Related
I need some sample code to create/delete zone and A record in microsoft DNS server by C#
You have to use WMI to invoke the DNSProvider.
This to add a record:
public void AddARecord(string hostName, string zone, string iPAddress, string dnsServerName)
{
ManagementScope scope =
new ManagementScope(#"\\" + dnsServerName + "\\root\\MicrosoftDNS");
scope.Connect();
ManagementClass cmiClass =
new ManagementClass(scope,
new ManagementPath("MicrosoftDNS_AType"),
null);
ManagementBaseObject inParams =
cmiClass.GetMethodParameters("CreateInstanceFromPropertyData");
inParams["DnsServerName"] = this.ServerName;
inParams["ContainerName"] = zone;
inParams["OwnerName"] = hostName + "." + zone;
inParams["IPAddress"] = iPAddress;
cmiClass.InvokeMethod("CreateInstanceFromPropertyData", inParams, null);
}
You can reference the WMI reference and extend this as you need using the methods and classes
http://msdn.microsoft.com/en-us/library/ms682123(v=vs.85).aspx
Microsoft exposes it as a POX service, so you could just push XML over the wire to it, using the System.Net stuff & your user credentials.
http://technet.microsoft.com/en-us/library/dd278634.aspx
I agreed with Taylor but in my case i have got 2 different error with above code
1- Generic Error
2- Not Found error
Below code has solved this problems
private ManagementPath UpdateARecord(string strDNSZone, string strHostName, string strIPAddress)
{
ManagementScope mgmtScope = new ManagementScope(#"\\.\Root\MicrosoftDNS");
ManagementClass mgmtClass = null;
ManagementBaseObject mgmtParams = null;
ManagementObjectSearcher mgmtSearch = null;
ManagementObjectCollection mgmtDNSRecords = null;
string strQuery;
strQuery = string.Format("SELECT * FROM MicrosoftDNS_AType WHERE OwnerName = '{0}.{1}'", strHostName, strDNSZone);
mgmtScope.Connect();
mgmtSearch = new ManagementObjectSearcher(mgmtScope, new ObjectQuery(strQuery));
mgmtDNSRecords = mgmtSearch.Get();
//// Multiple A records with the same record name, but different IPv4 addresses, skip.
//if (mgmtDNSRecords.Count > 1)
//{
// // Take appropriate action here.
//}
//// Existing A record found, update record.
//else
if (mgmtDNSRecords.Count == 1)
{
ManagementObject mo = new ManagementObject();
foreach (ManagementObject mgmtDNSRecord in mgmtDNSRecords)
{
if (mgmtDNSRecord["RecordData"].ToString() != strIPAddress)
{
mgmtParams = mgmtDNSRecord.GetMethodParameters("Modify");
mgmtParams["IPAddress"] = strIPAddress;
mgmtDNSRecord.InvokeMethod("Modify", mgmtParams, null);
}
mo = mgmtDNSRecord;
break;
}
return new ManagementPath(mo["RR"].ToString());
}
// A record does not exist, create new record.
else
{
mgmtClass = new ManagementClass(mgmtScope, new ManagementPath("MicrosoftDNS_AType"), null);
mgmtParams = mgmtClass.GetMethodParameters("CreateInstanceFromPropertyData");
mgmtParams["DnsServerName"] = Environment.MachineName;
mgmtParams["ContainerName"] = strDNSZone;
mgmtParams["OwnerName"] = strDNSZone;// string.Format("{0}.{1}", strHostName.ToLower(), strDNSZone);
mgmtParams["IPAddress"] = strIPAddress;
var outParams = mgmtClass.InvokeMethod("CreateInstanceFromPropertyData", mgmtParams, null);
if ((outParams.Properties["RR"] != null))
{
return new ManagementPath(outParams["RR"].ToString());
}
}
return null;
}
I am having quite some difficulty connecting a specific, existing network adapter to an existing switch. I can create a new network adapter and connect it to my VM through several examples posted online but cannot make that extra step. The following function finds my network adapter and executes without error, but does not otherwise make the connection. Any assistance is greatly appreciated!
**EDIT: Solved, see code below.**
Solved:
public static void ConnectInterfaceToSwitch(string VmName, string networkInterfaceName, string switchName)
{
ManagementScope scope = new ManagementScope(#"root\virtualization\v2");
ManagementObject mgtSvc = WmiUtilities.GetVirtualMachineManagementService(scope);
ManagementObject ethernetSwitch = NetworkingUtilities.FindEthernetSwitch(switchName, scope);
ManagementObject virtualMachine = WmiUtilities.GetVirtualMachine(VmName, scope);
ManagementObject virtualMachineSettings = WmiUtilities.GetVirtualMachineSettings(virtualMachine);
ManagementObjectCollection portsSettings = virtualMachineSettings.GetRelated("Msvm_SyntheticEthernetPortSettingData", "Msvm_VirtualSystemSettingDataComponent", null, null, null, null, false, null);
{
foreach (ManagementObject portSettings in portsSettings)
{
if (portSettings["ElementName"].Equals(networkInterfaceName))
{
Console.WriteLine("Adapter found: " + networkInterfaceName);
ManagementObjectCollection connections = portSettings.GetRelated("Msvm_EthernetPortAllocationSettingData");
foreach (ManagementObject connection in connections)
{
connection["HostResource"] = new string[] { ethernetSwitch.Path.Path };
connection["EnabledState"] = 2; // 2 means "Enabled"
ManagementBaseObject inParams = mgtSvc.GetMethodParameters("ModifyResourceSettings");
inParams["ResourceSettings"] = new string[] { connection.GetText(TextFormat.WmiDtd20) };
ManagementBaseObject outParams = mgtSvc.InvokeMethod("ModifyResourceSettings", inParams, null);
WmiUtilities.ValidateOutput(outParams, scope);
Console.WriteLine(string.Format(CultureInfo.CurrentCulture, "Connected VM '{0}' to switch '{1}'.", VmName, switchName));
}
}
}
}
}
I'm trying to write a small command line application with C# that will prompt for a username and a password that will be used to login to several remote computers that are sitting on the same network/domain and start a local session.
I've tried connecting to a remote computer and to query the remote PC's operating system info with the following code:
ConnectionOptions options = new ConnectionOptions();
ManagementScope scope = new ManagementScope(#"\\REMOTE_COMPUTER_NAME");
scope.Connect();
ObjectQuery query = new ObjectQuery("SELECT * FROM Win32_OperatingSystem");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query);
ManagementObjectCollection queryCollection = searcher.Get();
foreach (ManagementObject m in queryCollection)
{
// Display the remote computer information
Console.WriteLine("Computer Name : {0}", m["csname"]);
Console.WriteLine("Windows Directory : {0}", m["WindowsDirectory"]);
Console.WriteLine("Operating System: {0}", m["Caption"]);
Console.WriteLine("Version: {0}", m["Version"]);
Console.WriteLine("Manufacturer : {0}", m["Manufacturer"]);
}
However, this only returns information on the local PC that I'm working on and not on the remote PC.
Am I overlooking something with this code? And is there an appropriate approach to accomplish what I am trying to do?
I don't have remote machine right now to give you the working example, but you can try this. advapi32.logonuser
Example:
[DllImport("advapi32.dll")]
public static extern bool LogonUser(string name, string domain, string pass,
int logType, int logpv, out IntPtr pht);
IntPtr ptr;
// LogonUser("username", "remotemachine", "password", 2, 0, out ptr);
LogonUser("username", "remotemachine", "password", 9, 0, out ptr);
WindowsIdentity windowsIdentity = new WindowsIdentity(ptr);
var impersonationContext = windowsIdentity.Impersonate();
// your code goes here...
impersonationContext.Undo();
This logon type allows the caller to clone its current token and
specify new credentials for outbound connections. The new logon
session has the same local identifier but uses different credentials
for other network connections. NOTE: This logon type is supported
only by the LOGON32_PROVIDER_WINNT50 logon provider. NOTE: Windows NT:
This value is not supported.
http://www.pinvoke.net/default.aspx/advapi32.logonuser
Edit
Give it a try cassia
ITerminalServicesManager manager = new TerminalServicesManager();
using (ITerminalServer server = manager.GetRemoteServer("servername"))
{
server.Open();
foreach (ITerminalServicesSession session in server.GetSessions())
{
Console.WriteLine("Hi there, " + session.UserAccount + " on session " + session.SessionId);
Console.WriteLine("It looks like you logged on at " + session.LoginTime +
" and are now " + session.ConnectionState);
}
}
You have to use ConnectionOptions and pass it to the ManagementScope
public void GetSystemInformation(string _yourDomain, string _hostName, string _userName, SecureString _password)
{
ManagementScope Scope = null;
string computerName = _hostName;
string userName = _userName;
SecureString password = _password;
ManagementObjectCollection collection = null;
try
{
SelectQuery query = new SelectQuery("SELECT * FROM Win32_OperatingSystem");
//string query = "SELECT * FROM Win32_NetworkAdapterConfiguration" + " WHERE IPEnabled = 'TRUE'";
var options = new ConnectionOptions
{
EnablePrivileges = false,
Impersonation = ImpersonationLevel.Impersonate,
Username = _userName,
SecurePassword = _password,
Authority = "ntlmdomain:" + _yourDomain
};
Scope.Options = options;
Scope.Connect();
ManagementObjectSearcher searcher = new ManagementObjectSearcher(Scope, query);
collection = searcher.Get();
//Do something with the collection
}
catch (ManagementException ex)
{
Console.WriteLine(ex.Message);
}
catch (UnauthorizedAccessException ex)
{
throw new ArgumentException(ex.Message);
}
}
private static SecureString CreateSecuredString(string pw)
{
var secureString = new SecureString();
foreach (var c in pw)
{
secureString.AppendChar(c);
}
return secureString;
}
You might have to try some different stats with the variables EnablePrivileges and Impersonation
edit:
If you want to get your information from your pc (local) than you dont have to pass the options to the scope.
I'm looking for a way to get the users that are logged in on a remote machine. I would love to know if they are logged on localy or remotely, but most of all I MUST know their status.
I saw some answers on the net that are written in VB, but I need it in c#.
the solution given in markdmak answer here is looking like a good start, but it's in VB and it looks for remote sessions only.
I have this piece of code, which can be a start, but I would like to couple the LogonId to a username and to see its status:
string fqdn = ""; // set!!!
ConnectionOptions options = new ConnectionOptions();
options.EnablePrivileges = true;
// To connect to the remote computer using a different account, specify these values:
// these are needed in dev environment
options.Username = ConfigurationManager.AppSettings["KerberosImpersonationUser"];
options.Password = ConfigurationManager.AppSettings["KerberosImpersonationPassword"];
options.Authority = "ntlmdomain:" + ConfigurationManager.AppSettings["KerberosImpersonationDomain"];
ManagementScope scope = new ManagementScope("\\\\" + fqdn + "\\root\\CIMV2", options);
try
{
scope.Connect();
}
catch (Exception ex)
{
if (ex.Message.StartsWith("The RPC server is unavailable"))
{
// The Remote Procedure Call server is unavailable
// cannot check for logged on users
return false;
}
else
{
throw ex;
}
}
SelectQuery query = new SelectQuery("Select * from Win32_LogonSession");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query);
ManagementObjectCollection results = searcher.Get();
bool returnVal = false;
foreach (ManagementObject os in results)
{
try
{
if (os.GetPropertyValue("LogonId").ToString() != null && os.GetPropertyValue("LogonId").ToString() != "")
{
returnVal = true;
}
}
catch (NullReferenceException)
{
continue;
}
}
return returnVal;
}
What I really need and can't find, is a way of getting ALL users on a remote machine AND their status, meaning: Active, Disconnected, Logged-off, etc.
You can use the Win32_LogonSession WMI class filtering for the LogonType property with the value 2 (Interactive)
Try this sample
using System;
using System.Collections.Generic;
using System.Management;
using System.Text;
namespace GetWMI_Info
{
class Program
{
static void Main(string[] args)
{
try
{
string ComputerName = "remote-machine";
ManagementScope Scope;
if (!ComputerName.Equals("localhost", StringComparison.OrdinalIgnoreCase))
{
ConnectionOptions Conn = new ConnectionOptions();
Conn.Username = "username";
Conn.Password = "password";
Conn.Authority = "ntlmdomain:DOMAIN";
Scope = new ManagementScope(String.Format("\\\\{0}\\root\\CIMV2", ComputerName), Conn);
}
else
Scope = new ManagementScope(String.Format("\\\\{0}\\root\\CIMV2", ComputerName), null);
Scope.Connect();
ObjectQuery Query = new ObjectQuery("SELECT LogonId FROM Win32_LogonSession Where LogonType=2");
ManagementObjectSearcher Searcher = new ManagementObjectSearcher(Scope, Query);
foreach (ManagementObject WmiObject in Searcher.Get())
{
Console.WriteLine("{0,-35} {1,-40}", "LogonId", WmiObject["LogonId"]);// String
ObjectQuery LQuery = new ObjectQuery("Associators of {Win32_LogonSession.LogonId=" + WmiObject["LogonId"] + "} Where AssocClass=Win32_LoggedOnUser Role=Dependent");
ManagementObjectSearcher LSearcher = new ManagementObjectSearcher(Scope, LQuery);
foreach (ManagementObject LWmiObject in LSearcher.Get())
{
Console.WriteLine("{0,-35} {1,-40}", "Name", LWmiObject["Name"]);
}
}
}
catch (Exception e)
{
Console.WriteLine(String.Format("Exception {0} Trace {1}", e.Message, e.StackTrace));
}
Console.WriteLine("Press Enter to exit");
Console.Read();
}
}
}
#RRUZ got me started but the Associators query did not work on remote machine with a lot of Win32_LoggedOnUser objects (don't know why). No results were returned.
I also needed remote Desktop sessions so I used LogonType "10" sessions and my ConnectionOptions were differents
I replaced the Associators query with WmiObject.GetRelationships("Win32_LoggedOnUser") and the speed increases by a lot and results were there.
private void btnUnleash_Click(object sender, EventArgs e)
{
string serverName = "serverName";
foreach (var user in GetLoggedUser(serverName))
{
dataGridView1.Rows.Add(serverName, user);
}
}
private List<string> GetLoggedUser(string machineName)
{
List<string> users = new List<string>();
try
{
var scope = GetManagementScope(machineName);
scope.Connect();
var Query = new SelectQuery("SELECT LogonId FROM Win32_LogonSession Where LogonType=10");
var Searcher = new ManagementObjectSearcher(scope, Query);
var regName = new Regex(#"(?<=Name="").*(?="")");
foreach (ManagementObject WmiObject in Searcher.Get())
{
foreach (ManagementObject LWmiObject in WmiObject.GetRelationships("Win32_LoggedOnUser"))
{
users.Add(regName.Match(LWmiObject["Antecedent"].ToString()).Value);
}
}
}
catch (Exception ex)
{
users.Add(ex.Message);
}
return users;
}
private static ManagementScope GetManagementScope(string machineName)
{
ManagementScope Scope;
if (machineName.Equals("localhost", StringComparison.OrdinalIgnoreCase))
Scope = new ManagementScope(String.Format("\\\\{0}\\root\\CIMV2", "."), GetConnectionOptions());
else
{
Scope = new ManagementScope(String.Format("\\\\{0}\\root\\CIMV2", machineName), GetConnectionOptions());
}
return Scope;
}
private static ConnectionOptions GetConnectionOptions()
{
var connection = new ConnectionOptions
{
EnablePrivileges = true,
Authentication = AuthenticationLevel.PacketPrivacy,
Impersonation = ImpersonationLevel.Impersonate,
};
return connection;
}
I need some sample code to create/delete zone and A record in microsoft DNS server by C#
You have to use WMI to invoke the DNSProvider.
This to add a record:
public void AddARecord(string hostName, string zone, string iPAddress, string dnsServerName)
{
ManagementScope scope =
new ManagementScope(#"\\" + dnsServerName + "\\root\\MicrosoftDNS");
scope.Connect();
ManagementClass cmiClass =
new ManagementClass(scope,
new ManagementPath("MicrosoftDNS_AType"),
null);
ManagementBaseObject inParams =
cmiClass.GetMethodParameters("CreateInstanceFromPropertyData");
inParams["DnsServerName"] = this.ServerName;
inParams["ContainerName"] = zone;
inParams["OwnerName"] = hostName + "." + zone;
inParams["IPAddress"] = iPAddress;
cmiClass.InvokeMethod("CreateInstanceFromPropertyData", inParams, null);
}
You can reference the WMI reference and extend this as you need using the methods and classes
http://msdn.microsoft.com/en-us/library/ms682123(v=vs.85).aspx
Microsoft exposes it as a POX service, so you could just push XML over the wire to it, using the System.Net stuff & your user credentials.
http://technet.microsoft.com/en-us/library/dd278634.aspx
I agreed with Taylor but in my case i have got 2 different error with above code
1- Generic Error
2- Not Found error
Below code has solved this problems
private ManagementPath UpdateARecord(string strDNSZone, string strHostName, string strIPAddress)
{
ManagementScope mgmtScope = new ManagementScope(#"\\.\Root\MicrosoftDNS");
ManagementClass mgmtClass = null;
ManagementBaseObject mgmtParams = null;
ManagementObjectSearcher mgmtSearch = null;
ManagementObjectCollection mgmtDNSRecords = null;
string strQuery;
strQuery = string.Format("SELECT * FROM MicrosoftDNS_AType WHERE OwnerName = '{0}.{1}'", strHostName, strDNSZone);
mgmtScope.Connect();
mgmtSearch = new ManagementObjectSearcher(mgmtScope, new ObjectQuery(strQuery));
mgmtDNSRecords = mgmtSearch.Get();
//// Multiple A records with the same record name, but different IPv4 addresses, skip.
//if (mgmtDNSRecords.Count > 1)
//{
// // Take appropriate action here.
//}
//// Existing A record found, update record.
//else
if (mgmtDNSRecords.Count == 1)
{
ManagementObject mo = new ManagementObject();
foreach (ManagementObject mgmtDNSRecord in mgmtDNSRecords)
{
if (mgmtDNSRecord["RecordData"].ToString() != strIPAddress)
{
mgmtParams = mgmtDNSRecord.GetMethodParameters("Modify");
mgmtParams["IPAddress"] = strIPAddress;
mgmtDNSRecord.InvokeMethod("Modify", mgmtParams, null);
}
mo = mgmtDNSRecord;
break;
}
return new ManagementPath(mo["RR"].ToString());
}
// A record does not exist, create new record.
else
{
mgmtClass = new ManagementClass(mgmtScope, new ManagementPath("MicrosoftDNS_AType"), null);
mgmtParams = mgmtClass.GetMethodParameters("CreateInstanceFromPropertyData");
mgmtParams["DnsServerName"] = Environment.MachineName;
mgmtParams["ContainerName"] = strDNSZone;
mgmtParams["OwnerName"] = strDNSZone;// string.Format("{0}.{1}", strHostName.ToLower(), strDNSZone);
mgmtParams["IPAddress"] = strIPAddress;
var outParams = mgmtClass.InvokeMethod("CreateInstanceFromPropertyData", mgmtParams, null);
if ((outParams.Properties["RR"] != null))
{
return new ManagementPath(outParams["RR"].ToString());
}
}
return null;
}