0

I've got a simple problem. I've only found two ways that will actually run my msi file, and neither of them will work.

Pay close attention to my usage of ' and ".

Simply put, I want a way to do this:

$Basics = "$PSScriptRoot"
Start-Process msiexec.exe -Wait -ArgumentList "/i $Basics\Installer_.64 bit_.msi /passive /norestart"

However the string being given to -ArgumentList is invalid, and I'm not sure why. I've done a lot of attempts as you can see below, in trying to get this right.
$Basics is just a copy of $PSScriptRoot for now, but I want it has a separate variable in case if I change it in the future.
/passive /norestart is removed for testing purposes.

Note: This is not the actual installer file's name. This is made just to contain all the weird characters (.,_,) that some of the installers I'm trying to run with this, have. Basically a worst case scenario.

Also, sorry in advance that this is a lot to read, I'm not really sure how to format it better. Go ahead and edit if you know a better way.

Attempts:

Not in order, organized by what kind of attempt it was. My first attempt was "/i '$Basics\Installer_.64 bit_.msi'"

Start-Process msiexec.exe -Wait -ArgumentList "/i $Basics\Installer_.64 bit_.msi"

^ Result: Opens generic Windows Installer help window.

Start-Process msiexec.exe -Wait -ArgumentList "/i '$Basics\Installer_.64 bit_.msi'"

^ Result: Opens generic Windows Installer help window.

Start-Process msiexec.exe -Wait -ArgumentList '/i $Basics\Installer_.64 bit_.msi'

^ Result: "This installation package could not be opened. Verify that the package exists and that you can access it, or contact the application vendor to verify that this is a valid Windows Installer package."

Start-Process msiexec.exe -Wait -ArgumentList '/i "$Basics\Installer_.64 bit_.msi"'

^ Result: "This installation package could not be opened. Verify that the package exists and that you can access it, or contact the application vendor to verify that this is a valid Windows Installer package."

Start-Process msiexec.exe -Wait -ArgumentList "/i Installer_.64 bit_.msi"

^ Result: Works; However, this isn't acceptable as I need to be able to put a variable in the directory.

Start-Process msiexec.exe -Wait -ArgumentList '/i "C:\Users\Administrator\Downloads\flashdrive\redist\Install (x86 Office)\Installer_.64 bit_.msi"'

^ Result: Works; However, this isn't acceptable as I need to be able to put a variable in the directory.

Start-Process msiexec.exe -Wait -ArgumentList "/i C:\Users\Administrator\Downloads\flashdrive\redist\Install (x86 Office)\Installer_.64 bit_.msi"

^ Result: Opens generic Windows Installer help window.

Start-Process msiexec.exe -Wait -ArgumentList "/i .\Installer_.64 bit_.msi"

^ Result: "This installation package could not be opened. Verify that the package exists and that you can access it, or contact the application vendor to verify that this is a valid Windows Installer package."

udlp
  • 127
  • 1
  • 7
  • I would suggest using the Windows Installer PowerShell Module that Stein pointed out below. If that's not possible then write-host the string you're using for ArgumentList and you'll see when your vars are not being interpolated. – Doc Sep 28 '19 at 20:36

2 Answers2

0

Powershell treats everything between single quotes as a literal string. Your variables won't get expanded if you use single quotes. So you need to use double quotes if you want to use variable expansion.
The problem with your example with the double quotes is that powershell interprets all the characters until a whitespace as a single variable. And since "$Basics\Installer_.64 bit_.msi" is not the variable that you want, this doesn't work either. You can put your variable name between curly brackets ({}) to delimit it from the rest of the string. So an example that would work is this:

Start-Process msiexec.exe -Wait -ArgumentList "/i ${Basics}\Installer_.64 bit_.msi"

Another option would be to use the format string operator:

'/i {0}\Installer_.64 bit_.msi' -f $Basics

This operator gives you a lot more freedom and you can do some very advanced string formatting with it. Another added benefit is that this way you can use single quotes. This makes sure that no expansion will take place. For example, in case your msi files have dollar signs in the name, the first example will not work, since powershell will try to expand the variables.

0

PowerShell Module: There is now a Windows Installer PowerShell Module courtesy of Heath Stewart of Microsoft. I haven't tested it much, just a smoke test. See below for another alternative using MSI API directly via COM.


Re-Quoting: I saw someone write a lot about PowerShell and escape sequences. It looks pretty complicated: Setting Public Property Values on the Command Line - there were other posts too.

Alternatives?: Perhaps you can go via MSI API COM calls? I have this old answer on various ways to uninstall MSI packages. I'll see if I can dig up a PowerShell example, in the meantime here is a VBScript version using MSI API COM calls:

Set installer = CreateObject("WindowsInstaller.Installer")
installer.InstallProduct "C:\Product.msi", "REBOOT=ReallySuppress"

There is also WMI - which I never use. See section 10 here.


Link:

Stein Åsmul
  • 34,628
  • 23
  • 78
  • 140