Installing all .msi files within a folder

2019-05-20 00:21发布

问题:

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?

回答1:

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 v6.1.0)


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      


回答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"
}