1+ [CmdletBinding ()]
2+ param ([Parameter (Mandatory = $true )]
3+ [string ]$buildNumber )
4+
5+ # Ensure the error action preference is set to the default for PowerShell3, 'Stop'
6+ $ErrorActionPreference = ' Stop'
7+
8+ # Constants
9+ $WindowsSDKOptions = @ (" OptionId.UWPCpp" )
10+ $WindowsSDKRegPath = " HKLM:\Software\Microsoft\Windows Kits\Installed Roots"
11+ $WindowsSDKRegRootKey = " KitsRoot10"
12+ $WindowsSDKVersion = " 10.0.$buildNumber .0"
13+ $WindowsSDKInstalledRegPath = " $WindowsSDKRegPath \$WindowsSDKVersion \Installed Options"
14+ $StrongNameRegPath = " HKLM:\SOFTWARE\Microsoft\StrongName\Verification"
15+ $PublicKeyTokens = @ (" 31bf3856ad364e35" )
16+
17+ function Download-File
18+ {
19+ param ([string ] $outDir ,
20+ [string ] $downloadUrl ,
21+ [string ] $downloadName )
22+
23+ $downloadPath = Join-Path $outDir " $downloadName .download"
24+ $downloadDest = Join-Path $outDir $downloadName
25+ $downloadDestTemp = Join-Path $outDir " $downloadName .tmp"
26+
27+ Write-Host - NoNewline " Downloading $downloadName ..."
28+
29+ try
30+ {
31+ $webclient = new-object System.Net.WebClient
32+ $webclient.DownloadFile ($downloadUrl , $downloadPath )
33+ }
34+ catch [System.Net.WebException ]
35+ {
36+ Write-Host
37+ Write-Warning " Failed to fetch updated file from $downloadUrl "
38+ if (! (Test-Path $downloadDest ))
39+ {
40+ throw " $downloadName was not found at $downloadDest "
41+ }
42+ else
43+ {
44+ Write-Warning " $downloadName may be out of date"
45+ }
46+ }
47+
48+ Unblock-File $downloadPath
49+
50+ $downloadDestTemp = $downloadPath ;
51+
52+ # Delete and rename to final dest
53+ if (Test-Path - PathType Container $downloadDest )
54+ {
55+ [System.IO.Directory ]::Delete($downloadDest , $true )
56+ }
57+
58+ Move-Item - Force $downloadDestTemp $downloadDest
59+ Write-Host " Done"
60+
61+ return $downloadDest
62+ }
63+
64+ function Get-ISODriveLetter
65+ {
66+ param ([string ] $isoPath )
67+
68+ $diskImage = Get-DiskImage - ImagePath $isoPath
69+ if ($diskImage )
70+ {
71+ $volume = Get-Volume - DiskImage $diskImage
72+
73+ if ($volume )
74+ {
75+ $driveLetter = $volume.DriveLetter
76+ if ($driveLetter )
77+ {
78+ $driveLetter += " :"
79+ return $driveLetter
80+ }
81+ }
82+ }
83+
84+ return $null
85+ }
86+
87+ function Mount-ISO
88+ {
89+ param ([string ] $isoPath )
90+
91+ # Check if image is already mounted
92+ $isoDrive = Get-ISODriveLetter $isoPath
93+
94+ if (! $isoDrive )
95+ {
96+ Mount-DiskImage - ImagePath $isoPath - StorageType ISO | Out-Null
97+ }
98+
99+ $isoDrive = Get-ISODriveLetter $isoPath
100+ Write-Verbose " $isoPath mounted to ${isoDrive} :"
101+ }
102+
103+ function Dismount-ISO
104+ {
105+ param ([string ] $isoPath )
106+
107+ $isoDrive = (Get-DiskImage - ImagePath $isoPath | Get-Volume ).DriveLetter
108+
109+ if ($isoDrive )
110+ {
111+ Write-Verbose " $isoPath dismounted"
112+ Dismount-DiskImage - ImagePath $isoPath | Out-Null
113+ }
114+ }
115+
116+ function Disable-StrongName
117+ {
118+ param ([string ] $publicKeyToken = " *" )
119+
120+ reg ADD " HKLM\SOFTWARE\Microsoft\StrongName\Verification\*,$publicKeyToken " / f | Out-Null
121+ if ($env: PROCESSOR_ARCHITECTURE -eq " AMD64" )
122+ {
123+ reg ADD " HKLM\SOFTWARE\Wow6432Node\Microsoft\StrongName\Verification\*,$publicKeyToken " / f | Out-Null
124+ }
125+ }
126+
127+ function Test-Admin
128+ {
129+ $identity = [Security.Principal.WindowsIdentity ]::GetCurrent()
130+ $principal = New-Object Security.Principal.WindowsPrincipal $identity
131+ $principal.IsInRole ([Security.Principal.WindowsBuiltInRole ]::Administrator)
132+ }
133+
134+ function Test-RegistryPathAndValue
135+ {
136+ param (
137+ [parameter (Mandatory = $true )]
138+ [ValidateNotNullOrEmpty ()]
139+ [string ] $path ,
140+ [parameter (Mandatory = $true )]
141+ [ValidateNotNullOrEmpty ()]
142+ [string ] $value )
143+
144+ try
145+ {
146+ if (Test-Path $path )
147+ {
148+ Get-ItemProperty - Path $path | Select-Object - ExpandProperty $value - ErrorAction Stop | Out-Null
149+ return $true
150+ }
151+ }
152+ catch
153+ {
154+ }
155+
156+ return $false
157+ }
158+
159+ function Test-InstallWindowsSDK
160+ {
161+ $retval = $true
162+
163+ if (Test-RegistryPathAndValue - Path $WindowsSDKRegPath - Value $WindowsSDKRegRootKey )
164+ {
165+ # A Windows SDK is installed
166+ # Is an SDK of our version installed with the options we need?
167+ if (Test-RegistryPathAndValue - Path $WindowsSDKInstalledRegPath - Value " $WindowsSDKOptions " )
168+ {
169+ # It appears we have what we need. Double check the disk
170+ $sdkRoot = Get-ItemProperty - Path $WindowsSDKRegPath | Select-Object - ExpandProperty $WindowsSDKRegRootKey
171+ if ($sdkRoot )
172+ {
173+ if (Test-Path $sdkRoot )
174+ {
175+ $refPath = Join-Path $sdkRoot " References\$WindowsSDKVersion "
176+ if (Test-Path $refPath )
177+ {
178+ $umdPath = Join-Path $sdkRoot " UnionMetadata\$WindowsSDKVersion "
179+ if (Test-Path $umdPath )
180+ {
181+ # Pretty sure we have what we need
182+ $retval = $false
183+ }
184+ }
185+ }
186+ }
187+ }
188+ }
189+
190+ return $retval
191+ }
192+
193+ function Test-InstallStrongNameHijack
194+ {
195+ foreach ($publicKeyToken in $PublicKeyTokens )
196+ {
197+ $key = " $StrongNameRegPath \*,$publicKeyToken "
198+ if (! (Test-Path $key ))
199+ {
200+ return $true
201+ }
202+ }
203+
204+ return $false
205+ }
206+
207+ Write-Host - NoNewline " Checking for installed Windows SDK $WindowsSDKVersion ..."
208+ $InstallWindowsSDK = Test-InstallWindowsSDK
209+ if ($InstallWindowsSDK )
210+ {
211+ Write-Host " Installation required"
212+ }
213+ else
214+ {
215+ Write-Host " INSTALLED"
216+ }
217+
218+ $StrongNameHijack = Test-InstallStrongNameHijack
219+ Write-Host - NoNewline " Checking if StrongName bypass required..."
220+
221+ if ($StrongNameHijack )
222+ {
223+ Write-Host " REQUIRED"
224+ }
225+ else
226+ {
227+ Write-Host " Done"
228+ }
229+
230+ if ($StrongNameHijack -or $InstallWindowsSDK )
231+ {
232+ if (! (Test-Admin ))
233+ {
234+ Write-Host
235+ throw " ERROR: Elevation required"
236+ }
237+ }
238+
239+ if ($InstallWindowsSDK )
240+ {
241+ # Static(ish) link for Windows SDK
242+ # Note: there is a delay from Windows SDK announcements to availability via the static link
243+ $uri = " https://go.microsoft.com/fwlink/?prd=11966&pver=1.0&plcid=0x409&clcid=0x409&ar=Flight&sar=Sdsurl&o1=$buildNumber "
244+
245+ if ($buildNumber -eq 18362 )
246+ {
247+ # Workaround for removed SDK
248+ $uri = " https://go.microsoft.com/fwlink/?linkid=2083448" ;
249+ }
250+
251+ if ($buildNumber -eq 19041 )
252+ {
253+ # Workaround for missing SDK
254+ $uri = " https://go.microsoft.com/fwlink/?linkid=2120735" ;
255+ }
256+
257+ if ($env: TEMP -eq $null )
258+ {
259+ $env: TEMP = Join-Path $env: SystemDrive ' temp'
260+ }
261+
262+ $winsdkTempDir = Join-Path $env: TEMP " WindowsSDK"
263+
264+ if (! [System.IO.Directory ]::Exists($winsdkTempDir ))
265+ {
266+ [void ][System.IO.Directory ]::CreateDirectory($winsdkTempDir )
267+ }
268+
269+ $file = " winsdk_$buildNumber .iso"
270+
271+ Write-Verbose " Getting WinSDK from $uri "
272+ $downloadFile = Download- File $winsdkTempDir $uri $file
273+
274+ # TODO Check if zip, exe, iso, etc.
275+ try
276+ {
277+ Write-Host - NoNewline " Mounting ISO $file ..."
278+ Mount-ISO $downloadFile
279+ Write-Host " Done"
280+
281+ $isoDrive = Get-ISODriveLetter $downloadFile
282+
283+ if (Test-Path $isoDrive )
284+ {
285+ Write-Host - NoNewLine " Installing WinSDK..."
286+
287+ $setupPath = Join-Path " $isoDrive " " WinSDKSetup.exe"
288+ Start-Process - Wait $setupPath " /features $WindowsSDKOptions /q"
289+ Write-Host " Done"
290+ }
291+ else
292+ {
293+ throw " Could not find mounted ISO at ${isoDrive} "
294+ }
295+ }
296+ finally
297+ {
298+ Write-Host - NoNewline " Dismounting ISO $file ..."
299+ # Dismount-ISO $downloadFile
300+ Write-Host " Done"
301+ }
302+ }
303+
304+ if ($StrongNameHijack )
305+ {
306+ Write-Host - NoNewline " Disabling StrongName for Windows SDK..."
307+
308+ foreach ($key in $PublicKeyTokens )
309+ {
310+ Disable-StrongName $key
311+ }
312+
313+ Write-Host " Done"
314+ }
0 commit comments