Delve logo

How to export your Delve blogs content?

This post was most recently updated on September 17th, 2020.

3 min read.

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.

mm
0 0 votes
Article Rating
Subscribe
Notify of
guest

1 Comment
most voted
newest oldest
Inline Feedbacks
View all comments