3

I'm trying to write a powershell script that I am kicking off from a python script that will allow me to go through and install each .msi file that is contained within a certain folder.

This is what I have so far:

$msiFiles = Get-ChildItem -Path "***PATH TO FOLDER***" -Recurse -Include *.msi

foreach($file in $msiFiles)
{

    Write-Host "$file is being installed"
    Start-Process "msiexec.exe" -arg "/I $file /qb ADDLOCAL=ALL ALLUSERS=TRUE" -Wait
    Write-Host "$file is finished being installed"


}

I want to install these msi's in silent mode so I don't see or need ant GUI interaction. When it goes to install the msi's I get a pop up from the installer with all the possible commands to use to install stuff, but it doesn't actually install it.

What is the proper command to install these in silent mode?

Zack Sloan
  • 101
  • 3
  • 13
  • Do this `Write-Host "/I $file /qb ADDLOCAL=ALL ALLUSERS=TRUE"` In your code right before the Start-Process line. Please put one sample of the output from that in your question. – EBGreen Jul 20 '18 at 18:54
  • Have you tried searching for it? Not very hard to find i think. Have a look at this answer from Polynomial https://stackoverflow.com/questions/8560166/silent-installation-of-a-msi-package – Theo Jul 20 '18 at 18:55
  • @Theo Yes I have tried using the steps in that link already but am still getting the same pop up I have described above – Zack Sloan Jul 20 '18 at 19:07
  • 1
    Note that [ALLUSERS](https://learn.microsoft.com/en-us/windows/desktop/msi/allusers) should be set to 0 or 1 (or 2 with MSIINSTALLPERUSER), not TRUE. Also ADDLOCAL=ALL may or may not be good, depending on the features within a given .msi file. (Neither of these are syntactically invalid, though, so aren't causing the problem you're asking about.) – Michael Urman Jul 21 '18 at 00:48
  • Not an answer as such, but I just want to inform you of this: [**The Windows Installer PowerShell Module**](https://github.com/heaths/psmsi) on github.com - it provides **MSI cmdlets** (scroll down for description, use **releases tab for download** or read instructions). I haven't really tested it much, but it is from [Heath Stewart](https://blogs.msdn.microsoft.com/heaths/) - Microsoft Senior Software Engineer (github). – Stein Åsmul Jul 22 '18 at 00:01

2 Answers2

3

Generally, if invoking msiexec does nothing but show a dialog describing the command-line syntax, the implication is that there's a syntax problem.

The likely source of the syntax error is that the "..." string you're using as the -arg argument (full name: -Args or -ArgumentList) has $file embedded in it without embedded quoting:

That is, if the value of $file has embedded spaces, for instance (e.g., C:\Msi Installers\foo.msi), the resulting msiexec command will be syntactically invalid, because the space-separated tokens of the path are each considered an argument.

Bill_Stewart's helpful answer shows you how to use embedded quoting around $file to solve this problem, by enclosing it in `" (` is PowerShell's escape character).

If you were to stick with passing the arguments as a single string, you would use:

Start-Process msiexec.exe -Args "/I `"$file`" /qb ADDLOCAL=ALL ALLUSERS=TRUE" -Wait

Arguably, however, it's cleaner not to pass a single, command-line-like string as the only argument, but to instead pass the arguments as elements of an array, which is indeed what -ArgumentList / -Args was designed to accept (its parameter type is [string[]]):

Start-Process msiexec.exe -Args /I, `"$file`", /qb, ADDLOCAL=ALL, ALLUSERS=TRUE -Wait

Note how $file is still passed with embedded quoting, which is unfortunately required due to a bug in Start-Process (as of Windows PowerShell v5.1 / PowerShell Core v7.1); it looks like this bug will not get fixed, however, but the linked GitHub report suggests introducing a new
-ArgumentArray parameter with the correct behavior.


You may alternatively build up the array of arguments in advance; note how this is done in expression mode (with syntax more like regular programming languages), so the array elements all require quoting; also note how I'm using single quotes to define literal arguments:

# Create the array of arguments to pass to msiexec
$msiArgs = 
  '/I',
  "`"$file`"",      #`# !! enclosing in `"...`" is needed due to the bug mentioned above
  '/qb',
  '/ADDLOCAL=ALL',
  'ALLUSERS=TRUE'

Start-Process msiexec.exe -Args $msiArgs -Wait      
mklement0
  • 382,024
  • 64
  • 607
  • 775
2

Try it this way:

$msiFiles = Get-ChildItem -Path "***PATH TO FOLDER***" -Recurse -Include *.msi

foreach ( $file in $msiFiles ) {
  $fullPath = $file.FullName
  Write-Host "'$fullPath' is being installed"
  Start-Process -FilePath msiexec.exe -ArgumentList "/I `"$fullPath`"","/qb","ADDLOCAL=ALL","ALLUSERS=TRUE" -Wait
  Write-Host "$fullPath is finished being installed"
}
Bill_Stewart
  • 22,916
  • 4
  • 51
  • 62