Delve logo

How to export your Delve blogs content?

This post was most recently updated on November 28th, 2019.

Reading Time: 4 minutes.

The news is out – Delve Blogs will be axed, leaving your users without a blogging platform on Office 365, and their data homeless. And by homeless, I mean deleted. Might be a good time to start thinking about storing it somewhere else instead!

This post is the second post in my impromptu, Delve Blogs -themed blog series:

While we’re all still waiting to see whether Microsoft sticks to their ambitious schedule (partial content freeze in December 2019, total content freeze in January 2020, and finally, total content deletion in April 2020), and whether they’ll finally offer a migration option or not, it probably doesn’t hurt to get ready for the move by yourself – so I’m offering one way to export the content from your tenant’s Delve blogs!

How to export Delve Blogs content

I crafted this handy little script for exporting the content as a CSV, and all of the used header pictures as separate images in the defined “temp folder”.

You can set the location for the exported CSV with all of the Delve blogs content as well. Authors of different blog posts will also be stored.

Just like described in my earlier post about Delve Blogs deprecation, the script is loosely based on Drew Madelung’s excellent script to report on Delve Blog usage.

You’ll need the following things to run this:

  • SharePointPnPPowershellOnline PowerShell module
  • At least SharePoint-admin credentials

PowerShell script to export Delve blogs’ content

 
function Make-ServerRelative ($path) {
    return $path.Substring($path.IndexOf("sharepoint.com/")+14)
}
 
try {
    # Variables for export
    $creds = Get-Credential
    $tenantadmin = "https://contoso-admin.sharepoint.com"
    $outputfilepath = "c:\temp\delveblogexport.csv"
    $tempfolder = "c:\temp"
 
    # Variables for modern blog creation
    $modernBlogUrl = "https://contoso.sharepoint.com/sites/blogposts"
 
    # Connect to tenant to get blog sites
    Connect-PnPOnline $tenantadmin -Credentials $creds
    $sites = Get-PnPTenantSite -Template POINTPUBLISHINGPERSONAL#0
 
    $resultsarray = @()
 
    # Loop through sites to get details for blog
    foreach($s in $sites){
        Connect-PnPOnline $s.Url -Credentials $creds
 
        $ctx = Get-PnPContext
 
        $list = Get-PnPList -Identity "Pages"
        $pagecount = $list.ItemCount
        $contributor = Get-PnPGroupMembers -Identity "Contributors" | select Email
 
        $items = Get-PnPListItem -List $list
        $ctx.ExecuteQuery();
 
        Write-Host "Exporting from: "$s.Url -ForegroundColor Yellow
 
        foreach($i in $items){     
            $ctx.Load($i)
            $ctx.Load($i.File)
            $ctx.ExecuteQuery()       
 
            $path = $s.Url + "/pPg/" + $i.File.Name
            $path = Make-ServerRelative $path
 
            Write-Host "Exporting page "$path
 
            $f = Get-PnPFile -Url $path -AsString
            $lastmodified = (Get-PnPFile -Url $path).TimeLastModified
 
            $o = ConvertFrom-Json $f
 
            $title = $o.Title
            $subTitle = $o.SubTitle
            $content = ""
            $filename = $i.File.Name
            $headerImage = ""
            $color = ""
 
            $listItem = Get-PnPListItem -List $list -Id $i.Id
 
            $ctx.Load($listItem)
            $ctx.ExecuteQuery()
 
            $listItem = $listItem.LastItemUserModifiedDate
 
            $props = $o.ControlData.psobject.properties.name
            $count = $props | measure-object
 
            for ($index = 0; $index -lt $count.Count; $index++) 
            {
                $propName = $props[$index]
 
                Write-Host "Exporting item: "$index" "$propName" of type " $o.ControlData.$propName.ControlType
 
                # Header content
                if ($o.ControlData.$propName.ControlType -eq 4) 
                { 
                    $content += "<h1>"+$o.ControlData.$propName.DataContext.Title+"</h1><h2>"+$o.ControlData.$propName.DataContext.Subtitle+"</h2>"
                    $headerImage = $o.ControlData.$propName.DataContext.ImageSource
                    continue; 
                }
 
                # Text content
                if ($o.ControlData.$propName.ControlType -eq 0) {
                    $content += $o.ControlData.$propName.DataContext.Value
                }
 
                # Picture content
                if ($o.ControlData.$propName.ControlType -eq 1) {
                    $content += "<img src='"+$o.ControlData.$propName.DataContext.ImageSource+"' /><caption>"+$o.ControlData.$propName.DataContext.CaptionText+"</caption>"
                }
 
                # Document content
                if ($o.ControlData.$propName.ControlType -eq 8) {
                    $content += "<a href='"+$o.ControlData.$propName.DataContext.OfficeDocumentDataContext.DocPath+"'>"+$o.ControlData.$propName.DataContext.Annotation+"</a>"
                }
 
                # Video content
                if ($o.ControlData.$propName.ControlType -eq 9) {
                    $content += "<a href='"+$o.ControlData.$propName.DataContext.VideoSource+"'><caption><img src='"+$o.ControlData.$propName.DataContext.ImageSource+"' />"+$o.ControlData.$propName.DataContext.CaptionText+"</caption></a>"
                }
            }
 
            if ($null -ne $headerImage -and $headerImage.IndexOf('#') -ge 0) 
            {
                $color = $headerImage
            }
            else 
            {
                try 
                {
                    $serverRelativeImageHeaderUrl = Make-ServerRelative $headerImage
                    $imgFile = Get-PnPFile -Url $serverRelativeImageHeaderUrl
 
                    Get-PnPFile -Url $serverRelativeImageHeaderUrl -Path $tempfolder -AsFile
                }
                catch {
                    Write-Host "There was likely no header image present, so couldn't export it."
                }
            }
 
            # Add to the export object
            $obj = New-Object PSObject
            Add-Member -InputObject $obj -MemberType NoteProperty -Name DelveBlogUrl -Value $s.Url
            Add-Member -InputObject $obj -MemberType NoteProperty -Name BlogPageCount -Value $pagecount
            Add-Member -InputObject $obj -MemberType NoteProperty -Name Email -Value $contributor.Email
            Add-Member -InputObject $obj -MemberType NoteProperty -Name LastModified -Value $lastmodified
            Add-Member -InputObject $obj -MemberType NoteProperty -Name Title -Value $title
            Add-Member -InputObject $obj -MemberType NoteProperty -Name Subtitle -Value $subTitle
            Add-Member -InputObject $obj -MemberType NoteProperty -Name HeaderImage -Value $headerImage
            Add-Member -InputObject $obj -MemberType NoteProperty -Name Content -Value $content
            Add-Member -InputObject $obj -MemberType NoteProperty -Name FileName -Value $filename
            Add-Member -InputObject $obj -MemberType NoteProperty -Name HeaderFile -Value $imgFile.Name
            Add-Member -InputObject $obj -MemberType NoteProperty -Name ThemeColor -Value $color
 
            $resultsarray += $obj
            $obj = $null
        }
    }
    # Export results
    $resultsarray | Export-Csv -Path $outputfilepath -NoTypeInformation -Force
 
    Write-Host "Export Complete" -ForegroundColor Green
    Disconnect-PnPOnline
}
catch
{
    Write-Host $_.Exception.Message -ForegroundColor Red
}

It’s not super pretty, but at least it’s modifiable. Feel free to tweak to your needs!

What’s next?

Tomorrow, I’ll be posting about importing this content into Modern SharePoint Communication site as new articles with (somewhat) matching styling.

Antti K. Koskela

Antti Koskela is a proud digital native nomadic millennial full stack developer (is that enough funny buzzwords? That's definitely enough funny buzzwords!), who works as a Solutions Architect for Valo Intranet, the product that will make you fall in love with your intranet. Working with the global partner network, he's responsible for the success of Valo deployments happening all around the world.

He's been a developer from 2004 (starting with PHP and Java), and he's been bending and twisting SharePoint into different shapes since MOSS. Nowadays he's not only working on SharePoint, but also on .NET projects, Azure, Office 365 and a lot of other stuff.

This is his personal professional (e.g. professional, but definitely personal) blog.
mm

Leave a Reply

avatar
5000
  Subscribe  
Notify of