Friday, April 16, 2021

Server Error in '/' Application when activating "Nintex Forms" web app feature.

Apparently "INSTALL-NFService" need to be run in SharePoint PowerShell to fix this problem.

 

When I installed Nintex Forms again,

I can't add license, because I got message that "Nintex Forms has not been activated yet.

Please go to Central Administration and activate the Nintex Forms under Web Application > Manage web application > Manage Features

Problems with overwriting the versions Nintex Workflow

 I wanted to modify a workflow, but I didn't want my modifications to overwrite the existing version,

so when saving I unticked the relevant checkbox.

I thought that this checkbox will come back next time but it is not there anymore for that particular workflow. 

And now, when I tested and published, I want to have the possibility to overwrite the existing version with new one,

but instead I have to save a new unpublished version, publish it, and delete the old one, which is not the best way.

So, the question is, how to get the checkbox back?

 

Resolution steps

 

(List Settings -> Workflow Settings -> Remove a workflow) and set all previous workflow versions to No New Instances and left only the most recent version as Allow. 

Upon doing this, I was again able to edit an existing workflow, publish it with overwrite, and see only the latest version on the Start a New Workflow page.

Note, if you select to Remove previous workflow versions, I believe it deletes them presently and you can no longer view the workflow history diagram on historical items that used this workflow version.

 

Looping in a Nintex Workflow running slow

Not sure if I understood completely, but I will say that the Pause action defaults to 5 minutes, even if you set it for say 1 minute. 

This can be changed internally within SharePoint but messing with the timer in such a way isn't really recommended as it can cause other issues.   

What you might be able to do is introduce the Pause Action after X amount of items, so maintain a Counter and then Run If counter = say 25,

then Pause for 5 minutes.  In this way you can control the amount of Pauses that take place and ultimately lower the amount of time this process takes.

 

 


Create a Random Password Generator with C#

Here is our code to read. 
using System;
using System.Text.RegularExpressions;
using System.Text;
                    
public class Program
{
    public static void Main()
    {
	const int MAXIMUM_PASSWORD_ATTEMPTS = 10000;
        bool includeLowercase = true;
        bool includeUppercase = true;
        bool includeNumeric = true;
		bool includeSpecial = false;
        int lengthOfPassword  = 16;
        
		PasswordGeneratorSettings settings = new PasswordGeneratorSettings(includeLowercase, includeUppercase, includeNumeric, includeSpecial, lengthOfPassword);
		string password;
		if (!settings.IsValidLength())
		{
			password = settings.LengthErrorMessage();
		}
		else
		{
			int passwordAttempts = 0;
			do
			{
				password = PasswordGenerator.GeneratePassword(settings);
				passwordAttempts++;
			}
			while (passwordAttempts < MAXIMUM_PASSWORD_ATTEMPTS && !PasswordGenerator.PasswordIsValid(settings, password));
			
			password = PasswordGenerator.PasswordIsValid(settings, password) ? password : "Try again";
		}
        
        Console.WriteLine(password);
    }
}

public class PasswordGeneratorSettings
{
	const string LOWERCASE_CHARACTERS = "abcdefghijklmnopqrstuvwxyz";
	const string UPPERCASE_CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
	const string NUMERIC_CHARACTERS = "0123456789";
	const string SPECIAL_CHARACTERS = @"!#$%&*@\";
	const int PASSWORD_LENGTH_MIN = 8;
	const int PASSWORD_LENGTH_MAX = 128;
	
	public bool IncludeLowercase {get; set; }
	public bool IncludeUppercase { get; set; }
	public bool IncludeNumbers { get; set; }
	public bool IncludeSpecial { get; set; }
	public int PasswordLength { get; set; }
	public string CharacterSet { get; set; }
	public int MaximumAttempts { get; set; }
	
	public PasswordGeneratorSettings(bool includeLowercase, bool includeUppercase, bool includeNumbers, bool includeSpecial, int passwordLength)
	{
		IncludeLowercase = includeLowercase;
		IncludeUppercase = includeUppercase;
		IncludeNumbers = includeNumbers;
		IncludeSpecial = includeSpecial;
		PasswordLength = passwordLength;
		
		StringBuilder characterSet = new StringBuilder();
		
		if (includeLowercase)
		{
			characterSet.Append(LOWERCASE_CHARACTERS);
		}
		
		if (includeUppercase)
		{
			characterSet.Append(UPPERCASE_CHARACTERS);
		}
		
		if (includeNumbers)
		{
			characterSet.Append(NUMERIC_CHARACTERS);
		}
		
		if (includeSpecial)
		{
			characterSet.Append(SPECIAL_CHARACTERS);
		}
		
		CharacterSet = characterSet.ToString();
	}
	
	public bool IsValidLength()
	{
		return PasswordLength >= PASSWORD_LENGTH_MIN && PasswordLength <= PASSWORD_LENGTH_MAX;
	}
	
	public string LengthErrorMessage()
	{
		return string.Format("Password length must be between {0} and {1} characters", PASSWORD_LENGTH_MIN, PASSWORD_LENGTH_MAX);
	}
}


public static class PasswordGenerator
{
	
	/// <summary>
	/// Generates a random password based on the rules passed in the settings parameter
	/// </summary>
	/// <param name="settings">Password generator settings object</param>
	/// <returns>Password or try again</returns>
	public static string GeneratePassword(PasswordGeneratorSettings settings)
	{
		const int MAXIMUM_IDENTICAL_CONSECUTIVE_CHARS = 2;
		char[] password = new char[settings.PasswordLength];
		int characterSetLength = settings.CharacterSet.Length;
		
		System.Random random = new System.Random();
		for (int characterPosition = 0; characterPosition < settings.PasswordLength; characterPosition++)
		{
			password[characterPosition] = settings.CharacterSet[random.Next(characterSetLength - 1)];
			
			bool moreThanTwoIdenticalInARow =
				characterPosition > MAXIMUM_IDENTICAL_CONSECUTIVE_CHARS
				&& password[characterPosition] == password[characterPosition - 1]
				&& password[characterPosition - 1] == password[characterPosition - 2];
			
			if (moreThanTwoIdenticalInARow)
			{
				characterPosition--;
			}
		}
		
		return string.Join(null, password);
	}
	
	
	/// <summary>
	/// When you give it a password and some settings, it validates the password against the settings.
	/// </summary>
	/// <param name="settings">Password settings</param>
	/// <param name="password">Password to test</param>
	/// <returns>True or False to say if the password is valid or not</returns>
	public static bool PasswordIsValid(PasswordGeneratorSettings settings, string password)
	{
		const string REGEX_LOWERCASE = @"[a-z]";
		const string REGEX_UPPERCASE = @"[A-Z]";
		const string REGEX_NUMERIC = @"[\d]";
		const string REGEX_SPECIAL = @"([!#$%&*@\\])+";
		
		bool lowerCaseIsValid = !settings.IncludeLowercase || (settings.IncludeLowercase && Regex.IsMatch(password, REGEX_LOWERCASE));
		bool upperCaseIsValid = !settings.IncludeUppercase || (settings.IncludeUppercase && Regex.IsMatch(password, REGEX_UPPERCASE));
		bool numericIsValid = !settings.IncludeNumbers || (settings.IncludeNumbers && Regex.IsMatch(password, REGEX_NUMERIC));
		bool symbolsAreValid = !settings.IncludeSpecial || (settings.IncludeSpecial && Regex.IsMatch(password, REGEX_SPECIAL));
		
		return lowerCaseIsValid && upperCaseIsValid && numericIsValid && symbolsAreValid;
	}
}

Copy list attachments to a Document Library using Nintex workflow

 

In SharePoint 2016, you can do like below.

1.Build String action.

2. Create Item action.

3. Copy to SharePoint action.

Using PreSaveItem to add custom validation to SharePoint list form

 

In this article I explain how to change the standard server side to a custom client side form validation. You can’t really change for server to client side, but you can validate your input with JavaScript before to send them to the server and then “skip” server side validation. You can do all of this by using a standard JavaScript function used on every submit button, PreSaveItem.

Out-of-the-box PreSaveItem doesn’t do anything, but on every form save action, SharePoint checks if PreSaveItems return false. In this case it doesn’t allow the form submit. See the following row to better understand what I mean.

if (!PreSaveItem()) return false;​

In a custom javascript file you have to redefine the PreSaveItem function, adding your custom data validation. In my article I wrote a function that leverage the power of regular expressions to validate an email address field. Let’s see the example below.

function PreSaveItem(){
  var err = false;
  var email = $("input[title='E-mail']");
  
  var re_email = /^[0-9a-zA-Z]+([0-9a-zA-Z]*[-._+])*[0-9a-zA-Z]+@[0-9a-zA-Z]+([-.][0-9a-zA-Z]+)*([0-9a-zA-Z]*[.])[a-zA-Z]{2,6}$​/;
  
  if (!(re_email.test(email.val())) || email.val().length == 0){
    var erremail = '<div class="ms-formvalidation"><span role="alert"><b>E-mail address</b> field is not valid.</span></div>';
    email.after(erremail);
    email.focus();
    err = true;
  }

  return !(err)

I used jQuery to select the field and to add an error message after the input when needed. I also added another little piece of  code to clear the error message when the user change the fields value.

$(document).ready(function(){
  $("input[title='E-mail']").change(function(){
    $(this).next().hide();
  }); 
});

Create Custom Login Page Mixed authentication SharePoint 2013

 

In series of my SP2013 blogs my this blog describes how to “Create Custom Login Page Mixed authentication in SharePoint 2013“.

It is bit similar to SP2010 with a small change of the master page it inherits and sharepoint assembly version. So below is my code to achieve login functionality for “Windows Authentication” and “Forms Authentication“.

ASPX Page(Application Page):

Note: 1. Some things you must replace those are highlighted below.

2. Master page used for mixed mode login page is errorv15.master

3. I override click event of login button that default use CommandName=”Login”

4. Also you can use either  <%–<a href=”/_windows/default.aspx?ReturnUrlor  <asp:LinkButton ID=”lbInternalUsers” … former is easy but less in control from code, later best for controlling events.

<%@ Assembly Name="Microsoft.SharePoint.IdentityModel, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Assembly Name="$SharePoint.Project.AssemblyFullName$" %>
 
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="YourPageName.aspx.cs" Inherits="YourNameSpace.YourClassName" MasterPageFile="~/_layouts/15/errorv15.master" %>
 
<%@ Import Namespace="Microsoft.SharePoint.WebControls" %>
<%@ Register TagPrefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Import Namespace="Microsoft.SharePoint" %>
<%@ Assembly Name="Microsoft.Web.CommandUI, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="asp" Namespace="System.Web.UI" Assembly="System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" %>
 
<asp:Content ID="PageTitle" ContentPlaceHolderID="PlaceHolderPageTitle" runat="server">
    <SharePoint:EncodedLiteral runat="server" EncodeMethod="HtmlEncode" ID="ClaimsFormsPageTitle" />
</asp:Content>
 
<asp:Content ID="Main" ContentPlaceHolderID="PlaceHolderMain" runat="server">
    <div id="SslWarning" style="color: red; display: none">
        <SharePoint:EncodedLiteral runat="server" EncodeMethod="HtmlEncode" ID="ClaimsFormsPageMessage" />
    </div>
    <script language="javascript">
        if (document.location.protocol != 'https:') {
            var SslWarning = document.getElementById('SslWarning');
            SslWarning.style.display = '';
        }
    </script>
    <asp:Label ID="lblError" class="ms-error" runat="server" Visible="false" />
    <asp:Login ID="signInControl" FailureText="<%$Resources:wss,login_pageFailureText%>" runat="server" Width="100%">
        <LayoutTemplate>
            <asp:Label ID="FailureText" class="ms-error" runat="server" />
            <table width="100%">
                <tr>
                    <td nowrap="nowrap">
                        <SharePoint:EncodedLiteral ID="EncodedLiteral1" runat="server" Text="<%$Resources:wss,login_pageUserName%>" EncodeMethod='HtmlEncode' /></td>
                    <td width="100%">
                        <asp:TextBox ID="UserName" autocomplete="off" runat="server" class="ms-inputuserfield" Width="99%" /></td>
                </tr>
                <tr>
                    <td nowrap="nowrap">
                        <SharePoint:EncodedLiteral ID="EncodedLiteral2" runat="server" Text="<%$Resources:wss,login_pagePassword%>" EncodeMethod='HtmlEncode' /></td>
                    <td width="100%">
                        <asp:TextBox ID="password" TextMode="Password" autocomplete="off" runat="server" class="ms-inputuserfield" Width="99%" /></td>
                </tr>
                <tr>
                    <td colspan="2" align="right">
                        <asp:Button ID="login" OnClick="login_click" Text="<%$Resources:wss,login_pagetitle%>" runat="server" /></td>
                    <!--CommandName="Login"-->
                </tr>
                <tr>
                    <td colspan="2">
                        <asp:CheckBox ID="RememberMe" Text="<%$SPHtmlEncodedResources:wss,login_pageRememberMe%>" runat="server" /></td>
                </tr>
            </table>
        </LayoutTemplate>
    </asp:Login>
    <br />
    <h2>Admin Login</h2>   
    <%--<a href="/_windows/default.aspx?ReturnUrl=<%=Request.QueryStringource"] %>">Click here to login</a>    --%>
 <asp:LinkButton ID="lbInternalUsers" Text="Click here to login" runat="server" Font-Names="Calibri" Font-Size="Small" CssClass="ms-standardheader" Font-Bold="true" ForeColor="Green" OnClick="lbInternalUsers_OnClick"></asp:LinkButton>
 
</asp:Content>

Code(cs class):
Note: 1.
In forms replace "subsiteurl" with server relative url of the subsite.
2. In forms replace "YourPage" with the page name where you want to redirect user after login.  protected void login_click(object sender, EventArgs e)         {             try             {                 //Check and validate the user is exists with the right user and password or not                                 if (SPClaimsUtility.AuthenticateFormsUser(new Uri(SPContext.Current.Web.Url), signInControl.UserName, signInControl.Password))                 {                     SPSecurity.RunWithElevatedPrivileges(delegate()                     {                         string loginName = "i:0#.f|fbamembershipprovider|" + signInControl.UserName;                         using (SPSite site = new SPSite(SPContext.Current.Site.Url))                         {                             using (SPWeb web = site.OpenWeb())                             {                                 SPUser spUser = web.AllUsers[loginName];                                 if (spUser != null)                                 {                                     bool IsUserInGroupA = false;                                     bool IsUserInGroupB = false;                                     foreach (SPGroup spGroup in spUser.Groups)                                     {                                         if (spGroup.Name == "A")                                         {                                             IsUserInGroupA = true;                                             break;                                         }                                         if (spGroup.Name == "B")                                         {                                             IsUserInGroupB = true;                                             break;                                         }                                     }                                     if (IsUserInGroupA)                                     {                                         SPUtility.Redirect(web.Webs["subsiteurl"].Url + "/Pages/YourPage.aspx", SPRedirectFlags.Trusted, this.Context);                                         //FormsAuthentication.RedirectFromLoginPage();                                     }                                     else if (IsUserInISGTFGroup)                                     {                                          //SPUtility.Redirect(web.Webs["subsiteurl"].Url + "/Pages/YourPage.aspx", SPRedirectFlags.Trusted, this.Context);                                         //FormsAuthentication.RedirectFromLoginPage();                                     }                                     else                                     {                                         SPUtility.Redirect(web.Url, SPRedirectFlags.Trusted, this.Context);                                                                             }                                 }                             }                         }                     });                 }                 else                 {                     lblError.Visible = true;                     lblError.Text = "The server could not sign you in. Make sure your user name and password are correct, and then try again.";                 }             }             catch (Exception ex)             {             }         }         

protected void lbInternalUsers_OnClick(object sender, EventArgs e)         {             try             {                 if (null != SPContext.Current && null != SPContext.Current.Site)                 {                     SPIisSettings iisSettings = SPContext.Current.Site.WebApplication.IisSettings[SPUrlZone.Default];                     if (null != iisSettings && iisSettings.UseWindowsClaimsAuthenticationProvider)                     {                         SPAuthenticationProvider provider = iisSettings.WindowsClaimsAuthenticationProvider;                         Redirect(provider);                     }                 }             }             catch (Exception ex)             {                 //lblError.Text = ex.Message;             }         }         

private void Redirect(SPAuthenticationProvider provider)         {             string comp = HttpContext.Current.Request.Url.GetComponents(UriComponents.Query, UriFormat.SafeUnescaped);             string url = provider.AuthenticationRedirectionUrl.ToString();             if (provider is SPWindowsAuthenticationProvider)             {                 comp = EnsureUrl(comp, true);             }             SPUtility.Redirect(url, SPRedirectFlags.Default, this.Context, comp);         }         

private string EnsureUrl(string url, bool urlIsQueryStringOnly)         {             if (!url.Contains("ReturnUrl="))             {                 if (urlIsQueryStringOnly)                 {                     url = url + (string.IsNullOrEmpty(url) ? "" : "&");                 }                 else                 {                     url = url + ((url.IndexOf('?') == -1) ? "?" : "&");                 }                 url = url + "ReturnUrl=";             }             return url;         }

So this is the crisp about creating full controlled login page for SP 2013 in mixed authentication mode.

This is how my login page look like.




Server Error in '/' Application when activating "Nintex Forms" web app feature.

Apparently "INSTALL-NFService" need to be run in SharePoint PowerShell to fix this problem.   When I installed Nintex Forms agai...