1

The issue has already been discussed here, but did not end up with any clear answer, so it is raised again.

I am trying to extract the contents of an .msi file as follows:

function script:Export-MsiContents
{
[CmdletBinding()]
param
(
    [Parameter(Mandatory = $true, Position = 0)]
    [ValidateNotNullOrEmpty()]
    [ValidateScript({Test-Path $_})]
    [ValidateScript({$_.EndsWith(".msi")})]
    [String] $MsiPath,

    [Parameter(Mandatory=$false, Position = 1)]
    [String] $TargetDirectory
)

if(-not($TargetDirectory))
{
    $currentDir = [System.IO.Path]::GetDirectoryName($MsiPath)
    Write-Warning "A target directory is not specified. The contents of the MSI will be extracted to the location, $currentDir\Temp"

    $TargetDirectory = Join-Path $currentDir "Temp"
}

$MsiPath = Resolve-Path $MsiPath

Write-Verbose "Extracting the contents of $MsiPath to $TargetDirectory"
Start-Process "MSIEXEC" -ArgumentList "/a $MsiPath /qn TARGETDIR=$TargetDirectory" -Wait -NoNewWindow
}

Once called I get the window pop up . Please take a look at the attached screenshotenter image description here

And there is no extraction of the .msi file.

Theo
  • 57,719
  • 8
  • 24
  • 41
sajis997
  • 1,089
  • 1
  • 15
  • 29
  • Can you show us exactly how you are calling this function? The title says you want to extract to _the provided path_, but the function does not test if that given path exists, it merely checks if the parameter `$TargetDirectory` is given or not, which IMO is bad coding.. – Theo Feb 16 '20 at 14:45
  • Export-MsiContents -MsiPath $msiPath and here I am not providing the target directory which means that this directory will be created if the target directory is not provided. – sajis997 Feb 16 '20 at 14:49
  • Is `$msiPath` an absolute path you are providing? The function only resolves this AFTER it tries to get the directory path from it. – Theo Feb 16 '20 at 15:00
  • Without knowing what will be extracted, you may run into a 'Path too long' issue here. What happens if you try to extract to some other short path like `C:\Test`. Also, access to the C-drive may be restricted. You could test with a target location in your userprofile `Join-Path -Path $env:USERPROFILE -ChildPath 'Temp'` – Theo Feb 16 '20 at 15:16
  • Also note that the function validates the $MsiPath using `$_.EndsWith(".msi")`. This is no good, because that validates case-sensitive and should be `[ValidateScript({$_ -match '\.msi$'})]`. If you also change the `Test-Path` validation used into `[ValidateScript({Test-Path -LiteralPath $_ -PathType Leaf})]`, there is no question the path needs to be absolute. The line `$MsiPath = Resolve-Path $MsiPath` can then be removed. The function should also create the target path if it does not exist. In other words, without altering that function, you should be aware of its weaknesses. – Theo Feb 16 '20 at 15:51

1 Answers1

1

1. Escaping: The escape character in PowerShell is the grave-accent: ` (ASCII: 96, Unicode: U+0060 - I think). Grave accent use in programming. Try to escape as follows:

Start-Process "MSIEXEC" -ArgumentList "/a `"C:\my setup.msi`" /qn TARGETDIR=`"C:\Extract here`"" -Wait -NoNewWindow

2. "Stop Parsing": PSv3+ offers --%, the stop-parsing symbol (more from ss64.com). It passes the rest of the command line as-is to the external utility, save for potential expansion of %...%-style environment variables:

# Everything after --% is passed as-is.
msiexec --% /a "C:\my setup.msi" /qn TARGETDIR="C:\Extract here"

I am not a Powershell expert. The above based on:


Other Links:

Stein Åsmul
  • 39,960
  • 25
  • 91
  • 164
  • 1
    I tested it, the second option worked as it is shown above (for me), but there were a lot of quirks indeed when I tried variations. [See the link above (repeated here)](https://stackoverflow.com/questions/18923315/using-in-powershell). – Stein Åsmul Feb 17 '20 at 17:06