0

I'm deep into a rabbit hole of why a simple powershell script (below) works via the ISE, but fails when run via InstallShield's Powershell custom action type.

I'm posting the InstallShield-ready version of the script. Trace-Info can be replaced with Write-Host and Set-Property can be commented out.

try
{
    Import-Module ActiveDirectory


    $all_gmsa_accts = Get-ADServiceAccount -Filter '*'
    $valid_gmsa_accts = @( )

    ForEach ($acct in $all_gmsa_accts) {
        Trace-Info -LogMessage "Checking if account $($acct.Name) can be used on this machine"
        if(Test-ADServiceAccount -Identity $acct.Name -WarningAction silentlyContinue) {
            $valid_gmsa_accts += $acct.Name
        }
    }

    $prop_value = $valid_gmsa_accts -join ','
    $prop_name = "MANAGEDSERVICEACCOUNTS"
    Set-Property -Name $prop_name -Value $prop_value
}
catch {
    Trace-Info -LogMessage "Exception:"
    Trace-Info -LogMessage $_.Exception.Message
}

When I run on either PS command line or PS ISE, I get expected results:

PS D:\ps> .\get-mgmd-test.ps1
Checking if account gmsauser1 can be used on this machine
Checking if account gmsauser2 can be used on this machine
Checking if account cantuseme can be used on this machine
Checking if account tsrcsvcuser1 can be used on this machine
Checking if account tsrcsvcuser2 can be used on this machine
Checking if account tsrcsvcuser3 can be used on this machine
Checking if account tsrcsvcuser4 can be used on this machine
Checking if account tsrcsvcuser5 can be used on this machine

When run from InstallShield, I get the below error messages in the log output.

Action start 11:34:42: GetManagedServiceAccounts.
MSI (c) (64:E8) [11:34:42:266]: Invoking remote custom action. DLL: C:\Users\ADMINI~1\AppData\Local\Temp\MSI9B2D.tmp, Entrypoint: m2
InstallShield: Attempting to load through CLR 4 APIs...
InstallShield: Getting meta host...
InstallShield: Enumerating available runtimes...
InstallShield: Highest available runtime: v4.0.30319
InstallShield: Trying to use highest runtime...
InstallShield: Using highest version runtime...
InstallShield: Loading assembly ClrPsHelper from resource 4097
InstallShield: Calling method with parameters [(System.UInt32)165, (System.String)C:\Users\administrator\AppData\Local\Temp\d397fb4e-db0a-445a-9dc8-7ee4520e6436\getmanagedsvcaccts.ps1]
PowerShell wrapper: Exception:
PowerShell wrapper: Could not load file or assembly 'Microsoft.ActiveDirectory.Management' or one of its dependencies. Invalid pointer (Exception from HRESULT: 0x80004003 (E_POINTER))
Action ended 11:34:44: GetManagedServiceAccounts. Return value 1.
  • So, does anyone have insight into the specific mechanics of the InstallShield powershell CA type shim(s)?
  • Why would it be trying to load Microsoft.ActiveDirectory.Management when the ISE does not?
  • Is there some way I can get the PS command line to function in the same profile as msiexec?
Damon D
  • 186
  • 6
  • It seems that InstallShield opens the 32 bit version of Powershell, according to the accepted answer here: https://stackoverflow.com/questions/48095563/installshield-checking-for-key-in-registry-failed-with-powershell?rq=1. If the dll is only available for 64 bit that might cause the problem. – TToni Feb 28 '18 at 18:51
  • I created a new IS2016 basic MSI project, created two Powershell custom actions: one that has "Run 64-bit PowerShell script" to yes, and one set to no. Both give same result. Will also try running a custom action that calls powershell.exe directly, but then I lose the ability to set properties. – Damon D Feb 28 '18 at 19:06
  • Are you willing to refactor your design to get out of the rabbit hole? – Christopher Painter Feb 28 '18 at 20:42
  • @ChristopherPainter to an extent, yes. I have to jam these custom actions (which check for valid GMSA accounts, only available via powerhsell) into a dozen+ installs. Only other way I've seen this work is by using process.start via C# and parsing output stream (yuck!). – Damon D Feb 28 '18 at 22:27
  • Take a look at WiXToolSet's DTF C# managed custom actions. You'll find some articles on my blog. Once you got that you can use System.management.automation to establish a powershell pipeline. Assuming you still need powershell... getting to C# might be enough for what you are doing. – Christopher Painter Feb 28 '18 at 22:30
  • @ChristopherPainter I'll have a look, TY. Unfortunately, I do need to get into PS as that's the only way to work with GMSA accounts. BTW: I did implement this solution before with `using (PowerShell psinstance = PowerShell.Create())` and ran into the same issue above. Unclear as to how InstallShield can completely mangle run time behavior of custom actions like this based on build environment differences. – Damon D Feb 28 '18 at 22:44
  • I know I worked out the C# path pretty good to work regardless of bitness and OS version. I was doing some AppV work that *ONLY* had cmdlets... caused me to ask this question almost 5 years ago: https://stackoverflow.com/questions/18876660/interoping-with-powershell-cmdlets – Christopher Painter Feb 28 '18 at 23:48

0 Answers0