Thursday, November 5, 2020

Call WebExtensions.WebExistsFullUrl method from OfficeDevPnP library for different site collection

Few years ago I wrote about one problem in OfficeDevPnP method WebExtensions.WebExistsFullUrl: shortly when it was called with url which belongs to non-existent site collection from different managed path it returned true. Full description of the problem is available here: How to check does site collection exist by absolute url using CSOM in Sharepoint. Also I posted issue to PnP-Sites-Core in github: WebExtensions.WebExistsFullUrl returns true for non-existent sites from different managed path in Sharepoint 2013 on-premise. I checked this issue with the latest PnP version (which is 3.26.2010 at the moment of writing of this article) and found that this problem is fixed now by MS. I.e. code of WebExtensions.WebExistsFullUrl method is still the same:

public static bool WebExistsFullUrl(ClientRuntimeContext context, string webFullUrl)
{
    bool exists = false;
    try
    {
        using (ClientContext testContext = context.Clone(webFullUrl))
        {
            testContext.Load(testContext.Web, w => w.Title);
            testContext.ExecuteQueryRetry();
            exists = true;
        }
    }
    catch (Exception ex)
    {
        if (IsUnableToAccessSiteException(ex) || IsCannotGetSiteException(ex))
        {
            // Site exists, but you don't have access .. not sure if this is really valid
            // (I guess if checking if URL is already taken, e.g. want to create a new site
            // then this makes sense).
            exists = true;
        }
    }
    return exists;
}

but now when we try to clone ClientContext in this line:

ClientContext testContext = context.Clone(webFullUrl))

and webFullUrl corresponds to non-existent site collection from another managed path (e.g. if context was created from the root site collection http://example.com and we pass webFullUrl = http://example.com/sites/som-non-existent-url) it throws System.Exception (System.Net.WebException) now:

The remote server returned an error: (404) Not Found

while in earlier CSOM version it created ClientContext for the root site in this case. And as result WebExtensions.WebExistsFullUrl returns false as expected. So fortunately issue was fixed and we can call this method for checking existence of different site collections.

Friday, October 16, 2020

Problem in OTB groupstatus.aspx Sharepoint Online page and mobile browsers

In SPO there is one very useful OTB application layouts page groupstatus.aspx. Using this page we may redirect user to Notebook, Planner plan or Sharpeoint site associated with O365 group, e.g.

{siteUrl}/_layouts/15/groupstatus.aspx?target={target}

where {siteUrl} is url of the site associated with O365 group. And target may be "site", "notebook", "planner", etc. Full list may be found here: Generic URLs for all Office 365 Group connected workloads.
If we don't know url of the site associated with O365 group we may still use this page in context of the root tenant site and specify id of O365 group in additional query string parameter:

https://{tenant}.sharepoint.com/_layouts/15/groupstatus.aspx?target={target}&id={groupId}

 
In this case it will still redirect you to the requested target. And this is exactly how we use this page in TW - we open it in context of the root tenant site and provide target=site and id of the group in query string.
 
However at the same time Sharepoint has own redirection system for mobile devices: when you visit some Sharepoint site from mobile device it will redirect to special application layouts page optimized for mobile view \_layouts\Mobile\mblwpa.aspx (see Overview of Mobile Pages and the Redirection System). According to documentation this redirection for mobile devices is performed via http module (SPRequestModule). It means that in ASP.Net pipeline it will happen before request will come to groupstatus.aspx page. So when we redirect user to the root tenant site on mobile browser:

  https://{tenant}.sharepoint.com/_layouts/15/groupstatus.aspx?target={target}&id={groupId}

Sharepoint will just redirect user to mblwpa.aspx page in this root site

https://{tenant}.sharepoint.com/_layouts/15/mobile/mblwpa.aspx

and instead of seeing site associated with specified O365 group - user will see root tenant site. Will try to report this problem to MS using available communication channels. For now posted this problem on StackOverflow here.

Tuesday, October 13, 2020

How to free space on OS Windows drive by moving SoftwareDistribution folder to another disk via junction folder

If you are lucky owner of PC with 100Gb OS SSD disk or when OS disk on your server is not big enough then you may face with situation when there is no enough space anymore for installing updates, new tools, etc. In this post I will share solution which will help to free some space on OS drive.

Probably the first thing which you will try when will face with this problem is WinDirStat tool which allows to gather report of disk space usage per folders. The same report will most probably show that C:\Windows\SoftwareDistribution folder takes a lot of space. This folder is used by Windows Update for storing temporary files needed for installing new updates. As it is important Windows component you can’t just delete or move it and free space on OS drive. However what we can do is to create folder on another drive, move files there and create junction between C:\Windows\SoftwareDistribution and this folder. Here are needed steps:

1. Stop Windows Update service (Control Panel > Administration > Services)
2. Create new folder on another drive with enough space, e.g. D:\WinSoftwareDistribution. This is where files will be stored after all
3. Rename C:\Windows\SoftwareDistribution e.g .to C:\Windows\SoftwareDistribution.old
4. Create junction between folders:

mklink /j C:\Windows\SoftwareDistribution D:\WinSoftwareDistribution

5. Move files from C:\Windows\SoftwareDistribution.old to D:\WinSoftwareDistribution. After that you may go to C:\Windows\SoftwareDistribution junction and ensure that files appear there again
6. Run Windows Update service

After that your SoftwareDistribution will be located on another drive and you will have more space on your OS drive. Hope that this trick will help someone.

Update 2022-08-19: there may be side effects which this solution. Workaround for one of them is described here: Fix for "The system cannot open the device or file specified" error in Windows Installer.

Thursday, October 1, 2020

How to enable Android App links in web-facing Sharepoint on-prem site

In previous article I showed how to enable universal links for iOS on Sharepoint on-prem site – see How to enable iOS universal links in web-facing Sharepoint on-prem site. In this post I will describe how to enable Android App links for web-facing Sharepoint on-prem site.

For Android App links the process is different. First of all we need to prepare special assetlinks.json file with predefined content:

[{
  "relation": ["delegate_permission/common.handle_all_urls"],
  "target": {
    "namespace": "...",
    "package_name": "...",
    "sha256_cert_fingerprints": ["..."]
  }
}]

I won’t describe here details about content of assetlinks.json file – you may find this information on Android documentation sites. Next step is to place assetlinks.json file into .well-known subfolder of the root folder of our site. On Sharepoint we can create this folder in site’s IIS folder C:\inetpub\wwwroot\wss\VirtualDirectories\{SiteName}.

After that we need to go to IIS manager > choose Sharepoint site > right click .well-known sub folder and click “Convert to Application”:

When .well-known subfolder is ready and configured in IIS manager we may copy assetlinks.json file there.

Now we need to make assetlinks.json file available for anonymous access (otherwise it won’t be available for Android infrastructure) and ensure that server adds Content-Type: "application/json" http header in response. In order to do that add the following web.config file to .well-known subfolder:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.web>
      <authorization>
        <allow users="*" />
      </authorization>
    </system.web>
    <system.webServer>
      <staticContent>
        <clear />
        <mimeMap fileExtension=".json" mimeType="application/json" />
      </staticContent>
        <handlers>
            <remove name="JSONHandlerFactory" />
        </handlers>
    </system.webServer>
</configuration>

After that Android App links will be available on your web-facing Sharepoint on-prem site.

Tuesday, September 29, 2020

How to fix error could not load type 'Microsoft.SharePoint.Administration.DesignPackageType' error when import Microsoft.Online.SharePoint.PowerShell module

When you try to import Microsoft.Online.SharePoint.PowerShell module:

Import-Module -Name Microsoft.Online.SharePoint.PowerShell

you may get the following error:

Import-Module : Could not load type 'Microsoft.SharePoint.Administration.DesignPackageType' from assembly 'Microsoft.SharePoint.Client, Version=16.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c'.

also error can be the following:

Import-Module : Could not load type 'Microsoft.SharePoint.Client.Publishing.PortalLaunch' from assembly 'Microsoft.SharePoint.Client.Publishing, Version=16.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c'.

The main problem is that PowerShell tries to use on-prem CSOM assemblies (which have version 16.0.0.0) instead of online (with version 16.1.x.x). There are some articles and posts which recommend to manually remove Microsoft.SharePoint.Client folders from GAC. It should not be done! Especially if you have on-prem Sharepoint installation on the same server – this installation may be broken because of that.

The reason of this error is conflicts between different versions of Sharepoint Online SDKs (SharePoint Client Components, SharePoint Online Management Shell). So correct way to solve this problem is the following:

1. Go to Control Panel > Programs and features and uninstall all instances of SharePoint Online Management Shell and SharePoint Client Components

2. Open PowerShell console and uninstall existing versions of Microsoft.Online.SharePoint.PowerShell module:

Uninstall-Module -Name Microsoft.Online.SharePoint.PowerShell -AllVersions

3. After that close PowerShell, open new session and install latest version of Microsoft.Online.SharePoint.PowerShell module:

Import-Module -Name Microsoft.Online.SharePoint.PowerShell

This time it should go without error.

Tuesday, September 22, 2020

How to enable iOS universal links in web-facing Sharepoint on-prem site

Universal links allow to open mobile app when user clicks it inside the site. I.e. if user has appropriate mobile app it will be opened instead of regular browser page which will give better user experience on mobile devices. In this post I will show how to configure universal links for iOS in web-facing Sharepoint on-premise site. At the same time I won’t write about all steps like building mobile app itself, getting its app id, etc – please refer to appropriate resources related with mobile apps development for that.

In order to enable universal links for iOS on your web-facing Sharepoint on-prem site the following steps have to be done:

  1. create AASA (Apple app site association) file. File name should be exactly “apple-app-site-association” without extension. It should contain data in json format with predefined structure (see below)
  2. put it to the root folder of web-facing site
  3. ensure that AASA file is available for anonymous users (robots) with Content-Type = “application/json”

This is how AASA file may look like:

{
  "applinks": {
    "apps": [],
    "details": [ { "appID": "{appId}", "paths": ["*"] } ]
  }
}

(use you app id instead of {appId} placeholder). When file is ready we need to copy it to the IIS folder of our Sharepoint site. Next step is to provide anonymous access and set correct content type. It can be done by modifying web.config of Sharepoint site – we need to add new location element here under configuration tag (usually in web.config of Sharepoint site there are many others location elements – so just put them together):

 <location path="apple-app-site-association">
    <system.web>
      <authorization>
        <allow users="*" />
      </authorization>
    </system.web>
    <system.webServer>
      <staticContent>
        <mimeMap fileExtension="." mimeType="application/json" />
      </staticContent>
    </system.webServer>
  </location>

It will make AASA file available for anonymous users and will set content type to “application/json”.

The last step is to verify that everything is configured properly. It can be done on AASA validator. Result should look like this:

At the end you should have universal links enabled for your web-facing Sharepoint on-prem site.

Update 2020-10-01: guide for enabling Android App links on Sharepoint site is available here: How to enable Android App links in web-facing Sharepoint on-prem site.

Monday, September 21, 2020

Call AAD secured Azure functions from Postman

It is often needed to test our AAD secured Azure functions from client applications like Postman. In one of my previous articles I showed how to call secured Azure functions from C# and PowerShell (see Call Azure AD secured Azure functions from C#). Let’s see now to to call them from Postman app – in this case we won’t need to write any code for testing our functions.

First of all we need to obtain access token. If app permissions are used we may use the same approach as in article mentioned above. For delegated user permissions you may go to SPFx page which calls Azure function, open browser Network tab, find call to some Azure function there and copy access token from Authorization header (value after “Bearer” part).

After that go to Postman and create new request using url of Azure function (it can be copied from Azure portal > Functions app) and correct http verb. On Autorization tab set Type = “Bearer Token” and copy access token to the Token field:

After that on Headers tab set correct content type if needed (e.g. application/json):

Then press Send. After that we should get results from AAD secured Azure function in Postman.