Just as last year , I wrote a PowerShell script using which you can download the PowerPoint decks, and, videos from Microsoft Build’s conference, instead of streaming it (or manually download it one by one). You can choose if you want the decks, or the videos, or both. For the videos you can choose the desired resolution (Low, Medium, High) – of course the higher the resolution, the more space is needed. The script also downloads the description and if there is a session image (if there is one).

A few points to note:

  • The slides only once downloaded is ~10GB and with videos (high-resolution), the size goes up to 90.5 GB. So make sure you have enough space.
  • By default the download location is C:\build-2018\; you can change this to whatever you want, but make sure there is a trailing backslash. Think of this as the ‘base’ folder.
  • For each session a sub-folder with the session name will be created in the ‘base’ folder setup in the previous step.
  • If a file already exists, it will be skipped.
  • As each file is downloaded, it save it in the root folder and once the download is complete, only then moves it in the relevant subfolder.
  • If a download fails for some reason to retry it, delete the ‘left over’ file(s) in the base folder and then run the script again. The script itself will ’eat’ the exception and move on to the next file.
  • The video quality parameter is 1 for Low, 2 for Medium, and 3 for High (default).

And if you read through, the script is quite self-explanatory.

  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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
# Comments that you should read, before you kick this off. Yes, seriously. :)
# 1. Setup the folder where to download using the parameters outlined below
# 2. Loop through and get the slides first
# 3. Finally, loop through and get the videos last
  
 param (
    [string]$path = "C:\build-2018\",
    [switch]$sessionvideo = $true,
    [int][ValidateRange(1,3)]$videoquality = 3,
    [switch]$sessiondeck = $true
 )
 
[Environment]::CurrentDirectory=(Get-Location -PSProvider FileSystem).ProviderPath 
$rss = (new-object net.webclient)
 
#Filenames might get long, so keep this short!
#$downloadlocation = "D:\build-2018"
 
if (-not (Test-Path $path)) {
    Write-Host "Folder $fpath dosen't exist. Creating it..."
    New-Item $path -type directory 
}
 
set-location $path
 
if($sessiondeck) {  
# Grab the Slides RSS feed - Build 2018
$slides = ($rss.downloadstring("http://s.ch9.ms/events/build/2018/rss/slides")) 
 
    # ********** download the decks **********
    try { 
        foreach($item in $slides.rss.channel.item) {  
            $code = $item.comments.split("/") | select -last 1     
     
            # Get the url for the pptx file
            $urlpptx = New-Object System.Uri($item.enclosure.url)
         
            # make the filename readable
            $filepptx = $code + " - " + $item.title.Replace(":", "-").Replace("?", "").Replace("/", "-").Replace("<", "").Replace("|", "").Replace('"',"").Replace("*","").Replace("’","'").Replace("â€","").Replace("'NEW SESSION'","").Replace("™","").Replace("œ","")
            $filepptx = $filepptx.substring(0, [System.Math]::Min(120, $filepptx.Length))
            $filepptx = $filepptx.trim()
            $filejpg = $filepptx
  
            $filepptx = $filepptx + ".pptx" 
            $filejpg = $filejpg + "_960.png"
  
      
            $folder = $item.title.Replace(":", "-").Replace("?", "").Replace("/", "-").Replace("<", "").Replace("|", "").Replace('"',"").Replace("*","").Replace("’","'").Replace("â€","").Replace("'NEW SESSION'","").Replace("™","").Replace("œ","")
            $folder = $folder.substring(0, [System.Math]::Min(100, $folder.Length))
            $folder = $folder.trim()
              
            if (-not (Test-Path $folder)) { 
                Write-Host "Folder $folder doesnt exist. Creating it..."  
                New-Item $folder -type directory 
            }
      
            # Make sure the PowerPoint file doesn't already exist
            if (!(test-path "$path\$folder\$filepptx")) {   
                # Echo out the file that's being downloaded
                $filepptx
                $wc = (New-Object System.Net.WebClient)  
  
                # Download the pptx file
                Invoke-WebRequest $urlpptx -OutFile $path\$filepptx
  
                # download the jpg but don't want to break if this doesn't exist; hence the nested try blocks
                try {
                    if($item.thumbnail -ne $null) {
                        $urljpg = New-Object System.Uri($item.thumbnail.url)
 
                        if (!(test-path "$path\$filejpg")) {    
                            $wc.DownloadFile($urljpg, "$path\$folder\$filejpg")
                        }
                    }
                }
                catch {
                    Write-Host "Image (jpeg) $filejpg doesn't exist ... eating the exception and moving on ..."
                }
          
                mv $filepptx $folder 
                #mv $filejpg $folder 
            } #endif
            else {
                Write-Host "PPTX: $filepptx exist; skipping download."  
            }
 
            #try and get the sessions details
            try {
                $descriptionFileName = "$($path)\$($folder)\$($Code.trim()).txt"
 
                if (!(test-path "$descriptionFileName")) {
                    $OutFile = New-Item -type file $descriptionFileName -Force  
                    $Content = "Title: " + $item.title.ToString().trim() + "`r`n" + "`r`n" + "Presenter: " + $item.creator + "`r`n" + "`r`n" + "Summary: " + $item.summary.ToString().trim() + "`r`n" + "`r`n" + "Link: " + $item.comments.ToString().trim() 
 
                    #some categories are missing; so need to eat the exception
                    #this is a hack and not very elegant
                    try {
                        if($item.category -ne $null) {
                            $Content = $Content + "`r`n" + "`r`n" + "Category: " + $item.category.ToString().trim().Replace("+"," ")
                        }
                    }
                    catch {
                        #do nothing; eat the exception
                    }
 
                    add-content $OutFile $Content
                }
            }
            catch {
                $ErrorMessage = $_.Exception.Message
                $FailedItem = $_.Exception.ItemName
                Write-host "\t" $ErrorMessage + "\n" + $FailedItem
            }
        } #end-loop foreach
  
        Write-host "*************** Downloading all the decks complete ***************"
    }
    catch
    {
        Write-host "Oops, could not find any slides."
        $ErrorMessage = $_.Exception.Message
        $FailedItem = $_.Exception.ItemName
        Write-host "\t" $ErrorMessage + "\n" + $FailedItem
    }
} #download session-deck 
 
# ********** download the videos **********
# if you don't want the video but only the slides just comment all the code below in the foreach loop
try { 
    # check for video download
    if($sessionvideo) {
        switch ($videoquality) {
            1 {$video = ($rss.downloadstring("http://s.ch9.ms/events/build/2018/rss/mp3")); break}
            2 {$video = ($rss.downloadstring("http://s.ch9.ms/events/build/2018/rss/mp4")); break}
            default {$video = ($rss.downloadstring("http://s.ch9.ms/events/build/2018/rss/mp4high")); break}
        }
  
        foreach($item in $video.rss.channel.item) {    
            # Grab the URL for the MP4 file
            $url = New-Object System.Uri($item.enclosure.url)  
      
            # Create the local file name for the video download
            $file = $item.title.Replace(":", "-").Replace("?", "").Replace("/", "-").Replace("<", "").Replace("|", "").Replace('"',"").Replace("*","").Replace("’","'").Replace("â€","").Replace("'NEW SESSION'","").Replace("™","").Replace("œ","")
            $file = $file.substring(0, [System.Math]::Min(120, $file.Length))
            $file = $file.trim()
            $file = $file + ".mp4"  
      
            $folder = $item.title.Replace(":", "-").Replace("?", "").Replace("/", "-").Replace("<", "").Replace("|", "").Replace('"',"").Replace("*","").Replace("’","'").Replace("â€","").Replace("'NEW SESSION'","").Replace("™","").Replace("œ","")
            $folder = $folder.substring(0, [System.Math]::Min(100, $folder.Length))
            $folder = $folder.trim()
      
            if (-not (Test-Path $folder)) { 
                Write-Host "Folder $folder doesn't exist. Creating it..."  
                New-Item $folder -type directory 
            }
          
      
            # Make sure the video file doesn't already exist
            if (!(test-path "$folder\$file"))     
            {   
                # Echo out the  file that's being downloaded
                $file
              
                # Download the video file
                try{
                    if (!(test-path "$path\$file"))
                    {
                        Invoke-WebRequest $url -OutFile $path\$file
              
                        #move it from the current working folder to the target
                        mv $file $folder
                    }
                    else {
                        Write-Host "Video: $file - anoter process possibly working on this; skipping download."
                    }
                }
                catch {
                    $ErrorMessage = $_.Exception.Message
                    $FailedItem = $_.Exception.ItemName
                    Write-host "\t" $ErrorMessage + "\n" + $FailedItem
                }
            }
            else {
                Write-Host "Video: $file exist; skipping download."  
            }
          
        } #end-loop foreach
    } #end - video check
}
catch
{
    Write-host "Oops, could not find any videos or some other error happened."
    $ErrorMessage = $_.Exception.Message
    $FailedItem = $_.Exception.ItemName
    Write-host "\t" $ErrorMessage + "\n" + $FailedItem
} # ********** End - download the videos section **********
  
Write-host "*************** All Done! Woot! ***************"