Application deployment optimalization

Sometimes as a consultant you enter an environment where there is some room for improvements. In this case a customer used a task sequence for creating a new Citrix golden image took many hours to complete. There was lot of room for improvements so this process would require less time.

One of the conclusions from the performed research was that there was an application base of about 40 applications installed locally, so it looked like a typical golden image that you can find at many companies.

In order to reduce the deployment time, a great starting point is to narrow down into some logging, especially for those application installations. During this search there where a few installations found of about 1,5GB – 2,5GB that had a few thousands of small files.

During the monitoring of the task sequence you can see that each file will be copied separately and when the copying process is finished it will set the security descriptors for each and every single file.
If there is any chance you can real-time monitor the SMSTSLOG during the task sequence process, do yourself a favor and check it out sometime, it can really give you some useful information.
When you do a search on the internet “copy small files over network” you will get a dozen of results about slow copy’s and possible ways to increase the speed in regular situations.

The Meaning of the security descriptors:
“A security descriptor contains the security information associated with a securable object. A security descriptor consists of a SECURITY_DESCRIPTOR structure and its associated security information.”
Source: Microsoft

The addressed issue
Copying large amounts of small files over the network is slow, and setting security descriptors take a general amount of time.

The Solution
Put those huge amounts of files into a single file, and done…. Right? YES!
Personally I like using the freeware tool PSAppDeployToolkit for deploying all applications, because you have an easy, standardized method, extensive logging and the possibility to make your own extensions.

The solution itself is really simple, but requires a few extra steps when creating a deployment and running the installation. The steps explained:

  1. Create (and mount) a VHDX file
  2. Put all installation files into the VHDX File,
  3. Unmount the VHDX File
  4. Before the application installation (on the client) mount the VHDX File
  5. Run the installation from within the VHDX File
  6. Unmount the VHDX File

Creating the VHDX File
All these actions will be performed on an admin / packaging machine

Copy your installation files to the Virtual disk, access the virtual disk using the mountpoint (c:\Appdisk).
Detatch the appdisk via Diskmgmt

 

The PSAppDeployToolkit needs 2 extensions.
The first extension is to mount the virtual disk to a mountpoint, the second extension is to unmount the virtual disk and remove the mountpoint.
Download and extract the PSAppDeployToolkit.
Inside the folder “Toolkit\AppDeployToolkit” there is a file called AppDeployToolkitExtensions.ps1
This is the file that needs the modifications listed below

Add the following below the rule # <Your custom functions go here>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
function Mount-VHDToFolder
{
[CmdLetBinding()]
param
(
[Parameter(Mandatory=$true)][String]$Image,
[Parameter(Mandatory=$true)][String]$MountFolder
)
process
{
Try {
# Gets a mounted disk image
$mountedDisk = Mount-DiskImage -ImagePath $Image -NoDriveLetter -PassThru -ErrorAction Stop | Get-DiskImage
Write-Log -Message "Mounted VHDX Image $Image" -Source "Mount-VHDToFolder" -LogType "CMTrace"
}
catch
{
Write-Log -Message "ERROR: Failed to mount VHDX Image $Image" -Source "Mount-VHDToFolder" -LogType "CMTrace"
return
}
# Get all of the partitions
$partitions = Get-Partition -DiskNumber $mountedDisk.Number
foreach($partition in $partitions)
{
if ($partition.PartitionNumber -eq "1")
{
# Clean up this folder if it exists
if(Test-Path $MountFolder)
{
remove-item $MountFolder -Recurse -Confirm:$false -Force
Write-Log -Message "MountFolder Cleaned $MountFolder" -Source "Mount-VHDToFolder" -LogType "CMTrace"
}
mkdir $MountFolder | Out-Null
try
{
# Add the access path for the disk
Add-PartitionAccessPath -InputObject $partition -AccessPath $MountFolder -ErrorAction Stop
Write-Log -Message "AccessPath $MountFolder is Active" -Source "Mount-VHDToFolder" -LogType "CMTrace"
}
catch
{
Write-Log -Message "ERROR: Could not add access path $MountFolder" -Source "Mount-VHDToFolder" -LogType "CMTrace"
}
}
}
}
}

This function will mount the virtual drive defined in the object $Image containing the application installation to a mountpoint defined in the object $Mountpoint. The Image needs to be mounted before the application installation, so call this function in the pre-installation part.Add the following below the rule # <Your custom functions go here>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function Dismount-VHDFromFolder
{
[CmdLetBinding()]
param
(
[Parameter(Mandatory=$true)][String]$Image,
[Parameter(Mandatory=$true)][String]$MountFolder
)
process
{
Write-Log -Message "Dismount-Diskimage: Unmounting VHDX: $Image" -Source "Dismount-VHDFromFolder" -LogType "CMTrace"
Dismount-diskimage $Image | Out-Null
# Clean up this folder if it exists
if(Test-Path $MountFolder)
{
remove-item $MountFolder -Recurse -Confirm:$false -Force
Write-Log -Message "Dismount-Diskimage: Removed $MountFolder" -Source "Dismount-VHDFromFolder" -LogType "CMTrace"
}
}
}

This function will dismount the VHDX in the variable $Image and remove the folder that is defined in the variable $Mountfolder. This function needs to be called after the installation has completed; in the installation script in the Post-Install part.

These are the only functions needed as extension for PSAppDeployToolkit. Those functions can also be a start for any custom scripting.

Creating the installation script
All information about how to use PsAppdeploytoolkit can be found in the documentation that is provided inside the download.

modify the installallation script (Deploy-Application.ps1).
In the post-install part, mount the VHDX file to a mountfolder using the following command:

1
Mount-VHDToFolder "$DirFiles\AppDisk.vhdx" "$DirFiles\VHDAppDisk"



This will mount the VHDX file to the following mountpoint: “c:\Windows\CCMCache\xyz\Files\VHDAppDisk”
Where xyz is the random folder name in the CCMCache Directory.

In the installation part run the installation:

1
Execute-Process -Path "$DirFiles\VHDAppDisk\Setup.exe"

Because we use the path $DirFiles\VHDAppDisk the installation will run directly from the mountpoint.

When the installation has finished, the VHDX file needs to be dismounted and a cleanup needs to be performed. To do this, the Dismount-VHDFromFolder function needs to be called:

1
Dismount-VHDFromFolder "$DirFiles\AppDisk.vhdx" "$DirFiles\VHDAppDisk"

The deploy-application.ps1 will look similar to this

Conclusion
To compare the original installation and the VHDX Based installation, an installation containing 48.500 files and 1750 folders will be used as an example. The total amount of data is 900MB (average file size is 20KB).

The PsAppDeployToolkit / VHDX based installation just contains 12 files, 3 folders and has a size of 1.15GB, meaning just a little overhead in size caused by the VHDX.
The deployment of the original installation took over 60 minutes when deploying the application using an task sequence, using the VHDX based installation in the same task sequence only 10 minutes.

Although it will take some time to build your installation this will save you lots of time during the installation process. Another advantage is that the ConfigMgr logging Is smaller since it will not record huge amounts of actions. This could make troubleshooting much more easy.

Leave a Reply

Your email address will not be published. Required fields are marked *