Add Owner Group to Users OneDrive for Business


Every OneDrive for business site in SharePoint Online has a primary and secondry owner.  There are situations when primary owner leaves the company but during the initial setup administrator did not entered the secondry administrator value.  This value should be a group instead of a User.  Around a year ago I faced this situation with a customer who had over 40K OneDrive Sites created but now no one had ownership of these sites.  To add the site collection owner on these sites I used the script below.  This hopefuly will help someone else.

$Creds = Get-Credential -Message “Please enter SPO Admin Credentials.”
Start-Transcript -Path C:\temp\transcript.txt
Connect-MsolService -Credential $Creds

$SPOAdminSiteURL = “https://tenant-admin.sharepoint.com/”
#Add references to SharePoint client assemblies and authenticate to Office 365 site – required for CSOM
Add-Type -Path “C:\Program Files\Common Files\microsoft shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.dll” -ErrorAction Stop
Add-Type -Path “C:\Program Files\Common Files\microsoft shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.Runtime.dll” -ErrorAction Stop
Add-Type -Path “C:\Program Files\Common Files\microsoft shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.UserProfiles.dll” -ErrorAction Stop

Connect-SPOService -Url $SPOAdminSiteURL -Credential $Creds

$credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($Creds.UserName, $Creds.Password)
$ctx = New-Object Microsoft.SharePoint.Client.ClientContext($SPOAdminSiteURL)
$ctx.Credentials = $credentials
$ctx.Load($ctx.Web);
$ctx.ExecuteQuery()

$NewSites =$null;
$NewSites = @();

$PeopleManager = New-Object Microsoft.SharePoint.Client.UserProfiles.PeopleManager($ctx)
$PeopleLoader =[Microsoft.SharePoint.Client.UserProfiles.ProfileLoader]::GetProfileLoader($ctx)

#To Get the Group ID. Add the Group in People Picker in Site Collection Admin dialog on SPO Admin Center and then use the IE Developer Tools to click on it name
$CSVPath = “C:\Temp\UniUsers.csv”
$IAMCloudOneDriveID = “c:0-.f|rolemanager|s-1-5-21-3431014192-700181988-4181250490-129537758”
try
{
    $Data = Import-Csv -Path $CSVPath
   
    if($Data)
    {
        $Count = 0;
        foreach($User in $Data)
        {
            $Count++;
            try
            {
         
              $Start = (Get-Date).Second
              $Name = $($User.UserName).Trim();
              Write-Host “Getting Prifle Number $Count of $($Data.Count) for User $Name” -ForegroundColor Yellow
              $AccountName = “i:0#.f|membership|$Name”
              $UserProfile = $PeopleManager.GetPropertiesFor($AccountName)
              $ctx.Load($UserProfile)
              $ctx.ExecuteQuery()
             
              if($UserProfile.DisplayName -eq $null -and $UserProfile.Email -eq $null)
              {
                Write-Host “This user $Name does not exist in User Profile System…” -ForegroundColor Red
                continue
              }
            }
            catch
            {
              Write-Output “Error processing a profile “
            }
            $OneDriveUrl = $UserProfile.PersonalUrl
            if($OneDriveUrl.Contains(“Person”))
            {
              try
              {
                $PeopleManager.SetSingleValueProfileProperty($AccountName, “PersonalUrl”, “”);
                $ctx.ExecuteQuery();
                $OneDriveUrl = $null;
              }
              catch
              {
                $PeopleManager.SetSingleValueProfileProperty($AccountName, “PersonalSpace”, “”);
                $ctx.ExecuteQuery();
                $OneDriveUrl = $null;
              }
             
            }
           
            If ($OneDriveUrl -ne $null)
            {
                try
                {
               
                  $SiteUrl = “”
                  Write-Host “Starting to Add Group on User OneDrive for:” $AccountName -ForegroundColor Yellow
                  $SiteUrl = $UserProfile.PersonalUrl
                  Write-Host “”
                  $SiteUrl = $SiteUrl.Remove($SiteUrl.LastIndexOf(“/”),1)
                  $Site = Get-SPOSite -Identity $SiteUrl
                  if($Site)
                  {
                    Write-Host “Adding The Cloud Group …”-ForegroundColor Yellow
                    Set-SPOUser -Site $Site.Url -LoginName $IAMCloudOneDriveID -IsSiteCollectionAdmin $true -ErrorAction SilentlyContinue
                    Write-Host “Group Added Successfully in $($Site.Url)…” -ForegroundColor Green
                  }
                }
                catch
                {
                  Write-Output “Error processing a profile “
                }
             }
             else
             {
                Write-Host “Personal Url is null for $Name. So Creating personal Site…”
                $Email = $UserProfile.Email
                [string]$emails = $Email
                $PeopleLoader.CreatePersonalSiteEnqueueBulk($Email);
               
                Write-Host “Creating User Profile for $($Email)” -ForegroundColor Green
              
                $NewSite = New-Object PSObject
                Add-Member -input $NewSite noteproperty ‘AccountName’ $AccountName
                $NewSites += $NewSite
            }
            $End = (Get-Date).Second
            $Secs = $End – $Start
            $ExpectedTime = ($Data.Count – $Count) * $Secs
            Write-Host “Total Profiles $($Data.Count) Processed Profiles $Count” -ForegroundColor Cyan
            Write-Host “The script took $Secs second(s) to run.” -ForegroundColor DarkMagenta
            Write-Host “Expect this to complete in $(($ExpectedTime/60)) minutes or $(($ExpectedTime/60)/60) Hours” -ForegroundColor Red
           
        }
        foreach($object in $NewSites)
        {
            $AccountName = $object.AccountName
              $UserProfile = $PeopleManager.GetPropertiesFor($AccountName) 
              $ctx.Load($UserProfile)
              $ctx.ExecuteQuery()
             
              $SiteUrl = $UserProfile.PersonalUrl
              if($SiteUrl.Length -gt 0)
              {
                Write-Host “Personal Site Found for $AccountName …” -ForegroundColor Yellow
                $SiteUrl = $Url.Remove($Url.LastIndexOf(“/”),1)
                Set-SPOUser -Site $SiteUrl -LoginName $IAMCloudOneDriveID -IsSiteCollectionAdmin $true -ErrorAction SilentlyContinue
                Write-Host “Group Added Successfully in $($Site.Url)…” -ForegroundColor Green
                $continue = $false
              }
        }
    }
}
catch
{
    Write-Host “Failed.” -ForegroundColor Yellow
}
Stop-Transcript

Script is also available here

https://gallery.technet.microsoft.com/Add-Owner-Group-to-Users-06003db8

Advertisements

Get OneDrive for Business Site URL for Users using CSOM and PowerShell


Get OneDrive Site URL for Users using SharePoint Online Client Object Model and PowerShell.  This is a very basic script but useful.  I have seen some scripts and people are still usin the traditional SharePoint User Profile Web Service Report for reporting from User profile system.  The script below can do the same job nicely.  You just specify the name of the user and it find the oneDirve Site URL.

param
(
  #Must be SharePoint Administrator URL
  [Parameter(Mandatory = $false)]
  [ValidateNotNullOrEmpty()]
  [string] $SPOAdminUrl,

  #Must be SharePoint Administrator URL
  [Parameter(Mandatory = $true)]
  [ValidateNotNullOrEmpty()]
  [string] $InputFilePath
)

$InputFilePath = “C:\Temp\OneDriveUsers.txt”

Add-Type -Path “C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.dll”
Add-Type -Path “C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.Runtime.dll”
Add-Type -Path “C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.UserProfiles.dll”

$Users = Get-Content -Path $InputFilePath

if ($Users.Count -eq 0)
{
  Write-Host $(“Unexpected user count: [{0}]” -f $Users.Count) -ForegroundColor Red
  return
}

#$SPOAdminUrl = “https://sharepointmvp-admin.sharepoint.com/”

$Creds = Get-Credential -Message “Please enter SharePo”
$SPOCreds = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($Creds.UserName,$Creds.Password)
$Context = New-Object Microsoft.SharePoint.Client.ClientContext($SiteURL)
Connect-SPOService -Url $SiteURL -Credential $Creds
$Context.Credentials = $SPOCreds

$profileloader = [Microsoft.SharePoint.Client.UserProfiles.ProfileLoader]::GetProfileLoader($Context)
$PeopleManager = New-Object Microsoft.SharePoint.Client.UserProfiles.PeopleManager($Context) -ErrorAction Inquire

Write-Host “Script Completed”

foreach($aUser in $Users)
{
    Write-Host “Trying to access User Profile for Personal Site…” -ForegroundColor Yellow
   
    $ClaimsUserFormat = “i:0#.f|membership|$aUser”
   
    $UserProfile = $PeopleManager.GetPropertiesFor($ClaimsUserFormat) 
    $Context.Load($UserProfile)
    $Context.ExecuteQuery()
 
    $Profile = $UserProfile | Select-Object PersonalUrl
    $SiteUrl = $Profile.PersonalUrl
   
    if($SiteUrl.Length -gt 0)
    {
      Write-Host “Personal Site Found for $aUser Starting to Loading files…” -ForegroundColor Yellow
      $SiteUrl = $Url.Remove($Url.LastIndexOf(“/”),1)
      $Site = Get-SPOSite -Identity $SiteURL
      Write-Host “Site URL is $($SiteUrl)” -ForegroundColor Yellow
      $continue = $false
    }
}

Add Owner to SharePoint Online List PowerShell


This script uses SharePoint Client Side Object Model to Add Owner to selected SharePoint Online Libraries and Lists.  You need to install the latest SharePoint Online Client Components from Github or download them from Microsoft download center.  You can change the script to only find list by title and then add the owner.  The script creates the required objects and then add the User as owner. 

$User = “user@domain.onmicrosoft.com”
#$User = Read-host “Please enter Office365 Admin User name username@domain.onmicrosoft.com. “
$Creds = Get-Credential

Connect-SPOService -Url https://tenant-admin.sharepoint.com -Credential $Creds
$site = Get-SPOSite https://site.sharepoint.com/teams/HCPTS

Add-Type -Path ‘C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.dll’
Add-Type -Path ‘C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.Runtime.dll’

#Get the Client Context and Bind the Site Collection
$ctx = New-Object Microsoft.SharePoint.Client.ClientContext($site.Url)

#Authenticate
$credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($Creds.UserName , $Creds.Password)
$ctx.Credentials = $credentials

#Fetch the users in Site Collection

$Web = $ctx.Web;
$ctx.Load($Web)
$Lists = $Web.Lists
$ctx.Load($Lists)
$ctx.ExecuteQuery()

$SAPLists = $Lists | ?{$_.Title -Like “SAP Data Quality Review*” } | Select Title
$SAPLists | Select Title

foreach($alist in $SAPLists)
{

   Write-Host $alist.Title
  $OwnersGroupTitle = “Site Owners”
  $OwnerGroup = $Web.SiteGroups.GetByName($OwnersGroupTitle)

  $FullControl = $web.RoleDefinitions.GetByName(“Full Control”)
  # Create a role assignment and apply the ‘read’ role.
  $roleAssignment = New-Object Microsoft.SharePoint.Client.RoleDefinitionBindingCollection($ctx)
  $roleAssignment.Add($FullControl)

 
  $SelectedList = $Web.Lists.GetByTitle($alist.Title)
  $ctx.Load($SelectedList)
  $ctx.Load($SelectedList.RoleAssignments.Add($OwnerGroup,$roleAssignment))
  $SelectedList.Update()
  $ctx.ExecuteQuery()
}

Script is also available below

https://gallery.technet.microsoft.com/Add-Owner-to-SharePoint-4f13d94f

Get SharePoint Online Group Information from PowerShell using Client Object Model


If you try to use PowerShell and CSOM to get SharePoint Online Group Owner information, you learn that the returned Microsoft.SharePoint.Client.Group object Owner property will be empty.  I tried to read value of Owner property and got the following.

image

I found two ways to get over this.  First I used the basic Object.Retreive method and pass an array or string properties.  The output was show as expected.

To see all the properties you can use

$Owner | Select *

$Group = $Web.SiteGroups.GetByName(“Test”)

$Owner = $Group.Owner

$Owner.Retrieve(“Id”,”LoginName”,”Title”,”PrincipalType”,”IsHiddenInUI”)

$Context.ExecuteQuery() $

$Owner | Select *

The output is exactly as I expected

image

The second method would be to use Lambda expressions.  PowerShell does not support lambda expressions like C# (object, a => a.XYZ) so I did some research and found a post from PowerShell Guru Garry Lapointe here.  It has a PowerShell script which enables you to call any property of the main object directly. 

https://gist.github.com/glapointe/cc75574a1d4a225f401b#file-load-csomproperties-ps1

$Group = $Web.SiteGroups.GetByName(“Test”)
$Owner = $Group.Owner
Load-CSOMProperties -object $Group.Owner -propertyNames @(“ID”,”LoginName”,”Title”,”PrincipalType”,”IsHiddenInUI”)
$Context.ExecuteQuery()
$Owner | Select *

Output is exactly the same but lot cleaner script as I don’t have to work with Retrieve method.
image