关于本文
本文采用借助生成式 AI 的自动化流程创建。我们参考了 Microsoft Learn 的 Compare-Object 官方规范,并构建了使用虚拟设备台账来理解比较方向的实验。验证状态:📘 已确认官方规范・尚未在 PowerShell 实机上执行
PowerShell 的 Compare-Object 差分方向反了?如何安全识别添加、删除和一致项
想要对比昨天的设备台账和今天的台账,汇报增加和减少的项目。虽然可以使用 Excel 涂色核对,但如果是每天重复的工作,PowerShell 的Compare-Object将非常有用。然而,如果误读了结果中出现的<=和=>,就会把新添加的设备误报为已被删除。这些符号并不代表实际的添加或删除操作,而是表示该值存在于哪一个输入中。
这次我们不操作实际文件,而是将虚拟的设备代码放入变量中进行比较。我们创建两个数组,预测结果,确认符号的含义,然后调换输入方向观察差异。之后,我们还将探讨数量变更、重复代码以及空值处理等简单比较所不擅长的情况。屏幕示例是根据官方规范推导出的期望结果,并非在本文制作过程中执行 PowerShell 得到的结果。
支持环境、功能与限制(确认于:2026年11月7日)
| 项目 | 条件 |
|---|---|
| 对象 | Windows PowerShell 5.1 或 PowerShell 7 系列 |
| 使用功能 | Microsoft.PowerShell.Utility 的 Compare-Object |
| 所需物品 | PowerShell 控制台。无需附加模块或管理员权限 |
| 输入 | 包含虚构设备代码的字符串数组 |
| 执行范围 | 仅限内存中的比较。无文件修改或外部通信 |
| 未确认 | 示例代码的实机运行情况、各终端上的显示顺序 |
| 限制 | 不具备自动追踪设备数量或状态变更的功能 |
首先,比较两个数组
假设昨天的台账有 A01、B02、C03,今天的台账有 B02、C03、D04。设定为昨天的 A01 消失了,今天的 D04 增加了。最初将其做成小型列表,便能亲眼判断输出是否正确。这里只使用字符串,无需粘贴公司的终端信息或客户数据。
$yesterday = @('A01', 'B02', 'C03')
$today = @('B02', 'C03', 'D04')
Compare-Object -ReferenceObject $yesterday -DifferenceObject $today
在预期结果中,A01 带有<=,D04 带有=>显示。由于 B02 和 C03 两边都有,因此默认不输出。比较结果中的InputObject是目标值,SideIndicator是指示其处于哪一侧的列。切勿仅凭显示行的顺序来判断添加或删除,请务必结合这两列一起阅读。
第一个陷阱是认为“屏幕上没有的东西就是被删除了”。在差异显示的默认行为中,两边都有的项目不会显示。B02 和 C03 并不是消失了,而是因为没有变化而被省略了。如果需要核对台账的所有条目,请使用稍后介绍的匹配显示功能。
符号表示数据存在的一侧
ReferenceObject是作为比较基准的输入,DifferenceObject这是与该基准进行比对的输入。如果像这次这样确定前一天为基准、当天的日期为比对对象,<=就意味着仅限昨天,=>则意味着仅限今天。之所以能将仅属于昨天的 A01 解读为“删除候选”,将仅属于今天的 D04 解读为“添加候选”,是因为我们事先确定了该输入的作用。
符号本身并不具有固定的“删除”或“添加”含义。如果颠倒输入,箭头的方向也会随之相反。在将比对结果交付给他人时,如果明确注明“基准是昨天,比对目标是今天”,就能减少看到相同符号的人做出相反判断的事故。特别是在自动报告脚本中,在变量名中使用表示日期或基准的名称是很实用的做法。
下图仅表示输入与符号的对应关系。图中的箭头并不表示设备的移动或文件操作,而是表示比对结果的分类。
flowchart TD
A["昨日と今日の一覧を比較"] --> B{"値が存在する側は?"}
B -->|"昨日だけ"| C["ReferenceObject 側: <="]
B -->|"今日だけ"| D["DifferenceObject 側: =>"]
B -->|"両方"| E["既定では非表示"]
图中的最后一个分支非常重要。看不到一致的项目与项目不存在是两码事。了解了这一区别后,即使差异结果为空,也可以分头调查“全数一致的可能性”和“输入数据为空的可能性”。
改变一个条件:同时显示一致项
接下来在不改变输入内容的情况下,-IncludeEqual仅添加该项。此选项还将同时存在于两个列表中的项目包含在结果中。这是一项用于确认相比于默认的差异显示,究竟会添加哪些信息的实验。
Compare-Object -ReferenceObject $yesterday -DifferenceObject $today -IncludeEqual
预期的分类是:A01 仅属于昨天,D04 仅属于今天,B02 和 C03 两者兼有。两边都有的项目会带有==。如果只想确认增减情况,默认输出就足够了;但如果要记录核对这一行为,显示一致的项目会更容易进行说明。不过,==仅表示设备代码在双方中都存在,并不证明连数量或存放地点也完全一致。
让我们也来改变输入的顺序。如果反过来将昨天和今天传进去,A01 和 D04 的箭头就会对调。这并不是比对出错了,而是互换了 ReferenceObject 和 DifferenceObject 作用的结果。如果单纯死记硬背“指向左边就是删除”,在这个实验中就会做出错误的判断。最重要的是遵循先固定基准再解读符号的顺序。
Compare-Object -ReferenceObject $today -DifferenceObject $yesterday
在预期结果中,D04 是<=,A01 是=>。如果要在运营中恢复以昨天为基准,请将参数顺序改回原样。即便变量内容相同,仅仅改变参数的分配就会导致报告的含义完全相反,这是该命令中最需要记住的特点。
容易出错的边界条件
即使设备代码 A01 昨天和今天都存在,其数量也可能从 3 变为了 5。仅通过代码比对是无法发现这种变更的。PowerShell 的Compare-Object虽然具有通过-Property指定比对对象属性的功能,但必须将其与“以相同代码为键来对应数量变更前后”的操作分离开来设计。因为“值的有无”与“属性的变化”是两个不同的问题。
请注意重复代码。如果台账中有多行相同的代码,仅凭比较结果无法唯一判断“哪一行被更新了”。应在事先检测输入重复,确认物品代码是否真的是唯一键。如果台账中的代码在不同部门之间可能重复,则必须事先确定业务上的唯一性,例如使用部门与代码组合的键。
大小写的处理也很重要。默认的字符串比较不区分大小写。如果业务上将A01和a01视为不同的代码,请考虑-CaseSensitive。反之,如果在输入源处已统一了书写格式,那么在比较前进行规范化有时会更便于运维。哪种方式正确,取决于台账中代码的大小写是否有实际意义。
此外,即使外观相同,末尾带有空格的值也是不同的字符串。请决定是在比较前去除多余空格,还是作为输入错误进行报告。如果无条件删除空格,对于原本将空格用作有意义字符的数据,则会引发其他问题。在对字符串进行处理之前,确认数据的正式规范才是安全的。
获取输入失败时也需要注意。比较结果为空,并不一定意味着两个台账完全一致。请确认原始数据是否为空、数据量是否在预期之内、读取时是否没有发生错误。在定期处理中,比较前记录获取的记录数和日期、如果出现异常则停止差分报告的机制非常有效。
如果在工作中实际使用,应将差分视为批准前的候选内容
设想在信息系统部门比较终端列表的场景。即使发现了仅在昨天存在的终端,也不一定意味着它已被废弃。可能是因为电源关闭、收集失败、未连接网络等原因。差分只是缩小调查范围的材料,并不是执行删除操作的许可。应首先确认收集条件和原始数据,必要时向相关负责人咨询。
物品台账也是如此。在断定仅在今天存在的代码属于新购入之前,请确认是否存在代码修改或部门间调拨的情况。将比较结果直接反映到正式台账中并不安全,更安全的做法是将其保存为差分报告,并通过单独的流程仅反映已确认的变更。自动化设计的初期阶段应限定在“发现”为止,变更则应在经过批准后进行。
处理大量数据时,请同时验证处理时间和内存占用量。适用于当前几条数组的逻辑,并不能保证在拥有数万条数据的台账中具备相同的性能。此外,若用于审计,则应保存输入数据和比较条件,以便日后能够重现相同的结。为了在错拿不同日期的文件时能够及时察觉,记录获取日期时间和数据量也是实务中的一种巧思。
总结
Compare-Object的<=与=>表示值存在于两个输入的哪一方中。如果将昨天固定为ReferenceObject,将今天固定为DifferenceObject,就可以区分仅存在于昨天和仅存在于今天的项目。如果还想显示一致的项目,可以添加IncludeEqual。正确读取差分与判断业务上的增减是两回事。请首先通过虚拟数组确认方向,在实际台账中检查获取是否成功、是否存在重复、键、数量以及空行后再加以利用。
参考资料与官方一手信息
- Microsoft Learn“Compare-Object”: https://learn.microsoft.com/ja-jp/powershell/module/microsoft.powershell.utility/compare-object?view=powershell-7.6

