Thursday, June 10, 2021

Updated script to re-index user profiles for search

white printer paper on green typewriter

This has been on my mind for years and I finally got the time to create a new version of my PowerShell script to re-index user profiles for the scenario where you map a new UPA property to be used in search.

You can pick up reindex-users-v2.ps1 from https://github.com/wobba/SPO-Trigger-Reindex. The script allows for quicker updates especially for tenants with a lot of profiles as it uses the UPA bulk import API instead of iterating the UPA.

See https://docs.microsoft.com/en-us/sharepoint/dev/solution-guidance/bulk-user-profile-update-api-for-sharepoint-online and https://docs.microsoft.com/en-us/previous-versions/office/sharepoint-csom/mt642955(v=office.15) for documentation.

Cover image by Markus Winkler @ Unsplash

Wednesday, May 5, 2021

Site descriptions are now searchable!! (and more)

image

“What????!” you might say, hasn’t it always been like that? And the answer is that ever since SharePoint 2013 it hasn’t. Because if it had, I would not be writing this – just saying.

As a bonus if you create a column in a library named Description, the content of this property is now also searchable. See my old post https://www.techmikael.com/2014/12/solution-to-cannot-search-content-in.html about this issue.

That’s correct people, you get a 2 for 1 special as Microsoft Search has rectified a long time nuance. And I’ll take the credit for getting this fixed (with some awesome technical help from Himanshu on the Stream team) - I can be humble another time

image

Note: The change applies to updated content, not content already in the index. For active sites it should fix itself, so no action needed on your part.

Technical explanation

For the site description (or the description of an Office 365 group or a Team) the crawled property storing the description value, ows_SiteDescription, was mapped to two managed properties:

  • Description
  • SiteDescription

Neither which were marked as searchable, effectively removing the ability to get a match on normal user queries from a search box. We have now made a search schema change to map ows_SiteDescription to the managed property Contents in addition to the two existing ones, ensuring full-text search.

Same goes for a SharePoint column/field named Description. Except this is a weird one as the crawled property for this column is Office:6, not ows_Description. To be on the safe side we have mapped both Office:6 and ows_Description to Contents as well.

Need a refresh on what makes content free-text searchable in SharePoint? Head over to https://www.techmikael.com/2014/07/what-makes-sharepoint-column-searchable.html.

Cover image by Alexander Krivitskiy@unsplash

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