3 Helper module to install an archive to a directory
6 Helper module to download and extract an archive to a specified directory
9 Uri of artifact to download
11 .PARAMETER InstallDirectory
12 Directory to extract artifact contents to
15 Force download / extraction if file or contents already exist. Default = False
17 .PARAMETER DownloadRetries
18 Total number of retry attempts. Default = 5
20 .PARAMETER RetryWaitTimeInSeconds
21 Wait time between retry attempts in seconds. Default = 30
24 Returns False if download or extraction fail, True otherwise
26 function DownloadAndExtract {
27 [CmdletBinding(PositionalBinding=$false)]
29 [Parameter(Mandatory=$True)]
31 [Parameter(Mandatory=$True)]
32 [string] $InstallDirectory,
33 [switch] $Force = $False,
34 [int] $DownloadRetries = 5,
35 [int] $RetryWaitTimeInSeconds = 30
37 # Define verbose switch if undefined
38 $Verbose = $VerbosePreference -Eq "Continue"
40 $TempToolPath = CommonLibrary\Get-TempPathFilename -Path $Uri
42 # Download native tool
43 $DownloadStatus = CommonLibrary\Get-File -Uri $Uri `
45 -DownloadRetries $DownloadRetries `
46 -RetryWaitTimeInSeconds $RetryWaitTimeInSeconds `
50 if ($DownloadStatus -Eq $False) {
51 Write-Error "Download failed"
56 $UnzipStatus = CommonLibrary\Expand-Zip -ZipPath $TempToolPath `
57 -OutputDirectory $InstallDirectory `
61 if ($UnzipStatus -Eq $False) {
62 # Retry Download one more time with Force=true
63 $DownloadRetryStatus = CommonLibrary\Get-File -Uri $Uri `
66 -RetryWaitTimeInSeconds $RetryWaitTimeInSeconds `
70 if ($DownloadRetryStatus -Eq $False) {
71 Write-Error "Last attempt of download failed as well"
75 # Retry unzip again one more time with Force=true
76 $UnzipRetryStatus = CommonLibrary\Expand-Zip -ZipPath $TempToolPath `
77 -OutputDirectory $InstallDirectory `
80 if ($UnzipRetryStatus -Eq $False)
82 Write-Error "Last attempt of unzip failed as well"
83 # Clean up partial zips and extracts
84 if (Test-Path $TempToolPath) {
85 Remove-Item $TempToolPath -Force
87 if (Test-Path $InstallDirectory) {
88 Remove-Item $InstallDirectory -Force -Recurse
99 Download a file, retry on failure
102 Download specified file and retry if attempt fails
105 Uri of file to download. If Uri is a local path, the file will be copied instead of downloaded
108 Path to download or copy uri file to
111 Overwrite existing file if present. Default = False
113 .PARAMETER DownloadRetries
114 Total number of retry attempts. Default = 5
116 .PARAMETER RetryWaitTimeInSeconds
117 Wait time between retry attempts in seconds Default = 30
121 [CmdletBinding(PositionalBinding=$false)]
123 [Parameter(Mandatory=$True)]
125 [Parameter(Mandatory=$True)]
127 [int] $DownloadRetries = 5,
128 [int] $RetryWaitTimeInSeconds = 30,
129 [switch] $Force = $False
134 if (Test-Path $Path) {
135 Remove-Item $Path -Force
138 if (Test-Path $Path) {
139 Write-Host "File '$Path' already exists, skipping download"
143 $DownloadDirectory = Split-Path -ErrorAction Ignore -Path "$Path" -Parent
144 if (-Not (Test-Path $DownloadDirectory)) {
145 New-Item -path $DownloadDirectory -force -itemType "Directory" | Out-Null
148 if (Test-Path -IsValid -Path $Uri) {
149 Write-Verbose "'$Uri' is a file path, copying file to '$Path'"
150 Copy-Item -Path $Uri -Destination $Path
154 Write-Verbose "Downloading $Uri"
155 while($Attempt -Lt $DownloadRetries)
158 Invoke-WebRequest -UseBasicParsing -Uri $Uri -OutFile $Path
159 Write-Verbose "Downloaded to '$Path'"
164 if ($Attempt -Lt $DownloadRetries) {
165 $AttemptsLeft = $DownloadRetries - $Attempt
166 Write-Warning "Download failed, $AttemptsLeft attempts remaining, will retry in $RetryWaitTimeInSeconds seconds"
167 Start-Sleep -Seconds $RetryWaitTimeInSeconds
171 Write-Error $_.Exception
182 Generate a shim for a native tool
185 Creates a wrapper script (shim) that passes arguments forward to native tool assembly
190 .PARAMETER ShimDirectory
191 The directory where shims are stored
193 .PARAMETER ToolFilePath
194 Path to file that shim forwards to
197 Replace shim if already present. Default = False
200 Returns $True if generating shim succeeds, $False otherwise
202 function New-ScriptShim {
203 [CmdletBinding(PositionalBinding=$false)]
205 [Parameter(Mandatory=$True)]
207 [Parameter(Mandatory=$True)]
208 [string] $ShimDirectory,
209 [Parameter(Mandatory=$True)]
210 [string] $ToolFilePath,
211 [Parameter(Mandatory=$True)]
216 Write-Verbose "Generating '$ShimName' shim"
218 if (-Not (Test-Path $ToolFilePath)){
219 Write-Error "Specified tool file path '$ToolFilePath' does not exist"
223 # WinShimmer is a small .NET Framework program that creates .exe shims to bootstrapped programs
224 # Many of the checks for installed programs expect a .exe extension for Windows tools, rather
225 # than a .bat or .cmd file.
226 # Source: https://github.com/dotnet/arcade/tree/master/src/WinShimmer
227 if (-Not (Test-Path "$ShimDirectory\WinShimmer\winshimmer.exe")) {
228 $InstallStatus = DownloadAndExtract -Uri "$BaseUri/windows/winshimmer/WinShimmer.zip" `
229 -InstallDirectory $ShimDirectory\WinShimmer `
232 -RetryWaitTimeInSeconds 5 `
236 if ((Test-Path (Join-Path $ShimDirectory "$ShimName.exe"))) {
237 Write-Host "$ShimName.exe already exists; replacing..."
238 Remove-Item (Join-Path $ShimDirectory "$ShimName.exe")
241 & "$ShimDirectory\WinShimmer\winshimmer.exe" $ShimName $ToolFilePath $ShimDirectory
246 Write-Host $_.Exception
253 Returns the machine architecture of the host machine
256 Returns 'x64' on 64 bit machines
257 Returns 'x86' on 32 bit machines
259 function Get-MachineArchitecture {
260 $ProcessorArchitecture = $Env:PROCESSOR_ARCHITECTURE
261 $ProcessorArchitectureW6432 = $Env:PROCESSOR_ARCHITEW6432
262 if($ProcessorArchitecture -Eq "X86")
264 if(($ProcessorArchitectureW6432 -Eq "") -Or
265 ($ProcessorArchitectureW6432 -Eq "X86")) {
268 $ProcessorArchitecture = $ProcessorArchitectureW6432
270 if (($ProcessorArchitecture -Eq "AMD64") -Or
271 ($ProcessorArchitecture -Eq "IA64") -Or
272 ($ProcessorArchitecture -Eq "ARM64")) {
280 Get the name of a temporary folder under the native install directory
282 function Get-TempDirectory {
283 return Join-Path (Get-NativeInstallDirectory) "temp/"
286 function Get-TempPathFilename {
287 [CmdletBinding(PositionalBinding=$false)]
289 [Parameter(Mandatory=$True)]
292 $TempDir = CommonLibrary\Get-TempDirectory
293 $TempFilename = Split-Path $Path -leaf
294 $TempPath = Join-Path $TempDir $TempFilename
300 Returns the base directory to use for native tool installation
303 Returns the value of the NETCOREENG_INSTALL_DIRECTORY if that environment variable
304 is set, or otherwise returns an install directory under the %USERPROFILE%
306 function Get-NativeInstallDirectory {
307 $InstallDir = $Env:NETCOREENG_INSTALL_DIRECTORY
309 $InstallDir = Join-Path $Env:USERPROFILE ".netcoreeng/native/"
319 Powershell module to unzip an archive to a specified directory
321 .PARAMETER ZipPath (Required)
322 Path to archive to unzip
324 .PARAMETER OutputDirectory (Required)
325 Output directory for archive contents
328 Overwrite output directory contents if they already exist
331 - Returns True and does not perform an extraction if output directory already exists but Overwrite is not True.
332 - Returns True if unzip operation is successful
333 - Returns False if Overwrite is True and it is unable to remove contents of OutputDirectory
334 - Returns False if unable to extract zip archive
336 function Expand-Zip {
337 [CmdletBinding(PositionalBinding=$false)]
339 [Parameter(Mandatory=$True)]
341 [Parameter(Mandatory=$True)]
342 [string] $OutputDirectory,
346 Write-Verbose "Extracting '$ZipPath' to '$OutputDirectory'"
348 if ((Test-Path $OutputDirectory) -And (-Not $Force)) {
349 Write-Host "Directory '$OutputDirectory' already exists, skipping extract"
352 if (Test-Path $OutputDirectory) {
353 Write-Verbose "'Force' is 'True', but '$OutputDirectory' exists, removing directory"
354 Remove-Item $OutputDirectory -Force -Recurse
356 Write-Error "Unable to remove '$OutputDirectory'"
360 if (-Not (Test-Path $OutputDirectory)) {
361 New-Item -path $OutputDirectory -Force -itemType "Directory" | Out-Null
364 Add-Type -assembly "system.io.compression.filesystem"
365 [io.compression.zipfile]::ExtractToDirectory("$ZipPath", "$OutputDirectory")
367 Write-Error "Unable to extract '$ZipPath'"
373 Write-Host $_.Exception
380 export-modulemember -function DownloadAndExtract
381 export-modulemember -function Expand-Zip
382 export-modulemember -function Get-File
383 export-modulemember -function Get-MachineArchitecture
384 export-modulemember -function Get-NativeInstallDirectory
385 export-modulemember -function Get-TempDirectory
386 export-modulemember -function Get-TempPathFilename
387 export-modulemember -function New-ScriptShim