自动化实践(7.25):把 PsTools 接入 PowerShell / 批处理 / Ansible

自动化实践(7.25):把 PsTools 接入 PowerShell / 批处理 / Ansible

  • [自动化实践(7.25):把 PsTools 接入 PowerShell / 批处理 / Ansible](#自动化实践(7.25):把 PsTools 接入 PowerShell / 批处理 / Ansible)
    • 1)前置与安全基线
    • [2)PowerShell 集成:模块化、并发与结构化日志](#2)PowerShell 集成:模块化、并发与结构化日志)
      • [2.1 目录与凭据约定](#2.1 目录与凭据约定)
      • [2.2 并发执行(PowerShell 7 推荐)](#2.2 并发执行(PowerShell 7 推荐))
      • [2.3 封装常用动作(示例库)](#2.3 封装常用动作(示例库))
    • 3)批处理(.bat/.cmd):轻依赖、可落地
      • [3.1 基础模板(带日志与退出码)](#3.1 基础模板(带日志与退出码))
      • [3.2 并发小技巧(慎用)](#3.2 并发小技巧(慎用))
    • [4)Ansible 集成:把 PsTools 纳入编排](#4)Ansible 集成:把 PsTools 纳入编排)
      • [4.1 示例清单](#4.1 示例清单)
    • [5)流水线与计划任务:把脚本放进 CI/CD](#5)流水线与计划任务:把脚本放进 CI/CD)
      • [5.1 Windows 计划任务(每日清点)](#5.1 Windows 计划任务(每日清点))
      • [5.2 Jenkins/GitLab CI(示意)](#5.2 Jenkins/GitLab CI(示意))
    • 6)幂等与回滚策略
    • 7)故障快修清单(执行层面)
    • 8)推荐仓库结构(可直接落地)
    • 结语

自动化实践(7.25):把 PsTools 接入 PowerShell / 批处理 / Ansible

目标:把 PsExec / PsInfo / PsService / PsLogList 等常用 PsTools,系统化封装进 PowerShell 脚本、批处理(.bat/.cmd)与 Ansible 流水线,实现可复用、可审计、可回滚的批量运维与应急流程。


1)前置与安全基线

  • 网络 :目标机放行 445/TCP(SMB)135/TCP(RPC)动态 RPC 端口
  • 权限:使用域受控账号或最小权限服务账号;工作组注意 UAC 远程限制。
  • 共享ADMIN$ / C$ 未禁用。
  • 签名/EDR :将 PsTools 目录与 PSEXESVC 行为加入白名单。
  • 时间/DNS:NTP 同步、DNS 正常解析(Kerberos/NTLM 影响大)。
  • 脚本规范 :全流程 日志留痕 + 幂等检查 + 失败回滚

2)PowerShell 集成:模块化、并发与结构化日志

2.1 目录与凭据约定

复制代码
C:\Ops\PsTools\       # 放置 PsTools
C:\Ops\Scripts\       # 自建脚本目录
C:\Ops\Logs\          # 结构化日志输出
C:\Ops\hosts.txt      # 主机清单(逐行一个主机)

凭据建议 :用 Get-Credential 交互获取,或安全地从 Windows 凭据管理器/密管(Vault)读取。

powershell 复制代码
# C:\Ops\Scripts\New-PsExecSession.ps1
param(
  [Parameter(Mandatory)] [string]$Computer,
  [Parameter()] [pscredential]$Credential,
  [Parameter()] [string]$Command = 'hostname',
  [switch]$System, [switch]$High, [int]$Timeout = 20,
  [string]$WorkDir, [string[]]$CpuAffinity
)

$psi = @{
  FilePath   = 'psexec.exe'
  ArgumentList = @("\\$Computer")
  NoNewWindow = $true
  Wait       = $true
}
if ($Credential) { $psi.ArgumentList += @('-u', $Credential.UserName, '-p', $Credential.GetNetworkCredential().Password) }
if ($System)     { $psi.ArgumentList += '-s' }
if ($High)       { $psi.ArgumentList += '-h' }
if ($Timeout)    { $psi.ArgumentList += @('-n', $Timeout) }
if ($WorkDir)    { $psi.ArgumentList += @('-w', $WorkDir) }
if ($CpuAffinity){ $psi.ArgumentList += @('-a', ($CpuAffinity -join ',')) }
$psi.ArgumentList += @('-accepteula','-nobanner')
$psi.ArgumentList += $Command

try{
  $sw = [Diagnostics.Stopwatch]::StartNew()
  $p  = Start-Process @psi -PassThru -RedirectStandardOutput 'stdout.tmp' -RedirectStandardError 'stderr.tmp'
  $code = $p.ExitCode
  $out  = Get-Content .\stdout.tmp -Raw
  $err  = Get-Content .\stderr.tmp -Raw
  Remove-Item .\stdout.tmp, .\stderr.tmp -ErrorAction SilentlyContinue
  [pscustomobject]@{
    Computer = $Computer; Command = $Command; ExitCode = $code
    DurationMs = $sw.ElapsedMilliseconds; StdOut = $out; StdErr = $err; Time = (Get-Date)
  }
}
catch{
  [pscustomobject]@{
    Computer = $Computer; Command = $Command; ExitCode = -1
    DurationMs = 0; StdOut = ''; StdErr = $_ | Out-String; Time = (Get-Date)
  }
}

2.2 并发执行(PowerShell 7 推荐)

powershell 复制代码
# C:\Ops\Scripts\Invoke-PsToolsBatch.ps1
$hosts = Get-Content 'C:\Ops\hosts.txt' | ? {$_ -and $_ -notmatch '^\s*#'}
$cred  = Get-Credential -Message '输入用于 PsExec 的域凭据(最小权限)'

$results = $hosts | ForEach-Object -Parallel {
  Import-Module -Name 'C:\Ops\Scripts\New-PsExecSession.ps1' -Force
  # 示例:查询磁盘信息(可以换成任意命令,如:ipconfig /all)
  . 'C:\Ops\Scripts\New-PsExecSession.ps1' -Computer $_ -Credential $using:cred -High `
      -Command 'cmd /c wmic logicaldisk get caption,freespace,size /format:table'
} -ThrottleLimit 20

# 结构化日志(JsonLines)
$log = 'C:\Ops\Logs\psexec-' + (Get-Date -UFormat %Y%m%d-%H%M%S) + '.jsonl'
$results | ForEach-Object { $_ | ConvertTo-Json -Compress | Out-File -FilePath $log -Append -Encoding utf8 }

# 失败告警粗筛
$fail = $results | ? { $_.ExitCode -ne 0 }
if($fail){ Write-Warning "失败 ${($fail.Count)} 台,详情:$log" } else { Write-Host '全部成功' -ForegroundColor Green }

2.3 封装常用动作(示例库)

  • 服务健康三连(查询→依赖→重启)
powershell 复制代码
function Invoke-ServiceHealth {
  param([string]$Computer, [string]$Service, [pscredential]$Credential)
  . 'C:\Ops\Scripts\New-PsExecSession.ps1' -Computer $Computer -Credential $Credential -High -Command "psservice query $Service"
  . 'C:\Ops\Scripts\New-PsExecSession.ps1' -Computer $Computer -Credential $Credential -High -Command "psservice depend $Service"
  . 'C:\Ops\Scripts\New-PsExecSession.ps1' -Computer $Computer -Credential $Credential -High -Command "psservice restart $Service"
}
  • 冻结→抓转储→恢复(针对 CPU 飙高的 w3wp)
powershell 复制代码
function Invoke-FreezeDumpResume {
  param([string]$Computer,[pscredential]$Credential,[string]$Proc='w3wp',[string]$Dump='C:\Dumps\w3wp.dmp')
  . 'C:\Ops\Scripts\New-PsExecSession.ps1' -Computer $Computer -Credential $Credential -High -Command "pssuspend $Proc"
  . 'C:\Ops\Scripts\New-PsExecSession.ps1' -Computer $Computer -Credential $Credential -High -Command "procdump -accepteula -ma $Proc $Dump"
  . 'C:\Ops\Scripts\New-PsExecSession.ps1' -Computer $Computer -Credential $Credential -High -Command "pssuspend -r $Proc"
}
  • 拉事件日志(近 2 天关键错误)
powershell 复制代码
. 'C:\Ops\Scripts\New-PsExecSession.ps1' -Computer $Computer -Credential $cred -Command `
  'psloglist -s -d 2 -i 41,1001 System'

幂等性建议

  • 起服务前先 query 判断状态;
  • 改配置前先 get 对比;
  • 大规模批量先试点(1~3 台)再并发放量。

3)批处理(.bat/.cmd):轻依赖、可落地

3.1 基础模板(带日志与退出码)

bat 复制代码
@echo off
setlocal enabledelayedexpansion
set P= C:\Ops\PsTools
set H= C:\Ops\hosts.txt
set LOG=C:\Ops\Logs\batch-%date:~0,10%_%time:~0,8%.log

for /f "usebackq delims=" %%h in ("%H%") do (
  if not "%%h"=="" (
    echo ===== %%h ===== >> "%LOG%"
    "%P%\psexec.exe" \\%%h -accepteula -nobanner ipconfig /all >> "%LOG%" 2>&1
    set EC=!errorlevel!
    echo ExitCode=!EC! >> "%LOG%"
    if not "!EC!"=="0" echo [WARN] %%h 失败(!EC!)
  )
)
echo 完成:%LOG%
endlocal

3.2 并发小技巧(慎用)

bat 复制代码
:: 同时对 3 台发起
start "" cmd /c "%P%\psexec.exe \\PC-001 hostname & echo EC=!errorlevel! >> %LOG%"
start "" cmd /c "%P%\psexec.exe \\PC-002 hostname & echo EC=!errorlevel! >> %LOG%"
start "" cmd /c "%P%\psexec.exe \\PC-003 hostname & echo EC=!errorlevel! >> %LOG%"

注意 :批处理缺少原生结构化日志与健壮错误处理,建议用 PowerShell 主导,批处理当"引导器"。


4)Ansible 集成:把 PsTools 纳入编排

思路 :Ansible 控制端为 Windows (或 WSL/代理到 Windows),PsTools 安装在控制端。Playbook 通过 delegate_to: localhost 在控制端循环调用 PsTools 远程连接各 Windows 主机。

4.1 示例清单

inventory.ini

ini 复制代码
[win]
PC-001
PC-002
SRV-APP

group_vars/win.yml

yaml 复制代码
psexec_path: 'C:\\Ops\\PsTools\\psexec.exe'
ops_user: 'CORP\\opsuser'
ops_pass: '{{ vault_ops_pass }}'   # 建议用 Ansible Vault

playbook:批量查询磁盘信息

yaml 复制代码
---
- name: PsTools orchestration from Windows control node
  hosts: win
  gather_facts: no

  tasks:
    - name: Run PsExec disk query
      ansible.windows.win_command: >
        "{{ psexec_path }}"
        "\\{{ inventory_hostname }}"
        -u {{ ops_user }} -p {{ ops_pass }}
        -accepteula -nobanner
        cmd /c wmic logicaldisk get caption,freespace,size /format:table
      register: out
      delegate_to: localhost

    - name: Save raw output per host
      ansible.builtin.copy:
        dest: "C:/Ops/Logs/{{ inventory_hostname }}-disk.txt"
        content: "{{ out.stdout }}"
      delegate_to: localhost

更推荐 :Ansible 访问 Windows 目标,首选 WinRM + ansible.windows.* 原生模块 (如 win_servicewin_commandwin_eventlogwin_package)。

在必须跨越网络策略/EDR 限制时,再用 PsTools 作为"后备通道"。


5)流水线与计划任务:把脚本放进 CI/CD

5.1 Windows 计划任务(每日清点)

powershell 复制代码
$act = New-ScheduledTaskAction -Execute 'pwsh.exe' -Argument '-File C:\Ops\Scripts\Invoke-PsToolsBatch.ps1'
$trg = New-ScheduledTaskTrigger -Daily -At 03:00
Register-ScheduledTask -Action $act -Trigger $trg -TaskName 'Nightly-PsTools-Inventory' -User 'CORP\svc_ops' -Password (Read-Host -AsSecureString)

5.2 Jenkins/GitLab CI(示意)

  • Jenkins :Windows Node 执行 pwsh -File C:\Ops\Scripts\Invoke-PsToolsBatch.ps1,归档 C:\Ops\Logs\*.jsonl
  • GitLab CI:Windows Runner 执行同上,产物落盘归档。

6)幂等与回滚策略

  • 服务/配置 :变更前 psservice query 快照 → 变更 → 失败时按快照回退。
  • 关机/重启psloglist 抽取关键事件留痕;计划窗口+沟通提示。
  • 杀进程 :优先 pssuspend(冻结)+ 取证(procdump)+ 再 pskill
  • 大批量:分批灰度(10% → 30% → 100%),提高成功率与可控性。

7)故障快修清单(执行层面)

现象 快速定位 处置
Access is denied 权限/UAC/ADMIN$ 管理员凭据;启用 ADMIN$;必要时工作组放宽 UAC 远程限制
RPC/SMB 不通 Test-NetConnection -ComputerName HOST -Port 445/135 放行端口、防火墙策略核对
Logon failure 凭据错误/锁定 校验域名 + 口令;解锁策略
PSEXESVC 启动失败 EDR/白名单 协同安全放行 PsExec 行为
回显阻塞 交互/超时 -d 后台、或 -i 指定会话、-n 超时

8)推荐仓库结构(可直接落地)

复制代码
Ops-Automation/
├─ PsTools/                      # 官方二进制
├─ Scripts/
│  ├─ New-PsExecSession.ps1      # 核心封装
│  ├─ Invoke-PsToolsBatch.ps1     # 并发批量执行
│  ├─ Recipes/                    # 业务动作库(服务健康、转储、日志收集...)
├─ Logs/                          # JsonLines/CSV/原始输出
├─ hosts.txt                      # 资产清单
└─ README.md                      # 使用说明、安全提示、回滚流程

结语

把 PsTools 接入 PowerShell/批处理/Ansible 后,你就拥有了一个 轻依赖、跨版本、可编排 的 Windows 批量运维"工具台"。建议从 PowerShell 封装 + 并发执行 + 结构化日志 起步,逐步沉淀"动作库"(服务治理、事件采集、取证流程),再上 CI/计划任务,实现 标准化、自动化与可审计 的闭环。

下一篇(7.26):安全与合规------最小权限、日志审计与取证要点,保证"能用更要安全可查"。

相关推荐
开开心心就好3 小时前
微软官方出品:免费数据恢复工具推荐
网络·笔记·microsoft·pdf·word·音视频·symfony
星尘库9 小时前
抖音自动化-实现给特定用户发私信
前端·javascript·自动化
Mr_Xuhhh9 小时前
GUI自动化测试--自动化简单示例
运维·服务器·自动化
研究司马懿1 天前
【ETCD】ETCD——confd配置管理
数据库·golang·自动化·运维开发·etcd·argocd·gitops
2501_915921431 天前
Fastlane 结合 开心上架(Appuploader)命令行版本实现跨平台上传发布 iOS App 免 Mac 自动化上架实战全解析
android·macos·ios·小程序·uni-app·自动化·iphone
RPA机器人就用八爪鱼1 天前
RPA自动化程序:企业数字化转型的智能引擎
运维·自动化·rpa
IT小哥哥呀1 天前
Jenkins + Docker 打造自动化持续部署流水线
docker·微服务·自动化·jenkins·springboot·高并发·限流
2501_915918411 天前
Flutter 加固方案对比与实战,多工具组合的跨平台安全体系(Flutter App 加固/IPA 成品混淆/Ipa Guard CLI/自动化安全流程)
安全·flutter·ios·小程序·uni-app·自动化·iphone
007tg1 天前
Telegram SCRM 系统构建指南:自动化营销与客户管理实战
大数据·运维·自动化