NuGet: refreshing NuGet packages in packages folder during development

I'm working on NuGet packages in a Visual Studio project. On build I publish a new version of my nuget package to a repository (a directory on my system).

I don't increment version numbers after each change, i only want to do that on published versions of my packages.

To test out changes to the package in my solution where I already reference the package I want to pull in a new version of the package that has the same version number.

install-package does not have a -force option to force uninstall/install of the package with an unchanged version number.

The script below solves this issue. Save as Update-NuGetPackages.ps1 and put next to NuGet.exe.

Test out first on a copy of your Packages folder (copy to PackagesTest), so you have all parameters right. The script deletes all existing packages.

UPDATE: Updated the code so if package is deleted and install fails, an empty folder with the package name is created so after fixing the error the script can be called again to retry the update.

Update-NuGetPackages.ps1
  1. <#
  2.     .SYNOPSIS
  3.         Update NuGet packages with same version of package.
  4.  
  5.     .DESCRIPTION
  6.         During the development cycle version numbers of packages are often not changed,
  7.         but the contents of the package itself is updates. Update-NuGetPackages.ps1
  8.         refreshes all packages in a given packages directory.
  9.         
  10.         By default don't specify any sources, so NuGet.exe (version 1.3 and later) will use
  11.         the NuGet.config which is stored in the AppData folder and shared between Visual Studio
  12.         and NuGet.exe
  13.  
  14.     .PARAMETER  PackagesPath
  15.         Path to folder containing the packages to refresh.
  16.  
  17.     .PARAMETER  PackagesSource
  18.         Source where packages should be installed from. Post version 1.3 of NuGet.exe
  19.         supports specifying multiple sources separated by ';'.
  20.         Source paths may not contain PSDrives in its path, like product:\mypath.
  21.         
  22.     .PARAMETER  IncludeDefaultSource
  23.         Switch parameter to specify that the default NuGet packages source
  24.         https://go.microsoft.com/fwlink/?LinkID=206669 should be included as a
  25.         packages source. Don't specify this switch and dont use the PackagesSource
  26.         parameter to let NuGet.exe use the sources specified in the NuGet.config.
  27.         This functionality is available after release version 1.3 of NuGet.exe.
  28.         If used together with the PackagesSource parameter a version newer than
  29.         version 1.3 of NuGet.exe is required.
  30.  
  31.     .EXAMPLE
  32.         PS C:\> Update-NuGetPackages.ps1 -PackagesSource c:\MyProduct\Packages
  33.         Deleting package 'EntityFramework' version '4.1.10331.0'
  34.         Deleting package 'MacawSolutionsFactory-Core' version '1.0.0'
  35.         Deleting package 'MacawSolutionsFactory-Spf2010' version '1.0.0'
  36.         Deleting package 'T4Scaffolding' version '1.0.0'
  37.         Reinstalling package 'EntityFramework' version '4.1.10331.0'
  38.         Successfully installed 'EntityFramework 4.1.10331.0'.
  39.         Reinstalling package 'MacawSolutionsFactory-Core' version '1.0.0'
  40.         'T4Scaffolding (= 1.0.0)' not installed. Attempting to retrieve dependency from source...
  41.         Done.
  42.         Dependency 'EntityFramework (= 4.1.10311.0)' already installed.
  43.         Successfully installed 'T4Scaffolding 1.0.0'.
  44.         Successfully installed 'MacawSolutionsFactory-Core 1.0.0'.
  45.         Reinstalling package 'MacawSolutionsFactory-Spf2010' version '1.0.0'
  46.         Dependency 'T4Scaffolding (= 1.0.0)' already installed.
  47.         Dependency 'EntityFramework (= 4.1.10311.0)' already installed.
  48.         Successfully installed 'MacawSolutionsFactory-Spf2010 1.0.0'.
  49.         Reinstalling package 'T4Scaffolding' version '1.0.0'
  50.         Dependency 'EntityFramework (= 4.1.10311.0)' already installed.
  51.         'T4Scaffolding 1.0.0' already installed.
  52.         Done.
  53.  
  54.     .EXAMPLE
  55.         PS C:\> Update-NuGetPackages.ps1 -PackagesSource c:\MyProduct\Packages `
  56.                 -PackagesSource "c:\Dist\Feed1;c:\Dist\Feed2" -IncludeDefaultSource
  57.         :
  58.         
  59.     .INPUTS
  60.         System.String,System.String,System.Boolean
  61.  
  62.     .NOTES
  63.         This script must be located next to NuGet.exe.
  64.         
  65.         This script requires a version later than the release version 1.3 of NuGet.exe
  66.         when specifying multiple sources on the commandline and/or using the IncludeDefaultSource
  67.         parameter.
  68.         
  69.         Version: 1.0
  70.         Author: Serge van den Oever (http://weblogs.asp.net/soever)
  71. #>
  72. [CmdletBinding()]
  73. param
  74. (
  75.     [Parameter(Position=0, Mandatory=$true)][String]$PackagesPath,
  76.     [Parameter(Position=1, Mandatory=$false)][String]$PackagesSource = '',
  77.     [Parameter(Position=2, Mandatory=$false)][Switch]$IncludeDefaultSource = $false
  78. )
  79.  
  80. $nugetDefaultSource= 'https://go.microsoft.com/fwlink/?LinkID=206669'
  81.  
  82. function Get-ScriptDirectory
  83. {
  84. $Invocation = (Get-Variable MyInvocation -Scope 1).Value
  85. Split-Path $Invocation.MyCommand.Path
  86. }
  87.  
  88. $nugetExe = Join-Path -Path (Get-ScriptDirectory) -ChildPath 'nuget.exe'
  89. if (-not (Test-Path -Path $nugetExe)) { throw ("Expected NuGet.exe at path '{0}'" -f $nugetExe) }
  90.  
  91. if (-not (Test-Path -Path $PackagesPath)) { throw ("Specified PackagesPath '{0}' does not exist" -f $PackagesPath) }
  92. $PackagesPath = Convert-Path -Path $PackagesPath
  93.  
  94. # Collect packages
  95. $packageFolders = Get-ChildItem -Path $PackagesPath | Where-Object {$_.psIsContainer -eq $true}
  96.  
  97. $packages = @()
  98. if ($packageFolders -ne $null) {
  99.     $packageFolders | ForEach-Object {
  100.         $packageFolder = Convert-Path -Path $_.FullName # Handle case where PSDrive is specified
  101.         $packageFolderName = Split-Path -Path $packageFolder -Leaf
  102.         $parts = $packageFolderName.split('.')
  103.         $packageName = $parts[0]
  104.         $packageVersion = $parts[1..$($parts.length-1)] -join '.'
  105.         $packages += @{
  106.             Name = $packageName;
  107.             Version = $packageVersion;
  108.             Folder = $packageFolder;
  109.         }
  110.     }
  111. }
  112.  
  113. # Delete all package folders
  114. $packages | ForEach-Object {
  115.     Write-Host ("Deleting package '{0}' version '{1}'" -f $_.Name, $_.Version)
  116.     Remove-Item -Recurse -Force -Path $_.Folder -ErrorAction SilentlyContinue
  117.     if (Test-Path -Path $_.Folder) { Write-Warning ("Can't remove folder '{0}'. Make sure it is not locked." -f $_.Folder) }
  118. }
  119.  
  120. # Reinstall all packages
  121. $packages | ForEach-Object {
  122.     Write-Host ("Reinstalling package '{0}' version '{1}'" -f $_.Name, $_.Version)
  123.     if ($IncludeDefaultSource) {
  124.         $source = $nugetDefaultSource
  125.     } else {
  126.         $source = ''
  127.     }
  128.     if ($PackagesSource -ne '') {
  129.         if ($source -ne '') { $source += ';' }
  130.         $source += (Convert-Path -Path $PackagesSource)
  131.     }
  132.     
  133.     if ($source -ne '') {
  134.         & $nugetExe install $_.Name -Version $_.Version -Source $source -OutputDirectory $PackagesPath
  135.     } else {
  136.         & $nugetExe install $_.Name -Version $_.Version -OutputDirectory $PackagesPath
  137.     }
  138.  
  139.     if (-not (Test-Path -Path $_.Folder)) {
  140.         New-Item -Path $_.Folder -Type Directory -Force
  141.         Write-Warning ("Failed to reinstall package '{0}' version '{1}'. Created dummy directory '$($_.Folder). Fix error and try again." -f $_.Name, $_.Version)
  142.     }
  143. }
  144.  
  145. # Call Init.ps1 on all packages
  146. $packages | ForEach-Object {
  147.     $initScript = Join-Path -Path $_.Folder -ChildPath 'Tools\Init.ps1'
  148.     if (Test-Path -Path $initScript)
  149.     {
  150.         $rootPath = $_.Folder
  151.         $toolsPath = Join-Path -Path $_.Folder -ChildPath 'Tools'
  152.         $package = Get-Package -Filter $_.Name
  153.         $project = $null
  154.         
  155.         & $initScript -rootPath $rootPath -toolsPath $toolsPath -package $package -project $project
  156.     }
  157. }
  158.  
  159. Write-Host 'Done.'

No Comments