After November 2024, SharePoint will remove the ability to keep scripting capabilities enabled as shown in this message:
To help you navigate these changes, our experts have created a script that you can run automatically every 8 hours using Windows scheduler. This will temporarily keep scripting capabilities enabled and allow ShortPoint to continue working on Classic SharePoint Pages for MS 365.
NOTESharePoint 2019 and SE will be unaffected by the said changes.
This script is a temporary solution so that you can continue the migration from classic pages to modern pages. We highly recommend you complete this migration for all important pages to avoid disruptions caused by future SharePoint updates.
TABLE OF CONTENTS
- Transforming Classic Pages to Modern Pages
- Step-by-step Tutorial
Transforming Classic Pages to Modern Pages
You can watch the video below to see a detailed guide on how to accomplish the transformation from classic pages to modern pages:
You can also refer to the following articles:
- ShortPoint Microsoft 365 Classic Pages Deprecation: Transforming Classic Pages to Modern Pages
- How to Transform a Classic SharePoint Page into Modern
Step-by-step Tutorial
Follow the steps below for a detailed guide on how to schedule the automatic persistence of Scripting Capabilities.
Note that the PC you apply these steps on should be kept running 24/7 to be able to run the script every 8 hours (it shouldn't be shut down or not put to sleep)
The steps have been divided into 5 parts. Make sure to carefully follow the steps for each part.
Part 1: Install PowerShell 7 and Pnp.Powershell
This part will detail how to install PowerShell 7 and Pnp.Powershell:
Step 1: Install and Start PowerShell 7
- Go to Installing PowerShell on Windows and scroll down to Installing the MSI Package. You will find the download link there:
- After installing, start PowerShell 7 as admin from the start menu:
Step 2: Install Pnp.Powershell
- Run the command below:
Install-Module PnP.PowerShell -Scope CurrentUser
- Then, type A and press enter:
- Run the command below to register an app that will be used to run the commands daily:
Register-PnPEntraIDAppForInteractiveLogin -ApplicationName "ShortPoint Persist Scripting Capabilities" -Tenant 8lvrfv.onmicrosoft.com -Interactive
- After running the command, you’ll need to sign in using a SharePoint Global Administrator user:
Part 2: Grant the Necessary Permissions
This part will show all the necessary permissions to be granted in Microsoft Azure:
Step 1: Open ShortPoint Persist Scripting Capabilities
- Go to [1] App Registrations and select [2] ShortPoint Persist Scripting Capabilities. This is needed to give permissions to the ShortPoint Persist Scripting Capabilities app.
- Copy the Application (client) ID. Take note of this as you will need it later.
Step 2: Add the necessary permissions
- Go to [1] Authentication and enable [2] Allow public client flows:
- Then, go to API permissions:
- Add the following permissions:
- Once done, click [1] Grant Admin Consent for <tenant name> and select [2] Yes:
- The API permissions page should look like this:
Part 3: Generate a Certificate
This part will demonstrate how to generate a certificate which you need to upload to the app:
Step 1: Copy the script
- Copy the script below to generate a certificate and save it on a folder on your PC:
#Requires -RunAsAdministrator
<#
.SYNOPSIS
Creates a Self Signed Certificate for use in server to server authentication
.DESCRIPTION
.EXAMPLE
.\Create-SelfSignedCertificate.ps1 -CommonName "MyCert" -StartDate 2015-11-21 -EndDate 2017-11-21
This will create a new self signed certificate with the common name "CN=MyCert". During creation you will be asked to provide a password to protect the private key.
.EXAMPLE
.\Create-SelfSignedCertificate.ps1 -CommonName "MyCert" -StartDate 2015-11-21 -EndDate 2017-11-21 -Password (ConvertTo-SecureString -String "MyPassword" -AsPlainText -Force)
This will create a new self signed certificate with the common name "CN=MyCert". The password as specified in the Password parameter will be used to protect the private key
.EXAMPLE
.\Create-SelfSignedCertificate.ps1 -CommonName "MyCert" -StartDate 2015-11-21 -EndDate 2017-11-21 -Force
This will create a new self signed certificate with the common name "CN=MyCert". During creation you will be asked to provide a password to protect the private key. If there is already a certificate with the common name you specified, it will be removed first.
#>
Param(
[Parameter(Mandatory=$true)]
[string]$CommonName,
[Parameter(Mandatory=$true)]
[DateTime]$StartDate,
[Parameter(Mandatory=$true)]
[DateTime]$EndDate,
[Parameter(Mandatory=$false, HelpMessage="Will overwrite existing certificates")]
[Switch]$Force,
[Parameter(Mandatory=$false)]
[SecureString]$Password
)
# DO NOT MODIFY BELOW
function CreateSelfSignedCertificate(){
#Remove and existing certificates with the same common name from personal and root stores
#Need to be very wary of this as could break something
if($CommonName.ToLower().StartsWith("cn="))
{
# Remove CN from common name
$CommonName = $CommonName.Substring(3)
}
$certs = Get-ChildItem -Path Cert:\LocalMachine\my | Where-Object{$_.Subject -eq "CN=$CommonName"}
if($certs -ne $null -and $certs.Length -gt 0)
{
if($Force)
{
foreach($c in $certs)
{
remove-item $c.PSPath
}
} else {
Write-Host -ForegroundColor Red "One or more certificates with the same common name (CN=$CommonName) are already located in the local certificate store. Use -Force to remove them";
return $false
}
}
$name = new-object -com "X509Enrollment.CX500DistinguishedName.1"
$name.Encode("CN=$CommonName", 0)
$key = new-object -com "X509Enrollment.CX509PrivateKey.1"
$key.ProviderName = "Microsoft RSA SChannel Cryptographic Provider"
$key.KeySpec = 1
$key.Length = 2048
$key.SecurityDescriptor = "D:PAI(A;;0xd01f01ff;;;SY)(A;;0xd01f01ff;;;BA)(A;;0x80120089;;;NS)"
$key.MachineContext = 1
$key.ExportPolicy = 1 # This is required to allow the private key to be exported
$key.Create()
$serverauthoid = new-object -com "X509Enrollment.CObjectId.1"
$serverauthoid.InitializeFromValue("1.3.6.1.5.5.7.3.1") # Server Authentication
$ekuoids = new-object -com "X509Enrollment.CObjectIds.1"
$ekuoids.add($serverauthoid)
$ekuext = new-object -com "X509Enrollment.CX509ExtensionEnhancedKeyUsage.1"
$ekuext.InitializeEncode($ekuoids)
$cert = new-object -com "X509Enrollment.CX509CertificateRequestCertificate.1"
$cert.InitializeFromPrivateKey(2, $key, "")
$cert.Subject = $name
$cert.Issuer = $cert.Subject
$cert.NotBefore = $StartDate
$cert.NotAfter = $EndDate
$cert.X509Extensions.Add($ekuext)
$cert.Encode()
$enrollment = new-object -com "X509Enrollment.CX509Enrollment.1"
$enrollment.InitializeFromRequest($cert)
$certdata = $enrollment.CreateRequest(0)
$enrollment.InstallResponse(2, $certdata, 0, "")
return $true
}
function ExportPFXFile()
{
if($CommonName.ToLower().StartsWith("cn="))
{
# Remove CN from common name
$CommonName = $CommonName.Substring(3)
}
if($Password -eq $null)
{
$Password = Read-Host -Prompt "Enter Password to protect private key" -AsSecureString
}
$cert = Get-ChildItem -Path Cert:\LocalMachine\my | where-object{$_.Subject -eq "CN=$CommonName"}
Export-PfxCertificate -Cert $cert -Password $Password -FilePath "$($CommonName).pfx"
Export-Certificate -Cert $cert -Type CERT -FilePath "$CommonName.cer"
}
function RemoveCertsFromStore()
{
# Once the certificates have been been exported we can safely remove them from the store
if($CommonName.ToLower().StartsWith("cn="))
{
# Remove CN from common name
$CommonName = $CommonName.Substring(3)
}
$certs = Get-ChildItem -Path Cert:\LocalMachine\my | Where-Object{$_.Subject -eq "CN=$CommonName"}
foreach($c in $certs)
{
remove-item $c.PSPath
}
}
if(CreateSelfSignedCertificate)
{
ExportPFXFile
RemoveCertsFromStore
}
Step 2: Run the Script
- Right-click on the file and select Run with PowerShell.
- You should see 2 files get created:
- <common name>.pfx
- <common name>.cer
NOTEIf you encounter any issues, you can check out Granting access via Azure AD App-Only | Microsoft Learn.
- Copy the location of the folder you’re currently on. You'll need it to run some commands.
Part 4: Connect and Run Command
This part will demonstrate how to connect the generated certificate and run commands:
Step 1: Connect the Certificate to the App
- Go to [1] Certificate & secrets, click [2] Upload certificate, and [3] select the .cer file generated in Part 3:
- You should see the certificate added on the page:
Step 2: Use PowerShell 7 to run a command to allow scripting capabilities
- Enter the following command in the PowerShell 7 window. Remember to replace the URL and Tenant values with your tenant URL and tenant name:
Connect-PnPOnline -ClientId <$application client id as copied over from the AAD app registration above> -CertificatePath '<$path to the PFX file generated by the PowerShell script above>' -CertificatePassword (ConvertTo-SecureString -AsPlainText "<$password assigned to the generated certificate pair above>" -Force) -Url https://<$yourtenant>.sharepoint.com -Tenant "<$tenantname>.onmicrosoft.com”
This is an example of the command with the replaced tenant URL and tenant name:
Connect-PnPOnline -ClientId e9bb531d-09e8-4571-9c3b-ca799df6a568 -CertificatePath 'C:\Desktop Folders\Working On\2024-11-05-Scripting-Capabilities\scripting-capabilities-app-cert.pfx' -CertificatePassword (ConvertTo-SecureString -AsPlainText "qwerasdf" -Force) -Url https://8lvrfv.sharepoint.com -Tenant "8lvrfv.onmicrosoft.com"
- Export a list of all of the sites in the tenant to a .csv file
Get-PnPTenantSite | Select-Object Url, Title, Template, Owner | Export-Csv -Path "C:\Desktop Folders\Working On\2024-11-05-Scripting-Capabilities\all-sites.csv" -NoTypeInformation
- Run the command below to allow the running of scripting capabilities on each site:
$siteUrls = Import-Csv -Path "C:\Desktop Folders\Working On\2024-11-05-Scripting-Capabilities\all-sites.csv"; foreach ($site in $siteUrls) { Write-Host "Running command on site: " $site.Url; Set-PnPTenantSite -Identity $site.Url -DenyAddAndCustomizePages:$false; };
Part 5: Add to Windows Scheduler
This part will show you how to add a .ps1 file to Windows Scheduler:
Step 1: Create a .ps1 file
- Create a .txt file and add the following inside it:
# Connect to the tenant using the certificate:
Connect-PnPOnline -ClientId e9bb531d-09e8-4571-9c3b-ca799df6a568 -CertificatePath 'C:\Desktop Folders\Working On\2024-11-05-Scripting-Capabilities\scripting-capabilities-app-cert.pfx' -CertificatePassword (ConvertTo-SecureString -AsPlainText "qwerasdf" -Force) -Url https://8lvrfv.sharepoint.com -Tenant "8lvrfv.onmicrosoft.com"
# Create a csv file with a list of all of the sites:
Get-PnPTenantSite | Select-Object Url, Title, Template, Owner | Export-Csv -Path "C:\Desktop Folders\Working On\2024-11-05-Scripting-Capabilities\all-sites.csv" -NoTypeInformation
# Run the command to allow scripting capabilities on each of the sites in the csv:
$siteUrls = Import-Csv -Path "C:\Desktop Folders\Working On\2024-11-05-Scripting-Capabilities\all-sites.csv"; foreach ($site in $siteUrls) { Write-Host "Running command on site: " $site.Url; Set-PnPTenantSite -Identity $site.Url -DenyAddAndCustomizePages:$false; };
- Then, rename the file from <filename>.txt to <filename>.ps1
Step 2: Add the .ps1 file to Windows Scheduler
- Open Task Scheduler from the Start Menu.
- In the Task Scheduler, click Create Task in the right-hand Actions pane:
- Click [1] General tab, [2] give your task a name and description, choose [3] Run only when user is logged, and check [4] Run with highest privileges:
- Go to the [1] Triggers tab, click [2] New, set the trigger to [3] Daily & specify the start time:
- Click [1] Repeat taskevery & set it to 8 hours (to run three times a day), and ensure that it [2] Recurs every is 1 days. Finally, click [3] OK:
- Then, set the following Actions:
- Go to the Actions tab
- Click New
- Set the action to Start a program
- In the Program/script field, type
C:\\Program Files\\PowerShell\\7\\pwsh.exe
- In the Add arguments (optional) field, type
-File "C:\\path\\to\\your\\script.ps1
- Click OK.
- Disable all of the options in the Conditions tab:
- Enable the following in the Settings tab:
- Allow tasks to be run on demand;
- Run task as soon as possible after a scheduled start is missed;
- Stop the task if it runs longer than [3] days;
- If the running task does not end when requested, force it to stop.
- Click OK to save the task. You may be prompted to enter your password.
NOTEMake sure to keep the device you did these steps running 24/7 so that the script runs every 8 hours and scripting capabilities remain allowed on your tenant.
Step 3: Check that Custom Script is allowed for all sites
- Copy the URL below:
https://<tenant name>-admin.sharepoint.com/_layouts/15/online/AdminHome.aspx#/siteManagement/view/CUSTOM SCRIPT ENABLED SITES
- Replace <tenant name> with your tenant name.
- In the Custom Script column, all sites must have the word "Allowed":
That's it! You can now schedule the automatic persistence of Scripting Capabilities. Take note that this is only a temporary solution and we still recommend that you transform your Classic page to modern pages to avoid any disruptions.
If you need further assistance with this, don’t hesitate to submit a ticket or send us an email at support@shortpoint.com.
Related articles:
- ShortPoint Microsoft 365 Classic Pages Deprecation: Transforming Classic Pages to Modern Pages
- How to Transform a Classic SharePoint Page into Modern