tim laqua dot com Thoughts and Code from Tim Laqua


Hiding SSAS Attributes With Powershell

The challenge here was that we have a cube with some great data as well as some low level detail (customer detail, think PII) that we want to expose to a larger audience. The problem is that the low level detail is not something that the new audience needs (or in some cases, is allowed) to have access to. The obvious answer here is Dimension security - why not use that? Two reasons. First, Dimension security is slow. Second, even if it wasn't slow, to hide all the data in many (30+) attributes is tedious to setup, and when new attributes were added we would have to make sure and disable access to those as well. To be clear, we're not just hiding attributes here, we're creating an entire copy of the existing SSAS database and hiding attributes in the copy.

# Import Required Libraries
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.AnalysisServices") >$NULL
# Connect to server
$server = New-Object Microsoft.AnalysisServices.Server
# Make a metadata copy of the existing cube
$newdb = $server.Databases.GetByName('POS Data').Clone()
# Change ID and Name of SSAS DB
$newdb.Name = 'POS Data - Limited'
$newdb.ID = 'POS Data - Limited'
# Drop Existing SSAS DB if it exists
$server.Databases['POS Data - Limited'].Drop()
# Add the new copy to the server
# Sync our copy of the new database with the server's copy
# Grab the cube we want to work with from the new database
$cube = $newdb.Cubes.GetByName('POS Data')
# Hide the Location Dimension
$cube.Dimensions.GetByName('Location').Visible = $false
# Hide all attributes and hierarchies in the Customer dimension
$cube.Dimensions.GetByName('Customer').Attributes |  %{$_.AttributeHierarchyEnabled=$false; $_.AttributeHierarchyVisible=$false;}
$cube.Dimensions.GetByName('Customer').Hierarchies | %{$_.Visible=$false; $_.Enabled=$false;}
# Enable the key attribute in the customer dimension - it won't work if the key isn't enabled
$cube.Dimensions.GetByName('Customer').Attributes['Dim Customer'].AttributeHierarchyEnabled=$true
# Enable the Market attribute in the customer dimension
$cube.Dimensions.GetByName('Customer').Attributes['Market'] | %{$_.AttributeHierarchyEnabled=$true; $_.AttributeHierarchyVisible=$true;}
# Hide the Location Database attribute in the Product dimension
$cube.Dimensions.GetByName('Product').Attributes['Location Database'] | %{$_.AttributeHierarchyEnabled=$false; $_.AttributeHierarchyVisible=$false;}
# Add a new member to the role granting Read Only permissions in the cube
$newMember = new-object Microsoft.AnalysisServices.RoleMember("domain\tlaqua")
$newdb.Roles['Role 1'].Members.Add($newMember)
# Push our updates to the server
# Process the new database
# Disconnect from the server

This approach has two notable downfalls. First, you have to think up a different database name because the original db with the low level detail still exists on the server. Second, you have to ProcessFull the clone that you made. It doesn't close the data, it clones the metadata. All in all, works great for us, this particular cube is only processed once a week and the 20 minutes we lose processing data in to the clone is more than acceptable (looks really clean to the users as well).

Comments (2) Trackbacks (0)
  1. Hi-
    If the requirement was just to provide a different view without security implication, wouldn’t a perspective be a good option?

    Saurav M

    • It’d be a great option! We actually have a perspective in that particular cube that has almost exactly the same visibility. The reason we ended up here instead was twofold. First, this is easy, it’s just a quick few lines of code. Second, here we can actually flip the AttributeHierarchyEnabled property to make that data much harder to get at than a perspective would (where perspectives are all about visibility, think just AttributeHierarchyVisible).

Leave a comment

No trackbacks yet.