Localization migration from AIP classic client to Security and Compliance Center

This post has been republished via RSS; it originally appeared at: New blog articles in Microsoft Tech Community.

 

With the recent announcement and sunset scheduling of AIP classic client and the AIP label management portal, the need to migrate to Security and Compliance Center (SCC) is becoming an important task to achieve as soon as possible.
There are 3 main objects in the policy definition that can be migrated to the Security and Compliance portal. Some of the object migrations are automated and some of must be completed manually:

  • Label definition – automatically migrated when you click the Activate button.
  • Different policies - can be copied automatically, make sure to pay attention to the fact that the copy policy  automatically publishes the policies in the Security and Compliance portal.
  • Localization settings-manual process (until today).

Today, we are happy to share an internal  tool,  built by one of our PFEs (Kudos to Friedrich Weinmann) to semi-automate the localization settings migration  process.
Instructions to make the Localization settings migration process as easy as possible are provided below.

 

Note: In case you are using automatic conditions in your policy for automatic labeling, they still need to be reconfigured on the SCC portal.

 

Disclaimer: This tool is not provided with  support or maintenance by Microsoft. This tool is shared with you for use under your  consideration only.

 

1.Connecting

Connect to the Security & Compliance Center using PowerShell.

There are two ways you can login into the SCC using PowerShell:

 

After the connection is established, export the XML and load the command that will perform the import:

 

2.Exporting the localization XML

From the Azure Information Protection portal,  export the languages that you are interested in importing  to  Security and Compliance label configuration.

 

 

AIP portal.jpg

 

3. Loading the command

 

Paste the following function definition into the console with the established connection from Step . Note that pasting the function does not perform any changes.

 

--------

Function Import-LegacyLabelXml {

    <#

    .SYNOPSIS

        Imports labels into the Security & Compliance Center from an export-xml of classic AIP labels.

        This import only applies to localization components of tags!

    

    .DESCRIPTION

        Imports labels into the Security & Compliance Center from an export-xml of classic AIP labels.

 

        This avoids having to manually update labels in multiple-language scenarios.

        This import only applies to localization components of tags!

 

        Settings will be merged into existing labels, if those already exist.

        

        Important:

        This command assumes you are already connected to the Office365 Security & Compliance Center!

    

    .PARAMETER Path

        Path to the XML file(s) to import.

    

    .PARAMETER Replace

        By default, keys for existing languages are not overwritten.

        Enabling this switch will instead overwrite those with the strings defined in the import xml.

    

    .EXAMPLE

        PS C:\> Get-ChildItem C:\export\*.xml | Import-LegacyLabelXml

 

        Imports all the xml files in C:\export, parses them for label DisplayNames and descriptions and uploads them into S&CC.

    #>

    [CmdletBinding()]

    param (

        [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]

        [Alias('FullName')]

        [string[]]

        $Path,

 

        [switch]

        $Replace

    )

 

    begin {

        #region Utility Functions

        function Write-LabelObject {

            [CmdletBinding()]

            param (

                [string]

                $Name,

 

                [AllowNull()]

                [AllowEmptyString()]

                [string]

                $Parent,

 

                [string]

                $Identity,

 

                [string]

                $Language,

 

                [string]

                $Setting,

 

                [string]

                $Text,

 

                [string]

                $DefaultText,

 

                [Hashtable]

                $DataSet,

 

                [Hashtable]

                $Labels

            )

        

            if (-not $DataSet[$Identity]) {

                $DataSet[$Identity] = [PSCustomObject]@{

                    Name        = $Name

                    Parent      = $Parent

                    Identity    = $Identity

                    ID          = $Labels[$Identity].Guid

                    ParentID    = $(if ($Parent) { $Labels[$Parent].Guid } else { $null })

                    Description = @{ }

                    DisplayName = @{ }

                }

                $DataSet[$Identity].$($Setting)['default'] = $DefaultText

            }

 

            $DataSet[$Identity].$($Setting)[$Language] = $Text

        }

 

        function Update-LocalizedLabel {

            [CmdletBinding()]

            param (

                $DataObject,

 

                [Hashtable]

                $Labels,

 

                [bool]

                $Replace

            )

 

            Write-Verbose "Updating $($DataObject.Identity)"

            $identity = $DataObject.ID

            if (-not $identity) { $identity = $Labels[$DataObject.Identity].Guid }

 

            $jsonData = $Labels[$DataObject.Identity].LocaleSettings | ConvertTo-Json

            $displayNameList = @{ }

            foreach ($entry in ($jsonData | Where-Object LocaleKey -eq "displayName").Settings) {

                $displayNameList[$entry.Key] = @{

                    Key   = $entry.Key

                    Value = $entry.Value

                }

            }

            foreach ($languageKey in $DataObject.DisplayName.Keys) {

                if (-not $Replace -and $displayNameList[$languageKey]) { continue }

                $displayNameList[$languageKey] = @{

                    Key   = $languageKey

                    Value = $DataObject.DisplayName[$languageKey]

                }

            }

            $displayNameObject = [PSCustomObject]@{

                LocaleKey = 'DisplayName'

                Settings  = @($displayNameList.Values | Write-Output)

            }

            Set-Label -Identity $identity -LocaleSettings (ConvertTo-Json $displayNameObject -Depth 3 -Compress)

 

            $tooltipList = @{ }

            foreach ($entry in ($jsonData | Where-Object LocaleKey -eq "tooltip").Settings) {

                $tooltipList[$entry.Key] = @{

                    Key   = $entry.Key

                    Value = $entry.Value

                }

            }

            foreach ($languageKey in $DataObject.Description.Keys) {

                if (-not $Replace -and $tooltipList[$languageKey]) { continue }

                $tooltipList[$languageKey] = @{

                    Key   = $languageKey

                    Value = $DataObject.Description[$languageKey]

                }

            }

            $tooltipObject = [PSCustomObject]@{

                LocaleKey = 'Tooltip'

                Settings  = @($tooltipList.Values | Write-Output)

            }

            Set-Label -Identity $identity -LocaleSettings (ConvertTo-Json $tooltipObject -Depth 3 -Compress)

        }

 

        function New-LocalizedLabel {

            [CmdletBinding()]

            param (

                $DataObject,

 

                [Hashtable]

                $Labels

            )

 

            Write-Verbose "Creating $($DataObject.Identity)"

            $parameters = @{

                Name = [guid]::NewGuid()

                DisplayName = $DataObject.Name

            }

            if ($DataObject.ParentID) {

                $parameters['ParentID'] = $DataObject.ParentID

            }

            elseif ($DataObject.Parent) {

                $parameters['ParentID'] = $Labels[$DataObject.Parent].Guid

            }

 

            $newLabel = New-Label @parameters | Select-Object -Property Name, DisplayName, Guid, ParentID, LocaleSettings, Identity

            $newLabel.Identity = $DataObject.Identity

            $Labels[$newLabel.Identity] = $newLabel

 

            Update-LocalizedLabel -DataObject $DataObject -Labels $Labels -Replace $true

        }

        #endregion Utility Functions

        

        $dataSet = @{ }

        $labelBase = @{ }

        $labels = @{ }

 

        $labelData = Get-Label | Select-Object -Property Name, DisplayName, Guid, ParentID, LocaleSettings, Identity

            

        foreach ($label in $labelData) {

            $labelBase[$label.Guid] = $label

        }

        foreach ($label in $labelData) {

            $identity = $label.DisplayName

            if ($label.ParentID) { $identity = '{0}/{1}' -f $labelBase[$label.ParentID].DisplayName, $label.DisplayName }

            $labels[$identity] = $label

        }

    }

 

    process {

        foreach ($filePath in $Path) {

            Write-Verbose "Processing $filePath"

 

            #region Validation

            if (-not (Test-Path $filePath)) {

                Write-Warning "File does not exist: $filePath !"

                throw "File does not exist: $filePath !"

            }

 

            try {

                [xml]$xmlData = Get-Content -Path $filePath -ErrorAction Stop -Encoding utf8

            }

            catch {

                Write-Warning "Input is not a legal XML file: $filePath !"

                throw

            }

            #endregion Validation

 

            #region Process File

            $language = $xmlData.Language.Id

            $localizationData = $xmlData.Language.LocItem |

                Where-Object ID -match '^labelGroups/Sensitivity/labels/.+/(DisplayName|Description)$' |

                    Select-Object @{

                        Name       = 'ID'

                        Expression = {

                            $_.ID.Replace("labelGroups/Sensitivity/labels/", "")

                        }

                    }, defaultText, LocalizedText

            foreach ($localDatum in $localizationData) {

                $parent = $null

                $identity = ($localDatum.ID -split "/")[-2]

                if (($localDatum.ID -split "/").Count -ge 4) {

                    $parent = ($localDatum.ID -split "/")[-4]

                    $identity = '{0}/{1}' -f $parent, $identity

                }

                $parameters = @{

                    Name        = ($localDatum.ID -split "/")[-2]

                    Parent      = $parent

                    Identity    = $identity

                    Language    = $language

                    Setting     = ($localDatum.ID -split "/")[-1]

                    Text        = $localDatum.LocalizedText

                    DefaultText = $localDatum.defaultText

                    DataSet     = $dataSet

                    Labels      = $labels

                }

                Write-LabelObject @parameters

            }

            #endregion Process File

        }

    }

    end {

        foreach ($labelObject in ($dataSet.Values | Where-Object Parent -eq "")) {

            if ($labelObject.ID) { Update-LocalizedLabel -DataObject $labelObject -Labels $labels -Replace $Replace.ToBool() }

            else { New-LocalizedLabel -DataObject $labelObject -Labels $labels }

        }

 

        foreach ($labelObject in ($dataSet.Values | Where-Object Parent -ne "")) {

            if ($labelObject.ID) { Update-LocalizedLabel -DataObject $labelObject -Labels $labels -Replace $Replace.ToBool() }

            else { New-LocalizedLabel -DataObject $labelObject -Labels $labels }

        }

    }

}

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

When completed, you are ready to proceed with the import.

 

4.Importing label localization XML files

When preparations are completed, import the XML files thatcontain the export of the label localization data using the following command:

 

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

Get-ChildItem C:\export\*.xml | Import-LegacyLabelXml

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

 

This sample command assumes the files to import were placed in the folder C:\export (make sure to adjust accordingly, if you chose a different path).

 

Notes:

  • You can import any number of language xml files at the same time.
  • You do not need to import all xml files at the same time – you can import additional languages at a later time.
  • If localization for a language already exists (manual entry, previous import) this action  will not overwrite them, unless you also specify the "-Replace" parameter.
  • Importing a localization for a label that does not exist, creates the label.
  • This script does not check the validity of the XML files. Make sure you use the correct XML.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.