Batch delete sharepoint list items with Graph API & Powershell

Xav 1 Reputation point
2022-10-10T12:00:06.783+00:00

Hi,

I try to delete in batch with Graph and Powershell all the items present in a Sharepoint list (+/- 3000 items).
I get the following error when I run the following script: "Id property cannot be empty".

Thanks for your help !

Script :

Connect-MgGraph -TenantId $TenantId  
      
$startTime = Get-Date  
  
$data = Invoke-MgGraphRequest -Uri "https://graph.microsoft.com/v1.0/Sites/$($SiteId)/lists/$($ListId)/items?expand=fields"  
  
$results = @()  
  
$results += $data.Value.Id  
  
$pages = $data.'@odata.nextLink'  
  
while($null -ne $pages) {  
  
$additional = Invoke-MgGraphRequest -Uri $pages  
  
If($pages) {  
$pages = $additional.'@odata.nextLink'  
}  
  
$results += $additional.Value.Id  
}  
  
$listItems = $results | ConvertFrom-Csv -Header "Id"  
   
$totalItems = $listItems.Count  
$i = 0  
$iTotal = 0  
$batchSize = 20  
   
$requests = @()  
$header = @{ "Content-Type" = "application/json" }  
   
foreach ($listItem in $listItems) {  
    $i++  
    $iTotal++  
      
    $listItemId = $listItem.Id  
  
    $body = @{  
        fields = @{  
            ID =  $listItemId;  
        }  
    }  
       
    #build POST request for the current item and add to $requests array  
    $request = @{  
        method  = "Delete"  
        url     = "/Sites/$siteId/Lists/$listId/Items/$listItemId"  
        body    = $body  
        headers = $header  
    }  
   
    $requests += $request  
      
   
    #if batch (array) contains specified number of items or if it's the last item from CSV  
    if ($i -eq $batchSize -or $iTotal -eq $totalItems) {  
       
        $batchRequests = @{  
            requests = $requests  
        }  
           
        #IMPORTANT: use -Deph parameter  
        $batchBody = $batchRequests | ConvertTo-Json -Depth 4  
   
        #send batch request  
        $batchRequest = Invoke-MgGraphRequest -Method POST -Uri 'https://graph.microsoft.com/v1.0/$batch' -ContentType "application/json" -Body $batchBody  
    
        #reset batch item counter and requests array  
        $i = 0  
        $requests = @()  
    }  
}  
   
$endTime = Get-Date  
$totalTime = $endTime - $startTime  
   
write-host "Total script run time: $($totalTime.Hours) hours, $($totalTime.Minutes) minutes, $($totalTime.Seconds) seconds" -ForegroundColor Cyan  
Microsoft Security Microsoft Graph
0 comments No comments
{count} votes

2 answers

Sort by: Most helpful
  1. CarlZhao-MSFT 46,371 Reputation points
    2022-10-11T10:19:41.097+00:00

    Hi @Xav

    Would you mind using the c# graph sdk? I don't do much research on powershell script, I use c# code to batch delete all items of a specific list of a specific site and it works fine. refer to:

    using Azure.Identity;   
    using Microsoft.Graph;  
      
    var scopes = new[] { "https://graph.microsoft.com/.default" };  
      
    var tenantId = "tenant id";  
      
    // Values from app registration  
    var clientId = "client id";  
    var clientSecret = "client secret";  
      
    // using Azure.Identity;  
    var options = new TokenCredentialOptions  
    {  
        AuthorityHost = AzureAuthorityHosts.AzurePublicCloud  
    };  
      
    // https://learn.microsoft.com/dotnet/api/azure.identity.clientsecretcredential  
    var clientSecretCredential = new ClientSecretCredential(  
        tenantId, clientId, clientSecret, options);  
      
    var graphClient = new GraphServiceClient(clientSecretCredential, scopes);  
      
    var items = await graphClient.Sites["site id"].Lists["list id"].Items  
        .Request()  
        .GetAsync();  
      
    for (int i = 0; i < items.Count; i++)  
    {      
        var ids = items[i].Id.ToString();      
    
        await graphClient.Sites["site id"].Lists["list id"].Items[ids]  
        .Request()  
        .DeleteAsync();  
    }  
    

    If the answer is helpful, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    1 person found this answer helpful.
    0 comments No comments

  2. Xav 1 Reputation point
    2022-10-11T16:20:06.433+00:00

    Hi @CarlZhao-MSFT

    It is the Microsoft Graph Powershell SDK.
    I finally managed to correct my mistakes based on another script I found here
    Thanks anyway for your script!

    Connect-MgGraph -ClientId $ClientId -TenantId $TenantId -CertificateThumbprint $CertificateThumbprint  
      
    $startTime = Get-Date  
      
    $data = Invoke-MgGraphRequest -Uri "https://graph.microsoft.com/v1.0/Sites/$($SiteId)/lists/$($ListId)/items?expand=fields"  
      
    $results = @()  
      
    $results += $data.Value.Id  
      
    $pages = $data.'@odata.nextLink'  
      
    while($null -ne $pages) {  
      
    $additional = Invoke-MgGraphRequest -Uri $pages  
      
    If($pages) {  
    $pages = $additional.'@odata.nextLink'  
    }  
    $results += $additional.Value.Id  
    }  
      
    $listItems = $results | ConvertFrom-Csv -Header "Id"  
       
    $totalItems = $listItems.Count  
    $i = 0  
    $iTotal = 0  
    $batchSize = 20  
       
    $requests = @()  
    $header = @{ "Content-Type" = "application/json"  
                 "If-Match" = "*" }  
        
       for($i=$totalItems-1;$i -ge 0;$i--)  
        {  
              $itemId = $listItems[$i].Id   
                $request = @{  
                  id      = $i  
                  method  = "DELETE"  
                  url     = "/sites/$siteID/lists/$listID/items/$itemId"  
                  headers = $header  
                  }            
                $requests += $request   
           if($requests.count -eq $batchSize -or $requests.count -eq $totalItems)  
           {   
              $batchRequests = @{  
              requests = $requests  
           }  
               
            #IMPORTANT: use -Deph parameter  
            $batchBody = $batchRequests | ConvertTo-Json -Depth 4  
            #send batch request  
            $response = Invoke-MgGraphRequest -Method Post -Uri 'https://graph.microsoft.com/v1.0/$batch' -ContentType "application/json" -Body $batchBody  
             #$StatusCode = $Response.StatusCode  
             
             #write-host $("$StatusCode response for deleting 20")  
             #reset batch item counter and requests array  
             $requests = @()  
             $totalItems = $totalItems - $batchSize  
            }  
          }  
       
    $endTime = Get-Date  
    $totalTime = $endTime - $startTime  
       
    write-host "Total script run time: $($totalTime.Hours) hours, $($totalTime.Minutes) minutes, $($totalTime.Seconds) seconds" -ForegroundColor Cyan  
    

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.