DEV Community

Kinga
Kinga

Posted on • Edited on

3

Azure Functions, PnP PowerShell, Managed Identity and SharePoint Online

EDIT 2002.11.13: What a time to be alive! 🙃 Since version 1.11.95-nightly, Managed Identities are both supported against SharePoint Online as well as Microsoft Graph cmdlets. 🎉 🥳 🎊

Decide how you want to authenticate in your Azure Function: By using a Managed Identity

Most of this blog post is still valid. In the profile.ps1 however, simply use Connect-PnPOnline -ManagedIdentity from now on.

If you followed Using PnP PowerShell in Azure Functions and now try to connect to your SPO site using

Connect-PnPOnline -ManagedIdentity
Enter fullscreen mode Exit fullscreen mode

you will get The current connection holds no SharePoint context.

Access token

You can still use the managed identity though. You just need additional step, to connect to Azure services in app code:

profile.ps1

$resourceURI ="https://<yourtenant>.sharepoint.com"
$siteUrl="https://<yourtenant>.sharepoint.com/sites/<yoursite>"

if ($env:MSI_SECRET) {
    $tokenAuthURI = $env:MSI_ENDPOINT + "?resource=$resourceURI&api-version=2017-09-01"
    $tokenResponse = Invoke-RestMethod -Method Get -Headers @{"Secret" = "$env:MSI_SECRET" } -Uri $tokenAuthURI
    $accessToken = $tokenResponse.access_token

    Connect-PnPOnline -Url  $siteUrl -AccessToken $accessToken
    #Invoke Get-PnPSite to test
}
Enter fullscreen mode Exit fullscreen mode

The $env:MSI_SECRET and $env:IDENTITY_HEADER return the same values. And so do $env:MSI_ENDPOINT and $env:IDENTITY_ENDPOINT.

run.ps1

$listTitle = "<yourlistname>"
try{
    $connection = Get-PnPConnection
    $list = Get-PnPList  -Identity $listTitle -Connection $connection
    $item = Add-PnPListItem -List $list -Values @{"Title" = "item 4" }  -Connection $connection
    Write-Host "Item created"
}
catch{
    Write-Host "ERROR CREATING ITEM"
    Get-Error
}
Enter fullscreen mode Exit fullscreen mode

Minimum required permissions

And since I believe in assigning minimum required permissions, the managed identity has only Sites.Selected API permissions for Graph API and SPO.

Setup.ps1

function Set-AzureADPermissions_SitesSelected {
    param(
        $tenantId,
        $appDisplayName
    )
    Connect-AzureAD -TenantId $tenantId

    $GraphAppId = "00000003-0000-0000-c000-000000000000"  # Microsoft Graph
    $SPOAppId = "00000003-0000-0ff1-ce00-000000000000" # SharePoint Online

    #Retrieve the Azure AD Service Principal instance for the Microsoft Graph (00000003-0000-0000-c000-000000000000) or SharePoint Online (00000003-0000-0ff1-ce00-000000000000).
    $servicePrincipal_Graph = Get-AzureADServicePrincipal -Filter "appId eq '$GraphAppId'"
    $servicePrincipal_SPO = Get-AzureADServicePrincipal -Filter "appId eq '$SPOAppId'"
    $permissionName = "Sites.Selected"

    $SPN = Get-AzADServicePrincipal -Filter "displayName eq '$appDisplayName'"
    Start-Sleep -Seconds 10

    # Use application permissions. Delegate permissions cannot be utilized using a Managed Identity.
    # $servicePrincipal_Graph.AppRole | Where-Object { $_.AllowedMemberType -eq "Application" -and $_.Value -eq "Sites.Selected"}

    $appRole_Graph = $servicePrincipal_Graph.AppRoles | Where-Object { $_.AllowedMemberTypes -eq "Application" -and $_.Value -eq $permissionName }
    $appRole_SPO = $servicePrincipal_SPO.AppRoles | Where-Object { $_.AllowedMemberTypes -eq "Application" -and $_.Value -eq $permissionName }

    # Grant API Permissions
    New-AzureAdServiceAppRoleAssignment -ObjectId $SPN.Id -PrincipalId $SPN.Id -ResourceId $servicePrincipal_Graph.ObjectId -Id $appRole_Graph.Id
    New-AzureAdServiceAppRoleAssignment -ObjectId $SPN.Id -PrincipalId $SPN.Id -ResourceId $servicePrincipal_SPO.ObjectId -Id $appRole_SPO.Id

    # Write-Host "Now grant access to SPO site using the following:"
    # Write-Host "App Id: $($SPN.AppId)"
    # Write-Host "App Name: $($SPN.DisplayName)"

    return $SPN.AppId
}
function Set-PnPSiteAccess{
    param(
        $siteUrl,
        $appId,
        $appName,
        $permission

    )
    Connect-PnPOnline -Url $siteUrl -Interactive
    Grant-PnPAzureADAppSitePermission -AppId $appId -DisplayName $appName -Site $siteUrl -Permissions $permission
}

$appId= Set-APIPermissions -tenantId $tenantId -appDisplayName $appName
Set-PnPSiteAccess -siteUrl $siteUrl -appId $appId -appName $appName -permission Write
Enter fullscreen mode Exit fullscreen mode

Image of Timescale

🚀 pgai Vectorizer: SQLAlchemy and LiteLLM Make Vector Search Simple

We built pgai Vectorizer to simplify embedding management for AI applications—without needing a separate database or complex infrastructure. Since launch, developers have created over 3,000 vectorizers on Timescale Cloud, with many more self-hosted.

Read more

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay