SharePoint App-Only is the older, but still very relevant, model of setting up app-principals. This model works for both SharePoint Online and SharePoint 2013/2016 on-premises and is ideal to prepare your applications for migration from SharePoint on-premises to SharePoint Online.
I am not familiar with Python3 but you can use the below code sample in your code as it uses REST API.
Please refer the following articles and let me know if you have any questions
SharePoint App-Only - https://sprider.blog/spol-download-file-from-library-using-sharepoint-app-only-access-and-powershell
Graph API - https://sprider.blog/download-sharepoint-file-using-microsoft-graph-api
How to get Tenant ID - https://sprider.blog/get-office-365-tenant-id-from-domain-name
Tenant Name - abc as per your code example.
Client Id and Secret can be retrived from SharePoint or Azure AD App Registration
###### Global Static Variables - Start ######
$grantType = "client_credentials"
$principal = "00000003-0000-0ff1-ce00-000000000000"
###### Global Static Variables - End ######
###### Global Tenant Specific Variables - Start ######
$m365TenantId = "yourtenantguid"
$targetHost = "yourtenantname.sharepoint.com"
$appClientId = "clientid-from-previous-section"
$appClientSecret = "clientsecret-from-previous-section"
###### Global Tenant Specific Variables - End ######
###### Site/File Path Variables - Start ######
$targetFolder = $PSScriptRoot
$siteRelativeUrl = "sites/yoursite"
$folderRelativeUrl = "your-document-library-name"
$fileName = "your-file-name.png"
###### Site/File Path Variables - Start ######
###### Helper Functions - Start ######
function Add-Working-Directory([string]$workingDir, [string]$logDir) {
if (!(Test-Path -Path $workingDir)) {
try {
$suppressOutput = New-Item -ItemType Directory -Path $workingDir -Force -ErrorAction Stop
$msg = "SUCCESS: Folder '$($workingDir)' for CSV files has been created."
Write-Host -ForegroundColor Green $msg
}
catch {
$msg = "ERROR: Failed to create '$($workingDir)'. Script will abort."
Write-Host -ForegroundColor Red $msg
Exit
}
}
if (!(Test-Path -Path $logDir)) {
try {
$suppressOutput = New-Item -ItemType Directory -Path $logDir -Force -ErrorAction Stop
$msg = "SUCCESS: Folder '$($logDir)' for log files has been created."
Write-Host -ForegroundColor Green $msg
}
catch {
$msg = "ERROR: Failed to create log directory '$($logDir)'. Script will abort."
Write-Host -ForegroundColor Red $msg
Exit
}
}
}
function Add-Log([string]$message, [string]$logFile) {
$lineItem = "[$(Get-Date -Format "dd-MMM-yyyy HH:mm:ss") | PID:$($pid) | $($env:username) ] " + $message
Add-Content -Path $logFile $lineItem
}
function Get-AccessToken {
try {
$message = "Getting Accesstoken..."
Add-Log $message $Global:logFile
$tokenEndPoint = "https://accounts.accesscontrol.windows.net/$m365TenantId/tokens/oauth/2"
$client_Id = "$appClientId@$m365TenantId"
$resource = "$principal/$targetHost@$m365TenantId"
$requestHeaders = @{
"Content-Type" = "application/x-www-form-urlencoded"
}
$requestBody = @{
client_id = $client_Id
client_secret = $appClientSecret
grant_type = $grantType
resource = $resource
}
$response = Invoke-RestMethod -Method 'Post' -Uri $tokenEndPoint -Headers $requestHeaders -Body $requestBody
$accesstoken = $response.access_token
$message = "Accesstoken received."
Add-Log $message $Global:logFile
return $accesstoken
}
catch {
$statusCode = $_.Exception.Response.StatusCode.value__
$statusDescription = $_.Exception.Response.StatusDescription
$message = "StatusCode: $statusCode"
Add-Log $message $Global:logFile
$message = "StatusDescription : $statusDescription"
Add-Log $message $Global:logFile
return $null
}
}
function Download-File([string]$fileUrl, [string]$targetFilePath) {
$accessToken = Get-AccessToken
if (![string]::IsNullOrEmpty($accessToken)) {
try {
$fileUri = New-Object System.Uri($fileUrl)
$wc = New-Object System.Net.WebClient
$wc.Headers.Add("Authorization", "Bearer $accessToken")
$job = $wc.DownloadFileTaskAsync($fileUri, $targetFilePath)
$message = "Downloading file $fileUrl at $targetFilePath."
Add-Log $message $Global:logFile
while (!$job.IsCompleted) {
sleep 1
}
if ($job.Status -ne "RanToCompletion") {
$message = "Failed to download file."
Add-Log $message $Global:logFile
}
else {
$message = "File downloaded."
Add-Log $message $Global:logFile
}
}
catch {
$statusCode = $_.Exception.Response.StatusCode.value__
$statusDescription = $_.Exception.Response.StatusDescription
$message = "StatusCode: $statusCode"
Add-Log $message $Global:logFile
$message = "StatusDescription : $statusDescription"
Add-Log $message $Global:logFile
$message = "Failed to download file."
Add-Log $message $Global:logFile
}
}
else {
$message = "Unable to get Accesstoken."
Add-Log $message $Global:logFile
}
}
###### Helper Functions - End ######
###### Main Program - Start ######
###### Log Setup - Start ######
$currentDirectoryPath = Split-Path -Parent $MyInvocation.MyCommand.Definition
$workingDirectory = $currentDirectoryPath
$logDirectoryName = "Logs"
$logDirectory = "$workingDirectory/$logDirectoryName"
$logFileName = "$(Get-Date -Format "yyyyMMddTHHmmss")_downloadjobexecution.log"
$Global:logFile = "$logDirectory/$logFileName"
Add-Working-Directory $workingDirectory $logDirectory
###### Log Setup - Start ######
Write-Host -ForegroundColor Yellow "WARNING: Minimal output will appear on the screen."
Write-Host -ForegroundColor Yellow " Please look at the log file '$($logFile)'"
$message = "**************************************** SCRIPT STARTED ****************************************"
Add-Log $message $Global:logFile
###### Download File - Start ######
$targetFilePath = Join-Path $targetFolder $fileName
$fileUrl = "https://$targetHost/$siteRelativeUrl/_api/Web/GetFolderByServerRelativeUrl('$folderRelativeUrl')/Files('$fileName')/`$value"
Download-File $fileUrl $targetFilePath
###### Download File - End ######
$message = "**************************************** SCRIPT COMPLETED ****************************************"
Add-Log $message $Global:logFile
###### Main Program - End ######