Wednesday, July 10, 2019

SPFx Extension - Tenant Scoped and Activated by Default on All Sites

SPFx Extensions are used to extend the SharePoint experience. For example, custom header or footer, custom view for a list field etc.

SPFX Extensions can be deployed and activate in three ways:

  1. Site Scoped Local Activation - SPFx extensions are installed explicitly on a site and are then available like any other app on a site, and can be activated from site contents page. 
  2. Tenant Scoped on demand activation - Tenant wide deployed but not activated - Extension is available to all sites in the tenant but activation can be done via script alone. 
  3. Tenant Scoped and activated by default - Extension is deployed tenant wide and also activated automatically across all the sites.We will explore this way in more detail in this blog.

Tenant Scoped and activated by default option for Extensions is very useful when you want the extension to be available on all the sites in the tenant. Lets say for example there is a header or footer that needs to be displayed in all sites.

I created my extension using the following options that yeoman generator walks me through:

Let's create a new SharePoint solution.
? What is your solution name? on-demand-extension
? Which baseline packages do you want to target for your component(s)? SharePoint Online only (latest)
? Where do you want to place the files? Create a subfolder with solution name
Found npm version 6.9.0
? Do you want to allow the tenant admin the choice of being able to deploy the solution to all sites immediately without running any feature deployment or adding apps in sites? Yes
? Will the components in the solution require permissions to access web APIs that are unique and not shared with other components in the tenant? No
? Which type of client-side component to create? Extension
? Which type of client-side extension to create? Application Customizer
Add new Application Customizer to solution on-demand-extension.
? What is your Application Customizer name? custom-header
? What is your Application Customizer description? custom-header

When you are creating the extension make sure you have selected Yes for the option i have highlighted above. What this does is that, a feature is defined in the package-solution.json file and an Assets folder is created with Client Side Instance xml and elements xml. When this package is deployed to SharePoint, every time a site is created or for existing sites this feature and there by the Extension is activated. 

Now a folder with the base code for SPFx Extension is created. Open the folder in your code editor, and open the package-solution.json, you will see the following:
{ "$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json", "solution": { "name": "on-demand-extension-client-side-solution", "id": "dafe6ae3-7d52-4e85-b784-728be2a7660c", "version": "1.0.0.0", "includeClientSideAssets": true, "skipFeatureDeployment": true, "isDomainIsolated": false, "features": [ { "title": "Application Extension - Deployment of custom action.", "description": "Deploys a custom action with ClientSideComponentId association", "id": "8e500ccf-e147-480d-92b5-9cef681c2eb8", "version": "1.0.0.0", "assets": { "elementManifests": [ "elements.xml", "clientsideinstance.xml" ] } } ] }, "paths": { "zippedPackage": "solution/on-demand-extension.sppkg" } }

skipFeatureDeployment is the property that determines if this SPFx solution will be deployed tenant wide or not. If it is set to true means it will be deployed tenant wide.

Lets build the package using
gulp bundle
gulp package-solution
gulp serve --nobrowser

Drag and drop the solution package file from the \sharepoint\solution folder to app catalog site, you will be prompted to trust the solution, select the option to make the solution available to all the sites in the organization and click Deploy.

Now in the app catalog site if you navigate to the Tenant Wide Extensions list, you can find our extension there.


Also notice the component property,, the value is "Test message", and that is the property that is being used in the default extensions pop up control. 




Lets say you want to display an updated message, then what you can do is just go to the Tenant Wide Extensions list and update the Component Property value, i did just that and updated the value to "Mahesh is Testing New Message" and now see the pop up's update message:



As you can see this Tenant Wide Deployment is an excellent option for components that need to be displayed across all the sites in the tenant. It is easy to use and Component Property mechanism allows for easy maintenance.

Thanks for reading, do let me know if you have implemented something similar and share your use case and solution.


Tuesday, July 2, 2019

SPFx Extension - On Demand Activation


SPFx Extensions are used to extend the SharePoint experience. For example, custom header or footer, custom view for a list field etc.

SPFX Extensions can be deployed and activate in three ways:

  1. Site Scoped Local Activation - SPFx extensions are installed explicitly on a site and are then available like any other app on a site, and can be activated from site contents page. 
  2. Tenant Scoped on demand activation - Tenant wide deployed but not activated - Extension is available to all sites in the tenant but activation can be done via script alone. We will explore this way in more detail in this blog.
  3. Tenant Scoped and activated by default - Extension is deployed tenant wide and also activated automatically across all the sites.

Tenant Scoped but on demand activation

I created my extension using the following options that yeoman generator walks me through:

Let's create a new SharePoint solution.
? What is your solution name? on-demand-extension
? Which baseline packages do you want to target for your component(s)? SharePoint Online only (latest)
? Where do you want to place the files? Create a subfolder with solution name
Found npm version 6.9.0
? Do you want to allow the tenant admin the choice of being able to deploy the solution to all sites immediately without running any feature deployment or adding apps in sites? Yes
? Will the components in the solution require permissions to access web APIs that are unique and not shared with other components in the tenant? No
? Which type of client-side component to create? Extension
? Which type of client-side extension to create? Application Customizer
Add new Application Customizer to solution on-demand-extension.
? What is your Application Customizer name? custom-header
? What is your Application Customizer description? custom-header

Now a folder with the base code for SPFx Extension is created. Open the folder in your code editor, and open the package-solution.json, you will see the following:
{ "$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json", "solution": { "name": "on-demand-extension-client-side-solution", "id": "dafe6ae3-7d52-4e85-b784-728be2a7660c", "version": "1.0.0.0", "includeClientSideAssets": true, "skipFeatureDeployment": true, "isDomainIsolated": false, "features": [ { "title": "Application Extension - Deployment of custom action.", "description": "Deploys a custom action with ClientSideComponentId association", "id": "8e500ccf-e147-480d-92b5-9cef681c2eb8", "version": "1.0.0.0", "assets": { "elementManifests": [ "elements.xml", "clientsideinstance.xml" ] } } ] }, "paths": { "zippedPackage": "solution/on-demand-extension.sppkg" } }

skipFeatureDeployment is the property that determines if this SPFx solution will be deployed tenant wide or not. If it is set to true means it will be deployed tenant wide.

After the isDomainIsolated property you can see a "features" property, this feature is used by SharePoint to automatically activate the SPFx extension when we select the option to deploy tenant wide. If you dont want that to happen  i.e. you want the extension to be deployed tenant wide but dont want it to be activated automatically then remove the feature property. Since we want to do On Demand Activation, we will remove the features property and also the Assets folder which is located under the sharepoint folder.

Lets build the package using
gulp bundle
gulp package-solution
gulp serve --nobrowser

Drag and drop the solution package file from the \sharepoint\solution folder to app catalog site, you will be prompted to trust the solution, select the option to make the solution available to all the sites in the organization and click Deploy.

You will notice you are not seeing the default prompt that we see when an extension is available on a site. That is because we have still not activated the solution to a particular site. Lets activate the solution via power shell,  use the following commands:

  Connect-PnPOnline
Add-PnPCustomAction -Name "Extension ABC" -Title "Ext Title"
 -Location "clientSideExtension.ApplicationCustomizer"
 -ClientSideComponentId

Client Side Component Id can be obtained from the manifest file which resides under   
\src\extensions\customHeader\CustomHeaderApplicationCustomizer.manifest.json

Following is the content of that manifest file
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx/client-side-extension-manifest.schema.json", "id": "186751b2-ff1d-42d9-bada-2ff7c7b9ca0f", "alias": "CustomHeaderApplicationCustomizer", "componentType": "Extension", "extensionType": "ApplicationCustomizer", // The "*" signifies that the version should be taken from the package.json "version": "*", "manifestVersion": 2, // If true, the component can only be installed on sites where Custom Script is allowed. // Components that allow authors to embed arbitrary script code should set this to true. // https://support.office.com/en-us/article/Turn-scripting-capabilities-on-or-off-1f2c515f-5d7e-448a-9fd7-835da935584f "requiresCustomScript": false }

The Id property in the above json file is the ClientSideComponentId

So our power-shell command will look like this:
  Connect-PnPOnline
Add-PnPCustomAction -Name "Extension ABC" -Title "Ext Title"
 -Location "clientSideExtension.ApplicationCustomizer"
 -ClientSideComponentId 186751b2-ff1d-42d9-bada-2ff7c7b9ca0f 

Now our extension solution is active on that particular site.

Thanks for reading, please do share your experiences around SharePoint extensions.

Monday, June 17, 2019

Adding new property bag item in SharePoint Online

In SharePoint online when you try to add a property bag via pnp powershell, you will notice that you get the following error

Set-PnPPropertyBagValue : Site has NoScript enabled, and setting property bag values is not supported
At line:1 char:1
+ Set-PnPPropertyBagValue -Key "KEY_XYZ" -V ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (SharePointPnP.P...ropertyBagValue:SetPropertyBagValue) [Set-PnPPropertyBagValue], Exception
    + FullyQualifiedErrorId : NoScriptEnabled,SharePointPnP.PowerShell.Commands.SetPropertyBagValue

As the error says, we need to disable NoScript property by running the following command
Connect-PnPOnline Site Collection URL
Set-PnPTenantSite -Url Site Collection URL -NoScriptSite:$false     
After running the above command you should be able to add your new property bag item using the following command:
         Set-PnPPropertyBagValue -Key "" -Value "" 

PLEASE NOTE : Connect-PnPOnline command is very important, without this even you were already logged in the NoScript property cant be set to false. It sounds strange but that is what i experienced.

Thursday, May 2, 2019

Consuming Microsoft Graph in SharePoint Framework(SPFx)

In this blog I am sharing my experience of working with SPFx and Microsoft Graph API. I was pleasantly surprised how easy it was to get going with Microsoft Graph and I will show you with a demo how to consume Microsoft Graph from SharePoint Framework (SPFx) web part.


SPFx has now become the preferred way to create custom experiences on SharePoint online as well as On-Prem. I am not going to cover details on how to create and deploy SPFx web parts. If you are looking to get started on SPFx first go to https://docs.microsoft.com/en-us/sharepoint/dev/spfx/set-up-your-developer-tenant and then look up the SharePoint Developer Community channel on YouTube https://www.youtube.com/channel/UC_mKdhw-V6CeCM7gTo_Iy7w.

Microsoft Graph as I understand is a common API layer on top of all Microsoft Office 365 services like One Drive, SharePoint, Excel, Planner, Teams, Outlook, Azure Active Directory etc. It is just awesome because as an Office developer you can interact with all the above mentioned services and more with a common schema and a single access token. To know more graph API get started here https://developer.microsoft.com/en-us/graph/blogs/30daysmsgraph-day-1-why-you-should-learn-the-microsoft-graph/

Now that we have seen what is SPFx and Microsoft Graph, let me briefly explain the problem statement we will use to explore SharePoint framework and Microsoft Graph. Many organization like to manage access to SharePoint sites, Network folders, One drive documents etc. using Active Directory groups because these groups can be centrally managed and reused across applications. Usually it is not easy for business or power users to know exactly who are the members of these Active Directory groups. Our solution is to create a SPfx web part that can be used to display members of an Azure Active Directory Group. Power users can just add this web part to their SharePoint online site and view the members of the Azure Active Directory Groups.

If this if the first time you are building a SPFx web part then please first install the required tools, refer this: https://docs.microsoft.com/en-us/sharepoint/dev/spfx/set-up-your-development-environment

Lets build our solution, I am going to start with creating an SPFx web part by using the following command:
yo @microsoft/sharepoint
and I am going to select the option for  React JS


Lets open this folder using VS Code and you will see the typical SPFx folder structure created for you.


First Step: Dependencies
Since we know we are going to use query SharePoint site and Graph ensure dependencies for pnp graph and pnp sharepoint are included in the package.json file. You can get the dependencies from my code sample. Link to my code is available at the end of this blog.

Second Step: Graph Permissions
In our example we know we would like to read Azure AD groups and Users hence we will use Directory.Read.All permission scope. For identifying what permission scope is required you should always refer this article: 


In our project, open the config/package-solution.json and include the following permissions under the solution object:
"webApiPermissionRequests": [
     {
       "resource": "Microsoft Graph",
       "scope": "Directory.Read.All"
     }
   ]


Third Step: Get SP Context in the web part class file
Getting SPContext is a must without this you will not be able to access Graph.

We can get SPContext created this way
export default class AzureAdGroupViewerWebPart extends BaseClientSideWebPart<IAzureAdGroupViewerWebPartProps> {

  public onInit(): Promise<void> {
    pnpSetup({
      spfxContext: this.context
    });
    return Promise.resolve();
  }
  public render(): void {


Fourth Step: Component class
Now under the components folder you will find your component file as .tsx file
Here we need to make sure we import 
import { graph } from '@pnp/graph';
import { sp } from "@pnp/sp";


In my example I am using the Details List component from Office UI Fabric to display local SharePoint user groups and also members of a Azure Active Directory group. I strongly recommend using Office UI Fabric components because the look and feel matches with SharePoint theme and also it has been vetted by Office Developers community.

import {
  DetailsList,
  DetailsListLayoutMode,
  IColumn,
  IDetailsList
} from 'office-ui-fabric-react/lib/DetailsList';



To query SharePoint user group I have used pnp sp object. I am doing an ajax call to get a specific group using its name and the getting all users who are part of that group and saving that in the local state.

public componentDidMount(): void {
    sp.web.siteGroups.getByName(").users.get().then(users=>{
      this.setState({
        groups: users  
      });       
    }); 
  }


and the resulting grid looks like this:

You can see that this example SharePoint user group has many Azure AD groups as members. Now when we click on the button, we will query the Graph API and get users who are members of that Azure AD group, to do that we will call a function on button click:

1 onClick = (item,event) => {      
2    let gid = item.LoginName;
3    gid = gid.substr(gid.lastIndexOf("|") + 1, gid.length - gid.lastIndexOf("|"));
4    graph.groups.getById(gid).members.get().then(members => {   
5      this.setState({
6        grpMembers:members
7      }) 
8    });
9    event.preventDefault();   
10  }


In lines 2 and 3 in the above code snippet I am extracting the Azure Group's GUID and then using that to query graph API, once I get the members I save them to local state and I have another grid to display these users:



Code is available here : https://github.com/mahesh2005/SPFxWithGraph


Tuesday, October 11, 2011

MOSS 2007, WSS 3.0 Service Pack 3 (SP3)

announced the release of service pack 3 for MOSS and WSS 3.0.

They will make the SP3 available for download in Q4 of 2011. That is a huge relief. I was going to start applying the cumulative patches. Now I will just wait for the SP3 to made available.

You can refer to their blog for details:

Wednesday, October 13, 2010

This implementation is not part of the Windows Platform FIPS validated cryptographic algorithms

I was installing SharePoint 2010 Foundation on a Win 2008 server SP2 (NOT R2) and got the following error when I ran the config wizard:

Failed to create the configuration database.
An exception of type System.InvalidOperationException was thrown. Additional exception information: This implementation is not part of the Windows Platform FIPS validated cryptographic algorithms.
System.InvalidOperationException: This implementation is not part of the Windows Platform FIPS validated cryptographic algorithms.
at System.Security.Cryptography.SHA256Managed..ctor()
at Microsoft.SharePoint.UserCode.SPSolutionValidatorCollection.ComputeHash()
at Microsoft.SharePoint.Administration.SPUserCodeService.UpdateValidatorsHash()
at Microsoft.SharePoint.Administration.SPPersistedChildCollection`1.Add(T newObj, Boolean ensure)
at Microsoft.SharePoint.Administration.SPPersistedChildCollection`1.Add(T newObj)
at Microsoft.SharePoint.UserCode.SPSolutionValidatorCollection.Insert(SPSolutionValidator validator, Int32 index)
at Microsoft.SharePoint.UserCode.SPSolutionValidatorCollection.Add(SPSolutionValidator validator)
at Microsoft.SharePoint.Administration.SPUserCodeService.Update()
at Microsoft.SharePoint.Administration.SPPersistedChildCollection`1.Add(T newObj, Boolean ensure)
at Microsoft.SharePoint.Administration.SPPersistedChildCollection`1.Ensure(T newObj)
at Microsoft.SharePoint.Administration.SPUserCodeService.EnsureService(SPFarm farm, Boolean upgrading)
at Microsoft.SharePoint.Administration.SPFarm.CreateBasicServices(SqlConnectionStringBuilder administrationContentDatabase, IdentityType identityType, String farmUser, SecureString farmPassword)
at Microsoft.SharePoint.Administration.SPFarm.Create(SqlConnectionStringBuilder configurationDatabase, SqlConnectionStringBuilder administrationContentDatabase, IdentityType identityType, String farmUser, SecureString farmPassword, SecureString masterPassphrase)
at Microsoft.SharePoint.Administration.SPFarm.Create(SqlConnectionStringBuilder configurationDatabase, SqlConnectionStringBuilder administrationContentDatabase, String farmUser, SecureString farmPassword, SecureString masterPassphrase)
at Microsoft.SharePoint.PostSetupConfiguration.ConfigurationDatabaseTask.CreateOrConnectConfigDb()
at Microsoft.SharePoint.PostSetupConfiguration.ConfigurationDatabaseTask.Run()
at Microsoft.SharePoint.PostSetupConfiguration.TaskThread.ExecuteTask()

I checked out few blogs and KB articles, but was not able to resolve the issue.

In my case

1.) The FIPS settings was already disabled in local security policy settings.

2.) The accounts had required access to the hive, inetpub and all the other folders.

3.) We didn't have access to change the machine.config files.

After running the process monitor tool as the config wizard was running, we found that there were other Reg Keys that were showing up in the procmon logs.

On further analysis we found that there are FIPS related keys in three locations

1.)HKLM\SYSTEM\ControlSet001\Control\LSA\FipsAlgorithm

2.)HKLM\SYSTEM\ControlSet002\Control\LSA\FipsAlgorithm

3.)HKLM\SYSTEM\CurrentControlSet\Control\LSA\FipsAlgorithm

Only the 3rd key had the value as 0 i.e. disabled, but the other two had values as 1 i.e. enabled. I changed the values to 0 for the other two and then ran the PSCONFIG again. This time the installation was successfully completed. ISSUE RESOLVED.

Tuesday, September 14, 2010

SharePoint 2010 Installation Error - FIPS cryptographic algorithm

*****************************************************************************************
UPDATE October 13th, 2010- ISSUE RESOLVED- I had to make changes to few more reg keys!
Details are available here

*****************************************************************************************************************************



I was installing SharePoint 2010 Foundation in standalone mode on a Win 2008 server SP2 (NOT R2) and got the following error when I ran the config wizard.

Failed to create the configuration database.

An exception of type System.InvalidOperationException was thrown. Additional exception information: This implementation is not part of the Windows Platform FIPS validated cryptographic algorithms.

System.InvalidOperationException: This implementation is not part of the Windows Platform FIPS validated cryptographic algorithms.

I checked out few blogs, but was not able to resolve the issue.

These were the blogs/links I referred to:

Amol's blog:

http://sharepointknowledgebase.blogspot.com/2009/04/this-implementation-is-not-part-of.html,

this pointed me to this KB article http://support.microsoft.com/kb/911722. The KB article talks about adding a section to your web.config, but in my case, the central admin site is also still not created so there is no web.config.

I also referred to another link which suggested to disable the FIPS compliance related Local security policy, but in my case it was already disabled.

I will troubleshoot this further and keep updating this post.


Update Oct 11th,2010.

We re-imaged our virtual server, basically got a new server and tried again, same problem again.

I have posted a question in technet

http://social.technet.microsoft.com/Forums/en-US/sharepoint2010setup/thread/81e1b564-c722-4aea-b7a1-788ff35e055d

*****************************************************************************************
UPDATE October 13th, 2010- ISSUE RESOLVED- I had to make changes to few more reg keys!
Details are available here

*****************************************************************************************************************************