Friday, June 4, 2021

Issue with PnP JS sp.site.exists() call when page url contains hashes

Today we faced with interesting problem when tried to use sp.site.exists(url) method from PnP JS for determining whether site collection with specified url exists or not: all calls returned 403 with System.UnauthorizedAccessException:

During analysis I've found that it tried to make HTTP POST calls to the following url for all sites: https://{tenant}.sharepoint.com/sites/_api/contextinfo which is definitely not correct because https://{tenant}.sharepoint.com/sites is not correct url but managed path. Then we noticed that page where this code was executed contains #/ in url:

https://{tenant}.sharepoint.com/sites/mysitecol#/favorites

and it seems like PnP JS parses it incorrectly in this case. As workaround we checked which API is used inside sp.site.exists(url) call (/_api/SP.Site.Exists) and rewrote code with explicit API call instead:

let promise = context.spHttpClient.post(context.pageContext.site.absoluteUrl + "/_api/SP.Site.Exists",
  SPHttpClient.configurations.v1, {
  headers: {
	"accept": "application/json;"
  },
  body: JSON.stringify({
	url: url
  })
}).then((response: SPHttpClientResponse) => {
  response.json().then((exists: any) => {
	if (exists.value) {
	  // site exists
	} else {
	  // site doesn't exist
	}
  });
});

Hope that PnP JS will fix this issue at some point.

Wednesday, May 26, 2021

Latest Az 6.0.0 module conflicts with PnP.PowerShell 1.3.0

Today new Az 6.0.0 module was released (we wait for this release since it should contain fix for this issue: Webapp:Set-AzWebApp doesn't update app settings of App service). However it introduced own problem: it conflicts with PnP.PowerShell 1.3.0. It is important in each order these 2 modules are imported: if PnP.PowerShell is imported before Az then call to Connect-AzAccount will throw the following error:

Connect-AzAccount : InteractiveBrowserCredential authentication failed:
Method not found: 'Void Microsoft.Identity.Client.Extensions.Msal.MsalCacheHelper.RegisterCache(Microsoft.Identity.Client.ITokenCache)'.
+ Connect-AzAccount
+ ~~~~~~~~~~~~~~~~~
    + CategoryInfo          : CloseError: (:) [Connect-AzAccount], AuthenticationFailedException
    + FullyQualifiedErrorId : Microsoft.Azure.Commands.Profile.ConnectAzureRmAccountCommand

Here is the minimal PowerShell code which allows to reproduce the issue:

Import-Module "PnP.PowerShell" -MinimumVersion "1.3.0"
Import-Module "Az" -MinimumVersion "6.0.0"
Connect-AzAccount

In order to avoid the error Az module should be imported before PnP.PowerShell:

Import-Module "Az" -MinimumVersion "6.0.0"
Import-Module "PnP.PowerShell" -MinimumVersion "1.3.0"
Connect-AzAccount


Tuesday, May 25, 2021

Camlex 5.3 and Camlex.Client 4.2 released: support for StorageTZ attribute for DateTime values

Today new versions of Camlex library (both for server side and CSOM) have been released: Camlex 5.3 and Camlex.Client 4.2. For client object model separate packages are available for Sharepoint online and on-premise:

Package Version Description
Camlex.NET.dll 5.3.0 Server object model (on-prem)
Camlex.Client.dll 4.2.0 Client object model (SP online)
Camlex.Client.2013 4.2.0 Client object model (SP 2013 on-prem)
Camlex.Client.2016 4.2.0 Client object model (SP 2016 on-prem)
Camlex.Client.2019 4.2.0 Client object model (SP 2019 on-prem)

In this release possibility to specify StorageTZ attribute for DateTime values was added. Main credits for this release go to Ivan Russo who implemented basic part of the new feature. So now when you create CAML query for DateTime values you may pass "true" into IncludeTimeValue() method which then will add StorageTZ="True" attribute for Value tag:

var now = new DateTime(2021, 5, 18, 17, 31, 18);
string caml = Camlex.Query().Where(x => (DateTime)x["Created"] > now.IncludeTimeValue(true)).ToString();

will generate the following CAML:

<Where>
  <Gt>
      <FieldRef Name="Created" />
      <Value Type="DateTime" IncludeTimeValue="True" StorageTZ="True">2021-05-18T17:31:18Z</Value>
  </Gt>
</Where>

Thank you for using Camlex and as usual, if you have idea for its further improvement you may post it here.

Thursday, May 20, 2021

One problem with bundling SPFx solution

If you run "gulp bundle" for your SPFx project and face with the following error:

No such file or directory "node_modules\@microsoft\gulp-core-build-sass\node_modules\node-sass\vendor"

Try to run the following command first:

node node_modules\@microsoft\gulp-core-build-sass\node_modules\node-sass\scripts\install.js

It will create "vendor" subfolder under "node_modules\@microsoft\gulp-core-build-sass\node_modules\node-sass" and will download necessary binaries there:

Downloading binary from https://github.com/sass/node-sass/releases/download/v4.12.0/win32-x64-64_binding.node                                                 
Download complete                                                                                                                                             
Binary saved to ...\node_modules\@microsoft\gulp-core-build-sass\node_modules\node-sass\vendor\win32-x64-64\binding.node

After that "gulp bundle" command should work.

Tuesday, May 11, 2021

New task group is not visible in edit Azure DevOps pipeline window

If you have created new task group in Azure DevOps and want to add it to your pipeline you may face with the problem that this task group won't be visible in Add task window (I'm talking now about using visual designer when edit pipeline, not by edit yaml file). Even if you stop edit and edit pipeline again - it won't appear. In this case try to click Refresh link on the top - it will fetch latest results from DevOps and your task should appear after that. Note that you should search by task group name:



Wednesday, May 5, 2021

How to suppress warning "TenantId ... contains more than one active subscription. First one will be selected for further use" when use Connect-AzAccount

When you use Connect-AzAccount cmdlet from Az.Accounts module and there are several subscriptions in your tenant it will show the following warning:


"TenantId ... contains more than one active subscription. First one will be selected for further use. To select another subscription, use Set-AzContext"

If you want to handle this situation and give user possibility to explicitly select needed subscription then this warning may not be needed (as it may confuse end users). In order to suppress it use "-WarningAction Ignore" parameter:

Connect-AzAccount -WarningAction Ignore

In this case warning won't be shown:

You may use this technique for suppressing warning from other cmdlets too.

Friday, April 30, 2021

Provision Azure Storage table via ARM template

It is possible to provision Azure Storage table via New-AzStorageTable cmdlet. However it is also possible to provision it via ARM template and New-AzResourceGroupDeployment cmdlet. Last technique is quite powerful because allows to provision many different Azure resources in universal way. In order to provision Azure Storage table via ARM template use the following template:

"resources": [
{
  "type": "Microsoft.Storage/storageAccounts",
  "name": "[parameters('storageAccountName')]",
  "apiVersion": "2019-04-01",
  "kind": "StorageV2",
  "location": "[parameters('location')]",
  "sku": {
	"name": "Standard_LRS"
  },
  "properties": {
	"supportsHttpsTrafficOnly": true
  }
},
{
	"name": "[concat(parameters('storageAccountName'),'/default/','Test')]",
	"type": "Microsoft.Storage/storageAccounts/tableServices/tables",
	"apiVersion": "2019-06-01",
	"dependsOn": [
		"[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]"
	]
},

In this example we provision both Azure storage and then table Test in this Azure storage. It is also possible to provision only table - in this case use only second part of template.