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

使用PowerShell管理Windows服务:远程服务核查与启动流程实现问询

PowerShell 远程Windows服务状态核查与启动管理实现方案

1. 前置准备

  • 执行脚本的账户需拥有远程计算机的WMI/CIM访问权限、服务管理权限,以及SMTP发件权限
  • 提前整理OS服务白名单,用于区分OS相关服务和应用服务,也可通过服务可执行文件路径判断OS服务
  • 提前配置SMTP服务器信息、服务与负责人的映射关系表
  • 服务账户凭证建议使用ConvertTo-SecureString加密存储,禁止明文写在脚本中

2. 完整实现脚本

# 入参配置
param(
    [Parameter(Mandatory=$true)]
    [string[]]$RemoteComputers,
    # OS服务白名单,可替换为路径判断逻辑
    [Parameter(Mandatory=$true)]
    [string[]]$OsServiceWhitelist,
    # 应用服务和对应通知人映射,示例:@{"Tomcat" = @("appteam@example.com","serveradmin@example.com")}
    [Parameter(Mandatory=$true)]
    [hashtable]$ServiceOwnerMapping,
    [string]$SmtpServer = "你的SMTP服务器地址",
    [string]$SmtpSender = "alert@example.com",
    [int]$SmtpPort = 25
)

# 遍历所有远程计算机
foreach ($computer in $RemoteComputers) {
    # 先测试网络连通性
    if (-not (Test-Connection -ComputerName $computer -Count 1 -Quiet -ErrorAction SilentlyContinue)) {
        Write-Warning "无法连通计算机 $computer,跳过处理"
        continue
    }

    # 获取所有设置为自动启动但当前停止的服务
    try {
        $stoppedServices = Get-CimInstance -ClassName Win32_Service -ComputerName $computer -Filter "State = 'Stopped' AND StartMode = 'Auto'" -ErrorAction Stop
    }
    catch {
        Write-Warning "获取计算机 $computer 服务信息失败:$_"
        continue
    }

    # 逐个处理停止的服务
    foreach ($service in $stoppedServices) {
        $serviceName = $service.Name
        $displayName = $service.DisplayName
        $startAccount = $service.StartName

        # 判断是否为OS相关服务
        if ($OsServiceWhitelist -contains $serviceName) {
            # 核查所有依赖服务运行状态
            $dependentServices = Get-CimAssociatedInstance -InputObject $service -ResultClassName Win32_Service -Association Win32_DependentService -Role Dependent -ErrorAction SilentlyContinue
            $depsAllRunning = $true
            foreach ($depService in $dependentServices) {
                if ($depService.State -ne "Running") {
                    $depsAllRunning = $false
                    Write-Host "服务 $serviceName 的依赖服务 $($depService.Name) 未运行,无法启动"
                    break
                }
            }
            if (-not $depsAllRunning) { continue }

            # 判断启动账户类型
            $systemAccounts = @("LocalSystem", "NT AUTHORITY\LocalService", "NT AUTHORITY\NetworkService")
            if ($systemAccounts -contains $startAccount) {
                # 本地系统类账户直接启动
                try {
                    Start-Service -InputObject (Get-Service -Name $serviceName -ComputerName $computer) -ErrorAction Stop
                    Write-Host "已成功启动计算机 $computer 的OS服务 $serviceName"
                }
                catch {
                    Write-Warning "启动计算机 $computer 的OS服务 $serviceName 失败:$_"
                }
            }
            else {
                # 自定义服务账户启动,需自行实现凭证获取逻辑,禁止明文存储密码
                try {
                    # 示例:从加密存储的凭证库获取对应服务账户的凭证
                    $serviceCred = Get-StoredCredential -ServiceAccount $startAccount
                    $service | Invoke-CimMethod -MethodName StartService -Arguments @{
                        User = $serviceCred.UserName
                        Password = $serviceCred.GetNetworkCredential().Password
                    } -ErrorAction Stop
                    Write-Host "已使用服务账户 $startAccount 启动计算机 $computer 的服务 $serviceName"
                }
                catch {
                    Write-Warning "使用服务账户启动计算机 $computer 的服务 $serviceName 失败:$_"
                }
            }
        }
        else {
            # 非OS应用服务,发送告警邮件
            if ($ServiceOwnerMapping.ContainsKey($serviceName)) {
                $recipients = $ServiceOwnerMapping[$serviceName]
                $mailSubject = "告警:服务器 $computer 应用服务 $displayName 已停止"
                $mailBody = @"
您好:
服务器 $computer 上的应用服务 $displayName(服务标识:$serviceName)当前处于停止状态,且配置为自动启动,请相关团队尽快核查处理。
"@
                try {
                    Send-MailMessage -From $SmtpSender -To $recipients -Subject $mailSubject -Body $mailBody -SmtpServer $SmtpServer -Port $SmtpPort -ErrorAction Stop
                    Write-Host "已向 $($recipients -join ',') 发送服务停止告警邮件"
                }
                catch {
                    Write-Warning "发送服务 $serviceName 告警邮件失败:$_"
                }
            }
            else {
                Write-Warning "未配置应用服务 $serviceName 的对应负责人,跳过邮件通知"
            }
        }
    }
}

3. 补充说明

  • 若不想维护OS服务白名单,可替换判断逻辑为$isOsService = $service.PathName -like "C:\Windows\System32\*",通过可执行文件路径判断是否为系统服务,该方式简便但可能存在少量误判
  • 若远程计算机开启了防火墙,需要开放WMI对应端口(TCP 5985为HTTP、5986为HTTPS)
  • 可根据需求新增日志记录逻辑,将所有操作和异常写入本地日志文件,方便后续排查

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 01:39:03