You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调用OpenServiceA后遇系统错误1060:PowerShell控制WinRM服务失败

使用WinAPI通过PowerShell控制WinRM服务时遇到错误码1060

我在练习用WinAPI通过PowerShell控制WinRM服务,脚本能成功获取服务控制管理器数据库句柄,但调用OpenServiceA获取WinRM服务句柄时返回错误码1060(指定服务未作为已安装服务存在)。

脚本代码(Service.ps1)

$loadAdvapi32 = @"

  public struct LPSERVICE_STATUS {
      public uint dwServiceType;
      public uint dwCurrentState;
      public uint dwControlsAccepted;
      public uint dwWin32ExitCode;
      public uint dwServiceSpecificExitCode;
      public uint dwCheckPoint;
      public uint dwWaitHint;
  }

 [DllImport("Advapi32.dll", CharSet=CharSet.Auto)]
 public static extern 
 IntPtr OpenSCManager(string  lpMachineName,
                      string  lpDatabaseName,
                      uint    dwDesiredAccess);

 [DllImport("Advapi32.dll", CharSet=CharSet.Auto)]
 public static extern 
 IntPtr OpenServiceA(IntPtr    hSCManager,
                     string    lpServiceName,
                     uint      dwDesiredAccess);

 [DllImport("Advapi32.dll", CharSet=CharSet.Auto)]
 public static extern 
 bool ControlService(IntPtr           hService,
                     uint             dwControl,
                     out LPSERVICE_STATUS lpServiceStatus);
"@

$loadKernel32 = @"
 [DllImport("Kernel32.dll", CharSet=CharSet.Auto)]
 public static extern 
 int GetLastError();
"@

Add-Type -MemberDefinition $loadAdvapi32 -Name 'Advapi32' -Namespace 'Win32';
Add-Type -MemberDefinition $loadKernel32 -Name 'Kernel32' -Namespace 'Win32';

$lpMachineName = [NullString]::Value;
$lpDatabaseName = [NullString]::Value;

# 服务权限常量
$SC_MANAGER_ALL_ACCESS = 0xF003F;
$SERVICE_ALL_ACCESS = 0xF01FF;


$hSCManager = [Win32.Advapi32]::OpenSCManager($lpMachineName, $lpDatabaseName, $SC_MANAGER_ALL_ACCESS);
[Win32.Kernel32]::GetLastError()

$schService = [Win32.Advapi32]::OpenServiceA($hSCManager, "WinRM", $SERVICE_ALL_ACCESS);
[Win32.Kernel32]::GetLastError()

脚本输出

PS C:\Windows\system32> C:\Service.ps1
0
1060

已尝试的排查步骤

  • WinRM服务已存在且已安装
  • 以管理员权限运行PowerShell脚本
  • 确认服务名称正确

问题根源

错误核心是字符集不匹配:

  1. 你在DllImport中指定了CharSet=CharSet.Auto,但显式调用了ANSI版本的OpenServiceA,而PowerShell默认使用Unicode(UTF-16)字符串,直接传入ANSI函数会导致字符串编码转换错误,服务名称无法被正确识别。
  2. 额外问题:GetLastError的调用时机不合理——只有当API返回失败状态(比如OpenServiceA返回IntPtr.Zero)时,调用该函数才能得到有效错误码,否则可能获取到无关的残留错误值。

修复方案

方案1:使用自动适配字符集的OpenService(推荐)

将OpenServiceA改为OpenService,让CharSet.Auto根据系统环境自动选择ANSI或Unicode版本:

[DllImport("Advapi32.dll", CharSet=CharSet.Auto)]
public static extern 
IntPtr OpenService(IntPtr    hSCManager,
                   string    lpServiceName,
                   uint      dwDesiredAccess);

调用时对应改为:

$schService = [Win32.Advapi32]::OpenService($hSCManager, "WinRM", $SERVICE_ALL_ACCESS);

方案2:显式使用Unicode版本OpenServiceW

如果需要强制指定Unicode版本,修改函数定义为:

[DllImport("Advapi32.dll", CharSet=CharSet.Unicode)]
public static extern 
IntPtr OpenServiceW(IntPtr    hSCManager,
                   string    lpServiceName,
                   uint      dwDesiredAccess);

调用时使用OpenServiceW即可。

优化错误检查逻辑

添加API返回值判断,仅在调用失败时获取错误码:

$hSCManager = [Win32.Advapi32]::OpenSCManager($lpMachineName, $lpDatabaseName, $SC_MANAGER_ALL_ACCESS);
if ($hSCManager -eq [IntPtr]::Zero) {
    Write-Error "打开服务控制管理器失败,错误码: $([Win32.Kernel32]::GetLastError())"
} else {
    Write-Host "打开服务控制管理器成功"
}

$schService = [Win32.Advapi32]::OpenService($hSCManager, "WinRM", $SERVICE_ALL_ACCESS);
if ($schService -eq [IntPtr]::Zero) {
    Write-Error "打开WinRM服务失败,错误码: $([Win32.Kernel32]::GetLastError())"
} else {
    Write-Host "成功获取WinRM服务句柄"
}

修复后的完整脚本

$loadAdvapi32 = @"
  public struct LPSERVICE_STATUS {
      public uint dwServiceType;
      public uint dwCurrentState;
      public uint dwControlsAccepted;
      public uint dwWin32ExitCode;
      public uint dwServiceSpecificExitCode;
      public uint dwCheckPoint;
      public uint dwWaitHint;
  }

 [DllImport("Advapi32.dll", CharSet=CharSet.Auto)]
 public static extern 
 IntPtr OpenSCManager(string  lpMachineName,
                      string  lpDatabaseName,
                      uint    dwDesiredAccess);

 [DllImport("Advapi32.dll", CharSet=CharSet.Auto)]
 public static extern 
 IntPtr OpenService(IntPtr    hSCManager,
                   string    lpServiceName,
                   uint      dwDesiredAccess);

 [DllImport("Advapi32.dll", CharSet=CharSet.Auto)]
 public static extern 
 bool ControlService(IntPtr           hService,
                     uint             dwControl,
                     out LPSERVICE_STATUS lpServiceStatus);
"@

$loadKernel32 = @"
 [DllImport("Kernel32.dll", CharSet=CharSet.Auto)]
 public static extern 
 int GetLastError();
"@

Add-Type -MemberDefinition $loadAdvapi32 -Name 'Advapi32' -Namespace 'Win32';
Add-Type -MemberDefinition $loadKernel32 -Name 'Kernel32' -Namespace 'Win32';

$lpMachineName = [NullString]::Value;
$lpDatabaseName = [NullString]::Value;

$SC_MANAGER_ALL_ACCESS = 0xF003F;
$SERVICE_ALL_ACCESS = 0xF01FF;

# 打开服务控制管理器
$hSCManager = [Win32.Advapi32]::OpenSCManager($lpMachineName, $lpDatabaseName, $SC_MANAGER_ALL_ACCESS);
if ($hSCManager -eq [IntPtr]::Zero) {
    Write-Error "打开服务控制管理器失败,错误码: $([Win32.Kernel32]::GetLastError())"
    exit 1
}

# 打开WinRM服务
$schService = [Win32.Advapi32]::OpenService($hSCManager, "WinRM", $SERVICE_ALL_ACCESS);
if ($schService -eq [IntPtr]::Zero) {
    Write-Error "打开WinRM服务失败,错误码: $([Win32.Kernel32]::GetLastError())"
} else {
    Write-Host "成功获取WinRM服务句柄"
}

内容的提问来源于stack exchange,提问作者GhostDuck

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 18:31:42