Monday, December 30, 2019

Convert (archive) SharePoint Pages to PDF

Problem-Scenario:

During our SharePoint 2010  to SharePoint Online migration, i was asked to archive around 1000+ article pages (used as company newsletters) as PDF and store in SharePoint Online site. If i could archive those pages as PDF, there was no need to keep all those sites. So it was also a good opportunity to cleanup our environment before migration

Solution:
First thing that came to my mind was to print from Internet Explorer but the results were horrendous. It would take 7-8 pages to print one article page.
I searched for third party tools and found PDFCreator and WkhtmltoPdf tools.
Option 1) automating using wkhtmltopdf tool
Observation:
  1. links are clickable
  2. banner is coming
  3. photos are not coming in most cases
  4. colors were better than option 2)
  5. Takes 6-7 pages to print one sharepoint article page

Option 2) automating using PDFCreator + Powershell
Observation:
a.       links are showing up but aren't clickable
b.       banner is not coming
c.       photos are coming
d.   Takes 6-7 pages to print one sharepoint article page

Still both the above options were taking few pages to print just one article page. This wasn't ideal since users won't be able to make any sense out of reading these PDFs. I had to come up with something better. Thanks to Stackexchange site, i read about a post asking to try command line of chrome.
To test, I tried printing using chrome and it works perfectly. It takes only one page to print one article page, has better colors, all links are clickable, all images gets printed.

Using the headless and disabling GPU options did the trick.

This obviously needs Chrome browser to be installed on the server. Since i wasn't allowed to install Chrome on the SharePoint server, i copied the Google folder from my desktop-program files and pasted it on SP server. That was all it took to make the command work. In the powershell, you have to mention the path to chrome.exe as you will see in the code below:


# This script is intended to work on SharePoint 2010. For higher versions,
# just use CSOM
# Load Microsoft.SharePoint
# Open your SharePoint web
[void][System.reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint") 
$site = new-object Microsoft.SharePoint.SPSite("http://your absolute sharepoint 2010 web Url where newsletters/article pages reside")                                                        
$web = $site.openweb()
write-host $web.Title
# Get all publishing pages
# Since there were folders in library, i added Scope=Recursive
$pubweb = [Microsoft.SharePoint.Publishing.PublishingWeb]::GetPublishingWeb($web)
$query = new-object Microsoft.SharePoint.SPQuery 
$query.ViewAttributes = "Scope='Recursive'"
$pages = $pubweb.GetPublishingPages($query)    

write-host 'no of pages ' $pages.count   
    
# Loop through pages

# $newslettername: i kept it same as file name
#    Remove .aspx and change extension to .pdf
#    this also contains the desktop path where pdf will be saved
foreach ($listItem in $pages)
{
    $newslettername = ''
    $pageurl = ''
    
    $pageurl = $listItem.uri.AbsoluteUri
    
    if($pageurl -Match 'templates') {
       $newslettername = 'c:\temp\newsletters\templates\' + $listItem.name + '.pdf'    
    }
    else {   
    $newslettername = 'c:\temp\newsletters\' + $listItem.name + '.pdf'    
    }
    
    $newslettername = $newslettername -replace '.aspx',''  
    
# Give full path to chrome.exe

# Run the command for converting .aspx page i.e. newsletter i.e. article page to PDF
F:\shishir\Google\Chrome\Application\chrome.exe --headless --disable-gpu --print-to-pdf=$newslettername $pageurl

    write-host 'printed the page at' $pageurl
}
$web.Dispose()
$site.Dispose()  

Wednesday, August 14, 2019

Azure Devops Automate building of SharePoint Apps

Problem-Scenario:

In Azure Devops there are .net related templates available for use in build definition but there isn't anything available for building SharePoint apps

Solution:
There isn't an inbuilt template available for building SharePoint apps. So i had improvise.

After trying different options, I was able to use yml code to build pipeline for SharePoint hosted apps. 
There aren’t any inbuilt templates available for SP hosted apps.

Background: 
Our sharepoint hosted app's source code is stored in azure Repos. Repo is used as an input to build pipeline. Use minimal starter yml and then update based on the information in this blog.

Below are the main steps to remember:
Also attached is the complete yaml file at the end

Trigger

 
You can mention committing to which branch will trigger the build pipeline. You can also configure it to exclude some branches or sub-branches.


Build SP Hosted app


Ignore the script step. This just displays the internal location of directories.

Used MSBuild to build our SharePoint app Repo and output .APP file


Copy files to artifact staging directory





Copies the output for publishing
FlattenFolders: true --> Flattens the folder structure
Contents: 'app.publish/**/*.app' --> filters *.app file


Publishing the artifact









Where does the artifacts go? Or how to access it?

Open build result & look at snapshot below:





The folder structure can be changed if needed.

This is saved for each build that is run and is retained as per our retention policy.

This artifact, in turn, will directly consumed by RELEASE pipeline which can either be triggered automatically or manually.



Below is the entire .yml file for your ease of use.


# Starter pipeline
# Start with a minimal pipeline that you can customize to build and deploy your code.
# Add steps that build, run tests, deploy, and more:
# https://aka.ms/yaml

trigger:
- master


pool:
vmImage: 'windows-latest'

variables:
solution: '**/*.sln'
buildPlatform: 'Any CPU'
buildConfiguration: 'Release'

steps:
- script: echo Hello, world!DA1S $(Build.SourcesDirectory) and agent da1 is $(Agent.BuildDirectory) AND $(System.DefaultWorkingDirectory)/bin/
displayName: 'Run a one-line script'

- task: MSBuild@1
inputs:
solution: '$(solution)'
msbuildArguments: '/t:Package /p:OutputPath=$(Build.SourcesDirectory)/bin/'
platform: '$(buildPlatform)'
configuration: '$(buildConfiguration)'
- task: CopyFiles@2
inputs:
SourceFolder: '$(Build.SourcesDirectory)/bin/'
Contents: '**'
TargetFolder: '$(Build.ArtifactStagingDirectory)'
- task: PublishBuildArtifacts@1
inputs:
ArtifactName: 'drop'
PathtoPublish: '$(Build.SourcesDirectory)/bin/'