Wednesday, November 14, 2018

Different access rights for creating new Azure function project in Visual Studio 2017

When you create new Azure functions project in Visual Studio 2017:

image

it asks you to specify Access rights for the newly created function:

image

There are 3 following options available which mean the following (see Azure Functions HTTP triggers and bindings):

  • Function – a function-specific API key is required. This is the default value if none is provided.
  • Anonymous - no API key is required
  • Admin - the master key is required

More info about these keys can be found here. But how this chose affects Visual Studio project? There are number of files created after you click Ok on the above dialog window:

  • sln – solution file
  • csproj – project file
  • host.json – host settings file
  • local.settings.json – local app settings file
  • Function1.cs – code of Azure function

The difference is only in function code cs file (Function1.cs): different AuthorizationLevel values will be passed to HttpTrigger attribute when different access rights are chosen:

image

Other files are equal. Hope that this info will help to understand Azure functions project structure better.

Wednesday, November 7, 2018

Problem with rendering list RSS feed in Firefox

As you probably know Sharepoint allows to export list content into RSS format. There may be one issue however: some items may not be shown in Firefox default RSS viewer although these items exist in page source (i.e. returned from server). If you will check browser console you may find the following error there:

NS_ERROR_UNEXPECTED
SH_writeContent chrome://browser/content/feeds/subscribe.js:17:5
window.onload chrome://browser/content/feeds/subscribe.js:28:3

image

If we check RSS feeds where items are shown with RSS feeds where items are not shown we will find one difference – enclosure tag:

Working RSS:

<item>
  <title>Test</title>
  <link>http://example.com</link>
  <description></description>
  <author>...</author>
  <pubDate>...</pubDate>
  <guid isPermaLink="true">http://example.com</guid>
</item>

Non-working RSS:

<item>
  <title>Test</title>
  <link>http://example.com</link>
  <description></description>
  <author>...</author>
  <enclosure url="..." />
  <pubDate>...</pubDate>
  <guid isPermaLink="true">http://example.com</guid>
</item>

Items which are not rendered correctly have enclosure tag while items which are rendered correctly don’t have it.

In order to fix this issue you may use the following workaround for Sharepoint on-premise: create ashx handler, put it to /Layouts subfolder, code of the handler will send internal http request to OTB /_layouts/15/listfeed.aspx?List={listId} url, then remove enclosure tag via Regex and return final result to the response (i.e. implement kind of proxy for OTB RSS feed):

string url = string.Format("{0}?List={1}", SPUrlUtility.CombineUrl(web.Url, "_layouts/15/listfeed.aspx"), list.ID);
var request = (HttpWebRequest)WebRequest.Create(url);
request.Credentials = CredentialCache.DefaultNetworkCredentials;
var response = (HttpWebResponse)request.GetResponse();
if (response.StatusCode == HttpStatusCode.OK)
{
	using (var stream = response.GetResponseStream())
	{
		using (var reader = new StreamReader(stream))
		{
			result = reader.ReadToEnd();
		}
	}
	result = Regex.Replace(result, @"<enclosure.+?/>", string.Empty);
}

As result there won’t be enclosure tag and RSS feed will be rendered correctly in Firefox.

Tuesday, October 30, 2018

Problem with delayed effect of setting DenyAddAndCustomizePages to false on modern Sharepoint Online site

Some time ago we faced with the following problem: let’s say we have PowerShell script which does some actions on modern Sharepoint Online site collection. Among with other actions it sets property bag values on the root site of the target site collection:

Set-PnPPropertyBagValue -Key "Key" -Value "Value"

In order to do that (as well as to do other customizations on the modern site) you need to set DenyAddAndCustomizePages property to false on that site (see e.g. Access denied when try to delete folder in Modern Sharepoint site’s doclib). It can be done using the following PnP PowerShell cmdlet:

Set-PnPTenantSite -Url $url -NoScriptSite:$false

It returns control quite quickly. The problem however that on practice effect from setting DenyAddAndCustomizePages to false has delay. I.e. if you will try to set property bag value using cmdlet shown above immediately after you set DenyAddAndCustomizePages to false – there won’t be any errors but value won’t be really saved into property bag.

As workaround I’ve added 60 seconds delay to the script with UI indication (dots are printed to output each second until there won’t be 60 dots in line):

Write-Host "Wait some time before changes will take effect..."
$i = 0
do
{
	Write-Host "." -NoNewLine
	Start-Sleep -s 1
	$i++
}
while ($i -lt 60)
Write-Host

After this delay property bag values were saved successfully.

Wednesday, October 17, 2018

UnauthorizedAccessException when try to delete alert from Sharepoint site

If you try to delete alerts from the Sharepoint site programmatically:

SPWeb web = ...;
web.Alerts.Delete(alertId);

You may face with UnauthorizedAccessException:

<nativehr>0x80070005</nativehr><nativestack></nativestack>
    at Microsoft.SharePoint.SPGlobal.HandleUnauthorizedAccessException(UnauthorizedAccessException ex)
    at Microsoft.SharePoint.Library.SPRequest.DeleteSubscription(String bstrUrl, String bstrListName, String bstrSubId, Boolean bListItem, UInt32 ulItemId, Boolean bSiteAdmin, Int32 lUserId)
    at Microsoft.SharePoint.SPAlertCollection.Delete(Guid idAlert)

First thing to check is of course that account under which the code above is executed has all necessary permissions on the site. If this is the case but the problem is still there check that your site collection is not in readonly mode. You may do it using the following PowerShell command:

Get-SPSite -Id http://example.com | select ReadOnly,Readlocked,WriteLocked,LockIssue | ft -autosize

If site is in readonly mode result will look like this:

image

and if site is not readonly it will look like this:

image

You may unlock site collection using the following PowerShell command:

Set-SPSite -Id http://example.com -LockState Unlock

And set it to readonly mode like this:

Set-SPSite -Id http://example.com -LockState ReadOnly

Hope that this information will be helpful.

Friday, October 12, 2018

Using of relative and absolute urls when create Modern Sharepoint site via PnP PowerShell

Modern Team and Communication sites can be created through PnP PowerShell cmdlet New-PnPSite. Here are examples how you may create these sites:

Team: New-PnPSite -Type TeamSite -Title Test -Alias test
Communication: New-PnPSite -Type CommunicationSite -Title Test -Url https://{tenant}.sharepoint.com/sites/test

Note that for Team site we use Alias parameter while for Communication site we use Url. It is mandatory to use relative url when you create Team site and absolute url when you create Communication site. If you will try to create Team site with absolute url:

Team: New-PnPSite -Type TeamSite -Title Test -Alias https://{tenant}.sharepoint.com/sites/test

you will get the following error:

Invalid value specified for property 'mailNickname' of resource 'Group'.

And if you will try to create communication site with relative url:

Communication: New-PnPSite -Type CommunicationSite -Title Test -Url test

there will be another error:

This operation is not supported for a relative URI.

Hope that it will help someone.

Wednesday, October 10, 2018

Access denied when try to delete folder in Modern Sharepoint site’s doclib

Recently I faced with the following problem: when you create OTB Modern Team or Communication site (see How to create modern Team or Communication site in Sharepoint) you can create sub folders in document libraries, e.g. in Style library:

image

(BTW with modern experience currently it is possible to create sub folders of only first level. If you want to create sub folders of deeper levels you have to switch to classic experience and create sub folder from there)

However if you will try to delete this folder you will get the following error:

Sorry, something went wrong
The server has encountered the following error(s):
Test
Access denied. You do not have permission to perform this action or access this resource.

image

In order to avoid this error you need to enable customizations of pages and scripts on the site. You may do it with the following PowerShell command:

Connect-SPOService -Url https://{tenant}-admin.sharepoint.com
Set-SPOSite {url} -DenyAddAndCustomizePages 0

After that you will be able to delete sub folders in Style library doclib on the modern site.

Thursday, September 27, 2018

Problem with getting user token for MS Graph using Azure AD app of Web app type registered in v1 portal.azure.com

As you probably know currently it is possible to register Azure AD apps in 2 places:

  1. https://portal.azure.com – v1 portal
  2. https://apps.dev.microsoft.com – v2 portal

There is number of differences between apps registered in these 2 portals – you may check them e.g. here: About v2.0. For this article let’s notice that apps registered in v2 may support both web app and native platforms while apps in v1 may be either web app or native but not both. If you need them both you have to register 2 apps in v1 portal.

Recently we faced with a problem of getting user token for MS Graph i.e. token based on user credentials. We used the following code for that and it works properly for the app registered in v2 portal with native platform support:

var credentials = new Microsoft.IdentityModel.Clients.ActiveDirectory.UserCredential("username", "password");       
var token = Task.Run(async () =>
{
    var authContext = new AuthenticationContext(string.Format("https://login.microsoftonline.com/{0}", "mytenant.onmicrosoft.com"));
    var authResult = await authContext.AcquireTokenAsync("https://graph.microsoft.com", appId, credentials);
    return authResult.AccessToken;
}).GetAwaiter().GetResult();

where for appId we used Azure AD app id registered in v2. When we tried to run the same code for the app registered in v1 portal with web app type the following error was shown:

Error: index was outside the bounds of the array

The same code also works properly for the app from v1 portal but with native type. I.e. it looks like AuthenticationContext.AcquireTokenAsync() method may fetch user token only for native app. If you know how to get user token for web app from v1 portal please share it in comments.