Reputation: 69
I'm trying to mass install a bunch of .msi's one after the other. But when I run my powershell script the msiexec /? comes up as if my arguments are wrong. What am I missing here?
$Path = Get-ChildItem -Path *my path goes here* -Recurse -Filter *.MSI
foreach ( $Installer in ( Get-ChildItem -Path $Path.DirectoryName -Filter *.MSI ) ) {
Start-Process -Wait -FilePath C:\windows\system32\msiexec.exe -ArgumentList "/i '$Installer.FullName'"
}
Upvotes: 2
Views: 613
Reputation: 27566
In Powershell 5.1, with msi's, you can also do:
install-package $installer.fullname
Upvotes: 0
Reputation: 5252
The syntax "/i '$Installer.FullName'"
is not correct. It should be "/i", $Installer.FullName
in your code.
Surrounding a PowerShell object in double quotes triggers string expansion. When that occurs, only the variable itself is substituted with its value and then the remaining characters not part of the name are treated as a string. You can see when you run the following snippet that the object performed a ToString() and then just added the string .FullName to it.
foreach ( $Installer in ( Get-ChildItem -Path $Path.DirectoryName -Filter *.MSI ) ) {
"/i $Installer.FullName"
}
If you must have double quotes, then a way around it is to use the sub-expression operator $(). Anything inside is treated as an expression by the parser. So the more verbose "/i '$($Installer.FullName)'"
would technically work.
The complete code should be:
$Path = Get-ChildItem -Path *my path goes here* -Recurse -Filter *.MSI
foreach ( $Installer in ( Get-ChildItem -Path $Path.DirectoryName -Filter *.MSI ) ) {
Start-Process -Wait -FilePath C:\windows\system32\msiexec.exe -ArgumentList "/i", $Installer.FullName
}
Upvotes: 3
Reputation: 439912
Olaf's answer contains good pointers, but let me try to boil it down conceptually:
There are two unrelated problems with your attempt:
Inside expandable strings ("..."
) only simple variable references ($Installer
) can be used as-is; expressions ($Installer.FullName
) require $()
, the subexpression operator: $($Installer.FullName)
- see this answer for an overview of expandable strings (string interpolation) in PowerShell.
Since you're passing the arguments for msiexec
via -ArgumentList
as a single string, only embedded double quoting, "..."
, is supported, not '...'
(single quoting).
Therefore, use the following (for brevity, the -FilePath
and -ArgumentList
arguments are passed positionally to Start-Process
):
Get-ChildItem $Path.DirectoryName -Recurse -Filter *.MSI | ForEach-Object {
Start-Process -Wait C:\windows\system32\msiexec.exe "/i `"$($_.FullName)`""
}
Note:
The -ArgumentList
parameter is array-typed ([string[]]
). Ideally, you'd therefore pass the arguments individually, as the elements of an array: '/i', $_.FullName
, which wouldn't require you to think about embedded quoting inside a single string.
Unfortunately, Start-Process
doesn't handle such individually passed arguments properly if they contain embedded spaces, so the robust solution is to use a single -ArgumentList
argument comprising all arguments, with embedded double-quoting, as necessary, as shown above.
See this answer for a more detailed discussion.
Upvotes: 3