Search code examples
powershellcompareobject

Import-Csv data parse to array


I have a CSV file which contains multiline in some cells. I will use this data to compare the value got it from powershell.

This returns differences between the object, however the value is the same.

Expected Results should return nothing because both values are the same.

CSV content:

Value
System\CurrentControlSet\Control\ProductOptions
System\CurrentControlSet\Control\Server Applications
Software\Microsoft\Windows NT\CurrentVersion

Code:

PS> $data = Import-Csv .\tr.csv

PS> $data.Value
System\CurrentControlSet\Control\ProductOptions
System\CurrentControlSet\Control\Server Applications
Software\Microsoft\Windows NT\CurrentVersion

PS> $regval = ((Get-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Control\SecurePipeServers\winreg\AllowedExactPaths).machine | Out-String).Trim()

PS> $regval
System\CurrentControlSet\Control\ProductOptions
System\CurrentControlSet\Control\Server Applications
Software\Microsoft\Windows NT\CurrentVersion

PS> Compare-Object $data.Value $regval
System\CurrentControlSet\Control\ProductOptions...                                                                                                  =>
System\CurrentControlSet\Control\ProductOptions...                                                                                                  <=

PS> $Tostring = ($data.Value | out-string).Trim()

PS> Compare-Object $Tostring $regval

InputObject                                                                                                                                         SideIndicator
-----------                                                                                                                                         -------------
System\CurrentControlSet\Control\ProductOptions...                                                                                                  =>
System\CurrentControlSet\Control\ProductOptions...                                                                                                  <=


PS> $Tostring.Length
145

PS> $regval.Length
147

Solution

  • The likeliest explanation is that:

    • the multi-line value from your CSV (obtained from a single field) contains LF-only (Unix-style) newlines,
    • whereas the string derived form the registry values has CRLF (Windows-style) newlines, due to applying Out-String to an array of strings.

    The most direct fix is to remove the CR chars. from $regval (you can use "`r" in PowerShell to generate a CR char):

    # ...
    
    # Remove all CRs from $regval.
    # Note that not providing a replacement string (missing 2nd RHS operand)
    # default to the empty string, which effectively *removes* what was matched.
    $regval = $regval -replace "`r"
    
    # Should now work as expected.
    Compare-Object $data.Value $regval
    

    That said:

    • Since you're comparing just two objects that are strings, you can avoid the overhead of Compare-Object and simply use -eq:

      $data.Value -eq $regVal
      
    • Alternatively, you can split the multi-line values into arrays of lines and compare them individually; note that if you use regex "`r?`n" or ('\r?\n') to match newlines to split by - which matches both LF-only and CRLF newlines - you needn't remove CR chars. beforehand or even apply Out-String to the array output from the Get-ItemProperty HKLM:\... call to begin with; however, with the variable values from your question, you'd use:

      # Newline-style-agnostic
      Compare-Object ($data.Value -split "`r?`n") ($regval -split "`r?`n")
      
      # Or, knowing that $data.Value has LF, and $regval CRLF
      Compare-Object ($data.Value -split "`n") ($regval -split "`r`n")
      
      # Or, by using the [string[]] array of registry values directly:
      $regvals = (Get-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Control\SecurePipeServers\winreg\AllowedExactPaths).machine
      Compare-Object ($data.Value -split "`n") $regvals
      

    As for what you tried:

    $Tostring = ($data.Value | out-string).Trim()

    If $data.Value is a single string that doesn't have a trailing newline - whether or not it has embedded newlines - the above is an effective no-op:

    • An input object that is already a string is passed through as-is by Out-String.
    • While Out-String does append a trailing CRLF newline (on Windows), the subsequent .Trim() call removes it again.