cli-microsoft365 icon indicating copy to clipboard operation
cli-microsoft365 copied to clipboard

New sample script: Download attachments from a SharePoint Online list

Open plamber opened this issue 3 years ago • 11 comments

Docs
Author Ruud
Original Post https://www.sharepointdiary.com/2017/01/sharepoint-online-download-attachments-from-list-using-powershell.html
Description Download attachments from a SharePoint Online list.
Keywords Migration

plamber avatar Aug 31 '21 03:08 plamber

Hi @plamber / @waldekmastykarz, Could you please assign this to me?

sprider avatar Sep 25 '21 16:09 sprider

Thank you. All yours

plamber avatar Sep 25 '21 23:09 plamber

@plamber / @waldekmastykarz, As discussed in #2661, we don't have AttachmentFiles property currently so I created with M365 CLI and classic API to complete this script as shown below:

Are you okay with this plan or I have to wait until AttachmentFiles property is avilable?

Function Get-ListAttachments() {
    param
    (
        [Parameter(Mandatory = $true)] [string] $AccessToken,
        [Parameter(Mandatory = $true)] [string] $SiteURL,
        [Parameter(Mandatory = $true)] [string] $ListTitle,
        [Parameter(Mandatory = $true)] [int] $ItemId
    )   
    Try {
        $ListItemAttachmentsEndPoint = "$($SiteURL)/_api/web/lists/getbytitle('$($ListTitle)')/items($($ItemId))/AttachmentFiles"
        $Header = @{
            "Authorization" = "Bearer $($AccessToken)"
            "Accept"        = "application/json; odata=verbose" 
            "Content-Type"  = "application/json "
        }
        $ListItemAttachments = Invoke-RestMethod -Uri $ListItemAttachmentsEndPoint -Headers $Header -Method Get  
        return $ListItemAttachments.d.results
    }
    Catch {
        write-host -f Red "Error Getting List Item Attachments!" $_.Exception.Message
    }
}
Function Download-ListAttachments() {
    param
    (
        [Parameter(Mandatory = $true)] [string] $TenantName,
        [Parameter(Mandatory = $true)] [string] $SiteURL,
        [Parameter(Mandatory = $true)] [string] $ListTitle,
        [Parameter(Mandatory = $true)] [string] $DownloadDirectory
    )   
    Try {
 
        #Get All Items from the List
        $ListItems = m365 spo listitem list --webUrl $SiteURL --title $ListTitle -o json | ConvertFrom-Json -AsHashtable
         
        #Create download directory if it doesn't exist
        If (!(Test-Path -path $DownloadDirectory)) {           
            New-Item $DownloadDirectory -type directory         
        }
         
        #Iterate through each list item
        Foreach ($Item in $ListItems) {
            $AccessToken = m365 util accesstoken get --resource "https://$($TenantName).sharepoint.com" --new 

            #Get All attachments from the List Item
            $Attachments = Get-ListAttachments -AccessToken $AccessToken -SiteURL $SiteURL -ListTitle $ListTitle -ItemId $Item.Id
            foreach ($Attachment in $Attachments) {
                $TargetFilePath = "$($DownloadDirectory)/$($Item.Id)_$($Attachment.FileName)"
                #Download attachment
                m365 spo file get --webUrl $SiteURL --url $Attachment.ServerRelativeUrl --asFile --path $TargetFilePath
            }
        }
 
        write-host  -f Green "List Attachments Downloaded Successfully!"
    }
    Catch {
        write-host -f Red "Error Downloading List Attachments!" $_.Exception.Message
    }
}

#Set Parameters
$TenantName = "spridermvp"
$SiteRelativePath = "sites/dev"
$ListTitle = "SPOL Download"
$DownloadDirectory = $PSScriptRoot

$SiteURL = "https://$($TenantName).sharepoint.com/$($SiteRelativePath)"

#Call the function to copy list items
Download-ListAttachments -TenantName $TenantName -SiteURL $SiteURL -ListTitle $ListTitle -DownloadDirectory $DownloadDirectory

sprider avatar Sep 29 '21 16:09 sprider

We should check #2661. I will create some issues for it and come back to you

plamber avatar Sep 29 '21 16:09 plamber

Hi @sprider, First of all. Thank you for your efforts. These are highly appreciated.

I created an issue for the m365 spo listitem attachment list command (#2730). We should use that one for the example we are referencing here.

On the other hand, I like your approach of solving the issue by calling directly the REST API of SharePoint and using the CLI to retrieve the required tokens. I think this should become a sample by its own. @waldekmastykarz: what do you think about this? I would reuse the sample of @sprider and give it a different title: "How to call the SharePoint REST API using the CLI". What do you think?

Cheers

plamber avatar Sep 30 '21 14:09 plamber

Hi @sprider,

First of all. Thank you for your efforts. These are highly appreciated.

I created an issue for the m365 spo listitem attachment list command (#2730). We should use that one for the example we are referencing here.

On the other hand, I like your approach of solving the issue by calling directly the REST API of SharePoint and using the CLI to retrieve the required tokens. I think this should become a sample by its own. @waldekmastykarz: what do you think about this? I would reuse the sample of @sprider and give it a different title: "How to call the SharePoint REST API using the CLI". What do you think?

Cheers

Perfect, Thank you @plamber

sprider avatar Sep 30 '21 15:09 sprider

Hi @sprider, First of all. Thank you for your efforts. These are highly appreciated.

I created an issue for the m365 spo listitem attachment list command (#2730). We should use that one for the example we are referencing here.

On the other hand, I like your approach of solving the issue by calling directly the REST API of SharePoint and using the CLI to retrieve the required tokens. I think this should become a sample by its own. @waldekmastykarz: what do you think about this? I would reuse the sample of @sprider and give it a different title: "How to call the SharePoint REST API using the CLI". What do you think?

Cheers

I think there is a room for both: from the functional point of view, we'd preferably want to have a dedicated command. That said, there might always be the case when you want to do something that's not covered by the CLI, so showing how to get an access token is also valuable.

waldekmastykarz avatar Oct 01 '21 13:10 waldekmastykarz

Hi, just created the issue #2731 and assigned @sprider to it. We should take your example and explain that you can still use the CLI to simplify the creation of scripts that are not yet covered by the CLI. This might be a good sample.

Thank you, Patrick

plamber avatar Oct 01 '21 13:10 plamber

As #2730 has been implemented it looks like we can now progress this sample script.

@sprider are you happy to continue working on this?

garrytrinder avatar Jul 01 '22 21:07 garrytrinder

@garrytrinder Thank you for checking with me. Unfortunately, I am currently a bit busy and may be unable to take this issue. Could you please keep this open so that someone can pick up this?

sprider avatar Jul 02 '22 20:07 sprider

No problem, thank you for the reply 👍🏻

Opening up

garrytrinder avatar Jul 03 '22 20:07 garrytrinder

I can attempt to work on the sample.

reshmee011 avatar Feb 07 '23 11:02 reshmee011

Great to hear @reshmee011!

milanholemans avatar Feb 07 '23 11:02 milanholemans

@milanholemans : where do I add the sample script? I have amended the sample code provided by @sprider to use the m365 cli to get the attachments

param ( [Parameter(Mandatory = $true)] [string] $SiteURL, [Parameter(Mandatory = $true)] [string] $ListTitle, [Parameter(Mandatory = $true)] [string] $DownloadDirectory )

$m365Status = m365 status if ($m365Status -match "Logged Out") { Write-Host "Logging in the User!" m365 login --authType browser }

Try {

    #Get All Items from the List
    $ListItems = m365 spo listitem list --webUrl $SiteURL --listTitle $ListTitle | ConvertFrom-Json
     
    #Create download directory if it doesn't exist
    If (!(Test-Path -path $DownloadDirectory)) {           
        New-Item $DownloadDirectory -type directory         
    }
     
    #Iterate through each list item
    Foreach ($Item in $ListItems) {

        #Get All attachments from the List Item
        $Attachments = m365 spo listitem attachment list --webUrl $SiteURL --listTitle $ListTitle --itemId $Item.Id | ConvertFrom-Json
        foreach ($Attachment in $Attachments) {
            $TargetFilePath = "$($DownloadDirectory)/$($Item.Id)_$($Attachment.FileName)"
            #Download attachment
            m365 spo file get --webUrl $SiteURL --url $Attachment.ServerRelativeUrl --asFile --path $TargetFilePath
        }
    }

    write-host  -f Green "List Attachments Downloaded Successfully!"
}
Catch {
    write-host -f Red "Error Downloading List Attachments!" $_.Exception.Message
}

reshmee011 avatar Feb 12 '23 21:02 reshmee011

Hi @reshmee011, great to hear! You can add the script under ./docs/sample-scripts/spo. Make sure that you don't forget to add the assets/sample.json file.

milanholemans avatar Feb 12 '23 21:02 milanholemans