Download a File From SharePoint Online Using Python

How do you download a file from a SharePoint Online library using Python?

Items needed to run the script in this example:
Install and run a simple Python script.
Office365 Rest Python Client library:
https://pypi.org/project/Office365-REST-Python-Client/
SharePoint App Only Client Id and Secret:
Microsoft documentation:
https://docs.microsoft.com/en-us/sharepoint/dev/solution-guidance/security-apponly-azureacs
You can create an app principle that is limited to a single site, list, library, or a combination of them:
https://piyushksingh.com/2018/12/26/register-app-in-sharepoint/

from office365.runtime.auth.authentication_context import AuthenticationContext
from office365.sharepoint.client_context import ClientContext
from office365.sharepoint.files.file import File

app_settings = {
    'url': 'https://YOURtenant.sharepoint.com/sites/somesite/',
    'client_id': '12344-abcd-efgh-1234-1a2d12a21a2121a',
    'client_secret': 'Oamytacohungry234343224534543=',
}

context_auth = AuthenticationContext(url=app_settings['url'])
context_auth.acquire_token_for_app(client_id=app_settings['client_id'], client_secret=app_settings['client_secret'])

ctx = ClientContext(app_settings['url'], context_auth)
web = ctx.web
ctx.load(web)
ctx.execute_query()

response = File.open_binary(ctx, "/Shared Documents/Invoice.pdf")
with open("./Invoice.pdf", "wb") as local_file:
    local_file.write(response.content)

If the above script does not work, take a step back and make sure you are connected to the site.

from office365.runtime.auth.authentication_context import AuthenticationContext
from office365.sharepoint.client_context import ClientContext
from office365.sharepoint.files.file import File

app_settings = {
    'url': 'https://YOURtenant.sharepoint.com/sites/somesite/',
    'client_id': '12344-abcd-efgh-1234-1a2d12a21a2121a',
    'client_secret': 'Oamytacohungry234343224534543=',
}

context_auth = AuthenticationContext(url=app_settings['url'])
context_auth.acquire_token_for_app(client_id=app_settings['client_id'], client_secret=app_settings['client_secret'])

ctx = ClientContext(app_settings['url'], context_auth)
web = ctx.web
ctx.load(web)
ctx.execute_query()

print("Site title: {0}".format(web.properties['Title']))

Use Flow to Get Files Created or Modified Today in a SharePoint Library

Scenario:
Each day I have a couple of Azure Runbooks export SharePoint list items and upload them to a SharePoint library. If one of the Runbooks fails, I needed to send an email alert that something went wrong.

Basic logic:
If files created today in SharePoint <> X, send an email.

The easy solution would have been to loop through the files, check their created date, increment a variable, then make a condition statement.

More-better way:
Run flow daily at 6:00 PM
Send an HTTP request to SharePoint to get files
Parse the response
Condition statement
— if true, send an email

Uri text from the HTTP call:

_api/search/query?querytext='Path%3Ahttps%3A%2F%2Fsharepointed.sharepoint.com%2Fsites%2Fsitename%2Fsubsite%2Fexports%2F*%20LastModifiedTime%3Dtoday'

Parse JSON schema

{
    "type": "object",
    "properties": {
        "odata.metadata": {
            "type": "string"
        },
        "ElapsedTime": {
            "type": "integer"
        },
        "PrimaryQueryResult": {
            "type": "object",
            "properties": {
                "RelevantResults": {
                    "type": "object",
                    "properties": {
                        "TotalRows": {
                            "type": "integer"
                        },
                        "TotalRowsIncludingDuplicates": {
                            "type": "integer"
                        }
                    }
                }
            }
        }
    }
}

Power BI and SharePoint Person or Group Field

I created a simple Power BI report to pull data from a SharePoint list and quickly ran into a problem with the Person or Group column type.

Error:
Expression.Error: We cannot convert the value “” to type Table.
Details:
Value=
Type=[Type]

In the report, I was trying to expand a Person or Group column, but not all of the field values were populated.

Here is the fix:

let
    Source = SharePoint.Tables("https://taco.sharepoint.com/sites/food", [Implementation="2.0", ViewMode="All"]),
    #"abcc-b8fe-4b23-be01-abc5f2c3320c" = Source{[Id="abcc-b8fe-4b23-be01-abc5f2c3320c"]}[Items],
    #"Expanded Assigned User2" = Table.TransformColumns(#"abcc-b8fe-4b23-be01-abc5f2c3320c", {{"Assigned User", each if Value.Is(_,type list) then _{0} else [title = "not assigned"], type record}} ),
    #"Expanded Assigned Analyst" = Table.ExpandRecordColumn(#"Expanded Assigned User2", "Assigned User", {"title"}, {"Assigned User.title"})
in
    #"Expanded Assigned User"

Get Files From a Folder Using PNP

How do you get all of the files from a folder in SharePoint using PowerShell PNP?

  $devConn = Connect-PnPOnline -Url "https://sharepointed.sharepoint.com/sites/siteA/siteB" -Credentials $userCredential -ReturnConnection

    $folderName = "/Shared Documents/myfolder/anotherfolder"

    $folderItems = Get-PnPFolderItem -FolderSiteRelativeUrl $folderName -Connection $devConn

    foreach($item in $folderItems)
    {
        Write-Host $item.Name
    }

    Write-Host "done"

You could also use a search query with a path filter to get the files, just depends on your needs.

Example of using the Get-PnPListItem cmdlet with the FolderServerRelativeUrl parameter.

$devConn = Connect-PnPOnline -Url "https://sharepointed.sharepoint.com/sites/siteA/siteB" -Credentials $userCredential -ReturnConnection

    $folderName = "/sites/spdev2/bw2/Shared Documents/myfolder/anotherfolder"

    $folderItems = Get-PnPListItem -List "Shared Documents" -FolderServerRelativeUrl $folderName -Connection $devConn 

    foreach($item in $folderItems)
    {
        Write-Host $item
    }
    

Flow Trigger On SharePoint Item Version

How do you run a Flow on a specific version SharePoint item version?

Create a Flow, then navigate into the Settings of the first step. Scroll down to Trigger Conditions and enter the following:

@equals(float(triggerBody()?['{VersionNumber}']),1.0)

Save the Flow and run a test.
The Flow should only process items / documents where the version is equal to 1.0.

Copy Files From Azure File Storage to SharePoint

As of today, there is not a Logic App trigger for Azure File Storage, so I went with a schedule-based approach. Yes, this example leaves out a lot of fine-tuning, but it will get you headed in the right direction.

Create a blank Logic app
Trigger: Schedule
Action: Azure File Storage – List files
Action: SharePoint – Create file

After you add the SharePoint action, the Logic App should automatically add a For Each action and place the SharePoint Create File action inside of it.

Overview of the Logic App
For each action expanded
Testing the Logic App

In the last screenshot, I tested the Logic App by uploading a couple of documents in Azure Storage Explorer, then I manually ran the Logic App (click the Run button).

Again, this is a simple example. The example does not account for processing the same files over and over…

SharePoint Search Query Tool Login

If you have ever worked with SharePoint search you likely already know about the SharePoint Search Query Tool. If you are new to SharePoint and need a little insight into the SharePoint search experience this tool is a lifesaver!

SharePoint Query Tool GitHub: https://github.com/pnp/PnP-Tools/

In future posts, I will outline how to form queries and use the tool but for now, I want to simply connect to my SharePoint Online site.

Enter the URL for your SharePoint site, select the Authentication options shown above, then click Sign-In. If a web login form appears be sure to complete it. If your normal Windows login doesn’t work, try using your work email address and password, and if that doesn’t work try your work email address and App Password.

App Passwords are created and managed at this URL: https://account.activedirectory.windowsazure.com/AppPasswords.aspx

Power Automate Bad Gateway Error

I was trying to use a SQL Insert Row action to insert a new row in a SQL Server table and received a Bad Gateway error. First, I thought it was a permissions issue, then I thought my Flow stopped working…

Turned out to be an issue with the amount of data being inserted into a field. One SQL column was set to varchar(X) and the Flow was trying to insert more characters than X.

Flow Power Automate and SharePoint Required Fields

On the surface, this request sounded super simple and straightforward. “we need to copy files from a SharePoint library to Blob storage.” Simple enough? Well, yes, but the SharePoint library has a couple of required fields and a Flow is triggered by an action.

Consider what I’m outlining below to be version ONE of the process. In the near future, I will update this post with a slightly more resilient solution.

My SharePoint library has a required field titled DesinationFolder

Context of what I’m doing in the Flow:
Trigger: When files is created in a folder
When a file is added to a library the flow is triggered
Get file metadata
File Identifier: Use File identifier from the step above
Get file properties
Id: Use the ItemId from the previous step
Initialize variable
Name: vCheckedOut
Type: Boolean
Value: Checked out (field from Get properties)
Initialize variable
Name: vFolderPath
Type: String
Value:
Condition
vCheckedOut is equal to true
Yes:
Do until
vCheckout is equal to False
GetFileProperties
Set variable
Name: vCheckedOut
Value: Checked out (value from the Get file properties above)
No:
Set variable
Name: vFolderPath
Value: FolderPath (SharePoint field)

Compose
/blobfolder/vFolderPath (variable)
Create blob