You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SharePoint列表克隆PowerShell脚本执行报错排查求助

SharePoint Online列表克隆脚本「Item does not exist」报错修复

需求说明

  • 将源SharePoint列表克隆至目标列表
  • 若目标列表已存在,克隆前先删除
  • 克隆源列表的结构及所有条目,包含人员、元数据及查找项(若有)

原脚本代码

param(
    [Parameter(Mandatory=$true)] [string] $SourceListName,
    [Parameter(Mandatory=$true)] [string] $DestinationListName,
    [Parameter(Mandatory=$true)] [string] $User,
    [Parameter(Mandatory=$true)] [string] $Password,
    [Parameter(Mandatory=$false)] [string] $SiteURL = "https://mygroupgroup.sharepoint.com/sites/my-app",
    [Parameter(Mandatory=$false)] [bool] $ForceExisting = $false,
    [Parameter(Mandatory=$false)] [string] $CSOMPath = "C:\proj\myproj.import\Microsoft.SharePointOnline.CSOM.16.1.23912.12000\lib\net45"
)

# Convert the password to a SecureString
$SecurePassword = ConvertTo-SecureString $Password -AsPlainText -Force

# Load SharePoint CSOM Assemblies
Add-Type -Path "$CSOMPath\Microsoft.SharePoint.Client.dll"
Add-Type -Path "$CSOMPath\Microsoft.SharePoint.Client.Runtime.dll"

# Setup Credentials to connect
$Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($User, $SecurePassword)

# Setup the context
$Ctx = New-Object Microsoft.SharePoint.Client.ClientContext($SiteURL)
$Ctx.Credentials = $Credentials

Write-Host "Debug: Context set up."

# Declare the list of fields to ignore
$AllFieldsToIgnore = @("ID", "Attachments", "GUID", "Created", "Modified", "Author", "Editor", "_Level", "_IsCurrentVersion", "_UIVersion", "_UIVersionString", "WorkflowVersion", "owshiddenversion", "_ModerationStatus", "InstanceID", "Order", "WorkflowInstanceID", "FileRef", "FileDirRef", "Last_x0020_Modified", "Created_x0020_Date", "FSObjType", "SortBehavior", "FileLeafRef", "UniqueId", "ParentUniqueId", "SyncClientId", "ProgId", "ScopeId", "MetaInfo")

# Check if destination list already exists
$Lists = $Ctx.Web.Lists
$Ctx.Load($Lists)
$Ctx.ExecuteQuery()

Write-Host "Debug: Loaded existing lists."

$ExistingList = $Lists | Where-Object { $_.Title -eq $DestinationListName }

if ($ExistingList) {
    Write-Host "Debug: Existing list found."
    if ($ForceExisting) {
        $ExistingList.DeleteObject()
        $Ctx.ExecuteQuery()
        Write-Host "Debug: Existing list deleted."
    } else {
        $UserConfirmation = Read-Host "The list '$DestinationListName' already exists. Do you want to overwrite it? (y/n)"
        if ($UserConfirmation -eq 'y') {
            $ExistingList.DeleteObject()
            $Ctx.ExecuteQuery()
        } else {
            Write-Host "Operation cancelled."
            return
        }
    }
}

# Get the source list
try {
    $SourceList = $Ctx.Web.Lists.GetByTitle($SourceListName)
    $Ctx.Load($SourceList)
    $Ctx.ExecuteQuery()
    Write-Host "Debug: Source list loaded."
} catch {
    Write-Host "Error: Could not load source list."
    return
}

# Create the destination list
$ListInfo = New-Object Microsoft.SharePoint.Client.ListCreationInformation
$ListInfo.Title = $DestinationListName
$ListInfo.TemplateType = $SourceList.BaseTemplate
$DestinationList = $Ctx.Web.Lists.Add($ListInfo)
$Ctx.ExecuteQuery()

# Get items from the source list
$Query = New-Object Microsoft.SharePoint.Client.CamlQuery
$SourceItems = $SourceList.GetItems($Query)
$Ctx.Load($SourceItems)
$Ctx.ExecuteQuery()

# Copy items to the destination list
foreach ($Item in $SourceItems) {
    $NewItemInfo = New-Object Microsoft.SharePoint.Client.ListItemCreationInformation
    $NewItem = $DestinationList.AddItem($NewItemInfo)
    $Ctx.Load($NewItem)
    $Ctx.ExecuteQuery()

    foreach ($Field in $Item.FieldValues.Keys) {
        # Skip system fields
        if ($AllFieldsToIgnore -notcontains $Field) {
            # Check for null values
            if ($null -ne $Item[$Field]) {
                # Detect field type and handle accordingly
                $FieldType = $Item[$Field].GetType().Name
                switch ($FieldType) {
                    "FieldLookupValue" {
                        $LookupValue = New-Object Microsoft.SharePoint.Client.FieldLookupValue
                        $LookupValue.LookupId = $Item[$Field].LookupId
                        $NewItem[$Field] = $LookupValue
                    }
                    "FieldUserValue" {
                        $UserValue = New-Object Microsoft.SharePoint.Client.FieldUserValue
                        $UserValue.LookupId = $Item[$Field].LookupId
                        $NewItem[$Field] = $UserValue
                    }
                    "TaxonomyFieldValue" {
                        $TaxonomyValue = New-Object Microsoft.SharePoint.Client.TaxonomyFieldValue
                        $TaxonomyValue.Label = $Item[$Field].Label
                        $TaxonomyValue.TermGuid = $Item[$Field].TermGuid
                        $NewItem[$Field] = $TaxonomyValue
                    }
                    default {
                        $NewItem[$Field] = $Item[$Field]
                    }
                }
            }
        }
    }

    $NewItem.Update()
    $Ctx.ExecuteQuery()
}

# Output success message
Write-Host "List and items cloned successfully!"

执行报错信息

PS C:\proj\myproj.import\ps-scripts> .\clone-list.ps1 -SourceListName "source-contacts" -DestinationListName "ClonedDestContacts" -User "admin@mygroup.net" -ForceExisting $true -Password "mypassword"
Debug: Context set up.
Debug: Loaded existing lists.
Debug: Existing list found.
Debug: Existing list deleted.
Debug: Source list loaded.
Exception calling "ExecuteQuery" with "0" argument(s): "Item does not exist. It may have been deleted by another user."
At C:\proj\base-myproj.import\ps-scripts\clone-list.ps1:121 char:5
+     $Ctx.ExecuteQuery()
+     ~~~~~~~~~~~~~~~~~~~
CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
FullyQualifiedErrorId : ServerException

Exception calling "ExecuteQuery" with "0" argument(s): "Item does not exist. It may have been deleted by another user."
At C:\proj\base-myproj.import\ps-scripts\clone-list.ps1:121 char:5
+     $Ctx.ExecuteQuery()
+     ~~~~~~~~~~~~~~~~~~~
CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
FullyQualifiedErrorId : ServerException

Exception calling "ExecuteQuery" with "0" argument(s): "Item does not exist. It may have been deleted by another user."
At C:\proj\base-myproj.import\ps-scripts\clone-list.ps1:121 char:5
+     $Ctx.ExecuteQuery()
+     ~~~~~~~~~~~~~~~~~~~
CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
FullyQualifiedErrorId : ServerException

问题分析

报错的核心原因是在创建新ListItem后立即执行$Ctx.Load($NewItem)和$Ctx.ExecuteQuery():

  • 使用AddItem()方法返回的ListItem对象仅存在于本地上下文,尚未提交到SharePoint服务器
  • 此时执行Load操作,服务器上还没有该Item的记录,因此抛出「Item does not exist」异常

另外,创建目标列表后,上下文里的DestinationList对象字段信息不完整,可能导致后续设置字段时出现隐性问题,需要补充加载列表字段。

修复后的脚本

param(
    [Parameter(Mandatory=$true)] [string] $SourceListName,
    [Parameter(Mandatory=$true)] [string] $DestinationListName,
    [Parameter(Mandatory=$true)] [string] $User,
    [Parameter(Mandatory=$true)] [string] $Password,
    [Parameter(Mandatory=$false)] [string] $SiteURL = "https://mygroupgroup.sharepoint.com/sites/my-app",
    [Parameter(Mandatory=$false)] [bool] $ForceExisting = $false,
    [Parameter(Mandatory=$false)] [string] $CSOMPath = "C:\proj\myproj.import\Microsoft.SharePointOnline.CSOM.16.1.23912.12000\lib\net45"
)

# Convert the password to a SecureString
$SecurePassword = ConvertTo-SecureString $Password -AsPlainText -Force

# Load SharePoint CSOM Assemblies
Add-Type -Path "$CSOMPath\Microsoft.SharePoint.Client.dll"
Add-Type -Path "$CSOMPath\Microsoft.SharePoint.Client.Runtime.dll"

# Setup Credentials to connect
$Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($User, $SecurePassword)

# Setup the context
$Ctx = New-Object Microsoft.SharePoint.Client.ClientContext($SiteURL)
$Ctx.Credentials = $Credentials

Write-Host "Debug: Context set up."

# Declare the list of fields to ignore
$AllFieldsToIgnore = @("ID", "Attachments", "GUID", "Created", "Modified", "Author", "Editor", "_Level", "_IsCurrentVersion", "_UIVersion", "_UIVersionString", "WorkflowVersion", "owshiddenversion", "_ModerationStatus", "InstanceID", "Order", "WorkflowInstanceID", "FileRef", "FileDirRef", "Last_x0020_Modified", "Created_x0020_Date", "FSObjType", "SortBehavior", "FileLeafRef", "UniqueId", "ParentUniqueId", "SyncClientId", "ProgId", "ScopeId", "MetaInfo")

# Check if destination list already exists
$Lists = $Ctx.Web.Lists
$Ctx.Load($Lists)
$Ctx.ExecuteQuery()

Write-Host "Debug: Loaded existing lists."

$ExistingList = $Lists | Where-Object { $_.Title -eq $DestinationListName }

if ($ExistingList) {
    Write-Host "Debug: Existing list found."
    if ($ForceExisting) {
        $ExistingList.DeleteObject()
        $Ctx.ExecuteQuery()
        Write-Host "Debug: Existing list deleted."
    } else {
        $UserConfirmation = Read-Host "The list '$DestinationListName' already exists. Do you want to overwrite it? (y/n)"
        if ($UserConfirmation -eq 'y') {
            $ExistingList.DeleteObject()
            $Ctx.ExecuteQuery()
        } else {
            Write-Host "Operation cancelled."
            return
        }
    }
}

# Get the source list
try {
    $SourceList = $Ctx.Web.Lists.GetByTitle($SourceListName)
    $Ctx.Load($SourceList)
    $Ctx.Load($SourceList.Fields)
    $Ctx.ExecuteQuery()
    Write-Host "Debug: Source list loaded with fields."
} catch {
    Write-Host "Error: Could not load source list."
    return
}

# Create the destination list
$ListInfo = New-Object Microsoft.SharePoint.Client.ListCreationInformation
$ListInfo.Title = $DestinationListName
$ListInfo.TemplateType = $SourceList.BaseTemplate
$DestinationList = $Ctx.Web.Lists.Add($ListInfo)
$Ctx.ExecuteQuery()

# Reload destination list with fields to ensure context has latest metadata
$DestinationList = $Ctx.Web.Lists.GetByTitle($DestinationListName)
$Ctx.Load($DestinationList)
$Ctx.Load($DestinationList.Fields)
$Ctx.ExecuteQuery()
Write-Host "Debug: Destination list created and loaded with fields."

# Get items from the source list
$Query = New-Object Microsoft.SharePoint.Client.CamlQuery
$SourceItems = $SourceList.GetItems($Query)
$Ctx.Load($SourceItems)
$Ctx.ExecuteQuery()
Write-Host "Debug: Loaded $($SourceItems.Count) source items."

# Copy items to the destination list
foreach ($Item in $SourceItems) {
    $NewItemInfo = New-Object Microsoft.SharePoint.Client.ListItemCreationInformation
    $NewItem = $DestinationList.AddItem($NewItemInfo)

    foreach ($Field in $Item.FieldValues.Keys) {
        # Skip system fields
        if ($AllFieldsToIgnore -notcontains $Field) {
            # Check for null values
            if ($null -ne $Item[$Field]) {
                # Detect field type and handle accordingly
                $FieldType = $Item[$Field].GetType().Name
                switch ($FieldType) {
                    "FieldLookupValue" {
                        $LookupValue = New-Object Microsoft.SharePoint.Client.FieldLookupValue
                        $LookupValue.LookupId = $Item[$Field].LookupId
                        $NewItem[$Field] = $LookupValue
                    }
                    "FieldUserValue" {
                        $UserValue = New-Object Microsoft.SharePoint.Client.FieldUserValue
                        $UserValue.LookupId = $Item[$Field].LookupId
                        $NewItem[$Field] = $UserValue
                    }
                    "TaxonomyFieldValue" {
                        $TaxonomyValue = New-Object Microsoft.SharePoint.Client.TaxonomyFieldValue
                        $TaxonomyValue.Label = $Item[$Field].Label
                        $TaxonomyValue.TermGuid = $Item[$Field].TermGuid
                        $NewItem[$Field] = $TaxonomyValue
                    }
                    default {
                        $NewItem[$Field] = $Item[$Field]
                    }
                }
            }
        }
    }

    $NewItem.Update()
    $Ctx.ExecuteQuery()
    Write-Host "Debug: Copied item ID $($Item.Id) successfully."
}

# Output success message
Write-Host "List and items cloned successfully!"

关键修复点

  1. 移除了$Ctx.Load($NewItem)和对应的$Ctx.ExecuteQuery():创建ListItem后直接设置字段,调用Update()再提交到服务器即可,无需提前Load
  2. 添加了列表字段的加载逻辑:创建目标列表后重新加载列表及其字段,确保上下文拥有完整的列表元数据,避免字段映射错误
  3. 增加了调试输出:显示复制的Item ID,便于跟踪进度

内容的提问来源于stack exchange,提问作者serge

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 18:07:02