Showing posts with label howto. Show all posts
Showing posts with label howto. Show all posts

Monday, July 8, 2024

One small step for SharePoint intranets, one giant leap for news roll-up

image

..well, not really, but it’s an improvement which makes news roll-up match multiple information architecture scenarios. I’ll leave it up to those setting up intranets to gage the usefulness, and I know there has been demand for this feature.

A shoutout to my old peeps at Puzzlepart for wanting this feature – adding to many other customers who have asked for this feature.

So, what am I talking about? In the news web part, when you use “Select sites” or “Recommended for the current user”, a new option to either show or hide the site title will show below the sites you pick.

imageimage

When displaying news from one site, the site title is already hidden as you are on that one site anyways. If you pick more sites, you may want to hide the site title because content authoring happens in multiple sites because of information architecture, not because you need to show the site title.

Here’s an example with and without site titles.

image

Happy intranet authoring!

What’s great at Microsoft, is that anyone can contribute anywhere. The above feature was implemented by yours sincerely as part of one of the yearly hackathons we have at Microsoft. It allowed me to look more closely at how web parts are built in SharePoint, and also solve a customer pain. Win-win!

Tuesday, June 25, 2024

Search nugget: The beauty of SharePoint Site Columns

image

The scenario I’m sharing is not a new one, but (somewhat) recent changes to SharePoint indexing of items may make the scenario easier to solve.

Before we dig into the details, let's talk about Microsoft Syntex, as it has bearing on the nugget I will share. Microsoft Syntex is a service that uses AI and machine learning to automatically sort and classify documents across SharePoint, Microsoft Teams, OneDrive for Business, and Exchange.

Or simply put in terms for SharePoint: Pulling structured data out from unstructured data and store it as metadata for easier use and retrieval. Something we have done manually or via customized processed for the longest time in SharePoint lists and libraries.

Microsoft Syntex is licensed via a pay-as-uou go model, where you pay for items processed. See https://learn.microsoft.com/en-us/microsoft-365/syntex/syntex-pay-as-you-go-services and  for more details and the offering currently includes these features:

  • Prebuilt document processing
  • Structured and freeform document processing
  • Unstructured document processing
  • Autofill columns
  • Content assembly
  • Image tagging
  • Taxonomy tagging
  • SharePoint eSignature
  • Document translation
  • Optical character recognition (OCR)
  • Microsoft 365 Archive
  • Microsoft 365 Backup (Preview)
  • Microsoft 365 Backup Storage (Preview)
A Microsoft Syntex enabled library also enable a better context query user experience. See https://learn.microsoft.com/en-us/microsoft-365/syntex/metadata-search for details.

Let's get to it!

Say you have a library where you add a new column. In this case a number column.

image

In a search scenario for the library you want to filter results based on the number value. One example being all items with a value above 100.

In my case the column has an internal name of PnPNumberColumn. If the column was manually created at the library it would output a crawled property named ows_PnPNumberColumn. This crawled property could be mapped to RefinableInt00 and after re-indexing you could use the below KQL query to list all items with a value above 100. If you add an alias to the managed property you could use this instead.

RefinableInt00>100

Now, let us go back to the site column scenario. Site columns will in addition to the default crawled property, create an additional crawled property and an automatic managed property. This is described at Automatically created managed properties in SharePoint Server which also apply to SharePoint Online despite what the article is tagged as.

The caveat of the automatically created managed properties is that they are of type text, which is not very useful when it comes to numbers. The example column above yields an automatic managed property named PnPNumberColumnOWSNMBR. This means I can query with:

PnPNumberColumnOWSNMBR:500 or PnPNumberColumnOWSNMBR=500 and get a match, as it matches on text. PnPNumberColumnOWSNMBR>500 would however be invalid KQL.

And here is the nugget. In addition to PnPNumberColumnOWSNMBR we now also get an additional property PnPNumberColumnOWSTNMBR. Note the extra T.

A word from our sponsor: This tip was brought to you by indexing advancements made for Microsoft Syntex. Microsoft Syntex greatly automates creation of site column for the average user. What are you waiting for?

And don’t be fooled by the schema admin page saying the property is of type text, as it is indeed of type number. A fact somewhat called out in a notice when you view the property settings, so you just have to trust me.

image

image

Below is screenshot showcasing the behavior where the query PnPNumberColumnOWSTNMBR>499 return the sample document. Easy as pie!

image

PS! The property is not refinable so you can not use it as refinement filter. If this is your case keep on as you always have and map to e.g RefinableInt00

Thursday, January 18, 2024

Easier editing of Microsoft Search verticals in SharePoint sites (finally fixed!)

This is perhaps a tiny one, but for the longest time search verticals in a SharePoint site or SharePoint hub site has been a bit of a mystery when you wanted to edit a vertical. To invoke edit, you had to double click the vertical, as there was no Edit button in the ribbon.

The issue has been known since the feature rolled out, but not addressed. I'll be as blunt to say I decided to take matters into my own hands and just fix it. So here you go, a gift from me to allow a more intuitive way of editing search verticals in SharePoint - as the Microsoft 365 Admin center has had the Edit button always.

At last the experience matches the documentation at https://learn.microsoft.com/en-us/microsoftsearch/manage-verticals#manage-site-level-verticals.



Thursday, January 11, 2024

Demystifying Author properties on files in SharePoint and search

demystify

For as long as I have been doing SharePoint, figuring out what properties to use when filtering or displaying search results in regards to people has been a challenge as the documentation in this space is somewhat lacking. I’m not sure why I haven’t done this writeup earlier, but no time like the present.

Thursday, August 10, 2023

How to paginate large results sets for SharePoint items using the Microsoft Graph Search API

If you want to paginate over a large set of results for some reason using the Microsoft Graph Search API, you can employ the logic mentioned for the SharePoint API at https://learn.microsoft.com/en-us/sharepoint/dev/general-development/pagination-for-large-result-sets. Note that this option applies to OneDrive and SharePoint items, not necessarily other content sources available via the Graph Search API (not tested).

Use a basic JSON template like below for your search requests, or modify to add other parameters needed for your request.

{
"requests": [
{
"entityTypes": [
"driveItem"
],
"from": 0,
"size": 500,
"query": {
"queryString": "contoso indexdocid>**LASTID**"
},
"fields": [
"indexdocid"
],
"sortProperties": [
{
"name": "[DocId]",
"isDescending": "false"
}
]
}
]
}

Where **LASTID** is 0 on the initial request. Once you get results back, pick the value of indexdocid of the last result, and use that as **LASTID** on the next request. In the below screenshot you would use 2377359 for the seconds request. Continue this logic until you stop getting results, and you should have iterated all files (driveItems) containing the term contoso for the above sample.




Tuesday, April 25, 2023

Filter on managed properties in search with or without values

Back in 2014 I wrote the post How To: Search up items which don’t have a value set, which covers how to write keyword query syntax (KQL) filters to return or restrict items depending on if a specific managed property has a value or not. Recently Microsoft added support to more easily query if managed properties of type Text contain or does not contain a value.

Here’s a link to the updated documentation:

https://learn.microsoft.com/en-us/sharepoint/dev/general-development/keyword-query-language-kql-syntax-reference#filter-on-items-where-a-text-property-is-empty-or-contains-a-value

Note: The new supported syntax only works for Microsoft 365 / Online

  image

 

Items missing or having a text value

The syntax is as follows:

KQL Syntax Description
NOT <Property Name>:* Items where a property does not have a value
<Property Name>:* Items where a property does has a value

The documentation uses the following example to list SharePoint sites associated to a hub site.

(DepartmentId:* OR RelatedHubSites:*) AND contentclass:sts_site NOT IsHubSite:true

Deciphering the query:

KQL Description
(DepartmentId:* OR RelatedHubSites:*) return items which has a value in the original DepartmentId managed property or in the successor RelatedHubSites property
contentclass:sts_site return only site items
NOT IsHubSite:true exclude hub site results

Note that hubs connected to another hub will not be included in the above query. If you want those, then remove the NOT IsHubSite:true part and post-process the results as needed.

For completeness let’s cover how to accomplish the same for other types of managed properties.

Items missing or having a YesNo value

To find items missing a value in a date property the syntax shown in my 2014 seems to no longer work and should be replaced with the following where the date is some low non-used date.

KQL Description
NOT (RefinableYesNo00:true OR RefinableYesNo00:false) return items not having a value in a YesNo property
(RefinableYesNo00:true OR RefinableYesNo00:false) return items having a value in a YesNo property

 

Items missing or having a date value

To find items missing a value in a date property the syntax shown in my 2014 seems to no longer work and should be replaced with the following where the date is some low non-used date.

KQL Description
NOT RefinableDate00>1900-01-01 return items not having a value in a date property
RefinableDate00>1900-01-01 return items having a value in a date property

 

Items missing or having a number value

For number type managed properties it’s easier as you typically know the range of values.

KQL Description
NOT Size>=0 if the managed property only contain positive values, then this will return all items with no value set
NOT RefinableDecimal00>=0 NOT RefinableDecimal00<0 return items where the property RefinableDecimal00 has no value
Size>=0 return all items having a value which is greater than your smallest value

Monday, January 4, 2021

Microsoft Graph: Encoding and decoding the drive id

image

If you have worked with the Microsoft Graph API and SharePoint items you might have encountered URL’s which include a drive id. Where you in SharePoint typically work with URL’s for a site and the document library, a drive id is an encoded representation of a document library location.

The following Graph REST request will list all items in a specific document library:

GET https://graph.microsoft.com/v1.0/drives/b!VvpCx03990mC5Lb5YxH0SUA9TgZHvEZImra6PMjrvbx85KUwT1BMTbhen6I6ffXL/root/children

Fetching the item for a file you use this signature to retrieve the file itself where item id is part of the listing: GET /drives/{drive-id}/items/{item-id}

With some reverse engineering you easily can figure out the drive-id is a prefixed base64 encoded string composed of the site id, web id and list id for a particular library.

Using PowerShell here’s a few lines converting the drive id string to the correct guid’s and back:

$driveId = "b!VvpCx03990mC5Lb5YxH0SUA9TgZHvEZImra6PMjrvbx85KUwT1BMTbhen6I6ffXL"   
$encodedDriveId = $driveId.Substring(2).Replace('_','/').Replace('-','+')
$bytes = [Convert]::FromBase64String($encodedDriveId)
$siteIdBytes = [byte[]]$bytes[0..15]
$siteIdGuid = New-Object Guid @(,$siteIdBytes) #site id

$webIdBytes = [byte[]]$bytes[16..31]
$webIdGuid = New-Object Guid @(,$webIdBytes) #web id

$listIdBytes = [byte[]]$bytes[32..47]
$listIdGuid = New-Object Guid @(,$listIdBytes) #list/library id

$bytes = $siteIdGuid.ToByteArray() + $webIdGuid.ToByteArray() + $listIdGuid.ToByteArray()
$driveId = "b!" + [Convert]::ToBase64String($bytes)

The item-id part is a bit more tricky and looks to be some sort of base32 encoding of a SharePoint item’s unique id. As I haven’t figured out the mechanics you can still access the item by route of the list item unique id:

GET https://graph.microsoft.com/v1.0/drives/{drive-id}/list/items/{unique-id}/driveItem

Example: https://graph.microsoft.com/v1.0/drives/b!VvpCx03990mC5Lb5YxH0SUA9TgZHvEZImra6PMjrvbx85KUwT1BMTbhen6I6ffXL/list/items/7D0E814C-0798-4966-A20C-6DE4F27F2027/driveItem

Of course, if you already have the site id, web id, list id and unique item id, you can access a drive item using the following syntax as mentioned in my file preview post.

GET https://graph.microsoft.com/v1.0/sites/{site-id},{web-id}/lists/{list-id}/items/{item- id}/driveItem

Photo by https://unsplash.com/@maurosbicego

Friday, November 13, 2020

Mapping or clearing crawled property to managed property mappings using PowerShell (or code)

image

Mapping a crawled property to a managed property in SharePoint Online is usually done via the user interface. A somewhat cumbersome task as you first have to create content with a value which will ensure the creation of a crawled property matching your SharePoint field (or column if you want). Once the crawled property is available you can map it to a managed property.

Lately there has been issues where crawled properties are not listed in the admin UI due to a bug, and this blocks tenants from creating search solutions dependent on schema mappings. There are some workarounds available which you can check out at https://platinumdogs.me/2020/11/13/sharepoint-online-search-crawled-properties-not-created-not-showing-or-not-available/.

Instead of these workaround I figured I’d show how you can use search configuration XML files to accomplish the same task – a pattern I used many times back in the day when working on SharePoint 2013 on-premises and had to move search configurations between environments. These files together with the PnP cmdlet Set-PnPSearchConfiguration is a time saver. You can also use

Get-PnPSearchConfiguration -Scope Site -OutputFormat ManagedPropertyMappings

to see any mappings at a particular site.

The first bonus of my solution is that you can map a crawled property which don’t yet exists, as it will be created for you. No need to create content before you start mapping.

The other bonus is that you can also clear out an existing mapping, reverting it to the default behavior. Particularly handy if you at a site scope override a global mapping, and later want to revert. Something you simply cannot do in the admin interface today. 

Note: The best way to create these files is to use a new site collection in either SharePoint Online or SharePoint 2013/2016/2019 where you are able to do the mappings. Manually create the needed mappings and export the search configuration file to be used in another environment (site, or tenant).

The script currently works with ows_<fieldName> crawled properties. Which means you need to figure out the name of the crawled property manually. (ows_ + internal name of the SharePoint Field). It will also only work with the reusable managed properties as we know the id’s of these beforehand. In order to make it work for other crawled properties the script must be expanded to support more property set id’s. Focusing on the set 00130329-0000-0130-c000-000000131346 should however cover most scenarios.

image

Head over to https://github.com/wobba/SearchConfiguration and fetch the files:

  • MapCrawledPropertyToManagedProperty.ps1
  • SearchMappingTemplate.xml
  • SearchMappingReset.xml

Check the top of the ps1 for usage. Happy property mapping!

Cover photo by Markus Winkler @ Unsplash

Tuesday, September 29, 2020

Search and modern multilingual pages in SharePoint Online

image

The ability to create SharePoint pages in multiple languages was/is a popular feature for classic SharePoint publishing pages. If you work in an organization where your employees use multiple languages, for example English and Norwegian, creating side by side pages in native languages is beneficial both from a communication point of view and also helps to tailor the information related to countries/regions based on language.

Back in SharePoint 2013 the functionality was called variations. This time around it’s more aptly named the “multilingual feature”. You can read the feature announcement from June 2020 at the Microsoft Tech Community.

While variations were an option for sites using the classic SharePoint publishing feature, the ability to create multilingual pages is currently enabled by default for Communication sites only.

If you want to enable multilingual page support on a Team site you can do so by activating a hidden feature called SitePagePublishing using for example PnP PowerShell as a site owner.

Connect-PnPOnline https://contoso.sharepoint.com/sites/mysite
Enable-PnPFeature -Identity f39dad74-ea79-46ef-9ef7-fe2370754f6f

If you want to take advantage of the ability to author multilingual pages, head over to Create multilingual communication sites, pages, and news which describes in detail how to turn on the capability as well as how to author the pages.

Details needed for search

What happens behind the scenes when you create multilingual pages? For one, each language copy is stored in its separate folder. In my case English is the primary site language, and I opted to have Norwegian as a secondary language.

image

Two pages in the original language.

image

One of the pages is translated.

Secondly, to connect and keep track of the original vs. the translated pages there are some internal properties in SharePoint per item keeping track of this.

SharePoint Column

Search Managed Property

Description

_SPTranslatedLanguages

SPTranslatedLanguages

Source page stores a list of the language of all translated languages.
E.g. nb-no.

_SPTranslationLanguage

SPTranslationLanguage

Translated page stores the language of the page.

E.g.: nb-no

_SPTranslationSourceItemId

SPTranslationSourceItemId

Translates page stores a reference to the original page.

E.g: 1f50aa8b-d31e-415a-bc4a-4ced38f5cdc4

_SPIsTranslation

SPIsTranslation

The translated page stores the boolean value true to indicate it’s a translation and not the original. The original article has no value.

The desired behavior when searching is to return a page in the users’ display language if it exists. If a translation does not exist, fall back to the original language – which follows the default language of a site set at site creation.

The examples below explain the logic used by Microsoft Search, and you can replicate this yourself as well in custom solutions.

To return English pages returned the query would be:

(SPTranslationLanguage:en-us OR (NOT SPTranslatedLanguages:en-us AND NOT SPIsTranslation:true))

image
Both pages returned in the original language - English.

To return Norwegian pages the query would be:

(SPTranslationLanguage:nb-no OR (NOT SPTranslatedLanguages:nb-no AND NOT SPIsTranslation:true))

clip_image008
One translated page and one non-translated returned.

If you are using the PnP Modern Search web parts you can use the query variable {PageContext.currentUICultureName} to substitute the correct display language into the query.

Easy as pie :)

PS! For the KQL savvy, you can not replace the NOT operator with the (minus) operator for boolean values – for some weird reason that fails.

Cover photo by Mat Reding @ Unsplash

Thursday, March 26, 2020

Searching within Office 365 Groups or Teams content

image

There are at least three ways to limit the search results within a group or a team using the keyword query language (KQL). These are cases where the managed property used exists on all items for the site/group.

Path

If you know the URL of the groups site you can use a path filter, and remember the trailing slash (/) to avoid edge case inclusion of other data.

path:https://contoso.sharepoint.com/teams/myteam/

Site Id

If you know the underlying site id of the Groups site.

SiteID:<guid>

Group Id

If you know the Group Id, meaning the AAD id of the group, you can use this as well.

GroupId:<guid>

Bonus: Search within all the groups a user is member of

And here’s the kicker to effectively scope results to all the groups a user is member of. Say you have pulled out a list of all the groups a user is member of via the Microsoft Graph API:

https://graph.microsoft.com/v1.0/me/memberOf/$/microsoft.graph.group
?$filter=groupTypes/any(a:a eq 'unified')

Armed with all the group ids, you can issue a SharePoint Search REST query using a wildcard (*) as the query text and the following FQL in the refinementfilters property.

GroupId:or(<guid1>,<guid2>,….)

GroupId:or(81eb706e-2904-4ac6-89f4-a0cf9d59d1c4,79958190-024b-4c62-ab55-65dc9a066cac)

If you are a member of many groups, then I suggest using a POST payload instead of GET, and refinementfilters is not limited by 4k either (at the time of this writing) :)

See https://www.techmikael.com/2013/07/limiting-search-results-by-exact-time.html for an explanation of refinement filter usage.

Note: How the above syntax will work using the Microsoft Graph Search API which is in beta, is not known at this point.

Photo by Mike Szczepanski @Unsplash

Friday, March 20, 2020

I finally found a use case for the Surface Pen (after 4 years)

I’ve been using Surface Pro’s since the Pro 3 and I know have a Pro 6. I have always liked the form factor of it and each one of them came with a Surface pen. Sure, I’ve tested the pen for fun and used it occasionally to sign something, but in the end I’m a laptop guy, not a tablet guy when it comes to work. So the pens have trustfully followed along in my back back never being used.

Until now that is!

In my home office I have opted to get a speaker phone as wearing a headset for longer periods of time is uncomfortable. The advantage with cabled headsets is that they have a mute/unmute button on the cord, allowing you to sit back and toggle the microphone on and off based on the conversation.

With a speaker phone I can still mute and unmute. Doing so requires me to stretch over to the speaker, not having the button easily in my hand. When using Microsoft Teams, I can use a keyboard shortcut shift-alt-m, but that requires the application to be active and is a bit too quirky.

You probably see where this is going :)

The solution is pretty simple. Being a programmer I browsed around and found out how to programmatically toggle a microphone on/off. You can find the C# code over at https://github.com/wobba/MuteToggleMicrophone. (I did look at NIRCMD, but it mutes speaker as well as mic when devices have the same names.)

As the program is a console application, I browsed to the .exe file, and created a shortcut for it as shortcuts can be set to be run minimized. The .exe takes the parameter of a string matching the name of your microphone device (if you have more) or “all” to toggle each one.

image

The last step is to configure pressing the eraser button on the Surface pen to launch this program.

image

Now I can relax back in my chair, not touching the keyboard, and mute/unmute myself as needed :)

Wednesday, May 15, 2019

Approve a document in Teams using Adaptive Cards and Flow

Co-incidentally the same scenarios often appear simultaneously from different people at the same time, and this is one of them.

I’ve been assisting with random comments to a client who wants to start an approval on a document, and have that show up as a card with Approve/Decline buttons in Teams. And yesterday the good SharePoint/Flow man himself Chaks at Microsoft reached out with a similar scenario.

Chaks wanted to build a bot for this, and I asked if he had tried the Adaptive Card action in Flow, and have card buttons trigger an approval/decline action via a HTTP trigger. Turns out that adaptive cards via Flow in Teams does not support Action.Http. End of story.

Here I am, having told a client this should be easy, and Chaks telling me I can’t do it. Being me, that’s not acceptable, of course it can be done – and turns out my ego was right this time :D (it’s not always)

Start the approval Flow from SharePoint.

Adaptive card in Teams.


Important: Enable Major, minor versioning and approval on the document library. And I have not put any thoughts into licensing of actions in Flow if any for this scenario.

How??? Let me show you!

Thursday, January 24, 2019

A no-nonsense solution to implement cascading dropdowns using PowerApps as a custom form in SharePoint

Search for “powerapps cascading dropdowns sharepoint” on the interwebs and you will find a bunch of ways to get this to work, but I dare to say that the solution I propose is by far the easiest and most elegant. And a big thank you to my colleague Thomas who helped along with this one.

My sample is super easy. I have three lists, Countries, Cities and Customers. Cities has a lookup to Countries, and Customers has a lookup to both Countries and Cities.

image

By default the input form looks like the image below, where all cities are shown regardless of the selected country. But this is easily fixed.

image

Thursday, September 27, 2018

Workaround for removing a deep folder structure in SharePoint

Deep water signage

I had a client which were not able to delete a deep folder structure from SharePoint which I’m guessing was synced in via OneDrive.

The error they got when trying to delete anything in the structure was “Error Code: 6404” – not a very descriptive error.

image

I tried all sorts of API’s, but having worked with SharePoint and Windows for a while I figured this had to do with a total path being too long, and I was correct.

In the end I renamed every single folder to “a”, just one character, and then the total path length was short enough for SharePoint Online, and the structure deleted nicely.

Photo by Rosie Kerr on Unsplash

Monday, September 10, 2018

An approach to search for a URL within a page or document in SharePoint

image

The Search Explained Yammer network is a great place to ask the weird and quirky search questions. Unfortunately it’s not indexed by Google, so answers there will not benefit everyone – which is why I’m writing this post.

A couple of days ago someone posted a question if it was possible to find pages in SharePoint which contain a specific link. The need was to identify broken links. Use-case can be if you rename a file, and want to find all pages linking to that file before renaming – to make sure they still point correctly.

This post will show you one approach which works, and if you have a better suggestion, please let me know.

Question is; how can you go about finding a page with the link https://contoso.sharepoint.com/sites/collection/site/library/document.docx as part of the content?

Monday, August 27, 2018

Modifying terms using app-only tokens in SharePoint – undocumented work-around


Photo by Alekzan Powell at Unsplash

In a rage of fits yesterday where I was running a PowerShell script against SharePoint Online with an account using multi factor authentication – which just don’t work reliably due to the use of login via web browser I decided to use app-only authentication instead.

I used the following permission manifest which should ensure god rights, right?

<AppPermissionRequests AllowAppOnlyPolicy="true" >
  <AppPermissionRequest Scope="http://sharepoint/content/tenant" Right="FullControl" />
  <AppPermissionRequest Scope="http://sharepoint/taxonomy" Right="Write" />
</AppPermissionRequests>

But since I’m dealing with modifications to terms in this script, that quickly broke down. More rage, more fits!

Reading https://msdn.microsoft.com/en-us/library/office/mt210897.aspx?f=255&MSPPError=-2147217396#sectionSection0 states:

You can't use the app-only policy with the following APIs:

  • User Profile

  • Search

  • Taxonomy (this only applies to scenarios that write to the managed metadata service)

Tuesday, May 8, 2018

How to get the list item from a file URL using PnP PowerShell

image
Photo by Karly Santiago at Unsplash

This is one of the snippets I always forget, but which is very handy in cases where you have the absolute URL to an item in SharePoint. The magic is really line 6 which uses the static method WebUrlFromFolderUrlDirect to get the web URL of the file, so that you can connect properly.

[Updated 2021-01-19 to support "People with existing access" sharing URL's]

$uri = [Uri]'https://contoso.sharepoint.com/sites/foo/bar/Shared%20Documents/mikael-is-cool.docx'.replace(":w:/r/","")
$uri = [Uri]$uri.OriginalString.Replace($uri.Query,"")
# Connect to the root site, or any other site
Connect-PnPOnline -Url ($uri.Scheme+'://'+$uri.Host)
$ctx = Get-PnPContext
# Get the web url for the file
$webUrl = [Microsoft.SharePoint.Client.Web]::WebUrlFromFolderUrlDirect($ctx, $uri)
Connect-PnPOnline -Url $webUrl
$fileItem =  Get-PnPFile -Url ([System.Web.HttpUtility]::UrlDecode($uri.AbsolutePath)) -AsListItem

Monday, February 26, 2018

Alternative way to solve the issue where a SPFx v1.4.0 web part don’t show when upgrading.

In SPFx v1.4.1 there was an important bug fix which was introduced in SPFx v1.4.0. If you created a web part which was manually installed on a site collection, upgrading the web part would result in the web part not showing. The issue noted on the release notes for v1.4.1 says in order to fix this do the following:

  1. Remove all instances of existing SharePoint Framework solutions from site level
  2. Remove SharePoint Framework solution from app catalog
  3. Upload new SharePoint Framework solution built with 1.4.1 version to your app catalog
  4. Install SharePoint Framework solutions back to sites.

You don’t have to uninstall the solution, but can follow these steps instead:

  1. Upgrade your web part to SPFx v1.4.1 and bump the version number of the part in package-solution.json and package it.
  2. Navigate to https://<tenant>.sharepoint.com/sites/<AppCatalogSite>/Lists/ComponentManifests and remove the entry for the web part in question.
  3. Upload the updated web part to your app catalog, overwriting the old one, and ensure the app is checked in, if it becomes checked out.
  4. Upgrade the web part package on the site collection(s) where used (site contents, classic view, about on the part, then “Get it” to get the latest version.
    image
    image

Unfortunately there is no easy way to see all sites which have installed a particular SPFx v1.4.0 web part, so you have to loop over all sites in order to ensure they are all working as expected.

Tuesday, February 13, 2018

How to properly use the “Get Manager” Flow action with a SharePoint list

A confident man in a blue blazer
Photo by Olu Eletu at Unsplash.

This is a short one and quite easy. When you create an item in SharePoint the unique identifier for a person field is the claim, while the Get Manager action takes a UPN (user prinipcal name).

image

For Office 365 they are almost equal. The claim is actually the UPN + a claim prefix.

UPN: john@contoso.com
Claim: i:0#.f|membership|john@contoso.com

If you have a flow triggering on a SharePoint list, you would enter the following expression for the UPN field to strip off the prefix from the claim.

replace(triggerBody()?['Editor']?['Claims'],'i:0#.f|membership|','')

image

Sure you can use the e-mail address which usually match the UPN, but you would be surprised how often multiple accounts have the same e-mail address - admin accounts, test accounts etc. So using a unique identifier is always a better approach compared to the e-mail address.

Monday, February 12, 2018

Validating a number format in SharePoint – divide and conquer formulas

A modern white chair at a table with a laptop, a notebook and a calculator

Photo by Oliver Thomas Klein at Unsplash.

Validating input in SharePoint is nothing new, but I haven’t dug much into this over the years. This time around I have a list where one of the fields takes a case number. The case number should be on the format:

0000/000000 <- four digits, a slash, then 6 digits.

Using regular expression this would have been a breeze - \d{4}\/\d{6} , but that’s not an option in SharePoint. Using the official formula documentation as a lookup I ended up with the following formula. I’ve split it over multiple lines and added comments for readability, so remember to remove the comments before using. Depending on your locale you might have to use comma instead of semi-colon.

Make note of the +0 which is workaround to convert text to a number.

AND(
    LEN([Case Number])=11;                # Total length is 11 characters
    MID([Case Number];5;1)="/";           # Fifth character is a slash
    ISNUMBER(MID([Case Number];1;4)+0);   # First four characters is a number 
    LEN(TRIM(MID([Case Number];1;4)))=4;  # First four characters has no spaces
    ISNUMBER(MID([Case Number];6;6)+0);   # Last six characters is a number
    LEN(TRIM(MID([Case Number];6;6)))=6   # Last six characters has no spaces
)

Validation is entered at the columns settings.

image

And here I only have 5 digits at the end, which does not validate.

image