Follow-up on downloading Windows Assessment and Deployment Kit (Windows ADK) 8.1

*! Update: 2014-09-30:
Looking for the latest version of ADK 8.1, see my most recent post

I proposed last year two scripts to download the latest Windows Assessment and Deployment Kit (ADK) files using BITS and PowerShell šŸ™‚

Today is April 8, 2014 and it’s the perfect time to update the script.

But let’s first see how I built the DATA blocks in the function.

I first launched the webinstaller of the ADK and told him to download files into C:\ADK.
Then I used PowerShell to extract the DATA using the following code.

# First test the regular expression with the built-in select-string cmdlet
Get-Content 'C:\adk\Windows Assessment and Deployment Kit for Windows 8.1_20140403114657.log' | 
Select-String -Pattern "Acquiring\spackage:\s(?<Name1>.*),\spayload:\s(?<Name2>.*),\sdownload\sfrom:\s(?<URL>.*)$"

# Extract URL and file names from the log file and send it through the pipeline
$ADKFiles = (
Get-Content "C:\adk\Windows Assessment and Deployment Kit for Windows 8.1_20140403114657.log" -ReadCount 1 | ForEach-Object {
    ([regex]'Acquiring\spackage:\s(?<Name1>.*),\spayload:\s(?<Name2>.*),\sdownload\sfrom:\s(?<URL>.*)$').Matches($_) | ForEach-Object {
            URL = @($_.Groups)[-1].Value ;
            FileName = ([URI]@($_.Groups)[-1].Value).Segments[-1] -replace '%20'," "

# Let me know how many files are downloaded
Write-Verbose -Message ("There are {0} files in the ADK toolkit to download" -f $Adkfiles.Count) -Verbose

Write-Verbose -Message (
    "There are {0} files in the ADK toolkit from ../adk/Installers" -f ($Adkfiles| Where URL -match "adk/Installers/").Count
) -Verbose

Write-Verbose -Message (
    "There are {0} files in the ADK toolkit from ../adk/Patches" -f ($Adkfiles| Where URL -notmatch "adk/Installers/").Count
) -Verbose

# Construct the first DATA block
$count = 0
($Adkfiles| Where URL -match "adk/Installers/") | ForEach-Object {
 '{0}={1}' -f $count,$_.FileName
# Construct the second DATA block
$count = 0
($Adkfiles| Where URL -notmatch "adk/Installers/") | ForEach-Object {
 '{0}={1}' -f $count,$_.FileName

Then I copied the console output you can see above into the appropriate DATA blocks and updated manually the version string from 8.100.26020 to 8.100.26629

#Requires -Version 4
#Requires -RunAsAdministrator 
Function Get-ADKFiles {
Begin {
    $HT = @{}
    $HT += @{ ErrorAction = 'Stop'}
    # Validate target folder
    try {
        Get-Item $TargetFolder @HT | Out-Null
    } catch {
        Write-Warning -Message "The target folder specified as parameter does not exist"
Process {
    $adkGenericURL = (Invoke-WebRequest -Uri -MaximumRedirection 0 -ErrorAction SilentlyContinue)

    # 302 = redirect as moved temporarily
    if ($adkGenericURL.StatusCode -eq 302) {
        # Currently set to
        $MainURL = $adkGenericURL.Headers.Location
        $InstallerURLs = DATA {
            ConvertFrom-StringData @'
                0=Toolkit Documentation-x86_en-us.msi
                6=Application Compatibility Toolkit-x86_en-us.msi
                11=Microsoft Compatibility Monitor-x86_en-us.msi
                12=Application Compatibility Toolkit-x64_en-us.msi
                14=Microsoft Compatibility Monitor-x86_en-us.msi
                15=Windows Deployment Tools-x86_en-us.msi
                45=Windows System Image Manager on amd64-x86_en-us.msi
                46=Windows System Image Manager on x86-x86_en-us.msi
                47=Windows Deployment Customizations-x86_en-us.msi
                56=Windows PE x86 x64-x86_en-us.msi
                64=Windows PE x86 x64 wims-x86_en-us.msi
                67=User State Migration Tool-x86_en-us.msi
                70=Volume Activation Management Tool-x86_en-us.msi
                74=WPT Redistributables-x86_en-us.msi
                78=Windows Assessment Toolkit-x86_en-us.msi
                82=Windows Assessment Toolkit (AMD64 Architecture Specific)-x86_en-us.msi
                83=Windows Assessment Toolkit (X86 Architecture Specific)-x86_en-us.msi
                84=Assessments on Client-x86_en-us.msi
                146=Windows Assessment Services-x86_en-us.msi
                150=Windows Assessment Services - Client (Server SKU)-x86_en-us.msi
                153=Windows Assessment Services - Client (AMD64 Architecture Specific, Server SKU)-x86_en-us.msi
                154=Assessments on Server-x86_en-us.msi
                156=Windows Assessment Services - Client (Client SKU)-x86_en-us.msi
                157=Windows Assessment Services - Client (X86 Architecture Specific, Client SKU)-x86_en-us.msi
                158=Windows Assessment Services - Client (AMD64 Architecture Specific, Client SKU)-x86_en-us.msi
                159=Kits Configuration Installer-x86_en-us.msi
        $PatchesURLs = DATA {
            ConvertFrom-StringData @'
                0=Toolkit Documentation-x86_en-us.msp
                1=Application Compatibility Toolkit-x86_en-us.msp
                2=Application Compatibility Toolkit-x64_en-us.msp
                3=Windows Deployment Tools-x86_en-us.msp
                4=Windows System Image Manager on amd64-x86_en-us.msp
                5=Windows System Image Manager on x86-x86_en-us.msp
                6=Windows PE x86 x64-x86_en-us.msp
                7=User State Migration Tool-x86_en-us.msp
                8=Volume Activation Management Tool-x86_en-us.msp
                11=WPT Redistributables-x86_en-us.msp
                12=Windows Assessment Toolkit-x86_en-us.msp
                13=Assessments on Client-x86_en-us.msp
                14=Windows Assessment Services-x86_en-us.msp
                15=Windows Assessment Services - Client (Server SKU)-x86_en-us.msp
                16=Assessments on Server-x86_en-us.msp
                17=Windows Assessment Services - Client (Client SKU)-x86_en-us.msp
        "Installers","Patches\8.100.26629" | ForEach-Object -Process {
            # Create target folders if required as BIT doesn't accept missing folders
            If (-not(Test-Path (Join-Path -Path $TargetFolder -ChildPath $_))) {
                try {
                    New-Item -Path (Join-Path -Path $TargetFolder -ChildPath $_) -ItemType Directory -Force @HT
                } catch {
                    Write-Warning -Message "Failed to create folder $($TargetFolder)/$_"
        # Get adksetup.exe
        Invoke-WebRequest -Uri "$($MainURL)adksetup.exe" -OutFile  "$($TargetFolder)\adksetup.exe"
        # Create a job that will downlad our first file
        $job = Start-BitsTransfer -Suspended -Source "$($MainURL)Installers/$($InstallerURLs['0'])" -Asynchronous -Destination (Join-Path -Path $TargetFolder -ChildPath ("Installers/$($InstallerURLs['0'])")) 
        # Downlod installers
        For ($i = 1 ; $i -lt $InstallerURLs.Count ; $i++) {
            $URL = $Destination = $null
            $URL = "$($MainURL)Installers/$($InstallerURLs[$i.ToString()])"
            $Destination = Join-Path -Path (Join-Path -Path $TargetFolder -ChildPath Installers) -ChildPath (([URI]$URL).Segments[-1] -replace '%20'," ")
            # Add-BitsFile
            $newjob = Add-BitsFile -BitsJob $job -Source  $URL -Destination $Destination
            Write-Progress -Activity "Adding file $($newjob.FilesTotal)" -Status "Percent completed: " -PercentComplete (($newjob.FilesTotal)*100/($InstallerURLs.Count))
        # Donwload Patches
        For ($i = 0 ; $i -lt $PatchesURLs.Count ; $i++) {
            $URL = $Destination = $null
            $URL = "$($MainURL)Patches/8.100.26629/$($PatchesURLs[$i.ToString()])"
            $Destination = Join-Path -Path (Join-Path -Path $TargetFolder -ChildPath "Patches/8.100.26629") -ChildPath (([URI]$URL).Segments[-1] -replace '%20'," ")
            # Add-BitsFile
            $newjob = Add-BitsFile -BitsJob $job -Source  $URL -Destination $Destination
        # Begin the download and show us the job
        Resume-BitsTransfer  -BitsJob $job -Asynchronous
        while ($job.JobState -in @('Connecting','Transferring','Queued')) {
            Write-Progress -activity "Downloading ADK files" -Status "Percent completed: " -PercentComplete ($job.BytesTransferred*100/$job.BytesTotal)
        Switch($job.JobState) {
         "Transferred" {
            Complete-BitsTransfer -BitsJob $job
         "Error" {
            # List the errors.
            $job | Format-List
        default {
            # Perform corrective action.
End {}

Then I tested the function like this:

  1. I created the target folder
  2. If you don’t create it and try to launch the function, you’ll get the following warning:

  3. I dotsourced the script
  4. I launched the download

  5. I compared the downloaded files made with the webinstaller and my function.

The following links are still valid to obtain the:

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.