Follow Marc D Anderson's Blog on Feedspot

Continue with Google
Continue with Facebook


This is more confusing than it should be, frankly. I’ve had to explain this to clients multiple times, so a blog post is in order! This stuff changes over time, so if you’re reading this post in the future, some screen details and actions may have changed. Actually, I hope they have changed, because this is too confusing!

There are two different ways you can add/change users, one for internal users (people in your tenant) and one for external users (people not in your tenant). For all of this, you must have the right permissions to take the actions I outline. I live in SharePoint most days, so these instructions are SharePoint-centric.

Internal Users

On the home page of the site, click on the ‘x members’ link in the upper right.

This opens a panel which shows the current Group membership.

If you click on the Add members button, you can add people in your tenant by typing in their name or email address.

If you’d like to change someone’s permissions or remove them, you can do that from the Group membership panel:

Maybe you noticed the text in the Add members panel above? I know most people don’t!

Add colleagues to this group. To add guests, go to Outlook.

External Users

As noted in the message above, to add guests – what we usually call external users – you need to click on the link above or go to Outlook: and that’s Outlook Online.

External users can only be set up as Guests. The process here is a little different – and unfortunately a little clunkier.

When you click on Add members, you’ll see a link to go to Outlook to add guests.

Clicking on that link takes you to Outlook Online (sometimes called OWA = Outlook Web Access). You may not be aware, but this is also a way for you to check email just in the browser. There’s a link on this page to Add members. Yes, it says members, but you can also add guests here. (You have to click on the icon, not the text.)

You can add either type of user here. For external users, you add them using their email address.

Be sure to click Save when you are done.

If you don’t think this makes much sense – it doesn’t really. I think the reason we have to go over to Outlook may be because Office 365 Groups were originally an Exchange team idea. But I’m not totally sure. In any case, it’s a hard one to explain.

  • Show original
  • .
  • Share
  • .
  • Favorite
  • .
  • Email
  • .
  • Add Tags 

Lots of my clients want a quick and easy way to search for people in SharePoint. Unfortunately, it isn’t as simple as it should be.

On any given site, when you use the Search Box in the top right, you land on a search results page which doesn’t even have a People tab. Worse, you get no results representing people.

However, if you click on the Organization part of the breadcrumb, you get a People tab and results based on the search term(s) you have typed.

Better yet, if you click on the People tab, you get only people results, and they are rick people results, with People Cards showing all the details available.

Wouldn’t it be nice if you could just get people there right away?

Here’s a trick that works. You can add a Quick Link to the home page of any site taking you directly to the People Search. I’m suggesting this on the home page of Intranets at this point – until Microsoft gives us an easy path. (What would collaboration be if we couldn’t find any people?)

This is actually pretty easy, but it requires a small amount of thought. When you create the link in the Quick Links Web Part, it should have a link like this:

[link to the site]/_layouts/15/search.aspx/people

The [link to the site] part is important. When you click on the Quick Link, you’d like people to be able to get back to the place from whence they have come. By anchoring the link in the current site, the Exit search link will do that for them.

Adding the link is simple. Just add a new link with a URL like the one above. By default, it won’t be a very pretty button, so change the Title and give it a nice icon.

Here’s a decent way to make it look.

Not too bad, right? You can add one of these Quick Links wherever you’d like to give people easy access to a “find people” function. Just be sure to use the anchor to the current site as the start of the link.

Meanwhile, hey Microsoft – maybe make this easier?

  • Show original
  • .
  • Share
  • .
  • Favorite
  • .
  • Email
  • .
  • Add Tags 

We’re in an interesting time in the SharePoint world. Rather than waiting for three year product cycles like we did in the past, we’re along for the ride. To me, it feels like we’re nearing the end of one of the cycles, as modern SharePoint has almost fully taken hold – at least in Office 365.

There are challenges here, and we have several chasms to cross before we’re in the promised land. (And by the time we get there, the promised land will have moved on another few hundred miles.)

Chasm One – Managing Content Types

Many smaller organizations – and even some large ones – only used one Site Collection for most things in SharePoint. When this was the case, we could set up Content Types in the root site in the Site Collection, then every subsite could use those Content Types and Site Columns easily because of the inheritance model.

If we needed wider coverage of the information architecture (more than one Site Collection) we used the Content Type Hub to manage Content Types which we needed to use across Site Collections. But in many cases, the Content Type Hub wasn’t needed, as there were few Content Types shared across Site Collections or there were too few Site Collections to drive its use.

If you work with or in a large organization, you may say no one would be using SharePoint this way – and you’d be wrong. There are many different types of SharePoint implementations, and I get to see a lot of them, there is no one-size-fits-all thinking here.

Now that we are moving to a flatter site topology, the Content Type Hub is really important. In most organizations – as part of the move to modern and to take advntage of new innovations like Hub Sites – we’re working to flatten those old topologies.

This means we need that antiquated Content Type Hub to be able to syndicate our information architecture across Site Collections. It’s not really up to the joib, and it hasn’t gotten any love from the Product Group in years. But it does get the job done, if you are patient and plan accordingly.

What about Site Scripts and Site Designs, you may ask? Well, those are great, but out of reach of your average power user. To use them, you tend to need a developer mindset (JSON, scripting, oh my), and that means getting IT into the game. This may be easy in your organization, but it’s hard in many others.

This push-me–pull-you between users of the platform and IT continues…

As it happens, I’m speaking about this topic at the SharePoint Conference in May in Las Vegas. If you haven’t registered yet, you really should. This is going to be a big one, with SO many announcements from Microsoft about modern SharePoint and Microsoft 365. If you use code MANDERSON, you can even save $50!

Wait, you say. You said there are several chasms! Well, stay tuned. I’ll get there…

  • Show original
  • .
  • Share
  • .
  • Favorite
  • .
  • Email
  • .
  • Add Tags 

In my previous post entitled Creating and Deploying a Custom Theme in SharePoint Online, I was remiss by not mentioning Stefan Bauer’s (@stfbauer) highly useful Panthema Web Part. See: Panthema web part is now release – know your SharePoint theme colours

The Panthema Web Part shows the colors for all the theme “slots”. We can adjust any of these slots, though as I griped about in my previous post, the Office Fabric UI Theme Generator only lets us adjust three slots via the UI.

If you want to have a discussion about the theme you’ll apply to your site(s), installing the Panthema Web Part and creating a new page with just that Web Part on it can be a handy tool.

As you hover over each of the cards, you’ll see what that color is applied to.

Image lovingly borrowed from Stefan’s post

In this way, you can identify any small tweaks you might want to make to your branding beyond the three slots you can change in the Office Fabric UI Theme Generator.

I’ll refer you to the readme in Stefan’s N8Design repo on Github for installation instructions, since they may change over time.

Have fun theming!

  • Show original
  • .
  • Share
  • .
  • Favorite
  • .
  • Email
  • .
  • Add Tags 

If you’re moving from classic SharePoint to modern, sooner or later (I’m guessing sooner), you’ll want some control over the colors and fonts in your modern sites. I think the main reason people decide they need to do something about this is the random colors which are assigned to each new site as you create it.

Looking at just a handful of modern sites in our Sympraxis tenant, you can see what I mean.

If you’re in a classic site, you’re going to have weird half and half theming options. There are two different theming engines.

  • Classic Change the look options – which means the old type of theme (the ones which include Sea Monster!).
  • Modern themes in the modern Change the look options. (The modern Change the look options are in mid-upgrade to add new options [Navigation and Footer], but you won’t see those options in a classic site.)

Modern themes do get applied to classic pages, so it you have a mix, you should use a modern theme.

You can create a custom modern theme using the Theme Generator tool. Unfortuantely, there are only three “slots” you can change in the tool:

  • Primary Theme Color
  • Body Text Color
  • Body Background Color

The code you need is generated in a box in the page and you can copy it out when you are done.

What I’d love to see is two enhancements: the ability to enter more color codes to change “slots” beyond the three above, and the ability to paste existing theme code back into the tool to tweak further.

The trick then is to deploy the theme you have generated. You can certainly use a Site Script, but for a one-off, it probably makes more sense to use a little Powershell.

You do need to be a SharePoint Admin for this to work because you have to connect to https://mytenant-admin.sharepoint.com to deploy the custom theme.

The theme is then available to all sites, but you have to apply it in the Change the look settings.

The Powershell for this is really simple, and any admin worth their salt should be ably to follow any of the three posts below with no problem – it’s just three lines. If you create a theme in the Theme Generator, you can just give your admin the theme settings. The easiest format for them to deal with would probably be from the Powershell tab.

Connect-SPOService -Url https://mytenant-admin.sharepoint.com/

$themepalette = @{
"themePrimary" = "#3395cf";
"themeLighterAlt" = "#f5fafd";
"themeLighter" = "#daecf7";
"themeLight" = "#baddf0";
"themeTertiary" = "#7cbde2";
"themeSecondary" = "#48a1d4";
"themeDarkAlt" = "#2e87ba";
"themeDark" = "#27729d";
"themeDarker" = "#1d5474";
"neutralLighterAlt" = "#f8f8f8";
"neutralLighter" = "#f4f4f4";
"neutralLight" = "#eaeaea";
"neutralQuaternaryAlt" = "#dadada";
"neutralQuaternary" = "#d0d0d0";
"neutralTertiaryAlt" = "#c8c8c8";
"neutralTertiary" = "#b9bec9";
"neutralSecondary" = "#7c8392";
"neutralPrimaryAlt" = "#4a5160";
"neutralPrimary" = "#363c49";
"neutralDark" = "#2a2e38";
"black" = "#1f2229";
"white" = "#ffffff";

Add-SPOTheme -Identity "My Company Theme" -Palette $themepalette -IsInverted $false

Microsoft Documentation

Blog Posts

Each of these posts walk you through creating a custom theme with the Theme Generator and deploying it to a site using the SharePoint Online Management Shell (Powershell). They are all good, and each takes a slightly different slant.

  • Show original
  • .
  • Share
  • .
  • Favorite
  • .
  • Email
  • .
  • Add Tags 

When we migrate from classic SharePoint to modern SharePoint, we often have some historical content which should turn into News items on the modern end. If we need to load a large number of News stories, we may use Powershell or custom code, depending on the source. Because News hasn’t existed in SharePoint before, it’s not necessarily a one-to-one mapping.

In some cases, we simply want to seed News with some of the more recent articles from the organization. Loading all of the old news-like content may not make sense. In these cases, we often just create the new News items by hand.

As a consultant who often does this, I don’t really want to leave my fingerprints all over those News items. Other then the people I’m working with, no one in the client organization knows who I am, so seeing me as the author doesn’t lend the articles any credibility.

The other issue is any News items I create have the current date and time stamps. Since we’re trying to back-fill historical News, we want the dates to reflect when the original content was published, not when I create it.

One of my favorite software tools ever – Sharegate aka SG:Desktop – can help with this, and make it quite easy, to boot!

High Level Steps
  • Create News pages manually or in an automated way
  • Using Sharegate, export the News pages’ metadata to Excel
  • Edit the Excel file to replace the First Published Date, Created By, Created, Modified By, and/or Modified fields, as needed
  • Import the metadata changes
  • Bask in the glory
Detailed Steps

In Sharegate, you’ll want to navigate to the Site Pages library where you’ve created the News pages.

Select the News items you’d like to work with. Here, I’m just selecting two News items, but if you have a lot of pages, you might want to create a view in the site Pages library filtered for Promoted State = 2. That’s what distinguishes News from other pages (most have Promoted State = 0).

Click Export Metadata. You’ll be asked where to save the file.

Once the export is finished, click on Open File. This will launch the Excel file with the metadata.

In the Excel file, make the metadata changes you need. Notice that you can specify any user in your organization by providing their email address.

Save the file and close it.

Back in Sharegate, click the Import & Edit button. You’ll be asked where the file lives – it’s the one you just edited in Excel.

At the next screen, in most cases, you’ll just want to click the Bulk Edit button. There are all sorts of options here which are REALLY useful in other scenarios, but not important right now.

If all goes according to plan, you’ll see green checkboxes next to each page.

Et voila! The metadata is updated to reflect the correct people and date/time stamps. Note that it may take a little while before search picks up the changes and you see them in News roll ups in other sites.

Here’s just one more reason why I love Sharegate. It’s not just a migration tool – it’s my everyday tool!

  • Show original
  • .
  • Share
  • .
  • Favorite
  • .
  • Email
  • .
  • Add Tags 

Yay! SharePoint Framework 1.8.0 is available! I decided to upgrade one of my simpler Web Parts to see what the experience was like. I learned a few things, I figured I’d share.

One of the things we get as part of this upgrade is a newer version of the TypeScript transpiler. We can choose which version of TypeScript we want to use when we add the dev dependency into the package.json file. I elected to move forward to TypeScript 3.3 by adding this line:

@microsoft/rush-stack-compiler-3.3": "0.1.7

TypeScript 3.3 is more strict than previous versions. As the SPFx 1.8.0 release notes say:

Fix all the new and interesting tslint errors that are now getting raised with a newer compiler. For large projects, this might take a while. The default behavior of the TS compilers is getting stricter, but your code will be the better for it.

What this means is that code which transpiled and worked perfectly well in earlier versions of SPFx now may refuse to transpile. You may decide that’s annoying, but as the quote above says, your code will be better for it.

In my case, the errors pointed out two main types of things I had been doing that I needed to clean up.

Unused References and Declarations

Unused references and declarations are now a no-no. I had quite a few imports in my components what I wasn’t actually using and variables I once used but no longer was. You’re likely to have at least a few of these if you’ve refactored your code into separate components over time.

In earlier versions of TypeScript, this was fine. Depending on your IDE (I’m partial to WebStorm), you may or may not have gotten a warning. In TypeScript 3.3, those unused references throw an error. It’s a nice opportunity to get rid of the junk you have laying around.

Here’s an example from my code. I’m importing IPSSite, but I’m not using it in the component because I moved some logic into a different component.

import {IServiceProperties, ISPSite, IExclusion} from "./models/Models";

The error about this is:

[12:02:52] Error - [tsc] src/webparts/myTeams/MyTeamsWebPart.ts(17,29): error TS6133: 'ISPSite' is declared but its value is never read.

The fix is to simply remove the unused references or declarations. So now my line just looks like this:

import {IServiceProperties, IExclusion} from "./models/Models";
Possibly Undefined Objects

If you’re sloppy like I sometimes am, you may simply assume a variable is going to have a value. If you come from the JavaScript world, you may do this more often than someone who comes from the C# (strictly typed) world. TypeScript 3.3 doesn’t want us to be sloppy like that, so if you’re not checking for an undefined state, you now get an error.

Here’s a line from my Web Part where I got the error:

return this.processSearchResults2(result.RawSearchResults.PrimaryQueryResult.RelevantResults.Table);

In that line, I’m assuming I’m going to get results back from a call to the Search service containing a collection of subsites. Of course, it’s possible that there won’t be any values because something has gone wrong, the user doesn’t have permissions on any subsites, or whatever. In my testing, this was no problem because I always got a collection of sites back. It may never be an issue, but my code isn’t safe.

Here’s the error:

[12:08:09] Error - [tsc] src/webparts/myTeams/services/DataService.ts(74,39): error TS2532: Object is possibly 'undefined'.

In this case, the fix is to add safer checking on the value of the variable result. The brute force way to fix this is to test the entire object chain for undefined, like so:

if(result.RawSearchResults && result.RawSearchResults.PrimaryQueryResult && result.RawSearchResults.PrimaryQueryResult.RelevantResults && result.RawSearchResults.PrimaryQueryResult.RelevantResults.Table) {
  return this.processSearchResults2(result.RawSearchResults.PrimaryQueryResult.RelevantResults.Table);
} else {
  return sites;

To me that feels sort of messy. Lodash comes bundled with the SPFx installation, so you can do something cleaner like this:

let searchResults = lodash.get(result, "RawSearchResults.PrimaryQueryResult.RelevantResults.Table", []);

return this.processSearchResults2(searchResults);

The lodash.get() function is slick: it does the testing down the chain for you and also allows you to pass a default value to use if the object chain is undefined somewhere along the way. (Thanks to Julie [@jfj1997] for sharing her Bingle-fu on this one.)

By fixing my code for those two types of errors, I was able to get back to a good state. This is a relatively small Web Part, so it took me longer to write this post than to actually fix things.

This all means that it may be a little work to upgrade your SPFx solutions to 1.8.0. The value of getting these new errors, though, outweighs the annoyance of fixing the issues. Over time, TypeScript is going to help you write better code, and your solutions will be more foolproof. It won’t guarantee your code doesn’t have any bugs, but it may make it harder for you to write silly bugs into your code in the first place.

For some other insights on the SPFx release, check out these posts:

Have you found an useful article about SPFx 1.8.0? Please share in the comments…

  • Show original
  • .
  • Share
  • .
  • Favorite
  • .
  • Email
  • .
  • Add Tags 

With all of the changes happening in Office 365, it can be difficult to know how a particular thing works at any given point in time. I find myself doing little experiments all the time so I’m sure the information I give my clients is true – at least when I tell them! I figure some of the experiments might be useful for others, so why not do a quick blog post with the results?

Today’s question was how to determine which image in a News Post will be displayed as the thumbnail. The experiment showed me my assumptions would have been correct, but it’s always better to check than to assume.

When you create a News Post, you get a canvas to work with which looks like this:

You have two places where you can add an image in a News Post (or any modern page, really):

  • Header – This is the large area at the top of the News Post which has a dummy background image to start.
  • Body – This is the “meat” of the News Post – basically everything below the header.

In my experiment, I tried every combination I could think of. I used the same images from a Web Search for each test to ensure the images themselves wouldn’t come into play.

Header Image
Internal Image One
Internal Image Two

Here are the results.

  • Header Image Only – With only a header image, this is the image used in the News Web Part. No surprise here.
  • Internal Image Only – In this case, the internal image (added using the Image Web Part) was shown as the thumbnail. This was the variant I wasn’t totally sure about when I started.
  • Two Internal Images – With two Image Web Parts in the body, the first one was used as the thumbnail.
  • Header Image and Internal Image – With both a header image and an internal image, the header image was used as the thumbnail.
  • Image Gallery Only – When I used the Image Gallery Web Part (rather than the Image Web Part), the first image (leftmost, not necessarily the first one I added) in the Image Gallery was used as the thumbnail.
  • Header Image and Image Gallery – With both a header image and an internal image using the Image Gallery Web Part, the header image was used as the thumbnail.

So, no big surprises. But guess what? You can totally throw those rules out if you want to! You can change the thumbnail which is displayed in the Page details of the News Post itself when you edit the page. It can be one of the images you’ve already used (these are available in the Site Assets library in a folder like SitePages/Page-Name) or something entirely different.


There is a potential downside to the way the images are stored when you use the Web Search to find them. Each page gets its own folder in the Site Assets library, so if you reuse images – like I did in my experiment – you end up with multiple copies of each image. This is good because you can edit or alter each copy of the image for your needs. But it’s bad for image reuse.

Regardless how you think about this, it’s important from a content management perspective to understand the visual vocabulary you’re using in your site(s) so you can provide some consistency for your users and you can manage the corpus of imagery well.

  • Show original
  • .
  • Share
  • .
  • Favorite
  • .
  • Email
  • .
  • Add Tags 

At Sympraxis, we love interacting with the SharePoint community. Julie, Todd, and I try to get to as many great conferences as we can, whether we are speakers or just attendees.

We learn a lot attending the sessions, but the best part is often the interactions we have in the hallways and sides of session rooms. That’s where we learn about the great solutions you’re all building or what problems are keeping you up at night.

One of our all-time favorite conferences in the SharePoint Conference. It’s been around for many years, but has changed its guise a few times. These days, it’s the SharePoint Conference North America, and will be held in Las Vegas on May 21-23, 2019.

All three of us will be speaking this year, and we’re psyched about it. so psyched that Julie even convinced Todd and me to make a little video about it.

Join Sympraxis at SharePoint Conference NA - YouTube

Here’s some info on the session I’ll be doing. It’s called ‘Managing Content Types in the Modern World’, and in it I’ll talk about all the new things we should be thinking about as we are building out a strong information architecture in modern SharePoint.

When the order of the day was huge, pyramid-shaped Site Collections for capabilities like Intranets, managing your Content Types was relatively easy: any Site Columns and Content Types you built in the root site were available throughout the Site Collection. When we needed more enterprise-wide information architecture, we turned to the Content Type Hub. In our new, flatter world, we need to think about information architecture differently while hanging onto the better practices of the past.

That may be a bit vague. I’m hoping to be able to cover improvements we don’t even know about yet, but that I’ll learn about in the interim.

I hope to see you in Las Vegas in May. If you register with code MANDERSON, you can even save $50 off the registration fee!

  • Show original
  • .
  • Share
  • .
  • Favorite
  • .
  • Email
  • .
  • Add Tags 

This occasional series probably ought to be titled “How to solve a search problem by asking Mikael Svenson” (@MikaelSvenson), but he probably doesn’t want to be the world’s help desk for search. Luckily, I know him.

In my previous post, I showed how to simplify your code by using PnPJS and async/await. I didn’t focus much on what I was trying to accomplish. The goal of the search call was to get a list of all the sites (STS_Site) which the current user could access. We’ve built a My Team Sites SPFx Web Part and this call is in the services for it.

Over several weeks, we’ve been trying to get the Web Part to display what we want – which wasn’t as simple as we would have thought. If you work with the search APIs all the time, these things may be old hat to you, but since there is usually a big gap in between the times I use them, my memory can get a little fuzzy.

In the prior post in this series, I talked about how the way that the search API trims duplicates – which may make total sense in many ad hoc search results – can cause you to miss results you actually need. By setting TrimDuplicates to false, we can ask the search API to return all the results.

We ran into another search “feature” in this instance. Since we’re trying to retrieve all the sites to which the current user has access, we’re asking the search API to return objects where contentclass=STS_Site. I’d already turn off duplicate trimming – can’t catch me twice on that! But we still weren’t getting all of the sites back. Even more strangely, we were getting some modern sites back, but not others. The sites we were getting back and those we weren’t were darn near identical in their set up and use. Because they represented a project covering a specific scientific topic, the names of the sites were almost identical.

Here’s an abstraction of what we were seeing:

Site 1Site 2
Site TypeModern Team SiteModern Team Site

* In this case, my permissions as I was testing, but we checked with a few other people’s views as well.

As you can see, the only difference we could spot was the single character difference in the Title and URL for the site. Duplicate trimming could certainly have kicked in there, but we had already turned that off. (If you have any ideas of what else might be different, I’m all ears!)

After a discussion with Mikael, he suggested adding EnableDynamicGroups to the call. Magical – it worked! I can’t for the life of me understand why it worked, since we were seeing probably a good half of the modern Team Sites already, but since it worked, I guess we should just be happy with that. As Mikael told me, “turn off duplicate trimming and add that, and things usually work.”

If you’re using PnPJS and async/await- as I recommended in my prior post, then the change is in lines 14-20. We’ve simply added the EnableDynamicGroups property and set it to true.

private async _getSiteData(): Promise<ISPSite[]> {

    var thisDomain: string = location.host.split(".")[0];
    var exclusions: string[] = ["https://" + thisDomain + "-my.sharepoint.com", "https://" + thisDomain + ".sharepoint.com/portals/personal"];
    var exclusionString: string = " -Path:" + exclusions.join(" -Path:");
    exclusionString += " -Path=https://" + thisDomain + ".sharepoint.com";

    try {

      let result = await sp.search(<SearchQuery>{
        Querytext: "contentclass:sts_site " + exclusionString,
        RowLimit: 500,
        TrimDuplicates: false,
        Properties: [{
          Value: {
            BoolVal: true,
            QueryPropertyValueTypeIndex: QueryPropertyValueType.BooleanType
        SelectProperties: ["Title", "Path", "SiteLogo"]

      return this.processSearchResults(result);

    } catch (e) {

      return null;



Read for later

Articles marked as Favorite are saved for later viewing.
  • Show original
  • .
  • Share
  • .
  • Favorite
  • .
  • Email
  • .
  • Add Tags 

Separate tags by commas
To access this feature, please upgrade your account.
Start your free month
Free Preview