Download Build deck and video (2018)

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.

# 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! ***************"

Author: Amit Bahree

This blog is my personal blog and while it does reflect my experiences in my professional life, this is just my thoughts. Most of the entries are technical though sometimes they can vary from the wacky to even political – however that is quite rare. Quite often, I have been asked what’s up with the “gibberish” and the funny title of the blog? Some people even going the extra step to say that, this is a virus that infected their system (ahem) well. [:D] It actually is quite simple, and if you have still not figured out then check out this link – whats in a name?

Leave a Reply

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