Execute PnP PowerShell with Azure DevOps Pipeline

Azure DevOps promotes collaboration between development and operation to faster and more reliable software delivery. 

In this article, I am going to demonstrate, How to automate & execute the PnP PowerShell using Azure DevOps Pipeline. Let's get started with the below steps.



Create Azure DevOps Repository

  • Navigate to https://dev.azure.com and log in with your valid credentials.
  • Select the Organization & Navigate to Repo to create a new repository. (Note, we can use the existing repository also).
  • Create a repository with the name PNP Powershell and click save.
  • Once it's saved, Created Repository and README.md file will appear as per the below screenshots.
Configure the YAML pipeline 
  • Select the Pipeline from the left-hand side and then select the Azure Repos Git i.e. (free private Git Repositories).


  • Select the respective created repository (as we created earlier with the name PNPPowershell). 



  • The YAML file will get generated with the below sample code.

The YAML file will get generated with the below sample code.



Create & Upload the PnP PowerShell

PnP PowerShell Code snippet to display the Site Title & credentials is parameterized. It is always a best practice to store the credentials as managed identity or user library group, which exists under pipeline sections. 

param (

[Parameter()]

[string]$UserName,

[Parameter()]

[SecureString]$Password

)

# Site URL, It can be parametrize also

$SiteURL= "https://mittal1201.sharepoint.com/sites/commsitehub"

#$SecurePassword = ConvertTo-SecureString -String $Password -AsPlainText -Force

$Cred = New-Object -TypeName System.Management.Automation.PSCredential -argumentlist ($UserName, $Password)

#Connect to PnP Online

Connect-PnPOnline -Url $SiteURL -Credential $Cred

#Get the Root Web

$Web = Get-PnPWeb

#Get the Site Title

Write-host -f Green "Site Title " $Web.Title

If you have mapped the repo with a local machine, then desired IDE can be used, such as Visual Code, to do check-in & check-out. As part of this demo, I directly uploaded this file with the below click.

  • Select vertical dots against the Repo name.
  • Browse the ps1 file and click save.
  • SiteTitle.ps1 file start appearing parallel to the .yml file.



Add Credentials to Pipeline

  • Select the Library section under Pipelines & choose variable groups
  • Give the desired name to the variable group, i.e. credentials
  • Add variable as Key-Value pair
    • username: email id
    • password: **** (lock it)


 

 Add YML file task 

  • The variable used to get detail from Library defined value at run time.
  • The steps consist of two tasks
    • Install PNP Powershell within the current user context.
    • Execute the PnP Powershell with defined credentials into the variable.

# Starter pipeline # Start with a minimal pipeline that you can customize to build and deploy

 # Add steps that build, run tests, deploy, and more:

# https://aka.ms/yaml trigger: - main pool: vmImage: ubuntu-latest variables: - group: Credentials - name: user_name value: $(username) - name: pass_word value: $(password) steps: - task: PowerShell@2 inputs: targetType: 'inline' script: 'Install-Module -Name PnP.PowerShell -Scope CurrentUser -Force' - task: PowerShell@2 displayName: 'PowerShell Script' inputs: targetType: filePath filePath: ./SiteTitle.ps1 arguments: '-username "$(user_name)"  
-password $(ConvertTo-SecureString "$(pass_word)" -AsPlainText -Force)'


Create and Execute Pipeline 

Select Pipeline and click on Run Pipeline.

Under Run pipeline, choose the branch under which yml file exists. 

Click Run to execute.




Output

Once the Pipeline execution is complete and we extend the script section under the job, and we can see Site Title has been printed.



So this is the secure & automated way to execute the PNP PowerShell using Azure DevOps Pipeline. Hope you have learned something new and refreshing in this article.

 

SPFx | Optimize Network call with Image Helper API & Private CDN

 

Office 365 CDN

Office 365 CDN (content delivery network) played a vital role in reducing the network traffic and fastest rendering of the content. It comprises the Private origins CDN and Public origins CDN.

As images are now automatically managed in a SharePoint Online service-managed Private CDN, the manually configured Private CDN is being deprecated. This means that customers no longer need to configure. Reference article here.

Problem Statement



Custom Control (SPFx) renders or displays multiple images which is part of List not part of SPFx solution itself. So content should allow to change later point of time. It cause multiple network call to each render image and lead to performance issues.


Way to achieve the solution

Let's begin to enablement of Private CDN to optimize and reduce the network traffic and configure the codebase accordingly.

Step 1. To validate the Private CDN

  1. Get-SPOTenantCdnEnabled -CdnType Private: return True or False (false means not enabled)
  2. Get-SPOTenantCdnOrigins -CdnType Private: return the path of the origin (blank means not configured and doesn't exist)
  3. Get-SPOTenantCdnPolicies -CdnType Private: return the defined or configured policies.

Step 2. Configure the Private CDN

  1. Set-SPOTenantCdnEnabled -CdnType Private
  2. Press A to confirm the CDN enablement at the Tenant Level
  3. Private CDN-enabled locations start appearing 
  4. Validate Private CDN enablement with Get-SPOTenantCdnEnabled -CdnType Private (True means private CDN enabled)


Step 3. Create a List with an Image DataType

SharePoint Online List structure with the below columns



Step 4. List Image Storage

All List images under the image column get stored in Site Assets automatically. Once you navigate to Site Assets, Sub Folder will get created with the name Lists and a further subfolder with List ID with all images. 

Note. As Private CDN is enabled or enabled automatically, Site Assets origin is set CDN enabled library or folder.


Step 5. Get List Items into the TSX file

Create a state variable type array i.e. footeritems array , and bind the list data within the array using setState.

Step 6. To Convert the source Image Url to CDN, enable the URL using ImageHelper

import { ImageHelper } from "@microsoft/sp-image-helper";

Create a function that takes the source Url and returns the CDN-Enabled Url.

ImageCdnUrl(originalImageUrl : string) { return ImageHelper.convertToImageUrl( { sourceUrl: originalImageUrl, // important width: 80 // up to requirement, size can be set } ); }


Finally, Render Method.

public render(): React.ReactElement<IFooterProps> { return (<> { <section className={`${styles.footer} ${this.props.hasTeamsContext ? styles.teams : ''}`}> <h1 className={`${styles.title}`}>{this.props.description}</h1> <div className={`${styles.socialMediaLinks}`}> {this.state.footerItems.map((fLink, i) => { return ( <> <a target="_blank" href={fLink.FooterUrl?.Url} data-interception="off" rel="noreferrer"> <img alt={fLink["Title"]} src={this.ImageCdnUrl(JSON.parse(fLink.FooterImage)?.serverRelativeUrl)} /> </a> </> ); }) } </div> </section> }</> ); }

 Step 7. Let's build the package, deploy the solution to the app catalog, add a webpart to the page, and validate the Image render path.

I ran the below command to deploy the package.

  1. Gulp Build
  2. Gulp Bundle --ship
  3. Gulp Package-Solution --ship

Once the solution is deployed, the web part is added to the page. Inspect the images; we can see all control images redder from Private CDN. It will improve the network traffic with one call instead of multiple.



 



Hope you have learned something useful here.