Resolving the WMI DNS Host Name - c#

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.

Related

Retrieve LoggedOnUsers on Remote Machine

I'm building a C# application to monitor server and workstation workloads with WMI and WQL queries. I'm using WMI because it seems to be faster in comparison to powershell queries. My hardship starts when I try to retrieve logged on users on a remote machine. I figured I need to use the Win32_LoggedOnUser class. I have tried the following queries:
#"SELECT * FROM Win32_LoggedOnUser"
#"SELECT Antecedent FROM Win32_LoggedOnUser"
What I'm used to is to retrieve the desired value like this:
var cims = connection.getCimInstances(this, queryUser);
if (cims != null)
{
foreach (CimInstance cim in cims)
{
Komponenten.User user = new Komponenten.User();
user.Name = Convert.ToString(cim.CimInstanceProperties["Name"].Value);
users.Add(user);
}
}
where queryUser is one of the strings from above.
In both cases, I get a Win32_Account object in return, which seems to suggest - and the debugger seems to confirm - that I should use CimInstanceProperties["Name"].Value on the returned Win32_Account class again. But that's not working at all. Any ideas on how to get access to the CimInstanceProperties of a Win32_Account stored in a CimInstanceProperity ? I can't find anything on the respective Windows reference page (https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/win32-loggedonuser) nor during my extensive google-search.
Thanks!
I ended up using the ManagementObject-Class and Regex to find the usernames after converting the Antecedent - Object to a string:
var users = new List<Komponenten.User>();
var searcher = this.connection.makeQuery(this, "SELECT * FROM Win32_LoggedOnUser");
if (searcher != null)
{
foreach (ManagementObject queryObj in searcher.Get())
{
Komponenten.User user = new Komponenten.User();
var win32_account = queryObj["Antecedent"].ToString();
string stripped = Regex.Replace(win32_account, "[^a-zA-Z=]+", "", RegexOptions.Compiled);
int end = stripped.LastIndexOf("=");
user.Name = stripped.Substring(end+1);
users.Add(user);
}
this.users = users;
An alternative which takes the LogonSession into account is:
var users = new List<Komponenten.User>();
var searcher = this.connection.makeQuery(this, "SELECT LogonId FROM Win32_LogonSession Where LogonType=2");
var Scope = this.connection.getScope(this, this.connection.getConnection());
if (searcher != null)
{
foreach (ManagementObject queryObj in searcher.Get())
{
ObjectQuery LQuery = new ObjectQuery("Associators of {Win32_LogonSession.LogonId=" + queryObj["LogonId"] + "} Where AssocClass=Win32_LoggedOnUser Role=Dependent");
ManagementObjectSearcher LSearcher = new ManagementObjectSearcher(Scope, LQuery);
foreach (ManagementObject LWmiObject in LSearcher.Get())
{
Komponenten.User user = new Komponenten.User();
user.Name = Convert.ToString(LWmiObject["Name"]);
users.Add(user);
}
}
this.users = users;
}
where this.connection.getConnection is a ConnectionsOption object depending on your respective domain and account data

How to run services of one pc from another pc

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.

C# get user's current pc in a domain

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?

How can you remotely login to a remote computer using C#?

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.

WMI dependent services to use WMI Query

I am using WMI query to get share folder:
public static List<string> GetNetworkShareFoldersList(string serverName)
{
List<string> shares = new List<string>();
// do not use ConnectionOptions to get shares from local machine
ConnectionOptions connectionOptions = new ConnectionOptions();
//connectionOptions.Username = #"Domain\Administrator";
//connectionOptions.Password = "password";
//connectionOptions.Impersonation = ImpersonationLevel.Impersonate;
ManagementScope scope = new ManagementScope("\\\\" + serverName + "\\root\\CIMV2",
connectionOptions);
scope.Connect();
ManagementObjectSearcher worker = new ManagementObjectSearcher(scope,
new ObjectQuery("select Name from win32_share"));
foreach (ManagementObject share in worker.Get())
{
shares.Add(share["Name"].ToString());
}
return shares;
}
Thanks to the link http://www.morgantechspace.com/2014/02/Get-or-List-Network-shares-in-CSharp-using-WMI.html
Now my question is is this wmi code depends on any Windows Service in local or remote machine?... bcoz I am getting 0 results from above code

Categories

Resources