SOLVED

Deleting Site UserCustomActions if you can't get access to the Site Collection

%3CLINGO-SUB%20id%3D%22lingo-sub-4953%22%20slang%3D%22en-US%22%3EDeleting%20Site%20UserCustomActions%20if%20you%20can't%20get%20access%20to%20the%20Site%20Collection%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-4953%22%20slang%3D%22en-US%22%3E%3CP%3EOops..%3C%2FP%3E%3CP%3EInstead%20of%20pasting%20a%20plain%20text%20URL%20I%20managed%20to%20create%20a%20Site%20UserCuctomAction%20with%20HTML%20code%20in%20it.%3C%2FP%3E%3CP%3EThis%20%22script%22%20is%20now%20executing%20on%20every%20page.%3C%2FP%3E%3CP%3EThe%20result%20is%20an%20(Office365)%20SharePoint%20server%20that%20delivers%20me%20only%20blank%20pages.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EIs%20there%20an%20easy%20method%20of%20resetting%20UserCustomActions%3F%3C%2FP%3E%3C%2FLINGO-BODY%3E%3CLINGO-SUB%20id%3D%22lingo-sub-6105%22%20slang%3D%22en-US%22%3ERe%3A%20RE%3A%20Deleting%20Site%20UserCustomActions%20if%20you%20can't%20get%20access%20to%20the%20Site%20Collection%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-6105%22%20slang%3D%22en-US%22%3E%3CP%3ESome%20REST%20calls%20instead%20of%20JSOM%20did%20the%20job%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3C%2FLINGO-BODY%3E%3CLINGO-SUB%20id%3D%22lingo-sub-6070%22%20slang%3D%22en-US%22%3ERe%3A%20Deleting%20Site%20UserCustomActions%20if%20you%20can't%20get%20access%20to%20the%20Site%20Collection%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-6070%22%20slang%3D%22en-US%22%3E%3CP%3EDid%20you%20try%20the%20PnP%20PoSH%3F%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ERemove-SPOCustomAction%20-Scope%20Site%3C%2FP%3E%3C%2FLINGO-BODY%3E%3CLINGO-SUB%20id%3D%22lingo-sub-6068%22%20slang%3D%22en-US%22%3ERE%3A%20Deleting%20Site%20UserCustomActions%20if%20you%20can't%20get%20access%20to%20the%20Site%20Collection%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-6068%22%20slang%3D%22en-US%22%3EIf%20the%20page%20is%20loading%2C%20but%20blank%20because%20it%20is%20breaking%2C%20you%20can%20delete%20it%20in%20the%20browser's%20console%20window%20by%20scripting%20CSOM.%3C%2FLINGO-BODY%3E%3CLINGO-SUB%20id%3D%22lingo-sub-6018%22%20slang%3D%22en-US%22%3ERe%3A%20Deleting%20Site%20UserCustomActions%20if%20you%20can't%20get%20access%20to%20the%20Site%20Collection%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-6018%22%20slang%3D%22en-US%22%3E%3CP%3EI've%20made%20the%20same%20mistake%20doing%20some%20testing.%20To%20fix%20it%20I%20wrote%20a%20small%20console%20app%20to%20list%20the%20user%20custom%20actions%20and%20pick%20and%20choose%20to%20delete%20them.%20Maybe%20for%20future%20reference%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%3Eusing%20System%3B%0Ausing%20System.Collections.Generic%3B%0Ausing%20System.Linq%3B%0Ausing%20System.Text%3B%0Ausing%20System.Threading.Tasks%3B%0Ausing%20Microsoft.SharePoint.Client%3B%0Ausing%20System.Security%3B%0A%0Anamespace%20SharePointCustomAction%0A%7B%0A%20%20%20%20class%20Program%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20static%20void%20Main(string%5B%5D%20args)%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20Console.WriteLine(%22Password%3A%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20var%20password%20%3D%20GetConsoleSecurePassword()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20Console.WriteLine()%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20using%20(var%20ctx%20%3D%20new%20ClientContext(%22https%3A%2F%2Ftenant.sharepoint.com%22))%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20ctx.Credentials%20%3D%20new%20SharePointOnlineCredentials(%22user%40tenant.onmicrosoft.com%22%2C%20password)%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20var%20uca%20%3D%20ctx.Web.UserCustomActions%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20ctx.Load(uca)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20ctx.ExecuteQuery()%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20for%20(var%20i%20%3D%20uca.Count%20-%201%3B%20i%20%26gt%3B%20-1%3B%20i--)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Console.WriteLine(string.Format(%22Delete%20embedded%20script%3A%20%7B0%7D%22%2C%20uca%5Bi%5D.Title))%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20var%20input%20%3D%20Console.ReadKey()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(input.KeyChar%20%3D%3D%20'y')%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20uca%5Bi%5D.DeleteObject()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Console.WriteLine()%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20ctx.ExecuteQuery()%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Console.WriteLine(%22-----Finished------%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Console.ReadLine()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20private%20static%20SecureString%20GetConsoleSecurePassword()%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20SecureString%20pwd%20%3D%20new%20SecureString()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20while%20(true)%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20ConsoleKeyInfo%20i%20%3D%20Console.ReadKey(true)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(i.Key%20%3D%3D%20ConsoleKey.Enter)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20break%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20else%20if%20(i.Key%20%3D%3D%20ConsoleKey.Backspace)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pwd.RemoveAt(pwd.Length%20-%201)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Console.Write(%22%5Cb%20%5Cb%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20else%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pwd.AppendChar(i.KeyChar)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Console.Write(%22*%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20pwd%3B%0A%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%7D%0A%0A%0A%7D%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3C%2FLINGO-BODY%3E%3CLINGO-SUB%20id%3D%22lingo-sub-4978%22%20slang%3D%22en-US%22%3ERe%3A%20Deleting%20Site%20UserCustomActions%20if%20you%20can't%20get%20access%20to%20the%20Site%20Collection%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-4978%22%20slang%3D%22en-US%22%3EIts%20a%20ScriptLink%20(Site%20UserCustomAction)%2C%20I%20have%20never%20seen%20those%20in%20SPD.%3CBR%20%2F%3E(My)%20Quickest%20way%20was%20to%20go%20to%20another%20Site%20Collection%20(authenticated)%20get%20the%20RequestDigest%20from%20the%200ffending%20site%20with%20a%20REST%20call%20and%20then%20clear%20out%20the%20Site%20Action%20with%20a%20REST%20DELETE%3CBR%20%2F%3E%3CBR%20%2F%3EI%20now%20understand%20why%20Microsoft%20disabled%20these%20type%20of%20UserCustomActions%20%3A)%3C%2Fimg%3E%20But%20we%20still%20want%20one%20script%20for%20every%20(New%20Experience)%20page...%3C%2FLINGO-BODY%3E%3CLINGO-SUB%20id%3D%22lingo-sub-4957%22%20slang%3D%22en-US%22%3ERe%3A%20Deleting%20Site%20UserCustomActions%20if%20you%20can't%20get%20access%20to%20the%20Site%20Collection%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-4957%22%20slang%3D%22en-US%22%3EWould%20it%20not%20be%20the%20easiets%20way%20to%20remove%20the%20custom%20action%20by%20deleting%20it%20using%20Sharepoint%20Designer%202013%3F%3C%2FLINGO-BODY%3E
Highlighted
Contributor

Oops..

Instead of pasting a plain text URL I managed to create a Site UserCuctomAction with HTML code in it.

This "script" is now executing on every page.

The result is an (Office365) SharePoint server that delivers me only blank pages.

 

Is there an easy method of resetting UserCustomActions?

6 Replies
Highlighted
Would it not be the easiets way to remove the custom action by deleting it using Sharepoint Designer 2013?
Highlighted
Its a ScriptLink (Site UserCustomAction), I have never seen those in SPD.
(My) Quickest way was to go to another Site Collection (authenticated) get the RequestDigest from the 0ffending site with a REST call and then clear out the Site Action with a REST DELETE

I now understand why Microsoft disabled these type of UserCustomActions :) But we still want one script for every (New Experience) page...
Highlighted

I've made the same mistake doing some testing. To fix it I wrote a small console app to list the user custom actions and pick and choose to delete them. Maybe for future reference:

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.SharePoint.Client;
using System.Security;

namespace SharePointCustomAction
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Password:");
            var password = GetConsoleSecurePassword();
            Console.WriteLine();

            using (var ctx = new ClientContext("https://tenant.sharepoint.com"))
            {
                ctx.Credentials = new SharePointOnlineCredentials("user@tenant.onmicrosoft.com", password);

                var uca = ctx.Web.UserCustomActions;
                ctx.Load(uca);
                ctx.ExecuteQuery();

                for (var i = uca.Count - 1; i > -1; i--)
                {
                    Console.WriteLine(string.Format("Delete embedded script: {0}", uca[i].Title));
                    var input = Console.ReadKey();
                    if (input.KeyChar == 'y')
                    {
                        uca[i].DeleteObject();
                    }
                    Console.WriteLine();

                }
                ctx.ExecuteQuery();

                Console.WriteLine("-----Finished------");
                Console.ReadLine();
            }
        }

        private static SecureString GetConsoleSecurePassword()
        {
            SecureString pwd = new SecureString();
            while (true)
            {
                ConsoleKeyInfo i = Console.ReadKey(true);
                if (i.Key == ConsoleKey.Enter)
                {
                    break;
                }
                else if (i.Key == ConsoleKey.Backspace)
                {
                    pwd.RemoveAt(pwd.Length - 1);
                    Console.Write("\b \b");
                }
                else
                {
                    pwd.AppendChar(i.KeyChar);
                    Console.Write("*");
                }
            }
            return pwd;
        }

    }


}

 

Highlighted
Best Response confirmed by Danny Engelman (Contributor)
Solution
If the page is loading, but blank because it is breaking, you can delete it in the browser's console window by scripting CSOM.
Highlighted

Did you try the PnP PoSH?

 

Remove-SPOCustomAction -Scope Site

Highlighted

Some REST calls instead of JSOM did the job