Update - Was a typo in the script, which I fixed. If someone had an issue, copy it again and give it a go.

I prefer to download and see the decks and videos ‘offline’ instead of streaming, as I can easily pause them and then pick off where I left - especially handy when I need to go to a meeting, or take care of some work, or just on a crappy network.

To that end, I downloaded all the sessions and the videos from Build (2016); I think one of the sessions might have gotten corrupted, but ignoring that I have about 140GB of data downloaded and 219 Sessions.

To do this, I used a Power Shell script that helped me download. The script (below) is simple enough - it loops through and for each session does the following:

  • Creates the relevant folder - this includes the Session code, Title, and the Presenters.
  • For each session, extracts the abstract / description of that session and saves it in a text file in that folder.
  • Downloads the presentation for that session.
  • Downloads a jpg which shows the image session - sometimes it is easier just to see the title slide. I thought better to have it and not use it, than the other way.
  • And finally downloads the high-quality video of that session. In the script, you can choose a lower quality video if you prefer that. And if you want only the decks, then you can comment out parts of the script where it doesn’t download the video.

Here is an example on what the output for one of the sessions (P517 - Debugging Events in Edge) looks like:

Build-2016-download-example

A few points to note:

  • In the script, the root folder it tries to create and use is "d:\build"; you might want to change this to something else you prefer or what works for you. I would recommend to not making the root too long as you would get into long file name issues.
  • The script first loops through and downloads everything else except the videos first. And then 2nd time goes and grabs the videos.
  • If there is an exception with the images, then it just ’eats’ it and moves on. It is not a breaking condition to stop the script.
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# First setup the folder where to download using the parameters outlined below.
# Second, loop through and get the decks first
# Third. loop through and get the videos last
# Note: IF you don't want to download the videos, and want only the pptx then comment the section later in the script
 
# parameters
[Environment]::CurrentDirectory=(Get-Location -PSProvider FileSystem).ProviderPath 
$rss = (new-object net.webclient)
 
#Filenames might get long, so keep this short!
$downloadlocation = "D:\build"
 
    if (-not (Test-Path $downloadlocation)) { 
        Write-Host "Folder $fpath dosen't exist. Creating it..." 
        New-Item $downloadlocation -type directory 
    }
set-location $downloadlocation
 
# Grab the RSS feed - Build 2016
$a = ($rss.downloadstring("http://s.ch9.ms/events/build/2016/rss/mp4high")) 
$b = ($rss.downloadstring("http://s.ch9.ms/events/build/2016/rss/slides")) 
 
# Video quality default is high; you can select regular (mp4) or lower quality (mp3)
#$a = ($rss.downloadstring("http://s.ch9.ms/events/build/2015/rss/mp4")) 
#$a = ($rss.downloadstring("http://s.ch9.ms/events/build/2015/rss/mp3")) 
 
 
# ********** download the decks **********
try { 
    $b.rss.channel.item | foreach {   
        $code = $_.comments.split("/") | select -last 1    
     
        # Get the url for the pptx file
        $urlpptx = New-Object System.Uri($_.enclosure.url)  
        $urljpg = New-Object System.Uri($_.thumbnail.url)
 
        # make the filename readable
        $filepptx = $code + "-" + $_.creator + " - " + $_.title.Replace(":", "-").Replace("?", "").Replace("/", "-").Replace("<", "").Replace("|", "").Replace('"',"").Replace("*","")
        $filepptx = $filepptx.substring(0, [System.Math]::Min(120, $filepptx.Length))
        $filepptx = $filepptx.trim()
        $filejpg = $filepptx
 
        $filepptx = $filepptx + ".pptx" 
        $filejpg = $filejpg + "_960.jpg"
 
        if ($code -ne "") {
             $folder = $code + " - " + $_.title.Replace(":", "-").Replace("?", "").Replace("/", "-").Replace("<", "").Replace("|", "").Replace('"',"").Replace("*","")
             $folder = $folder.substring(0, [System.Math]::Min(100, $folder.Length))
             $folder = $folder.trim()
        }
        else {
            $folder = "NoCodeSessions"
        }
     
        if (-not (Test-Path $folder)) { 
            Write-Host "Folder $folder dosen't exist. Creating it..."  
            New-Item $folder -type directory 
        }
     
     
        # Make sure the PowerPoint file doesn't already exist
        if (!(test-path "$downloadlocation\$folder\$filepptx")) {   
            # Echo out the file that's being downloaded
            $filepptx
            $wc = (New-Object System.Net.WebClient)  
 
            # Download the pptx file
            $wc.DownloadFile($urlpptx, "$downloadlocation\$filepptx")
 
            # download the jpg but don't want to break if this doesn't exist; hence the nested try blocks
            try {
                $wc.DownloadFile($urljpg, "$downloadlocation\$filejpg")
            }
            catch {
                Write-Host "Jpeg $filejpg doesn't exist ... eating the exception and moving on ..."
            }
         
            mv $filepptx $folder 
            mv $filejpg $folder 
        } #endif
    } #end-loop foreach
 
    Write-host "*************** Downloading all the decks complete ***************"
}
catch
{
    Write-host "Oops, could not find any slides."
}
 
# ********** download the videos **********
$a.rss.channel.item | foreach {   
    $code = $_.comments.split("/") | select -last 1    
     
    # Grab the URL for the MP4 file
    $url = New-Object System.Uri($_.enclosure.url)  
     
    # Create the local file name for the MP4 download
    $file = $code + "-" + $_.creator + "-" + $_.title.Replace(":", "-").Replace("?", "").Replace("/", "-").Replace("<", "").Replace("|", "").Replace('"',"").Replace("*","")
    $file = $file.substring(0, [System.Math]::Min(120, $file.Length))
    $file = $file.trim()
    $file = $file + ".mp4"  
     
    if ($code -ne "") {
         $folder = $code + " - " + $_.title.Replace(":", "-").Replace("?", "").Replace("/", "-").Replace("<", "").Replace("|", "").Replace('"',"").Replace("*","")
         $folder = $folder.substring(0, [System.Math]::Min(100, $folder.Length))
         $folder = $folder.trim()
    }
    else {
        $folder = "NoCodeSessions"
    }
     
    if (-not (Test-Path $folder)) { 
        Write-Host "Folder $folder) dosen't exist. Creating it..."  
        New-Item $folder -type directory 
    }
     
    # Make sure the MP4 file doesn't already exist
    if (!(test-path "$folder\$file")) {     
        # Echo out the  file that's being downloaded
        $file
        $wc = (New-Object System.Net.WebClient)  
 
        # Download the MP4 file
        $wc.DownloadFile($url, "$downloadlocation\$file")
        mv $file $folder
    }
 
    #Try and get the Sessions text description
    $OutFile = New-Item -type file "$($downloadlocation)\$($Folder)\$($Code.trim()).txt" -Force  
    $Category = "" ; $Content = ""
    $_.category | foreach {$Category += $_ + ","}
    $Content = $_.title.trim() + "`r`n" + $_.creator + "`r`n" + $_.summary.trim() + "`r`n" + "`r`n" + $Category.Substring(0,$Category.Length -1)
    add-content $OutFile $Content       
} #end-loop foreach
 
Write-host "*************** All Done! ***************"