Auto-install of .Net 3.5 on Windows 2012 R2

The “standard” way of installing .Net 3.5 into a Windows 2012 R2 server, is to mount the install DVD (or ISO image), and use Add Features to install it. Obviously this is a massive pain if you’ve got a lot to do, as you either need to copy 4.5Gb of image around, or use some out-of-band method of mounting the image, neither of which are ideal. The only sane option would be to extract the ISO to a CIFS share, and make that available to all servers, but this wasn’t an option here.

For automation, we would normally use the PowerShell command:

Install-WindowsFeature Net-Framework-Core -source \\image-path\sources\sxs

… so already, it looks like we don’t need all the image to do the install, just the “sources\sxs” directory.

A quick check shows that the “sources\sxs” directory is 289Mb, so much more manageable, but surely we can do better than this, as it includes a lot of other features.

Running a filter with procmon during the feature install allows you to capture all the file accesses to the sources\sxs directory, which can be exported as a CSV file:
"Time of Day","Process Name","PID","Operation","Path","Result","Detail"
"1:59:25.0591131 PM","TiWorker.exe","2896","ReadFile","D:","SUCCESS","Offset: 0, Length: 4,096, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal"
"1:59:25.1140710 PM","TiWorker.exe","2896","ReadFile","D:","SUCCESS","Offset: 4,096, Length: 4,096, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal"
"1:59:25.1183118 PM","TiWorker.exe","2896","ReadFile","D:","SUCCESS","Offset: 8,192, Length: 4,096, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal"
"1:59:25.1197002 PM","TiWorker.exe","2896","CreateFile","D:\sources\sxs","SUCCESS","Desired Access: Read Attributes, Disposition: Open, Options: Open Reparse Point, Attributes: n/a, ShareMode: Read, Write, Delete, AllocationSize: n/a, Impersonating: NT AUTHORITY\SYSTEM, OpenResult: Opened"
"1:59:25.1215631 PM","TiWorker.exe","2896","QueryBasicInformationFile","D:\sources\sxs","SUCCESS","CreationTime: 3/21/2014 2:27:47 PM, LastAccessTime: 3/21/2014 2:27:47 PM, LastWriteTime: 3/21/2014 2:27:47 PM, ChangeTime: 3/21/2014 2:27:47 PM, FileAttributes: RD"
"1:59:25.1215789 PM","TiWorker.exe","2896","CloseFile","D:\sources\sxs","SUCCESS",""
"1:59:30.8039209 PM","TiWorker.exe","2896","ReadFile","D:","SUCCESS","Offset: 0, Length: 4,096, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal"
...etc....

This can then be condensed with (I’m using a *nix command line to do this as it’s more familiar to me):

cat Logfile.CSV | cut -d"," -f5 | cut -d"\\" -f4 | sort -u | grep -v -e "^$" -e "^\""

To give a list of subfolders in the “sources\sxs” directory that are required. These can be used to copy the relevant source files to a zip archive:
cat Logfile.CSV | cut -d"," -f5 | cut -d"\\" -f4 | sort -u | grep -v -e "^$" -e "^\"" | while read folder
do
zip -r net35.zip /Volumes/Win2012R2ISO/sources/sxs/$folder
done

…which generates an (approx) 88Mb zip file, much more suitable for installing via automation.

It’s then a fairly straightforward task to use your automation framework (Chef, Puppet etc) to copy the zip file down to the server, extract and run the powershell command to install.