I am trying to query hardware data of computers on my local domain using WMI in a C# ASP.NET Application running on a server using IIS.
After successfully opening a cim session using the New-CimSession
cmdlet and querying WMI data in powershell I tried to acomplish the same thing using CimSession.Create
in C#.
However when trying to query the same data using C# I receive an Access Denied
error with code 0x80070005
.
According to the microsoft documentation (https://learn.microsoft.com/en-us/windows/win32/wmisdk/wmi-troubleshooting) this is caused by DCOM.
So far I have been unable to come up with a different solution and I find it weird that essentially the same attempt works fine when using powershell.
Some general information:
Successful attempt in powershell:
$CimSession = New-CimSession -ComputerName "PC-HOSTNAME" -Credential (Get-Credential)
Get-CimInstance -CimSession $CimSession -ClassName Win32_ComputerSystem
Code example trying to use the same credentials from the windows user logged in on the server running the application without passing explicit authentication parameters:
CimSession session = CimSession.Create("PC-HOSTNAME");
// The next line results in the error
var response = session.QueryInstances(@"root\cimv2", "WQL", "SELECT * FROM Win32_ComputerSystem");
This should work as is but to make sure I also tried passing explicit authentication parameters which also results in the same error:
DComSessionOptions dComOptions = new DComSessionOptions();
dComOptions.Impersonation = ImpersonationType.Impersonate;
//Build secure string from plain text for representation
var somePasswordString = "password"
var password = new SecureString();
somePasswordString.ToList().ForEach(x => password.AppendChar(x));
dComOptions.AddDestinationCredentials(new CimCredential(PasswordAuthenticationMechanism.Default, "mydomain.local", "myusername", password));
CimSession session = CimSession.Create("PC-HOSTNAME");
// The next line results in the error
var response = session.QueryInstances(@"root\cimv2", "WQL", "SELECT * FROM Win32_ComputerSystem");
I have seen many different approaches on WMI in C# but using CimSession
with the QueryInstances
method seemed to be the most straight forward for my use case. Nonetheless all other code examples I found resulted in the same error.
Any help would be greatly appreciated - thanks!
As pointed out by @IanKemp I understand that it's bad practice to run operations requiring administrator permissions in a web application. However I am just trying to figure out how to run a basic WMI query in C# and what issues could lead to me getting the described Access Denied
error whereas it works perfectly fine using powershell.
I have found an interesting answer on serverfault: https://serverfault.com/a/1105113
If you are trying to access WMI there are two protocols available: DCOM and WinRM. Which protocol you are using will depend on the tools or API being used. For example, when you are using PowerShell, the 'older' Get-WmiObject cmdlet uses DCOM, whereas the 'newer' Get-CimInstance cmdlet uses WinRM.
This could explain why powershell behaves differently in my case but I still had no luck finding a solution to get it to work in C#
After a bit of trial and error I have found a solution to my problem.
As mentioned in my "Update V2" this post lead to my solution: https://serverfault.com/a/1105113
Two things that resolved my problem:
I granted my user 'Remote Enable' permissions under WMI control as mentioned in the post on serverfault
In development I have to run Visual Studio as Administrator (don't know why but this resolved any Access Denied issues I encountered earlier even though I authenticated as administrator in code)
Edit: I posted a new post about using wmi without admin permissions Running wmi queries as a non-admin user on a remote machine using C#