资讯详情 WMIC命令实战指南:从基础语法到PowerShell CIM迁移
📅 2026/10/18 10:24:07
WMIC 这东西放到今天看确实有点“老古董”的意思但你要是翻过运维脚本、看过 PE 维护工具、或者处理过几台老服务器绝对绕不开它。一条wmic cpu get name敲下去CPU 型号直接出来一条wmic process where namexxx.exe call terminate进程说杀就杀。不用装额外软件不用打开图形界面更不用一台台去点鼠标这对于批量查机器信息、做资产盘点、远程排查故障来说实在是太顺手了。但这几年有个尴尬情况新一代 Windows 系统默认已经不装 WMIC 了很多教程和脚本还在用结果不少人一执行就提示“wmic 不是内部或外部命令”。于是有人困惑有人干脆放弃还有人硬着头皮在老环境里继续用。这篇文章我想把 WMIC 命令这件事讲透——它是什么、怎么用、有哪些常见坑、以及和 PowerShell 的 CIM 命令到底该怎么选。适合刚接触命令行的新手也适合从老脚本 migration 过来的运维老手。不管你最后用不用 WMIC理解它背后的思路对排查系统信息和写批处理都会很有帮助。1. WMIC 是什么为什么老脚本里全是它1.1 命名空间、类和实例WMIC 背后的逻辑想要真正理解 WMIC不能光记命令。它本质上是 WMIWindows Management Instrumentation的命令行外壳而 WMI 本身是一套管理规范把系统里的 CPU、内存、进程、服务、磁盘、网卡等信息都抽象成了“类”。比如说CPU 信息对应Win32_Processor类操作系统信息对应Win32_OperatingSystem类进程对应Win32_Process类。每一台机器上的具体 CPU、具体进程就是这些类的“实例”。WMIC 做的事情就是让你在命令行里对这些类和实例做查询、做修改。它把复杂的 WMI 查询语句转换成了更像自然语言的命令格式。举个例子底层 WMI 查询可能是SELECT * FROM Win32_Processor而用 WMIC 只需要敲wmic cpu list brief。这种封装让不熟悉 WQL 查询语法的人也能快速上手。用生活里的类比WMI 像一个巨大的档案室Win32_Processor是其中一个文件柜“CPU 型号”是抽屉里的档案。WMIC 则是档案室门口的前台你告诉前台“我要看 CPU 信息”前台去档案室帮你把文件抽出来递给你。所以本质上用 WMIC 查信息不是 WMIC 自己知道答案而是它在背后向 WMI 发起了查询请求。1.2 为什么十年前大家都在用 WMIC现在 PowerShell 功能强大大家可能不太理解为什么老脚本里全是 WMIC。原因主要有这么几个第一出现得早。在 PowerShell 还没大规模普及的年代WMIC 已经是 Windows 自带的管理工具装好系统就能用不需要额外配置。第二语法简洁。对于只查一两个字段比如查个 CPU 型号、查个序列号wmic cpu get name比当时其他方法要短得多。第三批量友好。配合批处理 for 循环能够一台接一台采集信息输出成文本方便汇总。当时做资产盘点很多人就是靠 WMIC 批量导出的。第四支持远程。通过/node、/user、/password参数可以在命令行里直接连远程机器查信息这在当时是非常强大的能力。所以你翻到的很多老教程、老脚本里WMIC 几乎是无处不在的标配。即便现在微软已经在新的系统里移除了它那些老的运维流程、自动化脚本仍然大量建立在 WMIC 之上。这也是为什么直到今天你依然需要知道它、能读得懂它。2. 先把 WMIC 的语法骨架看懂2.1 全局格式别名、动词和参数WMIC 的命令格式其实非常固定理解了骨架之后任何命令都能拆解。基本结构是wmic [全局开关] 别名 [动词] [参数]全局开关作用于整条命令的选项比如/node指定目标机器、/output指定输出位置、/user和/password指定远程连接身份。别名你要操作的对象对应某个 WMI 类。常见的有cpu、os、diskdrive、logicaldisk、process、service、startup、nicconfig、useraccount、share、product等等。动词对对象执行的操作通常是get获取属性、list列表、call调用方法、create创建、delete删除、set修改。默认情况下只输入别名会自动执行list brief。参数给动词补充条件。get后面跟字段名where后面跟筛选条件call后面跟方法名。举个例子wmic cpu get name这条命令里cpu是别名get是动词name是参数表示只需获取 CPU 的name属性。再比如wmic process where namenotepad.exe get processid,executablepath这里就是先where筛选出进程名等于notepad.exe的进程再get它的processid和executablepath。理解了这个骨架所有命令都只是在换别名、换动词、换参数而已。2.2 三大动词get、where 和 callget 动词用来获取对象的属性字段。关键词是“字段”不是整段信息。CPU 有几十个属性你用get name就只拿名称用get name,maxclockspeed就多拿最大时钟频率。多个字段之间用英文逗号分隔中间不需要空格。如果不加字段直接get则会显示该类的所有属性输出会非常长而且很多时候会折行混乱。所以我建议尽量把需要的字段写全不要偷懒用裸get。where 子句用来筛选特定实例。它相当于 SQL 里的WHERE写法是where 条件条件用英文双引号包起来。比如wmic service where namewuauserv get state,startmode这条命令查询名为wuauservWindows Update 服务的状态和启动模式。注意服务名两侧是英文单引号整个条件外面是英文双引号。如果少了一个引号命令经常报错。这个细节坑过很多人。call 动词是用来调用 WMI 类的方法的。比如终止进程可以用wmic process where namenotepad.exe call terminate这里call后面跟着方法名terminate意思是把筛选出来的进程终止掉。类似的方法还有service的startservice、stopserviceprocess的create等。call 属于写操作会影响系统状态使用前一定要确认筛选条件准确无误。2.3 关于输出格式的几个细节WMIC 默认把结果输出到控制台但控制台宽度有限经常会出现折行、错位非常难看。这时候可以用/output全局开关wmic /output:D:\cpu_info.txt cpu get name,numberofcores这个命令把结果写到指定文件。如果不想要文件只想去掉表头可以用format相关的参数/format:csv、/format:list、/format:table。例如wmic cpu get name,numberofcores /format:csv会输出 CSV 格式的文本方便后续处理。还有/format:list会一行一个字段地输出适合解析。我自己常用的是list格式因为字段对应关系清楚脚本解析不容易出错。输出还有个经典问题中文乱码。控制台代码页和输出文件的编码如果不匹配中文系统信息会变成乱码。通常可以用chcp 65001切到 UTF-8或者用cmd /u启动 Unicode 模式。后面我会在问题排查部分细说。3. 日常运维最常用的 WMIC 实操场景3.1 一条命令摸清一台机器的配置拿到一台“新”机器不管是入职配发的电脑还是刚上架的服务器我习惯先用 WMIC 把核心配置拉一遍。下面这几条命令基本可以覆盖 80% 的信息需求。CPU 型号与核心数wmic cpu get name,numberofcores,numberoflogicalprocessors,maxclockspeed输出大概是这样的MaxClockSpeed Name NumberOfCores NumberOfLogicalProcessors 2808 Intel(R) Xeon(R) CPU E5-2680 v4 2.40GHz 14 28注意MaxClockSpeed有时候显示的是标称频率有时候显示当前睿频具体看系统版本。别太纠结这个值。内存容量与内存条型号wmic memorychip get capacity,speed,manufacturer,partnumber这条命令输出的是每条物理内存的信息而不是“总内存”。如果要看操作系统能识别的总内存用wmic computersystem get totalphysicalmemory注意单位是 KB不是 GB。我之前就犯过迷糊把几千万 KB 直接当字节看以为机器内存爆炸了。主板序列号与整机序列号wmic bios get serialnumber wmic baseboard get serialnumber,product,manufacturer整机序列号有时候在bios里有时候在baseboard里不同品牌型号位置不一样两条都跑一下。这个在资产盘点时特别重要。操作系统版本与安装时间wmic os get caption,version,installdate,lastbootuptimeinstalldate和lastbootuptime是 CIM 日期格式比如20240115093000.000000480表示 2024 年 1 月 15 日 9 点 30 分。需要转换一下但信息本身很有价值特别是排查“这台机器多久没重启了”的时候。硬盘型号与序列号wmic diskdrive get model,serialnumber,size,interfacetype这里要说明一下size是逻辑大小单位字节要除以 1,000,000,000 才是常见的“多少 GB”。而serialnumber是硬盘固件序列号不是你在资源管理器里看到的盘符。3.2 进程与服务管理三板斧查配置是只读操作相对安全。但在日常运维里更常用的是进程和服务的排查功能。列出所有正在运行的进程名称和 PIDwmic process get name,processid,executablepath如果只想找某个进程加wherewmic process where namejava.exe get processid,executablepath,commandline这里commandline属性特别有用它能显示进程启动时带了什么参数可以用来判断这个 Java 进程到底属于哪个应用。很多老运维排查端口占用第一步就是用这条命令先定位进程。终止进程一个进程卡死了、杀不掉可以用wmic process where processid1234 call terminate也可以按进程名批量终止wmic process where namenotepad.exe call terminate注意按进程名操作时要格外小心因为可能同时有多实例运行。比如用户开了三个记事本你这么一敲全给关掉了。所以优先用 PID或者加commandline条件精确匹配。查询服务状态与启动类型wmic service where namewuauserv get state,startmode,pathnamestate表示当前状态startmode表示开机启动类型。排查某个服务为什么起不来先看startmode是不是Auto再看state是不是Running然后再查依赖。查看开机启动项wmic startup list full这条命令会列出所有开机启动项包括注册表启动项和启动文件夹里的项目。输出包含Caption、Command、Location等字段排查开机慢、可疑自启动时非常有用。我见过很多恶意软件会往启动项里写东西用这条命令能很快看到异常。3.3 资产盘点把信息导出成文件资产盘点的时候不可能一台台抄写。用/output加get可以一次性把一台机器的信息导出来。我最常用的组合是wmic /output:C:\pc_info.csv cpu get name,numberofcores /format:csv wmic /output:C:\pc_info.txt bios get serialnumber两台机器可以写成一个批处理然后用批处理变量拼接文件名批量执行后统一汇总。比如echo off set pcname%COMPUTERNAME% wmic /output:C:\info_%pcname%.txt os get caption,version wmic /output:C:\info_%pcname%.txt cpu get name,numberofcores wmic /output:C:\info_%pcname%.txt bios get serialnumber注意这里有个细节/output指定的同一文件多个 WMIC 命令会覆盖而不是追加。所以在批处理里要每个命令一个文件名或者先输出到临时文件再合并。我之前吃过这个亏三条命令指向同一个文件最后只剩最后一条的内容。产品列表导出用得也很多比如列出机器上安装的所有软件名称和版本wmic product get name,version不过提醒一句product别名执行起来非常慢比从注册表卸载项读数据要慢得多因为它在后台会触发 WMI 的产品审计逐项核对已安装产品的信息。机器上软件一多可能要跑好几分钟。如果你只是想知道装了什么软件我更推荐用注册表路径查询或者直接用 PowerShell 的Get-ItemProperty。但product的好处是它能获取到部分软件完整的version和installsource有时候排查软件冲突会用得上。,执行前要做好心理准备别以为它卡死了。4. 远程查询与踩坑实录4.1 远程机器的三种连接方式WMIC 能远程查询这是它曾经的招牌功能。基本格式是在命令最前面加/node、/user、/password。wmic /node:192.168.10.20 /user:administrator /password:yourpassword cpu get name这条命令会远程连到 IP 为 192.168.10.20 的机器使用 administrator 身份查询 CPU 名称。连接远程机器的过程依赖几个关键条件目标机器开启 WMI 服务也就是 Windows Management Instrumentation 服务Winmgmt默认是启动的。目标机器防火墙允许 WMI 访问入站规则需要放行“Windows Management InstrumentationWMI”或者 TCP 135 端口以及后续 WMI 动态分配的高位端口。如果防火墙配置不当经常出现“节点错误”或“拒绝访问”。本地账号有足够权限目标机器上用于连接的账号必须在Administrators组或WinRMRemoteWMIUsers组中。如果是在域环境里域管理员账号一般都可以如果是工作组环境可能还需要配置本地账号的“通过网络访问此计算机”权限。UAC 远程限制对于内置本地管理员账号Windows 默认会通过 UAC 过滤掉大部分远程管理权限。如果直接使用内置 administrator 还提示拒绝访问往往需要修改LocalAccountTokenFilterPolicy注册表值或者使用域账号。这里我多说一句远程操作属于高风险行为在真实生产环境里密码写到命令行里本身就是不安全的行为。/password是明文出现在命令行里的可能被其他进程看到也会留在命令历史中。所以我才建议能本地操作的就本地操作远程操作尽量使用已授权的远程管理平台或者用 PowerShell 的Enter-PSSession配合受控会话。4.2 我踩过的几个典型坑这些年用 WMIC 遇到过不少问题挑几个典型的说说大家遇到的时候能少走弯路。报错“节点错误”或者“RPC 服务器不可用”这种基本都是网络不通或者防火墙拦截。排查步骤先ping目标机器确认能通再用telnet 目标IP 135测试 135 端口是否可达最后检查目标机器的 Windows 防火墙里 WMI 入站规则是否启用。如果目标在域环境可能还要检查组策略是否禁用了 WMI 相关规则。报错“拒绝访问”账号权限问题。优先级从高到低排查账号是否在管理员组账号密码是否正确内置 Administrator 账号是否被 UAC 过滤。一个很隐蔽的坑如果目标机器启用了“仅来宾”本地账户模型则任何非域账号都无法远程 WMI。检查注册表LocalAccountTokenFilterPolicy设为 1 可以取消内置管理员远程 UAC 限制但这个修改需要重启服务或重启系统才生效。中文信息乱码比如查操作系统版本或查软件名称结果显示一堆????这是因为控制台代码页和输出编码不匹配。解决办法一是执行chcp 65001切到 UTF-8 后再跑 WMIC二是用/format:csv输出到文件再打开通常也是 UTF-8 编码三是用cmd /u启动 Unicode 模式这样输出到文件的就是 UTF-16记事本打开不会乱。64 位与 32 位路径问题新版 Windows 里 WMIC 已不再默认存在老系统则存在 64 位和 32 位两套权限环境。当你用一个 32 位进程去调用 WMIC 时系统可能会重定向到SysWOW64目录下的 WMI 工具这会导致某些底层系统信息读取不到比如读取Win32_LogicalDisk时出现 64 位/32 位路径不一致的问题。解决办法是在 64 位环境下用%SystemRoot%\System32\wbem\WMIC.exe的完整路径调用。杀毒软件拦截WMIC 这类命令行工具经常被安全软件视为高风险操作尤其是在执行process call terminate、service call stopservice这类敏感操作时。如果脚本在一台机器上正常、在另一台机器上报错“拒绝访问”或者“找不到文件”先看看是不是安全软件拦截了命令行调用。4.3 权限与安全边界WMIC 是一把双刃剑查询信息很方便写操作也非常直接。比如wmic service where name某服务 call stopservice这一条命令就能把服务停掉。如果你远程执行这个命令且没有精确控制目标范围影响范围可能远超预期。所以我对使用 WMIC 有几个原则只读查询优先能用get、list解决的就不要用call、delete。写操作必须有审计在批处理脚本里执行call terminate或delete时至少先输出确认信息或者通过时机和参数限制避免误操作。不要把明文密码写进脚本如果非要远程使用 WMIC用交互式输入密码或者用更安全的连接方式比如先用net use建立受控连接再执行 WMIC 命令。生产环境操作前先备份或演练特别是对服务器批量执行命令之前先在测试机上验证筛选条件和影响范围。5. 从 WMIC 平滑迁移到 PowerShell5.1 命令对照表CIM 替代方案现在新装系统默认没有 WMIC我们总不能在后续脚本里依赖一个不存在的命令。PowerShell 里对应的命令是 CIM 相关 cmdlet核心是Get-CimInstance。它和 WMIC 使用的 WMI 类是一模一样的只是调用方式不同。我把常用的 WMIC 命令和对应的 PowerShell 命令整理成了一张对照表场景WMIC 命令PowerShell 命令查询 CPU 信息wmic cpu get name,numberofcoresGet-CimInstance Win32_Processor | Select-Object Name,NumberOfCores查询操作系统信息wmic os get caption,versionGet-CimInstance Win32_OperatingSystem | Select-Object Caption,Version查询物理内存wmic memorychip get capacity,speedGet-CimInstance Win32_PhysicalMemory | Select-Object Capacity,Speed查询磁盘信息wmic diskdrive get model,serialnumber,sizeGet-CimInstance Win32_DiskDrive | Select-Object Model,SerialNumber,Size查询进程列表wmic process get name,processid,executablepathGet-CimInstance Win32_Process | Select-Object Name,ProcessId,ExecutablePath按条件杀进程wmic process where namex.exe call terminateGet-CimInstance Win32_Process -Filter Namex.exe | Invoke-CimMethod -MethodName Terminate查询服务状态wmic service where namex get stateGet-CimInstance Win32_Service -Filter Namex | Select-Object State查询启动项wmic startup list fullGet-CimInstance Win32_StartupCommand | Select-Object *查询已安装软件wmic product get name,versionGet-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* | Select-Object DisplayName,DisplayVersion注意Get-CimInstance的-Filter参数先于-Query执行效率比Get-WmiObject -Query更高。而且Get-CimInstance输出的是对象不是格式化文本在管道里做筛选、排序、导出非常方便。5.2 为什么新环境建议直接用 CIM新系统默认不带 WMIC 只是表面原因。更深层的原因在于WMIC 是十几年前的设计它在新时代有两个明显短板第一输出是文本流。没有结构化的对象想在批处理里提取某个值要么用for /f切分要么用 findstr 匹配非常原始。PowerShell 直接输出对象取属性就是.PropertyName做条件判断、循环都方便得多。第二兼容性考虑。WMIC 在一些新版本的系统上已经没有了即便手动从旧系统拷贝 wmic.exe 过去也可能因为缺少配套的 MOF 文件或WMIC.exe依赖项而无法正常工作。与其维护这种“补丁式”方案不如直接在脚本里用Get-CimInstance一步到位。不过话说回来PowerShell 也有自己的坑。比如早期版本的 PowerShell 中Get-WmiObject与Get-CimInstance的输出格式和可用方法并不完全一致。Get-WmiObject直接绑定 WMI 对象而Get-CimInstance返回的是 CIM 实例方法调用需要通过Invoke-CimMethod一开始会有点不习惯。但熟练之后CIM 的体验更好因为它可以通过-CimSession轻松复用远程连接省去反复验证身份的过程。5.3 迁移小技巧和兼容脚本写法如果你和我一样手里有一批老脚本还在用 WMIC又想让它们在新系统上也能跑可以加一个兼容层。思路很简单判断当前系统有没有 wmic.exe有就用 WMIC 执行没有就调用 PowerShell 的 CIM 命令。批处理里可以这样写echo off where wmic nul 2nul if %errorlevel%0 ( wmic cpu get name,numberofcores ) else ( powershell -Command Get-CimInstance Win32_Processor | Select-Object Name,NumberOfCores )这样新老环境都能跑不会因为缺了 WMIC 直接报“不是内部或外部命令”。缺点是两套命令都要维护适合过渡阶段。更推荐的做法是把老的 WMIC 查询统一改成 PowerShell 脚本至少新写的脚本不再依赖 WMIC。下面是一个采集系统信息的 PowerShell 示例可以作为参考$cpu Get-CimInstance Win32_Processor $os Get-CimInstance Win32_OperatingSystem $bios Get-CimInstance Win32_BIOS $info [PSCustomObject]{ ComputerName $env:COMPUTERNAME CPUName $cpu.Name CoreCount $cpu.NumberOfCores OSVersion $os.Caption LastBoot $os.LastBootUpTime BIOSSerial $bios.SerialNumber TotalMemoryGB [math]::Round($os.TotalVisibleMemorySize / 1MB, 2) } $info | Export-Csv -Path C:\info.csv -NoTypeInformation -Encoding UTF8这个脚本读配置、算内存、导出 CSV一次完成。TotalVisibleMemorySize单位是 KB所以要除两次 1024 转成 GB。Export-Csv默认会带类型信息加上-NoTypeInformation去掉导出的 CSV 更干净。迁移过程中有个小技巧先在命令行里用Get-CimInstance Win32_Processor直接敲一遍看输出再用Select-Object慢慢裁剪字段最后才写进脚本。不要一步到位试图背命令CIM 类的属性名和 WMIC 的别名映射不是一一对应的实际看一下最稳。最后再说一点经验我自己现在的习惯是新机器、新脚本默认用 PowerShell CIM老系统上应急排查才用 WMIC。反正两条路子本质都是访问同一套 WMI 数据掌握其中一个再迁移到另一个并不难。关键在于理解背后的“类”和“属性”概念而不是死记命令拼写。如果有人问我有没有必要专门去学 WMIC我的回答是值得了解但不必在新项目里死守它。碰到了老脚本能读、能改遇到没有 PowerShell 的环境比如某些 PE 维护系统能应急就足够了。而如果你正在维护一批依赖 WMIC 的自动化脚本我的建议很直接别拖尽早把核心功能迁到Get-CimInstance然后给脚本加一层兼容判断让它在新旧系统上都能跑。这样以后系统升级了你也不用半夜被喊起来改命令。最后分享一个保存命令输出的小技巧用wmic ... /format:list输出到文件时每行是一个字段后续用来做 diff 对比特别方便。比如你怀疑两台机器配置有差异把两台机器的list输出存成文件再用fc命令对比哪里不一样一眼就看出来了。这是纯文本时代留下来的笨办法但很多时候比图形界面对比还直观。