Monday, April 23, 2012

Powershell: Compare system configuration vs baseline

Powershell makes it very easy to take custom baselines and compare configurations to that baseline.  One of the easiest examples is checking for changes to services.  Powershell has simple cmdlets for listing services, saving the results to a file, and comparing for differences.  Here is a quick snip of code that hi-lights what we are doing.

$baseline = get-service
stop-service spooler -force
$current = get-service
Compare-Object $baseline $current -Property Name Status

This will capture a baseline, stop your print spooler, then capture a current list.  Then we compare a few properties.  It will hilight that in one list the service is running and in the other it is not.  If a new service was added or removed, then it would also be indicated.  We can use this simple concept to build a configuration change tracking system.

I want to expand this a little bit into a script that I can run every week to show me the changes on my systems. Sounds easy enough, so lets see what we come up with.

function Compare-Baseline($folder, $id, $command, $properties){

 $Root = "$folder"
 $report = "$root\$id-report.txt"

 #Prep folders
 if((Test-Path($Root)) -eq $false){
     md $Root
 }

 #Prep Baseline
 if((Test-Path("$root\$id-base.xml")) -eq $false  ){
     & $command | Select-Object -Property $properties | Export-Clixml -Path "$root\$id-base.xml"
     "New $id Baseline created" | Out-File $report -Append
 }

 & $command | Select-Object -Property $properties | Export-Clixml -Path "$root\$id-current.xml"

 $base = Import-Clixml $root\$id-base.xml
 $current = Import-Clixml $root\$id-current.xml
 $compare =  Compare-Object $base $current -Property $properties -SyncWindow 100 

 if($compare){
  $compare | Out-File $report -Append
 }
 Remove-Item $root\$id-base.xml
 Move-Item $root\$id-current.xml $root\$id-base.xml

 type $report
} 

Compare-Baseline "c:\scratch" "Service" {Get-WMIObject win32_service} ("Name", "Startmode", "state", "pathname")
Now I can run this any time I want to see when the services on this box change.  I decided to use the WMI win32_service because it gives me a few more details, the its the same idea.  I wrote this in a very general way so it would be possible run it on many machines.

I have several ideas for this going forward.  I could easily schedule this and have the results emailed to me.  I may also collect those baselines in a central location.  Taking this a step further, I can have one task that checks AD for servers.  Then runs this once on each server.  This would allow it to discover new servers and provide me a single report.