Skip to content

Instantly share code, notes, and snippets.

View phillipharding's full-sized avatar

Phil Harding phillipharding

View GitHub Profile
@phillipharding
phillipharding / Convert Javascript Text to Unicode Base64 Encoded String.ts
Last active January 12, 2026 17:43
Useful for updating the vti_indexedpropertykeys property bag item in SharePoint Online, where the key name required is the Base64 encoded Unicode bytes of the property key name
// ==============================================
// ENCODE
/** NODEJS */
const encodedKeyName = Buffer.from("PropertyKeyName", 'utf16le').toString('base64');
/** BROWSER */
function encodeToUtf16LE(str: string): Uint8Array {
const buffer = new ArrayBuffer(str.length * 2);
const view = new Uint16Array(buffer);
@phillipharding
phillipharding / Update SharePoint User Custom Action.ts
Last active January 9, 2026 10:58
Retrieves and Updates a SharePoint App Customiser User Custom Action
import { spfi, SPBrowser, IUserCustomActionInfo } from "@pnp/sp/presets/all";
const sp = spfi().using(SPBrowser({ baseUrl: (window as any)._spPageContextInfo.webAbsoluteUrl }));
(async () => {
console.clear();
const { Title } = await sp.web.select("Title")()
console.log(`Web title: ${Title}`);
@phillipharding
phillipharding / Azure Functions Invocation Context with AsyncLocalStorage.ts
Last active December 23, 2025 17:54
Shows how to use Nodejs AsyncLocalStorage to manage the azure functions runtime Invocation Context (for logging and other things) across a single invocation without having to prop-drill the InvocationContext everywhere. This is safe for concurrent/parallel invocation use and safe for scaling scenarios.
// context.ts
import { AsyncLocalStorage } from 'node:async_hooks';
import { InvocationContext } from '@azure/functions';
const asyncLocalStorage = new AsyncLocalStorage<InvocationContext>();
export function setInvocationContext(context: InvocationContext): void {
asyncLocalStorage.enterWith(context);
}
@phillipharding
phillipharding / cacheProxyService.ts
Created November 14, 2025 12:08
Caching Proxy Wrapper
/* eslint-disable @typescript-eslint/no-explicit-any */
/** Configuration options for caching behavior in the cache proxy service.
*
* @property {number} [ttlMs] - Time-to-live in milliseconds for cached entries. If not specified, entries may be cached indefinitely.
* @property {string[]} [cacheMethods] - Array of method names that should have their results cached. If not specified, no methods will be cached by default.
* @property {string[]} [invalidateOn] - Array of method names that, when called, should invalidate the cache. Useful for clearing cache after data mutations.
* @property {(method: string, args: any[]) => string} [keyFn] - Custom function to generate cache keys based on the method name and arguments. If not provided, a default key generation strategy will be used.
* @property {(method: string, args: any[]) => string[] | undefined} [deriveIdsFromArgs] - Function to extract entity IDs from method arguments, used for selective cache invalidation. Returns an array of IDs or undefined if no I
@phillipharding
phillipharding / Querying SharePoint List Items using the Graph API with a Server Relative Site URL and List Title.md
Created August 8, 2025 17:13
Querying SharePoint List Items using the Graph API with a Server Relative Site URL and List Title

Query SharePoint List Items using the Graph API sites and lists

Uses a server relative site URL instead of a site id

Uses a list title instead of a list id

Expands the fields attribute and restricts the expanded fields to

  • id
  • Title
  • Author (Created by)
  • Editor (Modified by)
@phillipharding
phillipharding / ArrayElementMove.js
Created September 8, 2024 16:15
Array Element Moving
a=[
{ sortIdx: 5, value: "E"},
{ sortIdx: 6, value: "F"},
{ sortIdx: 1, value: "A"},
{ sortIdx: 4, value: "D"},
{ sortIdx: 3, value: "C"},
{ sortIdx: 2, value: "B"},
];
function move(elToMove, targetSortIdx) {
@phillipharding
phillipharding / Upgrading a Functions App and Code-base to the v4 Runtime.md
Created November 15, 2023 15:13
Upgrading a Functions App and Code-base to the v4 Runtime
@phillipharding
phillipharding / Toggle SharePoint Recycle Bin
Created April 30, 2023 11:17
Browser Book mark hack to toggle the SP recycle bin
javascript:(function(){var a=new URL(window.location.href);"5"===a.searchParams.get("view")&&(a.hash?a.hash="":a.hash="view=13"),document.location=a.href})();
@phillipharding
phillipharding / Verify AAD Access Token.js
Last active July 8, 2023 14:04
Verifies an access token issued by the Azure AD identity platform
/** References:
* https://www.npmjs.com/package/azure-ad-verify-token
* https://github.com/justinlettau/azure-ad-verify-token
* https://liangjunjiang.medium.com/verify-and-decode-azure-activity-directory-token-bc72cf7010bc
* https://liangjunjiang.medium.com/azure-active-directory-api-v1-0-vs-v2-0-5c75fb2b1154
* https://www.npmjs.com/package/jwks-rsa
* https://www.npmjs.com/package/jsonwebtoken
* https://www.voitanos.io/blog/validating-azure-ad-generated-oauth-tokens
*
* NOTE:
@phillipharding
phillipharding / Ensure a SharePoint Folder Path using PnPJS.ts
Last active November 9, 2023 10:38
Create/Ensure a SharePoint folder path with nested folders using PnPJS
/*
Hit 'ctrl + d' or 'cmd + d' to run the code, view console for results
*/
import { IWeb, sp, Web } from "@pnp/sp/presets/all";
import { HttpRequestError } from "./@pnp/odata";
const TranslatePnPError = async (opText: string, e) => {
if (e?.isHttpRequestError) {
const json = await (<HttpRequestError>e).response.json();
const errorObject = typeof json["odata.error"] === "object" ? {...json["odata.error"]} : {...e};