How to debug Office Dev PnP

Further to my one of my previous posts How to debug PnP Provisioning Engine in which I explained how to use the Set-SPOTraceLog Cmdlet to get more information from your PnP PowerShell commands. In this article I’m going to describe how to debug the PowerShell source code itself.

When the Set-SPOTraceLog got me to the point where a certain list was causing problems, I now want to know how to fix the actual issues. This quite often requires more detail than just knowing which list, content type of column is causing a command to fail.

The PnP PowerShell is a layer calling the PnP Site Core libraries. The core libraries are doing the actual work. So most likely when you feel the need to debug the PowerShell commands you will find that you actually want to debug the core library.

You could use use https://github.com/OfficeDev/PnP-PowerShell however it would be better to use your own fork. Your fork is like a branch that is for your use only.

 

In my case I’ve set up my branch

clone

Once the PowerShell code is there you will see the repository there in Visual Studio.

clone4

 

 

 

Now it is time to repeat the same for two other repositories.

You should of course create your own forks from the OfficeDev/PnP-Sites-Core and OfficeDev/PnP-Provisioning-Schema projects.

Once all repositories have been cloned you should have something like this (you don’t need the github repository):

clone5

Ok, so now I’ve got the latest code from my forks. But the code in the OfficeDev repositories has been updated. How do I sync this?

Synchronizing repositories

In Visual Studio you might see a warning:

gitvs

If you get the warning then you haven’t installed Git yet. You can either click on the install link or download it from https://git-scm.com/download/win.

Once you have installed Git, you will be able to synchronize the repositories.

First I’m going to open the Provisioning Scheme project.

history

I can now see that my last updates were done at 08/01/2016 by Paolo Pialorsi

history2

Now I want to synchronize with the latest code where more recent updates were done.

I will need to go to the git bash (this is installed as part of git). First I changed to the folder containing my repository.

git

Then the git-remote -v shows my my repositories.

I want to syn with the Office dev fork not my fork! Why does Git not know about the parent fork?

Now I run:

git remote add OfficeDev https://github.com/OfficeDev/PnP-Provisioning-Schema

then again I run the git-remote -v

git2

OK, so now I’ve got git to know about OfficeDev, then I tried in Visual Studio to merge branches but Visual Stuido doesn’t seem to pick this up. It only knows about origin.

So back to Bash

git3

I ran

git fetch OfficeDev

Alternatively within Visual Studio you can also fetch the code from officeDev:

fetch

and now Visual Studio knows about this branch. I select the Merge from option

merge

 

 

 

 

 

 

 

Now I had to select which branch to merge from and I selected OfficeDev/master which is the master branch. So this code matches the latest release code. When needed you might want to select development branches here.  In the other two projects (PowerShell and Core) there is a clear branch called dev.

merge3

Then finally click on Merge and the master branch of my code should now be updated with the latest changes.

When I now check version history of my source code I can see the latest updates.

history3

So now I go back to my fork on github and I’m still getting a 36 commits behind.

github2

So I’ve got my latest code locally but I’ve not checked that into my fork in github.

In Visual Studio, you can see the outgoing commits in the Team Explorer -> Synchronization.

outgoingcommits

Click on Sync and your fork will be updated.

Now repeat this for the Site Core and PowerShell projects.

At last we’ve got the latest code both locally and in Github. Although technically we probably didn’t need to syn with Github to do the debugging it is a good idea to sync your personal fork every now and then.

Debug PnP PowerShell.

So now finally I get to the point of debugging PnP PowerShell

 

Open the project OfficeDevPnP.Core in Visual Studio and build the OfficeDevPnP.Core project.

Open the project OfficeDevPnP.PowerShell in Visual Studio.

Then Build the following projects:

  • SharePointPnP.PowerShell.CmdletHelpAttributes.csproj
  • SharePointPnP.PowerShell.CmdletHelpGenerator.csproj
  • SharePointPnP.PowerShell.Commands.csproj

 

This last  build should copy the powershell commands to your profile:

C:\Users\username\Documents\WindowsPowerShell\Modules\SharePointPnPPowerShellOnline

Now we are ready to get started:

Open PowerShell ISE, or the non ISE version of PowerShell and check that the PowerShell commands are available.

ise

Within your PowerShell window run the following commands:

Connect-SPOnline -Url https://mytenant.sharepoint.com

Get-SPOProvisioningTemplate -Out c:\temp\templates.pnp

 

No open the pnp sites core project in Visual Studio and set a break point in the GetRemoteTemplate in the SiteToTemplateConversion.cs

This can be found in:  C:\Github\PnP-Sites-Core\Core\OfficeDevPnP.Core\Framework\Provisioning\ObjectHandlers\SiteToTemplateConversion.cs

break

No attach the debugger to your PowerShell ISE:

attach

Select the powershell_ise process and click on Attachattach2

Note that in Visual Studio your break point now shows the red dot.

break2

rerun the Get-SPOProvisioningTemplate command in PowerShell and your breakpoints will be picked up and you can step through the code.

If you find that Visual Studio doesn’t pick up the thread then you might have to open up some ports on your firewall. For more information see: https://msdn.microsoft.com/en-us/library/mt592018.aspx

Alternatively you can also use the PowerShell Interactive Window available in Visual Studio. Just attach the process to the PowershellProcessHostConsole.exe instead of powershell_ise.exe

piw

 

Give an App / Add-In / Azure webjob permissions to SharePoint

This App registration needs some global permissions to have access to every site collection.

 

Steps to provide tenant admin permission for app only add-in:

  • Store the generated Client ID and Client Secret. You’ll need the client ID this in the next steps. And both should be send to Poritva for the configuration of the Site Provisioning tool
  • Move to appinv.aspx page under your tenant admin site
  • Perform a lookup for the app id (=client ID) registered in previous steps in appinv.aspx page
  • Provide needed permissions for your add-in registration

 

<AppPermissionRequests>
<AppPermissionRequest Scope=”http://sharepoint/content/sitecollection” Right=”FullControl” />
<AppPermissionRequest Scope=”http://sharepoint/social/tenant” Right=”FullControl” />
</AppPermissionRequests>

 

 

  • Click on “Create”
  • Give trust for the updated add-in registration

Notice that this operation has to be completed under the tenant administration site and account used for these operations will need to have tenant administrative permissions.

From <https://msdn.microsoft.com/en-us/pnp_articles/how-to-provide-add-in-app-only-tenant-administrative-permissions-in-sharepoint-online>

Provider hosted app high trust

You’ll create a test .pfx certificate file first, and then a corresponding test .cer file.

PFX
The .pfx certificate contains the private key that is used by the remote web application to sign its communications to SharePoint.

CER
The .cer contains the public key that SharePoint uses to decrypt the messages, verify that they come from the remote web application, and verify that the remote web application has an access token from a token issuer that SharePoint trusts.

You need to have a cer and a pfx file before you start with the following scripts.

Create cer object from an existing certificate (.cer) file:

$publicCertPath = “C:\Certs\HighTrustSampleCert.cer”
$certificate = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($publicCertPath)
Set certificate as root athority:
New-SPTrustedRootAuthority -Name “HighTrustSampleCert” -Certificate $certificate

Get realm:

$realm = Get-SPAuthenticationRealm

Construct an issuer ID in the format that SharePoint requires(specific_issuer_GUID@realm_GUID):
$specificIssuerId = “11111111-1111-1111-1111-111111111111”
$fullIssuerIdentifier = $specificIssuerId + ‘@’ + $realm

Register the certificate as a trusted token issuer:

New-SPTrustedSecurityTokenIssuer -Name “High Trust Sample Cert” -Certificate $certificate -RegisteredIssuerName $fullIssuerIdentifier –IsTrustBroker
iisreset

 

Source: https://msdn.microsoft.com/en-us/library/office/fp179901.aspx

React and office-ui-fabric-react example

npm install -g create-react-app
create-react-app documentcardbasic-demo
cd documentcardbasic-demo
npm start
npm install office-ui-fabric-react --save
 

 

Open the documentcardbasic-demo project folder in Visual Studio Code.

Open the file src\App.js and replace the existing code inside render method to only return the DocumentCard component:

<div>
  <DocumentCard onClickHref='http://bing.com'>
      <DocumentCardPreview
        previewImages={ [
          {
            previewImageSrc: require('./documentpreview.png'),
            iconSrc: require('./iconppt.png'),
            width: 318,
            height: 196,
            accentColor: '#ce4b1f'
          }
        ] }
      />
      <DocumentCardTitle title='Revenue stream proposal fiscal year 2016 version02.pptx'/>
      <DocumentCardActivity
        activity='Created Feb 23, 2016'
        people={
          [
            { name: 'Kat Larrson', profileImageSrc: require('./avatarkat.png') }
          ]
        }
        />
    </DocumentCard>
</div>

 

import {
  DocumentCard,
  DocumentCardPreview,
  DocumentCardTitle,
  DocumentCardActivity
} from 'office-ui-fabric-react/lib/DocumentCard';

 

 

Sources:

https://github.com/OfficeDev/office-ui-fabric-react/blob/master/ghdocs/README.md

Provider hosted app and ADFS modifications (SharePointContext.cs and TokenHelper.cs)

When you created an provider hosted app with ADFS authentication you need to modify the OOTB files ‘SharePointContext.cs’ and ‘TokenHelper.cs’. These 2 files are needed to get the authentication token for the app. But these files are not compatible with ADFS (SharePointHighTrustSamlContext). They are only compatible for Azure Access Control Services (ACS/Office 365) and Windows authentication (SharePointHighTrustContext). When you use this example of the files you are missing the Session logic. When you implement the Session logic you can get after 10 minutes a 401 error unauthorized error. You can fix this as follow:

The outer token lifetime (10 minutes) needs to be higher than the HighTrustAccessTokenLifetime (12 hours).

Sources:

https://blog.lekman.com/2015/02/sharepoint-high-trust-apps-and-adfssaml.html

http://www.wictorwilen.se/sharepoint-2013-with-saml-claims-and-provider-hosted-apps

https://samlman.wordpress.com/2015/03/01/using-sharepoint-apps-with-saml-and-fba-sites-in-sharepoint-2013/

https://lekman.codeplex.com/releases/view/611248

https://blog.baslijten.com/getting-sharepoint-2013-apps-and-webapi-to-work/

http://blah.winsmarts.com/2014-8-Updated_TokenHelper_classes_in_VS2013.aspx

Office dev pnp features

Connect/Disconnect to sitecollection (ADFS)

TemplateProvisioning (Powershell)

TemplateProvisioning (Powershell) parameters

TemplateProvisioning (Js) (ProviderConnector)

TemplateProvisioning (Js) parameters

TemplateProvisioning explicit handlers

Add new publising page (disable VS publish precompile)

Add webparts to publising page

New welcomepage

Create new subsite

Propertybag

Open new context of another website

Tokens (listid, etc)

Custom pagelayout

Contenttype

Lists

Fields

Views

App permissions/manifest (Taxonomy, Sitecollection)

Logging

Set-PnPTraceLog -On -Level Debug
<command>
Set-PnPTraceLog -Off -Level Debug

Cannot drag and drop document in SharePoint list view webpart

If you add a list view webpart to a page and it is not possible to drag and drop documents, probably there are 2 js files not loaded.

Load these 2 js files in a CEWP or JSLINK:

 

SP.SOD.executeFunc(‘sp.js’,’SP.Utilities.Utility’, function() {

console.log(‘sp.js’);

});
SP.SOD.executeFunc(‘sp.core.js’,’SP.Utilities.CommandBlock’, function() {

console.log(‘sp.core.js’);

});

 

This issue occurs only on a list view webpart on a page. When you go directly to the document library it is working fine without this change.

Create subsite by Office Dev PnP CSOM

// Create new subsite
Web newWeb = web.CreateWeb(new OfficeDevPnP.Core.Entities.SiteEntity()
{
Title = “test”,
Url = “test”,
Description = “test”,
Template = “BLANKINTERNET#0”,
Lcid = 1043
}, true, true);

Office Dev PnP TemplateProvisioning

protected virtual void ApplyTemplate(ClientContext context)
{
// Read the XML file
XMLTemplateProvider provider = new XMLFileSystemTemplateProvider(String.Format(@”{0}\Templates\”, AppDomain.CurrentDomain.BaseDirectory), “”);

if (provider != null)
{
// Get the template
var template = provider.GetTemplate(“myCustomTemplate.xml”);
if (template != null)
{
template.Connector = provider.Connector;

ClientContext clientContext = context.Clone(Subsite.Url);

using (clientContext)
{
clientContext.Web.ApplyProvisioningTemplate(template);
}
}
}
}

Enable structural navigation in CSOM

protected void EnableStructuralNavigation(Web web, ClientContext context)
{
// enable structural navigation for the quick launch navigation
AreaNavigationEntity nav = new AreaNavigationEntity();
nav.CurrentNavigation.ShowSubsites = false;
nav.CurrentNavigation.ShowPages = false;
web.UpdateNavigationSettings(nav);
}