I have a code that tries to access the services of another computer.
try
{
var serviceName = "MyService";
var ip = "10.10.11.16";
var username = "SomeUser";
var password = "APassword";
var connectoptions = new ConnectionOptions();
connectoptions.Impersonation = ImpersonationLevel.Impersonate;
connectoptions.Authentication = AuthenticationLevel.Packet;
connectoptions.EnablePrivileges = true;
connectoptions.Username = username;
connectoptions.Password = password;
var scope = new ManagementScope("\\\\10.10.11.16\\root\\cimv2");
scope.Options = connectoptions;
var query = new SelectQuery("select * from Win32_Service where name = '" + serviceName + "'");
using (ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query))
{
var collection = searcher.Get();
foreach (ManagementObject service in collection.OfType<ManagementObject>())
{
if (service["started"].Equals(true))
{
service.InvokeMethod("StopService", null);
BtnStartStop.Content = "Stop";
LblService.Content = serviceName;
LblServiceStatus.Content = "Stopped";
}
else
{
service.InvokeMethod("StartService", null);
BtnStartStop.Content = "Stop";
LblService.Content = serviceName;
LblServiceStatus.Content = "Running";
}
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
Will this work on Server and client only? Won't this work on regular pc to another regular pc? Each time I run this when I get to the part of:
var collection = searcher.Get();
I get an error of
Access is denied. (Exception from HRESULT: 0x80070005
(E_ACCESSDENIED))
Do you have an idea on to make this work? Thank you.
STEPS DONE SO FAR
Followed the instruction on
https://learn.microsoft.com/en-us/windows/win32/wmisdk/connecting-to-wmi-remotely-starting-with-vista
typed in the cmd with admin privilege
netsh advfirewall firewall set rule group="windows management instrumentation (wmi)" new enable=yes
I even turned off the firewall just to be sure.
edited the registry of the pc I am connecting to this:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WBEM\CIMOM\AllowAnonymousCallback
Data type
REG\_DWORD
As for the antivirus, the pc I am connecting to does not have any anti virus.
I still get the same error.
As #colosso pointed out, you are receiving that error message because you do not have permission on the remote host to connect to the WMI service.
You should follow the instructions here to ensure the remote host is configured to allow your connection.
Related
I want to enter the logon ID and to receive the current PC that the account is logged.
I found a code with WMI, but running on 10,000+ computers takes a very long while (~ I gave up after 10 minutes.)
What I do is checking who is logged in every computer until there is a match between logged account and searched account.
private void getCurrentUser()
{
try
{
DirectoryEntry entry = new DirectoryEntry("LDAP://" + DOMAIN);
DirectorySearcher dSearch = new DirectorySearcher(entry);
dSearch.Filter = ("objectCategory=computer");
foreach (SearchResult result in dSearch.FindAll())
{
ManagementScope theScope = new ManagementScope("\\\\" + result.Properties["cn"][0].ToString() + "\\root\\cimv2");
ObjectQuery theQuery = new ObjectQuery("SELECT username FROM Win32_ComputerSystem");
ManagementObjectSearcher theSearcher = new ManagementObjectSearcher(theScope, theQuery);
ManagementObjectCollection theCollection = theSearcher.Get();
foreach (ManagementObject theCurObject in theCollection)
{
if (theCurObject["username"].ToString() == "LAS\\" + USERNAME)
Computer1.Text = result.Properties["cn"][0].ToString();
}
}
}
catch (Exception)
{
MessageBox.Show("Error");
}
}
this is the code, it works but I would like to know if there is another way to do that without waiting so long or how can I do it quickly?
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 have a WCF Service which is running on IIS. ApplicationPool uses the LocalSystem Identity.
The WCF Service has an method for rebooting the system with WMI using the following code:
ManagementBaseObject mboShutdown = null;
ManagementClass mcWin32 = null;
try
{
mcWin32 = new ManagementClass("Win32_OperatingSystem");
mcWin32.Get();
// You can't shutdown without security privileges
mcWin32.Scope.Options.EnablePrivileges = true;
ManagementBaseObject mboShutdownParams = mcWin32.GetMethodParameters("Win32Shutdown");
// Flag 6 means we want to trigger a force reboot
mboShutdownParams["Flags"] = "6";
mboShutdownParams["Reserved"] = "0";
foreach (ManagementObject manObj in mcWin32.GetInstances())
{
mboShutdown = manObj.InvokeMethod("Win32Shutdown", mboShutdownParams, null);
var result = Convert.ToInt32(mboShutdown["returnValue"]);
if (result != 0) throw new Win32Exception(result, "Could not restart local machine!");
}
}
catch (Exception ex)
{
SkippyLogger.WriteError(ex, "Error in IISAdminService.Restart");
throw ex;
}
finally
{
if (mcWin32 != null)
mcWin32.Dispose();
}
The method throw an exception with "Privilege not held".
Few things to try...
this
Can you run the same method, as LocalSystem outside of IIS - i.e host it as a windows service installed of IIS?
We have a similar system (hosted as a windows service) and it performs the actual reboot using this class.
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.
I am trying to make a comparison between a machine name i have retrieved from AD, and the DNS Host Name i want to get using WMI from the machine.
I currently have:
foreach (SearchResult oneMachine in allMachinesCollected)
{
pcName = oneMachine.Properties["name"][0].ToString();
ConnectionOptions setupConnection = new ConnectionOptions();
setupConnection.Username = USERNAME;
setupConnection.Password = PASSWORD;
setupConnection.Authority = "ntlmdomain:DOMAIN";
ManagementScope setupScope = new ManagementScope("\\\\" + pcName + "\\root\\cimv2", setupConnection);
setupScope.Connect();
ObjectQuery dnsNameQuery = new ObjectQuery("SELECT * FROM Win32_ComputerSystem");
ManagementObjectSearcher dnsNameSearch = new ManagementObjectSearcher(setupScope, dnsNameQuery);
ManagementObjectCollection allDNSNames = dnsNameSearch.Get();
string dnsHostName;
foreach (ManagementObject oneName in allDNSNames)
{
dnsHostName = oneName.Properties["DNSHostName"].ToString();
if (dnsHostName == pcName)
{
shutdownMethods.ShutdownMachine(pcName, USERNAME, PASSWORD);
MessageBox.Show(pcName + " has been sent the reboot command");
}
}
}
}
But i get a ManagementException >> dnsHostName = oneName.Properties["DNSHostName"].ToString(); << here saying not found.
Any ideas?
Depending on the operating system you are connecting to this property will not be available. You can see from the documentation that it is not available on Windows 2000 and XP. However, it is available on the Win32_NetworkAdapterConfiguration class, but you will receive more than one object, which you will have to loop over to get the name as most of them will be null.
Also, dnsHostName = oneName.Properties["DNSHostName"].ToString(); is not correct. It should be dnsHostName = oneName.Properties["DNSHostName"].Value.ToString(). Again, if you decide to use Win32_NetworkAdapterConfiguration keep in mind that it can be null.