Microsoft has changed the way they ship Cumulative Updates. Now we download the whole DVD image along with the application changes.
This post is intended as additional information for New Developer Tools for Dynamics NAV 2013 R2 and Install Client and Server update with PowerShell posts.
To update a code that is built on a RTM version or an older CU version I use the Merge-NAVToNewCU script package. I create a temporary folder and export three set of objects. One file for the original unchanged objects (38457Objects.txt), One file for the new CU objects (40938Objects.txt) and finally the modified version (38457customizedObjects.txt). When I export I normally skip the MenuSuites that I don’t have permission to import.
Microsoft sometimes adds new fields to tables, fields that are outside of my permission to insert. Therefore, when I have completed the compare and have my new customized object (40938customizedObjects.txt) I start by importing the object fob file directly from the Microsoft Dynamics NAV Application folder found in the CU package. I accept the default action, replace most objects and merge tables. This will create all the new fields needed by the update. After I am able to import the new customized objects text file and compile.
[code lang=”powershell”]$rootFolderName = $PSScriptRoot
$oldVersion = ‘38457’
$newVersion = ‘40938’
Import-Module "${env:ProgramFiles(x86)}\Microsoft Dynamics NAV\80\RoleTailored Client\Microsoft.Dynamics.Nav.Model.Tools.psd1" -force
Import-Module (Join-Path $rootFolderName ‘Merge-NAVVersionListString script.ps1’) -force
$diffFolderName = (Join-Path $rootFolderName ($oldVersion + ‘to’ + $newVersion + ‘diff’))
$oldObjects = (Join-Path $rootFolderName ($oldVersion + ‘objects.txt’))
$newObjects = (Join-Path $rootFolderName ($newVersion + ‘objects.txt’))
$newFolder = (Join-Path $rootFolderName ($newVersion + ‘update’))
$customObjects = (Join-Path $rootFolderName ($oldVersion + ‘customizedobjects.txt’))
$newCustomizedObjects = (Join-Path $rootFolderName ($newVersion + ‘customizedobjects.txt’))
$newCustomizedFolder = (Join-Path $rootFolderName ($newVersion + ‘customized’))
if (!(Test-Path $diffFolderName))
{
mkdir $diffFolderName
}
if (!(Test-Path $newFolder))
{
mkdir $newFolder
}
if (!(Test-Path $newCustomizedFolder))
{
mkdir $newCustomizedFolder
}
Write-Host "Comparing customized and original…"
Compare-NAVApplicationObject -Original $oldObjects -Modified $customObjects -Delta $diffFolderName | Where-Object CompareResult -eq ‘Identical’ | foreach { Remove-Item (Join-Path $diffFolderName ($_.ObjectType.substring(0,3) + $_.Id + ‘.delta’)) }
Write-Host "Splitting new objects…"
Split-NAVApplicationObjectFile $newObjects $newFolder
Write-Host "Removing unchanged new objects…"
Get-ChildItem -Path $newFolder | foreach { if (!(Test-Path ((Join-Path $diffFolderName $_.BaseName) + ‘.delta’))) { Remove-Item $_.FullName } }
Write-Host "Updating new objects…"
Update-NAVApplicationObject -Target $newFolder -Delta $diffFolderName -Result $newCustomizedFolder -DateTimeProperty FromModified -ModifiedProperty FromModified -VersionListProperty FromModified -DocumentationConflict ModifiedFirst
Write-Host "Updating customized object version list…"
Get-ChildItem -Path (Join-Path $newCustomizedFolder ‘*.txt’)| foreach { if (Test-Path (Join-Path $newFolder $_.Name)) {Set-NAVApplicationObjectProperty -Target $_.FullName -VersionListProperty (Merge-NAVVersionListString -source (Get-NAVApplicationObjectProperty -Source $_.FullName).VersionList -target (Get-NAVApplicationObjectProperty -Source (Join-Path $newFolder $_.Name)).VersionList) }}
Write-Host "Joining customized object to a single file…"
Join-NAVApplicationObjectFile -Source (Join-Path $newCustomizedFolder ‘*.txt’) -Destination $newCustomizedObjects
Write-Host "If you have conflicts then you need to manually fix conflicting code changes"
[/code]
I have also created a set of scripts to update the Binaries. For some time now Microsoft has not shipped the binary upgrade folders with the CU package. Now they deliver the whole DVD, including the new updated Demo Database. The scripts therefore must copy the files from the DVD instead of copying from the binary upgrade folders.
When copying from the DVD we must make sure that we don’t overwrite the configuration files for the server and the web client. This is the server update script. All server on the computer will be stopped, updated and restarted.
[code lang=”powershell”]$NAVDVDFilePath = ‘\\STORAGE\NAV 2015\NAV.8.0.40938.IS.DVD’
$NotToCopy = @(‘Tenants.config’,’CustomSettings.config’)
Write-Verbose "Copying NAV Server Update…"
$ClientKBFolder = Join-Path $NAVDVDFilePath ‘ServiceTier\program files\Microsoft Dynamics NAV\80\Service’
$navInstallationDirectory = Join-Path ${env:ProgramFiles} ‘Microsoft Dynamics NAV\80\Service’
if (Test-Path $navInstallationDirectory)
{
Import-Module (Join-Path $ClientKBFolder ‘Microsoft.Dynamics.Nav.Management.dll’) -DisableNameChecking | Out-Null
$RunningInstances = Get-NAVServerInstance | Where-Object { $_.State -eq "Running" }
Write-Verbose "Stopping Server Instances…"
Get-NAVServerInstance | Where-Object { $_.State -eq "Running" } | Set-NAVServerInstance -Stop
Start-Sleep -s 5
Write-Verbose "Running file copy command…"
Get-ChildItem -Path $ClientKBFolder | % {Copy-Item $_.FullName $navInstallationDirectory -Recurse -Force -Exclude $NotToCopy}
Write-Verbose "Done updating files…"
foreach ($RunningInstance in $RunningInstances)
{
$InstanceName = $RunningInstance.ServerInstance.ToString()
Write-Verbose "Starting Server Instance $InstanceName"
Get-NAVServerInstance -ServerInstance $InstanceName | Set-NAVServerInstance -Start
}
}[/code]
This is the web server update script
[code lang=”powershell”]$NAVDVDFilePath = ‘\\STORAGE\NAV 2015\NAV.8.0.40938.IS.DVD’
$NotToCopy = (‘web.config’,’instanceweb.config’,’Header.png’,’About.png’,’Splash.png’)
function Copy-LatestFile
{
[CmdletBinding()]
param (
[parameter(Mandatory=$true)]
[string]$SourceDirectoryPath,
[parameter(Mandatory=$true)]
[string]$DestinationDirectoryPath
)
Write-Verbose "Running file copy command…"
$sourcefiles = Get-ChildItem $SourceDirectoryPath -Recurse
$destfiles = Get-ChildItem $DestinationDirectoryPath -Recurse
foreach ($sourcefile in $sourcefiles)
{
$copyfile = $false
foreach($destfile in $destfiles)
{
if ($destfile.Name -eq $sourcefile.Name)
{
$copyfile = $true
break
}
}
if (!($copyfile) -or ($NotToCopy -match $sourcefile.BaseName))
{
write-verbose "not copying $sourcefile…"
}
else
{
write-verbose "copying $sourcefile…"
Copy-Item $sourcefile.FullName $destfile.FullName -Force
}
}
}
Write-Verbose "Copying Web Client Update…"
$ClientKBFolder = Join-Path $NAVDVDFilePath ‘WebClient\Microsoft Dynamics NAV\80\Web Client’
$navInstallationDirectory = Join-Path ${env:ProgramFiles} ‘Microsoft Dynamics NAV\80\Web Client’
if (Test-Path $navInstallationDirectory)
{
Copy-LatestFile -SourceDirectoryPath $ClientKBFolder -DestinationDirectoryPath $navInstallationDirectory
}
[/code]
And finally the client update script.
[code lang=”powershell”]$NAVDVDFilePath = ‘\\STORAGE\NAV 2015\NAV.8.0.40938.IS.DVD’
$NotToCopy = (‘Header.png’,’About.png’,’Splash.png’)
function Copy-LatestFile
{
[CmdletBinding()]
param (
[parameter(Mandatory=$true)]
[string]$SourceDirectoryPath,
[parameter(Mandatory=$true)]
[string]$DestinationDirectoryPath
)
Write-Verbose "Running file copy command…"
$sourcefiles = Get-ChildItem $SourceDirectoryPath -Recurse -File
$destfiles = Get-ChildItem $DestinationDirectoryPath -Recurse -File
foreach ($sourcefile in $sourcefiles)
{
$copyfile = $false
foreach($destfile in $destfiles)
{
if ($destfile.Name -eq $sourcefile.Name)
{
$copyfile = $true
break
}
}
if (!($copyfile) -or ($NotToCopy -match $sourcefile.BaseName))
{
write-verbose "not copying $sourcefile…"
}
else
{
write-verbose "copying $sourcefile…"
Copy-Item $sourcefile.FullName $destfile.FullName -Force
}
}
}
Write-Verbose "Copying RTC Update…"
$ClientKBFolder = Join-Path $NAVDVDFilePath ‘RoleTailoredClient\program files\Microsoft Dynamics NAV\80\RoleTailored Client’
$navInstallationDirectory = Join-Path ${env:ProgramFiles(x86)} ‘Microsoft Dynamics NAV\80\RoleTailored Client’
if (Test-Path $navInstallationDirectory)
{
Copy-LatestFile -SourceDirectoryPath $ClientKBFolder -DestinationDirectoryPath $navInstallationDirectory
}
Write-Verbose "Copying Office 14 Update…"
$ClientKBFolder = Join-Path $NAVDVDFilePath ‘Outlook\program files\Microsoft Dynamics NAV\80\OutlookAddin’
$navInstallationDirectory = Join-Path ${env:ProgramFiles(x86)} ‘Microsoft Office\Office14’
if (Test-Path $navInstallationDirectory)
{
Copy-LatestFile -SourceDirectoryPath $ClientKBFolder -DestinationDirectoryPath $navInstallationDirectory
}
Write-Verbose "Copying Office 15 Update…"
$ClientKBFolder = Join-Path $NAVDVDFilePath ‘Outlook\program files\Microsoft Dynamics NAV\80\OutlookAddin’
$navInstallationDirectory = Join-Path ${env:ProgramFiles(x86)} ‘Microsoft Office\Office15’
if (Test-Path $navInstallationDirectory)
{
Copy-LatestFile -SourceDirectoryPath $ClientKBFolder -DestinationDirectoryPath $navInstallationDirectory
}
[/code]
The ClickOnce distribution is always based on the client folder and the script in Install Client and Server update with PowerShell can be used for that purpose.
I am using these binary update scripts in the Instance and Tenant Administration tool and I normally maintain the ClickOnce distribution from there.