Search code examples
powershellvisual-studio-2012dsc

Visual Studio 12 VSIXInstaller reports a FileNotFoundException when running in DSC Script


I'm writing a Powershell DSC script so I can easily configure development environments. I'm trying to get Visual Studio 2012 Addons to install without opening the GUI.

I've downloaded the Specflow .vsix file. When I run

 & "C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\VSIXInstaller.exe" /q C:\Users\Public\Downloads\TechTalk.SpecFlow.Vs2010Integration.vsix

on the Powershell command prompt, it works without a hitch. But if I try to do the same thing in a DSC Script resource, I run into problems. Copying and pasting the command above into SetScript results in VSInstaller.exe results in the command never finishing.

I therefore tried the following, based on the Choco Install-VSIX cmdlet:

Script installSpecflowVS {
        SetScript  = {          
            $specUrl  = 'https://visualstudiogallery.msdn.microsoft.com/9915524d-7fb0-43c3-bb3c-a8a14fbd40ee/file/79327/7/TechTalk.SpecFlow.Vs2010Integration.vsix'
            $outfile  = 'C:\Users\Public\DownloadsTechTalk.SpecFlow.Vs2010Integration.vsix'
            wget $specUrl -outfile $outfile 
            $psi = New-Object System.Diagnostics.ProcessStartInfo
            $psi.FileName='C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\VSIXInstaller.exe'
            $psi.Arguments="/q $outfile"
            $s = [System.Diagnostics.Process]::Start($psi)
            $s.WaitForExit()
            return $s.ExitCode
      }
      TestScript = { return $False }
      GetScript  = { return $True }
}

In this case, the command completes, but VSIXInstall.exe throws a FileNotFound error which I can see from the log created in in C:\Windows\Temp\

1/18/2017 10:51:51 AM - Searching for applicable products...
1/18/2017 10:51:51 AM - Found installed product - Microsoft Visual Studio Professional 2012
1/18/2017 10:51:51 AM - System.IO.FileNotFoundException: The system cannot find the file specified. (Exception from HRESULT: 0x80070002)
  at System.Runtime.InteropServices.Marshal.ThrowExceptionForHRInternal(Int32 errorCode, IntPtr errorInfo)
  at System.Runtime.InteropServices.Marshal.ThrowExceptionForHR(Int32 errorCode)
  at Microsoft.VisualStudio.Settings.ExternalSettingsManager.GetScopePaths(String applicationPath, String suffixOrName, String vsVersion, Boolean isLogged, Boolean isForIsolatedApplication)
  at Microsoft.VisualStudio.Settings.ExternalSettingsManager.CreateForApplication(String applicationPath)
 at VSIXInstaller.App.GetExtensionManager(SupportedVSSKU sku)
 at VSIXInstaller.App.GetExtensionManagerForApplicableSKU(SupportedVSSKU supportedSKU, IInstallableExtension installableExtension, List`1 applicableSKUs)
 at VSIXInstaller.App.InitializeInstall()
 at VSIXInstaller.App.OnStartup(StartupEventArgs e)

The file is definitely there; if I supply VSInstaller with something that doesn't exist it gives the following error instead

1/18/2017 10:21:45 AM - VSIXInstaller.InvalidCommandLineException: Path to vsix file 'outfile' is invalid or you don't have required access permissions. Please check the path is valid and you have required access permissions.

The script is running locally on a Windows 7 SP1 virtual machine with Powershell 5. I'm executing it using Powershell ISE with Admin privileges.

There is obviously something different about scripts running via DSC Set-Script. Any ideas how to fix to fix it? Or another way of doing it?


Solution

  • VSIX is per user you need to tell DSC which user to install this as using PSDscRunAsCredential (added in PowerShell 5.0).

    Example, where $credential is the credentials for the user that you want to install the VSIX for.

    Script installSpecflowVS {
            SetScript  = {          
                $specUrl  = 'https://visualstudiogallery.msdn.microsoft.com/9915524d-7fb0-43c3-bb3c-a8a14fbd40ee/file/79327/7/TechTalk.SpecFlow.Vs2010Integration.vsix'
                $outfile  = 'C:\Users\Public\DownloadsTechTalk.SpecFlow.Vs2010Integration.vsix'
                wget $specUrl -outfile $outfile 
                $psi = New-Object System.Diagnostics.ProcessStartInfo
                $psi.FileName='C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\VSIXInstaller.exe'
                $psi.Arguments="/q $outfile"
                $s = [System.Diagnostics.Process]::Start($psi)
                $s.WaitForExit()
                return $s.ExitCode
          }
          TestScript = { return $False }
          GetScript  = { return $True }
          PSDscRunAsCredential = $credential
    }
    

    Please also see Securing the MOF File on how to properly encrypt the MOF file so you don't leak your credentials.