SharePoint: Export Managed Metadata terms to XML using PowerShell

This script uses CSOM PowerShell to export terms stored in managed metadata services to XML.

param (
    [string]$tennantUrl,
    [string]$userName,
    [string]$password,
    [string]$termStoreName
 )



#Load all required client assemblies
#If this script is run on a machine where SharePoint is NOT installed, 
#Please copy these libraries from the a SP server and copy to a local directory and update the paths below

Add-Type -Path "C:\Program Files\Common Files\microsoft shared\Web Server Extensions\15\ISAPI\Microsoft.SharePoint.Client.dll" 
Add-Type -Path "C:\Program Files\Common Files\microsoft shared\Web Server Extensions\15\ISAPI\Microsoft.SharePoint.Client.Runtime.dll" 
Add-Type -Path "C:\Program Files\Common Files\microsoft shared\Web Server Extensions\15\ISAPI\Microsoft.SharePoint.Client.Publishing.dll" 
Add-Type -Path "C:\Program Files\Common Files\microsoft shared\Web Server Extensions\15\ISAPI\Microsoft.SharePoint.Client.Taxonomy.dll"

$currentDir = (Resolve-Path .\).Path

 function Initialize(
    [string]$url,
    [string]$user,
    [string]$pass,
    [string]$termStoreName,
    [string]$groupName,
    [string]$termSetName,
    [string]$xmlFilePath
    )
 {

    $ctx = New-Object Microsoft.SharePoint.Client.ClientContext($url);
    $xmlWriter = $null;

    try
    {
        $xmlWriter = New-Object System.Xml.XmlTextWriter($xmlFilePath,$null);
        $xmlWriter.Formatting = [System.Xml.Formatting]::Indented

        $user = $user.Trim();
        $pass = $pass.Trim();

        #$securePassword = ConvertTo-SecureString $pass -AsPlainText -Force 
        #$credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($user, $securePassword) 

        if( [System.String]::IsNullOrEmpty( $user ) )
        {
            $credentials =[System.Net.CredentialCache]::DefaultCredentials;
        } else {
            $credentials = New-Object System.Net.NetworkCredential($user, $pass);
        }

        $ctx.Credentials = $credentials;
        # Works this way, but won't if using just $ctx.  Go figure....
        $ctx2 = [Microsoft.SharePoint.Client.ClientRuntimeContext] $ctx;
        $taxonomySession = [Microsoft.SharePoint.Client.Taxonomy.TaxonomySession]::GetTaxonomySession( $ctx2 );
        $ctx.Load($taxonomySession);
        $ctx.Load($taxonomySession.TermStores);
        $ctx.ExecuteQuery();

        $termStore = $taxonomySession.TermStores.GetByName($termStoreName);
        $groups = $termStore.Groups;

        $ctx.Load($termStore);
        $ctx.Load($groups);
        $ctx.ExecuteQuery();

        $termSetCollection = $termStore.Groups.GetByName($groupName).TermSets;

        $ctx.Load($termSetCollection);
        $ctx.ExecuteQuery();

        $termSet = $termSetCollection.GetByName($termSetName);


        $ctx.Load($termSet);
        $ctx.Load($termSet.Group);
        $ctx.Load($termSet.Terms);
        $ctx.ExecuteQuery( );

        $xmlWriter.WriteStartDocument();

        $xmlWriter.WriteStartElement("termSet");
        $xmlWriter.WriteAttributeString("name", $termSetName );
        $xmlWriter.WriteAttributeString("groupName", $groupName );        

        foreach($term in $termSet.Terms)
        {
            $ctx.Load($term);
            $ctx.ExecuteQuery();

            WriteTerm $xmlWriter $ctx $term;
        }

        $xmlWriter.WriteEndElement();
        $xmlWriter.WriteEndDocument();
        write-host -ForegroundColor Green $xmlFilePath "saved"

    }
    catch
    {
        Write-Host "Error : $($_)";
        #return;
    }
    finally
    {
        if($xmlWriter -ne $null)
        {
            $xmlWriter.Dispose();
        }

        $ctx.Dispose();
    }
 }

function WriteProperties(
    [System.Xml.XmlTextWriter]$writer, 
    [Microsoft.SharePoint.Client.ClientContext]$context, 
    [Microsoft.SharePoint.Client.Taxonomy.TermSetItem]$termSet
)
{
    if (0 -lt $termSet.CustomProperties.Count)
    {        

        foreach ($property in $termSet.CustomProperties.GetEnumerator())
        {            
            $writer.WriteAttributeString($property.Key,$property.Value);       
        }       
    }
}

function WriteLocalProperties(
    [System.Xml.XmlTextWriter]$writer, 
    [Microsoft.SharePoint.Client.ClientContext]$context, 
    [Microsoft.SharePoint.Client.Taxonomy.Term]$term
)
{
    if (0 -lt $term.LocalCustomProperties.Count)
    {       

        foreach ($property in $term.LocalCustomProperties.GetEnumerator())
        {            
            $writer.WriteAttributeString($property.Key,$property.Value);                                        
        }       
    }
}

function WriteTerm( 
    [System.Xml.XmlTextWriter]$writer, 
    [Microsoft.SharePoint.Client.ClientContext]$context, 
    [Microsoft.SharePoint.Client.Taxonomy.Term]$term
)
{
    $writer.WriteStartElement("term");
    $writer.WriteAttributeString("name", $term.Name);   

    $context.Load($term.Terms);
    $context.ExecuteQuery();

    WriteProperties $writer $context $term;
    WriteLocalProperties $writer $context $term

    if(0 -lt $term.Terms.Count)
    {

        $writer.WriteStartElement("terms");

        foreach ($child in $term.Terms)
        {
            WriteTerm $writer $context $child;
        }

        $writer.WriteEndElement();
    }

    $writer.WriteEndElement();
}