如何在一个简单示例中使用 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"
winrm quickconfig
显示服务正在运行(我们已经知道,否则 winrs
命令将无法运行)
winrm get winrm/config
显示TrustedHosts = localhost
、AllowUnencrypted = true
,所有认证方式都设置为true
- 在 this advice 之后,我设置了注册表项
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\LocalAccountTokenFilterPolicy = 1
- 工作时间 Windows 10
提前致谢!
我不知道这一点,所以不能评论它是否是常识,但 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 会引发此错误仍然是个谜。我把这个问题留给比我更有见识的人来回答,以防他们遇到这个问题。
为什么我的代码无法 运行 使用 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"
winrm quickconfig
显示服务正在运行(我们已经知道,否则winrs
命令将无法运行)winrm get winrm/config
显示TrustedHosts = localhost
、AllowUnencrypted = true
,所有认证方式都设置为true- 在 this advice 之后,我设置了注册表项
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\LocalAccountTokenFilterPolicy = 1
- 工作时间 Windows 10
提前致谢!
我不知道这一点,所以不能评论它是否是常识,但 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 会引发此错误仍然是个谜。我把这个问题留给比我更有见识的人来回答,以防他们遇到这个问题。