Sharepoint

PowerApps Functions

On 30/09/2022

PowerApps functions

Parse text to number

    Filter('Workflow Tasks'; ID = Value(txtId.Text))

Add datas (listItem)

    Patch(NewVoie;Defaults(NewVoie);{Num_x00e9_rovoie:"0"&LookUp(NewVoie;ID=1).Num_x00e9_rovoie}))

Update context, and forms datas

    SubmitForm(FormBeneficiaires);;ResetForm(FormBeneficiaires);; NewForm(FormBeneficiaires);; UpdateContext({showPopup:false});

        If(IsBlankOrError(SubmitForm(Form1)), Set(saveStatus, "An error occured" & Form1.Error), Set(saveStatus, "Operation succeded"))

Navigate to another form

    Navigate(Page_infos_enregistrements)

Get query string parameter and set a variable

    Set(InitiativeId; Param("ID"))

Getquerystringparam

 

Get a field from your datasource by ID

    First(Filter(Initiatives; ID=1)).Nom

 

And Or Not

Or(And(Radio1.Selected.Value=4; !IsBlank(txtComment.Text));Radio1.Selected.Value<4)

 

Update Lookup Field

Patch(
        ResultatAnalyses;
        First(//here item to update
            Filter(
                ResultatAnalyses;
                Affaire.Id = currentAffaire.ID And Analyse.Id = ThisItem.ID
            )
        );
        {
            Title: "notused";
            Commentaires: txtGalComment.Text;
            Gravite: Rating1.Value;
            Affaire: {//lookup field name
                Id: currentAffaire.ID;//id of lookup
                Value: LookUp(
                    Affaires;//list who contains lookup value
                    ID = currentAffaire.ID;//id of lookup
                    currentAffaire.Title//title of lookup value
                )
            }
        }
    )

Patch Choice

TypeIntervention: {Value: dtvTypeIntervention.Selected.Value}

Execute automate with json

'My workflow'.Run(
	JSON(
		{
			SolutionId: selectedSolution.ID,
			ImageContent: UploadedImage14.Image
		},
		JSONFormat.IncludeBinaryData
	)
);

Reg ex to get cleaned string

Clear(AttachmentsCollection);
ForAll(
      RenameColumns(DataCardValue91.Attachments, "Name", "Name1"),
      Collect(
             AttachmentsCollection,
             Name1
      )
);Set(Title1, First(AttachmentsCollection).Value);Set(FileName1, Concat( Split(First(AttachmentsCollection).Value, "" ), If( IsMatch(Result, "([^A-Za-z0-9\.\-])" ), "",Result ) ))

Save Form

SubmitForm(Form1);;If(!IsBlankOrError( Form1.Error); Notify("Une erreur est survenue lors de la sauvegarde " & Form1.Error; NotificationType.Error);Notify("La savegarde a réussi";NotificationType.Information);;Set(currentElement; Form1.LastSubmit))

 

Sort columns


Set(Month, Distinct(SortByColumns(CurrentMonthMails, "Year", Ascending, "Month", Ascending), Month))

Set date


Set(StartDate, DateAdd(DateTimeValue( Day(Today) &"/"& Month(Today) &"/"& Year(Today) &" 00:00:00"), -30));

Sum


Sum(Filter(CurrentMonthMails, Month = ThisItem.Result ), uniqMails)

 

SharePoint RestShow Users List

On 28/10/2025

 

Listuseer

 

 


let currentSort = { column: null, direction: 'asc' }; // Store the current sort state

// Creates the style element
function createStyleElement(id, content) {
    var style = document.createElement("style");
    style.type = "text/css";
    style.id = id;
    style.innerHTML = content;

    if (style.styleSheet) {
        style.styleSheet.cssText = content;
    } else {
        let st = document.getElementById(id);
        if (st == undefined) {
            var head = document.head || document.getElementsByTagName("head")[i];
            head.appendChild(style);
        } else {
            st.innerHTML = content;
        }
    }
    return style;
}


// Function to filter the table based on dropdown selection
function filterTable(columnIndex, value) {
    let table, tr, td, i, select, selectedValue, txtValue;
    table = document.querySelector("table");
    tr = table.getElementsByTagName("tbody")[0].getElementsByTagName("tr");
    select = table.getElementsByTagName("select")[columnIndex];
    //debugger;
    selectedValue = value;

    // Loop through all table rows and hide those that don't match the filter
    for (i = 0; i < tr.length; i++) {
        td = tr[i].getElementsByTagName("td")[columnIndex];
        if (td) {
            txtValue = td.textContent || td.innerText;
            if (selectedValue === "" || txtValue === selectedValue) {
                tr[i].style.display = "";
            } else {
                tr[i].style.display = "none";
            }
        }
    }
}
function sortTable(columnIndex, direction) {
    let table, rows, switching, i, x, y, shouldSwitch;
    table = document.querySelector("table");
    switching = true;
    let tbody = table.querySelector("tbody");

    // Set the current sort state
    currentSort.column = columnIndex;
    currentSort.direction = direction;

    while (switching) {
        switching = false;
        rows = tbody.rows;

        for (i = 0; i < rows.length - 1; i++) {
            shouldSwitch = false;
            x = rows[i].getElementsByTagName("td")[columnIndex];
            y = rows[i + 1].getElementsByTagName("td")[columnIndex];
            let isNumber = false;


            if (!isNaN(x.innerHTML)) {

                // Check if rows should switch based on ascending or descending order
                if (direction === 'asc') {
                    if (parseFloat(x.innerHTML) > parseFloat(y.innerHTML)) {
                        shouldSwitch = true;
                        break;
                    }
                } else if (direction === 'desc') {
                    if (parseFloat(x.innerHTML) < parseFloat(y.innerHTML)) {
                        shouldSwitch = true;
                        break;
                    }
                }
            }
            else {
                // Check if rows should switch based on ascending or descending order
                if (direction === 'asc') {
                    if (x.innerHTML.toLowerCase() > y.innerHTML.toLowerCase()) {
                        shouldSwitch = true;
                        break;
                    }
                } else if (direction === 'desc') {
                    if (x.innerHTML.toLowerCase() < y.innerHTML.toLowerCase()) {
                        shouldSwitch = true;
                        break;
                    }
                }
            }
        }
        if (shouldSwitch) {
            rows[i].parentNode.insertBefore(rows[i + 1], rows[i]);
            switching = true;
        }
    }
}
// Function to generate the table
function generateTableFromJson2(jsonArray, select, addHeaders = true) {
    const style = `
    body{
        background-color: #f8f8f8;
    }
    .parentDiv{
        height:400px;
        overflow-x:scroll;
        white-space: nowrap;
    }
    ul
    {
        list-style-type: none;
    }
    table {
            width: 100%;
            border-collapse: collapse;
        }

        th, td {
            padding: 8px 12px;
            text-align: left;
            border: 1px solid #ddd;
        }

        tbody tr{
           max-height: 15px;
        }

        th {
            background-color: #f4f4f4;
            color: #000;
        }

        /* Scrollable table wrapper */
        .table-wrapper {
            height: 800px;
            overflow-y: auto;
            border: 1px solid #ddd;
            overflow-x:scroll;
        }
        /* Style for dropdowns in header */
        select {
            width: 100%;
            padding: 4px;
            margin-top: 5px;
        }

        /* Style for the sorting arrows */
        .sort-arrows {
            cursor: pointer;
            margin-left: 5px;
        }    
        `;
    createStyleElement("fdiStyle", style);

    // Create table element
    let table = document.createElement('table');

    // Create table header
    let header = table.createTHead();
    let headerRow = header.insertRow(0);

    // Get keys (headers) from the first object in the JSON array
    //let keys = Object.keys(jsonArray[0]);
    let keys = select.split(",");
    if (addHeaders) {
        keys.forEach((key, index) => {
            if (key !== "__metadata") {

                let th = document.createElement('th');
                th.innerHTML = key;

                // Create a dropdown (select) for filtering
                let select = document.createElement('select');

                select.addEventListener('change', function () {
                    const selectedValue = select.value;
                    filterTable(index, selectedValue);
                });

                // Populate dropdown with unique values from the JSON data
                let uniqueValues = [...new Set(jsonArray.map(item => item[key]))];

                // Add a default "All" option for no filter
                let optionAll = document.createElement('option');
                optionAll.value = "";
                optionAll.text = `All`;
                select.appendChild(optionAll);

                // Create an option for each unique value
                if (typeof (uniqueValues[0]) === typeof (1)) {
                    const pp = uniqueValues.sort((a, b) => {
                        if (a < b) {
                            return -1;
                        }
                        if (a > b) {
                            return 1;
                        }
                        return 0;
                    });
                    pp.forEach(value => {
                        let option = document.createElement('option');
                        option.value = value;
                        option.text = value;
                        select.appendChild(option);
                    });
                } else
                    uniqueValues.sort().forEach(value => {
                        let option = document.createElement('option');
                        option.value = value;
                        option.text = value;
                        select.appendChild(option);
                    });
                // Sort arrows for sorting the columns
                let upArrow = document.createElement('span');
                upArrow.innerHTML = '⬆️';
                upArrow.classList.add('sort-arrows');
                upArrow.onclick = () => sortTable(index, 'asc');

                let downArrow = document.createElement('span');
                downArrow.innerHTML = '⬇️';
                downArrow.classList.add('sort-arrows');
                downArrow.onclick = () => sortTable(index, 'desc');

                th.appendChild(select);  // Append the dropdown to the header
                th.appendChild(upArrow);  // Append the dropdown to the header
                th.appendChild(downArrow);  // Append the dropdown to the header
                headerRow.appendChild(th);
            }
        });
    }

    // Create table body and populate rows with data
    let tbody = document.createElement('tbody');
    jsonArray.forEach((item) => {
        let row = tbody.insertRow();
        keys = select.split(",");
        keys.forEach((key) => {
            let cell = row.insertCell();
            if (key !== "__metadata") {
                cell.setAttribute("nowrap", "nowrap");
                if (key === "permissions") {
                    if (item.permissions !== undefined && item.permissions.length > 0) {
                        const ul = document.createElement('ul');
                        item.permissions.forEach((perm) => {

                            let li = document.createElement('li');
                            const tablePerm = document.createElement('table');
                            const tbodyPrem = document.createElement('tbody');
                            let rowPrem = tbodyPrem.insertRow();
                            let cellPerm = rowPrem.insertCell();
                            //member
                            cellPerm.appendChild(generateTableFromJson2([perm.Member], "LoginName,Title", false))
                            //perms
                            cellPerm = rowPrem.insertCell();
                            cellPerm.appendChild(generateTableFromJson2(perm.RoleDefinitionBindings.results, "Name", false));
                            tablePerm.appendChild(tbodyPrem);
                            li.appendChild(tablePerm);
                            ul.appendChild(li);
                        });
                        cell.appendChild(ul);
                    } else {
                        cell.innerHTML = " ";
                    }
                } else if (key.indexOf("/") > 0) {
                    cell.innerHTML = item[key.split("/")[0]][key.split("/")[1]]
                } else
                    cell.innerHTML = item[key];  // Insert each value from the JSON into the table cell
            }
        });
    });

    // Append the body to the table
    table.appendChild(tbody);
    return table;
}

function removeSlasches(select, datas) {
    const ret = [];
    const fields = select.split(',');
    for (let i = 0; i < datas.length; i++) {
        const toAdd = {};

        for (let j = 0; j < fields.length; j++) {
            if (fields[j].indexOf('/') > 0) {
                const splitted = fields[j].split('/');
                toAdd[splitted.join('')] = datas[i][splitted[0]][splitted[1]];
            } else
                toAdd[fields[j]] = datas[i][fields[j]];
        }
        ret.push(toAdd);
    }
    console.log("removeSlasches", ret);
    return ret;
}

async function GetDigestValue(siteUrl) {//
    const fetchOptions = {
        method: 'POST',
        headers: {
            'Accept': 'application/json;odata=verbose',
            'Content-type': 'application/json;odata=verbose'
        }
    };

    const response = await fetch(siteUrl + "/_api/contextinfo", fetchOptions);
    return (await response.json()).d.GetContextWebInformation.FormDigestValue;
}

function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

async function ExecuteQuery(req, fetchOptions, maxRetry = 3, wait = 1, trynum = 1) {

    console.log("ExecuteQuery", req, fetchOptions, maxRetry, wait, trynum);
    if (trynum >= maxRetry) {
        console.log("ExecuteQuery Error", req);
        console.log("ExecuteQuery Error", fetchOptions);
        throw new Error(`ExecuteQuery error! maxRetry >= trynum`);
    }
    try {
        let startDate = new Date();
        let diffMinutes = 0;
        respList1 = await fetch(req, fetchOptions);
        endDate = new Date();
        const diffMs = endDate - startDate;
        diffMinutes = Math.floor(diffMs / (1000));
        console.log(`seconds ${diffMinutes} queryNumber  ${trynum}`)

        //avoid 429 too much queries
        if (!respList1.ok && respList1.status == 429) {
            const errorDetails = await respList1.text(); // Get error details from the response
            let err = JSON.parse(errorDetails);
            console.error(`HTTP error! Status: ${respList1.status}, Details: ${err.error.message.value}`);
            await sleep(wait * 10);// * trynum
            return await ExecuteQuery(req, fetchOptions, maxRetry, (wait * 5), ++trynum);
        } else if (!respList1.ok && respList1.status == 503) {//avoid 503 server unavailable / connections error
            const errorDetails = await respList1.text(); // Get error details from the response
            let err = JSON.parse(errorDetails);
            console.error(`HTTP error! Status: ${respList1.status}, Details: ${err.error.message.value}`);
            await sleep(wait * 10);// * trynum
            return await ExecuteQuery(req, fetchOptions, maxRetry, (wait * 5), ++trynum);
        } else if (!respList1.ok && respList1.status == 403) {//avoid 403 reload page in another tab
            //debugger;
            window.open(_spPageContextInfo.webAbsoluteUrl, '_blank')
            const errorDetails = await respList1.text(); // Get error details from the response
            let err = JSON.parse(errorDetails);
            console.error(`HTTP error! Status: ${respList1.status}, Details: ${err.error.message.value}`);
            await sleep(wait * 10);// * trynum
            window.open(_spPageContextInfo.webAbsoluteUrl, '_blank')
            return await ExecuteQuery(req, fetchOptions, maxRetry, (wait * 5), ++trynum);
        } else if (!respList1.ok) {
            console.log("ExecuteQuery Error", respList1);
            const errorDetails = await respList1.text(); // Get error details from the response
            console.log("ExecuteQuery Error", respList1);
            console.error(`HTTP error! Status: ${respList1.status}, Details: ${errorDetails}`);
            let err = JSON.parse(errorDetails);
            console.error(`HTTP error! Status: ${respList1.status}, Details: ${err.error.message.value}`);
            console.log(err.error.message.value);
            throw new Error(`HTTP error! Status: ${respList1.status}`);
        }

        return respList1

    } catch (error) {
        console.log(error);
        throw new Error(`HTTP error! Status: ${error}`);
    }
}
const siteUrl = _spPageContextInfo.webAbsoluteUrl;
const fetchOptions = {
    method: 'GET',
    headers: {
        'Accept': 'application/json;odata=verbose'
    }
};

//get web server relative url
let resp = await ExecuteQuery(`${siteUrl}/_api/web?$select=ServerRelativeUrl`, fetchOptions);

let usrType1 = await resp.json();
console.log(usrType1.d);
const webRelativeUrl = usrType1.d.ServerRelativeUrl;

//get user list
resp = await ExecuteQuery(`${siteUrl}/_api/web/lists?$select=RootFolder/ServerRelativeUrl,Id&$expand=RootFolder`, fetchOptions);

usrType1 = await resp.json();
let userListId = "";
usrType1.d.results.forEach(list => {
    if (list.RootFolder.ServerRelativeUrl.toLowerCase() === (webRelativeUrl + "/_api/web/siteuserinfolist").toLowerCase() ||
        list.RootFolder.ServerRelativeUrl.toLowerCase() === (webRelativeUrl + "/_catalogs/users").toLowerCase()) {
        userListId = list.Id;
    }
});
if(userListId === ""){
    console.log("list not found");
    throw new Error("list not found");
}
    
resp = await ExecuteQuery(`${siteUrl}/_api/web/lists(guid'${userListId}')/items?$select=FirstName,IsActive,LastName,UserName,Modified,Author/Title,JobTitle,Department,IsSiteAdmin,EMail,Title,Name,ContentTypeDisp,Deleted,PrincipalCount,ID&$expand=Author`, fetchOptions);

let j = await resp.json();
console.log(j.d);


resp = await ExecuteQuery(`${siteUrl}/_api/web/siteusers?$select=ID,PrincipalType,IsShareByEmailGuestUser`, fetchOptions);

const usrType = await resp.json();

j.d.results.forEach(element => {
    //debugger;
    const usr = usrType.d.results.find(u => u.Id === element.ID);
    //console.log("usrType", usrType);
    if (usr !== undefined) {
        element.PrincipalType = usr.PrincipalType;
        element.IsShareByEmailGuestUser = usr.IsShareByEmailGuestUser;
    } else {
        element.PrincipalType = -1;
        element.IsShareByEmailGuestUser = false;
    }
});

document.body.innerHTML = `
`; const table = generateTableFromJson2(j.d.results, "EMail,Title,PrincipalType,IsShareByEmailGuestUser,Name,IsActive,FirstName,LastName,UserName,Modified,Author/Title,JobTitle,Department,IsSiteAdmin,Deleted,ID"); // Append the table to the container document.getElementById('tableContainer').appendChild(table);

Sharepoint Audit List Permissions batch

On 17/10/2025


const siteUrl = _spPageContextInfo.webAbsoluteUrl;
const listUrl = "Shared%20Documents";


function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}


async function generateGuid() {
    await sleep(10);// * trynum
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
        const r = Math.random() * 16 | 0;
        const v = c === 'x' ? r : (r & 0x3 | 0x8);
        return v.toString(16);
    });
}
async function getRequestDigest() {

    const fetchOptions = {
        method: "POST",
        headers: { Accept: "application/json;odata=verbose" },
        credentials: "include",
    };
    const data = (await (await ExecuteQuery(`${siteUrl}/_api/contextinfo`, fetchOptions)).json());
    return data.d.GetContextWebInformation.FormDigestValue;
}

async function ExecuteQuery(req, fetchOptions, maxRetry = 3, wait = 10000, trynum = 1) {

    console.log("ExecuteQuery", req, fetchOptions, maxRetry, wait, trynum);
    if (trynum >= maxRetry) {
        console.log("ExecuteQuery Error", req);
        console.log("ExecuteQuery Error", fetchOptions);
        throw new Error(`ExecuteQuery error! maxRetry >= trynum`);
    }
    try {
        let startDate = new Date();
        let diffMinutes = 0;
        respList1 = await fetch(req, fetchOptions);
        endDate = new Date();
        const diffMs = endDate - startDate;
        diffMinutes = Math.floor(diffMs / (1000));
        console.log(`seconds ${diffMinutes} queryNumber  ${trynum}`)

        //avoid 429 too much queries
        if (!respList1.ok && respList1.status == 429) {
            const errorDetails = await respList1.text(); // Get error details from the response
            let err = JSON.parse(errorDetails);
            console.error(`HTTP error! Status: ${respList1.status}, Details: ${err.error.message.value}`);
            await sleep(wait * 2);// * trynum
            if (fetchOptions.method === "POST") {
                //regnerate the digest
                fetchOptions["X-RequestDigest"] = await getRequestDigest();
            }
            return await ExecuteQuery(req, fetchOptions, maxRetry, (wait * 5), ++trynum);
        }

        //avoid 503 server unavailable / connections error
        if (!respList1.ok && respList1.status == 503) {
            const errorDetails = await respList1.text(); // Get error details from the response
            let err = JSON.parse(errorDetails);
            console.error(`HTTP error! Status: ${respList1.status}, Details: ${err.error.message.value}`);
            await sleep(1000 * wait);// wait 10 seconds
            if (fetchOptions.method === "POST") {
                //regnerate the digest
                fetchOptions["X-RequestDigest"] = await getRequestDigest();
            }
            return await ExecuteQuery(req, fetchOptions, maxRetry, (wait * 5), ++trynum);
        }

        //avoid 403 reload page in another tab
        if (!respList1.ok && respList1.status == 403) {
            //debugger;
            window.open(siteUrl, '_blank')
            const errorDetails = await respList1.text(); // Get error details from the response
            let err = JSON.parse(errorDetails);
            console.error(`HTTP error! Status: ${respList1.status}, Details: ${err.error.message.value}`);
            console.log("waiting due to error 403");
            await sleep(10000);// wait 10 seconds
            window.open(siteUrl, '_blank')
            await sleep(1000 * wait);// wait 10 seconds
            if (fetchOptions.method === "POST") {
                //regnerate the digest
                fetchOptions["X-RequestDigest"] = await getRequestDigest();
            }
            return await ExecuteQuery(req, fetchOptions, maxRetry, (wait * 5), ++trynum);
        }

        if (!respList1.ok) {
            console.log("ExecuteQuery Error", respList1);
            const errorDetails = await respList1.text(); // Get error details from the response
            console.log("ExecuteQuery Error", respList1);
            console.error(`HTTP error! Status: ${respList1.status}, Details: ${errorDetails}`);
            let err = JSON.parse(errorDetails);
            console.error(`HTTP error! Status: ${respList1.status}, Details: ${err.error.message.value}`);
            console.log(err.error.message.value);
            throw new Error(`HTTP error! Status: ${respList1.status}`);
        }

        return respList1

    } catch (error) {
        console.log(error);
        throw new Error(`HTTP error! Status: ${error}`);
    }
}

async function GetFolderSize(siteUrl, listUrl1, query) {
    // Fetch options with headers for authentication and response format
    const fetchOptions = {
        method: 'GET',
        headers: {
            'Accept': 'application/json;odata=verbose'
        }
    };

    //get web relativeUrl
    var req = `${siteUrl}/_api/web?$select=ServerRelativeUrl`;
    const webServerRelativUrl = (await (await ExecuteQuery(req, fetchOptions)).json()).d.ServerRelativeUrl;
    // get total items count 
    req = `${siteUrl}/_api/web/getlist('${webServerRelativUrl}/${listUrl1}')/?$select=ItemCount`;

    const ItemsCount = (await (await ExecuteQuery(req, fetchOptions)).json()).d.ItemCount;
    let query1 = "";
    if (`${query}`.trim() !== "") {
        query1 = `&$filter=${query}`;
        query = ` and ${query}`;
    }
    //get firstId
    req = `${siteUrl}/_api/web/getlist('${webServerRelativUrl}/${listUrl1}')/items?$select=Id&$top=1&$orderby=Id asc${query1}`;
    console.log("req", req);
    const firstId = (await (await ExecuteQuery(req, fetchOptions)).json()).d.results[0].Id;
    console.log("firstId", firstId);
    //get lastId
    req = `${siteUrl}/_api/web/getlist('${webServerRelativUrl}/${listUrl1}')/items?$select=Id&$top=1&$orderby=Id desc${query1}`;
    console.log("last", req);
    const lastId = (await (await ExecuteQuery(req, fetchOptions)).json()).d.results[0].Id;
    console.log("lastId", lastId);


    let startId = firstId;
    let endId = firstId + 5000;
    var allItems = [];

    console.log(`startId ${startId} endId ${endId} lastId ${lastId}`);//FileSizeDisplay
    console.log("query", query);//_UIVersionString File_x0020_Size
    const startDate = new Date();
    let endDate = new Date();
    let diffMinutes = 0;
    let queryNumber = 1;

    do {
        //to avoid 429 error
        if (queryNumber % 10 == 0) {
            console.log(`sleep 1 minute queryNumber ${queryNumber}`);
            await sleep(60000); // 60 000 ms = 1 minute
        }
        var select = "?$select=File/Length,File/UIVersionLabel,File_x0020_Type,Id,HasUniqueRoleAssignments,FileRef,FileLeafRef,FileDirRef,Created,Modified,Author/Title,Author/EMail,Editor/Title,Editor/EMail,ContentTypeId";
        req = `${siteUrl}/_api/web/getlist('${webServerRelativUrl}/${listUrl1}')/items${select}&$filter=Id ge ${startId} and Id lt ${endId} and Id le ${lastId}${query}&$orderby=Id asc&$top=5000&$expand=File,Author,Editor`;
        console.log("req", req);
        // Send the asynchronous GET request to the REST API endpoint /_api/site/usage
        let respList1 = null;
        try {
            respList1 = await ExecuteQuery(req, fetchOptions);

            endDate = new Date();
            queryNumber++;
        } catch (error) {
            console.log("error", error);
            return allItems;
        }
        const items = (await respList1.json()).d.results;
        allItems.push(...items);
        startId += 5000;
        endId += 5000;
        const diffMs = endDate - startDate;
        diffMinutes = Math.floor(diffMs / (1000 * 60));
        console.log(`startId ${startId} endId ${endId} lastId ${lastId} diffMinutes ${diffMinutes} queryNumber  ${queryNumber}, ItemsCount : ${ItemsCount}`)
        await sleep(1500); //  1,5 second
        //debugger;
    }
    while (startId <= lastId);

    return allItems;
}

async function batchFetchPermissions(queriess) {
    const queries = [...queriess];
    console.log("batchFetchPermissions", queries);
    const batchBoundary = "batch_" + await generateGuid();
    const batchBody = queries.map((query) => {
        return `
--${batchBoundary}
Content-Type: application/http
Content-Transfer-Encoding: binary

GET ${query.req} HTTP/1.1
Accept: application/json;odata=verbose
`;
    }).join("\n") + `\n--${batchBoundary}--`;
    const digest = await getRequestDigest();//
    console.log("batchBody", batchBody.length);
    const headers = {
        Accept: "application/json;odata=verbose",
        "X-RequestDigest": digest,
        "Content-Type": `multipart/mixed; boundary="${batchBoundary}"`,
    };

    const response = await fetch(`${siteUrl}/_api/$batch`, {
        method: "POST",
        headers,
        body: batchBody,
    });

    const text = await response.text(); // Parse response manually (multipart) 
    const responses = text.split("HTTP/1.1 200 OK");
    const results1 = [];
    for (let k = 1; k < responses.length; k++) {
        const parts = responses[k].split("\r\n\r\n")[1];
        // The JSON is the last part after the headers
        let jsonString = parts[parts.length - 1];

        // Parse the JSON
        jsonString = parts.split("\r\n")[0];
        const d = {
            Id: `${queries[k - 1].Id}`,
            Index: k,
            result: JSON.parse(jsonString.trim()).d
        }
        results1.push(d);
    }
    return [...results1];
}
const maxBatch = 20;
async function LoadUniquePermissions(items) {
    let batchCount = 0;
    let requests = [];
    var req = `${siteUrl}/_api/web?$select=ServerRelativeUrl`;
    const fetchOptions = {
        method: 'GET',
        headers: {
            'Accept': 'application/json;odata=verbose'
        }
    };
    const perms = [];
    const webServerRelativUrl = (await (await ExecuteQuery(req, fetchOptions)).json()).d.ServerRelativeUrl;

    for (let i = 0; i < items.length; i++) {
        items[i].permId = await generateGuid();
        if (items[i].HasUniqueRoleAssignments) {
            requests.push({
                Id: items[i].permId,
                req: `${siteUrl}/_api/web/getlist('${webServerRelativUrl}/${listUrl}')/items(${items[i].Id})/RoleAssignments?$expand=Member,RoleDefinitionBindings&$select=Member/Id,Member/LoginName,Member/Title,RoleDefinitionBindings/Name`
            });
            batchCount++;
        }

        if (requests.length === maxBatch) {
            perms.push(await batchFetchPermissions(requests));
            requests = [];
        }
    }

    if (requests.length > 0) {
        perms.push(await batchFetchPermissions(requests));
        requests = [];
    }

    for (let i = 0; i < items.length; i++) {
        const perm = perms.flat().filter(f => `${f.Id}` == `${items[i].permId}`);
        if (items[i].HasUniqueRoleAssignments && perm.length === 1) {
            items[i].permissions = perm[0].result.results;
        }
    }


    console.log("with perm", items);
    return items;
}
const disgest = await getRequestDigest();
console.log("disgest", disgest);
const items = await GetFolderSize(siteUrl, listUrl, "Id le 145000");//(Id eq 225 or Id eq 226) Id gt 270
const rest = await LoadUniquePermissions(items);


SharePoint Get Doc Lib Size avoid error 429

On 10/10/2025



function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

async function ExecuteQuery(req, fetchOptions, maxRetry = 3, wait = 1, trynum = 1) {

    console.log("ExecuteQuery", req, fetchOptions, maxRetry, wait, trynum);
    if (trynum >= maxRetry) {
        console.log("ExecuteQuery Error", req);
        console.log("ExecuteQuery Error", fetchOptions);
        throw new Error(`ExecuteQuery error! maxRetry >= trynum`);
    }
    try {
        let startDate = new Date();
        let diffMinutes = 0;
        respList1 = await fetch(req, fetchOptions);
        endDate = new Date();
        const diffMs = endDate - startDate;
        diffMinutes = Math.floor(diffMs / (1000));
        console.log(`seconds ${diffMinutes} queryNumber  ${trynum}`)

        //avoid 429 too much queries
        if (!respList1.ok && respList1.status == 429) {
            const errorDetails = await respList1.text(); // Get error details from the response
            let err = JSON.parse(errorDetails);
            console.error(`HTTP error! Status: ${respList1.status}, Details: ${err.error.message.value}`);
            await sleep(wait * 10);// * trynum
            return await ExecuteQuery(req, fetchOptions, maxRetry, (wait * 5), ++trynum);
        }

        //avoid 503 server unavailable / connections error
        if (!respList1.ok && respList1.status == 503) {
            const errorDetails = await respList1.text(); // Get error details from the response
            let err = JSON.parse(errorDetails);
            console.error(`HTTP error! Status: ${respList1.status}, Details: ${err.error.message.value}`);
            await sleep(wait * 10);// * trynum
            return await ExecuteQuery(req, fetchOptions, maxRetry, (wait * 5), ++trynum);
        }

        //avoid 403 reload page in another tab
        if (!respList1.ok && respList1.status == 403) {
            //debugger;
            window.open(_spPageContextInfo.webAbsoluteUrl, '_blank')
            const errorDetails = await respList1.text(); // Get error details from the response
            let err = JSON.parse(errorDetails);
            console.error(`HTTP error! Status: ${respList1.status}, Details: ${err.error.message.value}`);
            await sleep(wait * 10);// * trynum
            window.open(_spPageContextInfo.webAbsoluteUrl, '_blank')
            return await ExecuteQuery(req, fetchOptions, maxRetry, (wait * 5), ++trynum);
        }

        if (!respList1.ok) {
            console.log("ExecuteQuery Error", respList1);
            const errorDetails = await respList1.text(); // Get error details from the response
            console.log("ExecuteQuery Error", respList1);
            console.error(`HTTP error! Status: ${respList1.status}, Details: ${errorDetails}`);
            let err = JSON.parse(errorDetails);
            console.error(`HTTP error! Status: ${respList1.status}, Details: ${err.error.message.value}`);
            console.log(err.error.message.value);
            throw new Error(`HTTP error! Status: ${respList1.status}`);
        }

        return respList1

    } catch (error) {
        console.log(error);
        throw new Error(`HTTP error! Status: ${error}`);
    }
}
async function GetFolderSize(siteUrl, listUrl1, query) {
    // Fetch options with headers for authentication and response format
    const fetchOptions = {
        method: 'GET',
        headers: {
            'Accept': 'application/json;odata=verbose'
        }
    };

    //get web relativeUrl
    var req = `${siteUrl}/_api/web?$select=ServerRelativeUrl`;
    const webServerRelativUrl = (await (await ExecuteQuery(req, fetchOptions)).json()).d.ServerRelativeUrl;
    // get total items count 
    req = `${siteUrl}/_api/web/getlist('${webServerRelativUrl}/${listUrl1}')/?$select=ItemCount`;

    const ItemsCount = (await (await ExecuteQuery(req, fetchOptions)).json()).d.ItemCount;
    let query1 = "";
    if (`${query}`.trim() !== "") {
        query1 = `&$filter=${query}`;
        query = ` and ${query}`;
    }
    //get firstId
    req = `${siteUrl}/_api/web/getlist('${webServerRelativUrl}/${listUrl1}')/items?$select=Id&$top=1&$orderby=Id asc${query1}`;
    console.log("req", req);
    const firstId = (await (await ExecuteQuery(req, fetchOptions)).json()).d.results[0].Id;
    console.log("firstId", firstId);
    //get lastId
    req = `${siteUrl}/_api/web/getlist('${webServerRelativUrl}/${listUrl1}')/items?$select=Id&$top=1&$orderby=Id desc${query1}`;
    console.log("last", req);
    const lastId = (await (await ExecuteQuery(req, fetchOptions)).json()).d.results[0].Id;
    console.log("lastId", lastId);


    let startId = firstId;
    let endId = firstId + 5000;
    var allItems = [];

    console.log(`startId ${startId} endId ${endId} lastId ${lastId}`);//FileSizeDisplay
    console.log("query", query);//_UIVersionString File_x0020_Size
    const startDate = new Date();
    let endDate = new Date();
    let diffMinutes = 0;
    let queryNumber = 1;

    do {
        //to avoid 429 error
        if (queryNumber % 10 == 0) {
            console.log(`sleep 1 minute queryNumber ${queryNumber}`);
            await sleep(60000); // 60 000 ms = 1 minute
        }
        var select = "?$select=File/Length,File/UIVersionLabel,File_x0020_Type,Id,HasUniqueRoleAssignments,FileRef,FileLeafRef,FileDirRef,Created,Modified,Author/Title,Author/EMail,Editor/Title,Editor/EMail,ContentTypeId";
        req = `${siteUrl}/_api/web/getlist('${webServerRelativUrl}/${listUrl1}')/items${select}&$filter=Id ge ${startId} and Id lt ${endId} and Id le ${lastId}${query}&$orderby=Id asc&$top=5000&$expand=File,Author,Editor`;
        console.log("req", req);
        // Send the asynchronous GET request to the REST API endpoint /_api/site/usage
        let respList1 = null;
        try {
            respList1 = await ExecuteQuery(req, fetchOptions);

            endDate = new Date();
            queryNumber++;
        } catch (error) {
            console.log("error", error);
            return allItems;
        }
        const items = (await respList1.json()).d.results;
        allItems.push(...items);
        startId += 5000;
        endId += 5000;
        const diffMs = endDate - startDate;
        diffMinutes = Math.floor(diffMs / (1000 * 60));
        console.log(`startId ${startId} endId ${endId} lastId ${lastId} diffMinutes ${diffMinutes} queryNumber  ${queryNumber}, ItemsCount : ${ItemsCount}`)
        await sleep(1500); //  1,5 second
        //debugger;
    }
    while (startId <= lastId);

    //console.log("allItems", allItems);
    console.log("queryNumber", queryNumber);
    return allItems;
}
let totalSize = 0


const siteUrl = _spPageContextInfo.webAbsoluteUrl;

const items = await GetFolderSize(siteUrl, "Shared%20Documents", "");//startswith(ContentTypeId,'0x0101')

//calculate file Size
let separator = ";"
let csv = `Id${separator}HasUniqueRoleAssignments${separator}FromParent${separator}Title${separator}FileRef${separator}FileDirRef${separator}FileLeafRef${separator}Created${separator}CreatedMin${separator}Modified${separator}ModifiedMin${separator}AuthorTitle${separator}AuthorEMail${separator}EditorTitle${separator}EditorEMail${separator}FileLength${separator}MB${separator}GB${separator}FileUIVersionLabel${separator}File_x0020_Type${separator}ContentTypeId${separator}count\n`;

//display lastID
if (items !== undefined && items !== null && items.length > 0) {
    console.log(`lastId ${items[items.length - 1].Id}`);
}
//check child
//get folders with unique permissions
const folder = items.filter(file => file.HasUniqueRoleAssignments && file.ContentTypeId.startsWith('0x0120'));

for (let k = 0; k < folder.length; k++) {
    for (let i = 0; i < items.length; i++) {
        if(items[i].FromParent == undefined)
            items[i].FromParent = false;
        if (items[i].HasUniqueRoleAssignments == false && items[i].FileDirRef.startsWith(folder[k].FileRef)) {
            items[i].HasUniqueRoleAssignments = true;
            items[i].FromParent = true;
        }
    }
}
for (let i = 0; i < items.length; i++) {

    csv += `${items[i].Id}${separator}`;
    csv += `${items[i].HasUniqueRoleAssignments}${separator}`;
    csv += `${items[i].FromParent}${separator}`;
    csv += `${items[i].Title}${separator}`;
    csv += `${items[i].FileRef}${separator}`;
    csv += `${items[i].FileDirRef}${separator}`;
    csv += `${items[i].FileLeafRef}${separator}`;
    csv += `${items[i].Created}${separator}`;
    csv += `${items[i].Created.substring(0, 10)}${separator}`;
    csv += `${items[i].Modified}${separator}`;
    csv += `${items[i].Modified.substring(0, 10)}${separator}`;
    csv += `${items[i].Author.Title}${separator}`;
    csv += `${items[i].Author.EMail}${separator}`;
    csv += `${items[i].Editor.Title}${separator}`;
    csv += `${items[i].Editor.EMail}${separator}`;
    //if is a file 
    if (items[i].File != undefined && items[i].File.Length != undefined) {
        totalSize += parseInt(items[i].File.Length);
        csv += `${items[i].File.Length}${separator}`;
        csv += `${(items[i].File.Length / (1024 * 1024)).toFixed(2)}${separator}`;
        csv += `${(items[i].File.Length / (1024 * 1024 * 1024)).toFixed(2)}${separator}`;
        csv += `${items[i].File.UIVersionLabel}${separator}`;
        csv += `${items[i].File_x0020_Type}${separator}`;
    }
    else {
        //is folder
        csv += `${separator}`;
        csv += `${separator}`;
        csv += `${separator}`;
        csv += `${separator}`;
        csv += `${separator}`;
    }
    csv += (`${items[i].ContentTypeId}`.startsWith('0x0120') ? "folder" : `${items[i].ContentTypeId}`);
    csv += `${separator}1\n`;
}
const totalSizeGB = (totalSize / (1024 * 1024 * 1024)).toFixed(2);
console.log("totalSize   B", totalSize);
console.log("total size MB", (totalSize / (1024 * 1024)).toFixed(2));
console.log("total size GB", totalSizeGB);


console.log("items length", items.length);
console.log("csv", csv);
console.log("items", items);


Get SharePoint Document Library Size

On 09/10/2025

function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

async function GetFolderSize(siteUrl, listUrl1, query) {
    // Fetch options with headers for authentication and response format
    const fetchOptions = {
        method: 'GET',
        headers: {
            'Accept': 'application/json;odata=verbose'
        }
    };
    // get web relativeUrl
    var req = `${siteUrl}/_api/web?$select=ServerRelativeUrl`;
    const webServerRelativUrl = (await (await fetch(req, fetchOptions)).json()).d.ServerRelativeUrl;
    let query1 = "";
    if (`${query}`.trim() !== "") {
        query1 = `&$filter=${query}`;
        query = ` and ${query}`;
    }
    // get firstId
    req = `${siteUrl}/_api/web/getlist('${webServerRelativUrl}/${listUrl1}')/items?$select=Id&$top=1&$orderby=Id asc`;
    console.log("req", req);
    const firstId = 0;
    console.log("firstId", firstId);
    // get lastId
    req = `${siteUrl}/_api/web/getlist('${webServerRelativUrl}/${listUrl1}')/items?$select=Id&$top=1&$orderby=Id desc`;
    console.log("last", req);
    const lastId = (await (await fetch(req, fetchOptions)).json()).d.results[0].Id;
    console.log("lastId", lastId);
    let startId = firstId;
    let endId = firstId + 5000;
    var allItems = [];
    console.log(`startId ${startId} endId ${endId} lastId ${lastId}`);
    console.log("query", query);
    const startDate = new Date();
    let endDate = new Date();
    let diffMinutes = 0;
    let queryNumber = 0;
    do {
        // to avoid 429 error
        if(queryNumber % 10 == 0){
            await sleep(60000); // 60 000 ms = 1 minute
        }
        var select = "?$select=File/Length";
        req = `${siteUrl}/_api/web/getlist('${webServerRelativUrl}/${listUrl1}')/items${select}&$filter=Id ge ${startId} and Id lt ${endId}${query}&$orderby=Id asc&$top=5000&$expand=File`;
        console.log("req", req);
        let respList1 = null;
        try {
            respList1 = await fetch(req, fetchOptions);
            if (!respList1.ok) {
                const errorDetails = await respList1.text();
                console.error(`HTTP error! Status: ${respList1.status}, Details: ${errorDetails}`);
                let err = JSON.parse(errorDetails);
                console.error(`HTTP error! Status: ${respList1.status}, Details: ${err.error.message.value}`);
                console.log(err.error.message.value);
                throw new Error(`HTTP error! Status: ${respList1.status}`);
            }
            endDate = new Date();
            queryNumbercatch (error) {
            console.log("error", error);
            return null;
        }
        const items = (await respList1.json()).d.results;
        allItems.push(...items);
        startId += 5000;
        endId += 5000;
        const diffMs = endDate - startDate;
        diffMinutes = Math.floor(diffMs / (1000 * 60));
        console.log(`startId ${startId} endId ${endId} lastId ${lastId} diffMinutes ${diffMinutes} queryNumber  ${queryNumber}`)
    }
    while (endId < lastId);
    console.log("queryNumber", queryNumber);
    return allItems;
}
let totalSize = 0
const siteUrl = "Your site Url";
const items = await GetFolderSize(siteUrl, "Your doclib Name", "startswith(ContentTypeId,'0x0101')");
// calculate file Size
for (let i = 0; i < items.length; i++) {
    if (items[i].File != undefined && items[i].File.Length != undefined) {
        totalSize += parseInt(items[i].File.Length);
    }
}
const totalSizeGB = (totalSize / (1024 * 1024 * 1024)).toFixed(2);
console.log("totalSize   B", totalSize);
console.log("total size MB", (totalSize / (1024 * 1024)).toFixed(2));
console.log("total size GB", totalSizeGB);
console.log("items length", items.length);

        


function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}
async function GetFolderSize(siteUrl, listUrl1, query) {
    // Fetch options with headers for authentication and response format
    const fetchOptions = {
        method: 'GET',
        headers: {
            'Accept': 'application/json;odata=verbose'
        }
    };

    //get web relativeUrl
    var req = `${siteUrl}/_api/web?$select=ServerRelativeUrl`;
    const webServerRelativUrl = (await (await fetch(req, fetchOptions)).json()).d.ServerRelativeUrl;

    let query1 = "";
    if (`${query}`.trim() !== "") {
        query1 = `&$filter=${query}`;
        query = ` and ${query}`;
    }
    //get firstId
    req = `${siteUrl}/_api/web/getlist('${webServerRelativUrl}/${listUrl1}')/items?$select=Id&$top=1&$orderby=Id asc`;
    console.log("req", req);
    const firstId = 0;
    console.log("firstId", firstId);
    //get lastId
    req = `${siteUrl}/_api/web/getlist('${webServerRelativUrl}/${listUrl1}')/items?$select=Id&$top=1&$orderby=Id desc`;
    console.log("last", req);
    const lastId = (await (await fetch(req, fetchOptions)).json()).d.results[0].Id;
    console.log("lastId", lastId);


    let startId = firstId;
    let endId = firstId + 5000;
    var allItems = [];

    console.log(`startId ${startId} endId ${endId} lastId ${lastId}`);//FileSizeDisplay
    console.log("query", query);//_UIVersionString File_x0020_Size
    const startDate = new Date();
    let endDate = new Date();
    let diffMinutes = 0;
    let queryNumber = 0;
    do {
        //to avoid 429 error
        if(queryNumber % 10 == 0){
            await sleep(60000); // 60 000 ms = 1 minute
        }
        var select = "?$select=File/Length";
        req = `${siteUrl}/_api/web/getlist('${webServerRelativUrl}/${listUrl1}')/items${select}&$filter=Id ge ${startId} and Id lt ${endId}${query}&$orderby=Id asc&$top=5000&$expand=File`;
        console.log("req", req);
        // Send the asynchronous GET request to the REST API endpoint /_api/site/usage
        let respList1 = null;
        try {
            respList1 = await fetch(req, fetchOptions);

            if (!respList1.ok) {
                const errorDetails = await respList1.text(); // Get error details from the response
                console.error(`HTTP error! Status: ${respList1.status}, Details: ${errorDetails}`);
                let err = JSON.parse(errorDetails);
                console.error(`HTTP error! Status: ${respList1.status}, Details: ${err.error.message.value}`);
                console.log(err.error.message.value);
                throw new Error(`HTTP error! Status: ${respList1.status}`);
            }
            endDate = new Date();
            queryNumber++;
        } catch (error) {
            console.log("error", error);
            return null;
        }
        const items = (await respList1.json()).d.results;
        allItems.push(...items);
        startId += 5000;
        endId += 5000;
        const diffMs = endDate - startDate;
        diffMinutes = Math.floor(diffMs / (1000 * 60));
        console.log(`startId ${startId} endId ${endId} lastId ${lastId} diffMinutes ${diffMinutes} queryNumber  ${queryNumber}`)
    }
    while (endId < lastId);

    //console.log("allItems", allItems);
    console.log("queryNumber", queryNumber);
    return allItems;
}
let totalSize = 0


const siteUrl = "Your site Url";

const items = await GetFolderSize(siteUrl, "Your doclib Name", "startswith(ContentTypeId,'0x0101')");


//calculate file Size
for (let i = 0; i < items.length; i++) {

    if (items[i].File != undefined && items[i].File.Length != undefined) {
        totalSize += parseInt(items[i].File.Length);
    }
}
const totalSizeGB = (totalSize / (1024 * 1024 * 1024)).toFixed(2);
console.log("totalSize   B", totalSize);
console.log("total size MB", (totalSize / (1024 * 1024)).toFixed(2));
console.log("total size GB", totalSizeGB);


console.log("items length", items.length);
//console.log("items", items);

Sharepoint Web Templates List

On 07/10/2025

Modèles de sites SharePoint modernes (2025)

Code du modèle Nom du modèle Description Type de site associé
STS#3 Site d’équipe (Team Site) Site de collaboration pour les équipes, avec bibliothèques de documents, listes de tâches, calendrier et intégration avec Microsoft Teams. Groupe Microsoft 365/Teams
GROUP#0 Site d’équipe moderne Équivalent moderne de STS#3, toujours lié à un groupe Microsoft 365 (et donc à Teams si activé). Groupe Microsoft 365/Teams
SITEPAGEPUBLISHING#0 Site de communication (Communication Site) Pour diffuser des informations (actualités, rapports, événements) à large audience. Pas lié à Teams. Site autonome
COMMSITE#0 Site de communication moderne Version moderne du site de publication, optimisé pour la communication visuelle et les composants web. Site autonome
STS#0 Site vide (Blank Site) Site SharePoint vide, sans listes ni bibliothèques préconfigurées. Site autonome
BDR#0 Centre de documents Pour gérer et organiser des documents en masse, souvent utilisé comme archive. Site autonome
SRCHCEN#0 Centre de recherche Site dédié à la recherche avancée dans SharePoint. Site autonome
SRCHCENTERLITE#0 Centre de recherche léger Version simplifiée du centre de recherche. Site autonome
EDISC#0 Centre de découverte électronique Pour la gestion des données dans un contexte juridique ou de conformité. Site autonome
POINTPUBLISHING#0 Site de publication Pour publier des pages web avec flux de travail d’approbation (classique). Site autonome

2. Modèles classiques (moins utilisés en 2025, mais toujours disponibles)

Code du modèle Nom du modèle Description
STS#1 Site d’équipe classique Ancienne version du site d’équipe, sans intégration moderne avec Teams.
STS#2 Site d’équipe vide Site d’équipe sans contenu préconfiguré.
WIKI#0 Site Wiki Pour créer une base de connaissances collaborative sous forme de wiki.
BLOG#0 Site de blog Pour publier des articles sous forme de blog.
DEV#0 Site de développement Pour les développeurs, avec des listes de suivi de bugs et de tâches.
PROJECTSITE#0 Site de projet Pour gérer des projets, avec des listes de tâches et des jalons.
COMMUNITY#0 Site communautaire Pour créer une communauté avec forums de discussion.
VISPRJS#0 Référentiel Visio Pour stocker et partager des diagrammes Visio.

Sharepoint React SPFX issue scss missing

On 24/09/2025

in my react code below i have and an error : Cannot find module '../View.module.scss' or its corresponding type declarations.
import styles from './View.module.scss';

 

To solve it verify this fils exists

View.module.scss.ts was missing with code below, so i add it

require("./View.module.css");
const styles = {
  genericView: 'genericView_c46baf68',
  countryview: 'countryview_c46baf68',
  tableContainer: 'tableContainer_c46baf68',
  filterLabel: 'filterLabel_c46baf68',
  cell: 'cell_c46baf68',
  buttonCell: 'buttonCell_c46baf68',
  clearButton: 'clearButton_c46baf68',
  detailsList: 'detailsList_c46baf68',
  detailsListValue: 'detailsListValue_c46baf68',
  iconGreen: 'iconGreen_c46baf68',
  iconRed: 'iconRed_c46baf68',
  field: 'field_c46baf68',
  fieldLabel: 'fieldLabel_c46baf68',
  fieldLabelContainer: 'fieldLabelContainer_c46baf68',
  fieldValue: 'fieldValue_c46baf68',
  fieldLower: 'fieldLower_c46baf68',
  spinnerContainer: 'spinnerContainer_c46baf68',
  noItems: 'noItems_c46baf68',
  callout: 'callout_c46baf68',
  viewDescription: 'viewDescription_c46baf68',
  emptyItem: 'emptyItem_c46baf68',
  statusActive: 'statusActive_c46baf68',
  statusInactive: 'statusInactive_c46baf68',
  statusDissolved: 'statusDissolved_c46baf68'
};

export default styles;

Pnp PowerShell Export Import Site

On 02/07/2025

 

Define JSON configuration https://learn.microsoft.com/en-us/sharepoint/dev/solution-guidance/configuring-the-pnp-provisioning-engine

Connect-PnPOnline -Url $siteUrl -ClientId $clientId -Tenant $tenantName -Thumbprint $cert
 

$xml = Get-PnPSiteTemplate -Out $SchmaXMLPath -Configuration $configPath

# Invoke-PnPSiteTemplate -Path $SchmaXMLPath



{
  "$schema": "https://aka.ms/sppnp-extract-configuration-schema",
  "handlers": [
    "ContentTypes",
    "Fields",
    "Lists"
  ],
  "persistAssetFiles": false,
  "lists": {
    "lists": [
      {
        "title": "Eutelsat Entity",
        "includeItems": false,
        "query": {
          "includeAttachments": false
        }
      }
    ]
  },
  "contentTypes": {
    "groups": [
      "Market Access"
    ]
  }
}

# remove particular nodes
$SchmaXMLPathDest = "MA_pmsatEntity_15.xml"
[xml]$xmlContent = Get-Content $SchmaXMLPath 
Clear-Host
# Define the namespace if needed (common in SharePoint XML)
$nsmgr = New-Object System.Xml.XmlNamespaceManager($xmlContent.NameTable)
# Add the namespace you are using in the XML document. Use "ns" as a prefix here.
$nsmgr.AddNamespace("pnp", "http://schemas.dev.office.com/PnP/2022/09/ProvisioningSchema")

# Use XPath to select fields. Adjust the XPath query based on your XML structure.
$fields = $xmlContent.SelectNodes("//Field", $nsmgr)

Write-Host "cout $($fields.Count)"
# Iterate over fields and remove those whose InternalName starts with an underscore
for ($i = $fields.Count - 1; $i -ge 0; $i--) {
    $internalName = $fields[$i].Attributes["Name"].Value
    if ($internalName -like "_*") {
        # Remove the field from its parent node
        $fields[$i].ParentNode.RemoveChild($fields[$i]) | Out-Null
        continue;
    }
    $internalName = $fields[$i].Attributes["Group"].Value
    if ($internalName -eq "_Hidden") {
        # Remove the field from its parent node
        $fields[$i].ParentNode.RemoveChild($fields[$i]) | Out-Null
    }
}


$fields = $xmlContent.SelectNodes("//pnp:ContentType", $nsmgr)
for ($i = $fields.Count - 1; $i -ge 0; $i--) {
    $internalName = $fields[$i].Attributes["Name"].Value
    if ($internalName -ne "MA_EutelsatEntity") {
        # Remove the field from its parent node
        $fields[$i].ParentNode.RemoveChild($fields[$i]) | Out-Null
    }
}


# Save the modified XML back to a file
$xmlContent.Save("{0}\template\test2.xml" -f (get-location))

Sharepoint Rest Get User ID By Mail

On 23/06/2025



async function GetDigestValue(siteUrl) {//
    const fetchOptions = {
        method: 'POST',
        headers: {
            'Accept': 'application/json;odata=verbose',
            'Content-type': 'application/json;odata=verbose'
        }
    };

    const response = await fetch(siteUrl + "/_api/contextinfo", fetchOptions);
    return (await response.json()).d.GetContextWebInformation.FormDigestValue;
}




async function EnsureUser(siteUrl, userEmail) {
    const digest = await GetDigestValue(siteUrl);
    console.log("digest", digest);

    const body = {
        'logonName': `i:0#.f|membership|${userEmail}`
    }
    const response = await fetch(`${siteUrl}/_api/web/ensureuser?$select=Id`, {
        method: "POST",
        headers: {
            "Accept": "application/json;odata=verbose",
            "Content-Type": "application/json;odata=verbose",
            "X-RequestDigest": digest
        },
        body: JSON.stringify({
            'logonName': `i:0#.f|membership|${userEmail}`
        })
    });
    console.log("response", response);
    const userData = await response.json();
    return userData.d.Id;
}

async function getUserIdByEmail(siteUrl, userEmail) {
    try {

        const fetchOptions = {
            method: 'GET',
            headers: {
                'Accept': 'application/json;odata=verbose',
                'Content-type': 'application/json;odata=verbose'
            }
        };

        const response = await fetch(siteUrl + `/_api/web/siteusers/getbyemail('${encodeURIComponent(userEmail)}')`, fetchOptions);
        const data = await response.json();
        console.log("getUserByEmail data", data);
        return data.d.Id;
    } catch (error) {
        console.log("getUserByEmail Error", error);
        return null;
    }
}
let siteUrl1 = "https://eutelsatgroup.sharepoint.com/sites/fdiSandBox";
let email1 = "ffdietrich-ext@eutelsat.com";
let ret = await EnsureUser(siteUrl1, email1);


console.log("response", ret);
const siteUrl = "https://test.sharepoint.com/sites/Dev_wf";
const email = "fpalmo@test.com";
console.log("response", ret0); 
const ret = await EnsureUser(siteUrl, email);

const ret0 = await getUserIdByEmail(siteUrl, email);



console.log("response", ret);

Show Lists Roleassignments

On 27/05/2025



// Fonction pour récupérer tous les RoleDefinitionBindings
async function getRoleDefinitionBindings(list, Id, Title, ServerRelativeUrl, ItemsCount, Hidden, HasUniqueRoleAssignments) {

    let p = `vdfvd`;//$${apiGet}
    const getPai = `${list}/roleassignments?$expand=Member/users,RoleDefinitionBindings`;
    console.log("request", getPai);
    const response = await fetch(getPai, {
        method: 'GET',
        headers: {
            'Accept': 'application/json;odata=verbose'
        }
    });
    const data = await response.json();
    data.d.results;
    console.log(data.d.results);

    const ret = [];
    for (let i = 0; i < data.d.results.length; i++) {
        var perm = data.d.results[i];

        const toAdd = {};
        toAdd.ListId = Id;
        toAdd.ListTitle = Title;
        toAdd.ListServerRelativeUrl = ServerRelativeUrl;
        toAdd.ItemsCount = ItemsCount;
        toAdd.Hidden = Hidden;
        toAdd.HasUniqueRoleAssignments = HasUniqueRoleAssignments;
        toAdd.Id = perm.Member.Id;
        toAdd.LoginName = perm.Member.LoginName;
        toAdd.Email = perm.Member.Email ?? "";
        toAdd.Description = perm.Member.Description;
        toAdd.Title = perm.Member.Title;
        toAdd.IsHiddenInUI = perm.Member.IsHiddenInUI;
        toAdd.PrincipalId = perm.Member.PrincipalId;
        toAdd.PrincipalType = perm.Member.PrincipalType;
        //users bu group
        if (perm.Member.Users !== undefined && perm.Member.Users !== null && perm.Member.Users.results.length > 0) {
            toAdd.Users = [];
            for (let j = 0; j < perm.Member.Users.results.length; j++) {
                const u = perm.Member.Users.results[j];
                toAdd.Users.push({
                    Email: u.Email,
                    Id: u.Id,
                    Title: u.Title,
                    UserPrincipalName: u.UserPrincipalName,
                    IsSiteAdmin: u.IsSiteAdmin,
                    IsShareByEmailGuestUser: u.IsShareByEmailGuestUser
                });
            }
        }
        toAdd.RoleDefinitionBindings = ""
        if (perm.RoleDefinitionBindings !== undefined && perm.RoleDefinitionBindings !== null && perm.RoleDefinitionBindings.results.length > 0) {

            for (let j = 0; j < 1; j++) {
                const r = perm.RoleDefinitionBindings.results[j];
                toAdd.RoleDefinitionBindings = r.Name;
            }
        }
        ret.push(toAdd);
    }
    
    console.log(ret);
    return ret;
}

let url = "https://test.sharepoint.com/sites/csc";


let lists = `${url}/_api/web/lists?$select=Hidden,Title,RootFolder/ServerRelativeUrl,Id,ItemCount,HasUniqueRoleAssignments&$expand=RootFolder`;//&$filter=Hidden eq false
let response = await fetch(lists, {
    method: 'GET',
    headers: {
        'Accept': 'application/json;odata=verbose'
    }
});
let data = await response.json();


let datas = [];
for (let z = 0; z < data.d.results.length; z++) {//
    const lst = data.d.results[z];
    console.log("lst", lst);
    const datas1 = await getRoleDefinitionBindings(`${url}/_api/web/lists(guid'${lst.Id}')`, lst.Id, lst.Title, lst.RootFolder.ServerRelativeUrl, lst.ItemCount, lst.Hidden, lst.HasUniqueRoleAssignments);
    
    console.log(datas1);
    for (let u = 0; u < datas1.length; u++) {
        datas.push(datas1[u]);
    }
}

console.log("datas", datas);

let csv = "ListId;ListTitle;ListServerRelativeUrl;ItemsCount;Hidden;HasUniqueRoleAssignments;MemberTitle;MemberEmail;MemberLoginName;MemberId;MemberDescription;Permission;TopLevel;UserMail;UserTitle;UserId;UserUserPrincipalName;IsSiteAdmin;IsShareByEmailGuestUser\n";
for (let k = 0; k < datas.length; k++) {
    const d = datas[k];
    let member = "";
    member += `${d.ListId};`
    member += `${d.ListTitle};`
    member += `${d.ListServerRelativeUrl};`
    member += `${d.ItemsCount};`
    member += `${d.Hidden};`
    member += `${d.HasUniqueRoleAssignments};`
    member += `${d.Title};`
    member += `${d.Email};`
    member += `${d.LoginName};`
    member += `${d.Id};`
    member += `${d.Description ?? ""};`
    member += `${d.RoleDefinitionBindings};`
    csv += `${member}true;;;;;;\n`;
    //debugger;
    if (d.Users !== undefined) {
        for (let j = 0; j < d.Users.length; j++) {
            const user = d.Users[j];
            let u = `${member}false;`;
            u += `${user.Email};`;
            u += `${user.Title};`;
            u += `${user.Id};`;
            u += `${user.UserPrincipalName ?? ""};`;
            u += `${user.IsSiteAdmin};`;
            u += `${user.IsShareByEmailGuestUser}`;
            csv += `${u}\n`
        }
    }
}
console.log(csv);

Get Web Role Assignments

On 27/05/2025



// Fonction pour récupérer tous les RoleDefinitionBindings
async function getRoleDefinitionBindings(apiGet, type) {

    let p = `vdfvd`;//$${apiGet}
    const getPai = `${apiGet}/roleassignments?$expand=Member/users,RoleDefinitionBindings`;
    const response = await fetch(getPai, {
        method: 'GET',
        headers: {
            'Accept': 'application/json;odata=verbose'
        }
    });
    const data = await response.json();
    data.d.results;
    console.log(data.d.results);

    const ret = [];
    for (let i = 0; i < data.d.results.length; i++) {
        var perm = data.d.results[i];

        const toAdd = {};
        toAdd.type = type;
        toAdd.Id = perm.Member.Id;
        toAdd.LoginName = perm.Member.LoginName;
        toAdd.Email = perm.Member.Email ?? "";
        toAdd.Description = perm.Member.Description;
        toAdd.Title = perm.Member.Title;
        toAdd.IsHiddenInUI = perm.Member.IsHiddenInUI;
        toAdd.PrincipalId = perm.Member.PrincipalId;
        toAdd.PrincipalType = perm.Member.PrincipalType;
        //users bu group
        if (perm.Member.Users !== undefined && perm.Member.Users !== null && perm.Member.Users.results.length > 0) {
            toAdd.Users = [];
            for (let j = 0; j < perm.Member.Users.results.length; j++) {
                const u = perm.Member.Users.results[j];
                toAdd.Users.push({
                    Email: u.Email,
                    Id: u.Id,
                    Title: u.Title,
                    UserPrincipalName: u.UserPrincipalName,
                    IsSiteAdmin: u.IsSiteAdmin,
                    IsShareByEmailGuestUser: u.IsShareByEmailGuestUser
                });
            }
        }
        //debugger;
        // = [];
        toAdd.RoleDefinitionBindings = ""
        if (perm.RoleDefinitionBindings !== undefined && perm.RoleDefinitionBindings !== null && perm.RoleDefinitionBindings.results.length > 0) {

            for (let j = 0; j < 1; j++) {
                const r = perm.RoleDefinitionBindings.results[j];
                toAdd.RoleDefinitionBindings = r.Name;
                // toAdd.RoleDefinitionBindings = {
                //     Name: r.Name,
                //     Hidden: r.Hidden,
                //     Description: r.Description,
                //     RoleTypeKind: r.RoleTypeKind,
                //     Order: r.Order
                // };

            }
        }
        ret.push(toAdd);

    }
    console.dir("ret", ret);
    console.log(ret);
    return ret;
}

let url = "https://test.sharepoint.com/sites/csc";
debugger;
const datas = await getRoleDefinitionBindings(`${url}/_api/web`, "SiteCollection");


let csv = "type;MemberTitle;MemberEmail;MemberLoginName;MemberId;MemberDescription;Permission;TopLevel;UserMail;UserTitle;UserId;UserUserPrincipalName;IsSiteAdmin;IsShareByEmailGuestUser\n";
for (let k = 0; k < datas.length; k++) {
    const d = datas[k];
    let member = "";
    member += `${d.type};`
    member += `${d.Title};`
    member += `${d.Email};`
    member += `${d.LoginName};`
    member += `${d.Id};`
    member += `${d.Description ?? ""};`
    member += `${d.RoleDefinitionBindings};`
    csv += `${member}true;;;;;;\n`;
    //debugger;
    if (d.Users !== undefined) {
        for (let j = 0; j < d.Users.length; j++) {
            const user = d.Users[j];
            let u = `${member}false;`;
            u += `${user.Email};`;
            u += `${user.Title};`;
            u += `${user.Id};`;
            u += `${user.UserPrincipalName ?? ""};`;
            u += `${user.IsSiteAdmin};`;
            u += `${user.IsShareByEmailGuestUser}`;
            csv += `${u}\n`
        }
    }
}
console.log(csv);

PowerShell Compaire Property Items

On 26/05/2025


$ret1 = "PO-REQ-..2101.docx"
# $ret2 = "PO-RE..-2101.pdf"

$url1 = "https://test.sharepoint.com/sites/test/procedures";

$url2 = "https://test.sharepoint.com/sites/test/procedures"
Clear-Host
function ToPdf {
    param($fileName)

    $paths = $fileName.Split(".")
    if ($paths.Count -eq 2) {
        return "$($paths[0]).pdf"
    }
    if ($paths.Count -gt 2) {
        $ret = "";
        for ($i = 0 ; $i -lt $paths.Count - 1 ; $i++) {
            $ret += "$($paths[$i])" + "."
        }
        $ret += "pdf"
        return $ret
    }
    throw "Error : $($fileName)"
}



$list = "Work Instructions - Sources"
$list2 = "Work Instructions"
$ColumnsToCompaire = "Csc_Domain"
$ColumnRef = ""
$select = "Title,FileLeafRef,Csc_Domain,FileDirRef"

$buildSelet = ""
foreach ($col in ($select -split ",")) {
    $buildSelet += ""
}
$buildSelet += ""
$con1 = Connect-PnPOnline -Url $url1 -ReturnConnection -UseWebLogin
$con2 = Connect-PnPOnline -Url $url2 -ReturnConnection -UseWebLogin

$list1 = Get-PnPList -Identity $list -Connection $con1
Write-Host "list 1 : $($list1.ItemCount)"

$query = "<View Scope='RecursiveAll'><RowLimit>1000</RowLimit><OrderBy><FieldRef Name='Modified' Ascending='FALSE' /></OrderBy><Query><Where><Neq><FieldRef Name='FSObjType' /><Value Type='Integer'>1</Value></Neq></Where></Query>$($select)</View>"
$items1 = Get-PnPListItem -List $list -Connection $con1 -Query $query
$items2 = Get-PnPListItem -List $list2 -Connection $con2 -Query $query 

foreach ($item in $items1) {
    if ("$($item[$ColumnsToCompaire] )".Trim().ToLower() -eq "") {
        continue;
    }
    Write-Host ""
    Write-Host "list 1 : $($list1.ItemCount) item $($item.Id) ------------------"
    foreach ($col in ($select -split ",")) {
        Write-Host "item $($item.Id) '$($col)' : '$($item[$col])'"
        "item 1 $($item.Id) '$($col)' : '$($item[$col])'" | Out-File -LiteralPath ".\log\myLog_1.txt" -Encoding utf8 -Append
    }

    #$found = $items2 | Where-Object {$_.FileLeafRef -eq $item["FileLeafRef"]} #) -and $_.FileDirRef -eq $item["FileDirRef"]
    $founds = @();
    
    $toFound = ToPdf -fileName $item["FileLeafRef"]
    foreach ($found in $items2) {
        if ("$($toFound)".Trim().ToLower() -eq "$($found["FileLeafRef"])".Trim().ToLower()) {
            $founds += $found 
        }
    }

    if ($null -eq $founds) {
        Write-Error "File Error : $($item["FileLeafRef"]))" -ForegroundColor Yellow
    }
    elseif ($founds.Count -eq 0) {
        Write-Host "File ne found $($($item["FileLeafRef"])) -> $($toFound)" -ForegroundColor Yellow
        "File ne found $($($item["FileLeafRef"])) -> $($toFound)" | Out-File -LiteralPath ".\log\myLog_NotFound.txt" -Encoding utf8 -Append
    }
    elseif ($founds.Count -gt 1) {
        Write-Error "More than 1 file"
    }
    elseif ($founds.Count -eq 1) {
        if ($item[$ColumnsToCompaire] -ne $founds[0][$ColumnsToCompaire]) {
            Write-Host "to update"
            "to update  $($item.Id) '$($toFound)' - origine : '$($item[$ColumnsToCompaire])' - pdf : '$($founds[0][$ColumnsToCompaire])'" | Out-File -LiteralPath ".\log\myLog_2.txt" -Encoding utf8 -Append
            Set-PnPListItem -UpdateType SystemUpdate -Identity $founds[0].Id  -Connection $con2 -List $list2 -Values @{$ColumnsToCompaire = $item[$ColumnsToCompaire] }
            Write-Host "updated"
        }
    }
}

Sharepoint Rest Compaire 2 Lists Fields

On 25/03/2025


// Fonction pour comparer les champs de deux listes SharePoint
async function compareSharePointLists(urlSite1, urlSite2, ListRelativeUrl1, ListRelativeUrl2) {
    // Fonction auxiliaire pour obtenir les champs de la liste
    async function getListFields(urlSite, ListRelativeUrl) {
        const response = await fetch(`${urlSite}/_api/web/lists/getbytitle('${ListRelativeUrl}')/fields?$select=InternalName,TypeAsString`, {
            method: 'GET',
            headers: {
                'Accept': 'application/json;odata=verbose',
            },
        });

        if (!response.ok) {
            throw new Error(`Error fetching fields for list at ${ListRelativeUrl}: ${response.statusText}`);
        }

        const data = await response.json();
        return data.d.results;
    }

    try {
        // Obtenir les champs des deux listes
        const fields1 = await getListFields(urlSite1, ListRelativeUrl1);
        const fields2 = await getListFields(urlSite2, ListRelativeUrl2);

        // Comparer les champs
        fields1.forEach(field1 => {
            const matchingField = fields2.find(field2 => field2.InternalName === field1.InternalName);

            if (!matchingField) {
                console.log(`Le champ ${field1.InternalName} est manquant dans ${ListRelativeUrl2} de ${urlSite2}`);
            } else if (field1.TypeAsString !== matchingField.TypeAsString) {
                console.log(`Le type de champ ${field1.InternalName} ne correspond pas dans ${ListRelativeUrl2} de ${urlSite2} : ${field1.TypeAsString} vs ${matchingField.TypeAsString}`);
            }
        });

        fields2.forEach(field2 => {
            const matchingField = fields1.find(field1 => field1.InternalName === field2.InternalName);

            if (!matchingField) {
                console.log(`Le champ ${field2.InternalName} type ${field2.TypeAsString} est manquant dans ${ListRelativeUrl1} de ${urlSite1}`);
            }
        });
    } catch (error) {
        console.error('Erreur lors de la comparaison des champs des listes :', error);
    }
}

// Example usage
compareSharePointLists(
'https://test.sharepoint.com/sites/DoceboMigration', 
'https://test2.sharepoint.com/sites/fdiSandBox', 
'testConfiguration',
'fdiTasks');

Sharepoint List Groups And Permissions

On 24/03/2025


// Function to list all SharePoint groups of a site collection with their permission levels
async function listSharePointGroupsWithPermissions(siteUrl, targetDivId) {
    // Check if the siteUrl and targetDivId are provided
    if (!siteUrl || !targetDivId) {
        console.error("Site URL and target div ID must be provided.");
        // L'URL du site et l'ID de la div cible doivent être fournis.
        return;
    }

    // Construct the REST API URL to get the groups
    const groupsEndpoint = `${siteUrl}/_api/web/sitegroups`;

    try {
        // Fetch the groups from the SharePoint site
        const groupsResponse = await fetch(groupsEndpoint, {
            method: 'GET',
            headers: {
                'Accept': 'application/json;odata=verbose',
            },
        });

        // Check if the response is ok
        if (!groupsResponse.ok) {
            throw new Error(`Error fetching groups: ${groupsResponse.statusText}`);
            // Erreur lors de la récupération des groupes :
        }

        // Parse the JSON response
        const groupsData = await groupsResponse.json();
        const groups = groupsData.d.results;

        // Get the target div element
        const targetDiv = document.getElementById(targetDivId);
        if (!targetDiv) {
            throw new Error(`Target div with ID ${targetDivId} not found.`);
            // Div cible avec l'ID introuvable.
        }

        // Clear the target div
        targetDiv.innerHTML = '';
        
        const permsEndpoint = `${siteUrl}/_api/web/roleassignments?$expand=Member/users,RoleDefinitionBindings`;
        const permsResponse = await fetch(permsEndpoint, {
            method: 'GET',
            headers: {
                'Accept': 'application/json;odata=verbose',
            },
        })
        const permsData = await permsResponse.json();
            const roleAssignments = permsData.d.results;
        if (!permsResponse.ok) {
            throw new Error(`Error fetching roleassignments ${group.Title}: ${permsResponse.statusText}`);
            // Erreur lors de la récupération des utilisateurs pour le groupe
        }
        // Iterate through each group and display its information
        for (const group of groups) {
            // Fetch the role assignments for the group
            

            // Fetch the users in the group
            const usersEndpoint = `${siteUrl}/_api/web/sitegroups(${group.Id})/users`;
            const usersResponse = await fetch(usersEndpoint, {
                method: 'GET',
                headers: {
                    'Accept': 'application/json;odata=verbose',
                },
            });

            // Check if the response is ok
            if (!usersResponse.ok) {
                throw new Error(`Error fetching users for group ${group.Title}: ${usersResponse.statusText}`);
                // Erreur lors de la récupération des utilisateurs pour le groupe
            }

            // Parse the JSON response
            const usersData = await usersResponse.json();
            const users = usersData.d.results;

            // Create a div for the group
            const groupDiv = document.createElement('div');
            groupDiv.className = 'group';

            console.log(group.Title);
            // Create a header for the group
            const groupHeader = document.createElement('h3');
            groupHeader.textContent = `Group: ${group.Title}`;
            // Groupe :
            groupDiv.appendChild(groupHeader);

            // Create a list for the permission levels
            console.log("permissionsList", roleAssignments, group);
            const permissionsList = document.createElement('ul');
            roleAssignments.forEach(roleAssignment => {
                if(roleAssignment.PrincipalId == group.Id){
//Description Name
            roleAssignment.RoleDefinitionBindings.results.forEach(RoleDefinitionBinding => {
                    //RoleDefinitionBindings.results
                    const permissionItem = document.createElement('li');
                    permissionItem.textContent = `Permission Level: '${RoleDefinitionBinding.Name}' ${RoleDefinitionBinding.Description}`;
                    // Niveau de permission :
                    permissionsList.appendChild(permissionItem);
            });
                }
            });
            groupDiv.appendChild(permissionsList);

            // Create a list for the users in the group
            const usersList = document.createElement('ul');
            users.forEach(user => {
                const userItem = document.createElement('li');
                userItem.textContent = `User: ${user.Title}`;
                // Utilisateur :
                usersList.appendChild(userItem);
            });
            groupDiv.appendChild(usersList);

            // Append the group div to the target div
            targetDiv.appendChild(groupDiv);
        }
    } catch (error) {
        // Log the error to the console
        console.error(`Error: ${error.message}`);
        // Erreur :

        // Optionally, display the error message in the target div
        const targetDiv = document.getElementById(targetDivId);
        if (targetDiv) {
            targetDiv.innerHTML = `

Error: ${error.message}

`; //

Erreur : } } } // Example usage await listSharePointGroupsWithPermissions('https://test.sharepoint.com/sites/ssss', 'vpc_WebPart.unknown.a90bc6dc-fba2-4b5c-b7e2-f72005f01a14');

Sharepoint json formatting status icons

On 18/03/2025

Spicons


Here are the CSS classes used in JSON column formatting as sp-field-severity:

sp-field-severity--low: This class is used to indicate a low severity level. It typically applies a specific style to represent low urgency or importance1234.

sp-field-severity--good: This class is used to indicate a good or positive status. It applies a style that signifies a favorable condition1234.

sp-field-severity--warning: This class is used to indicate a warning level. It applies a style that signifies caution or a moderate level of urgency1234.

sp-field-severity--severeWarning: This class is used to indicate a severe warning level. It applies a style that signifies a high level of urgency or importance12354.

sp-field-severity--blocked: This class is used to indicate a blocked or critical status. It applies a style that signifies a very high level of urgency or a critical issue12354.

These classes are part of the SharePoint framework and are used to apply consistent styling across different columns based on the severity or status of the data.

{
  "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/column-formatting.schema.json",
  "elmType": "div",
  "attributes": {
    "class": "=if(@currentField == 'CheckMark', 'sp-field-severity--good', if(@currentField == 'Completed', 'sp-field-severity--good', if(@currentField == 'Forward', 'sp-field-severity--low', if(@currentField == 'Warning', 'sp-field-severity--warning', if(@currentField == 'Error', 'sp-field-severity--severeWarning', if(@currentField == 'ErrorBadge', 'sp-field-severity--blocked', '')))))) + ' ms-fontColor-neutralSecondary'"
  },
  "children": [
    {
      "elmType": "span",
      "style": {
        "display": "inline-block",
        "padding": "0 4px"
      },
      "attributes": {
        "iconName": "@currentField"
      }
    },
    {
      "elmType": "span",
      "txtContent": "@currentField"
    }
  ]
}




CheckMark
Completed
Error
Warning
Forward
ErrorBadge


Add
AddFriend
Admin
Airplane
Alert
AlignCenter
AlignLeft
AlignRight
Archive
ArrowDown
ArrowLeft
ArrowRight
ArrowUp
Attach
Back
Blocked
Bold
Bookmark
Calendar
Camera
Cancel
Checkbox
CheckboxComposite
CheckboxIndeterminate
Checkmark
ChevronDown
ChevronLeft
ChevronRight
ChevronUp
CircleRing
Clear
Clock
Close
Cloud
Code
CollapseMenu
Color
Comment
Contact
Copy
CreditCard
DataUsage
Delete
Dismiss
Document
Edit
Education
Emoji
Error
ErrorBadge
Event
Favorite
Filter
Flag
Folder
Forward
Gift
Globe
Group
Help
History
Home
Important
Info
Italic
Link
List
Location
Lock
Mail
Map
Megaphone
Mention
Message
More
Music
NavigateBack
NavigateForward
News
Note
Open
Paste
Pause
People
Phone
Photo
Pin
Play
Print
Product
Redo
Refresh
Remove
Reply
Save
Search
Send
Settings
Share
Shop
ShoppingCart
SignOut
Sort
Star
Status
Story
Tag
Task
Trash
Undo
Unlock
Upload
User
Video
View
Warning
Work



PowerShell SharePoint Search Extract File Content

On 12/03/2025


# Parameters
$siteUrl = "https://xxxx.sharepoint.com/sites/xxxx"
$outputFilePath = "report4.txt"
$doclibpath = "/Connectivity"

# Connect to the SharePoint site
Connect-PnPOnline -Url $siteUrl -UseWebLogin

# Initialize the output file
if (Test-Path $outputFilePath) {
    Remove-Item $outputFilePath
}
New-Item -Path $outputFilePath -ItemType File

# Define the search query to find '.url' files
$query = "Path:$($siteUrl)* And FileExtension:url"
$query = "Path:$($siteUrl)$($doclibpath)* And *.url"

# Execute the search query
$searchResults = Submit-PnPSearchQuery -Query $query -ErrorAction Stop -All -TrimDuplicates $true -SelectProperties "Path,FileName"
Write-Host "nb files found $($searchResults.TotalRows)"
# Check if there are any search results
if ($null -eq $searchResults -or $searchResults.TotalRows -eq 0) {
    Write-Host "No '.url' files found in the search results."
    Exit
}

# Initialize a variable to store combined content
$combinedContent = ""
$count = 0;
# Iterate through each search result
foreach ($result in $searchResults.ResultRows) {# ResultRows PrimarySearchResults
    # Get the file URL 
    $fileUrl = $result.Path
    if(-not $result.Path.ToLower().EndsWith(".url")){
        continue;
    }
    $count++;
    # Get the file content
    $fileContent = $null;
    # $fileContent = Get-PnPFileContent -Url $fileUrl -AsString -ErrorAction Stop
    try {
        $fileContent = Get-PnPFile -Url $fileUrl.Replace("https://eutelsatgroup.sharepoint.com", "") -AsString 
    }
    catch {
        Write-Host "File '$($fileUrl)' error. $($_)"
        continue;
    }
    #$fileContent = Get-PnPFile -Url $fileUrl -AsString
    # Check if the file content is null or empty
    if ([string]::IsNullOrEmpty($fileContent)) {
        Write-Host "File '$fileUrl' is empty or null."
        continue
    }

    # Append the file content to the combined content
    $combinedContent += $result.FileName + "`n"
    $combinedContent += $fileUrl + "`n"
    $combinedContent += $fileContent + "`n`n"
}

# Write the combined content to the output file
Add-Content -Path $outputFilePath -Value $combinedContent

# Disconnect from SharePoint Online
Disconnect-PnPOnline

Write-Host "nb files treated: $($count) Combined content written to '$($outputFilePath)'."

Fluent Ui Componants List

On 25/02/2025

Fluent UI Components and Properties

Button

Property Description
text The text to display on the button.
iconProps Properties to pass to the icon.
onClick Callback for when the button is clicked.
disabled Whether the button is disabled.

TextField

Property Description
label The label for the text field.
value The value of the text field.
onChange Callback for when the value changes.
placeholder Placeholder text for the text field.
disabled Whether the text field is disabled.

Dropdown

Property Description
label The label for the dropdown.
options Array of options to display in the dropdown.
selectedKey The key of the selected option.
onChange Callback for when the selected option changes.
placeholder Placeholder text for the dropdown.
disabled Whether the dropdown is disabled.

Checkbox

Property Description
label The label for the checkbox.
checked Whether the checkbox is checked.
onChange Callback for when the checkbox is toggled.
disabled Whether the checkbox is disabled.

Toggle

Property Description
label The label for the toggle.
checked Whether the toggle is checked.
onChange Callback for when the toggle is toggled.
disabled Whether the toggle is disabled.

Modal

Property Description
isOpen Whether the modal is open.
onDismiss Callback for when the modal is dismissed.
isBlocking Whether the modal is blocking.
containerClassName Custom class name for the modal container.

Panel

Property Description
isOpen Whether the panel is open.
onDismiss Callback for when the panel is dismissed.
headerText The text to display in the panel header.
closeButtonAriaLabel The ARIA label for the close button.

DetailsList

Property Description
items Array of items to display in the list.
columns Array of column definitions.
onItemInvoked Callback for when an item is invoked.
selection Selection object to manage selected items.

Icon

Property Description
iconName The name of the icon to display.
style Custom styles for the icon.
className Custom class name for the icon.

Spinner

Property Description
label The label for the spinner.
size The size of the spinner (e.g., 'small', 'medium', 'large').
ariaLive The ARIA live region attribute.

MessageBar

Property Description
messageBarType The type of the message bar (e.g., 'info', 'success', 'warning', 'error').
isMultiline Whether the message bar should display multiple lines.
onDismiss Callback for when the message bar is dismissed.
dismissButtonAriaLabel The ARIA label for the dismiss button.

Sharepoint List get list fields in console

On 20/02/2025


function getUrlParams() {
  const params = new URLSearchParams(window.location.search);
  const urlParams = {};
  for (const [key, value] of params.entries()) {
    urlParams[key] = value;
  }
  return urlParams;
}
async function getSharePointListFields(listId) {
  const apiUrl = `${_spPageContextInfo.webAbsoluteUrl}/_api/web/lists(guid'${listId}')/fields?$select=InternalName&$orderby=InternalName&$filter=Hidden eq false`;

  try {
    const response = await fetch(apiUrl, {
      method: 'GET',
      headers: {
        'Accept': 'application/json;odata=verbose',
        'Content-Type': 'application/json;odata=verbose',
      },
      credentials: 'include', // Include credentials for authenticated requests
    });

    if (!response.ok) {
      throw new Error('Network response was not ok');
    }

    const data = await response.json();
    return data.d.results;
  } catch (error) {
    console.error('Error fetching SharePoint list fields:', error);
    return [];
  }
}
// Usage
const urlParams = getUrlParams();
const listId = urlParams.List;
window.Fields = "";
if (listId) {
  getSharePointListFields(listId).then((fields) => {
    console.log('SharePoint List Fields:', fields);
    // Process the fields as needed
	fields.map((f) => {
	window.Fields += `${f.InternalName}\n`;
		
	});
    console.log(window.Fields);
  });
} else {
  console.error('List ID not found in URL parameters');
}


SharePoint Sites.Selected

On 03/02/2025

How to give permission for an Azure app you has permission : Sites.Selected

You must be admin of Azure

In Graph Explorer use this request to get the Azure Id of you Site

Add for permission Sites.selected and Site.FullControl for the account (in modify permissions Tab)

Graphexplorerpermissions

 

https://graph.microsoft.com/v1.0/sites/m365x87466739.sharepoint.com:/sites/allcompany?$select=id

replace the m365x87466739 by your Tenant name, and allcompany by the name / url of your site, 

it wiil returns you the azure id of your site


{
    "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#sites(id)/$entity",
    "id": "m365x87466739.sharepoint.com,1dc83cb4-d304-4afa-a0ff-cf33270f1c8b,e615f00e-ac05-4dfc-928e-e51688e8273b"
}

Then post a news query https://graph.microsoft.com/v1.0/sites/m365x87466739.sharepoint.com,1dc83cb4-d304-4afa-a0ff-cf33270f1c8b,e615f00e-ac05-4dfc-928e-e51688e8273b/permissions

 


{
  "roles": ["write"],//permission level you want to give
  "grantedToIdentities": [{
    "application": {
      "id": "9fb5c53a-5f25-4100-ba33-9a4595390c27",//this is you App Id
      "displayName": "AppSharePointDocebo"
    }
  }]
}

then you can use Connect-PnPOnline -Url $siteUrl -ClientId $clientId -Thumbprint $thumbprint -Tenant $tenantId

Postsite selectedpng

 

You can use site.url /_layouts/15/appinv.aspx opage, but you must be site coll Admin, and admin SharePoint on Azure

 

<AppPermissionRequests AllowAppOnlyPolicy="true">
<AppPermissionRequest Scope="https://myTrenant.sharepoint.com/sites/sites/site1" Right="FullControl" />
    </AppPermissionRequests>
 

Fileshare Migration to SharePoint

On 07/01/2025

Use SharePoint Migration Tool to upload your folder in a document library, here base settings in a json file

{
  "Tasks": [
    {
      "SourcePath": "\\\\mySite.fr\\divisions\\Processed matrices\\Doc1",
      "TargetPath": "https://test.sharepoint.com/sites/test1",
      "TargetList": "FDbase",
      "TargetListRelativePath": "Satellites/Doc1",
      "Options": {
        "PreserveFileSharePermissions": false,
        "MigrateHiddenFiles": true,
        "MigrateReadOnlyFiles": true,
        "PreserveLastModifiedTime": true,
        "PreserveCreatedTime": true,
        "SkipEmptyFolders": false
      }
    }
  ]
}