Promoting and Demoting Site pages to News in Modern SharePoint Sites using SPFx extension and Azure Function

The requirement that I will be addressing in this blog is how to Promote and Demote site pages to news articles in Modern SharePoint sites. This approach allows us to promote any site page to News, add approval steps and demote news articles to site pages if the news need to be updated. The news also shows in the modern news web part when the site page is promoted.

Solution Approach:

To start with, create a site page. For creating a Modern page using Azure Function, please refer to this blog. After the site page is created, we will be able to use a status column to track the news status and promote a site page to news status. The status column could have three values – draft, pending approval and published.

We will use a SPFx extension to set the values of the status column and call the Azure Function to promote the site page to news page using SharePoint Online CSOM.

Promoting a site page to news page

Below are the attributes that need to be set for site pages to promote as news article.

1. Promoted State Column set to 2 – set through SPFx extension
2. First Published date value set to published date – set through SPFx extension
3. Promoted state tag in the news site page to be set to value 2 – done in Azure Function
4. Site page needs to be published – done in Azure Function

For a detailed walkthrough on how to create a custom site page with metadata values, please refer to this blog. In order to set the values of ‘Promoted State’ and ‘First Published Date’ metadata values, use the below code after the page is created.

For calling Azure Function from SPFx extension, which will promote the site page to news, can be done using the below method.

Inside the Azure Function, use the below to promote a site page to news article.

Demoting a news to site page

Below are the attributes that needs to be set for demoting a news article to site page

1. Promoted State Column set to 0 – set through SPFx extension
2. First Published date value set to blank – set through SPFx extension
3. Promoted state tag in the news site page to be set to value 0 – done in Azure Function
4. Site page needs to be published – done in Azure Function

For setting the metadata values, the method calls as done above during promotion of site page, can be used. Next in Azure Function, use the below to demote a site page.

Conclusion:

Hence above we saw how we can use SPFx extension and Azure Function to promote and demote site pages to news articles in Modern SharePoint sites.

Creating SharePoint Modern Team sites using Site Scripts, Flow and Azure Function

With Site Scripts and Site design, it is possible to invoke custom PnP Provisioning for Modern Team Sites from a Site Script. In the previous blog, we saw how we can provision Simple modern sites using Site Scripts JSON. However, there are some scenarios where we would need a custom provisioning template or process such as listed below:

  • Auto deploy custom web components such as SPFx extension apps
  • Complex Site Templates which couldn’t be configured
  • Complex Document libs, content types that are provided by JSON schema. For an idea of support items using the OOB schema, please check here.

Hence, in this blog, we will see how we can use Flow and Azure Functions to apply more complex templates and customization on SharePoint Modern Sites.

Software Prerequisites:

  • Azure Subscription
  • Office 365 subscription or MS Flow subscription
  • PowerShell 3.0 or above
  • SharePoint Online Management Shell
  • PnP PowerShell
  • Azure Storage Emulator*
  • Postman*

* Optional, helpful for Dev and Testing

High Level Overview Steps:

1. Create an Azure Queue Storage Container
2. Create a Microsoft Flow with Request Trigger
3. Put an item into Azure Queue from Flow
4. Create an Azure Function to trigger from the Queue
5. Use the Azure Function to apply the PnP Provisioning template

Detailed Steps:

This can get quite elaborate, so hold on!!

Azure

1. Create an Azure Queue Store.

Note: For dev and testing, you can use the Azure Storage Emulator to emulate the queue requirements. For more details to configure Azure Emulator on your system, please check here.

Microsoft Flow

2. Create a Microsoft Flow with Request trigger and then add the below JSON.

Note: If you have an Office 365 enterprise E3 license, you get a Flow Free Subscription or else you can also register for a trial for this here.

3. Enter a message into the Queue in the Flow using the “Add message to Azure Queue” action.

FlowSiteDesignAzureQueue

Note: The flow trigger URL has an access key which allows it to be called from any tenant. For security reasons, please don’t share it with any third parties unless needed.

Custom SharePoint Site Template (PowerShell)

4. Next create a template site for provisioning. Make all the configurations that you will need for the initial implementation. Then create the template using PnPPowerShell, use the PnP Provisioning Command as shown below.

Get-PnPProvisioningTemplate -Out .\TestCustomTeamTemplate.xml -ExcludeHandlers Navigation, ApplicationLifecycleManagement -IncludeNativePublishingFiles

Note: The ExclueHandlers option depends on your requirement, but the configuration in the above command will save a lot of issues which you could potentially encounter while applying the template later. So, use the above as a starting template.

Note: Another quick tip, if you have any custom theme applied on the template site, then the provisioning template doesn’t carry it over. You might have to apply the theme again!

5. Export and save the PowerShell PnP Module to a local drive location. We will use it later in the Azure Function.

powershell Save-Module -Name SharePointPnPPowershellOnline -Path “[Location on your system or Shared drive]”

SharePoint
6. Register an App key and App Secret in https://yourtenant.sharepoint.com/_layouts/appregnew.aspx and provide the below settings.
7. Copy the App Id and Secret which we will use later for Step 9 and 10. Below is a screenshot of the App registration page.
8. Trust the app at https://yourtenant-admin.sharepoint.com/_layouts/appinv.aspx by providing the below xml. Fill in the App Id to get the details of the App.

Azure Function

9. Create a Queue Trigger PowerShell Azure function
10. After the function is created, go to Advance Editor (kudu) and then create a sub folder “SharePointPnPPowerShellOnline” in site -> wwwroot -> [function_name] -> modules. Upload all the files from the saved PowerShell folder in the Step above into this folder.
11. Add the below PowerShell to the Azure Function

12. Test the Function by the below input in PowerShell

$uri = "[the URI you copied in step 14 when creating the flow]"
$body = "{webUrl:'somesiteurl'}"
Invoke-RestMethod -Uri $uri -Method Post -ContentType "application/json" -Body $body

PowerShell and JSON

13. Create a Site Script with the below JSON and add it to a Site Design. For more details, please check the link here for more detailed steps.

14. After the above, you are finally ready to run the provisioning process. Yay!!

But before we finish off, one quick tip is that when you click manual refresh, the changes are not immediately updated on the site. It may take a while, but it will apply.

Conclusion:

In the above blog we saw how we can create Site templates using custom provisioning template by Flow and Azure Function using SharePoint site scripts and design.

Microsoft Teams Q&A

This page is a collection of Microsoft Teams and Skype for Business related questions and answers. It’s regularly updated as more information becomes available.

Microsoft Teams Q&A – Last Updated: 15th March 2018

Q: What is Microsoft Teams?

A: Microsoft Teams is a complete communications platform, that takes the best bits of Skype for Business, Yammer, SharePoint, Email and other web sources and presents them in one easy to use application. You can send IM’s, make voice and video calls, phone calls, Share documents, and collaborate all from within the one application.

Q: How do I get Microsoft Teams?

A: Simple! Sign up for an Office 365 plan over at http://www.office.comIf you’re already an Office 365 subscriber, check to see if Teams is available – it more than likely is!

Q: We currently use Skype for Business and Yammer. Should we make the switch to Teams?

A: Yes, but gradually. At some point in the future, Microsoft Teams will likely completely replace Skype for Business online from Office 365 (on premise versions of Skype are safe for now). It’s wise to start evaluating Teams now so that you can familiarize and prepare yourself once your organisation moves across.

You can also check out this short video on the subject of Yammer and Teams.

Q: We currently use Slack, and our devs aren’t going to want to give up slack easily.

A: Sure, change is scary. However, the ability to collaborate so simply in multiple ways within Teams makes it the ideal platform for dev teams to effectively work on. Give it a go!

Q: What about the investments we have made in Skype for Business hardware (phones, meeting room devices) and licensing?

A: Vendors are working hard to ensure their devices are compatible with Microsoft Teams. Right now, if the device is a year or two old and works with Skype for Business, there’s a good chance that with a firmware update from the manufacturer, it’ll work with Teams too.

Q: Are we able to develop custom applications for Teams?

A: Absolutely! There’s an entire section dedicated to creating custom applications for Microsoft Teams over at https://docs.microsoft.com/en-us/microsoftteams/platform/#pivot=home&panel=home-all

Q: I want to be able to send an SMS from Teams

A: Sure. You could write a custom application!

Q: Teams to Standard SIP video InterOP, will there be a open API available to develop one?
or should we depend on the Teams Partnered service providers only?

A: My understanding is that right now there’s only Teams/Skype integration. Whether that will change is a great question. Keep your eyes peeled on the Office 365 Roadmap.

Q: Will Teams support open Federation with other (on-premise or 3rd-party hosted) Skype for Business deployments?

A: Federated communication between other teams and Skype for business environments is on the Office 365 road map (https://products.office.com/en-us/business/office-365-roadmap?filters=#abc) and is currently in development.

Q: Should I be able to copy and paste Screenshots into the Wiki Feature? They keep disappearing.

A: From my testing, I am able to copy and paste screenshots that I took with the snipping tool in Windows into Wiki pages, and they remain in place.

Q: Am I able to invite people from other organisations into Teams chats, file sharing and other things?

A: Yes! Microsoft recently announced that guest access in Microsoft Teams is now fully rolled out, meaning you can now invite anyone into a Microsoft Teams team to chat, share files and more!

 

Do you have a question about Skype or Teams? Leave a comment below or tweet @cchiffers

Create Modern Pages and update metadata using SPFx Extensions, SP PnP JS and Azure Functions

Modern Site Pages (Site Page content type) have a constraint to associate custom metadata with it. In other words, the “Site Page” content type cannot have other site columns added to it as can be seen below.

SitePageContentTypeMissing

On another note, even though we can create a child content types from Site Page content type, the New Site page creation (screenshot below) process doesn’t associate the new content type when the Page is created. So, the fields from the child content type couldn’t be associated.

For eg. In the below screenshot, we have created a new site page – test.aspx using “Intranet Site Page Content Type” which is a child of “Site Page” content type. After the page is created, it gets associated to Site Page Content type instead of Intranet Site Page Content type. We can edit it again to get it associated to Intranet Page content type but that adds another step for end users to do and added training effort.

 

 

 

Solution Approach:

To overcome the above constraints, we implemented a solution to associate custom metadata into Modern Site Pages creation using SharePoint Framework (SPFx) List View Command Set extension and Azure Function. In this blog, I am going to briefly talk about the approach so it could be useful for anyone trying to do the same.

1. Create a List View Command Item for creating site pages, editing properties of site pages and promoting site pages to news
2. Create an Azure function that will create the Page using SharePoint Online CSOM
3. Call the Azure Function from the SPFx command.

A brief screenshot of the resulting SPFx extension dialog is below.

NewSitePage

Steps:

To override the process for modern page creation, we will use an Azure Function with SharePoint Online PnP core CSOM. Below is an extract of the code for the same. On a broad level, the Azure Function basically does the following

1. Get the value of the Site Url and Page name from the Query parameters
2. Check if the Site page is absent
3. Create the page if absent
4. Save the page

Note: The below code also includes the code to check if the page exists.

Next, create a SPFx extension list view command and SP dialog component that will allow us to call the Azure Function from Site Pages Library to create pages. The code uses ‘fetch api’ to call the Azure Function and pass the parameters for the Site Url and page name required for the Azure Function to create the page. After the page is created, the Azure function will respond with a success status, which can be used to confirm the page creation.

Note: Make sure that the dialog is locked while this operation is working. So, implement the code to stop closing or resubmitting the form.

After the pages are created, lets update the properties of the item using PnP JS library using the below code.

Conclusion:

As we can see above, we have overridden the Page Creation process using our own Azure Function using SPFx List View command and PnP JS. I will be detailing the SP dialog for SPFx extension in another upcoming blog, so keep an eye for it.

There are still some limitations of the above approach as below. You might have to get business approval for the same.

1. Cannot hide the out of the box ‘New Page’ option from inside the extension.
2. Cannot rearrange order of the Command control and it will be displayed at last to the order of SharePoint Out of the box elements.

Update Managed Metadata and Hyperlink column in a SharePoint list using PnP PowerShell

If you are trying to update a Managed Metadata and Hyperlink column in SharePoint online using PnP PowerShell and it is not getting updated, then this blog might be of help.

I had been working on a quick requirement for updating Managed Metadata columns using a PowerShell script for a bulk update requirement and it was not working as planned. The managed metadata column we were updating didn’t have the right format of Term store hierarchy and this was the cause of the issue.

Managed Metadata

The Managed Metadata termstore format below, will not work if anything is missed in the hierarchy or symbols.

$val = "Group|TermSet|Term1|Term2..."

So for eg. Your group is “Test Group” with Termset “Test Termset1” with Level 1 Term “Parent” and Level 2 Term “Child”, then the value is:

$val = "Test Group|Test Termset1|Parent|Child"

The update command in PnP Powershell will be:

Set-PnPListItem -List "[Lib Name]" -Identity [ItemID] -Values  @{"Managed Metadata Column" = $val}

Hyperlink

This one was amusing because I didn’t see the mistake till I realised that strings are not comma delimited, but space delimited! 🙂

HyperlinkImage

The format for updating a hyperlink is below. Notice the space after the comma (,) it is very important to get this right.

Set-PnPListItem -List "[Lib Name]" -Identity [ItemID] -Values  @{"Hyperlink Column" = $val}

Conclusion

So above we saw how we can update Managed Metadata and Hyperlink columns using PnP PowerShell.

Intro to Site Scripts and Site Designs with a Simple SharePoint Modern Site provisioning

Microsoft announced Site Scripts and Site Designs in late 2017 which became available for Targeted release in Jan 2018, and released to general use recently. It is a quick way to allow users to create custom modern sites, without using any scripting hacks. Hence, in this blog we will go through the steps of Site Scripts and Site design for a Simple SharePoint Modern Site Creation.

Before we get into detailed steps, lets’ get a brief overview about Site Designs and Site Scripts.

Site designs: Site designs are like a template. They can be used each time a new site is created to apply a consistent set of actions. You create site designs and register them in SharePoint to one of the modern template sites: the team site, or communication site. A site design can run multiple scripts. The script IDs are passed in an array, and they will run in the order listed.

Site Scripts: Site script is custom JSON based script that runs when a site design is selected. The site scripts detail the provisioning items such as creating new lists or applying a theme. When the actions in the scripts are completed, SharePoint displays detailed results of those actions in a progress pane. They can even call flow trigger that is essential for site creation.

Software Prerequisites:

  1. PowerShell 3.0 or above
  2. SharePoint Online Management Shell
  3. Notepad or any notes editor for JSON creation – I prefer Notepad++
  4. Windows System to run PowerShell
  5. And a must – SharePoint Tenant J

 Provisioning Process Overview:

The Provisioning process is divided into 4 steps

1. Create a Site Script using JSON template to call actions to be run after a Modern Site is created.
2. Add the Script to your tenant
3. Create a Site Design and add the Site Script to the design. Associate the Site Design to Modern Site Templates – Team Site template is 64 and Communication Site Template is 68
4. Create a Modern Site from SharePoint landing page
5. Wait for the Site Script to apply changes and refresh your site

Quick and Easy right!? Now lets’ get to the “how to”.

Steps

1. JSON Template: We will need to create a JSON template that will have the declarations of site resources that will be provisioned after the site is created. For more details, here is a link to Microsoft docs. The brief schema is below.

{
"$schema": "schema.json",
"actions": [
... [one or more verb   actions]  ...
],
"bindata": { },
"version": 1
};

For our blog here, we will use the below schema where we are creating a custom list with few columns.

2. Site Script: Add the above site script to your tenant using PowerShell. The below code with return the Site Script GUID. Copy that GUID and will be used later

Get-Content '[ JSON Script location ]' -Raw | Add-SPOSiteScript -Title “[ Title of the script ]

3. Site Design: After the Site Script is added, create the Site Design from the Site Script to be added to the dropdown menu options for creating the site.

Add-SPOSiteDesign -Title “[ Site design title ]” -WebTemplate "64"  -SiteScripts “[ script GUID from above step ]”  -Description "[ Description ]"

4. Create a Modern Site: After the Site Design is registered, you could see the design while creating a site as shown below

ModernTeamSiteWIthcustom

5. Click on the Manual Refresh button as per screenshot after the site upgrade process is complete.

SiteScriptFinish

When ready, the final Team site will look like the screenshot below after provisioning is complete.

CustomTeamSiteWithScriptResult

In this blog, we came to know about Site Script, Site design and how to use them to provision modern team sites.

Migrate SharePoint contents using ShareGate

Background

The first step in any migration project is to do the inventory and see what is the size of the data you have got which you are looking to migrate. For the simplicity, this post assumes you have already done this activity and have already planned new destination sites for your existing content. This means you have some excel sheet somewhere to identify where your content is going to reside in your migrated site and every existing site (in scope) have got at least a new home pointer if it qualifies for migration.

The project I was working on had 6 level of sites and subsites within a site collection, for simplicity we just consider one site collection in scope for this post and had finalised it will have max. 3 levels of site and a subsite initially after discussing it with business.

In this blog post, we will be migrating SharePoint 2010 and 2013 contents from on-premise to SharePoint Online (SPO) in our customer’s Office 365 tenant.

Creating Structure

After doing the magic of mapping an existing site collection, site and subsites; we came up with an excel sheet to have the mapping for our desired structure as shown below:

Level1.csv

Level2.csv

Level3.csv

The above files will be used as a reference master sheet to create site structure before pulling the trigger for migrating contents. We will be using PowerShell script below to create the structure for our desired state within our new site collection.

SiteCreation.ps1

$url = "https://your-client-tenant-name.sharepoint.com/"

function CreateLevelOne(){
    Connect-PnPOnline -Url $url -Credentials 'O365-CLIENT-CREDENTIALS'

    filter Get-LevelOne {
        New-PnPWeb -Title $_.SiteName -Url $_.URL1 -Template BLANKINTERNETCONTAINER#0 -InheritNavigation -Description "Site Structure created as part of Migration"
    }

    Import-Csv C:\_temp\Level1.csv | Get-LevelOne
}

function CreateLevelTwo(){

    filter Get-LevelTwo {
        $connectUrl = $url + $_.Parent

        Connect-PnPOnline -Url $connectUrl -Credentials 'O365-CLIENT-CREDENTIALS'
        New-PnPWeb -Title $_.SiteName -Url $_.URL2 -Template BLANKINTERNETCONTAINER#0 -InheritNavigation -Description "Site Structure created as part of Migration"
    }

    Import-Csv C:\_temp\Level2.csv | Get-LevelTwo
}

function CreateLevelThree(){

    filter Get-LevelThree {
        $connectUrl = $url +  $_.GrandPrent + '/' + $_.Parent 

        Connect-PnPOnline -Url $connectUrl -Credentials 'O365-CLIENT-CREDENTIALS'
        New-PnPWeb -Title $_.SiteName -Url $_.URL3 -Template BLANKINTERNETCONTAINER#0 -InheritNavigation -Description "Site Structure created as part of Migration"
    }

    Import-Csv C:\_temp\Level3.csv | Get-LevelThree
}

CreateLevelOne

CreateLevelTwo

CreateLevelThree

Migrating Contents

Once you have successfully created your site structure, this is the time now to start migrating contents to the newly created structure as per the mapping you have identified earlier. CSV file format looks like below:

MG-Batch.csv

Final step is to execute PowerShell script and migrate content using ShareGate commands from your source site to your destination site (as defined in your mapping file above)

Migration-ShareGate.ps1

<span id="mce_SELREST_start" style="overflow:hidden;line-height:0;"></span># folder where files will be produced
$folderPath = "C:\_Kloud\SGReports\"
$folderPathBatches = "C:\_Kloud\MigrationBatches\"

filter Migrate-Content {
    # URLs for source and destination
    $urlDes = $_.DesintationURL
    $urlSrc = $_.SourceURL 

    # file where migration log will be added again each run of this script
    $itemErrorFolderPath = $folderPath + 'SG-Migration-Log-Webs.csv'

    # migration settings used by ShareGate commands
    $copysettings = New-CopySettings -OnContentItemExists IncrementalUpdate -VersionOrModerationComment "updated while migration to Office 365" 

    # 

    $pwdDest = ConvertTo-SecureString "your-user-password" -AsPlainText -Force
    $siteDest = Connect-Site -Url $urlDes -Username your-user-name -Password $pwdDest

    $listsToCopy = @() 

    $siteSrc = Connect-Site -Url $urlSrc

    $listsInSrc = Get-List -Site $siteSrc 

    foreach ($list in $listsInSrc)
    {
        if ($list.Title -ne "Content and Structure Reports" -and
            $list.Title -ne "Form Templates" -and
            $list.Title -ne "Master Page Gallery" -and
            $list.Title -ne "Web Part Gallery" -and
            $list.Title -ne "Pages" -and
            $list.Title -ne "Style Library" -and
            $list.Title -ne "Workflow Tasks"){

            $listsToCopy += $list
        }
    }

    # building a log entry with details for migration run

    $date = Get-Date -format d
    $rowLog = '"' + $siteSrc.Address + '","' + $siteSrc.Title + '","' + $listsInSrc.Count + '","' +  $siteDest.Address + '","' +  $siteDest.Title + '","' + $listsToCopy.Count + '","' + $date + '"'
    $rowLog | Out-File $itemErrorFolderPath -Append -Encoding ascii

    Write-Host Copying $listsToCopy.Count out of $listsInSrc.Count lists and libraries to '('$siteDest.Address')'
    #Write-Host $rowLog

    $itemLogFolderPath = $folderPath + $siteSrc.Title + '.csv'
    #Write-Host $itemLogFolderPath

    $result = Copy-List -List $listsToCopy -DestinationSite $siteDest -CopySettings $copysettings -InsaneMode -NoCustomPermissions -NoWorkflows
    Export-Report $result -Path $itemLogFolderPath
}

function Start-Migration($batchFileName)
{
    $filePath = $folderPathBatches + $batchFileName

    Import-Csv $filePath | Migrate-Content
}

Start-Migration -batchFileName "MG-Batch.csv"
<span id="mce_SELREST_start" style="overflow:hidden;line-height:0;"></span>

Conclusion

In this blog post, we had used a silent mode of ShareGate using which we can run in parallel multiple migration jobs from the different workstations (depending on your ShareGate licensing).

For a complete list of ShareGate PowerShell commands, you can refer a list at URL.

I hope you have found this post useful to create a site structure and migrate contents (list/libraries) to content’s new home inside SharePoint Online.

Writing for the Web – that includes your company intranet!

You can have a pool made out of gold – if the water in it is as dirty and old as a swamp- no one will swim in it!

The same can be said about the content of an intranet. You can have the best design, the best developers and the most carefully planned out navigation and taxonomy but if the content and documents are outdated and hard to read, staff will lose confidence in its authority and relevance and start to look elsewhere – or use it as an excuse to get a coffee.

The content of an intranet is usually left to a representative from each department (if you’re lucky!) Usually people that have been working in a company for years. Or worse yet, to the IT guy. They are going to use very different language to a new starter, or to a book keeper, or the CEO. Often content is written for an intranet “because it has to be there” or to “cover ourselves” or because “the big boss said so” with no real thought into how easy it is to read or who will be reading it.

adaptive

Content on the internet has changed and adapted to meet a need that a user has and to find it as quickly as possible. Why isn’t the same attitude used for your company? If your workers weren’t so frustrated finding the information they need to do their job, maybe they’d perform better, maybe that would result in faster sales, maybe investing in the products your staff use is just as important as the products your consumers use.

I’m not saying that you have to employ a copywriter for your intranet but at least train the staff you nominate to be custodians of your land (your intranet- your baby).

Below are some tips for your nominated content authors.

The way people read has changed

People read differently thanks to the web. They don’t read. They skim.

  • They don’t like to feel passive
  • They’re reluctant to invest too much time at one site or your intranet
  • They don’t want to work for the information

People DON’T READ MORE because

  • What they find isn’t relevant to what they need or want.
  • They’re trying to answer a question and they only want the answer.
  • They’re trying to do a task and they only want what’s necessary.

Before you write, identify your audience

People come to an intranet page with a specific task in mind. When developing your pages content, keep your users’ tasks in mind and write to ensure you are helping them accomplish those tasks.  If your page doesn’t help them complete that task, they’ll leave (or call your department!)

Ask these questions

  • Who are they? New starters? Experienced staff? Both? What is the lowest common denominator?
  • Where are they? At work? At home? On the train? (Desktop, mobile, laptop, ipad)
  • What do they want?
  • How educated are they? Are they familiar with business Jargon?

Identify the purpose of your text

As an intranet, the main purpose is to inform and educate. Not so much to entertain or sell.

When writing to present information ensure:

  • Consistency
  • Objectivity
  • Consider tables, diagrams or graphs

Structuring your content

Headings and Sub headings

Use headings and sub headings for each new topic. This provides context and informs readers about what is to come. It provides a bridge between chunks of content.

Sentences and Paragraphs

Use short sentences. And use only 1-3 sentences per paragraph.

‘Front Load’ your sentences. Position key information at the front of sentences and paragraphs.

Chunk your text. Break blocks of text into smaller chunks. Each chunk should address a single concept. Chunks should be self-contained and context-independent.

Layering vs scrolling

It is OK if a page scrolls. It just depends how you break up your page! Users’ habits have changed in the past 10 years due to mobile devices, scrolling is not a dirty word, as long as the user knows there’s more content on the page by using visual cues.

phone.png

Use lists to improve comprehension and retention

  • Bullets for list items that have no logical order
  • Numbered lists for items that have a logical sequence
  • Avoid the lonely bullet point
  • Avoid death by bullet point

General Writing tips

  • Write in plain English
  • Use personal pronouns. Don’t say “Company XYZ prefers you do this” Say “We prefer this”
  • Make your point quickly
  • Reduce print copy – aim for 50% less copy than what you’d write for print
  • Be objective and don’t exaggerate
  • USE WHITE SPACE – this makes content easier to scan, and it is more obvious to the eye that content is broken up into chunks.
  • Avoid jargon
  • Don’t use inflated language

Hyperlinks

  • Avoid explicit link expressions (eg. Click here)
  • Describe the information readers will find when they follow the link
  • Use VERBS (doing word) as links.
  • Warn users of a large file size before they start downloading
  • Use links to remove secondary information from the bulk of the text (layer the content)

Remove

  • Empty words and phrases
  • Long words or phrases that could be shorter
  • Unnecessary jargon and acronyms
  • Repetitive words or phrases
  • Adverbs (e.g., quite, really, basically, generally, etc.)

Avoid Fluff

  • Don’t pad write with unnecessary sentences
  • Stick to the facts
  • Use objective language
  • Avoid adjectives, adverbs, buzzwords and unsubstantiated claims

Tips for proofreading

  1. Give it a rest
  2. Look for one type of problem at a time
  3. Double-check facts, figures, dates, addresses, and proper names
  4. Review a hard copy
  5. Read your text aloud
  6. Use a spellchecker
  7. Trust your dictionary
  8. Read your text backwards
  9. Create your own proofreading checklist
  10. Ask for help!

A Useful App

Hemingwayapp.com assesses how good your content is for the web.

A few examples (from a travel page)

Bad Example

Our Approved an​​​d Preferred Providers

Company XYZ has contracted arrangements with a number of providers for travel.  These arrangements have been established on the basis of extracting best value by aggregating spend across all of Company XYZ.

Why it’s Bad

Use personal pronouns such as we and you, so the user knows you are talking to them. They know where they work. Remove Fluff.

Better Example

Our Approved an​​​d Preferred Providers

We have contracted arrangements with a number of providers for travel to provide best value

Bad Example

Travel consultant:  XYZ Travel Solutions is the approved provider of travel consultant services and must be used to make all business travel bookings.  All airfare, hotel and car rental bookings must be made through FCM Travel Solutions

Why it’s bad

The author is saying the same thing twice in two different ways. This can easily be said in one sentence.

Better Example

Travel consultant

XYZ Travel Solutions must be used to make all airfare, hotel and car rental bookings.

Bad Example

Qantas is Company XYZ preferred airline for both domestic and international air travel and must be used where it services the route and the “lowest logical fare” differential to another airline is less than $50 for domestic travel and less than $400 for international travel

Why it’s bad

This sentence is too long. This is a case of using too much jargon. What does lowest logical fare even mean? And the second part does not make any sense. What exactly are they trying to say here? I am not entirely sure, but if my guess is correct it should read something like below.

Better Example

Qantas is our preferred airline for both domestic and international air travel. When flying, choose the cheapest rate available within reason. You can only choose another airline if it is cheaper by $50 for domestic and cheaper by $400 for international travel.

Bad Example

Ground transportation:  Company XYZ preferred provider for rental vehicle services is Avis.  Please refer to the list of approved rental vehicle types in the “Relevant Documents” link to the right hand side of this page.

Why it’s bad

Front load your sentences. With the most important information first. Don’t make a user dig for a document, have the relevant document right there. Link the Verb. Don’t say CLICK HERE!

Better Example

Ground transportation

Avis is our preferred provider to rent vehicles.

View our list of approved rental vehicles.

Bad Example

Booking lead times:  To ensure that the best airfare and hotel rate can be obtained, domestic travel bookings should be made between 14-21 days prior to travel, and international travel bookings between 21 and 42 days prior to travel.  For international bookings, also consider lead times for any visas that may need to be obtained.

Why it’s bad

Front load your sentence… most important information first. This is a good opportunity to chunk your text.

Better Example

Booking lead times

Ensure your book your travel early

14-21 day prior to travel for domestic

21-42 days prior to travel for internatonal (also consider lead times for visas)

This will ensure that the best airfare and hotel rate can be obtained.

 

Quick start guide for PnP PowerShell

It is quite easy and quick to set up PnP PowerShell on a local system and start using it. Considering that PnP PowerShell has been gaining a lot of momentum among Devs and Admins, I thought it would be good to have a post for everyone’s reference.

So why PnP PowerShell? Because it is the recommended and most updated PowerShell module for IT Pros to work on SharePoint Online, SharePoint on-premise and Office 365 Groups. It allows us to remotely maintain a SharePoint Online and Office 365 tenancy as we will see below.

Installation:

First, we have to make sure that we have the latest and greatest version of PowerShell (at least >= v4.0) on the system. We can simply check it using the following command $PSVersionTable.PSVersion which will give the output below.

PowerShell Version Check

If your version isn’t sufficient, then go to this link to upgrade – https://www.microsoft.com/en-us/download/details.aspx?id=40855. Since there are OS requirements accompanied with PowerShell, please make sure to check the System Requirements in order to make sure the OS matches the specs.

Also, I would recommend installing SharePoint Online Management Shell because there are various Tenant commands that you may not find in PnP PowerShell. The link can be found here – https://www.microsoft.com/en-au/download/details.aspx?id=35588. Again, make sure to check the System Requirements in order to make sure the OS matches the specs.

After you have the proper PowerShell version, run the following commands to install the PnP PowerShell module depending on if you’re using the Online or On-Premise version.  You only need to install the version(s) you need to interact with (no need to install on premise versions if you’re only working online).

SharePoint Version Command to install
SharePoint Online Install-Module SharePointPnPPowerShellOnline
SharePoint 2016 Install-Module SharePointPnPPowerShell2016
SharePoint 2013 Install-Module SharePointPnPPowerShell2013

It will likely take few mins to run and complete the above command(s).

Getting Started Guide:

To start using PnP PowerShell, first we will have to understand how PnP PowerShell works.

PnP PowerShell works in the context of the current Connection the site it is connected to. Assuming it is connected to a Site Collection, all commands refer by default to that Site Collection. This is different from SPO commands which require you to have Tenant Admin rights. A benefit of the PnP approach is that you can have separate Admin personnel to manage separate site collections or sites if needed.

Overview of Basic SharePoint Operations with PnP PowerShell

1. Connect to PnP Online

Connect-PnPOnline -Url

In the above case, if you are not given a prompt for entering your credentials, then create a credential object and pass it to the Connect command (as seen below).

$user = ""
$secpasswd = ConvertTo-SecureString "" -AsPlainText -Force
$mycreds = New-Object System.Management.Automation.PSCredential ($user, $secpasswd)
Connect-SPOnline -url $siteAdminURL -Credentials $mycreds

2. Get the web object using Get-PnPSite and then get the subsites in it

## For Site Collection (root web)
$web = Get-PnPSite 
## For Sub web
$web = Get-PnPWeb -Identity ""

Remember, PnP works in the context of the current connection.

3. To work on lists or objects of the site, use the “Includes” parameter to request them or else they will not be initialized.

$web = Get-PnPSite -Includes RootWeb.Lists

PnPPowerShell output

After you get the list object, you can traverse it as needed using the object.

4. To work on list items, you must request the list items and same goes for updating the items.

$listItem = Get-PnPListItem -List "Site Assets"

DocumentResults

Set-PnPListItem -List "Site Assets" -Identity 2 -Values @{"" = ""}

PnPPowerShell_UpdateItem

So, as we saw above, we can use PnP PowerShell to maintain SharePoint assets remotely.

Please feel free to let me know if there are any specific questions you may have regarding the approach above and I will post about those as well.

Automate SharePoint Document Libraries Management using Flow, Azure Functions and SharePoint CSOM

I’ve been working on a client requirement to automate SharePoint library management via scripts to implement a document lifecycle with many document libraries that have custom content types and requires regular housekeeping for ownership and permissions.

Solution overview

To provide a seamless user experience, we decided to do the following:

1. Create a document library template (.stp) with all the prerequisite folders and content types applied.

2. Create a list to store the data about entries for said libraries. Add the owner and contributors for the library as columns in that list.

3. Whenever the title, owners or contributors are changed, the destination document library will be updated.

Technical Implementation

The solution has two main elements to automate this process

1. Microsoft Flow – Trigger when an item is created or modified

2. Two Azure Functions – Create the library and update permissions

The broad steps and code are as follows:

1. When the flow is triggered, we would check the status field to find if it is a new entry or a change.

Note: Since Microsoft flow doesn’t have conditional triggers to differentiate between create and modified list item events, use a text column in the SharePoint list which is set to start, in progress and completed values to identify create and update events.

2. The flow will call an Azure function via an HTTP Post action in a Function. Below is the configuration of this.

AzureFunctionFromFlow

3. For the “Create Library” Azure function, create a HTTP C# Function in your Azure subscription.

4. In the Azure Function, open Properties -> App Service Editor. Then add a folder called bin and then copy two files to it.

  • Microsoft.SharePoint.Client
  • Microsoft.SharePoint.Client.Runtime

KuduTools_AzureFunction

Create Lib App Service Editor

Please make sure to get the latest copy of the Nuget package for SharepointPnPOnlineCSOM. To do that, you can set up a VS solution and copy the files from there, or download the Nuget package directly and extract the files from it.

5. After copying the files, reference them in the Azure function using the below code

#r "Microsoft.SharePoint.Client.dll"
#r "Microsoft.SharePoint.Client.Runtime.dll"
#r "System.Configuration"
#r "System.Web"

6. Then create the SharePoint client context and create a connection to the source list.

7. After that, use the ListCreationInformation class to create the Document library from the library template using the code below.

8. After the library is created, break the role inheritance for the library as per the requirement

9. Update the library permissions using the role assignment object

10. To differentiate between People, SharePoint Groups and AD Groups, find the unique ID and add the group as per the script below.

Note: In case you have people objects that are not in AD anymore because they have left the organisation, please refer to this blog for validating them before updating – Resolving “User not found” issue while assigning permissions using SharePoint CSOM

      Note: Try to avoid item.Update() from the Azure Function as that will trigger a second flow run, causing an iterative loop, instead use item.SystemUpdate()

11. After the update is done, return to the Flow with the success value from the Azure Function which will complete the loop.

As shown above, we saw how we can automate document library creation from a template and permissions management using Flow and Azure Functions