Solved

powershell INF compare.

Posted on 2013-05-20
22
772 Views
Last Modified: 2013-06-14
I am trying to build a query that will go in a compare two inf files that may have different delimiters so that I can then create a table and display it by converting it to an HTML file.

Any ideas?  The files that I am trying to compare are created by secedit.exe when the local group policy is exported..

I am able to compare the files when its X = Y but when it starts going x=y,z thats where I get lost..

I found this function and maybe thought it could be made to work for my needs..
Function Get-IniContent
{
    <#
    .Synopsis
        Gets the content of an INI file
        
    .Description
        Gets the content of an INI file and returns it as a hashtable
        
    .Notes
        Author    : Oliver Lipkau <oliver@lipkau.net>
        Blog      : http://oliver.lipkau.net/blog/
        Date      : 2010/03/12
        Version   : 1.0
        
        #Requires -Version 2.0
        
    .Inputs
        System.String
        
    .Outputs
        System.Collections.Hashtable
        
    .Parameter FilePath
        Specifies the path to the input file.
        
    .Example
        $FileContent = Get-IniContent "C:\myinifile.ini"
        -----------
        Description
        Saves the content of the c:\myinifile.ini in a hashtable called $FileContent
    
    .Example
        $inifilepath | $FileContent = Get-IniContent
        -----------
        Description
        Gets the content of the ini file passed through the pipe into a hashtable called $FileContent
    
    .Example
        C:\PS>$FileContent = Get-IniContent "c:\settings.ini"
        C:\PS>$FileContent["Section"]["Key"]
        -----------
        Description
        Returns the key "Key" of the section "Section" from the C:\settings.ini file
        
    .Link
        Out-IniFile
    #>
    
    [CmdletBinding()]
    Param(
        [ValidateNotNullOrEmpty()]
        [ValidateScript({(Test-Path $_) -and ((Get-Item $_).Extension -eq ".inf")})]
        [Parameter(ValueFromPipeline=$True,Mandatory=$True)]
        [string]$FilePath
    )
    
    Begin
        {Write-Verbose "$($MyInvocation.MyCommand.Name):: Function started"}
        
    Process
    {
        Write-Verbose "$($MyInvocation.MyCommand.Name):: Processing file: $Filepath"
            
        $ini = @{}
        switch -regex -file $FilePath
        {
            "^\[(.+)\]$" # Section
            {
                $section = $matches[1]
                $ini[$section] = @{}
                $CommentCount = 0
            }
            "^(;.*)$" # Comment
            {
                if (!($section))
                {
                    $section = "No-Section"
                    $ini[$section] = @{}
                }
                $value = $matches[1]
                $CommentCount = $CommentCount + 1
                $name = "Comment" + $CommentCount
                $ini[$section][$name] = $value
            } 
            "(.+?)=(.*)" # Key
            {
                if (!($section))
                {
                    $section = "No-Section"
                    $ini[$section] = @{}
                }
                $name,$value = $matches[1..2]
                $ini[$section][$name] = $value
            }
        }
        Write-Verbose "$($MyInvocation.MyCommand.Name):: Finished Processing file: $path"
        Return $ini
    }
        
    End
        {Write-Verbose "$($MyInvocation.MyCommand.Name):: Function ended"}
}

Open in new window


regards,

Erica
GptTmpl.inf.txt
0
Comment
Question by:Diazer
  • 12
  • 7
  • 3
22 Comments
 
LVL 4

Expert Comment

by:bepsoccer1
ID: 39184907
So have you tried something like compare-object (Get-IniContent A.ini) (Get-IniContent B.ini)?
0
 

Author Comment

by:Diazer
ID: 39185025
bepsoccer1,

When I type that it does nothing..
With the above script I can get it to add the values to a hash table, sort them and see there values but when it comes to comparing them is when I get lost..

Regards,
Erica
0
 
LVL 4

Expert Comment

by:bepsoccer1
ID: 39185059
When you say it does nothing you mean it gives no output?  Generally that means they are the same.  I don't know enough about the Get-INIContent function here, but just for more info does compare-object (Get-IniContent A.ini) (Get-IniContent B.ini) -includeEqual produce any results?
0
 

Author Comment

by:Diazer
ID: 39185284
I checked with windiff and they are not the same..  so I am at a loss.
0
 
LVL 4

Expert Comment

by:bepsoccer1
ID: 39185356
are you just trying to identify the differences?  If so, check out Beyond Compare, http://www.scootersoftware.com/download.php?c=kb_morerules
0
 

Author Comment

by:Diazer
ID: 39185393
I know that there are many utilities but what I am doing is going to compare the attached INF file as the base with a Unknown Inf file and then pipe the differences into an HTML file and this has to be done with little user internventions, I know that software exists out there but I also know that there has to be a way to put it data in an array or hashtable to compare it..
0
 
LVL 68

Expert Comment

by:Qlemo
ID: 39186013
The issue is that the hash table again contains hash tables. Compare-Object cannot compare that, it can't even compare hash tables, AFAIK. So we have to "flatten" that to something we can compare:
function flatten-hash ($hash)
{ foreach ($section in $hash.keys)
   { foreach ($key in $hash[$section].keys)
     { foreach ($value in $hash[$section][$key])
       {  New-Object PSObject -Property @{section = $section; key = $key; value = $value; String = "[$Section] $Key = $value" }
}}}}

$ini1 = flatten-hash (Get-IniContent GptTmpl.Inf)
$ini2 = flatten-hash (Get-IniContent GptReal.Inf)
Compare-Object -PassThru $ini1 $ini2 -Property String

Open in new window

That's not the best one can do, but should suffice to see differences.
0
 

Author Comment

by:Diazer
ID: 39186031
Qlemo,

Brilliant..  So how do I output that information to a HTML file?

Reason being is then I can do the Colorize and make things show up as the SideIndicator arrows just confuse the user.
0
 
LVL 68

Expert Comment

by:Qlemo
ID: 39186103
The result of the compare contains the complete object (because of -PassThru, plus the side indicator. A common transformation is to have one object on the left, the other on the right, depending on the side indicator. That table can then be converted into HTML.
Compare-Object -PassThru $ini1 $ini2 -Property String | % {
  if ($_.SideIndicator -eq "=>") { $obj = New-Object PSObject -Property @{LeftSection = $_.Section; LeftKey = $_.Key; LeftValue = $_.Value; RightSection = ""; RightKey = ""; RightValue = ""}}
  if ($_.SideIndicator -eq "<=") {
    if (!$obj) {
      $obj = New-Object PSObject -Property @{LeftSection = ""; LeftKey = ""; LeftValue = ""; RightSection = $_.Section; RightKey = $_.Key; RightValue = $_.Value }
    } else {
      $obj.RightSection, $obj.RightKey, $obj.RightValue = $_.Section, $_.Key, $_.Value
    }
    $obj
  }
} | select LeftSection, LeftKey, LeftValue, RightSection, RightKey, RightValue | ft

Open in new window

Again, that is not perfect, as it relies on the exact sequence as compare-object writes out differences. If you change one of the key names in GptReal.ini, you'll see.
0
 

Author Comment

by:Diazer
ID: 39187972
So the file would have to be exactiy the same as the other file sequence wise?

Do you know of a better method that would maybe put them in an array as the GptReal.inf is always going to be different computer to computer in some form or fasion.. I just want the most effective way of using SECedit.exe /export /cfg  GptReal.inf getting that inf that is created from the export and comparing to known security values..  I would have been able to convert it to a csv and saved myself some headaches but I don't know how to use the delimiters in a way to convert "MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Setup\RecoveryConsole\SecurityLevel=4,0" to a comma seperated table which would be even better honestly..  Go line by line thru the Inf and then convert it to look like "MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Setup\RecoveryConsole\SecurityLevel,4,0

I guess if I went in the document and replaced all the = with commas that would work would it not?  maybe I'm going about this the hard way.. LOL
0
 
LVL 68

Accepted Solution

by:
Qlemo earned 500 total points
ID: 39188259
If we use
$ini1 = flatten-hash (Get-IniContent GptTmpl.Inf) | sort String
$ini2 = flatten-hash (Get-IniContent GptReal.Inf) | sort String

Open in new window

(or instead sort for section, key, value, which does not make a difference) you should get a sorted list, and compare-object will try to do its best to sync both INFs.

If you want a tabular representation of your INFs, try with
$ini2 | format-table Section, Key, Value  # for Display
$ini2 | select Section, Key, Value | export-csv -NoType GptReal.CSV # for CSV file

Open in new window

or use convertto-* or ...
0
IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 

Author Closing Comment

by:Diazer
ID: 39188499
Thank you so much for your rapid response. I'm sure I will be calling on you for more questions.. :)
0
 

Author Comment

by:Diazer
ID: 39189159
I have been playing with the code but I still cant seem to get the tables to output into an HTML table..  I'm wanting a table that shows key and value.   So it could list all the key's that are in the GptTmpl.inf, The Values with the column name "Default" and another colomn "Actual" that shows the current setting even if it is empty to show "No Value"

So I guess it would look something like this

Keys                                  |     Default     |    Actual
MaximumPasswordAge  |         90         |       60

It just makes it easier to report the changes..
0
 

Author Comment

by:Diazer
ID: 39191516
Qlemo,

I manged to get the code to export to html but I am having some issues with the data not exporting over.. as you said the data has to line up.. I tried to use the sort feature but that seem to not make a differance.. Really I think that the code needs to be tweaked a little more and I am working on it but doing circles :( can you test with the file I attached and maybe export your GptTMPL.inf on your machine and do a compare.. Really I only need to display the table as I have above.

Thank you in advance
0
 
LVL 68

Expert Comment

by:Qlemo
ID: 39191775
We would need to perform exact matches, and some more logic, to get above format. Still thinking about how to do that ...
0
 
LVL 68

Expert Comment

by:Qlemo
ID: 39192684
Does this one work as a base for HTML reports for you?
Compare-Object -PassThru $ini1 $ini2 -Property String | % { $obj = $null } {
  if ($obj -and $obj.Section -eq $_.Section -and $obj.Key -eq $_.Key)
  {
    if ($_.SideIndicator -eq '<=') { $obj.Default = $_.Value } else { $obj.Value = $_.Value }
  } else {
    $obj
    $obj = New-Object PSObject -Property @{Section = $_.Section; Key = $_.Key; Default = $_.Value*($_.SideIndicator -eq '<='); Value = $_.Value*($_.SideIndicator -eq '=>') }
  }
} {$obj} 

Open in new window

0
 

Author Comment

by:Diazer
ID: 39192751
ok so that is looking better but it still does not line up the Key values and when it displays it they only shows the data that corrosponds to the key so I guess the Key values are not merging up and then displaying the values for each..

Would seeing the code help any?
0
 
LVL 68

Expert Comment

by:Qlemo
ID: 39193563
I see - compare-object is too stupid to provide differences in correct sequence. We have to sort that output, too.
Compare-Object -PassThru $ini1 $ini2 -Property String | sort String | % { $obj = $null } {
  if ($obj -and $obj.Section -eq $_.Section -and $obj.Key -eq $_.Key)
  {
    if ($_.SideIndicator -eq '<=') { $obj.Default = $_.Value } else { $obj.Value = $_.Value }
  } else {
    $obj
    $obj = New-Object PSObject -Property @{Section = $_.Section; Key = $_.Key; Default = $_.Value*($_.SideIndicator -eq '<='); Value = $_.Value*($_.SideIndicator -eq '=>') }
  }
} {$obj} 

Open in new window

This worked against my secedit export, which is totally different from your template, and so I'm confident it is what you need.
0
 

Author Comment

by:Diazer
ID: 39194832
do you know of any way to prevent this? maybe there is a way to merge the keys together?  


Key                                            Default                                        Value

 
AuditAccountLogon                         3

AuditAccountLogon                                                                           3

I'm looking into it as well as I'm sure its just another switch..  I know that we had it working the right way when importing the differnt CSV's
0
 
LVL 68

Expert Comment

by:Qlemo
ID: 39195001
Is it the same section? As long as both section and key are the same, you should only get a single entry. That worked great for me, as already said. Please check if there are no additional spaces in section or key or such (unlikely, but who knows?).
0
 

Author Comment

by:Diazer
ID: 39195696
It Works.  had spaces in the INf File..

Thank you so much :)
0
 

Author Comment

by:Diazer
ID: 39248254
Qlemo,

I am going to post another question and reference this one. as I am needing help with the hash table and I know you helped me before.  I want you to get credit for it.

Erica
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Active Directory replication delay is the cause to many problems.  Here is a super easy script to force Active Directory replication to all sites with by using an elevated PowerShell command prompt, and a tool to verify your changes.
How to sign a powershell script so you can prevent tampering, and only allow users to run authorised Powershell scripts
Access reports are powerful and flexible. Learn how to create a query and then a grouped report using the wizard. Modify the report design after the wizard is done to make it look better. There will be another video to explain how to put the final p…
This video gives you a great overview about bandwidth monitoring with SNMP and WMI with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're looking for how to monitor bandwidth using netflow or packet s…

760 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

21 Experts available now in Live!

Get 1:1 Help Now