September 24, 2014

SharePoint: Replacing owners of Term Sets and Terms using PowerShell and CSOM

SCRIPT

Param (
    [Parameter(Mandatory=$True)]
    [string]$Url,
    [Parameter(Mandatory=$True)]
     [string]$OldOwner,
    [Parameter(Mandatory=$True)]
    [string]$NewOwner,
    [Parameter(Mandatory=$True)]
    [string]$AdminUsername
)

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client")
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.Runtime")
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.Taxonomy")

## Stop here
$lcid = "1033"

Write-Host "Please enter password for $($Url):"
$pwd = Read-Host -AsSecureString

# connect/authenticate to SharePoint Online and get ClientContext object..
$sCtx = New-Object Microsoft.SharePoint.Client.ClientContext($Url)
$sCredentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($AdminUsername, $pwd)
$sCtx.Credentials = $sCredentials

if (!$sCtx.ServerObjectIsNull.Value)
{
    Write-Host "Connected to SharePoint Online: " $sCtx.Url "" -ForegroundColor Green

    $sTaxonomySession = [Microsoft.SharePoint.Client.Taxonomy.TaxonomySession]::GetTaxonomySession($sCtx)
    $sTaxonomySession.UpdateCache()
    $sCtx.Load($sTaxonomySession)
    $sCtx.ExecuteQuery()

    if (!$sTaxonomySession.ServerObjectIsNull)
    {
        Write-Host "Taxonomy session: " $sTaxonomySession.Path.Identity "" -ForegroundColor Green

        $sTermStore = $sTaxonomySession.GetDefaultSiteCollectionTermStore()
        $sCtx.Load($sTermStore)
        $sCtx.ExecuteQuery()

        if ($sTermStore.IsOnline)
        {
            Write-Host "Term Store connected:" $sTermStore.Id "" -ForegroundColor Green
            $sCtx.Load($sTermStore.Groups)
            $sCtx.ExecuteQuery()

            foreach ($sTermGroup in $sTermStore.Groups)
            {
                Write-Host "Term Group: " $sTermGroup.Name "-" $sTermGroup.Id "" -ForegroundColor Green
                $termSets = $sTermGroup.TermSets
                $sCtx.Load($termSets)
                $sCtx.ExecuteQuery()

                foreach($termSet in $termSets)
                {
                    Write-Host "Term Set found: " $termSet.Name ", Current Owner: " $termSet.Owner "" -ForegroundColor Green

                    If($termSet.Owner -match $OldOwner)
                    {
                        Write-Host "Replacing old termset owner!" -ForegroundColor Yellow
                        $termSet.Owner = $NewOwner
                    }

                    $terms = $termSet.Terms
                    $sCtx.Load($terms)
                    $sCtx.ExecuteQuery()
                    foreach($term in $terms)
                    {
                        Write-Host "Term found: " $term.Name ", Current Owner: " $term.Owner "" -ForegroundColor Green

                        If($term.Owner -match $OldOwner)
                        {
                            Write-Host "Replacing old term owner!" -ForegroundColor Yellow
                            $term.Owner = $NewOwner
                        }
                    }
                }               
            }

            #####
            Write-Host "Rolling back..." -ForegroundColor Cyan
            $sTermStore.RollbackAll()
            #Write-Host "Committing..." -ForegroundColor Cyan
            #$sTermStore.CommitAll()
            #####

            $sTermStore.UpdateCache()

            Write-Host "Done!" -ForegroundColor Green
        }
    }
}

 

USAGE

You need to uncommend the CommitAll command at the end, and comment the RollbackAll command in order for the script to store changes in database. Script will loop through all term groups and sets and terms and change owner of term sets and terms.

.\ReplaceTermSetOwner.ps1 -Url https://myspsite.sharepoint.com –OldOwner oldowner@myspsite.com -NewOwner newowner@myspsite.com -AdminUsername adminusername@myspsite.com

SharePoint: Change Term Set Owner using PowerShell via CSOM

SCRIPT

Param (
    [Parameter(Mandatory=$True)]
    [string]$Url,
    [Parameter(Mandatory=$True)]
    [string]$NewOwner,
    [Parameter(Mandatory=$True)]
    [string]$TermGroupName,
    [Parameter(Mandatory=$True)]
    [string]$TermSetName,
    [Parameter(Mandatory=$True)]
    [string]$AdminUsername
)
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client")
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.Runtime")
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.Taxonomy")
$lcid = "1033"
Write-Host "Please enter password for $($Url):"
$pwd = Read-Host -AsSecureString
# connect/authenticate to SharePoint Online and get ClientContext object..
$sCtx = New-Object Microsoft.SharePoint.Client.ClientContext($Url)
$sCredentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($AdminUsername, $pwd)
$sCtx.Credentials = $sCredentials
if (!$sCtx.ServerObjectIsNull.Value)
{
    Write-Host "Connected to SharePoint Online: " $sCtx.Url "" -ForegroundColor Green
    $sTaxonomySession = [Microsoft.SharePoint.Client.Taxonomy.TaxonomySession]::GetTaxonomySession($sCtx)
    $sTaxonomySession.UpdateCache()
    $sCtx.Load($sTaxonomySession)
    $sCtx.ExecuteQuery()
    if (!$sTaxonomySession.ServerObjectIsNull)
    {
        Write-Host "Taxonomy session: " $sTaxonomySession.Path.Identity "" -ForegroundColor Green
        $sTermStore = $sTaxonomySession.GetDefaultSiteCollectionTermStore()
        $sCtx.Load($sTermStore)
        $sCtx.ExecuteQuery()
        if ($sTermStore.IsOnline)
        {
            Write-Host "Term Store connected:" $sTermStore.Id "" -ForegroundColor Green
            $sCtx.Load($sTermStore.Groups)
            $sCtx.ExecuteQuery()
            foreach ($sTermGroup in $sTermStore.Groups)
            {
                if ($sTermGroup.Name -eq $TermGroupName)
                {
                    Write-Host "Term Group: " $sTermGroup.Name "-" $sTermGroup.Id "" -ForegroundColor Green
                    $termSets = $sTermGroup.TermSets
                    $sCtx.Load($termSets)
                    $sCtx.ExecuteQuery()
                    $termSet = $termSets.GetByName($TermSetName)
                    $sCtx.Load($termSet)
                    $sCtx.ExecuteQuery()
                        Write-Host "Term Set found: " $termSet.Name ", Current Owner: " $termSet.Owner "" -ForegroundColor Green
                        $termSet.Owner = $NewOwner
                         Write-Host "Owner changed to: " $NewOwner "" -ForegroundColor Cyan
                }
            }
            Write-Host "Committing..." -ForegroundColor Cyan
            $sTermStore.CommitAll()
            $sCtx.ExecuteQuery()
            Write-Host "Done!" -ForegroundColor Green
        }
    }
}

USAGE

.\ChangeTermSetOwner.ps1 -Url https://myspsite.sharepoint.com -NewOwner newowner@myspsite.com -TermGroupName MyTermGroup -TermSetName MyTermSet -AdminUsername adminusername@myspsite.com

August 27, 2014

WAC doesn’t work from specific SharePoint Web Applications

Problem

WAC (Office Web Apps) works from some SharePoint 2013 web applications of a farm, but not from some. You get the normal errors when trying to view document on the problematic web application via WAC, like:

Sorry, there was a problem and we can't open this document. If this happens again, try opening the document in Microsoft Word.

Solution

Make sure the AAM settings for the web application are configured so that the URL being used is set as Default Zone. There are of course millions of other reasons for the error above, but in my case everything else was configured correctly.

Technorati Tags:

March 11, 2014

SharePoint: Web Part Title URL with Refinement QueryString parameter

Task

I wanted to point SharePoint Web Part Title URL to a search results page with prepopulated refinement values. It didn’t work, as in Web Part settings, whenever I tried to input a valid URL with refinement parameter, I got error.

Example URL with refinement QueryString that didn’t work:

/Pages/MyPage.aspx?r=owstaxIdMyCategory:"a6c4a141-1b0e-4a2e-a7f7-2479251e3505"

 

Solution

You need to encode the colon (:) with %3A, so Web Part Title URL field becomes

/Pages/MyPage.aspx?r=owstaxIdMyCategory%3A"a6c4a141-1b0e-4a2e-a7f7-2479251e3505".

January 22, 2014

TFS: Delete workspace of another user

Task

I changed my account on Team Foundation Server Online and had multiple workspaces bound to my old account, so when trying to create new workspace I could do so as there was already a workspace created for my old account.

Solution

You need to use TF command on Visual Studio command prompt to remove the old workspace. Syntax is:

tf workspace /delete "WORKSPACENAME;PREVIOUSUSERACCOUNT”

as this was TFS Online, it was Microsoft Account, so in my case actual command was

tf workspace /delete "MIWORKSPACE;juss.palo@sulava.com"

January 10, 2014

SharePoint: Hide list rows with CSR

Problem

I needed to hide certain rows on a list view on SharePoint 2013, namely all items that contained either _ or @ characters. I couldn’t use normal list view filtering as there is no “NOT CONTAINS” clause in CAML.

Solution a.k.a dirty hack

I’m not too happy with the outcome, but I just couldn’t figure out how to override item rendering and only render item row if Title of the item didn’t contain the characters in question. What I ended up doing was using Client Side Rendering together with jQuery and postRenderHandler to remove the TR rows from DOM.

I didn’t want to customize the XSLT of the XsltListViewWebPart and use a simple XSL:IF to filter out the items because as soon as I customized the XSLT in SharePoint Designer, the UI of the list reverted to SP2010 look and feel. I really wanted to maintain the SP2013 look.

Oh, and the code, put it into a file, and reference it from JSLink on your list view web part:

var MiPortalViews = MiPortalViews || {};

(function () {
  var MiPortalOverrides = {};
  MiPortalOverrides.Templates = {};

  MiPortalOverrides.OnPostRender = [];
  MiPortalOverrides.OnPostRender.push(postRenderHandler);

  SPClientTemplates.TemplateManager.RegisterTemplateOverrides(MiPortalOverrides);
})();

function postRenderHandler()
{
    j("a:contains(_):contains(@)").closest("tr").remove(); 
}

January 8, 2014

SharePoint: Manually upgrade Service Application database

Task

After upgrading from SharePoint 2010 to SharePoint 2013, I didn’t need to upgrade all possible Service Applications, but Managed Metadata was one I needed to upgrade. Following TechNet instructions and trying to create new Managed Metadata Service Application using the old SP2010 database never completer, the PowerShell command just stuck and never finished – also the MM Service Application was stuck in Stopped state and couldn’t be started with $mms.Provision().

So, I created fresh Managed Metadata SA, and restored the old database over the new one, after which the Database Upgrade Status page showed that the database would need to be upgraded, how to do that? First guess was $db.Upgrade(), but that wasn’t it.

image

Solution

In order to upgrade the database, you need to provision it. So, in PowerShell do the following:

  1. Get a list of databases: Get-SPDatabase
  2. Get a hold of the database you want to upgrade: $db = Get-SPDatabase <GUID OF THE DATABASE FROM PREVIOUS STEP>
  3. Finally do the upgrade: $db.Provision()

All done!