When working in PowerShell, it is common to work with
collections of objects. Most PowerShell commands generate objects, as do
many of the methods that you work with in the .NET Framework. To help you
work with these object collections, PowerShell introduces the Compare-Object
cmdlet.
The Compare-Object
cmdlet provides
functionality similar to the well-known diff
commands, but with an object-oriented
flavor.
To compare the output of two commands, store
the output of each command in variables, and then use the Compare-Object
cmdlet to compare those
variables:
PS > notepad PS > $processes = Get-Process PS > Stop-Process -ProcessName Notepad PS > $newProcesses = Get-Process PS > Compare-Object $processes $newProcesses InputObject SideIndicator ----------- ------------- System.Diagnostics.Process (notepad) <=
The Solution shows how to determine which
processes have exited between the two calls to Get-Process
. The SideIndicator
of <=
tells us that the process was present in
the left collection ($processes
) but
not in the right ($newProcesses
). To
work with the actual object that was different, access the
InputObject
property:
PS > $diff = @(Compare-Object $processes $newProcesses)[0] PS > $process = $diff.InputObject PS > $process.Handles 55
By default, the Compare-Object
cmdlet
uses the comparison functionality built into most .NET objects. This
works as expected most of the time, but sometimes you might want to
override that comparison behavior. For example, you might want two
processes to be considered different if their memory usage changes. In
that case, use the -Property
parameter.
PS > Compare-Object $processes $newProcesses -Property Name,WS | Sort Name Name WS SideIndicator ---- -- ------------- dwm 31358976 <= dwm 29540352 => explorer 37969920 <= explorer 38023168 => lsass 1548288 => lsass 1372160 <= notepad 5701632 <= notepad 2891776 => powershell 44281856 => powershell 44290048 <= SearchIndexer 13606912 => SearchIndexer 13619200 <= svchost 56061952 <= svchost 43982848 <= svchost 56037376 => svchost 44048384 => svchost 12193792 <= svchost 12201984 => taskeng 9220096 <= taskeng 9228288 =>
When
you use the -Property
parameter, the
Compare-Object
cmdlet outputs custom objects that
have only the properties you used in the comparison. If you still want
access to the original objects used in the comparison, also use the
-PassThru
parameter. In that case, PowerShell instead
adds the SideIndicator
property to the original
objects.
If the objects you are comparing are
already in proper order (for example, the lines in a file), you can
improve the performance of the comparison process by using the
-SyncWindow
parameter. A sync window of five, for
example, looks for differences only within the surrounding five
objects.
For more information about the Compare-Object
cmdlet, type
Get-Help
Compare-Object
.
To determine simple differences in the content
of each file, store their content in variables, and then use the
Compare-Object
cmdlet to compare
those variables:
PS > "Hello World" > c: empfile1.txt PS > "Hello World" > c: empfile2.txt PS > "More Information" >> c: empfile2.txt PS > $content1 = Get-Content c: empfile1.txt PS > $content2 = Get-Content c: empfile2.txt PS > Compare-Object $content1 $content2 InputObject SideIndicator ----------- ------------- More Information =>
The primary focus of the Compare-Object
cmdlet is to compare two
unordered sets of objects. Although those sets of objects can be strings
(as in the content of two files), the output of Compare-Object
when run against files is
usually counterintuitive because of the content losing its order.
When comparing large files (or files where the
order of comparison matters), you can still use traditional file
comparison tools such as diff.exe
or
the WinDiff
application that comes
with both the Windows Support Tools and Visual Studio.
For more information about the Compare-Object
cmdlet, type Get-
Help
Compare-Object
.
To verify the integrity of file sets, use the
Get-FileHash
script provided in
Program: Get the MD5 or SHA1 Hash of a File to
generate the signatures of those files in question. Do the same for the
files on a known good system. Finally, use the Compare-Object
cmdlet to compare those two
sets.
To generate the information from the files in question, use a command like:
dir C:WindowsSystem32WindowsPowerShellv1.0 | Get-FileHash | Export-CliXml c: empPowerShellHashes.clixml
This command gets the hash values of the files
from C:WindowsSystem32 WindowsPowerShellv1.0,
and uses the Export-CliXml
cmdlet to
store that data in a file.
Transport this file to a system with files in a known good state, and then import the data from that file.
$otherHashes = Import-CliXml c: empPowerShellHashes.clixml
You can also map a network drive to the files in question and skip the export, transport, and import steps altogether:
net use x: \lee-deskc$WindowsSystem32WindowsPowerShellv1.0 $otherHashes = dir x: | Get-FileHash
Generate the information from the files you know are in a good state:
$knownHashes = dir C:WindowsSystem32WindowsPowerShellv1.0 | Get-FileHash
Finally, use the Compare-Object
cmdlet to detect any
differences:
Compare-Object $otherHashes $knownHashes -Property Path,HashValue
If there are any differences, the Compare-Object
cmdlet displays them in a list,
as shown in Example 22-1.
Example 22-1. The Compare-Object cmdlet showing differences between two files
PS > Compare-Object $otherHashes $knownHashes -Property Path,HashValue Path HashValue SideIndicator ---- --------- ----------------------- system.management.aut... 247F291CCDA8E669FF9FA... => system.management.aut... 5A68BC5819E29B8E3648F... <= PS > Compare-Object $otherHashes $knownHashes -Property Path,HashValue | Select-Object Path Path ---- system.management.automation.dll-help.xml system.management.automation.dll-help.xml
For more information about the Compare-Object
cmdlet, type Get-
Help
Compare-Object
. For more information about the
Export-CliXml
and Import-CliXml
cmdlets, type Get-Help Export-CliXml and Get-Help
Import-CliXml
, respectively.
18.189.180.43