As an aside:
If you're using Windows PowerShell and only need to remove MSI-installed applications, a much more convenient solution is to use Uninstall-Package
, as js2010 points out; e.g.,
Get-Package -ProviderName msi *App* | Uninstall-Package
If you're looking to execute UninstallString
/ QuietUninstallString
command lines extracted from the registry as-is, see this answer.
Your question can be reduced to how to extract a {...}
substring from a larger string, which you can do with PowerShell's regex-based -replace
operator:
# -> '{629388F2-A011-4F5C-A6BF-98A80A25317C}'
'MsiExec.exe /I{629388F2-A011-4F5C-A6BF-98A80A25317C}' -replace '^.+({.+?}).*$', '$1'
Note: {
and }
are situationally regex metacharacters, but are treated literally here, because they aren't part of valid quantifier subexpressions (such as o{2,3}
). You may choose to always escape them as \{
and \}
, to be safe.
Alternatively, you could use the equally regex-based -split
operator, and split the string into tokens by {
and }
, including those separators, with the help of look-around assertions, and extracting the 2nd token ([1]
):
# -> '{629388F2-A011-4F5C-A6BF-98A80A25317C}'
('MsiExec.exe /I{629388F2-A011-4F5C-A6BF-98A80A25317C}' -split '(?={)|(?<=})')[1]
See this regex101.com page for a detailed explanation of the regex and the ability to experiment with it. Note that the look-around assertions only match character positions, not actual characters, which is what enables including {
and }
in the tokens returned by -split
.
Or the .Split()
method of the .NET [string]
type, passing an array of (literal) characters to split by, using an expandable (double-quoted) string ("..."
) with the $(...)
, the subexpression operator to surround the extracted token in {
and }
again.
# -> '{629388F2-A011-4F5C-A6BF-98A80A25317C}'
"{$( ('MsiExec.exe /I{629388F2-A011-4F5C-A6BF-98A80A25317C}').Split([char[]] '{}')[1] )}"
Speaking of expandable strings:
The '$uninstallString'
in your doRemoveMSI
call,
doRemoveMSI -msi "msiexec.exe" -arguments '/x', '$uninstallString', '/quiet', 'REBOOT=R', '/L*V "C:\msilog.log"'
won't work as intended, because NO expansion (string interpolation) happens inside '...'
, i.e. verbatim (single-quoted) strings.
While "$uninstallString"
avoids that problem, you do not even need the "..."
(except in cases where you need explicit to-string conversion), and can simply pass $uninstallString
as-is.
As for how you're partitioning the arguments you're passing to doRemoveMSI
(consider renaming the function to conform to PowerShell's naming conventions, e.g., Uninstall-Msi
):
- As discussed in this answer to your previous question, given your desire to pass argument pairs via a single string with embedded double-quoting - e.g.
'/L*V "C:\msilog.log"'
- it is ultimately simpler to pass a single string overall, i.e. to declare your -arguments
parameter as type [string]
, and then invoke the function as follows:
# Note the use of a *single* "..." string,
# with *embeded* " chars. escaped as `"
doRemoveMSI -msi msiexec.exe -arguments "/x $uninstallString /quiet REBOOT=R /L*V `"C:\msilog.log`""