Is there an AR commandlets (get-qadobejct ) or other means to return the count of managed objects -vs- licensed external to the console?

creating an admin dashboard for my management that expects an on demand health assessment of 'where we are' on ActiveRoles Server Trinity - ARS/SQL/IIS system availability, license compliance, performance etc

I'm building out a dashboard to show at a glance this information …

powerCLI gives me VM related is-it-up, is-it-running data, along with disk/cpu data
invoke-webrequest gives me real world 'is it responding' to users for AD requests - for each site server
spml via PS New-WebServiceProxy  can provide proof the service is running and returning data for each SPML endpoint

what I don't have, need is the license compliance stuff in a nut I can crack without guidance.

Is there an exploitable node in the running configuration with get-qadobject <managed object container> …

if so, my bulb is too dim to see it.

thoughts?

for QAS (now Safeguard Authentication Services) has a command line license retrieval commandlets, Recovery Manager for AD as well, but none for ARS that I've found.

Top Replies

Parents
  • Hey  ,

    A group of us took a look at this, here's what we found.

         


    A Quick Explanation

    Just so you're aware, the Product Usage Statistics, for the most part, only matter for customers who are still on the old enabled users licensing model. If you are on the newer Managed Persons licensing model, then the only numbers that are relevant here are the Azure guest (Cloud only) Users, which uses a separate license. Everything else is covered under the Managed Persons model, which is not calculated by Active Roles directly. That may be enough of a reason to skip including this data in your dashboard, but if you still need to include it, here's the best answer I have.


    The (not so) Simple Answer

    The Product Usage Statistics are updated via a Builtin Scheduled Task, Managed Object Counter:

    This task writes to the Active Roles database, in a table called ManagedObjectStatistics, in which we can see that the statistics have a type of edsManagedObjectStatisticsData and are located in the CN=Managed Object Statistics,CN=Server Configuration,CN=Configuration container.

    The "simple" answer, is you can find them with get-qadobject:

    get-qadobject -SearchRoot "CN=Managed Object Statistics,CN=Server Configuration,CN=Configuration" -Type edsManagedObjectStatisticsData

    But, you'll see it isn't quite that simple.


    Getting the Real Data

    First, there could be multiple edsManagedObjectStatisticsData objects that exist, and we only need one -- the latest. We can pull this from the whenChanged property. I'm not quite sure what causes new objects to get created here, I seemed to have multiple in my lab, ranging back to some older versions of ARS and a few upgrades, but running the scheduled task will either create a new entry, or update one with a new whenChanged datetime value.

    Second, the actual usage stats are stored in XML format in a field called edsaStatisticsCountXML, which is not returned by default. So we need to include both this and whenChanged, and then parse & decipher the XML data.

    This code snippet shows how to pull the latest Statistics XML Data, and cast it from XML to a native Powershell object.

    $Stats = get-qadobject -SearchRoot "CN=Managed Object Statistics,CN=Server Configuration,CN=Configuration" -Type edsManagedObjectStatisticsData -IncludedProperties "edsaStatisticsCountXML","whenChanged" | Sort-Object -Descending -Property whenChanged | select-object -First 1 -ExpandProperty "edsaStatisticsCountXML"
    $StatXML = ([XML]$Stats).StatisticsRun

    The raw XML will look something like this:

    <StatisticsRun xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" runTime="132894959034594757" serviceName="App.ajlindner.local" xmlns="urn:schemas-quest-com:ActiveRolesServer">
      <Domains>
        <Domain>
          <DisplayName>ajlindner.local</DisplayName>
          <DN>DC=ajlindner,DC=local</DN>
          <Guid>29fe05c9-6b32-48c4-92ea-b1bdd81ea793</Guid>
          <Count>57</Count>
          <IsFailure>false</IsFailure>
        </Domain>
        <Domain>
          <DisplayName>ONEID.lab</DisplayName>
          <DN>DC=ONEID,DC=lab</DN>
          <Guid>771f3907-d262-4069-865d-5289610beb44</Guid>
          <Count>354</Count>
          <IsFailure>false</IsFailure>
        </Domain>
      </Domains>
      <Partitions>
        <Partition>
          <DisplayName>Test on dc.ajlindner.local:50000</DisplayName>
          <DN>CN=Test,DC=AJLDS,DC=Local</DN>
          <Guid>2ffb4cec-9e7f-4d76-8883-bb2fd78ee296</Guid>
          <Count>23</Count>
          <IsFailure>false</IsFailure>
        </Partition>
      </Partitions>
      <AzureObjectsInfo>
        <AzureCount>
          <DisplayName>ajlindner.xyz</DisplayName>
          <DN>CN=ajlindner.xyz,CN=Azure Tenants,CN=Azure Configuration,CN=Azure,CN=Configuration</DN>
          <Guid>f7449650-7712-4e45-9ee8-39ea7affe196</Guid>
          <CloudOnlyCount>4</CloudOnlyCount>
          <HybridCount>10</HybridCount>
          <GuestCount>2</GuestCount>
          <IsFailure>false</IsFailure>
        </AzureCount>
        <AzureCount>
          <DisplayName>ajlindner.info</DisplayName>
          <DN>cn=ajlindner.info,CN=Azure Tenants,CN=Azure Configuration,CN=Azure,CN=Configuration</DN>
          <Guid>129a584a-2aa5-4eb7-9aab-9cf2c240fc72</Guid>
          <CloudOnlyCount>45</CloudOnlyCount>
          <HybridCount>282</HybridCount>
          <GuestCount>107</GuestCount>
          <IsFailure>false</IsFailure>
        </AzureCount>
      </AzureObjectsInfo>
      <SAASObjects>
        <SAASObject>
          <DisplayName>Starling Connect</DisplayName>
          <DN>Starling Connect</DN>
          <Guid>8df48057-9104-43c9-b6ab-b4cfa092a0de</Guid>
          <Count>41</Count>
          <IsFailure>false</IsFailure>
        </SAASObject>
      </SAASObjects>
    </StatisticsRun>

    From here, you can poke around inside the $StatXML object to find the relevant statistics info.


    Missing Data

    The XML Data only includes a few raw data points, and the rest of what shows in the MMC seems to be generated, calculated, or hard-coded behind the scenes somehow.

    We won't be able to get the "User account type" display name, although the data does tell us what type of count we're looking at. We can't see the "License type", and we can't see the "Total estimated licenses".

    What we can get is the raw counts for every AD Domain, AD LDS Partition, SaaS Application, and Azure Tenant (broken down by Hybrid, Cloud, and Guest).


    Parsing the XML

    I went ahead and did some parsing of the XML data as an example for you. This pulls everything out and organizes it sort of like the Product Usage Statistics table, but please feel free to take and modify my code snippet for your needs. This is not good code, it is quick and dirty code Slight smile

    $Statistics = New-Object System.Collections.Arraylist
    
    # Get AD Domain Stats
    ForEach ($Domain in $StatXML.Domains.Domain) {
        $DomainStats = [pscustomobject]@{
            'User Account Type' = 'Active Directory (AD)'
            Source = $Domain.DisplayName
            'Total Accounts' = $Domain.Count
        }
        $Statistics.Add($DomainStats) | Out-Null
    }
    
    # Get AD LDS Stats
    ForEach ($Partition in $StatXML.Partitions.Partition) {
        $PartitionStats = [pscustomobject]@{
            'User Account Type' = 'AD LDS Partition'
            Source = $Partition.DisplayName
            'Total Accounts' = $Partition.Count
        }
        $Statistics.Add($PartitionStats) | Out-Null
    }
    
    # Get Azure Instance Stats
    ForEach ($Instance in $StatXML.AzureObjectsInfo.AzureCount) {
        
        # Hybrid
        $HybridStats = [pscustomobject]@{
            'User Account Type' = 'Azure (Hybrid Linked to AD Accounts)'
            Source = $Instance.DisplayName
            'Total Accounts' = $Instance.HybridCount
        }
    
        # Cloud
        $CloudStats = [pscustomobject]@{
            'User Account Type' = 'Azure (Cloud Only)'
            Source = $Instance.DisplayName
            'Total Accounts' = $Instance.CloudOnlyCount
        }
    
        # Guest
        $GuestStats = [pscustomobject]@{
            'User Account Type' = 'Azure Guest (Cloud Only)'
            Source = $Instance.DisplayName
            'Total Accounts' = $Instance.GuestCount
        }
    
    
        @($HybridStats,$CloudStats,$GuestStats) | ForEach {
            $Statistics.Add($_) | Out-null
        }
    }
    
    
    # Get SaaS Application Stats
    ForEach ($App in $StatXML.SaaSOBjects.SaaSObject) {
        $AppStats = [pscustomobject]@{
            'User Account Type' = 'SaaS Application'
            Source = $App.DisplayName
            'Total Accounts' = $App.Count
        }
        $Statistics.Add($AppStats) | Out-Null
    }
    
    # View Statistics
    $Statistics | Sort "User Account Type"

    Example Output:

     


    Remaining Questions

    If anyone else comes across this and knows the answers, I'm still curious about these questions.

    1. What would cause a new entry into the ManagedObjectStatistics table vs. updating the latest entry?
    2. Where does the MMC pull the "User account type" and "License type" field data from? Is that coded into the MMC, or can that be queried as well?
    3. I'll look into this and reply if I find the answer -- is there a way to execute the Managed Object Counter scheduled task from Powershell? It might be useful in this scenario to run a fresh update.
  • Thanks for the very thorough reply - Open mouth -  I had to tweak a few lines before the parseXML script worked for me.  Now good.

    Good and Useful info ... as we are on the original licensing model.   Re-reading your post and following it 'precisely' - works like a charm.  

Reply Children
No Data