SharePoint Online: Default New, Edit, and Display List Forms are missing
Summary
In SharePoint Online (SPO), the default new item, edit item, and display item forms for a SharePoint list may be missing, blank, deleted, or null. This can cause a number of symptoms, such as the following:
- When trying to create list items the following error occurs:
yourDomain.sharepoint.com redirected you too many times.
ERR_TOO_MANY_REDIRECTS - The link created by the “Copy Link” feature does not work.
- The list-level search feature does not return any results.
- When trying to create a new item in a list:
Unable to find the default new form for list (listName) - When trying to edit an existing item in the list:
Unable to find the default edit form for list (listName) - When trying to view an existing item in the list:
Unable to find the default display form for list (listName)
Cause
This can happen if the default new item form (NewForm.aspx), edit form (EditForm.aspx), or display form (dispform.aspx) have been deleted. Admins can do this mistakenly using PowerShell or SharePoint Designer, or sometimes it can occur as part of a site migration. This results in a missing / blank / empty / null default form values for the list.
You can verify this problem for your list by using REST.
Call the Lists REST API for the problem list to return the default form values by entering a sting like the following in a browser. For example, list name “SP1”:
https://contoso.sharepoint.com/sites/Team2/_api/web/lists/getbytitle('SP1')?$select=ID,DefaultDisplayFormUrl,DefaultEditFormUrl,DefaultNewFormUrl
In this example, DefaultDisplayFormUrl, DefaultEditFormUrl, and DefaultNewFormUrl are all Null:

They should be set to DispForm.aspx, EditForm.aspx, and NewForm.aspx, respectively. For comparison, here’s a “good” list named “L7”.

Resolution
To resolve this issue, the default forms for the problem list must be recreated. This can be done with a PowerShell script.
Enable Custom Script for the Site
In order to create new forms in a list or library (which is what the “Create-DefaultListForms-Interactive.ps1” PowerShell script does), Custom Script must be enabled for the site, which means the DenyAddAndCustomizePages site property must be set to 0.
Example:
# Set Parameters
$AdminSiteURL="https://contoso-admin.sharepoint.com/"
$SiteURL="https://contoso.sharepoint.com/sites/Team2"
# Connect to SharePoint Online Admin Center
Connect-SPOService -Url $AdminSiteURL
# Enable Custom Script
Set-SPOSite -Identity $SiteURL -DenyAddAndCustomizePages 0
Important! Failure to complete this step will result in an Access Denied error when you run the “Create-DefaultListForms-Interactive.ps1” script, even for a site collection administrator.
Run the Create-DefaultListForms-Interactive.ps1 Script
The following “Create-DefaultListForms-Interactive.ps1” script is an updated version of the script found at Create-DefaultListForms.ps1. It has been enhanced to allow the use of an Entra ID application registration (ClientID) to connect to the SharePoint site, and to allows you to supply a single site URL and list name to fix a single list.
The script can either take a single site URL and list name (-SiteURL and -ListName parameters), or if you use the -CSVPath parameter, it can fix multiple sites and lists at a time. It does that by reading the site URL and list name from a CSV file. You can find a sample CSV here: Sample CSV, or just create your own. It should look something like this:

Create-DefaultListForms-Interactive.ps1
### Create-DefaultListForms-Interactive.ps1 ###
<#
Microsoft provides programming examples for illustration only, without warranty either expressed or
implied, including, but not limited to, the implied warranties of merchantability and/or fitness
for a particular purpose. We grant You a nonexclusive, royalty-free right to use and modify the
Sample Code and to reproduce and distribute the object code form of the Sample Code, provided that
You agree: (i) to not use Our name, logo, or trademarks to market Your software product in which the
Sample Code is embedded; (ii) to include a valid copyright notice on Your software product in which
the Sample Code is embedded; and (iii) to indemnify, hold harmless, and defend Us and Our suppliers
from and against any claims or lawsuits, including attorneys' fees, that arise or result from the
use or distribution of the Sample Code.
This sample assumes that you are familiar with the programming language being demonstrated and the
tools used to create and debug procedures. Microsoft support professionals can help explain the
functionality of a particular procedure, but they will not modify these examples to provide added
functionality or construct procedures to meet your specific needs. if you have limited programming
experience, you may want to contact a Microsoft Certified Partner or the Microsoft fee-based consulting
line at (800) 936-5200.
#>
<#
.SYNOPSIS
Script to create default list forms (New, Edit, Display) if they are missing.
Will also re-add missing Form Webpart to existing list forms if they are missing.
.DESCRIPTION
Script to create default list forms (New, Edit, Display) if they are missing.
Will also re-add missing Form Webpart to existing list forms if they are missing.
Supply SiteURL and ListName to process a single list, or CSVPath to process multiple lists.
These input modes cannot be combined. If neither mode is specified, prompts for
SiteURL and ListName. There is no default CSV path.
CSV must have siteUrl and listTitle columns with nonblank values in each row.
Tested with List Templates: 100, 101, 102, 103, 104, 105, 106, 107, 108
Requires PowerShell 7 compatible with the installed PnP.PowerShell module.
If PnP.PowerShell is missing, the script will attempt to install it.
Connections always use interactive authentication with the specified client ID.
The client ID must identify an Entra ID application configured for PnP interactive
authentication with appropriate SharePoint delegated permissions and consent.
.PARAMETER CSVPath
Specify an explicit path to a CSV file containing siteUrl and listTitle fields.
Cannot be combined with SiteURL or ListName.
.PARAMETER SiteURL
Site URL for a single list. Required with ListName when CSVPath is not supplied.
Prompts for this value if omitted in single-list mode.
.PARAMETER ListName
List name to process at SiteURL. Required with SiteURL when CSVPath is not supplied.
Prompts for this value if omitted in single-list mode.
.PARAMETER ClientId
Required Entra ID application client ID used for interactive authentication.
You must supply your own client ID; there is no default value.
.EXAMPLE
.\Create-DefaultListForms-Interactive.ps1 -ClientId "00000000-0000-0000-0000-000000000001"
Prompts for SiteURL and ListName, then creates list forms using interactive login.
.EXAMPLE
.\Create-DefaultListForms-Interactive.ps1 -CSVPath C:\temp\targetlists.csv -ClientId "00000000-0000-0000-0000-000000000001"
Creates list forms for rows in the specified CSV using interactive login and your supplied client ID.
.EXAMPLE
.\Create-DefaultListForms-Interactive.ps1 -SiteURL "https://contoso.sharepoint.com/sites/team" -ListName "Tasks" -ClientId "00000000-0000-0000-0000-000000000001"
Creates list forms for the Tasks list at the specified site using interactive login.
#>
[CmdletBinding(DefaultParameterSetName="SingleList")]
param(
[parameter(Mandatory=$true, ParameterSetName="CSV")]
[ValidateNotNullOrEmpty()]
[string]$CSVPath,
[parameter(Mandatory=$true, ParameterSetName="SingleList")]
[ValidateNotNullOrEmpty()]
[ValidatePattern('\S')]
[string]$SiteURL,
[parameter(Mandatory=$true, ParameterSetName="SingleList")]
[ValidateNotNullOrEmpty()]
[ValidatePattern('\S')]
[string]$ListName,
[parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[guid]$ClientId
)
#############################################
if ($PSCmdlet.ParameterSetName -eq "SingleList") {
$targets = @([pscustomobject]@{
siteUrl = $SiteURL
listTitle = $ListName
})
}
else {
$targets = @(Import-Csv -LiteralPath $CSVPath -ErrorAction Stop)
if ($targets.Count -eq 0) {
throw "CSV at path '$CSVPath' must contain at least one row with siteUrl and listTitle columns."
}
for ($index = 0; $index -lt $targets.Count; $index++) {
if ([string]::IsNullOrWhiteSpace($targets[$index].siteUrl) -or
[string]::IsNullOrWhiteSpace($targets[$index].listTitle)) {
throw "CSV at path '$CSVPath' has missing or blank siteUrl or listTitle values in data row $($index + 1)."
}
}
}
#############################################
$module = Get-Module PnP.PowerShell -ListAvailable
if ($null -eq $module) {
Write-Output "Installing PowerShell Module: PnP.PowerShell"
Install-Module PnP.PowerShell -Force -AllowClobber -Confirm:$false -ErrorAction Stop
}
Import-Module PnP.PowerShell -ErrorAction Stop
#############################################
$webpartTemplate = @"
<WebPart xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/WebPart/v2">
<Assembly>Microsoft.SharePoint, Version=16.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c</Assembly>
<TypeName>Microsoft.SharePoint.WebPartPages.ListFormWebPart</TypeName>
<ListName xmlns="http://schemas.microsoft.com/WebPart/v2/ListForm">{{{LIST_ID}}}</ListName>
<ListId xmlns="http://schemas.microsoft.com/WebPart/v2/ListForm">{{LIST_ID}}</ListId>
<PageType xmlns="http://schemas.microsoft.com/WebPart/v2/ListForm">{{PAGE_TYPE}}</PageType>
<FormType xmlns="http://schemas.microsoft.com/WebPart/v2/ListForm">{{FORM_TYPE}}</FormType>
<ControlMode xmlns="http://schemas.microsoft.com/WebPart/v2/ListForm">{{CONTROL_MODE}}</ControlMode>
<ViewFlag xmlns="http://schemas.microsoft.com/WebPart/v2/ListForm">1048576</ViewFlag>
<ViewFlags xmlns="http://schemas.microsoft.com/WebPart/v2/ListForm">Default</ViewFlags>
<ListItemId xmlns="http://schemas.microsoft.com/WebPart/v2/ListForm">0</ListItemId>
</WebPart>
"@
Function Create-DefaultListForm
{
param(
[parameter(Mandatory=$true)]$List,
[parameter(Mandatory=$true)][string]$FormUrl,
[parameter(Mandatory=$true)][ValidateSet("Display", "Edit", "New")]$FormType
)
begin { }
process
{
$webpartXml = $webpartTemplate -replace "{{LIST_ID}}", $List.Id.ToString()
switch ($FormType)
{
"Display" {
$webpartXml = $webpartXml -replace "{{PAGE_TYPE}}", "PAGE_DISPLAYFORM"
$webpartXml = $webpartXml -replace "{{FORM_TYPE}}", "4"
$webpartXml = $webpartXml -replace "{{CONTROL_MODE}}", "Display"
break;
}
"Edit" {
$webpartXml = $webpartXml -replace "{{PAGE_TYPE}}", "PAGE_EDITFORM"
$webpartXml = $webpartXml -replace "{{FORM_TYPE}}", "6"
$webpartXml = $webpartXml -replace "{{CONTROL_MODE}}", "Edit"
break;
}
"New" {
$webpartXml = $webpartXml -replace "{{PAGE_TYPE}}", "PAGE_NEWFORM"
$webpartXml = $webpartXml -replace "{{FORM_TYPE}}", "8"
$webpartXml = $webpartXml -replace "{{CONTROL_MODE}}", "New"
break;
}
}
try
{
#Check if form page already exists
$listPages = Get-PnPProperty -ClientObject $List.RootFolder -Property Files
$formPage = $listPages | Where-Object { $_.ServerRelativeUrl.ToLower() -eq $FormUrl.ToLower() }
if ($null -eq $formPage) {
Write-Output " [Creating Form Page] $FormUrl"
#Create Form
$formPage = $List.RootFolder.Files.AddTemplateFile($FormUrl, [Microsoft.SharePoint.Client.TemplateFileType]::FormPage)
}
else {
#Form page exists, check if form is recognized by list (i.e. form page has a form webpart on it)
$listForms = Get-PnPProperty -ClientObject $List -Property Forms
if ($null -ne $listForms -and $listForms.Count -gt 0) {
$existingForm = $list.Forms | Where-Object { $_.ServerRelativeUrl.ToLower() -eq $FormUrl.ToLower() }
if ($null -ne $existingForm) {
Write-Warning " [Form Already Exists] $FormUrl"
return;
}
}
}
Write-Output " [Adding Form Webpart] $FormUrl"
#Get Webpart Manager for Form
$wpm = $formPage.GetLimitedWebPartManager([Microsoft.SharePoint.Client.WebParts.PersonalizationScope]::Shared)
#Import Webpart on page
$wp = $wpm.ImportWebPart($webpartXml)
#Add webpart to Form
$wpm.AddWebPart($wp.WebPart, "Main", 1) | Out-Null
#Execute changes
$List.Context.ExecuteQuery()
}
catch
{
Write-Error "Error creating form $FormType at $FormUrl. Error: $($_.Exception)"
}
}
end { }
}
#############################################
foreach ($row in $targets)
{
Write-Output "[$($row.siteUrl)] [$($row.listTitle)]"
Connect-PnPOnline -Url $row.siteUrl -Interactive -ClientId $ClientId.ToString() -ErrorAction Stop
$list = Get-PnPList $row.listTitle
$listUrl = $list.RootFolder.ServerRelativeUrl
# Handle Document Library Types
if ($list.BaseType -eq [Microsoft.SharePoint.Client.BaseType]::DocumentLibrary) {
Write-Host " > Processing Library: $listUrl"
Create-DefaultListForm -List $list -FormUrl "$listUrl/Forms/Upload.aspx" -FormType New
Create-DefaultListForm -List $list -FormUrl "$listUrl/Forms/DispForm.aspx" -FormType Display
Create-DefaultListForm -List $list -FormUrl "$listUrl/Forms/EditForm.aspx" -FormType Edit
}
# Handle Generic List Types
else {
Write-Host " > Processing List: $listUrl"
Create-DefaultListForm -List $list -FormUrl "$listUrl/NewForm.aspx" -FormType New
Create-DefaultListForm -List $list -FormUrl "$listUrl/DispForm.aspx" -FormType Display
Create-DefaultListForm -List $list -FormUrl "$listUrl/EditForm.aspx" -FormType Edit
}
}