Installing commands into the NuGet PowerShell profile

3 minute read

If you're one of those guys who prefers to automate things than repeating them manually, you've probably spent some time already in the NuGet Package Manager Console. Many packages are providing way more than just a set of binaries. Some of them are really full installations of functionality and help you automate actions within Visual Studio. A good example is the well-known MvcScaffolding package, which is providing tons of extra functionality in the PowerShell-enabled console.

Building a tools package?

There are also the so called tools packages, which only contain a tools folder inside the package and thus only ship such functionality, without installing anything into the target project or solution. If you want to build such package, it might be interesting to know that NuGet supports its own PowerShell profile.

An example tools package I recently created is the NuSpec package (Install-Package NuSpec). It provides a bunch of PowerShell command-lets that help you automate the creation of .nuspec files within Visual Studio.

Installing this package does not change anything to your solution or project. It's only when you start using the command-lets that you modify these files. So why would we need to install this package for every single solution over and over again? Let's install it into the NuGet PowerShell profile and have it sit there, readily available for whenever you need it, no matter which solution you open.

Installing the tools once and for all (*)

(*) until the next update or something :)

The NuGet PowerShell profile is not always available on the consuming computer. So as a package producer, it is our job to make detect it and make sure it's there for us in order to import our own modules into it. For this, we can conveniently make use of the $profile variable which contains the path to the NuGet_profile.ps1, which should be available in %USERPROFILE%\My Documents\WindowsPowerShell.

The following piece of PowerShell code creates the file if it doesn't exist, and imports a module with a configurable name:

# Set the module name
$moduleName = "MyModule"

# Check if the NuGet_profile.ps1 exists and register the module
if(!(Test-Path $profile)){
  mkdir -force (Split-Path $profile)
  New-Item $profile -Type file -Value "Import-Module $moduleName"
  Add-Content -Path $profile -Value "`r`nImport-Module $moduleName"

Put this in the init.ps1 file of your NuGet package and copy all the required files from your tools folder to the *%USERPROFILE%\My Documents\WindowsPowerShell\Modules\MyModule* directory.

A simple convention here can save you some code: the name of the module is also the name of the directory to copy to in the Modules folder. The following example illustrates what I mean:

  • NuGet package ID: MyModule
  • PowerShell module and manifest inside tools folder: MyModule.psd1 and MyModule.psm1
  • Target copy location for required files: %USERPROFILE%\My Documents\WindowsPowerShell\Modules*MyModule*\

Below, you find some key excerpts from the init.ps1 I use for the NuSpec package:

param($installPath, $toolsPath, $package, $project)

# Configure
$moduleName = "NuSpec"

# Derived variables
$psdFileName = "$moduleName.psd1"
$psmFileName = "$moduleName.psm1"
$psd = (Join-Path $toolsPath $psdFileName)
$psm = (Join-Path $toolsPath $psmFileName)

# Check if the NuGet_profile.ps1 exists and register the NuSpec.psd1 module
if(!(Test-Path $profile)){
  mkdir -force (Split-Path $profile)
  New-Item $profile -Type file -Value "Import-Module $moduleName"
  Add-Content -Path $profile -Value "`r`nImport-Module $moduleName"

# Copy the files to the module in the profile directory
$profileDirectory = Split-Path $profile -parent
$profileModulesDirectory = (Join-Path $profileDirectory "Modules")
$moduleDir = (Join-Path $profileModulesDirectory $moduleName)
if(!(Test-Path $moduleDir)){
  mkdir -force $moduleDir
copy $psd (Join-Path $moduleDir $psdFileName)
copy $psm (Join-Path $moduleDir $psmFileName)

# Copy additional files
copy "$toolsPath\*.xsd" $moduleDir
copy "$toolsPath\*.xml" $moduleDir

# Reload NuGet PowerShell profile
. $profile

Note: This approach doesn't support the classical Update-Package or Uninstall-Package commands obviously. You'll have to detect these upgrades/migrations when installing your package, which, again, is nothing more than some file or file contents manipulation using PowerShell.

Leave a Comment