Link to home
Start Free TrialLog in
Avatar of Diazer
DiazerFlag for United States of America

asked on

powershell INF compare.

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
Avatar of bepsoccer1
bepsoccer1
Flag of United States of America image

So have you tried something like compare-object (Get-IniContent A.ini) (Get-IniContent B.ini)?
Avatar of Diazer

ASKER

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
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?
Avatar of Diazer

ASKER

I checked with windiff and they are not the same..  so I am at a loss.
are you just trying to identify the differences?  If so, check out Beyond Compare, http://www.scootersoftware.com/download.php?c=kb_morerules
Avatar of Diazer

ASKER

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..
Avatar of Qlemo
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.
Avatar of Diazer

ASKER

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.
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.
Avatar of Diazer

ASKER

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
ASKER CERTIFIED SOLUTION
Avatar of Qlemo
Qlemo
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Diazer

ASKER

Thank you so much for your rapid response. I'm sure I will be calling on you for more questions.. :)
Avatar of Diazer

ASKER

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..
Avatar of Diazer

ASKER

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
We would need to perform exact matches, and some more logic, to get above format. Still thinking about how to do that ...
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

Avatar of Diazer

ASKER

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?
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.
Avatar of Diazer

ASKER

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
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?).
Avatar of Diazer

ASKER

It Works.  had spaces in the INf File..

Thank you so much :)
Avatar of Diazer

ASKER

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