With the newest MSGraph module one has the capability to get SharePoint files with MSGraph. I recently figured out, how to fetch them in a recursed manner. In this article I want to share with you how to get SharePoint files with MSGraph. You will need to get the files with MSGraph, if you are thinking about to do following things:
- Read/ Write/ Delete Metadata of SharePoint Files
- Obtain DriveItem IDs, if you want to upload files to specific folders
- Download specific SharePoint files
- Assess the storage of your SharePoint libraries
Table of Contents
What do you need to get SharePoint Files with MSGraph
You need to fulfil two requirements, so that you can get SharePoint files with MSGraph recursedly.
- You need to configure an Azure App registration with read permission to the SharePoint sites, where you want to obtain the files from. If you have never done this, follow my article, where I explain how to configure your Azure App registration for MSGraph access.
How to configure Azure App registration for MS Graph | SPO Scripts - Install the MSGraph module for PowerShell
Install the Microsoft Graph PowerShell SDK | Microsoft Learn
Demo Setup
In my demo setup I have a SharePoint Library, where I have stored some files and folders. I am showcasing you, so that you can understand what you can expect from the solution. I have also some files in a folder, which will show that the solution is able to fetch folder items.
I have created an Azure App registration with the Sites Read All permission. The authentication will be done with a self signed certificate.
How to Get all SharePoint Files with MSGraph in PowerShell (recursively)
Below you can find the PowerShell script to get all SharePoint files. I have created the function List-MgDriveItem in order to list the drive items of a drive. A drive item is either a file or a folder within a SharePoint Library You can adjust the function, if you want to have different attributes.
function List-MgDriveItem { [CmdletBinding()] param ( [Parameter()] $Drive, [Parameter()] $DriveItem ) Try { if ($DriveItem.folder) { # Recurse in the folder to get the childitems of the folder $ChildItems = (Get-MgDriveItem -DriveId $Drive.Id -DriveItemId $DriveItem.Id -ExpandProperty Children ).Children if ($ChildItems.Count -gt 0) { <# Action to perform if the condition is true #> $ChildItems | ForEach-Object { List-MgDriveItem -Drive $Drive -DriveItem (Get-MgDriveItem -DriveId $Drive.Id -DriveItemId $($_.Id) ) } } } $Result = New-Object psobject -Property @{ DriveItemName = $DriveItem.name; DriveitemSize = $DriveItem.Size } return $Result } catch { Return $Error[0] } }
A sample output of a folder driveitem looks like this:
PS C:\Users\Serka\OneDrive\Desktop\PS> $driveitem | Select-Object * webUrl : https://m365x04995906.sharepoint.com/sites/Remoteliving/Shared%20Documents/General id : 01NLC4VWP4YR6WIO6O6JFIFTARZGEQZMAL createdBy : {[user, System.Collections.Hashtable], [application, System.Collections.Hashtable]} lastModifiedBy : {[user, System.Collections.Hashtable], [application, System.Collections.Hashtable]} lastModifiedDateTime : 31.07.2023 12:17:50 name : General folder : {[childCount, 3]} size : 4505145 fileSystemInfo : {[lastModifiedDateTime, 31.07.2023 12:17:50], [createdDateTime, 31.07.2023 12:17:50]} createdDateTime : 31.07.2023 12:17:50 parentReference : {[id, 01NLC4VWN6Y2GOVW7725BZO354PWSELRRZ], [path, /drives/b!kJV0CniHeUeAiju7m8Gl4ZmfCOoRAXJNrYB9wjbkfZ-Vmuw3EELGQ7bZlNIfSaf4/root:], [driveType, documentLibrary], [driveId, b!kJV0CniHeUeAiju7m8Gl4ZmfCOoRAXJNrYB9wjbkfZ-Vmuw3EELGQ7bZlNIfSaf4]…} eTag : "{647DC4FC-CE3B-4AF2-82CC-11C9890CB00B},2" cTag : "c:{647DC4FC-CE3B-4AF2-82CC-11C9890CB00B},0" shared : {[scope, users]}
A sample output of a file driveitem looks like this:
PS C:\Users\Serka\OneDrive\Desktop\PS> $driveitem | select-object * |Format-list createdDateTime : 19.08.2023 20:56:39 cTag : "c:{6C722880-DCC4-45F4-B64C-96805B32D473},2" lastModifiedBy : {[user, System.Collections.Hashtable]} @microsoft.graph.downloadUrl : https://m365x04995906.sharepoint.com/sites/Remoteliving/_layouts/15/download.aspx?UniqueId=6c722880-dcc4-45f4-b64c-96805b32d473&Translate=false&tempauth=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiIwMDAwMDAwMy0wMDAwLTBmZjEtY2UwMC0wMDAwMDAwMDAwMDAvbTM2NXgwNDk5NTkwNi5zaGFyZXBvaW50LmNvbUAxZjc5NWU5NS1jMDZiLTQxMDktOTI0ZS0zNTY5ZmRkZjQ5OWYiLCJpc3MiOiIwMDAwMDAwMy0wMDAwLTBmZjEtY2UwMC0wMDAwMDAwMDAwMDAiLCJuYmYiOiIxNjk0OTc0NTMzIiwiZXhwIjoiMTY5NDk3ODEzMyIsImVuZHBvaW50dXJsIjoib0dEUzI3bnFpOEtUSHd5NHRaQ1NYVzE1Mk1KVGFMVkpZZmh0VUhBTVUrUT0iLCJlbmRwb2ludHVybExlbmd0aCI6IjE0MyIsImlzbG9vcGJhY2siOiJUcnVlIiwiY2lkIjoiVWxYbUJaczF1MHU4d3ZpSTFwTGhudz09IiwidmVyIjoiaGFzaGVkcHJvb2Z0b2tlbiIsInNpdGVpZCI6Ik1HRTNORGsxT1RBdE9EYzNPQzAwTnpjNUxUZ3dPR0V0TTJKaVlqbGlZekZoTldVeCIsImFwcF9kaXNwbGF5bmFtZSI6IlNQX1NlbnNpdGl2aXR5X0xhYmVscyIsIm5hbWVpZCI6IjkwNzQ3OTI1LTU1MGMtNDY1OC04NTBmLWIxOWQyNmVkMWE0M0AxZjc5NWU5NS1jMDZiLTQxMDktOTI0ZS0zNTY5ZmRkZjQ5OWYiLCJyb2xlcyI6ImFsbHNpdGVzLndyaXRlIiwidHQiOiIxIiwiaXBhZGRyIjoiMjAuMTkwLjE5MC4xMDMifQ.knKrUliPCxeMF4NQ2-3_FSAkEYRBD5nlTOvAVurT_gQ&ApiVersion=2.0 file : {[mimeType, image/png], [hashes, System.Collections.Hashtable]} photo : {} name : 2023-06-25 00_18_51-Alfahosting.de® • Meine Rechnungen and 2 more pages - Personal - Microsoft Edge.png fileSystemInfo : {[lastModifiedDateTime, 19.08.2023 20:56:39], [createdDateTime, 19.08.2023 20:56:39]} id : 01NLC4VWMAFBZGZRG46RC3MTEWQBNTFVDT shared : {[scope, users]} image : {[width, 868], [height, 406]} createdBy : {[user, System.Collections.Hashtable]} size : 23175 eTag : "{6C722880-DCC4-45F4-B64C-96805B32D473},1" lastModifiedDateTime : 19.08.2023 20:56:39 webUrl : https://m365x04995906.sharepoint.com/sites/Remoteliving/Shared%20Documents/2023-06-25%2000_18_51-Alfahosting.de%C2%AE%20%E2%80%A2%20Meine%20Rechnungen%20and%202%20more%20pages%20-%20Personal%20-%20Microsoft%E2%80%8B%20Edge.png parentReference : {[id, 01NLC4VWN6Y2GOVW7725BZO354PWSELRRZ], [path, /drives/b!kJV0CniHeUeAiju7m8Gl4ZmfCOoRAXJNrYB9wjbkfZ-Vmuw3EELGQ7bZlNIfSaf4/root:], [driveType, documentLibrary], [driveId, b!kJV0CniHeUeAiju7m8Gl4ZmfCOoRAXJNrYB9wjbkfZ-Vmuw3EELGQ7bZlNIfSaf4]…}
Here you can find the PowerShell script to get all SharePoint files with MSGraph. Keep in mind that you replace the param block with the values from your tenant, app etc.
Param ( $AppID = "90747925-550c-4658-850f-b19d26ed1a43", # Replace with the App ID of your App registration $Tenant = "1f795e95-c06b-4109-924e-3569fddf499f", # Replace with the Tenant ID $SiteID = "0a749590-8778-4779-808a-3bbb9bc1a5e1", # Replace it with the SiteID of your SharePoint Site https://m365x04995906.sharepoint.com/sites/Remoteliving/_api/site/id $LibraryName = "Documents", # Replace with the list name, $CertificatePath = "C:\Users\Serka\OneDrive\Desktop\PS\SPSitesReadAll.pfx", # Replace with the path to your certificate, $CertificatePassword = "XXX" # Replace with the password of your certificate ) function List-MgDriveItem { [CmdletBinding()] param ( [Parameter()] $Drive, [Parameter()] $DriveItem ) if ($DriveItem.folder) { <# Action to perform if the condition is true #> Write-Output "Folder $($DriveItem.Name), size $($DriveItem.Size) `n" # Recurse in the folder to get the childitems of the folder $ChildItems = $null $ChildItems = (Get-MgDriveItem -DriveId $Drive.id -DriveItemId $DriveItem.id -ExpandProperty Children ).Children if ($ChildItems.Count -gt 0) { <# Action to perform if the condition is true #> $ChildItems | ForEach-Object { List-MgDriveItem -Drive $Drive -DriveItem (Get-MgDriveItem -DriveId $Drive.ID -DriveItemId $($_.Id) ) } } } elseif ($null -ne $DriveItem.file) { <# Action when this condition is true #> Write-Output "File $($DriveItem.Name), size $($DriveItem.Size) `n" } } #region prerequistes Import-Module microsoft.graph.authentication # Load the certificate from file $Certificate = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($CertificatePath, $CertificatePassword) # Authenticate Connect-MgGraph -ClientID $AppID -TenantId $Tenant -CertificateThumbprint $Certificate.Thumbprint #endregion #region main # Get drive $Drive = Get-MgSite -SiteId $SiteID -Property Drives -ExpandProperty Drives | Select-Object Drives -ExpandProperty Drives | Where-Object { $_.Name -eq $LibraryName } # Get drive item $DriveItems = Invoke-MgGraphRequest -Uri "v1.0/drives/$($Drive.ID)/root/children" foreach ($DriveItem in $DriveItems.Value) { #Get All drivitems below root List-MgDriveItem -Drive $Drive -DriveItem $DriveItem } # #endregion
As you can see below, the script populates the space ocupation for each SharePoint file/ folder.
How to get DriveItemIDs for SharePoint Files?
I have modified the script, so that you can get all driveItemIDs for all SharePoint Files in your library. Below you can find the script with certificate based authentication.
Param ( $AppId = "90747925-550c-4658-850f-b19d26ed1a43", # Replace with the App Id of your App registration $Tenant = "1f795e95-c06b-4109-924e-3569fddf499f", # Replace with the Tenant prefix $SiteId = "0a749590-8778-4779-808a-3bbb9bc1a5e1", # Replace it with the SiteId of your SharePoint Site https://m365x04995906.sharepoint.com/sites/Remoteliving/_api/site/Id $LibraryName = "Documents", # Replace with the list name, $CertificatePath = "C:\Users\Serka\OneDrive\Desktop\PS\SPSitesReadAll.pfx", # Replace with the path to your certificate, $CertificatePasswordPath = "C:\Users\Serka\OneDrive\Desktop\PS\SPSitesReadAll.key" # Replace with the path to the password of your certificate, ) function List-MgDriveItem { [CmdletBinding()] param ( [Parameter()] $Drive, [Parameter()] $DriveItem ) Try { if ($DriveItem.folder) { # Recurse in the folder to get the childitems of the folder $ChildItems = (Get-MgDriveItem -DriveId $Drive.Id -DriveItemId $DriveItem.Id -ExpandProperty Children ).Children if ($ChildItems.Count -gt 0) { <# Action to perform if the condition is true #> $ChildItems | ForEach-Object { List-MgDriveItem -Drive $Drive -DriveItem (Get-MgDriveItem -DriveId $Drive.Id -DriveItemId $($_.Id) ) } } } $Result = New-Object psobject -Property @{ DriveItemName = $DriveItem.name; DriveitemId = $DriveItem.Id; DriveId = $Drive.Id; DriveItemURL = $DriveItem.webUrl } return $Result } catch { Return $Error[0] } } # Load required Modules Import-Module Microsoft.Graph.Authentication, Microsoft.Graph.Files # Load the certificate from file $CertificatePassword = (Import-Clixml -Path $CertificatePasswordPath).getnetworkcredential().Password $Certificate = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($CertificatePath, $CertificatePassword) # Authenticate Connect-MgGraph -ClientId $AppId -TenantId $Tenant -CertificateThumbprint $Certificate.Thumbprint -NoWelcome #region prepare export # Get drive $Drive = Get-MgSite -SiteId $SiteId -Property Drives -ExpandProperty Drives | Select-Object Drives -ExpandProperty Drives | Where-Object { $_.Name -eq $LibraryName } # Get drive item $DriveItems = Invoke-MgGraphRequest -Uri "v1.0/drives/$($Drive.Id)/root/children" $ItemExportRaw = New-Object System.Collections.Generic.List[object] foreach ($DriveItem in $DriveItems.Value) { #Get All drivitems below root $ItemExportRaw.Add( $(List-MgDriveItem -Drive $Drive -DriveItem $DriveItem)) } $ItemExport = New-Object System.Collections.Generic.List[object] $ItemExportRaw |ForEach-Object { $_ | ForEach-Object {$ItemExport.add($_)} } $ItemExport #endregion
If you want to use app secrets instead of certificate based authentication, you can use following script
Param ( $AppId = "13b20636-5165-402e-aedc-5e05eeb4a57f", # Replace with the App Id of your App registration $Tenant = "b7b0953d-d866-4606-9199-7642f06a0b2e", # Replace with the Tenant prefix $SiteId = "2dfd508f-98ab-46ad-839b-f0435730c79a", # Replace it with the SiteId of your SharePoint Site https://m365x04995906.sharepoint.com/sites/Remoteliving/_api/site/Id $LibraryName = "Documenten" # Replace with the list name, ) function List-MgDriveItem { [CmdletBinding()] param ( [Parameter()] $Drive, [Parameter()] $DriveItem ) Try { if ($DriveItem.folder) { # Recurse in the folder to get the childitems of the folder $ChildItems = (Get-MgDriveItem -DriveId $Drive.Id -DriveItemId $DriveItem.Id -ExpandProperty Children ).Children if ($ChildItems.Count -gt 0) { <# Action to perform if the condition is true #> $ChildItems | ForEach-Object { List-MgDriveItem -Drive $Drive -DriveItem (Get-MgDriveItem -DriveId $Drive.Id -DriveItemId $($_.Id) ) } } } $Result = New-Object psobject -Property @{ DriveItemName = $DriveItem.name; DriveitemId = $DriveItem.Id; DriveId = $Drive.Id; DriveItemURL = $DriveItem.webUrl } return $Result } catch { Return $Error[0] } } # Load required Modules Import-Module Microsoft.Graph.Authentication, Microsoft.Graph.Files # Complie Client Credential $ClientSecretCredential = Get-Credential($AppID) # Authenticate Connect-MgGraph -TenantId $Tenant -ClientSecretCredential $ClientSecretCredential -NoWelcome #region prepare export # Get drive $Drive = Get-MgSite -SiteId $SiteId -Property Drives -ExpandProperty Drives | Select-Object Drives -ExpandProperty Drives | Where-Object { $_.Name -eq $LibraryName } # Get drive item $DriveItems = Invoke-MgGraphRequest -Uri "v1.0/drives/$($Drive.Id)/root/children" $ItemExportRaw = New-Object System.Collections.Generic.List[object] foreach ($DriveItem in $DriveItems.Value) { #Get All drivitems below root $ItemExportRaw.Add( $(List-MgDriveItem -Drive $Drive -DriveItem $DriveItem)) } $ItemExport = New-Object System.Collections.Generic.List[object] $ItemExportRaw |ForEach-Object { $_ | ForEach-Object {$ItemExport.add($_)} } $ItemExport #endregion
Once the script is exectued, all driveitems are shown like this:
Further Reference
Here you can obtain the permission levels, which are required for your Azure App Registration:
Microsoft Graph permissions reference – Microsoft Graph | Microsoft Learn
Here you can find the cmdlet map for MS Graph module
Find Azure AD and MSOnline cmdlets in Microsoft Graph PowerShell | Microsoft Learn
Hi, I have updated the article, so that you can also authenticate via App secret.
How can you connect with client id and secret using the same scripts? On 1 tutorial you use the client id and the other one a certificate 🙁
Pingback: Assign Sensitivity Labels in SharePoint PowerShell Graph API