msiexec.exe is unusual in that, while it has an extensive CLI (command-line interface) with many supported parameters, it is a GUI-subsystem executable that runs independently of any calling console.
PowerShell runs GUI-subsystem executables asynchronously when you invoke them directly; that is, unlike with console-subsystem executables, it doesn't wait for the executable to terminate before continuing.
While Start-Process -Wait is indeed the typical way to invoke a GUI-subsystem executable synchronously, there is also a convenient shortcut:
If you pipe to Write-Output:[1]
PowerShell will wait for the executable('s process) to terminate, even if it is a GUI-subsystem application.
- Note: If you know that the GUI application produces no stdout output - and not doing so is typical - you can also pipe to
Wait-Process for better conceptual clarity (again, see footnote [1]).
Additionally, the automatic $LASTEXITCODE variable will properly reflect the process' exit code (which not many GUI-subsystem executables meaningfully set, but misexec.exe does), allowing you to infer success (exit code 0) vs. failure (any nonzero exit code), by convention.
Therefore, you can use the following:
# Note the `| Write-Output` at the end of the line, which ensures *synchronous* execution.
msiexec.exe /i "C:\MagtekCC\Files\Java\jre1.8.0_144.msi" /QN TRANSFORMS="jre1.8.0_144.mst" /L*V "C:\Temp\msilog.log" | Write-Output
$exitCode = $LASTEXITCODE
Write-Host -ForegroundColor Cyan "Installation finished with exit code $exitCode."
The above is the more convenient alternative to the following Start-Process -Wait solution, which also uses -PassThru to pass an object representing the launched process through, so that its .ExitCode property can be checked:
$exitCode = (Start-Process -Wait -NoNewWindow -PassThru msiexec.exe @'
/i "C:\MagtekCC\Files\Java\jre1.8.0_144.msi" /QN TRANSFORMS="jre1.8.0_144.mst" /L*V "C:\Temp\msilog.log"
'@).ExitCode
Write-Host -ForegroundColor Cyan "Installation finished with exit code $exitCode."
Note: -NoNewWindow typically makes no difference in this case, but would allow console output from those rare GUI applications that explicitly attach to the caller's console (see footnote [1]) to surface in the current console - albeit without the ability to capture it.
Note how all arguments for misexex.exe are passed as a single string to Start-Process (using a here-string for readability here), which positionally binds to the -ArgumentList parameter.
While the -ArgumentList parameter technically accepts an array of arguments - i.e. allows you to pass arguments individually - a long-standing bugs makes that unadvisable - see this answer.
As for what you tried:
Your Start-Process -Wait call failed, because you ended up passing more than two positional arguments:
start-process msiexec.exe "/i ..." -wait /QN ...
msiexec.exe positionally binds to the -FilePath parameter.
- Only the
"/i ..." argument positionally argument binds to the -ArgumentList parameter.
- Since no other
Start-Process parameters support positional binding, Start-Process doesn't know what to do with /QN (and all subsequent positional (unnamed) arguments), which is what the error message in your question indicates.
Note: If you did want to pass parameters individually - which is best avoided, as stated above - you'd have to pass them as an array, separated by ,
(Start-Process -Wait msiexec.exe '/i', ...)
[1] Note that any command in a subsequent pipeline segment works to ensure synchronous execution, because PowerShell always has to wait for the preceding segment's command to terminate, so as to ensure that all input has been received; While it ultimately doesn't matter what command you choose, Write-Output, which in this case will typically be a no-op, has the advantage of passing stdout output through so that it becomes visible / can be captured, if the GUI application at hand produces such output, which is rare (append 2>&1 to the GUI-application call to also capture stderr output). As Bender the Greatest points out, some GUI applications do so in order to produce debugging output, by explicitly attaching to the caller's console.