powershell

Executing custom commands in MSIX context

Sometimes, for troubleshooting it may be necessary to invoke commands in the context of MSIX, so that all virtualized file and registry resources are available. There are three main use cases for it:

  1. Testing out whether the files and registry entries are visible inside the virtual package in the correct place as defined in the AppxManifest.xml.
  2. Testing out whether Modification Package correctly merges its VFS and virtual registry with the base package.
  3. Executing your app from the MSIX package with custom executables and/or parameters which are not necessarily exposed as entry points.

There exists a really useful PowerShell cmdlet which does the heavy lifting, the only thing the user has to do is to supply the right parameters. Its signature (from MSDN):

Invoke-CommandInDesktopPackage
      [-PackageFamilyName] <String>
      [-AppId] <String>
      [-Command] <String>
      [[-Args] <String>]
      [-PreventBreakaway]

Both PackageFamilyName and AppId are required, as well as the command to be executed. You can get the two values from another cmdlet Get-AppxPackage.

The command that is started in the “bubble” can be pretty much anything (it is validated before running), but some typical examples are:

  • cmd.exe
  • powershell.exe
  • regedit.exe
  • Executables being part of the package (indirectly)

For example, let’s execute a PowerShell session in MSIX container to verify the virtualized file structure.

Continue reading →
Posted by Marcin Otorowski in MSIX, PowerShell, 0 comments

Displaying installed MSI products with a PowerShell module

Based on my previous post, I created a small project on my github and adjusted existing codebase to provide a simplistic PowerShell module. The code has been reorganized into proper units with exported functions. Here is a sample usage:

$Header = @"
&amp;lt;style&amp;gt;
TABLE {border: 1px solid gray collapse; }
TH { border: 1px solid gray; padding: 6px 4px; background-color: #eaeaea; }
TD { border: 1px solid gray; padding: 4px; }
&amp;lt;/style&amp;gt;
"@
Import-Module MsiClient
Get-MsiClientPackage | where { $_.Publisher -contains 'Microsoft Corporation' } | sort-object -Property ProductName | ConvertTo-Html -Property ProductCode,PackageName,ProductName,VersionString,Language,Publisher -Head $Header | Out-File c:\temp\test.html

The above snippet produces a HTML based report, showing all Microsoft products available on the current system.

There are still lots of TODOs, which I am going to cover soon, for example:

  • More methods supported (install, uninstall, repair etc.)
  • Better exception handling
  • Support for -WhatIf and -Confirm switches

In any case, my design goal is to keep the syntax similar to functions available in the AppVClient module, so that ideally for basic scenarios they have a 1-1 mapping in the MSI counterpart.

Link to my guthub (the project is licensed under MIT):
https://github.com/marcinotorowski/PowerShellMsiClient

Posted by Marcin Otorowski in Programming, 0 comments

Enumerating installed MSI products with PowerShell and msi.dll

If you were ever wondering how to properly read the list of installed MSI software, then two popular choices are available:

  • Querying uninstall registry keys (HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall), filtering out-non MSI entries and outputting the rest
  • Using Win32_Product from WMI

They both have their pros and cons. Querying registry is straightforward on its own, but requires awkward manipulations and accessing the data which is actually backing the Add/Remove Applet, not necessarily the Windows Installer API which uses its own complex registration. Additionally it may not work correctly with different installation context (user/machine) and you may have to query two places to get both x86 and x64 installations on a x64 system.

On the other hand, while WMI query is also pretty straightforward (see https://msdn.microsoft.com/en-us/library/aa394378(v=VS.85).aspx?f=255&MSPPError=-2147217396), it has a really big drawback. Running it is painfully slow, because Windows Installer checks integrity of each entry and triggers appropriate action (for example repair) if necessary.

So to have a solution which is both fast, reliable and without any side-effects, you may go for a third solution which is more complex, but once setup can be reused not only for querying but for a whole management of MSI-based installations. And so this blog today will be about P/invoking native msi.dll to get results returned by the true Windows Installer API.

This post may be too technical if you have never programmed in C/C++ or C#. If you just want the results without understanding how to implement them on your own, scroll to the bottom, the full content of the PowerShell script is there.
Continue reading →

Posted by Marcin Otorowski, 2 comments