Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to start PowerShell in WiX with proper access to Windows Registry?

Update

Interesting, if I run 32bit powershell to run the script, it gives me the same error. It looks like the 32bit powershell has no access to the 64 bit registry tree? I tried using WixQuietExec64 but it gave the same error. I also tried providing the full path of the powershell (C:\Windows\system32\WindowsPowerShell\v1.0\powershell.exe) to ensure the installer to launch the 64bit version, but that STILL gave the same error... It looks like this might be caused by the MSI installer itself being 32bit??

MSI (s) (4C:C0) [14:25:49:955]: Hello, I'm your 32bit Elevated Non-remapped custom action server.

Original post

I have the following test.ps1 script:

$exchangeroot = "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ExchangeServer\"
$allexchanges = Get-ChildItem -Path Registry::$exchangeroot -Name | Where-Object { $_ -match "^V.." }
$sorted = $allexchanges | Sort-Object -descending
If ($sorted.Count -gt 1) { $latest = $sorted[0] } Else { $latest = $sorted }
$setup = $exchangeroot + $latest + "\Setup"
$properties = Get-ItemProperty -Path Registry::$setup
$properties

Running the script in a normal PowerShell windows yields the following output:

PS C:\Program Files (x86)\TrustValidator Exchange Server Plugin> .\test.ps1

Required machine-level settings.          : 1
Services                                  : C:\Program Files\Microsoft\Exchange Server\V15
NewestBuild                               : 10845
CurrentBuild                              : 710737954
Information Store Service                 : 1
Messaging and Collaboration Event Logging : 1
MsiInstallPath                            : C:\Program Files\Microsoft\Exchange Server\V15\
...

So it works. Now launching PowerShell from WiX installer and executing the script, it doesn't generate the same result:

WixQuietExec:  Get-ItemProperty : Cannot find path 
WixQuietExec:  'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ExchangeServer\v15\Setup' because it 
WixQuietExec:  does not exist.
WixQuietExec:  At C:\Program Files (x86)\TrustValidator Exchange Server Plugin\test.ps1:10 
WixQuietExec:  char:16
WixQuietExec:  +     $properties = Get-ItemProperty -Path Registry::$setup
WixQuietExec:  +                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
WixQuietExec:      + CategoryInfo          : ObjectNotFound: (HKEY_LOCAL_MACH...erver\v15\Set 
WixQuietExec:     up:String) , ItemNotFoundException
WixQuietExec:      + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetIt 
WixQuietExec:     emPropertyCommand

Now if we observe the error message, it is as though it has access of the tree up until HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ExchangeServer\, because my script would search and list all the versions, so v15 has to be accessible up to that point, however when it tries to go deeper to get the ItemProperty, it can't.

This lead me to believe that perhaps I'm missing something when launching my PowerShell from WiX installer...?

This is what's in my wxs file:

<SetProperty Id="InstallPlugin"
     Before ="InstallPlugin"
     Sequence="execute"
     Value ="&quot;powershell.exe&quot; -Command &quot;cd '[INSTALLFOLDER]'; &amp; '[#TestPS1]' ; exit $$($Error.Count)&quot;" />
<CustomAction Id="InstallPlugin" BinaryKey="WixCA" DllEntry="WixQuietExec" Execute="deferred" Return="ignore" Impersonate="no" />

Below are a list of items that I've already tried or double checked:

  • I've tried different combinations of -NoProfile, -ExecutionPolicy ByPass, -Version 2.0 and still no good.
  • I'm already running the installer as InstallPrivileges="elevated"
  • I'm already running the CustomAction as Execute="deferred" and Impersonate="no"
  • I've tried with AdminImage="yes"
  • I've tried setting <Property Id="MSIUSEREALADMINDETECTION" Value="1" />

Any other clue would be appreciated. :(

like image 560
codenamezero Avatar asked Jul 25 '17 21:07

codenamezero


1 Answers

Oh... my... god...

Ok I finally got it working. There were actually several problems and the solutions for these problems were actually in bits and pieces of information that I gather from across multiple SO questions.

To recap, here is what I was trying to do:

  1. Launch a powershell from WiX to run my install script.
  2. My script search Windows Registry (requires 64bit) for installed Exchange Server's location
  3. My script loads the Exchange Management Shell (EMS) script (requires 64bit AND proper user) from the install location
  4. Under the EMS session, my script run a brunch of other scripts to register an Exchange plugin

Problem 1)

No matter what I did, the WiX installer always launches my powershell in 32bit, this is regardless of setting Platform="x64", Win64="yes", and even WixQuietExec64. I even built the installer in Visual Studio as x64 and everything else as x64.

The solution is to directly reference the sysnative powershell, it has to be sysnative in the SetProperty.

C:\Windows\sysnative\WindowsPowerShell\v1.0\powershell.exe

I actually did tried this before, and thought it wasn't working, but the root cause was being masked by Problem 2 below.

Problem 2)

Everywhere I read, they said you need to run with Execute="deferred" Impersonate="No". I believe this would indeed work for the most cases if you are not doing anything funky. However, I had to Impersonate. I discovered that the WiX installer would run your CA as elevated with user NT Authority/System. This screwed me over because the Exchange Management Shell script I was trying to source would basically use your credential and try to establish a session with the Exchange Server... and of course you can't connect as NT Authority/System!

The solution is to use Impersonate="yes" so that the WiX installer would run your CA as elevated AND the user you are currently logged in. I always had the impression that you must use Impersonate="no" when using Execute="deferred"... but you don't.

I gave up troubleshoot this for a few days and then went back to it and got it working. The 2 most helpful commands that helped me figured this out were actually:

  • whoami
  • Get-ChildItem env: (to check the PROCESSOR_ARCHITECTURE)
like image 100
codenamezero Avatar answered Nov 15 '22 04:11

codenamezero