0

I have a Powershell function that formats out put from another function I have to gather version, path and file information based on some registry queries. It seems all the data is being stored to one variable and only printing one line altogether. Below is my code, the output and an explanation of what I need in the desired output.

Code:

 function getOffice()
{
  $list = new-object System.Collections.Generic.List[PSCustomObject];
  $found_paths = @();
  $final_paths = @();

  $uninstall_keys = getRegistrySubkeys "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" '\\Office[\d+.*]';
  if ($uninstall_keys -ne $null) 
  {
    foreach ($key in $uninstall_keys)
    {
      $product_name = getRegistryValue $key "DisplayName";
      $version = getRegistryValue $key "DisplayVersion";
      $base_install_path = getRegistryValue $key "InstallLocation"; 
      $full_install_path = (Get-ChildItem -Directory -LiteralPath $base_install_path | Where-Object Name -match '^Office\d{1,2}\D?').FullName;

      $found_paths += ,$full_install_path;

      $exes = @("MSOCF.DLL", "access.exe", "word.exe", "wordCnv.exe", "WordViewer.exe", "Excel.exe", "ExcelCnv.exe", "ExcelViewer.exe", "PowerPoint.exe", 
      "PowerPointViewer.exe", "PowerPointCnv.exe", "Publisher.exe", "Project.exe", "OneNote.exe", "InfoPath.exe Groove.exe", "FrontPage.exe", 
      "SharePointDesigner.exe", "Visio.exe", "VisioViewer.exe", "Lync.exeOutlook.exe", "WINPROJ.EXE");

      foreach($path in $found_paths)
      {
        foreach($exe in $exes)
        {
          $found_files = Get-Item ([System.IO.Path]::Combine($path, $exe)) -EA Ignore;
          $found_file = $found_files.Name;

          if ($found_file)
          {
            $office = makeFileResult $found_file, $path, $version, $product_name, $version; 
            $list.Add($office);
            $list 

          }
        }
      }
    }
  }
} 

function makeFileResult($name, $path, $file_version, $product_name, $product_version)
{
     return [PSCustomObject]@{
       path = $path;
       file = $name;
       product_version = $product_version;
       product_name = $product_name;
       file_version = $file_version;
     };
}

getOffice 

Output:

path            : 
file            : {MSOCF.DLL, C:\Program Files\Microsoft Office\Office15, 15.0.4569.1506, Microsoft Project Standard 2013...}
product_version : 
product_name    : 
file_version    : 

path            : 
file            : {WINPROJ.EXE, C:\Program Files\Microsoft Office\Office15, 15.0.4569.1506, Microsoft Project Standard 2013...}
product_version : 
product_name    : 
file_version    : 

path            : 
file            : {MSOCF.DLL, C:\Program Files\Microsoft Office\Office15, 15.0.4569.1506, Microsoft Project Standard 2013...}
product_version : 
product_name    : 
file_version    : 

path            : 
file            : {WINPROJ.EXE, C:\Program Files\Microsoft Office\Office15, 15.0.4569.1506, Microsoft Project Standard 2013...}
product_version : 
product_name    : 
file_version    : 

I am not sure why all the data is only being stored in the `file` key here.

I am not sure why all the data is only being stored in the file key here.

Desired Output:

path            : C:\Program Files\Microsoft Office\Office15
file            : MSOCF.DLL
product_version : 15.0.4569.1506
product_name    : Microsoft Project Standard 2013
file_version    : 15.0.4569.1506

path            : C:\Program Files\Microsoft Office\Office15
file            : WINPROJ.EXE
product_version : 15.0.4569.1506
product_name    : Microsoft Project Standard 2013
file_version    : 15.0.4569.1506
1
  • 1
    My recommendation is to learn to walk before you start trying to run. Slow down and take out the foreach loops and do one value at a time and observe the results. Using a debugger helps too. Commented Jan 11, 2022 at 23:04

1 Answer 1

1

Seems silly, but remove the commas and only have spaces when making the function call makeFileResult.

$office = makeFileResult $found_file $path $version $product_name $version

Since the parameters in the function call have no type defined, PowerShell will do it's best to "guess" what type you mean. The commas in between the variables end up being interpreted as a string array instead of a string like you are expecting. You can see this when you get the type:

PS C:\> $office.file.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array

The spaces make the function call be evaluated like a traditional cmd call, with the Arg[] string array.

I personally would read about advanced Parameters and add named parameters which would make it easier to make sure everything gets logged in a consistent way.

Sign up to request clarification or add additional context in comments.

2 Comments

Ahh, so stupid.. lol This works but it's printing tons of dupes. I am guessing it has to be placed outside of the foreach loop?
@cynicalswan77 that's probably because you keep adding to $found_paths ($found_paths += ,$full_install_path;) and then iterating over them in the same loop - so if you've discovered 15 unintall keys, then you end up processing the first one 15 times, the second one 14 times, etc....

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.