Download Ubuntu ISO using PowerShell

My previous post Unattended Ubuntu 16.04 Setup Using PowerShell was about building Ubuntu Server Virtual Machine completely in unattended mode on Hyper-V. To do that we need at least a server operating system ISO file of particular Ubuntu version. I wanted to plug this script/functions in earlier script however to keep it simple, I didn’t do that. I will try to merge these script soon to come up one single script later.

In this post, I will share how to get a particular Ubuntu ISO file using PowerShell script. You can download the complete script from my github repository.

This script has 4 functions as listed below,

  • Get-AvailableUbuntuVersions
  • Get-UbuntuDownloadUrl
  • Save-UbuntuISO
  • Test-Checkum

Since I have explained functions in script manual, I will just talk briefly about them here. For more information please refer the script documentation.

Get-AvailableUbuntuVersions – This is main function which gets called after running the script. This function reads http://releases.ubuntu.com/ and extracts the available version details. It then presents the available version to user and let user select from it.Using the choice of user it then calls Get-UbuntuDownloadUrl to build/identify the download URL for the selected version.

Get-UbuntuDownloadUrl – Generate the download URL. Based on the ubuntu version selected by user, this function generates the download URL for the iso and MD5SUMS file. Before exiting it calls the Save-UbuntuISO to start the download.

Save-UbuntuISO – Download the ISO file. This function gets called from inside Get-UbuntuDownloadUrl with 2 parameters download link and target location to save file locally. It uses BITS module to initiate, monitor and close the download of ISO file. Since the BITS job is set to Asynchronous this function will keep track of the progress of the job and ensure BITs transfer is resumed appropriately in case of failures.

Test-Checkum – Check the MD5Sum of the downloaded file. Once the download is complete, It gets the input parameters (sourceMD5SumsFileURL, sourcefile, targetFile) from Save-UbuntuISO for the iso file which is getting downloaded. It checks if the checksum matches and gives appropriate status message back to user.

Screenshots

This slideshow requires JavaScript.

Notes:

  • This script is tested on PowerShell 5, Windows 10 Pro version 1703 (creator update).
  • I expect it to work on PowerShell 3 and above without any issues.
  • Currently this script will not work on PowerShell for Linux as it needs BITS modules. I will be testing wget or other similar options for the Linux capability. Stay tuned if you are interested to see that update. Having said, I will be glad hear your updates/comments if you test and find the alternatives before I could try myself.

Get-CloudManagementTools

This PowerShell script can be used to download some of the common cloud (Azure and AWS) management tools available on Windows Platform.

Earlier I had seen Download and Install SharePoint 2013 Prerequisites on Windows Server 2012.  However this technet script uses Start-BitsTransfer cmdlet from BitsTransfer module. I was toying with similar idea while working on my last workshop (Cloud Automation Using PowerShell) preparation. Since some of the URLs do redirect the Start-BitsTransfer wasn’t working for me initially.

I started with simple Invoke-WebRequest cmdlet and added second variation to handle redirected URLs and pass it to Start-BitsTransfer. So let’s go through the script and output for the both the approaches.

I am using Downloads directory to store the files. For demo I have created CloudTools folder inside. I already have AWS Tools for Windows PowerShell downloaded in the folder.

15012017-01

I am already into the working directory where the script is saved.

15012017-02

Started the script execution and you can notice it finds AWS Tools For Windows PowerShell and skips the download for it.

15012017-03

On my Windows Server 2012 R2 VM it created a CloudTools folder which was missing before download starts.

15012017-03-01

# The folder location where the downloads will be saved
$DestinationFolder = "$ENV:homedrive$env:homepath\Downloads\CloudTools"
If (!(Test-Path $DestinationFolder)){
 New-Item $DestinationFolder -ItemType Directory -Force
}

Download is in progress…

15012017-04

Before this, I have created hash table with Download URL and File Name After Downloaded

# Specify download url's for various cloud management tools. Do not change unless Microsoft changes the downloads themselves in future
$Downloads = @{
 # Latest Azure PowerShell
 # Github: https://github.com/Azure/azure-powershell/releases/latest
 # WebPI: https://www.microsoft.com/web/handlers/webpi.ashx/getinstaller/WindowsAzurePowershellGet.3f.3f.3fnew.appids
 "https://aka.ms/azure-powershellget2" = "$DestinationFolder\Azure-PowerShell.msi"; 
 # Latest Azure Storage Explorer
 "https://go.microsoft.com/fwlink/?LinkId=708343" = "$DestinationFolder\StorageExplorer.exe";
 # Latest AZCopy
 "http://aka.ms/downloadazcopy" = "$DestinationFolder\MicrosoftAzureStorageTools.msi";
 # Latest Azure CLI
 "http://aka.ms/webpi-azure-cli" = "$DestinationFolder\Azure-cli.msi";
 # Azure Storage Emulator
 "https://go.microsoft.com/fwlink/?LinkId=717179&clcid=0x409" = "$DestinationFolder\MicrosoftAzureStorageEmulator.msi";
 # Latest AWS Tools For Windows PowerShell
 "http://sdk-for-net.amazonwebservices.com/latest/AWSToolsAndSDKForNet.msi" = "$DestinationFolder\AWSToolsAndSDKForNet.msi";
 }

Approach 1 – using Invoke-WebRequest cmdlet ,

Then I have a function which loop through the elements in downloads hash table using Invoke-WebRequest cmdlet,

function DownloadFiles(){ 
 Write-Host ""
 Write-Host "====================================================================="
 Write-Host " Downloading Cloud Management Tools for Azure & AWS" 
 Write-Host "====================================================================="
 
 $ReturnCode = 0

$Downloads.GetEnumerator() | ForEach-Object { 
 $DownloadURL = $_.get_key()
 $Filespec = $_.get_value()
 # Get the file name based on the portion of the file path after the last slash 
 $FilePath = Split-Path $Filespec
 $FileName = Split-Path $Filespec -Leaf
 Write-Host "DOWNLOADING: $FileName"
 Write-Host " FROM: $DownloadURL"
 Write-Host " TO: $FilePath"
 
 Try 
 { 
 # Check if file already exists 
 If (!(Test-Path "$Filespec")) 
 { 
 # Begin download 
 Invoke-WebRequest -Uri $DownloadURL -OutFile "$Filespec" -ErrorVariable err
 If ($err) {Throw ""} 
 Write-Host " STATUS: Downloaded"
 Write-Host
 } 
 Else 
 { 
 Write-Host " STATUS: Already exists. Skipping." 
 Write-Host
 } 
 } 
 Catch 
 { 
 $ReturnCode = -1
 Write-Warning " AN ERROR OCCURRED DOWNLOADING `'$FileName`'" 
 Write-Error $_
 Break 
 }
} 
 return $ReturnCode 
}

and the downloads completed.

15012017-05

Approach 2 – using Start-BitsTransfer cmdlet,

First a function Get-RedirectedUrl to get redirected URL

# This function gets the end URL to avoid redirection in URL breaking the Start-BitsTransfer
# Courtesy: http://www.powershellmagazine.com/2013/01/29/pstip-retrieve-a-redirected-url/
Function Get-RedirectedUrl {
 Param (
 [Parameter(Mandatory=$true)]
 [String]$url
 )
 $request = [System.Net.WebRequest]::Create($url)
 $request.AllowAutoRedirect=$true
 try{
 $response=$request.GetResponse()
 $response.ResponseUri.AbsoluteUri
 $response.Close()
 }
 catch{
 “ERROR: $_”
 }
}

Then I have a function which loop through the elements in downloads hash table using Start-BitsTransfer cmdlet,

# Import Required Modules: BITS is used for file transfer
Import-Module BitsTransfer

function DownloadFiles(){ 
 Write-Host ""
 Write-Host "====================================================================="
 Write-Host " Downloading Cloud Management Tools for Azure & AWS" 
 Write-Host "====================================================================="
 
 $ReturnCode = 0

$Downloads.GetEnumerator() | ForEach-Object { 
 $DownloadURL = Get-RedirectedUrl -URL $_.get_key()
 $Filespec = $_.get_value()
 # Get the file name based on the portion of the file path after the last slash 
 $FilePath = Split-Path $Filespec
 $FileName = Split-Path $Filespec -Leaf
 Write-Host "DOWNLOADING: $FileName"
 Write-Host " FROM: $DownloadURL"
 Write-Host " TO: $FilePath"
 
 Try 
 { 
 # Check if file already exists 
 If (!(Test-Path "$Filespec")) 
 { 
 # Begin download 
 Start-BitsTransfer -Source $DownloadURL -Destination "$Filespec" -DisplayName "Downloading `'$FileName`' to $FilePath" -Priority High -Description "From $DownloadURL..." -ErrorVariable err 
 If ($err) {Throw ""} 
 Write-Host " STATUS: Downloaded"
 Write-Host
 } 
 Else 
 { 
 Write-Host " STATUS: Already exists. Skipping." 
 Write-Host
 } 
 } 
 Catch 
 { 
 $ReturnCode = -1
 Write-Warning " AN ERROR OCCURRED DOWNLOADING `'$FileName`'" 
 Write-Error $_
 Break 
 }

} 
 return $ReturnCode 
}

while downloading the progress bar looks different,

15012017-06

I had deleted 2 files and ran the script again and following is the output,

15012017-07

If you want to know more about BITSTransfer & PowerShell you can refer this How to copy files with BITS using PowerShell

You can try both variation scripts by downloading from my (cloudscripts) github. I will be updating it later for more tools.

That’s it for now.