Before you start...

Scenario

    The Syndication Partner is planning on implementing an Activation Project where customers who have purchased the service but have never assigned licenses to users, will be contacted via phone to assist them in activating their Office 365 service.

    The Syndication Partner must retrieve from MOP the list of customers and the SKUs they have purchased.  It is necessary to have the number of licenses for each SKU and the life cycle status of those licenses as well as whether the licenses have been assigned to users.  The partner plans to offer a free custom domain to the customer if the customer is available to activate the service within a week of having made first contact and thus, the partner also wants to learn which customers don't have any custom domain and become good candidates for the incentive.

    The Syndication Partner can obtain this information using Windows Azure Active Directory Module for Windows PowerShell cmdlets (previously known as the Microsoft Online Services Module for Windows PowerShell cmdlets).

       

Get Report for All Customers 

    Input
      None. The script will retrieve information for all customer tenants of the partner
    Output
      Two CSV files located in C:\Scripts named:
      • ActivationReport.csv => List of all SKUs for each customer including seats available, in grace period, disabled, assigned, date when first subscription was created for that SKU, domain information that includes the initial and default domains as well as the total count of domains registered in Office 365 for that customer and finally, a filter that indicates whether that customer is a candidate for the activation campaign and what actions are needed for any of the SKUs that the customer owns.  The partner is encouraged to use Pivot Tables to organize the information retrieved.
      • InvalidTenants.csv => List of tenants that at some point had one or more subscription, all of which are now deprovisioned.  The file may not always contain information if the partner does not have customers with all subscriptions deprovisioned.
      One txt file  located in C:\Scripts named:
      • TenantList.txt =>  List of all tenants for the partner with active, in grace period, disabled or deprovisioned subscriptions
       *** NOTE:  The folder C:\Scripts must exist prior to running the script
    Sample Script

Clear-Host
Write-Progress -Id 1 -Activity "Get tenant list" -Status "Retrieving... this may take several minutes"
$tenantList = Get-MsolpartnerContract -All | Format-Table -Property TenantID -AutoSize -HideTableHeaders | Out-file "C:\Scripts\TenantList.txt"
(get-content "C:\Scripts\TenantList.txt") | where {$_ -ne ""} | out-file "C:\Scripts\TenantList.txt"
$myOutput=@()
$myInvalidOutput=@()
$inputFile = get-content "C:\Scripts\TenantList.txt"
$totTenants =  $inputfile.count
foreach ($tenantItem in $inputFile)
    {
        $tenantCount = $tenantItem.readcount
        Write-Progress -Id 1 -Activity "Get tenant list" -Status "Completed" -PercentComplete 100
        Write-Progress -Id 2 -Activity "Validating tenant list and retrieving data" -PercentComplete (($tenantCount/ $totTenants)*100) -CurrentOperation " processing $tenantCount of $totTenants" -status "Please wait"   
        $Company = Get-MsolCompanyInformation -TenantID $tenantItem -ErrorAction SilentlyContinue
        If (!$?)
            {
                $objInvalid = New-Object system.object
                $objInvalid | Add-Member -Type NoteProperty -Name TenantID -value $tenantItem
                $myInvalidOutput += $objInvalid
            }
        Else
            {                        
                $Domain = Get-MsolDomain -TenantID $tenantItem
                $Seat = Get-MsolAccountSku -TenantID $tenantItem
                $Subscription = Get-MsolSubscription -TenantID $tenantItem
                $activation = $false
                $InitialDomain = ""
                $DefaultDomain = ""
                foreach ($domainItem in $domain)
                    {
                        Switch ($domainItem.IsInitial)
                            {
                                $true {$InitialDomain = $domainItem.Name}    
                            }
                        Switch ($domainItem.IsDefault)
                            {
                                $true {$DefaultDomain = $domainItem.Name}    
                            }
                    }
                foreach($seatItem in $Seat)
                    {
                        Switch ($seatitem.skupartnumber)
                            {
                                "EXCHANGESTANDARD" {$OfferN = "Exchange Online (Plan 1)"}
                                "EXCHANGEENTERPRISE" {$OfferN = "Exchange Online (Plan 2)"}
                                "EXCHANGEARCHIVE_ADDON" {$OfferN = "Exchange Online Archiving (EOA) for Exchange Online Customers"}
                                "EXCHANGEARCHIVE" {$OfferN = "Exchange Online Archiving (EOA) for Exchange Server"}
                                "EXCHANGEDESKLESS" {$OfferN = "Exchange Online Kiosk"}
                                "EXCHANGETELCO" {$OfferN = "Exchange Online POP"}
                                "MCOIMP" {$OfferN = "Lync Online (Plan 1)"}
                                "MCOSTANDARD" {$OfferN = "Lync Online (Plan 2)"}
                                "MCOVOICECONF" {$OfferN = "Lync Online (Plan 3)"}
                                "MCOVOICEESS" {$OfferN = "Lync to Phone 'Add-on'"}
                                "STANDARDPACK" {$OfferN = "Office 365 Enterprise E1"}
                                "STANDARDWOFFPACK" {$OfferN = "Office 365 Enterprise E2"}
                                "ENTERPRISEPACK" {$OfferN = "Office 365 Enterprise E3"}
                                "ENTERPRISEWITHSCAL" {$OfferN = "Office 365 Enterprise E4"}
                                "DESKLESSPACK" {$OfferN = "Office 365 Enterprise K1"}
                                "DESKLESSWOFFPACK" {$OfferN = "Office 365 Enterprise K2"}
                                "MIDSIZEPACK" {$OfferN = "Office 365 Midsize Business"}
                                "OFFICESUBSCRIPTION" {$OfferN = "Office 365 ProPlus"}
                                "LITEPACK" {$OfferN = "Office 365 Small Business"}
                                "LITEPACK_P2" {$OfferN = "Office 365 Small Business Premium"}
                                "WACSHAREPOINTSTD" {$OfferN = "Office Web Apps with SharePoint Plan 1"}
                                "WACSHAREPOINTENT" {$OfferN = "Office Web Apps with SharePoint Plan 2"}
                                "PROJECTCLIENT" {$OfferN = "Project Pro for Office 365"}
                                "SHAREPOINTSTANDARD" {$OfferN = "SharePoint Online (Plan 1)"}
                                "SHAREPOINTENTERPRISE" {$OfferN = "SharePoint Online (Plan 2)"}
                                "SHAREPOINTSTORAGE" {$OfferN = "SharePoint Online Storage"}
                                "VISIOCLIENT" {$OfferN = "Visio Pro for Office 365"}
                                Default {$OfferN = ""}
                            }
                        $earliest = Get-Date
                        foreach ($subscriptionItem in $Subscription)
                            {
                                if ($subscriptionItem.DateCreated -lt $earliest -And $subscriptionItem.SkuPartNumber -eq $seatitem.skupartnumber) {$earliest = $subscriptionItem.DateCreated}
                            }
                        $message = ""
                        If (($SeatItem.ActiveUnits -gt 0) -And ($SeatItem.WarningUnits -eq 0) -And ($SeatItem.ConsumedUnits -eq 0))
                            {
                                $message = "ACTIVATION OPPORTUNITY | No seats assigned yet"
                                $activation = $true
                            }
                        ElseIf (($SeatItem.ActiveUnits -eq 0) -And ($SeatItem.WarningUnits -gt 0) -And ($SeatItem.ConsumedUnits -eq 0))
                            {
                                $message = "ACTIVATION OPPORTUNITY | No seats assigned yet, all licenses are about to expire"
                                $activation = $true
                            }
                        ElseIf (($SeatItem.ActiveUnits -gt 0) -And ($SeatItem.WarningUnits -gt 0) -And ($SeatItem.ConsumedUnits -eq 0))
                            {
                                $message = "ACTIVATION OPPORTUNITY | No seats assigned yet, some licenses are about to expire"
                                $activation = $true
                            }
                        ElseIf ((($SeatItem.ActiveUnits + $SeatItem.WarningUnits) -gt $SeatItem.ConsumedUnits) -And  ($SeatItem.ConsumedUnits -gt 0) -And ($SeatItem.SuspendedUnits -eq 0))
                            {
                                $message = "ACTIVATION OPPORTUNITY | Not all seats have been assigned yet"
                                $activation = $true
                            }
                        ElseIf (($SeatItem.ActiveUnits -eq $SeatItem.ConsumedUnits) -AND ($SeatItem.ConsumedUnits -gt 0) -AND ($SeatItem.SuspendedUnits -eq 0) -AND ($SeatItem.WarningUnits -eq 0)) {$Message="NO ACTION NEEDED - Customer has all active licenses assigned"}
                        ElseIf ((($SeatItem.ActiveUnits + $SeatItem.WarningUnits) -lt $SeatItem.ConsumedUnits) -And  ($SeatItem.ConsumedUnits -gt 0) -And ($SeatItem.SuspendedUnits -eq 0)) {$message = "ACTION NEEDED | Customer has more users with licenses than licenses available"}
                        ElseIf (($SeatItem.ActiveUnits -eq 0) -AND ($SeatItem.WarningUnits -eq 0) -AND ($SeatItem.SuspendedUnits -gt 0) -AND ($SeatItem.ConsumedUnits -eq 0)) {$Message="NO ACTION NEEDED - Waiting for subscription life cyle to deprovision subscription"}
                        Else {$message = "Scenario not defined"}
                        $objSummary = New-Object system.object
                        $objSummary | Add-Member -Type NoteProperty -Name TenantID -value $tenantItem
                        $objSummary | Add-Member -Type NoteProperty -Name CompanyName -value $Company.DisplayName
                        $objSummary | Add-Member -Type NoteProperty -Name OnMicrosoftDomain -value $InitialDomain
                        $objSummary | Add-Member -Type NoteProperty -Name DefaultDomain -value $DefaultDomain
                        $objSummary | Add-Member -Type NoteProperty -Name TotalDomains -value $Domain.Count
                        $objSummary | Add-Member -Type NoteProperty -Name TotalSKUs -value $Seat.Count
                        $objSummary | Add-Member -Type NoteProperty -Name OfferName -value $OfferN
                        $objSummary | Add-Member -Type NoteProperty -Name SKUPartNumber -value $seatitem.skupartnumber
                        $objSummary | Add-Member -Type NoteProperty -Name SKUSubscriptions -value $Seatitem.Subscriptionids.guid.count
                        $objSummary | Add-Member -Type NoteProperty -Name EarliestSKUSubscription -value $earliest
                        $objSummary | Add-Member -Type NoteProperty -Name ActiveSeats -value $seatItem.ActiveUnits
                        $objSummary | Add-Member -Type NoteProperty -Name InGracePeriodSeats -value $seatItem.WarningUnits
                        $objSummary | Add-Member -Type NoteProperty -Name DisabledSeats -value $seatItem.SuspendedUnits
                        $objSummary | Add-Member -Type NoteProperty -Name AssignedSeats -value $seatItem.ConsumedUnits
                        $objSummary | Add-Member -Type NoteProperty -Name ActivationCandidate -value $activation
                        $objSummary | Add-Member -Type NoteProperty -Name SKUSpecificAction -value $Message
                        $myOutput += $objSummary
                    }
            }    
    }
$myOutput | export-csv -Path "C:\Scripts\ActivationReport.csv" -NoTypeInformation
$myInvalidOutput | export-csv -Path "C:\Scripts\InvalidTenants.csv" -NoTypeInformation 

    Sample Output

      Click image for better quality

      ActivationReport.csv
      (pending image - please check back later)



      InvalidTenants.csv


      TenantList.txt