0
votes

I'm using WinRM API in an attempt to collect some CIM instances from several hosts running either Windows or Linux. My code works fine when connecting to a Windows host, but an exception is thrown if I try to connect to a Linux machine, which is running the SFCB CIM server. I can retrieve CIM instances from the Linux host just fine via WBEM, but not via WS-MAN/WinRM.

Here's sample code that gets CIM_OperatingSystem from a Windows host - this works fine:

WSMan wsman = new WSMan();
IWSManConnectionOptions options = (IWSManConnectionOptions)wsman.CreateConnectionOptions();               

try
{
    string remoteHost = "WindowsHost1";
    options.UserName = @"domain\User";                    
    options.Password = "somePwd";                                                           
    IWSManSession session = (IWSManSession)wsman.CreateSession(remoteHost, wsman.SessionFlagCredUsernamePassword(), options);

    try
    {
        IWSManEnumerator cimInstances = session.Enumerate("http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/CIM_OperatingSystem");

        // Enumerate returned CIM instances.
        while (!cimInstances.AtEndOfStream)
        {
            string item = cimInstances.ReadItem();                  
            XDocument doc = XDocument.Parse(item);
            var resultSet = from e in doc.Elements() select e;

            foreach (var element in resultSet)
            {
                Console.WriteLine(element);
            }
        }
    }
    finally
    {
        Marshal.ReleaseComObject(session);
    }
}
finally
{
    Marshal.ReleaseComObject(options);
}   

If remoteHost points to a Linux machine (openSUSE VM in my example), here's what happens:

  • if I specify the hostname only, i.e. remoteHost = "myLinuxHost", session.Enumerate() fails:

Unhandled Exception: System.IO.FileNotFoundException: The network path was not found. at WSManAutomation.IWSManSession.Enumerate(Object resourceUri, String filter, String dialect, Int32 flags)

I can ping the machine successfully, so it should be visible. However, the hostname is only mapped to its IP in my Windows hosts file. If I try to create a session to this machine with PowerShell, an error occurs as well:

PS C:\Windows\system32> $session = new-cimsession myLinuxHost -credential user

new-cimsession : WinRM cannot process the request. The following error occurred while using Kerberos authentication: Cannot find the computer myLinuxHost. Verify that the computer exists on the network and that the name provided is spelled correctly.

  • if I specify the complete host URL (one that I can retrieve CIM instances with using WBEM), i.e. remoteHost = "https://<ip>:5989" or remoteHost = "https://myLinuxHost:5989" enumeration fails with:

Unhandled Exception: System.Runtime.InteropServices.COMException: A security error occurred at WSManAutomation.IWSManSession.Enumerate(Object resourceUri, String filter, String dialect, Int32 flags)

Details:

System.Runtime.InteropServices.COMException was unhandled
HResult=-2147012721
Message=A security error occurred 
Source=Session
ErrorCode=-2147012721
StackTrace:
   at WSManAutomation.IWSManSession.Enumerate(Object resourceUri, String filter, String dialect, Int32 flags)
   at WSManTest.Program.Main(String[] args)
   at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
   at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
   at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
   at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ThreadHelper.ThreadStart()

What am I doing wrong?

1

1 Answers

1
votes

After reading some manuals on how to establish a Powershell session to a non-WSMAN machine by using HTTPS CIMSessions, I have found that there is a parameter of type CIMSessionOption which can be constructed to use SSL, so that the actual connection is done via WBEM interface over HTTPS. The document is here, the codes are as follows:

$UserName="root"
$Password="calvin" # default password
$DracIP="10.10.0.120" # supply your box's IP
$SecurePass = ConvertTo-SecureString $Password -AsPlainText  -Force
$DracCred = new-object -typename System.Management.Automation.PSCredential -argumentlist $UserName,$SecurePass 
# this just makes a PSCredential object to be used as a reference
$cimop=New-CimSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck -Encoding Utf8 -UseSsl
# this instruction creates a SSL-enabled option set with ignore certificate checks (Dells have self-signed certs on their side)
$Dracsession=New-CimSession -Authentication Basic -Credential $DracCred -ComputerName $DracIP -Port 443 -SessionOption $cimop -OperationTimeoutSec 10000000
Get-CimInstance -CimSession $Dracsession -ResourceUri "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/root/dcim/DCIM_SystemView"

So, in order to make your C# program to connect via WBEM, you have to translate Powershell code that creates the CIMSessionOption and CIMSession using non-WSMAN method. In Powershell this should let you connect to the Linux machine if provided proper credentials. The ResourceUri parameter specifies what object you want to retrieve, and the proper URI should be taken from manuals on the target system.