SharepointOnLine

Usefull informations for Sharepoint On Line

SharePoint List Json Formating

On 09/12/2024

JSON Formatting in SharePoint Online: A Comprehensive Guide

JSON formatting in SharePoint Online enables users to customize the visual presentation of list and library data without requiring complex code. It allows for dynamic styling, icons, calculated values, and even conditional formatting based on field data. In this article, we’ll explore JSON formatting basics, advanced examples, limitations, and best practices.

Microsoft reference

GitHub reference

 

What is JSON Formatting in SharePoint Online?

JSON formatting is a declarative approach to customize how fields, rows, or views appear in SharePoint lists and libraries. It involves writing JSON code that defines the logic and styling based on field values.

 

Examples of JSON Formatting

1. Change Background Color Based on Approval Status

If the field "ApprovalStatus" has a value of `"pending"`, set the background color to yellow. JSON Code:


{
  "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/column-formatting.schema.json",
  "elmType": "div",
  "style": {
    "background-color": "=if(@currentField == 'pending', '#FFFF00', '')",
    "padding": "5px"
  },
  "txtContent": "@currentField"
}

 

2. Display an Alert Icon if Cost Equals 100 Add a warning icon next to the Cost field if its value is `100`. JSON Code:


{
  "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/column-formatting.schema.json",
  "elmType": "div",
  "children": [
    {
      "elmType": "span",
      "txtContent": "@currentField"
    },
    {
      "elmType": "span",
      "style": {
        "margin-left": "10px",
        "color": "red"
      },
      "attributes": {
        "iconName": "Warning"
      },
      "condition": "=if(@currentField == 100, true, false)"
    }
  ]
}

3. Concatenate Two Fields Combine two text fields, FirstName and LastName, into a single formatted output. JSON Code:


{
  "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/column-formatting.schema.json",
  "elmType": "div",
  "txtContent": "='Full Name: ' + [$FirstName] + ' ' + [$LastName]"
}

4. Add 3 Days to a Date Field Display a date that is 3 days later than the value in a field called StartDate. JSON Code:


{
  "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/column-formatting.schema.json",
  "elmType": "div",
  "txtContent": "=formatDate(addDays(@currentField, 3), 'yyyy-MM-dd')"
}

Limitations of JSON Formatting

1. Read-Only:

 - JSON formatting is purely visual; it does not change the actual field value or data in the list.

2. Complex Logic:

- While simple conditions are supported, JSON formatting cannot handle complex business logic or external data calls.

3. Limited Interactivity:

- JSON formatting cannot create interactive elements like buttons with advanced event handling.

4. Field Dependencies:

- If a calculated field is hidden in the view, JSON that relies on it may break.

5. Performance Impact:

- Excessive formatting, especially on large lists, may slow down rendering.

 

Best Practices for JSON Formatting

1. Keep it Simple:

- Avoid overly complex JSON. Keep the code readable and maintainable.

2. Validate JSON:

- Use online JSON validators or tools like VS Code with JSON extensions to catch syntax errors.

3. Optimize for Performance:

- Test formatting on large lists to ensure it doesn’t degrade performance.

4. Use Conditional Logic:

- Use `if` statements sparingly and test all possible conditions.

5. Test Across Browsers:

- Ensure formatting looks consistent across browsers, especially for icons and colors.

6. Document Your JSON:

- Add comments (externally, as SharePoint JSON doesn’t support comments) to document logic and purpose.

Conclusion

JSON formatting in SharePoint Online is a powerful tool to enhance list and library views. By applying dynamic styling and conditional logic, you can improve data visualization and user experience. However, its read-only nature and complexity for advanced scenarios mean it’s best suited for lightweight customizations.

By following best practices and understanding its limitations, you can use JSON formatting effectively in your SharePoint projects.

SharePoint get by Rest List Role DefinitionBindings

On 28/10/2024


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 = `
    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 {
            max-height: 800px;
            overflow-y: auto;
            border: 1px solid #ddd;
        }
        /* 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 === "RoleDefinitionBindings") {
                    cell.appendChild(generateTableFromJson2(item.RoleDefinitionBindings.results, "Name,Id", false));
                } 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;
}

// Function to get permissions for a SharePoint group
async function getSharePointPermissions(siteUrl, select) {

    // REST API endpoint to get group permissions
    const endpoint = `${siteUrl}`;

    // Fetch options with headers for authentication and response format
    const fetchOptions = {
        method: 'GET',
        headers: {
            'Accept': 'application/json;odata=verbose'
        }
    };

    console.log("endpoint", endpoint);
    // Send the asynchronous GET request to the REST API endpoint
    const response = await fetch(endpoint, fetchOptions);

    // Check if the response is OK (status code 200)
    if (!response.ok) {
        throw new Error(`Error fetching permissions: ${response.statusText}`);
    }

    // Parse the JSON response to extract permission data
    const data = await response.json();

    // Extract role assignments (permissions)
    const roleAssignments = data.d.results;
    console.log('roleAssignments', roleAssignments);
    console.log(JSON.stringify(roleAssignments));

    const D1 = removeSlasches(select, roleAssignments)
    const pattern2 = /\//g;
    console.log("json111", JSON.stringify(D1));
    const table = generateTableFromJson2(D1, select.replace(pattern2, ""));
    // Append the table to the container
    document.getElementById('tableContainer').appendChild(table);
}

// Usage example: Replace 'your-group-id' and 'your-site-url' with actual values
const select = "Member/Title,Member/Id,Member/LoginName,RoleDefinitionBindings";
let siteUrl = 'https://mySite.sharepoint.com/sites/Dev_wf';
siteUrl += `/_api/web/roleassignments/?$expand=RoleDefinitionBindings,Member&$select=${select}`; // Replace with the actual site URL
document.body.innerHTML = `<div id="tableContainer" class="table-wrapper"></div>`; await getSharePointPermissions(siteUrl, select); 

 

Permissions

Power Apps Limit 500 WorkArround

On 25/09/2024

Power Apps Limit WorkArround 500

The column Id hit type is counter, we cannot use it to filter if we have more than 500 items with "<" ou ">"

But with created we can use delegation with > and <

You can build a pagination with date filtering

Powerappslimit500listApp loading

Settingsbutton next

Powerappsnext 1button previous

Powerappslimit back

Buttons

 

Get User Permissions By Mail And Javascript

On 09/09/2024

Get User Permissions By Mail And Javascript

 


let siteUrl = "https://mayTenant.sharepoint.com/sites/test"

async function getUserPermissions(siteUrl, userMail) {

    // REST API endpoint to get group permissions
    const endpoint = `${siteUrl}/_api/web/siteusers?$filter=Email eq '${userMail}'&$select=Id`;
    //const endpoint = `${siteUrl}/_api/web/siteusers?$filter=Email eq '${userMail}'&$select=LoginName`;

    // Fetch options with headers for authentication and response format
    const fetchOptions = {
        method: 'GET',
        headers: {
            'Accept': 'application/json;odata=verbose'
        }
    };

    console.log("endpoint", endpoint);
    // Send the asynchronous GET request to the REST API endpoint
    const response = await fetch(endpoint, fetchOptions);

    // Check if the response is OK (status code 200)
    if (!response.ok) {
        throw new Error(`Error fetching permissions: ${response.statusText}`);
    }

    // Parse the JSON response to extract permission data
    const data = await response.json();
    console.log("data", data);

    if (data.d.results.length === 0) {
        console.log("user not found", userMail);
    } else {

        const userId = `${data.d.results[0].Id}`;
        for (const user in data.d.results) {

            console.log("user", userMail);
        }
        let ret = "";
        const endpoint2 = `${siteUrl}/_api/web//RoleAssignments/GetByPrincipalId(${userId})/RoleDefinitionBindings`;
        // Send the asynchronous GET request to the REST API endpoint
        const response2 = await fetch(endpoint2, fetchOptions);
        const data2 = await response2.json();
        console.log("data2", data2);
        for (let i = 0; i < data2.d.results.length; i++) {
            ret += `User ${data2.d.results[0].Name} : ${data2.d.results[0].Description}\r\n`;
        }

        //by groups
        const getGroupsEndPoint = `${siteUrl}/_api/web/GetUserById(${userId})/groups?$select=Id,Title`;
        const response3 = await fetch(getGroupsEndPoint, fetchOptions);
        const data3 = await response3.json();
        console.log("data3", data3);

        for (let i = 0; i < data3.d.results.length; i++) {
            //get group permissions
            const endpoint4 = `${siteUrl}/_api/web//RoleAssignments/GetByPrincipalId(${data3.d.results[i].Id})/RoleDefinitionBindings`;
            const response4 = await fetch(endpoint4, fetchOptions);
            const data4 = await response4.json();
            console.log("data4", data4);
            for (let j = 0; j < data4.d.results.length; j++) {
                ret += `Group ${data3.d.results[i].Title} Id ${data3.d.results[i].Id} : ${data4.d.results[j].Name} : ${data4.d.results[j].Description}. ` + "\r\n";
            }
        }

        return `${ret}.`;
    }
    return null;
}


await getUserPermissions(siteUrl, "test-ext@test.com");

Permissions to Check:

Here are some common permissions encoded in the High and Low values:

  • ViewListItems: 0x00000001
  • AddListItems: 0x00000002
  • EditListItems: 0x00000004
  • DeleteListItems: 0x00000008
  • OpenItems: 0x00000010
  • ViewVersions: 0x00000020
  • CancelCheckout: 0x00000040
  • ManagePermissions: 0x00010000
  • ManageWeb: 0x00040000

Manage SharePoint/ Teams Permissions

On 09/09/2024

How to manage SharePoint / Teams permissions

In every Teams, in background there is a SharePoint site.

How to access SharePoint associated with Teams

Browse your Teams files

1.Clic on “Files” tab
2.Clic on three bullets
3.Select “Open in SharePoint”
01 accestoteams 1
Access SharePoint site permission management
1.Clic on SharePoint « Settings » icon
2.Click on « Site permissions » link
3.Click « advanced permissions settings »
02 linkpermissions

 

 

03 access permissions

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Check user / Office 365 group permission

On SharePoint site advanced permissions page you can check user / Office 365 group permissions

04 checkpermissions

 

 

 

 

 

 

 

 

 

 

 

 

 

 

SharePoint standard defaults groups

On SharePoint Site creation, by default 3 groups are created

1.Owners
1.Full control permission
2.Member
1.Read / Write permission
3.Read
1.Read permission
 

By default, all content on the SharePoint site inherits permissions from the parent SharePoint site.

Allow only a few members or group for a folder

You can set specific permissions in SharePoint / Teams for :

Document library
Sub site
SharePoint list
Folder
Document
 

For each person / groups, you can set permission level :

Full control
Read / write
Read / write / but not delete
Read

 

Allow only a few members or group for a folder

1.Clic on three bullets on target folder
2.Clic “Manage access”
3.Clic three bullets
4.Clic “Advanced settings”

04 checkpermissions

 

 

 

 

 

 

 

 

 

 

 

 

 

By defaut the folder inherits parent folder or library permission, to break permissions and apply new ones :

1.Clic « Stop inheriting permissions »
2.Select available groups / users (to remove them or edit their permissions)
3.Remove user / group
4.Edit user / group permission (for read => read write per exemple)
5.Grant permission to a new user or group
6.Re inherite permissions (reset) from parent folder or document library
7.Check specifc user ou group permissions

 

06 delepermissions

 

 

 

 

 

 

 

 

 

 

Create specific permissions (Read / write but not delete)

By default in SharePoint we have 5 permissions levels

You can clic on default permission level to affine them but

 it’s not a good practice

.

To add a new permission level (in site permissions)

1.Clic permissions levels
2.Clic “Add a Permission level”
3.Name your permission
4.Check you required permissions
1.But uncheck “delete items”

 

07 permissionslevels

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Share / give permission to external user

Sharing with external users governance is managed at Tenant level

By default a Teams “private channel” cannot be Shared with externals users / domain 

With public site or channel, your can Share your SharePoint site :

1.Clic on site settings icon
2.Clic on “Site permissions” link
3.Clic on “Add members”
4.Select “Share site only”
5.Type user mail
6.Select the user and define his permission (Read, Edit or full control)
7.Clic on Add button

 

08 shareexternal

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

vvvvvx

 

ccc

SharePoint Format Date In View With JSON

On 06/09/2024

Format date background color in your SharePoint list with JSON

Json dateformatting

 


{
    "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/column-formatting.schema.json",
    "elmType": "div",
    "txtContent": "@currentField",
    "style": {
       "background-color": 
       {
          "operator": "?",
          "operands": [
             {
                "operator": ">=",/*if the date is greater than tomorrow  24x60x60x1000 = 86400000 = 1day    */
                "operands": [
                   "@currentField",
                   {
                      "operator": "+",
                      "operands": [
                         "@now",
                         86400000
                      ]
                   }
                ]
             },
             "red",
             {
                "operator": "?",
                "operands": [
                   {
                      "operator": "<=",/*if the date is less than today - 60 days*/
                      "operands": [
                         "@currentField",
                         {
                            "operator": "-",
                            "operands": [
                               "@now",
                               5184000000 /* 86400000 x 60 */
                            ]
                         }
                      ]
                   },
                   "yellow",
                   "transparent"
                ]
             }
          ]
       }
    }
  }

Gestion des droits dans SharePoint On line Bonnes Pratiques Conseils

On 06/09/2024

La gestion des droits et des autorisations dans SharePoint Online est un aspect crucial pour garantir la sécurité et l'efficacité de la collaboration au sein d'une organisation. Une bonne gestion des droits aide à maintenir la confidentialité des données, réduit le risque d’erreurs et garantit que les utilisateurs peuvent accéder aux informations dont ils ont besoin, sans compromettre la sécurité.

Voici un aperçu des bonnes pratiques et des mauvaises pratiques en matière de gestion des droits dans SharePoint Online.

 Bonnes Pratiques de Gestion des Droits dans SharePoint Online

 1. Utiliser les Groupes de Sécurité et de SharePoint
   - Bonnes pratiques : Utilisez des groupes SharePoint ou des groupes de sécurité pour gérer les autorisations au lieu d’attribuer des droits directement à des utilisateurs individuels. Les groupes facilitent l’administration des droits et permettent une gestion plus efficace des utilisateurs.
    - Exemple : Créer des groupes comme "Contributeurs", "Lecteurs", "Admins" pour les différents niveaux d’accès et affecter les utilisateurs à ces groupes.
   - Pourquoi ? : Il est plus facile de gérer les autorisations en fonction des rôles et des équipes. Vous pouvez ajouter ou retirer des utilisateurs des groupes sans devoir réviser chaque autorisation individuellement.

 2. Hériter des Autorisations
   - Bonnes pratiques : Par défaut, les sites, les bibliothèques de documents et les listes héritent des autorisations de leur site parent. Cela permet de garder les autorisations cohérentes et plus faciles à gérer. Rompez l'héritage uniquement lorsqu'il est absolument nécessaire.
   - Pourquoi ? : Limiter les ruptures d’héritage rend la gestion des autorisations plus simple et cohérente. Cela aide à réduire les erreurs liées à des autorisations mal configurées sur des objets individuels.

 3. Appliquer le Principe du Moindre Droit (Least Privilege)
   - Bonnes pratiques : Donnez aux utilisateurs uniquement les permissions dont ils ont besoin pour accomplir leur travail. Par exemple, si un utilisateur a seulement besoin de lire des documents, ne lui donnez pas des droits de modification.
   - Pourquoi ? : Cela réduit les risques d’erreurs humaines et améliore la sécurité en limitant l'accès inutile aux fonctionnalités ou aux données sensibles.

 4. Utiliser les Modèles de Permissions Standard
   - Bonnes pratiques : Utilisez les modèles de permissions par défaut fournis par SharePoint, tels que "Contributeur", "Lecteur", "Propriétaire", au lieu de créer des niveaux de permissions personnalisés. Les permissions standard sont bien connues et bien documentées, facilitant la gestion.
   - Pourquoi ? : Les modèles standards garantissent une bonne compréhension des rôles et réduisent la complexité de la gestion des autorisations.

 5. Effectuer des Audits et des Revues Périodiques des Permissions
   - Bonnes pratiques : Révisez régulièrement les autorisations sur les sites SharePoint pour s'assurer que les utilisateurs n'ont pas plus de permissions que nécessaire, et que les anciennes autorisations inutiles sont révoquées.
   - Pourquoi ? : Avec le temps, des utilisateurs peuvent accumuler des permissions inutiles, ce qui augmente le risque de fuites de données ou d’accès non autorisé.

 6. Utiliser la Gestion des Accès Conditionnels et Azure AD
   - Bonnes pratiques : Pour les entreprises utilisant Azure Active Directory, configurez des politiques d'accès conditionnel qui obligent l'utilisation de la Multi-Factor Authentication (MFA) et des restrictions d'accès basées sur l'emplacement.
   - Pourquoi ? : Ces pratiques renforcent la sécurité en s'assurant que seuls les utilisateurs autorisés, se connectant de manière sécurisée, ont accès à vos données SharePoint.

 7. Documenter les Modifications de Permissions
   - Bonnes pratiques : Chaque changement d'autorisation doit être documenté, en notant pourquoi il a été effectué, par qui et pour quelle durée. Cette documentation aide lors d'audits futurs ou de la résolution de problèmes.
   - Pourquoi ? : Cela facilite la gestion à long terme, permet de retracer les modifications en cas de problème et contribue à la conformité des données.

 

 Mauvaises Pratiques de Gestion des Droits dans SharePoint Online

 1. Donner des Permissions Directes à des Utilisateurs Individuels
   - Mauvaise pratique : Attribuer des droits directement à des utilisateurs au lieu d'utiliser des groupes.
   - Pourquoi c'est un problème ? : Gérer les autorisations devient difficile lorsque les utilisateurs quittent l'organisation ou changent de rôle. Cela rend également la gestion des droits plus complexe et propice aux erreurs.

 2. Rompre l'Héritage des Permissions Trop Souvent
   - Mauvaise pratique : Rompre l'héritage des autorisations à plusieurs niveaux (par exemple, sur des fichiers ou des sous-dossiers individuels).
   - Pourquoi c'est un problème ? : Cela complique énormément la gestion des permissions. Vous pouvez perdre le contrôle de qui a accès à quoi, et il devient facile de faire des erreurs en octroyant ou en révoquant des droits.

 3. Donner Trop de Permissions (Trop de Propriétaires)
   - Mauvaise pratique : Donner des droits de propriétaire ou des droits d'édition à trop de personnes.
   - Pourquoi c'est un problème ? : Les propriétaires peuvent modifier des paramètres critiques, ce qui peut affecter la structure du site et les permissions des autres utilisateurs. Cela augmente également le risque d’erreurs ou d’accès non autorisé à des informations sensibles.

 4. Ne Pas Révoquer les Permissions des Anciens Utilisateurs
   - Mauvaise pratique : Ne pas retirer les autorisations d’utilisateurs qui ne sont plus actifs dans le projet ou l'organisation.
   - Pourquoi c'est un problème ? : Des anciens utilisateurs peuvent encore avoir accès à des informations sensibles. Cela représente un risque de sécurité majeur, surtout si ces utilisateurs ne sont plus sous votre contrôle.

 5. Ne Pas Gérer les Permissions sur les Documents Sensibles
   - Mauvaise pratique : Donner des droits larges sur des documents sensibles sans les protéger spécifiquement (par exemple, via une bibliothèque dédiée avec des permissions restreintes).
   - Pourquoi c'est un problème ? : Cela peut conduire à des fuites de données, où des utilisateurs qui n’ont pas besoin d’accéder à des documents critiques y ont tout de même accès.

 6. Ne Pas Utiliser les Groupes O365/AAD pour Simplifier la Gestion
   - Mauvaise pratique : Ne pas intégrer les groupes Office 365/Azure Active Directory pour la gestion des droits SharePoint.
   - Pourquoi c'est un problème ? : Ne pas tirer parti des groupes centralisés complique la gestion des utilisateurs et peut entraîner des redondances ou des erreurs de permissions.

 7. Manque de Documentation sur les Modifications des Permissions
   - Mauvaise pratique : Modifier les autorisations sans documentation claire.
   - Pourquoi c'est un problème ? : En l'absence de documentation, il devient difficile de savoir qui a modifié quoi, pourquoi et quand. Cela complique les audits et rend le diagnostic des problèmes d’accès plus long.

 

 Conclusion

La gestion des droits dans SharePoint Online doit être effectuée avec soin pour assurer la sécurité et l'efficacité. En suivant les bonnes pratiques, vous pouvez éviter des problèmes tels que des accès non autorisés, des erreurs de configuration, et des difficultés de gestion à long terme. Évitez les mauvaises pratiques qui peuvent entraîner une confusion dans la gestion des permissions et augmenter le risque de failles de sécurité.

Une gestion rigoureuse des droits est cruciale pour protéger les informations sensibles et assurer que les utilisateurs accèdent seulement aux ressources nécessaires à leur travail.

Sharepoint REST roleassignments Break

On 14/05/2024

roleassignments

 


_api/lists/getByTitle('myLList')/items(2)/roleassignments/addroleassignment(principalid=15)},roledefid=1073741826)

break role inheritance


_api/lists/getByTitle('@{triggerBody()?['ListTitle']}')/items(@{int(triggerBody()['ItemId'])})/breakroleinheritance(copyRoleAssignments=false,clearSubscopes=true)

get role assigments ids

 


/_api/Web/RoleDefinitions?$select=Name,Description,Id

Roledefinitions

Name Description Id

Full ControlHas full control.1073741829

DesignCan view, add, update, delete, approve, and customize.1073741828

EditCan add, edit and delete lists; can view, add, update and delete list items and documents.1073741830

ContributeCan view, add, update, and delete list items and documents.1073741827

ReadCan view pages and list items and download documents.1073741826

Restricted ViewCan view pages, list items, and documents. Documents can be viewed in the browser but not downloaded.1073741832

Limited AccessCan view specific lists, document libraries, list items, folders, or documents when given permissions.1073741825

System.LimitedViewnull1073741924

System.LimitedEditnull1073741925

 

JSON Formatting Show File Size

On 03/05/2023

Show File size in kilo bytes in sharepoint list

 


{
  "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/column-formatting.schema.json",
  "elmType": "div",
  "attributes": {
  },
  "style": {
    "flex-directon": "row",
    "justify-content": "left",
    "align-items": "center",
    "flex-wrap": "nowrap"
  },
  "children": [
    {
      "elmType": "span",
      "txtContent": "=[$File_x0020_Size]/1000 + ' kbytes'"
    }
  ]
}

 

Get Sharepoint Audit Logs

On 05/04/2023

Create certification for azure app

    
        # Create certificate
        $mycert = New-SelfSignedCertificate -DnsName "myCertificate.org" -CertStoreLocation "cert:\CurrentUser\My" -NotAfter (Get-Date).AddYears(1) -KeySpec KeyExchange
        
        $mypwd = ConvertTo-SecureString -String "myCertificatePsw" -Force -AsPlainText
        # Export certificate to .pfx file
        $mycert | Export-PfxCertificate -FilePath myCertificate.pfx -Password $mypwd
        
        # Export certificate to .cer file
        $mycert | Export-Certificate -FilePath myCertificate.cer  
    

Connect to site

    
        $url = "https://m365x6422vvvvd.sharepoint.com/";
        $appId = "868d7a0c-a3dc-45af-b4a7-f72a70f61a60";
        $thumbprint = "A17177BB0E8A465F6AD08B0CEAE2F369C46D6481";
        $tenantId = "3533ab30-c2f0-48fd-b4c5-f5dc6ca77ec3"

        Connect-PnPOnline  -Url $url -Tenant $tenantId -Thumbprint $thumbprint -ClientId $appId
    

Export audit

premission required

Office 365 Management APIs (3) :: ActivityFeed.Read

possible filters

  • FilePreviewed
  • FileAccessed
  • SignInEvent
  • FileModifiedExtended
  • FileUploaded
  • PageViewed
  • PagePrefetched
  • FileCheckedIn
  • FileModified
  • FolderCreated
  • ListUpdated
  • ListViewed
    
        $ele = Get-PnPUnifiedAuditLog -ContentType SharePoint -StartTime (Get-Date).AddDays(-2) -EndTime (Get-Date).AddDays(-1)

        $ele = Get-PnPUnifiedAuditLog -ContentType SharePoint

        $ele = Get-PnPUnifiedAuditLog -ContentType SharePoint | Where-Object {$_.Operation -eq "PageViewed"} | Select-Object CreationTime,Operation,Workload,UserId,ObjectId,SourceFileName,SiteUrl,SourceFileExtension,SourceRelativeUrl

        $ele | Export-Csv -Path "Audit_3.csv" -Encodin:UTF8 -NoTypeInformation -Delimiter ";"
    

with sharepoint search request

    
        kqlQuery = "ContentTypeId:0x0101009D1CB255DA76424F860D91F20E6C4118*";//news
        kqlQuery = "ContentTypeId:0x0101* language=fr ViewsLastMonths3=0";//documents
        kqlQuery = "ContentTypeId:0x0101* ViewsLifeTime=0";
        var seletvvv = "Title,ViewsLifeTimeUniqueUsers,ViewsLifeTime,language,Created,Size,Path,LastModifiedTime,ViewsLastMonths3,ViewsLastMonths3Unique,LastAnalyticsUpdateTime";

        &sortlist='Size:descending'
        &sortlist='ViewsLifeTime:descending'
    

Connect Sharepoint With AppID Certificate

On 21/03/2023

Connect to Sharepoint using app registration and certificate

 



using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Graph;
using PnP.Core.Auth;
using PnP.Core.Auth.Services.Builder.Configuration;
using PnP.Core.Services;
using PnP.Core.Services.Builder.Configuration;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;


namespace HGH.Buisiness4
{
    public class SPTools2 : IDisposable
    {
        private IHost _host;


        public SPTools2()
        {

        }

        public async Task Connect(string appId, string tenantId, string siteUrl, string thumbprint, StoreName storeName, StoreLocation storeLocation)
        {
            try
            {
                _host = Host.CreateDefaultBuilder()
               .ConfigureServices((hostingContext, services) =>
               {
                   // Add the PnP Core SDK library
                   services.AddPnPCore(options =>
                   {
                       options.Sites.Add("SiteToWorkWith", new PnPCoreSiteOptions
                       {
                           SiteUrl = siteUrl
                       });
                   });
                   services.AddPnPCoreAuthentication(
                       options =>
                       {
                           // Configure an Authentication Provider relying on Windows Credential Manager
                           options.Credentials.Configurations.Add("x509certificate",
                               new PnPCoreAuthenticationCredentialConfigurationOptions
                               {
                                   ClientId = appId,
                                   TenantId = tenantId,
                                   X509Certificate = new PnPCoreAuthenticationX509CertificateOptions
                                   {
                                       StoreName = storeName,
                                       StoreLocation = storeLocation,
                                       Thumbprint = thumbprint
                                   }
                               });

                           // Configure the default authentication provider
                           options.Credentials.DefaultConfiguration = "x509certificate";

                           // Map the site defined in AddPnPCore with the 
                           // Authentication Provider configured in this action
                           options.Sites.Add("SiteToWorkWith",
                               new PnPCoreAuthenticationSiteOptions
                               {
                                   AuthenticationProviderName = "x509certificate"
                               });
                       });


               })
            // Let the builder know we're running in a console
            .UseConsoleLifetime()
            // Add services to the container
            .Build();
                await _host.StartAsync();
            }
            catch (Exception ex)
            {
                Console.WriteLine($"ERROR SPTools2 appId {appId} siteUrl {siteUrl} thumbprint {thumbprint} {ex}");
                throw new Exception($"ERROR SPTools2 appId {appId} siteUrl {siteUrl} thumbprint {thumbprint}", ex);
            }
            return 1;
        }

        public async Task LoadWeb()
        {
            try
            {
                // Optionally create a DI scope
                using (var scope = _host.Services.CreateScope())
                {
                    // Obtain a PnP Context factory
                    var pnpContextFactory = scope.ServiceProvider
                        .GetRequiredService();
                    // Use the PnP Context factory to get a PnPContext for the given configuration
                    using (var context = await pnpContextFactory.CreateAsync("SiteToWorkWith"))
                    {
                        // Retrieving web with lists and masterpageurl loaded ==> SharePoint REST query
                        var web = await context.Web.GetAsync(p => p.Title, p => p.Lists,
                        p => p.MasterUrl);

                        Console.WriteLine($"Web Title {web.Title} Loaded");
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"ERROR LoadWeb{ex}");
                throw new Exception($"ERROR LoadWeb ", ex);
            }
            return 1;
        }

        public void Dispose()
        {
            if (_host != null)
                _host.Dispose();
        }
    }
}


 

 

 

Powershell Import Export Fields

On 03/02/2023


Write-Output 'Connexion Portail'
# Connect-PnPOnline -Url $siteUrl -Tenant $aadDomain -Thumbprint $certifThumbprint -ClientId $appId

function ExportFieldsToCsv {
    Param(
        [string]$listTitle,
        [string]$csvFilename,
        [boolean]$includeHidden = $false
    )
    #$list = Get-PnPList -Identity $list 

    if ([string]::IsNullOrEmpty($listTitle)) {
        $fields = Get-PnPField
        $aFieldToExports = @();
        for ($i = 0 ; $i -lt $fields.Length ; $i++) {
            $field = $fields[$i];
            $aFieldToExport = New-Object -TypeName PSObject -Property @{        
                'Title'           = $field.Title;
                'InternalName'    = $field.InternalName;
                'Id'              = $field.Id;
                'TypeAsString'    = $field.TypeAsString;
                'Hidden'          = $field.Hidden;
                'StaticName'      = $field.StaticName;
                'Required'        = $field.Required;
                'Description'     = $field.Description;  
                'TypeDisplayName' = $field.TypeDisplayName;
                'Group'           = $field.Group;

            }
            $aFieldToExports += $aFieldToExport
            $aFieldToExports | Export-Csv -Path "$($csvFilename)" -Encodin:UTF8 -NoTypeInformation -Delimiter ";"
        }
    }
    else {
        <# Action when all if and elseif conditions are false #>
    }
}

function ExportFieldsToXml {
    Param(
        [string]$listTitle,
        [string]$xmlFilename,
        [boolean]$includeHidden = $false
    )
    #$list = Get-PnPList -Identity $list 

    if ([string]::IsNullOrEmpty($listTitle)) {
        $fields = Get-PnPField
        $stringBuilder = New-Object System.Text.StringBuilder
        $null = $stringBuilder.AppendLine("")
        for ($i = 0 ; $i -lt $fields.Length ; $i++) {
            $field = $fields[$i];
            $null = $stringBuilder.AppendLine($field.SchemaXml);

        }
        $null = $stringBuilder.AppendLine("")
        $stringBuilder.ToString() | Out-File -FilePath "$($xmlFilename)" -Encodin:UTF8 -Append
    }
}

function ImportFields {
    Param(
        [string]$listTitle,
        [string]$xmlFilePath,
        [boolean]$includeHidden = $false
    )
    [XML]$xmlfile = Get-Content -Path $xmlFilePath -Encoding:UTF8

    
    if ([string]::IsNullOrEmpty($listTitle)) {
        foreach ($field in $xmlfile.fields.Field) {
            Write-Host $field.Name

            $exists = Get-PnPField -Identity $field.Name -ErrorAction:SilentlyContinue

            if ($null -eq $exists) {
                Write-Host "$($field.Name) is null"

                Add-PnPFieldFromXml -FieldXml $field.OuterXml
                Write-Host "$($field.Name) added"
            }
            else {
                Write-Host "$($field.Name) exists"
            }
        }

    }
    else {        
        foreach ($field in $xmlfile.fields.Field) {
            $siteField = Get-PnPField -Identity $field.Name -ErrorAction:SilentlyContinue
            $listField = Get-PnPField -Identity $field.Name -List $listTitle -ErrorAction:SilentlyContinue
            if ($null -eq $siteField -and $null -eq $listField) {
                Write-Host "$($field.Name) is null"

                Add-PnPFieldFromXml -FieldXml $field.OuterXml
                Add-PnPField -List $listTitle -Field $field.Name
                Write-Host "$($field.Name) added"
            }
            elseif($null -eq $listField){
                Write-Host "$($field.Name) exists"
                Add-PnPField -List $listTitle -Field $siteField.InternalName
                Write-Host "$($field.Name) added to $($listTitle)"

            }
        }
    }
}

Power Automate Check User Exists

On 24/01/2022

Checkuser1

Checkuser2

 


/_api/web/ensureuser
content-type application/json; odata=verbose

{'logonName': '@{variables('userMailToCheck')}'}
@{outputs('Send_an_HTTP_request_to_SharePoint')['statusCode']}


In Nintex

Nintex 2016 Issue CodeTypeReferenceExpression

On 08/02/2021

Nintex 2016 Issue CodeTypeReferenceExpression

 

SharePoint Foundation Workflow Infrastructure Unexpected RunWorkflow:

Microsoft.SharePoint.SPException: CompilerError Line="-1" Column="-1" Text="Type System.CodeDom.CodeBinaryOperatorExpression is not marked as authorized in the application configuration file.

 

Error saving from workflow export file.: Nintex.Workflow.NWSavingWorkflowException: Erreur lors de la publication du flux de travail  Text="Le type System.CodeDom.CodeTypeReferenceExpression n'est pas indiqué comme étant autorisé dans le fichier de configuration de l'application."

 

You should add below red line in each web.config form your farm except central admin

<authorizedType Assembly="System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" Namespace="System.CodeDom" TypeName="CodeTypeReferenceExpression" Authorized="True" />


<authorizedType Assembly="System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" Namespace="System.CodeDom" TypeName="CodeTypeReferenceExpression" Authorized="True" />
     </targetFx>
    </authorizedTypes>
    <authorizedRuleTypes>
      <targetFx version="v4.0">

--------------------------------

 

Nintex.Workflow.NWException: Erreur lors de la lecture du paramètre 'SMTPServerPort' depuis la base de données de configuration. Vérifiez que vos bases de données Nintex Workflow sont à jour.

 

Nintex.Workflow.NWException: Error reading 'SMTPServerPort' parameter from configuration database. Make sure your Nintex Workflow databases are up to date.

 

To solve this issue, i executed this command line in an powershell admin instance

NWAdmin.exe -o UpgradeDatabases "Server=[serverName];Database=[dbName];Trusted_Connection=True;" -isConfig

For update workflow and forms Nintex configuration databases

 

 

Sharepoint Online Missing Icons

On 09/12/2020

Sharepoint missing icon on SPFX developpements

 

Some ican can be missing per exemple on :

SPFX missing icon as <i data-icon-name="Tag" class="ms-Button-icon icon-167" role="presentation" aria-hidden="true"></i> 

So you simply have to add this code below after yours imports

 


import { initializeIcons } from 'office-ui-fabric-react/lib/Icons';

initializeIcons();

 

In SQL

Sharepoint Caml Query

On 08/09/2020

Basic CSOM caml query

 

<View>
    <Query>
        <Where>
            <Eq>
                <FieldRef Name='Matricule'/>
                <Value Type='Text'>90136794</Value>
            </Eq>
        </Where>

<OrderBy><FieldRef Name='ID' Ascending='True'/></OrderBy>
    </Query>
    <ViewFields>
        <FieldRef Name='Matricule' />
        <FieldRef Name='Email' />
    </ViewFields>
    <RowLimit>2</RowLimit>
</View>

 

Query Null Text fields or not

<Where>
    <IsNotNull>
        <FieldRef Name="Famille"/>
    </IsNotNull>
</Where>


<Where>
    <IsNull>
        <FieldRef Name="Famille"/>
    </IsNull>
</Where>

 

by ID

<Where>
    <Eq>
        <FieldRef Name='ID'/>
        <Value Type='Counter'>645</Value>
    </Eq>
</Where>

 

Get tasks by itemId (relatedItems in tasks list)

<Where>
    <Eq>
        <FieldRef Name='RelatedItems'/>
        <Value Type='RelatedItems'>""ItemId"":435,</Value>
    </Eq>
</Where>

 

boolean / Yes/No

<Eq><FieldRef Name='YourFieldName'/><Value Type='Boolean'>1</Value></Eq>

 

Comparators

<Eq> => equals

<Neq> => not equals

<Lt> => Less than

<Leq> => less or equal

<Gt> greater than

<Geq> greater or equal

<Contains>

<BeginsWith>

 

Errors

  • Sharepoint error Error in my cases
    One or more field types are not installed properly. Go to the list settings page to delete these fields. Fields in your query are not in list

    Cannot complete this action.

    Please try again.

    Syntax error in your query
       
       
       
       
       
       
       

     

SPFX React Tips

On 02/09/2020

Override native css

 

:global(#spLeftNav) {  
  display: none;
} 
:global(.CanvasZone) {  
  max-width: 100%;
} 

Is member of

import 'core-js/modules/es6.string.includes.js';
import 'core-js/modules/es6.number.is-nan.js';
import 'core-js/es6/array';
import 'es6-map/implement';
import { sp,SPRest } from '@pnp/sp';
import { IWebPartContext } from '@microsoft/sp-webpart-base';
import * as React from 'react';

class PeopleService {
    private _context: IWebPartContext;
    private _localPnPSetup: SPRest;

    public constructor(webPartContext: IWebPartContext) {
        this._context = webPartContext;

        // To limit the payload size, we set odata=nometadata
        // We just need to get list items here
        // We use a local configuration to avoid conflicts with other Web Parts
        this._localPnPSetup = sp.configure({
            headers: {
                Accept: 'application/json; odata=nometadata',
            },
        }, this._context.pageContext.web.absoluteUrl);
    }

    public async isMemberOf(group: string): Promise{
        let groups = await this._localPnPSetup.web.currentUser.groups.get();
        let ret: boolean = false;
        
        groups.map(grp =>{
            if(grp.LoginName == group)
            ret =  true;
        });
        return ret;
    }

    public async isMemberOfanyGroup(groupNames: string[]): Promise{
        let groups = await this._localPnPSetup.web.currentUser.groups.get();
        let ret: boolean = false;
        groups.map(grp =>{
            groupNames.map(name =>{
                console.log("name : '" + name + "' grp : '" + grp.LoginName  + "'");
            if(grp.LoginName == name)
                ret = true;
            });
        });
        return ret;
    }

}
export default PeopleService;

Taxonomy, get tags, add tags

import { IWebPartContext } from '@microsoft/sp-webpart-base';
import { Session, ITermStore, ITermSet, ITermData, ITerm } from '@pnp/sp-taxonomy';

class TaxonomyService {
    private _context: IWebPartContext;
    
    public constructor(webPartContext: IWebPartContext) {
        this._context = webPartContext;
    }

    public async getTags() : Promise{
        
        console.log("Session");
        const taxonomy = new Session(this._context.pageContext.site.absoluteUrl);
        const store: any = taxonomy.termStores.getByName("Taxonomy_Wf8XzHaRobdAERjvvke+Tg==");
        let datas = await store.getTermSetById("c18ff3e6-e4a8-4dcb-85f5-51171f4bbc11").terms.select('Name', 'Id', 'Parent').get();
        
        let ret: string[] = [];
        for(let i = 0 ; i < datas.length ; i++)
            ret.push(datas[i]);

        return datas;
    }
    
    public async addNewTag(tag){
        
        const taxonomy = new Session(this._context.pageContext.site.absoluteUrl);
        const store: any = taxonomy.termStores.getByName("Taxonomy_Wf8XzHaRobdAERjvvke+Tg==");
        let datas = await store.getTermSetById("c18ff3e6-e4a8-4dcb-85f5-51171f4bbc11");
        const term: ITerm & ITermData = await datas.addTerm(tag, 1036, true);
    }
}
export default TaxonomyService;

CSOM Delete Items By Id Range

On 02/09/2020

CSOM delete items by id range

Get items

public ListItemCollection GetItems(string listRelativUrl, string where, string orderBy, string viewFields, int rowlimit = 100)
{
    string xmlView = "";
    try
    {
        List lst = CurrentWeb.GetList(CurrentWeb.ServerRelativeUrl + listRelativUrl);

        StringBuilder vf = new StringBuilder();
        if (!string.IsNullOrEmpty(viewFields))
        {
            vf.Append("<ViewFields>");
            foreach (string fieldName in viewFields.Split(",".ToCharArray(), StringSplitOptions.RemoveEmptyEntries))
            {
                vf.Append($"<FieldRef Name='{fieldName.Trim()}' />");
            }

            vf.Append("</ViewFields>");
        }

        CamlQuery camlQuery = new CamlQuery();
        camlQuery = new CamlQuery();
        Logger.LogInfo($"listRelativUrl {listRelativUrl} : <View><Query>{where}{orderBy}</Query>{vf.ToString()}<RowLimit>{rowlimit}</RowLimit></View>");
        xmlView = $"<View><Query>{where}{orderBy}</Query>{vf.ToString()}<RowLimit>{rowlimit}</RowLimit></View>";
        camlQuery.ViewXml = xmlView;

        ListItemCollection coll = lst.GetItems(camlQuery);
        SPContext.Load(coll);
        SPContext.ExecuteQuery();

        Logger.Log($"coll.Count : '{coll.Count}' : camlQuery.ViewXml {camlQuery.ViewXml}");

        return coll;
    }
    catch (ServerException ex1)
    {
        Logger.LogError($"Error ServerException Common.Sharepoint.SPTools.GetItems url '{_url}' login : '{_login}' " +
            $" listRelativUrl '{listRelativUrl}' where '{where}' orderBy '{orderBy}' rowlimit '{rowlimit}' xmlView : '{xmlView}' Exception '{ex1}'");
        throw;
    }
    catch (Exception ex)
    {
        Logger.LogError($"Error .Common.Sharepoint.SPTools.GetItems url '{_url}' login : '{_login}' " +
            $" listRelativUrl '{listRelativUrl}' where '{where}' orderBy '{orderBy}' rowlimit '{rowlimit}' xmlView : '{xmlView}' Exception '{ex}'");
        throw;
    }
}

delete items


public int DeleteItemByIdRange(string listRelativeUrl, int rowLimit, int from, int to = -1)
{
    int deleted = 0;
    try
    {
        string req = "";
        if (to == -1)
            req = $"<Where><Geq><FieldRef Name='ID'/><Value Type='Counter'>{from}</Value></Geq></Where>";
        else
        {
            if (from > to)
                throw new Exception($"DeleteItemByIdRange from should be < than to listRelativeUrl '{listRelativeUrl}' from '{from}' to '{to}'");
            req = $"<Where><And><Geq><FieldRef Name='ID' /><Value Type='Counter'>{from}</Value></Geq><Leq><FieldRef Name='ID' /><Value Type='Counter'>{to}</Value></Leq></And></Where>";
        }
        ListItemCollection coll = GetItems(listRelativeUrl, req, "", "ID", rowLimit);

        while (coll.Count > 0)
        {
            string id = coll[0].Id.ToString();
            coll[0].DeleteObject();
            this.ExecuteQuery($"DeleteItemByIdRange listRelativeUrl '{listRelativeUrl}' from '{from}' to '{to}' Id = '{id}'");
            deleted++;
        }
        return deleted;
    }
    catch (Exception ex)
    {
        Logger.LogError($"Error Sharepoint.SPTools.DeleteItemByIdRange from id '{from}' to id '{to}' url '{_url}' login : '{_login}'  Exception '{ex}'");
        throw;
    }
}

catch ServerException to get more details on CSOM exceptions

SPFX pnp Taxonomy with internet explorer 11

On 26/06/2020

SPFX webpart query Taxonomy / Term store with @pnp/sp-taxonomy on ie / internet explorer

 

Your package.json must contains at least :

"@pnp/polyfill-ie11": "1.0.0", 
"@pnp/sp": "1.2.7", 
"@pnp/sp-clientsvc": "^1.3.9", 
"@pnp/sp-taxonomy": "^1.3.9", 
"@types/es6-promise": "0.0.33"

 

In your service where you want to query Term store, you should import :

import 'core-js/modules/es6.string.includes.js';
import 'core-js/modules/es6.number.is-nan.js'; 
import 'core-js/es6/array'; 
import 'es6-map/implement'; 
import { Session } from '@pnp/sp-taxonomy'; 

 

Power Automate Flow Functions

On 18/06/2020

Power plateform

Power automate flow

 

Functions

Check date is null

if(equals(triggerBody()?['myDate'], null),'[myDate is null]', formatDateTime(triggerBody()?['myDate'], 'dd/MM/yyyy'))

Power apps

Display view on query string value

If ( !IsBlank(Param("taskDisplay")) && Param("taskDisplay")="true"; Navigate(DevTasksView;ScreenTransition.Cover) )

set variable value (separator in english is , in french ;)

Set(CurrentToShow; "loppement") ;; Set(CurrentButton; "DEV")

 

Addind header like this


{
  "Accept": "application/json; odata=verbose",
  "content-type": "application/json; odata=verbose",
  "X-HTTP-Method": "MERGE",
  "If-Match": "*"
}

 

Flow Get Item Send Mail

On 10/06/2020

Microsoft Flow hot to get item by lookup and send a mail, with lookup details

Initialize variable

Initvars

Get lookup datas

Getitem 1

Extract approver datas


{
    "type": "object",
    "properties": {
        "@@odata.type": {
            "type": "string"
        },
        "Claims": {
            "type": "string"
        },
        "DisplayName": {
            "type": "string"
        },
        "Email": {
            "type": "string"
        }
    }
}

Extractdisplayname

Append datas to an array

Appendtoarray

Create an html table

Createhtml

Send the mail

Sendmail

Sharepoint Online Web Templates

On 11/01/2019

Name Title Category Compatiblity Level
STS#3 Site d’équipe Collaboration 15
STS#0 Site d’équipe (expérience classique) Collaboration 15
BLOG#0 Blog Collaboration 15
BDR#0 Centre de documents Entreprise 15
DEV#0 Site de développeur Collaboration 15
OFFILE#1 Centre des enregistrements Entreprise 15
EHS#1 Site d’équipe - Configuration SharePoint Online Entreprise 15
SRCHCEN#0 Centre de recherche d’entreprise Entreprise 15
BLANKINTERNETCONTAINER#0 Portail de publication Publication 15
ENTERWIKI#0 Wiki d’entreprise Publication 15
PROJECTSITE#0 Site de projet Collaboration 15
COMMUNITY#0 Site communautaire Collaboration 15
COMMUNITYPORTAL#0 Portail communautaire Entreprise 15
SITEPAGEPUBLISHING#0 Site de communication Publication 15
SRCHCENTERLITE#0 Centre de recherche de base Entreprise 15

List templates

ID Template Name Description SP2016 SP2013 SP2010 SP2007
-1 InvalidType Not used. Yes Yes Yes Yes
0 NoListTemplate unspecified list type. Yes Yes Yes No
100 GenericList Custom list. Yes Yes Yes Yes
101 DocumentLibrary Document library. Yes Yes Yes Yes
102 Survey Survey. Yes Yes Yes Yes
103 Links Links. Yes Yes Yes Yes
104 Announcements Announcements. Yes Yes Yes Yes
105 Contacts Contacts. Yes Yes Yes Yes
106 Events Calendar. Yes Yes Yes Yes
107 Tasks Tasks. Yes Yes Yes Yes
108 DiscussionBoard Discussion board. Yes Yes Yes Yes
109 PictureLibrary Picture library.  Yes Yes Yes Yes
110 DataSources Data sources for a site. Yes Yes Yes Yes
111 WebTemplateCatalog Site template gallery.  Yes Yes Yes Yes
112 UserInformation User Information. Yes Yes Yes Yes
113 WebPartCatalog Web Part gallery. Yes Yes Yes Yes
114 ListTemplateCatalog List Template gallery. Yes Yes Yes Yes
115 XMLForm XML Form library. Yes Yes Yes Yes
116 MasterPageCatalog Master Page gallery. Yes Yes Yes Yes
117 NoCodeWorkflows No Code Workflows. Yes Yes Yes Yes
118 WorkflowProcess Custom Workflow Process. Yes Yes Yes Yes
119 WebPageLibrary Wiki Page Library. Yes Yes Yes Yes
120 CustomGrid Custom grid for a list. Yes Yes Yes Yes
121 SolutionCatalog Solutions. Yes Yes Yes No
122 NoCodePublic No Code Public Workflow. Yes Yes Yes No
123 ThemeCatalog Themes. Yes Yes Yes No
124 DesignCatalog DesignCatalog. Yes Yes No No
125 AppDataCatalog AppDataCatalog. Yes Yes No No
130 DataConnection
Library
Data connection library for sharing information about external data connections. Yes Yes Yes Yes
140 WorkflowHistory Workflow History. Yes Yes Yes Yes
150 GanttTasks Project Tasks. Yes Yes Yes Yes
151 HelpLibrary Help Library. Yes Yes No No
160 AccessRequest Access Request List. Yes Yes No No
171 TasksWithTimeline
AndHierarchy
Tasks with Timeline and Hierarchy. Yes Yes No No
175 MaintenanceLogs Maintenance Logs Library. Yes Yes No No
200 Meetings Meeting Series (Meeting). Yes Yes Yes Yes
201 Agenda Agenda (Meeting). Yes Yes Yes Yes
202 MeetingUser Attendees (Meeting). Yes Yes Yes Yes
204 Decision Decisions (Meeting). Yes Yes Yes Yes
207 MeetingObjective Objectives (Meeting). Yes Yes Yes Yes
210 TextBox Text Box (Meeting). Yes Yes Yes Yes
211 ThingsToBring Things To Bring (Meeting). Yes Yes Yes Yes
212 HomePageLibrary Workspace Pages (Meeting). Yes Yes Yes Yes
301 Posts Posts (Blog). Yes Yes Yes Yes
302 Comments Comments (Blog). Yes Yes Yes Yes
303 Categories Categories (Blog). Yes Yes Yes Yes
402 Facility Facility. Yes Yes Yes No
403 Whereabouts Whereabouts. Yes Yes Yes No
404 CallTrack Call Track. Yes Yes Yes No
405 Circulation Circulation. Yes Yes Yes No
420 Timecard Timecard. Yes Yes Yes No
421 Holidays Holidays. Yes Yes Yes No
499 IMEDic IME (Input Method Editor) Dictionary. Yes Yes Yes No
600 ExternalList External. Yes Yes Yes No
700 MySiteDocument
Library
MySiteDocumentLibrary. Yes Yes No No
1100 IssueTracking Issue tracking. Yes Yes Yes Yes
1200 AdminTasks Administrator Tasks. Yes Yes Yes Yes
1220 HealthRules Health Rules. Yes Yes Yes No
1221 HealthReports Health Reports.  Yes Yes Yes No
1230 DeveloperSiteDraft
Apps
Draft Apps library in Developer Site. Yes Yes No No
3100 AccessApp   Yes No No No
3101 AlchemyMobileForm   Yes No No No
3102 AlchemyApproval
Workflow
  Yes No No No
3300 SharingLinks   Yes No No No
    Total 64 60 52 38