Forum Discussion

Brent Ellis's avatar
Brent Ellis
Silver Contributor
Feb 08, 2017

"My Groups" list for SharePoint Homepage Web Part

So, we are about to do some major rollout of Groups to our company.  While there are a million "entry points" for Groups, we simply wanted a list of Groups that a member belongs to on our Intranet Homepage, with quick links to each of the major workloads.  We try to drive all users to our Intranet homepage as an easy means to accessing information, until (if ever) they become more comfortable navigating all of the tools themselves.

 

So I put together a quick script that will show (1) What groups I (the current user) belong to (item level permissions), (2) Links to the major workloads associated with that Group (excluding Planner cause havent figured that out yet), (3) other supporting information about the Group.

 

Now we can serve it up on our Intranet Homepage (with list web part, search results+display templates, script editor web part, however else) as "My Groups"

 

This also serves as an "auditing" list for us admins (we can see what groups exist, which language, what category/classification, dynamic membership, etc).

 

Probably more elegant ways to do this (and probably better SPFX stuff in the future, but I only know what I know), but in general, I am just clearing a SharePoint list of existing entries, querying all O365 Groups, and adding them into the SharePoint list, and then setting "Read" permissions on the list item to the particular Group (so only Group members can actually see their own Groups).  Probably running this once or twice a day.

 

 

# SharePoint Online DLLs
#$dllDirectory = "D:\Assets\\16.1.6112.1200"
$dllDirectory = "C:\PowerShell\DLL\16.1.6112.1200"
Add-Type -Path "$dllDirectory\Microsoft.SharePoint.Client.dll" 
Add-Type -Path "$dllDirectory\Microsoft.SharePoint.Client.Runtime.dll" 

# User Credentials and Variables 
$username = "<admin username here>"
$password = '<admin password here>'
$securePassword = ConvertTo-SecureString $Password -AsPlainText -Force 
$url = "https://contoso.sharepoint.com/sites/groups/" # the url of the site where your list is
$listName = "Groups" # the name of your list
$domain = "@contoso.com"

# Connect to Exchange Online
Write-Host "Connecting to Exchange Online..." -ForegroundColor Green 
$E_Credential = New-Object -TypeName System.Management.Automation.PSCredential -argumentlist $userName, $SecurePassword
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://ps.outlook.com/powershell/ -Credential $E_Credential -Authentication Basic -AllowRedirection
Import-PSSession $Session -AllowClobber  | out-null

# Connect to SPO
$clientContext = New-Object Microsoft.SharePoint.Client.ClientContext($url) 
$credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($username, $securePassword) 
$clientContext.Credentials = $credentials 
Write-Host "Connected to: '$Url'" -ForegroundColor Green 
	
$List = $clientContext.Web.Lists.getByTitle($listName)
$clientContext.Load($List)
$clientContext.ExecuteQuery()

# Get Existing Entries
$spQuery = New-Object Microsoft.SharePoint.Client.CamlQuery	
$items = $List.GetItems($spQuery)
$clientContext.Load($items)
$clientContext.ExecuteQuery()

# Remove Existing Entries
Write-Host "Clearing existing entries" -ForegroundColor Cyan
$count = 0
ForEach ($item in $items){
    Write-Host ("  "+$count+" "+$Item.FieldValues["ID"]+" "+$Item.FieldValues["Title"])
    $List.getitembyid($Item.id).DeleteObject()
    $clientContext.ExecuteQuery()
    $count += 1
}

# Get all O365 Groups
Write-Host "Getting O365 Groups" -ForegroundColor Cyan
$o365Groups = get-unifiedgroup
$count = 0
foreach($group in $o365Groups){
    $count++
    Write-Host "$count - Creating $($group.DisplayName)" -ForegroundColor Green
    #$group | select * # Show all available Group details

    $O365_group = $clientContext.Site.RootWeb.EnsureUser("c:0o.c|federateddirectoryclaimprovider|$($group.ExternalDirectoryObjectId)")
    $clientContext.Load($O365_group)

    [Microsoft.SharePoint.Client.FieldUserValue[]]$groupOwners = New-Object Microsoft.SharePoint.Client.FieldUserValue
    $owners = ($group.ManagedBy)
    foreach($owner in $owners){
        try{
            $user = $clientContext.Web.EnsureUser("$owner@buckman.com")
            $clientContext.Load($user)
		    $clientContext.ExecuteQuery()	                    
            [Microsoft.SharePoint.Client.FieldUserValue]$fieldUser = New-Object Microsoft.SharePoint.Client.FieldUserValue
            $fieldUser.LookupId = $user.Id
            if($counter -eq 0){
                $groupOwners = $fieldUser
            } else {
                $groupOwners += $fieldUser
            }
            $counter++
        } catch {
            Write-Host "User does not exist"
        }
    }


    # Create new entry in SharePoint List
    # Change the ["field"] values to match your SharePoint column internal names
    $ListItemInfo = New-Object Microsoft.SharePoint.Client.ListItemCreationInformation
    $newItem = $List.AddItem($ListItemInfo)
    $newItem["Title"] = $group.DisplayName # Single Line of Text
    $newItem["Group"] = $O365_group # Person/Group Field (Group enabled)    
    $newItem["Description"] = $group.Notes # Multiple Lines of Text
    $newItem["Conversation"] = "https://outlook.office.com/owa/?path=/group/$($group.Alias)$($domain)/mail, Conversation" # Hyperlink
    $newItem["Calendar"] = "https://outlook.office.com/owa/?path=/group/$($group.Alias)$($domain)/calendar, Calendar" # Hyperlink
    $newItem["Files"] = "https://outlook.office.com/owa/?path=/group/$($group.Alias)$($domain)/files, Files" # Hyperlink
    $newItem["Library"] = "$($group.SharePointDocumentsUrl), Document Library" # Hyperlink
    $newItem["Site"] = "$($group.SharePointSiteUrl), SharePoint Site" # Hyperlink
    $newItem["Notebook"] = "$($group.SharePointNotebookUrl), Notebook" # Hyperlink
    $newItem["Category"] = $group.Classification # Single Line of Text
    $newItem["Connectors"] = $group.ConnectorsEnabled # Boolean (Yes/No)
    $newItem["HiddenFromGAL"] = $group.HiddenFromAddressListsEnabled # Boolean (Yes/No)
    $newItem["Language"] = $group.Language # Single Line of Text
    $newItem["Privacy"] = $group.AccessType # Single Line of Text
    $newItem["DynamicMembership"] = $group.IsMembershipDynamic # Boolean (Yes/No)
    $newItem["ExternalDirectoryID"] = $group.ExternalDirectoryObjectId # Single Line of Text   
    $newItem["ExternalUserCount"] = $group.GroupExternalMemberCount # Number   
    $newItem["Owners"] = $groupOwners # Multiple Person Field
    # Add more as needed
    $newItem.Update()
    $clientContext.ExecuteQuery()

    # Break Permissions
    $newItem.BreakRoleInheritance($false, $false)  
    $clientContext.ExecuteQuery()  

    # Remove Any Existing Permissions
    $permissions = $newItem.RoleAssignments
    $clientContext.Load($permissions)
    $clientContext.ExecuteQuery()
    foreach($permission in $permissions){
        $newItem.RoleAssignments.GetByPrincipalId($permission.PrincipalId).DeleteObject()
    }

    # Set permissions to actual O365 Group
    $reader = $clientContext.Web.RoleDefinitions.GetByName("Read");
    $roleAssignment = New-Object microsoft.SharePoint.Client.RoleDefinitionBindingCollection($clientContext)
	$roleAssignment.Add($reader)
    $clientContext.Load($newItem.RoleAssignments.Add($O365_group, $roleAssignment)) 
                                     
    $newItem.Update();  
    $clientContext.ExecuteQuery()

}


 

  • Great stuff Brent Ellis! As you mentioned, would love to see this in SPFx form or potentially as "My Groups Bot" embedded in Microsoft Teams! The bot could help drive action around the Groups right there in the conversation for basic group maintenance, discovery, etc.

  • Pure beauty :-)

     

    Some things I didn't know and might be helpful to others:

     

    - don't forget to change @buckman.com to the domain you use for your O365 groups (I wonder if the script can be updated to detect the domain since you can use multiple domains?)

    - you can download the dll's from https://www.nuget.org/packages/Microsoft.SharePointOnline.CSOM (just download the nuget package and change the extension to zip)

    - Roldefinitions are localized so instead of $clientContext.Web.RoleDefinitions.GetByName("Read"), I had to use GetByName("Lezen"); (check the permission levels on your list)

    - if you have 1000+ groups, you could try get-unifiedgroup -resultsize unlimited

     

    Thanks!

    • Brent Ellis's avatar
      Brent Ellis
      Silver Contributor
      Thanks Bart! This is my quick and dirty attempt to solve an immediate need, thought I sanitized it enough before pasting but missed the domain :)

      I'm hardly a powershell expert, but more than armed and dangerous, so I'm sure there are many more efficiencies to be had.
      • Brent Ellis's avatar
        Brent Ellis
        Silver Contributor

        Got my first end-user visual set up for including on our home page.  I'm using the Group title, with selectable icons underneath to each workload.  Have a quick filter text box to narrow down groups and a small pagination to save real estate.  Then a link at the bottom to go to our "Informational" page about Groups.

         

  • RobOK's avatar
    RobOK
    Bronze Contributor
    Very impressive, I wish some of this was built in!!

Resources