如何在一个简单示例中使用 WinRM C++ API

How to use the WinRM C++ API in a simple example

为什么我的代码无法 运行 使用 WinRM's C++ API 的简单可执行文件?

//main.cpp
int main()
{
    ShellClient *shellClient = new ShellClient();
    
    //Set up the shell client here and connect to the localhost.
    //This seems to be working fine because I'm handling every
    //possible error code, and none of them are being triggered
    
    PCWSTR commandLine = L"\"MyExampleExecutable.exe\"";
    isOk = shellClient->RunCommand(commandLine);
    
    if (!isOk)
        return 1;
        
    return 0;   
}

//ShellClient.cpp
bool ShellClient::RunCommand(PCWSTR command)
{
    WSMAN_SHELL_ASYNC createCommandAsync;
    ZeroMemory(&createCommandAsync, sizeof(createCommandAsync));
    createCommandAsync.operationContext = this;
    createCommandAsync.completionFunction = (WSMAN_SHELL_COMPLETION_FUNCTION)CommandCreatedCallback;
    
    WSManRunShellCommand(shellHandle, 0, command, NULL, NULL, &createCommandAsync, &commandHandle);
    
    if (commandHandle == NULL)//It is *always* NULL
    {
        std::cout << "command handle null" << std::endl;
        system("pause");
        return false;
    }
    
    return true;
}

一个可能的线索是我的 C++ 代码认为 shell 创建的很好,但是在我机器的事件查看器中,有这样的:

WSMan operation CreateShell failed, error code 2150859250

在撰写本文时,这个可爱的错误代码在放入 Google 时给出的结果恰好为零,因此很难理解它的含义。

我已经检查过的背景和常见解决方案

正如同一作者 here and explaned in this video 所记录的那样,大多数 WinRM 问题归结为连接或身份验证问题。在我的例子中,如果我故意输入不正确的用户凭据,我会收到一个身份验证错误,所以我知道我的程序正在连接 在提供正确的用户名和密码时身份验证正常。还有:

    winrs -r:http://localhost:5985 -u:COMPUTERNAME\Jeremy "dir"

提前致谢!

我不知道这一点,所以不能评论它是否是常识,但 Microsoft 有一个漂亮的 error lookup tool,您可以在其中输入错误代码(将其从普通数字转换为十六进制后)它会告诉你这意味着什么。

在这种情况下,2150859250(十六进制的803381F2)对应于:

  ERROR_WINRS_IDLETIMEOUT_OUTOFBOUNDS                            wsmerror.h
# The WS-Management service cannot process the request. The
# requested IdleTimeout is outside the allowed range.

设置 WinRM shell 时,我进行了以下操作:

    WSMAN_SHELL_STARTUP_INFO  startupInfo;
    ZeroMemory(&startupInfo, sizeof(startupInfo));
    startupInfo.idleTimeoutMs = 1000;//not large enough!
    startupInfo.workingDirectory = L"C:\";
    //other parameters of startupInfo set here

    WSManCreateShell(session, 0, shellUri, &startupInfo, NULL, NULL, &createShellAsync, &shellHandle);

idleTimeoutMs 从 1000 更改为更大的数字(如 100000)解决了错误,我的程序现在可以正常工作了。

由于此参数的 official docs 表示 0 和 0xFFFFFFFF 之间的任何值都是有效的,因此为什么值 1000 会引发此错误仍然是个谜。我把这个问题留给比我更有见识的人来回答,以防他们遇到这个问题。