A Quick Look At The Get-PnPGroup Cmdlet And Its Operation

Why This Particular Topic?

I wouldn’t be surprised if some of you might be saying and asking, “Okay, that’s an odd choice for a post – even for you. Why?”

If you’re one of those people wondering, I would say that the sentiment and question are certainly fair. I’m actually writing this as part of my agreed upon “homework” from last Monday’s broadcast of the Community Office Hours podcast (I think that’s what we’re calling them). If you’re not immediately familiar with this particular podcast and its purpose, I’ll take two seconds out to describe.

I was approached one day by Christian Buckley (so many “interesting experiences” seem to start with Christian Buckley) about a thought he had. He wanted to start doing a series of podcasts each week to address questions, concerns, problems, and other “things” related to Office 365, Microsoft Teams, and all the O365/M365 associated workloads. He wanted to open it up as a panel-style podcast, and although anyone could join, he was interested in rounding-up a handful of Microsoft MVPs to “staff” the podcast in an ongoing capacity. The idea sounded good to me, so I said “Count me in” even before he finished his thoughts and pitch.

I wasn’t sure what to expect initially … but we just finished our 22nd episode this past Monday, and we are still going strong. The cast on the podcast rotates a bit, but there are a few of us that are part of what I’d consider the “core group” of entertainers …

The podcast has actually become something I look forward to every Monday, especially with the pandemic and the general lack of in-person social contact I seem to have (or rather, don’t have). We do two sections of the podcast every Monday: one for EMEA at 11:00am EST and the other for APAC at 9:00pm EST. You can find out more about the podcast in general through the Facebook group that’s maintained. Alternatively, you can send questions and things you’d like to see us address on the podcast to OfficeHours@CollabTalk.com.

If you don’t want (or have the time) to watch the podcast live, an archive of past episodes exists on Christian’s site, I maintain an active playlist of the recorded episodes on YouTube, and I’m sure there are other repositories available.

Ok, Got It. “Your Homework,” You Say?

The broadcasts we do normally have no fixed format or agenda, so we (mostly Christian) tend to pull questions and topics to address from the Facebook group and other places. And since the topics are generally so wide-ranging, it goes without saying that we have viable answers for some topics … but there are plenty of things we’re not good at (like telephony) and freely tell you so.

Whenever we get to a question or topic that should be dealt with outside the scope of the podcast (oftentimes to do some research or contact a resource who knows the domain), we’ll avoid BSing too much … and someone will take the time to research the topic and return back the following week with what they found or put together. We’re trying to tackle a bunch of questions and topics each week, and none of us is well-versed in the entire landscape of M365. Things just change so darn fast these days ….

So, my “homework” from last week was one of these topics. And I’m trying to do one better than just report back to the podcast with an answer. The topic and research may be of interest to plenty of people – not just the person who asked about it originally. Since today is Sunday, I’m racing against the clock to put this together before tomorrow’s podcast episodes …

The Topic

Rather than trying to supply a summary of the topic, I’m simply going to share the post and then address it. The inquiry/post itself was made in the Office 365 Community Facebook group by Bilal Bajwa. Bilal is from Milwaulkee, Wisconsin, and he was seeking some PowerShell-related help:

Being the lone developer in our group of podcast regulars (and having worked a fair bit with the SharePointPnP Cmdlets for PowerShell and PowerShell in general), I offered to take Bilal’s post for homework and come back with something to share. As of today (Sunday, 8/23/2020), the post is still sitting in the Facebook group without comment – something I hope to change once this blog post goes live in a bit.

SharePointPnP Cmdlets And The Get-PnPGroup Cmdlet Specifically

If you’re a SharePoint administrator and you’re unfamiliar with the SharePoint Patterns and Practices group and the PowerShell cmdlets they maintain, I’M giving YOU a piece of homework: read the Microsoft Docs to familiarize yourself with what they offer and how they operate. They will only help make your job easier. That’s right: RTFM. Few people truly enjoy reading documentation, but it’s hard to find a better and more complete reference medium.

If you are already familiar with the PnP cmdlets … awesome! As you undoubtedly know, they add quite a bit of functionality and extend a SharePoint administrator’s range of control and options within just about any SharePoint environment. The PnP group that maintains the cmdlets (and many other tools) are a group of very bright and very giving folks.

Vesa Juvonen is one name I associate with pretty much anything PnP. He’s a Principal Program Manager at Microsoft these days, and he directs many of the PnP efforts in addition to being an exceptionally nice (and resourceful!) guy.

The SharePoint Developer Blog regularly covers PnP topics, and they regularly summarize and update PnP resource material – as well as explain it. Check out this post for additional background and detail.

Cmdlet: Get-PnPGroup

Now that I’ve said all that, let’s get started with looking at the Get-PnPGroup cmdlet that is part of the SharePointPnP PowerShell module. I will assume that you have some skill with PowerShell and have access to a (SharePoint) environment to run the cmdlets successfully. If you’re new to all this, then I would suggest reviewing the Microsoft Docs link I provide in this blog post, as they cover many different topics including how to get setup to use the SharePoint PnP cmdlets.

In his question/post, Bilal didn’t specify whether he was trying to run the Get-PnPGroup cmdlet against a SharePoint Online (SPO) site or a SharePoint on-premises farm. The operation of the SharePointPnP cmdlets, while being fairly consistent and predictable from cmdlet to cmdlet, sometimes vary a bit depending on the version of SharePoint in-use (on-premises) or whether SPO is being targeted. In my experience, the exposed APIs and development surfaces went through some enhancement after SharePoint 2013 in specific areas. One such area that was affected was data pertaining to site users and their alerts; the data is available in SharePoint 2016 and 2019 (as well as in SPO), but it’s inaccessible in 2013.

Because of this, it is best to review the online documentation for any cmdlet you’re going to use. Barring that, make sure you remember the availability of the documentation if you encounter any issues or behavior that isn’t expected.

If we do this for Get-PnPGroup, we frankly don’t get too much. The online documentation at Microsoft Docs is relatively sparse and just slightly better than auto-generated docs. But we do get a little helpful info:

We can see from the docs that this cmdlet runs against all versions of SharePoint starting with SharePoint 2013. I would therefore expect operations to be generally be consistent across versions (and location) of SharePoint.

A little further down in the documentation for Get-PnPGroup (in Example 1), we find that simply running the cmdlet is said to return all SharePoint groups in a site. Let’s see that in practice.

Running Wild

I fired up a VM-based SharePoint 2019 farm I have to serve as the target for on-prem tests. For SPO, I decided to use my family’s tenant as a test target. Due to time constraints, I didn’t get a chance to run anything against my VM environment, so I’m assuming (dangerous, I know) that on-prem results will match SPO. If they don’t, I’m sure someone will tell me below (in the Comments) …

Going against SPO involves connecting to the tenant and then executing Get-PnPGroup. The initial results:

Running Get-PnPGroup returned something, and it’s initially presented to us in a somewhat condensed table format that includes ID, (group) Title, and LoginName.

But there’s definitely more under the hood than is being shown here, and that “under the hood” part is what I suspect might have been causing Bilal some issues when he looked at his results.

We’ve all probably heard it before at some point: PowerShell is an object-oriented scripting language. This means that PowerShell manipulates and works with Microsoft .NET objects behind-the-scenes for most things. What may appear as a scalar value or simple text data on first inspection could be just the tip of the “object iceberg” when it comes to PowerShell.

Going A Bit Deeper

To learn a bit more about what the function is actually returning upon execution, I ran the Get-PnPGroup cmdlet again and assigned the function return to a variable I called $group (which you can see in the screen capture earlier). Performing this variable assignment would allow me to continue working with the function output (i.e., the SharePoint groups) without the need to keep querying my SharePoint environment.

To display the contents of $group with additional detail, the PowerShell I executed might appear a little cryptic for those who don’t live in PowerShellLand:

$group | fl

There’s some shorthand in play with that last bit of PowerShell, so I’ll spell everything out. First, fl is the shorthand notation for the Format-List cmdlet. I could have just as easily typed …

$group | Format-List

… but that’s more typing! I’m no different than anyone else, and I like to get more done with less whenpossible.

Next, the pipe (“|”) will be familiar to most PowerShell practitioners, and here it’s used to send the contents of the $group variable to the Format-List cmdlet. The Format-List cmdlet then expands the data piped to it (i.e., the SharePoint groups in $group) and shows all the property values that exist for each SharePoint group.

If you’re not familiar with .NET objects or object-oriented development, I should point out that the SharePoint groups returned and assigned to our $group variable are .NET objects. Knowing this might help your understanding – or maybe not. Try not to worry if you’re not a dev and don’t speak dev. I know that to many admins, devs might as well be speaking jive …

For our purposes today, we’re going to limit our discussion and analysis of objects to just their properties – nothing more. The focus still remains PowerShell.

What Are The Actual Properties Available To Us?

If you’re asking the question just posed, then you’re following along and hopefully making some kind of sense of a what I’m sharing.

So, what are the properties that are exposed by each of the SharePoint groups? Looking at the output of the $group variable sent to the Format-List command (shown earlier) gives you an idea, but there’s a much quicker and more reliable way to get the listing of properties.

You may not like what I’m about to say, but it probably won’t surprise you: those properties are documented (for everyone to learn about) in Microsoft Docs. Yes, another documentation reference!

How did I know what to look/search for? If you refer to the end of the reference for the Get-PnPGroup cmdlet, there is a section that describes the “Outputs” from running the cmdlet. That output is only one line of text, and it’s exactly what we need to make the next hop in our hunt for properties details:

List<Microsoft.SharePoint.Client.Group>

A List is a .NET collection class, but that’s not important for our purposes. Simply put, you can think of a .NET List as a “bucket” into which we put other objects – including our SharePoint groups. The class/type that is identified between the “<” and “>” after List specify the type of each object in the List. In our case, each item in the List is of type Microsoft.SharePoint.Client.Group.

If you search for that class type, you’ll get a reference in your search results that points to a Microsoft Docs link serving as a reference for the SharePoint Group type we’re interested in. And if we look at the “Properties” link of that particular reference, each of the properties that appear in our returned groups are spelled out with additional information – in most cases, at least basic usage information is included.

A quick look at those properties and a review of one of the groups in the $group variable (shown below) should convince you that you’re looking at the right reference.

What Do We Do Now?

You might recall that we’re going through this exercise of learning about the output from the Get-PnPGroup cmdlet because Bilal asked the question, “Any idea how to filter?”

Hopefully the output that’s returned from the cmdlet makes some amount of sense, and I’ve convinced you (and Bilal) that it’s not “garbage” but a List collection of .NET objects that are all of the Microsoft.SharePoint.Client.Group type.

At this point, we can leave our discussion of .NET objects behind (for the most part) and transition back to PowerShell proper to talk about filtering. We could do our filtering without leaving .NET, but that wouldn’t be considered the “PowerShell way” of doing it. Just remember, though: there’s almost always more than one way to get the results you need from PowerShell …

Filtering The Results

In the case of my family’s SPO tenant, there are a total of seven (7) SharePoint groups in the main site collection:

Looking at a test case for filtering, I’m going to try to get any group that has “McDonough” in its name.

A SharePoint group’s name is the value of the Title property, and a very straightforward way to filter a collection of objects (which we have identified exists within our $group variable) is through the use of the Where-Object cmdlet.

Let’s setup some PowerShell that should return only the subset of groups that I’m interested in (i.e., those with “McDonough” in the Title). Reviewing the seven groups in my site collection, I note that only three (3) of them contain my last name. So, after filtering, we should have precisely three groups listed.

Preparing the PowerShell …

$group | where-object {$_.Title -like "*McDonough*"}

… and executing this, we get back the filtered results predicted and expected; i.e., three SharePoint groups:

For those that could use a little extra clarification, I will summarize what transpired when I executed that last line of PowerShell.

  1. From our previous Get-PnPGroup operation, we knew that the $group variable contained the seven groups that exist in my site collection.
  2. We piped (“|”) that unfiltered collection of groups to the Where-Object cmdlet. It’s worth pointing out that the cmdlets and most of the other strings/text in PowerShell are case-insensitive (Where-Object, where-object, and WhErE-oBjEcT are all the same from a PowerShell processing perspective).
  3. The curly braces after the where-object cmdlet define the logic that will be processed for each object (i.e., SharePoint group) that is passed to the where-object cmdlet.
  4. Within the curly braces, we indicated that we wanted to filter and keep each group that had a Title which was like “*McDonough*” This was accomplished with the -like operator (PowerShell has many other operators, too). The asterisks before and after “McDonough” are simply wildcards that will match against anything with “McDonough” in the Title – regardless of any text or characters appearing before and/or after “McDonough”
  5. Also worth nothing within the curly braces is the “$_.” notation. When iterating through the collection of SharePoint groups, the “$_.” denotes the current object/group we’re evaluating – each one in turn.

Round Two

Let’s try another one before pulling the plug (figuratively and literally – it’s close to my bed time …)

Let’s filter and keep only the groups where the members of the group can also edit the group membership. This is an uncommon scenario, and we might wish to know this information for some potential security tightening.

Looking at the properties available on the Group type, I see the one I’m interested in: AllowMembersEditMembership. It’s a boolean value, and I want back the groups that have a value of true (which is represented as $true in PowerShell) for this property.

$group | where-object {$_.AllowMembersEditMembership -eq $true}

Running the PowerShell just presented, we get only one matching group back:

Frankly, that’s one more group than I originally expected, so I should probably take a closer look in the ol’ family site collection …

Summary

I hope this helped you (and Bilal) understand that there is a method to PowerShell’s madness. We just need to lean on .NET and objected oriented concepts a bit to help us get what we want.

The filtering I demonstrated was pretty basic, and there are numerous ways to take it further and get more specific in your filtering logic/expressions. If you weren’t already comfortable with filtering, I hope you now know that it isn’t really that hard.

If I happened to skip or gloss over something important, please leave me a note in the Comments section below. My goal was to provide a complete-enough picture to build some confidence – so that the next time you need to work with objects and filter them in PowerShell, you’ll feel comfortable doing so.

Have fun PowerShelling!

References And Resources

  1. LinkedIn: Christian Buckley
  2. Podcast History: Microsoft Community Office Hours from 8/18/2020
  3. BuckleyPLANET: Community category and activities
  4. Facebook Group: Office 365 Community
  5. Email Group: OfficeHours@CollabTalk.com
  6. YouTube: Microsoft Community Office Hours playlist
  7. Microsoft Docs: PnP PowerShell Overview
  8. LinkedIn: Vesa Juvonen
  9. Blog: SharePoint Developer Blog
  10. Blog Post: Microsoft 365 & SharePoint Ecosystem (PnP) – July 2020 Update
  11. Microsoft Docs: Get-PnPGroup
  12. Microsoft: What Is .NET Framework?
  13. Microsoft Docs: Format-List
  14. Microsoft Docs: List<T> Class
  15. Microsoft Docs: Group Class
  16. Microsoft Docs: Group Properties
  17. Microsoft Docs: Where-Object
  18. Microsoft Docs: About Comparison Operators

What CDN Usage Does for SharePoint Online (SPO) Performance

If you need the what’s what on CDNs (content delivery networks), this is a bit of quick reading that will get you up to speed with what a CDN is, how to configure your SPO tenant to use a CDN, and the benefits that CDNs can bring.

The (Not Entirely Obvious) TL;DR Answer

CDN

Since I’m taking the time to write about the topic, you can safely guess that yes, CDNs make a difference withSPO page operations. In many cases, proper CDN configuration will make a substantial difference in SPO page performance. So enable CDN use NOW!

The Basis For That Answer: Introduction

Knowing that some folks simply want the answer up-front, I hope that I’ve satisfied their curiosity. The rest of this post is dedicated to explaining content delivery networks (CDNs), how they operate, and how you can easily enable them for use within your SharePoint Online (SPO) sites.

Let me first address a misconception that I sometimes encountered among SPO administrators and developers (including some MVPs) – that being that CDNs don’t really “do a whole lot” to help site and/or page performance. Sure, usage of a CDN is recommended … but a common misunderstanding is that a CDN is really more of a “nice-to-have” than “need-to-have” element for SPO sites. Of the people saying such things, oftentimes that judgment comes without any real research, knowledge, or testing. Skeptics typically haven’t read the documentation (the “non-RTFM crowd”) and haven’t actually spent any time profiling and troubleshooting the performance of SPO sites. Since I enjoy addressing perf. problems and challenges, I’ve been fortunate to experience firsthand the benefits that CDNs can bring. By the end of this post, I hope I’ll have made converts of a CDN skeptic or two.

What Is A CDN?

Abstract Network

A CDN is a Content Delivery Network. There are a lot of (good) web resources that describe and illustrate what CDNs are and how they generally operate (like this one and this one), so I’m not going to attempt to “add value” with my own spin. I will simply call attention to a couple of the key characteristics that we really care about in our use of CDNs with SPO.

  1. A CDN, at its core, can be thought of as a system of distributed (typically geographically so) servers for caching and offloading of SPO content. Rather than needing to go to the Microsoft network and data center where your tenant is located in order to fetch certain files from SPO, your browser can instead go to a (geographically) closer CDN server to get those same files.
  2. By virtue of going to a closer CDN instead of the Microsoft network, the chance that you’ll have a “bigger pipe” with more bandwidth – and less latency/delay – are greater. This usually translates directly to an improvement in performance.
  3. In addition to giving us the opportunity to download certain SPO files faster and with less delay, CDNs can do other things to improve the experience for the SPO files they serve. For instance, CDN servers can pass files back to the browser with cache-control headers that allow browsers to re-serve downloaded files to other users (i.e, to users who haven’t actually download the files), store downloaded files locally (to avoid having to download them again for a period of time), and more.

If you didn’t know about CDNs prior to this post, or didn’t understand how they could help you, I hope you’re beginning to see the possibilities!

The Arrival Of The Office 365 CDN

It wasn’t all that long ago that Microsoft was a bit more “modest” in its use of CDNs. Microsoft certainly made use of them, but prior to the implementation of its own content delivery networks, Microsoft frequently turned to a company called Akamai for CDN support.

When I first started presenting on SharePoint and its built-in caching mechanisms, I often spoke about Akamai and their edge network when talking about BLOB caching and how the max-age cache-control header could be configured and misconfigured. Back then, “Akamai” was basically synonymous with “CDN,” and that’s how many of us thought about the company. They were certainly leading the pack in the CDN service space.

Back then, if you were attempting to download a large file from Microsoft (think DVD images, ISO files, etc.), then there was a good change that the download link your browser would receive (from Microsoft’s servers) would actually point to an Akamai edge node near your location geographically instead of a Microsoft destination.

Fast forward to today. In addition to utilizing third-party CDNs like those deployed by Akamai, Microsoft has built (and is improving) their own first-party CDNs. There are a couple of benefits to this. First, many data regulations you may be subject to that prevent third-party housing of your data (yes, even in temporary locations like a CDN) can be largely avoided. In the case of CDNs that Microsoft is running, there is no hand-off to a third party and thus much less practical concern regarding who is housing your data.

Second, with their own CDNs, Microsoft has a lot more latitude and ability to extend the specifics of CDN configuration and operation its customers. And that’s what they’ve done with the Office 365 CDN.

Set Up The O365 CDN For Tenant’s Use

Now we’re talking! This next part is particularly important, and it’s what drove the creation of this post. It’s also the one bit of information that I promised Scott Stewart at Microsoft that I would try to get “out in the wild” as quickly and as visibly as possible.

So, if you remember nothing else from this post,please remember this:

Set-SPOTenantCdnEnabled -CdnType Public -Enable $true

That is the line of PowerShell that needs to be executed (against your SPO tenant, so you need to have a connection to your tenant established first) to enable transparent CDN support for public files. Run that, and non-sensitive files of public origin from SPO will begin getting cached in a CDN and served from there.

The line of PowerShell I shared goes through the SharePoint Online Management Shell – something most organizations using SPO (and their admins in particular) have installed somewhere.

It is also possible to enable CDN support if you’re using the PNP PowerShell module, if that’s your preference, by executing the following PowerShell:

Set-PnPTenantCdnEnabled -CdnType Public -Enable $true

No matter how you enable the CDN, it should be noted that the PowerShell I’ve elected to share (above) enables CDN usage for files of public origin only. It is easy enough to alter the parameters being passed in our PowerShell command so as to cover all files, public and private, by switching -CdnType to Both (with the SPO management shell) or executing another line of PowerShell after the first that swaps –type Public with –type Private (in the case of the SharePointPnP PowerShell module).

The reason I chose only public enablement is because your organization may be bound by restrictions or policies that prohibit or limit CDN use with private files. This is discussed a bit in the O365 CDN post originally cited, but it’s best to do your own research.

Enabling CDN support for public files, however, is considered to be safe in general.

What Sort Of Improvements Can I Potentially See?

I’ve got a series of images that I use to illustrate performance improvements when files are served via CDN instead of SPO list/library, and those files are from Microsoft. Thankfully, MS makes the images I tend to use (and a discussion of them) free available, and they are presented at this link for your reading and reference.

The example that is called out in the link I just shared involves offloading of the jQuery JavaScript library from SPO to CDN. The real world numbers that were captured reduced fetch-and-load time from just over 1.5 seconds to less than half a second (<500ms). That is no small change … and that’s for just one file!

The Other (Secret) Benefit Of CDNs

I guess “Secret” is technically the wrong choice of term here. A more accurate description would be to say that I seldom hear or see anyone talking about another CDN benefit I consider to be very important and significant. That benefit, quite simply, involves improving file fetching and retrieval parallelism when a web page and associated assets (CSS, JS, images, etc.) are requested for download by your browser. In plain English: CDNs typically improve file downloading by allowing the browser to issue a greater number of concurrent file requests.

To help with this concept and its explanation, I’ve created a couple of diagrams that I’ll share with you. The first one appears below, and it is meant to represent the series of steps a browser might execute when retrieving everything needed to show a (SharePoint/SPO) page. As we’ve talked about, what is commonly thought of as a single page in a SharePoint site is, more accurately, a page containing all sorts of dependent assets: image files, JavaScript files, cascading style sheets, and a whole bunch more.

A request for a SharePoint page housed at http://www.thesite.com might start out with one request, but your browser is going to need all of the files referenced within the context of that page (default.aspx, in our case) to render correctly. See below:

To get what’s needed to successfully render the example SharePoint page without CDN support, we follow the numbers:

  1. Your browser issues an HTTP request for the page you want to load – http://www.thesite.com/default.aspx in the case of example above.
  2. That page request goes to (and is served by) the web server/front-end that can return the page.
  3. Our page needs other files to render properly, like styling.css, logo.png, functions.js, and more. These get queued-up and returned according to some rules – more on this in a minute.
  4. In step four (4), files get returned to the browser. Notice I say “no more than six at a time” in the illustration. That’s important and will come into play once we start introducing CDN support to the page/site.

You might be wondering, “Only six files at a time? Really? Why the limitation?” Well, I should start by saying the limit is probably six … maybe a bit more, perhaps a bit less. It depends on the browser you’re using what the specific number is. There was a good summary answer on StackOverflow to a related (but slightly different) question that provides some additional discussion.

Section eight (8) of the HTTP specification (RFC 2616) specifically addresses HTTP connections, how they should be handled, how proxies should be negotiated, etc. For our purposes, the practical implementation of the HTTP specification by modern browsers generally limits the number of concurrent/active connections a browser can have to any given host or URL to six (6).

Notice how I worded that last sentence. Since you folks are smart cookies, I’ll bet you’re already thinking “Wait a minute. CDNs typically have different URLs/hosts from the sites they cache” and you’re imaging what happens (or can happen) when a new source (i.e., different host/URL) is introduced.

This illustration roughly outlines the fetch process when a CDN is involved:

Steps one (1) through four (4) of the fetch process with a CDN are basically still the same as was illustrated without a CDN a bit earlier. When the page is served-up in step three (3) and returned in step four (4), though, there are some differences and additional activity taking place:

  1. Since at least one CDN is in-use for the SPO environment, some of the resource links within the page that is returned will have different URLs. For instance, whereas styling.css was previously served from the SPO environment in the non-CDN example, it might now be referenced through the CDN host shown as http://cdn.source.com/styling.css
  2. The requested file is retrieved, and …
  3. Files come back to the client browser from the CDN at the same time they’re being passed-back from the SPO environment.

Since we’re dealing with two different URLs/hosts in our CDN example (http://www.thesite.com and cdn.source.com), our original six (6) file concurrent download limitation transforms into a 12 file limitation (two hosts serving six files a time, 2 x 6 = 12).

Whether or not the CDN-based process is ultimately faster than without a CDN depends on a great many factors: your Internet bandwidth, the performance of your computer, the complexity/structure of the page being served-up, and more. In the majority of cases, though, at least some performance improvement is observed. In many cases, the improvement can be quite substantial (as referenced and discussed earlier).

Additional Note: 8/24/2020

In a bit of laziness on my part, I didn’t do a prior article search before writing this post. As fate would have it, Bob German (a friend and fellow MVP – well, he was an MVP prior to joining Microsoft a couple of years back) wrote a great post at the end of 2017 that I became aware of this morning with a series of tweets. Bob’s post is called “Choosing a CDN for SharePoint Client Solutions” and is a bit more developer-oriented. That being said, it’s a fantastic post with good information that is a great additional read if you’re looking for more material and/or a slightly different perspective. Nice work, Bob!

Post Update: 8/26/2020

Anders Rask was kind enough to point out that the PnP PowerShell line I originally had listed wasn’t, in fact, PnP PowerShell. That specific line of PowerShell has since been updated to reflect the correct way of altering a tenant’s CDN with the PnP PowerShell cmdlets. Many thanks for the catch, Anders!

Conclusion

So, to sum-up: enable CDN use within your SPO tenant. The benefits are compelling!

References

  1. Microsoft Docs: Use The Office 365 Content Delivery Network (CDN) With SharePoint Online
  2. Imperva: What Is A CDN?
  3. Akamai: What Does CDN Stand For?
  4. MDN Web Docs: Cache-Control
  5. Company: Akamai
  6. Presentations: Caching-In For SharePoint Performance
  7. Akamai: Download Delivery
  8. Microsoft Docs: Configure Cache Settings For A Web Application In SharePoint Server
  9. Blog Post: Do You Know What’s Going To Happen When You Enable The SharePoint BLOB Cache?
  10. LinkedIn: Scott Stewart
  11. Microsoft Docs: Enabling O365 CDN support for public origin files.
  12. Microsoft Docs: Get Started With SharePoint Online Management Shell
  13. Microsoft Docs: PnP PowerShell Overview
  14. Microsoft Docs: Set Up And Configure The Office 365 CDN By Using PnP PowerShell
  15. Microsoft Docs: What Performance Gains Does A CDN Provide?
  16. Push Technologies: Browser Connection Limitations
  17. StackOverflow: How many maximum number of simultaneous Chrome connections/threads I can start through Selenium WebDriver?
  18. W3.org: RFC 2616, Section 8: Connection

One Tool to Rule Them All

Microsoft released the second iteration of its Page Diagnostics Tool for SharePoint. If you have an SPO site, you NEED this tool in your toolbox!

Last week, on Wednesday, September 18th, 2019, Microsoft released the second iteration of its Page Diagnostics Tool for SharePoint. An announcement was made, and the Microsoft Docs site was updated, but the day passed with very little fanfare in most circles.

“The One Ring” by Mateus Amaral is licensed under CC BY-NC-ND 4.0 

In my opinion, there should have been fireworks. Lots of fireworks.

What is it?

If you’re not familiar with the Page Diagnostics Tool for SharePoint, then I need to share a little history on how I came to be “meet” this tool.

Back in 2018, the SharePoint Conference North America (SPCNA) was rebooted after having been shutdown as part of Microsoft’s consolidation of product-specific conferences a number of years earlier. I had the good fortune of making the cut to deliver a couple of sessions at the conference: “Making the Most of OneDrive for Business and SharePoint Online” and “Understanding and Avoiding Performance Pitfalls with SharePoint Online.”

Sometime in the months leading up to the conference, I received an email from out-of-the-blue from a guy named Scott Stewart – who at the time was a Senior Program Manager for OneDrive and SharePoint Engineering. In the email, Scott introduced himself, what he did in his role, and suggested that we collaborate together for the performance session I was slated to deliver at SPCNA.

I came to understand that Scott and his team were responsible for addressing and remedying many of the production performance issues that arose in SharePoint Online (SPO). The more that Scott and I chatted, the more it sounded like we were preaching many of the same things when it came to performance.

One thing Scott revealed to me was that at the time, his team had been working on a tool to help diagnose SPO performance issues. The tool was projected to be ready around the time that SPCNA was happening, so I asked him if he’d like to co-present the performance session with me and announce the tool to an audience that would undoubtedly be eager to hear the news. Thankfully, he agreed!

The audience for our performance talk at SPCNA 2018

Scott demo’d version one (really it was more like a beta) during our talk, and the demo demons got the better of him … but shortly after the conference, v1.0 of the tool went live and was available to download as a Chrome browser extension.

So, what does it do?

Simply put, the Page Diagnostics Tool for SharePoint analyzes your browser’s interaction with SPO and points out conditions and configurations that might be adversely affecting your page’s performance.

The first version of the tool only worked for classic publishing pages. And as a tool, it was only available as a Google Chrome Extension:

The Page Diagnostics for SharePoint extension in the Google Chrome Store

The second iteration of the tool that was released last Thursday addresses one of those limitations: it analyzes both modern and classic SharePoint pages. So, you’re covered no matter what’s on your SPO site.

What Can the Tool Tell Me?

For one thing, the tool can get you the metrics I’ve highlighted that are relevant to diagnosing basic page performance issues – most notably, SPRequestDuration and SPIisLatency. But it can do so much more than that!

Many of the adverse performance conditions and scenarios I’ve covered while speaking and in blog posts (such as this one here) are analyzed and called-out by the tool, as well as many other things/conditions, such as navigational style used, whether or not content deployment networks (CDNs) are used by your pages, and quite a few more.

And finally, the tool provides a simple mechanism for retrieving round-trip times for pages and page resource requests. It eliminates the need to pull up Fiddler or your browser’s debug tools to try and track down the right numbers from a scrolling list of potentially hundreds of requests and responses.

How Do I Use It?

It’s easy, but I’ll summarize it for you here.

1. Open the Chrome Web Store. Currently, the extension is only available for Google Chrome. Open Chrome and navigate to https://chrome.google.com/webstore/search/sharepoint directly or search for “SharePoint” in the Chrome Web Store. However you choose to do it, you should see the Page Diagnostics Tool for SharePoint entry within the list of results as shown below.

2. Add the Extension to Chrome. Click the Add to Chrome button. You’ll be taken directly to the diagnostic tool’s specific extension page, and then Chrome will pop up a dialog like the one seen below. The dialog will describe what the tool will be able to do once you install it, and yes: you have to click Add Extension to accept what the dialog is telling you and to actually activate the extension in your browser.

3. Navigate to a SharePoint Online page to begin diagnosing it. Once you’ve got the extension installed, you should have the following icon in the tool area to the right of the URL/address bar in Chrome:

To illustrate how the tool works, I navigated to a modern Communication Site in my Bitstream Foundry tenant:

I then clicked on the SharePoint Page Diagnostics Tool icon in the upper right of the browser (as shown above). Doing so brings up the Page Diagnostics dialog and gives me some options:

Kicking off an analysis of the current page is as simple as clicking the Start button as shown above. Once you do so, the page will reload and the Tool dialog will change several times over the course of a handful of seconds based on what it’s loading, analyzing, and attempting to do.

When the tool has completed its analysis and is ready to share some recommendations, the dialog will change once again to show something similar to what appears below.

Right off the bat, you can see that the Page Diagnostics Tool supplies you with important metrics like the SPRequestDuration and SPIIsLatency – two measures that are critical to determining where you might have some slowdown as called out in a previous blog post. But the tool doesn’t stop there.

The tool does many other things – like look at the size of your images, whether or not you’re using structural navigation (because structural navigation is oh so bad for your SPO site performance), if you’re using content delivery networks (CDNs) for frequently used scripts and resources, and a whole lot more.

Let’s drill into one of the problem items it calls out on one of my pages:

The tool explains to me, in plain English, what is wrong: Large images detected. An image I’m using is too large (i.e., larger than 300KB). It supplies the URL of the image in question so that I’m not left wondering which image it’s calling out. And if I want to know why 300KB is special or simply learn about the best way to handle images in SharePoint Online, there’s a Learn More link. Clicking that link takes me to this page in Microsoft Docs:

Targeted and detailed guidance – exactly what you need in order to do some site fixup/cleanup in the name of improving performance.

Wrapping-Up

There’s more that the tool can do – like provide round trip times for pages and assets within those pages, as well as supply a couple of data export options if you want to look at the client/server page conversation in a tool that has more capabilities.

As a one-stop shop tool, though, I’m going to basically start recommending that everyone with an SPO site start downloading the tool for use within their own tenants. There is simply no other tool that is easier and more powerful for SharePoint Online sites. And the price point is perfect: FREE!

The next time you see Scott Stewart, buy him a beer to thank him for giving us something usable in the fight against poorly performing SPO sites.

References and Resources

  1. Company: Microsoft
  2. Browser Extension: Page Diagnostics for SharePoint
  3. Microsoft Docs: Use the Page Diagnostics for SharePoint tool
  4. Conference: The SharePoint Conference North America
  5. Presentation Resource: Making the Most of OneDrive for Business and SharePoint Online
  6. Presentation Resource: Understanding and Avoiding Performance Pitfalls with SharePoint Online
  7. LinkedIn: Scott Stewart
  8. Blog Post: The Five-Minute Page Performance Troubleshooting Guide for SharePoint Online
  9. Blog Post: Caching, You Ain’t No Friend of Mine
  10. Tool: Telerik Fiddler
  11. Web Page: Chrome Web Store Extensions
  12. Microsoft Docs: Optimize images in SharePoint Online modern site pages

What Happened To My Office 365 Public Site?

Close Out (Early 2016)

It would appear that things are more or less back to normal. I never got an “everything is okay and live” email, but theming and branding are working properly both on public sites (tick, tock, tick, tock …) and internal sites. No conflicts at this point. Since I like to tie things up when complete, we’ll call this one “done” for now and move on.

What the heck happened?Update (Evening 7/23/2015)

Microsoft has been looking at this issue, and progress is being made! My public site looks like it has returned to normal … but I know that we’re not quite out of the woods yet.

John from Microsoft followed-up with me yesterday and said the following:

“We have pulled the flight that was impacting everyone from production.  The plan is to address these issues before turning the flight back on.  Would you be up for piloting the upgraded flight before we turn it back on for everyone? Also, you mention you know others who are having problems, would they be willing to pilot the new flight as well?  If so, please provide their contact information so I can follow up with them.”

Clearly, there’s a strong “flying vibe” in Redmond ….

I told John that I was definitely a “go” for the flight, and that I knew some others who’d experienced problems. And that’s where I’m hoping that some of you can help.

If you have been encountering problems with your Office 365 public site that are similar to mine – and you want to be part of the fix – let me know and I’ll hook you up with John. Shoot me your name, email address, and public site URL; I think that will do the job.

Stay tuned!

Original Post (below)

First of all, let me state that I’m not talking about the fact that Office 365 public sites are going the way of the dinosaur. That’s old news at this point. Instead, I’m talking about a “disruption in the force” that some of you may have observed when recently browsing to your public sites and discovering that they had … changed.

And what do I mean by “changed?” In my case, it was the observation that my public site’s branding had been altered to something I hadn’t chosen. The background image was different, the fonts weren’t the same, a number of the CSS styles I had applied to address scrollbar positioning and what-not weren’t in effect, and more. In essence, my custom branding had been completely steamrolled.

The After And The (Sort-Of Before)

Office 365 Public Site: Forcing Some Branding Elements BackOffice 365 Public Site: Busted BrandingDon’t take my word for it, though. Have a look for yourself. On the left is my public site as I discovered it a couple of weeks back (i.e., near the beginning of July, 2015). On the right is the way it’s supposed to look … sort of. The fonts and aspects of the responsive design are still off in the “corrected” version on the right, but I managed to hack the proper background, scrollbars, and a few other elements back to where they were previously. Even though I didn’t get everything corrected, differences between the two are immediately obvious.

I was confident that it had been months since I had changed anything on my public site, but I verified the branding assets in the Office 365 site against what I was tracking in source control. As expected, they were identical. The changes I was observing were not due to anything I had done to the public site.

Grumble Grumble …

Facebook Complaint About Branding IssueSince it wasn’t the first time I’d had issues with unexpected changes and behavior on my public site, I wasted little time before going to Facebook to complain aloud. Many of my friends in the SharePoint community are also friends on Facebook, so I figured I’d get some support (moral, if nothing else) there.

Shortly after posting the update seen on the left, I tagged a couple of my Microsoft friends (specifically, Jeremy Thake and Chris Johnson) who work with the Office 365 team(s) and asked if I should have known about an update or change that might have affected my public site in this fashion. Even though I was confident that I hadn’t done anything to directly impact my public site’s look-and-feel, I was not about to rule out the possibility that I had missed something that had been communicated to me. In fact, I have been consulting in information technology long enough to know that my “mental glove” doesn’t catch everything thrown to me; anymore, I just kind of assume that I am in error and work from there.

Jeremy got back to me first and indicated that he didn’t have anything specific to share, but he indicated he would take the issue to folks (internally) who should know. Shortly after that, Chris tagged Steve Walker (another Microsoftee with superhuman powers) to bring the issue to his attention. Steve told me to file a service request (SR) and that he would escalate that SR right away. So, I filed the service request with supporting screenshots and documentation … and as he had indicated he would, Steve escalated the SR in less than an hour.

In the meantime, I did what I could to get some of my site’s branding back to the way it had been. How did I do that? With the liberal application of the dreaded !important CSS directive in the custom style sheet I had created to go with my master page. The !important directive is definitely not something I use (or even like to go near) on a daily basis, but in this case, I was trying to achieve results with a minimal investment of time and effort. I needed my styling to trump whatever was being laid-down after my style sheet was being processed.

So, What Happened Next?

Following Steve’s escalation, I started working with an extremely approachable escalation engineer named John. John and I exchanged some emails, did a late-night screen-sharing session, and generally looked things up-and-down. John concurred that what we were seeing shouldn’t have been happening, and he mentioned that he had another customer or two that seemed to be having a similar problem. Some tracing in those cases seemed to implicate a recent client-side theming change that had been made and rolled-out.

Analysis Of Styles In Internet Explorer Developer ToolsAn issue with client-side theming “felt” right to me. I had used Internet Explorer’s Developer Tools to do some backtracking into the source of the errant styles that were being applied to my site, and I noticed that the background image was being served from a temporary theme directory on the server. Until I started forcing my styles to override the ones that were being applied (an example of which is shown on the right), the theme styles were trumping my own styles.

John was out for a while, but he came back to me recently with the following explanation. And his explanation makes complete sense:

So the problem you were having was the result of a bad interaction with a third-party CSS minification technique called minisp.  By adding HTML comments around our CssLink controls in the master page, the <link> tags we normally render are part of a comment and therefore not part of the DOM.

When Client-Side Theming goes to replace the CSS on these pages, it wants to put the generated <style> blocks immediately before the corresponding <link> tags. Since it can’t find the <link> tags in the DOM, it defaults to adding the <style> blocks to the end of the document head. Since these come after the custom CSS, the rules in our themed CSS take priority over the rules in the custom CSS.

Resolution?

As of July 21st, 2015, there is no official resolution. Since this has been identified as a problem in how client-side theming handles CSS <style> block insertions, though, the ultimate fix needs to come from Microsoft. In the meantime, I’ll be sticking with my hacked CSS style sheet to get back most of the look-and-feel that I need. I could expend additional (development) effort to ensure that my styles are applied after the Office 365 theme styles without using !important, but there are plenty of other more important tasks vying for my attention right now.

Thumbs UpSo, if you found this post and it’s helping you to realize that you’re not going insane (at least not because of public site branding changes you didn’t make), I’ll feel that my job is done.

As I hear more and changes take place, I’ll try to update this post accordingly. Check back every now and then if you want the play-by-play on this issue.

Parting Thoughts: A Tip Of My Hat To Microsoft

In the past, I’ve been pretty vocal about the way that Microsoft has sort of “rolled” changes onto its Office 365 customer base and failed to communicate problems in a timely and complete fashion – actions (or lack of action) that ultimately caused pain and problems. As vocal as I’ve been in those situations, I want to go on-record as saying (just as loudly) that Microsoft has definitely listened to the critical feedback it has been receiving and has acted to make changes that we have indicated we need.

Even though this public site branding issue is indeed a bug, Microsoft listened and responded quickly – without protest, without claiming that “nothing is wrong,” and without some of the problem behaviors I used to see.

Where there were previously few communications about Office 365 outages, problems, changes, and updates, we now have a boatload of information (with some of it actually being pushed) to us to keep us in-the-know on our tenants, where they stand at any given point in time, and where they are going. I can get both at-a-glance health information and deep explanations for issues using the administrative portal’s Service Health dashboard. I get push notifications whenever something happens in my tenant using the Office 365 Admin application that runs on my Windows Phone. I know when new service features and capabilities are rolling out, if changes have been cancelled, etc., by looking at the Office 365 Roadmap. And these are just some of the channels and information streams that are available.

Is Microsoft “all the way there” yet? No, but they are dramatically further along than when Office 365 first rolled-out. Outages still occur – as they do with any service – but I feel like I know what’s going on now. That’s a huge improvement in my book.

References and Resources

  1. Microsoft Support: Information about changes to the SharePoint Online Public Website feature in Office 365
  2. Office 365 Public Site: Bitstream Foundry LLC
  3. LinkedIn: Jeremy Thake
  4. LinkedIn: Chris Johnson
  5. LinkedIn: Steve Walker
  6. Stack Overflow: What are the implications of using “!important” in CSS?
  7. MSDN: Using the F12 developer tools
  8. Microsoft: Office 365 Service Health Status
  9. Windows Phone App Store: Office 365 Admin
  10. Office.com: Office 365 Roadmap