Updating nuget version in tens of projects
The continuous integration build failed with an error. The error read “Could not load file or assembly ‘Moq, Version=4.13.0.0, Culture=neutral, PublicKeyToken=69f491c39445e920’ or one of its dependencies.”. Reason? Someone checked in a project with a higher Moq version in a large solution with hundreds of projects. Now, someone had to go thru all of the projects to understand where was the wrong version added.
Because this is a repeating problem, instead of going thru all the projects manually, I created a tiny script to correct the version and check out the files (I don’t want to check-in things without personally looking at them).
Here is the script for your reference. I hope this helps you. You can also re-purpose this script to upgrade nuget version in a lot of projects.
$projectpath = "C:\Projects\myfancyprojectname"
$TfExePath = "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer\tf.exe"
if(! (Test-Path $TfExePath)) # if path not found then try to see if local dev path works
{
$TfExePath = "C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer\tf.exe" # uncomment this to try this on dev env.
}
if(! (Test-Path $TfExePath)) # if path not found then try to see if local dev path works
{
$TfExePath = "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer\tf.exe" # uncomment this to try this on dev env.
}
if(! (Test-Path $TfExePath))
{
throw "TF path is not valid ($TfExePath)"
}
Set-Alias -Name tf -Value $TfExePath
function CheckoutFiles
{
param(
[string] $TfExePath,
[string] $FilesToBeChckedOut
)
process
{
Write-Host ""
Write-Host " More than 10 files have beeb batched for check-out. Hence, checking them out now."
Write-Host " Checking out files $FilesToBeChckedOut"
#start of checkout
# if a user has checked out the file on other machine then we can continue to ignore those errors.
# Only non 0 return value should be considered as an error.
$pinfo = New-Object System.Diagnostics.ProcessStartInfo
$pinfo.FileName = $TfExePath
$pinfo.RedirectStandardError = $true
$pinfo.RedirectStandardOutput = $true
$pinfo.UseShellExecute = $false
#$pinfo.WorkingDirectory = $SourceDirectory
$CheckoutCommand = " checkout $FilesToBeChckedOut"
$pinfo.Arguments = $CheckoutCommand
$p = New-Object System.Diagnostics.Process
$p.StartInfo = $pinfo
$p.Start() | Out-Null
$p.WaitForExit()
$stdout = $p.StandardOutput.ReadToEnd()
$stderr = $p.StandardError.ReadToEnd()
$ExitCode = $p.ExitCode
if($ExitCode -ne 0)
{
Write-Host "exit code: $ExitCode"
Write-Host "CheckoutCommand is $CheckoutCommand"
Write-Host "stdout: $stdout"
Write-Host "stderr: $stderr"
throw "An error occurred while checking out. Please look at stdout and stderr."
}
}
}
$MoqVersion = "4.16.1"
$IncorrectMoqVersionOutput =""
$FilesToBeChckedOut = ""
$Count = 0
foreach($proj in $PackagesConfigList)
{
$XMLfileName = $proj.FullName
# using this strange way of loading XML document to preserve white space (more info here: https://stackoverflow.com/questions/8160613/powershell-saving-xml-and-preserving-format )
$ProjFileXML = New-Object xml
$ProjFileXML.PreserveWhitespace = $true
# Load with preserve setting
$ProjFileXML.Load($XMLfileName)
$Nodes =$ProjFileXML.GetElementsByTagName("PackageReference")
$ProjectUpdated = $false;
if($Nodes)
{
foreach($node in $Nodes)
{
if( $node.Include -eq "Moq" -and $node.Version -ne $MoqVersion)
{
$ProjectUpdated = $true
if($IncorrectMoqVersionOutput -eq "" )
{
$IncorrectMoqVersionOutput += " $XMLfileName (" + $node.Version + ")";
}
else
{
$IncorrectMoqVersionOutput += "
$XMLfileName (" + $node.Version + ")";
}
$node.Version = $MoqVersion;
}
if($ProjectUpdated -eq $true)
{
Set-ItemProperty $proj -name IsReadOnly -value $false # remove read only attribute
$ProjFileXML.Save($XMLfileName)
$Count = $Count +1
if($Count -gt 10 )
{
CheckoutFiles $TfExePath $FilesToBeChckedOut
#end of checkout
$FilesToBeChckedOut = ""
$Count = 0
}
Write-Host ""
Write-Host " Will check out file $proj"
$FilesToBeChckedOut = $FilesToBeChckedOut + " ""$proj"" "
Write-Host ""
}
}
}
$ProjFileXML = $null
}
if($FilesToBeChckedOut -ne "")
{
CheckoutFiles $TfExePath $FilesToBeChckedOut
$FilesToBeChckedOut = ""
$Count = 0
}
if($IncorrectMoqVersionOutput -ne "" )
{
Write-Output "Incorrect MOQ version found in some projects (expected is $MoqVersion): "
Write-Output $IncorrectMoqVersionOutput
}
Happy coding!