Thursday, December 15, 2016

Unable to delete contacts from Outlook Contacts folder (Skype for Business or Lync)

Scenario:

You want to delete contacts from Office 365 Outlook folder: "Skype for Business Contacts" or "Lync Contacts". You get error:
"You cannot make changes to contents of this read-only folder"

Solution:

Go to the "light" Exchange Online mode: https://outlook.office365.com/owa/?exsvurl=1&layout=light and delete contacts.


Wednesday, December 14, 2016

Easy way to determine UEFI or Legacy BIOS from PowerShell

PowerShell script which determines the underlying system firmware (BIOS) type - either UEFI or Legacy BIOS:

if (Test-Path $env:windir\Panther\setupact.log) {(Select-String 'Detected boot environment' -Path "$env:windir\Panther\setupact.log"  -AllMatches).line -replace '.*:\s+'else {if (Test-Path HKLM:\System\CurrentControlSet\control\SecureBoot\State) {"UEFI"} else {"BIOS"}}

PowerShell script which determines EFI partition:

Get-WmiObject  -query 'Select * from Win32_DiskPartition Where Type = "GPT: System"' | select Name, Index, Bootable, BootPartition,PrimaryPartition, @{n="SizeInMB";e={$_.Size/1MB}}

You may need this information for VMware/Physical machines to Azure with Azure Site Recovery scenario (or even Hyper-V Gen 2 VMs where you don't have actual access to Hyper-V itself, ex. 3rd party IaaS provider). As of today UEFI partitions are not supported in these scenarios and you will end with
ERROR ID 78006
ERROR MESSAGE
The requested operation did not complete. 
PROVIDER ERROR
Provider error code: 95185 Provider error message: Protection could not be enabled. Provider error possible causes: Enable protection failed for the source disks {GUID} on the source machine <Hostname> (IP Address). UEFI partitions are not supported. Provider error recommended action: UEFI partitions are not supported. See http://go.microsoft.com/fwlink/?LinkId=613318 for the pre-requisites.
POSSIBLE CAUSES
Check the provider error for more details.
RECOMMENDATION
Resolve the issue as recommended in the provider error details.

Saturday, November 5, 2016

Cert Exam Prep Materials: 70-740, 70-741, 70-742, 70-743: MCSA: Windows Server 2016

These exams are required for the new MCSA: Windows Server 2016 certification: 70-740, 70-741, 70-742 (or just 70-743 for upgrade from MCSA: Windows Server 2008 or MCSA: Windows Server 2012 R2)


Cert Exam Prep: Exam 70-740: Installation, Storage, and Compute

This Certification Exam Prep session is designed for people experienced with Microsoft Windows Server who are interested in taking the 70-740 exam or the 70-743 exam.

VideoPowerPoint

Cert Exam Prep: Exam 70-741: Networking with Windows Server 2016

This Certification Exam Prep session is designed for people experienced with Microsoft Windows Server who are interested in taking the 70-741 exam or the 70-743 exam.

VideoPowerPoint 

Cert Exam Prep: Exam 70-742: Identity with Windows Server 2016

This Certification Exam Prep session is designed for people experienced with Microsoft Windows Server who are interested in taking the 70-742 exam or the 70-743 exam.

VideoPowerPoint

References

Friday, November 4, 2016

"Office 365 mailbox" button is missing in Exchange Admin Center (EAC) UI

Scenario

You install Microsoft Exchange Server for "Synchronized Identity" management only.
Example: after 3rd party mail server migration (Kerio Mailserver, Lotus Notes, CommunigatePro, etc.) and you have existing Active Directory configured with AAD Connect. Microsoft Exchange Server (EAC or EMS) is the only supported way for "Synchronized Identity" management and configured AAD Connect.
You try to create new "Office 365 mailbox" via EAC UI and with "Organization Management" permissions but no "Office 365 mailbox" button appears.


Notwithstanding this fact, you can create Office 365 mailbox via Exchange Management Shell (New-RemoteMailbox)

Solution

You need to install the Hybrid license key (free for Office 365 customers) on the Exchange Server (there is no need to configure full Exchange Server Hybrid however)

To obtain a Hybrid Edition product key for your Exchange 2010 SP3 or 2013 or 2016 server, go to the Exchange hybrid product key distribution wizard using Office 365 Global Admin credentials.

Apply obtained key to your Hybrid Exchange Server:

Set-ExchangeServer -Identity HybServer01 -ProductKey XXXXX-XXXXX-XXXXX-XXXXX-XXXXX
Get-Service -Name MSExchangeIS -ComputerName HybServer01 | Restart-Service

New-RemoteDomain -Name "Online Domain" -DomainName "tenant.mail.onmicrosoft.com"
Set-RemoteDomain -Identity "Online Domain" -TargetDeliveryDomain $true

Refresh browser session and "Office 365 mailbox" UI button will appear in EAC UI. If not then restart Hybrid server



References:

Tuesday, October 25, 2016

Exchange Cutover migration batch error "Couldn‎'t find object "/o=NT5..."

Scenario:

You migrate mailboxes to Exchange Online using Exchange Cutover scenario. You start the Cutover migration batch, and then you have following error on some users:
Error: ProvisioningFailedException: Failed to update one of the recipient properties. --> Couldn‎'t find object "/o=NT5/ou=9b22534a504ae64e826374ec36c06562/cn=a3b7c64174213644975404f83e27205a". Please make sure that it was spelled correctly or specify a different object.
Unfortunately the error message and the report gives no further details about exactly which recipient property failed to update. The synchronization of affected mailboxes can't be successfully finished due to this error.

Solution:


The reason is that affected on-premises mailbox account may have "Send-On-Behalf" permissions or the "Manager" field which points to disabled Active Directory account (ex. people who are no longer working for the company).  



The solution is to clear this stale account from the properties of affected mailbox. Then stop and re-run the Migration Cutover batch again.
Paul Cunningham provided a couple of PowerShell scripts which allow to find such stale objects:

Friday, September 23, 2016

Add Office 365: Exchange Online e-mail address @contoso.mail.onmicrosoft.com on every mailbox with PowerShell

Scenario

To handle mailflow in a Exchange Hybrid scenario every mailbox needs an e-mail routing address matching the tenant e-mail domain name (contosotenant.mail.onmicrosoft.com).

Hybrid Configuration Wizard (HCW) adds this new configuration automatically and the new e-mail address on every mailbox which has the e-mail address policy enabled on it ("Automatically update email addresses based on the email address policy applied to this recipient" checkbox). Challenge appears when a lot of mailboxes within Exchange organization do not have the e-mail address policy enabled. I hope Exchange HCW development team will fix this behavior soon.

When you try to move mailboxes from your on-premises environment to Exchange Online, you receive the following error message without @contosotenant.mail.onmicrosoft.com-like smtp alias:
The target mailbox doesn't have an SMTP proxy matching '<domain>.mail.onmicrosoft.com'
Solution

Following simple PowerShell script will automatically add the new e-mail address in format  of "alias@contosotenant.mail.onmicrosoft.com" on every mailbox within your Exchange Organization without enabling the e-mail address policy.

$mailboxes=Get-Mailbox -ResultSize Unlimited | where {!$_.EmailAddressPolicyEnabled} | select DisplayName, Alias, PrimarySmtpAddress, Identity

foreach ($mailbox in $mailboxes) {

$alias=$mailbox.alias
$email=$alias + “@contosotenant.mail.onmicrosoft.com”
Set-mailbox $mailbox.Identity -EmailAddresses @{add=$email}
}

$mailboxes | Export-Csv -Path "$env:USERPROFILE\Desktop\mailboxes_changed.csv"


Office 365 users are not appearing in Dynamics CRM Online

If you get a problem whereby newly created Office 365 users have not been synchronized to Dynamics CRM Online after you have assigned them a CRM Online licence then you should check the following.

In the Office 365 portal under the admin menu select the CRM option. 



From there select the "Edit Settings" for the CRM instance you are having problems with. Check that the "Instance Security Group" is not set otherwise only users in the assigned group will be allowed access to that CRM instance. If there is any other value like "<none>" you may need to clear and save settings it before users will appear in CRM Online


Thursday, July 21, 2016

Configure OAuth between Skype for Business Server and Exchange Online

This PowerShell script (Author: Aaron Marks) configures OAuth between Skype for Business Server and Exchange Online.

Requirements:
<#
    .SYNOPSIS
    Configure-OAuth_ExOn_SfB_Server
    
    Aaron Marks
    
    THIS CODE IS MADE AVAILABLE AS IS, WITHOUT WARRANTY OF ANY KIND. THE ENTIRE  
    RISK OF USE OR RESULTS FROM THE USE OF THIS CODE REMAINS WITH THE USER.
    
    Version 2.0, 5/26/2016
    
    .DESCRIPTION
    Configure Oauth between Exchange Online and Skype for Business Server.
    
    .LINK
    http://www.turnpointtech.com
    
    .NOTES
    
    Requirements:
        - Must be ran from Skype4B Server
        - Run from Elevated AAD PowerShell
        - MS Online Service Sign-in Assistant RTW:  
            http://go.microsoft.com/fwlink/?LinkID=286152  
        - AAD PowerShell:  
            http://go.microsoft.com/fwlink/p/?linkid=236297  
    
    Special thanks to Christian Burke for providing the  
    commands used to assemble this script: http://goo.gl/25ZZfK
    
    And, Thanks to @PatRichard for writing the part to export the OAuth certificate.
    Revision History
    --------------------------------------------------------------------------------
    1.0     Initial release
    2.0     Auto-export of OAuth Cert
    
    
    .PARAMETER WebExt
    Web External url from Skype for Business Front End Pool.
    
    .EXAMPLE
    .\Configure-OAuth_ExOn_SfB_Server.ps1 -WebExt "webext.contoso.com"  
    
#>
[CmdletBinding(DefaultParameterSetName="Default")]
Param(
    [Parameter(Mandatory=$True, ParameterSetName="Default")]
        [string]$WebExt
) #Param
Process {
    
    $CertPath = "C:\OAuth-SfB-EXO.cer"
    $Thumbprint = (Get-CsCertificate -Type OAuthTokenIssuer).Thumbprint
    $OAuthCert = Get-ChildItem -Path Cert:\LocalMachine\My\$Thumbprint
    Export-Certificate -Cert $OAuthCert -FilePath $CertPath -Type CERT
    
    # Script
    Import-Module LyncOnlineConnector
    # Logging into SfB Online
    Write-Output "Logging into SfB Online"
    $cred = Get-Credential
    $CSSession = New-CsOnlineSession -Credential $cred  
    Import-PSSession $CSSession -AllowClobber  
    # Clean up Old Entries if necessary
    Write-Output "Clean up Old Entries if necessary"
    If ( (Get-CsOauthServer).Identity -match "microsoft.sts") {
        Write-Output "Removing existing microsoft.sts OauthServer"
        Remove-CsOauthServer -Identity microsoft.sts
    }
    If ( (Get-CsPartnerApplication).Identity -match "microsoft.exchange") {
        Write-Output "Removing existing microsoft.exchange PartnerApplication"
        Remove-CsPartnerApplication -Identity microsoft.exchange
    }
    # Create New OAuth Server
    Write-Output "Create New OAuth Server"
    $TenantId = (Get-CsTenant).TenantId
    $metadataurl = "https://accounts.accesscontrol.windows.net/" `
    + "$TenantId" + "/metadata/json/1"
    New-CsOAuthServer -Identity microsoft.sts -metadataurl $metadataurl
    # Create New Partner Application
    Write-Output "Create New Partner Application"
    New-CsPartnerApplication -Identity microsoft.exchange `
    -ApplicationIdentifier 00000002-0000-0ff1-ce00-000000000000 `
    -ApplicationTrustLevel Full -UseOAuthServer
    #Set-CsOAuthConfiguration -ServiceName 00000004-0000-0ff1-ce00-000000000000
    # Elevate the SfB PowerShell  
    Write-Output "Elevate the SfB PowerShell"
    Import-Module MSOnlineExtended
    Connect-MsolService -Credential $cred
    Get-MsolServicePrincipal
    # Upload your OAuth Certificate
    Write-Output "Upload your OAuth Certificate"
    $certificate =  
    New-Object System.Security.Cryptography.X509Certificates.X509Certificate
    $certificate.Import("$CertPath")  
    $binaryValue = $certificate.GetRawCertData()  
    $credentialsValue = [System.Convert]::ToBase64String($binaryValue)  
    New-MsolServicePrincipalCredential `
    -AppPrincipalId 00000004-0000-0ff1-ce00-000000000000 `
    -Type Asymmetric -Usage Verify -Value $credentialsValue  
    Set-MSOLServicePrincipal -AppPrincipalID `
    00000002-0000-0ff1-ce00-000000000000 -AccountEnabled $true  
    # Add Your Lync External Web Services Name
    Write-Output "Add Your Lync External Web Services Name"
    $lyncSP = Get-MSOLServicePrincipal -AppPrincipalID `
    00000004-0000-0ff1-ce00-000000000000  
    $WebExtSpn = "00000004-0000-0ff1-ce00-000000000000/" + "$WebExt"
    $lyncSP.ServicePrincipalNames.Add("$WebExtSpn")  
    Set-MSOLServicePrincipal -AppPrincipalID `
    00000004-0000-0ff1-ce00-000000000000 `
    -ServicePrincipalNames $lyncSP.ServicePrincipalNames  
    
    Remove-PSSession $CSSession
    
} #Process

References:

Thursday, June 30, 2016

Juniper EX4550: Convert SCOM Network Device from GENERIC to CERTIFIED with Extended Monitoring Capability

Although my primary job focus is Microsoft Office 365 integrations and migrations right now, I must share my previous Microsoft System Center Operations Manager (SCOM) experience with you. 

In this article series I'll show you step-by-step how to get CERTIFIED status and extended monitoring capabilities in SCOM 2012+ for non-certified GENERIC network device Juniper EX4550 and Dell Force10 MXL 10/40GbE using just Notepad and no XML MP development effort. 

I'm sure following method will work for almost any other GENERIC network device that you might have. Just take an idea of my approach. 

Juniper EX4550 and Dell Force10 MXL 10/40GbE:
Note: Although MS published list for SCOM 2012 and SCOM 2012R2/2016 neither contains whole device list which SCOM will discover as "Certified" and with extended monitoring capabilities. Refer to my previous article if you want to get full list of "Certified" devices for your particular SCOM environment.
The idea is to find very similar vendor device which is already "Certified" and to use its configuration for SCOM generic network device.

Part I: Juniper EX4550-48T 
(System OID: .1.3.6.1.4.1.2636.1.1.1.2.92)

Step 1. After initial SCOM network discovery you'll have something similar to this picture:


SCOM:
  • cannot determine Model, Vendor;
  • has GENERIC Certification status for the device
  • there is no CPU/RAM/Network extended monitoring for the device
  • make a note it has System Object ID: .1.3.6.1.4.1.2636.1.1.1.2.92
Step 2. Juniper EX series contains of EX2200, EX3300, EX4200, EX4500 and EX4550 models. Each device has its unique system OID and characteristics. However those are managed by the same OS called JunOS and it makes me think they have similar SNMP MIBs (or maybe even the same) should be monitored by SCOM (or any SNMP monitoring software) in the same way using the same SNMP OID trees and counters.

Step 3There is folder "C:\Program Files\Microsoft System Center 2012 R2\Operations Manager\Server\NetworkMonitoring\conf\discovery" (for SCOM 2012R2) on SCOM Management servers which contains a lot of specific vendor files with prefix "oid2type" and file extension ".conf". Our scope of interest will be "oid2type_Juniper.conf" file.
Make a copy of this file for backup purposes.



Step 4. Open oid2type_Juniper.conf file with Notepad or with your favorite text editor (you should run Notepad as Administrator and navigate to folder path mentioned in Step 3) and search for string "EX4". You'll find the device Juniper EX4200 (we detect it's in the same device family in step 2) which is present in a list of the network devices supported by Operations Manager 2012R2 and 2016


Step 5. Copy the whole # Juniper EX4200 section and duplicate (paste) it under "}"


Step 6. Change configuration strings to device specific that you want to "certify".


In my case:
# Juniper EX4200 changed to # Juniper EX4550-48T (it's just a comment string, you can type anything you want there)
.1.3.6.1.4.1.2636.1.1.1.2.31 changed to .1.3.6.1.4.1.2636.1.1.1.2.92 (OID was taken from Step 1)
EX4200-48T changed to EX4550-48T (Model's DisplayName which will be shown in SCOM console)
Don't change "HEALTH = Juniper-EX4200" or anything else!

Changes summary in txt format:

# Juniper EX4550-48T
.1.3.6.1.4.1.2636.1.1.1.2.92 {
     TYPE = Switch
     VENDOR = Juniper
     MODEL  = EX4550-48T
     CERTIFICATION = CERTIFIED
     CONT = Juniper-EX-Series
     NEIGHBOR = LLDP-ATM-Peer
     HEALTH = Juniper-EX4200
     VLAN = Juniper-Vlan-Mib
     BRIDGE = Dot1q

INSTRUMENTATION:
     Environment                = JuniperEnvMon:DeviceID
     CPU/Memory                 = JuniperRouter:DeviceID
     Card-Fault                 = Juniper
     Interface-Fault            = MIB2
     Interface-Performance      = MIB2SNMP
     Port-Fault                 = MIB2
     Port-Performance           = MIB2
     Port-Ethernet-Performance  = dot3_Ethernet
}

Step 7. Save file changes in oid2type_Juniper.conf  
If you haven't run Notepad as Administrator in Step 4 you'll get "Access denied" error which doesn't allow you to save file.

Step 8. Repeat oid2type_Juniper.conf changes on each SCOM Management server which participates in Network Discovery Pool.

Step 9. Restart SCOM Management Server.

Step 10. Run "Rediscover Device" from SCOM console.


After some time Juniper EX4550 network device will be shown in SCOM as "Certified" and in few minutes you'll see all network, memory and CPU performance counters and their health.




In summary you have now:
  • "Certified" SCOM network device which was "Generic" previously
  • extended monitoring capabilities now such as: Processor, Memory and Network monitoring
  • no complex MP XML development effort has been implemented
Things to remember:
  • always make backup of *.conf file before changes
  • article is not an official guide
  • your customization maybe overwritten with SCOM update rollup or Service Pack (you may need to re-add txt sections again if it's happened)
References:

Wednesday, June 29, 2016

Winmail.dat attachment problem from Exchange Server or Exchange Online

Scenario:
By default, email messages that are sent from Exchange Online in Office 365 (same for Exchange Server) use the Transport Neutral Encapsulation Format (TNEF) format. Messaging systems that aren't based on Microsoft Exchange may be unable to interpret messages that use this rich text format (RTF). If the recipient’s messaging system can’t process this format, a file attachment that's called "Winmail.dat" is added to the message.

Solution:
Office 365 admins can use Windows PowerShell to change the message format to prevent the "Winmail.dat" attachment from being sent to external recipients. 
MS suggests you (kb2487954) to configure it per external contact or per external domain. However you may find this article useless if you'd like to not fix it again and again for every new detected domain or external contact. Proposed solution is to make global change for any external domain.

1. Connect to Exchange Online PowerShell or run Exchange Management Shell:

Monday, June 20, 2016

C2R error: "Is your internet connection working? Do you have enough free space on your main hard drive?"

Scenario:
You have configured Click-To-Run (C2R) Office 365 ProPlus installation package with Office Deployment Tool (ODT) and deployed Office 365 ProPlus or BP. Additionally you want to install C2R MS Visio or C2R MS Project downloaded from Office 365 portal via self-service user deployment. You get following error:

"Couldn't install
We're sorry, we had a problem installing your Office programs(s).
Is your internet connection working? Do you have enough free space on your main hard drive?
Please try installing again after you've checked above
Error Code: 30125-1011 (502)"



You definitely know that there is no issue with internet connectivity and you have enough free space on your main drive.

Solution:
Move your C2R installation executable to the same location where ODT has downloaded Office 365 ProPlus installation files. 

Run setup executable again.

Sunday, June 19, 2016

Cross-premises free/busy calendar sharing between Exchange on-premises and Exchange Online organizations

Scenario:
Federate Exchange Server on-premises and Exchange Online for calendar sharing. This specific use case is for two organizations to share Free/Busy calendar information between each other. The first organization has an Exchange Server 2010+ on premises environment. The second organization uses Office 365 with Exchange Online. Neither organization is configured for Hybrid.

Solution:
From Exchange Server 2010+ on premises EMS:

1. Create Federation Trust:

$ski = [System.Guid]::NewGuid().ToString("N")
New-ExchangeCertificate -FriendlyName "Exchange Federated Delegation" -DomainName $env:USERDNSDOMAIN -Services Federation -KeySize 2048 -PrivateKeyExportable $true -SubjectKeyIdentifier $ski
Get-ExchangeCertificate | ?{$_.friendlyname -eq "Exchange Federated Delegation"} | New-FederationTrust -Name "Microsoft Federation Gateway"

2. Create the federated domain proof encryption string for calendar sharing domain contoso.com:

Get-FederatedDomainProof -DomainName onpremisesdomain.com

3. Add domain proof as TXT record (generated in step 2) to onpremisesdomain.com public DNS domain and TXT record value is something like:

7Zyr2i/fE/M/T3AwCpitDbF30Fk/TdzXME6f7d1lDaKGthPdoS+UF94t43D2nU5hLNnIAP+5A3jJR2ik9HDPgg==

4. Once TXT record is added to public DNS then add a domain onpremisesdomain.com as a federated domain and enable federation for the Exchange organization:

Set-FederatedOrganizationIdentifier -DelegationFederationTrust "Microsoft Federation Gateway" -AccountNamespace "onpremisesdomain.com" -Enabled $true

5. Create an organization relationship with o365Domain.com Exchange Online domain:

Get-FederationInformation -DomainName "o365Domain.com" | New-OrganizationRelationship -Name "On-premises to Exchange Online" -DomainNames "o365Domain.com" -FreeBusyAccessEnabled $true -FreeBusyAccessLevel AvailabilityOnly

From Exchange Online

1. Connect to EXO in another PowerShell session or with "prefixed" session:

Import-PSSession (New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential (Get-Credential) -Authentication Basic -AllowRedirection)

2. Create a new organization relationship with Exchange Server on premises domain onpremisesdomain.com:

Get-FederationInformation -DomainName "onpremisesdomain.com" | New-OrganizationRelationship -Name "Exchange Online to on-premises" -DomainNames "onpremisesdomain.com" -FreeBusyAccessEnabled $true -FreeBusyAccessLevel AvailabilityOnly

Now it’s all done, it’s time for testing.
Some time you may notice the even after setup office 365 users may not be able to see the calendar free/busy info while it work from the other end. In this case you may need to restart IIS on on-premises exchange 2010+ CAS to get this working. Alternative path you may find under my article: Exchange Online users in Office 365 cannot see on-premises Exchange Server Free/Busy information.

References:

Friday, June 10, 2016

Office 365 CSP Tenants Subscription Usage summary using DAP access

Scenario:
You are Cloud Solution Provider (CSP) and have a mix of new CSP customers and invited from other Channels like Advisor, EA and etc. Following PowerShell scripts give you an idea what's going on in your CSP world of customer tenants and their subscriptions.

Prerequisites:
Microsoft Online Service Sign-in Assistant for IT Professionals RTW
You need to be connected with Office 365 "Connect-MsolService" cmdlet using Partner account that has delegated access permission (DAP) to Cloud Solution Provider (CSP) customer tenants prior to PowerShell script execution.

Included functions:

Get-MsolSubscriptionUsage
Get-MsolTenantMSSubscription
Get-MsolTenantNoActiveCSP
Get-MsolOffer

Get-MsolDomain -ErrorAction SilentlyContinue | out-null
if(!($?)) {Connect-MsolService}

<#
.Synopsis
   Following function will provide subscription usage summary info for tenant/s
.DESCRIPTION
   Following function  will search for the tenant/s by keyword and provide subscription usage summary for the tenant/s
   Keyword is a search string which is included into tenant displayname or "customer-inc.onmicrosoft.com" tenantname or primary domain name
   Ex. for "Rosemann Technology Inc." you can specify just "Rosemann" or "Rose" or "Rosemann.onmicrosoft.com"
.EXAMPLE
   Get-MsolSubscriptionUsage -Name Rose
   Will search for the subscriptions of the tenant or tenants which contains "Rose" string in their name
   ex. "Rose" matches "Rosemann Inc." or "Rosemann.onmicrosoft.com" or "Rose Inc.", etc.
.EXAMPLE
   Get-MsolSubscriptionUsage -Name Rosemann.onmicrosoft.com
   Will search for the subscriptions of the single customer with "Rosemann.onmicrosoft.com" tenant name
.EXAMPLE
   Get-MsolSubscriptionUsage -Name sill.com
   Will search for the subscriptions of the single customer with "sill.com" primary domain name
.EXAMPLE
   Get-MsolSubscriptionUsage
   Will search for all available tenants
.EXAMPLE
   Get-MsolSubscriptionUsage > Report.txt
   Will search for all available tenants and save results into Report.txt
#>
function Get-MsolSubscriptionUsage
{
    [CmdletBinding()]
    Param
    (
        [Parameter()]
        [string]$Name="*"
    )

Write-Verbose "Searching for the tenant/s that contains string $Name"

$Customer = Get-MsolCustomer -Name $Name

Write-Verbose "Found company: $($Customer.Name) - $($Customer.DefaultDomainName)"

if ($Customer) { $Customer | ForEach-Object {
    [System.Guid]$TenantID = $_.TenantId
    
    $Subscription = Get-MsolSubscription -TenantId $TenantID  -ErrorAction SilentlyContinue

    Show-MsolSubscription -Subscription $Subscription -TenantID $TenantID -Customer $_
    }} else {Write-Warning "Customer not found!"}
}

<#
.Synopsis
   This function will search for customers by primary domain name or by "onmicrosoft.com" name or by DisplayName
.DESCRIPTION
   This function will search for customers by primary domain name or by "onmicrosoft.com" name or by DisplayName
.EXAMPLE
   Get-MsolCustomer -Name domain.net
.EXAMPLE
   Get-MsolCustomer -Name tenantname.onmicrosoft.com
.EXAMPLE
   Get-MsolCustomer -Name CustomerName
#>
function Get-MsolCustomer
{
    [CmdletBinding()]
    Param
    (
        [Parameter(Mandatory=$true,
                   ValueFromPipelineByPropertyName=$true)]
        [string]$Name
    )
if ($Name -match ".*[.].*") {Get-MsolPartnerContract -SearchKey DefaultDomainName -DomainName $Name}
else {Get-MsolPartnerContract -All | ? {$_.Name -like "*$Name*"}}

}

<#
.Synopsis
   This function will search for MS Subscriptions
.DESCRIPTION
   This function will search for all tenants which contain at least one MS subscription (deployment opportunity of moving to CSP subscription)
.EXAMPLE
   Get-MsolTenantMSSubscription
#>
function Get-MsolTenantMSSubscription
{
    [CmdletBinding()]
    Param()

    $CustomerList=@()

    $Customer = Get-MsolPartnerContract -All

    $Customer | foreach {
    Write-Verbose "Looking into tenant $($_.DefaultDomainName)"

    $Subscription = Get-MsolSubscription -TenantId $_.TenantID  -ErrorAction SilentlyContinue | `
    ? {!($_.OwnerObjectId) -and ($_.Status -eq "Enabled" -or $_.Status -eq "Warning") -and $_.NextLifecycleDate}

    if ($Subscription) {
            Show-MsolSubscription -Subscription $Subscription -TenantID $_.TenantID -Customer $_
            $CustomerList+=$_.Name
            }
        }

    Write-Warning "Subscriptions provisioned by MS are detected in $($CustomerList.Count) customer tenants"
    $CustomerList
}

<#
.Synopsis
   This internal function will print subscription summary information for the particular tenant on screen
#>
function Show-MsolSubscription
{
    [CmdletBinding()]
    Param
    (
        [Parameter()]
        $Subscription,
        [Parameter(Mandatory=$true)]
        $TenantID,
        [Parameter(Mandatory=$true)]
        $Customer
    )
    
    $Customer | ft Name,TenantId,DefaultDomainName

    $Subscription | select `
    @{n="Created";e={$_.Datecreated.ToShortDateString()}}, `
    @{n="Expires";e={$_.NextLifecycleDate.ToShortDateString()}}, `
    @{n="SubscriptionId";e={$_.ObjectId}}, `
    @{n="ProvisionedBy";e={if (!$_.OwnerObjectId) {"Microsoft"} elseif `
    ($_.OwnerObjectId -eq "e63464b7-2b94-4841-8033-5b7f66d196d7") {"CSP"} `
    else {$_.OwnerObjectId}}}, `
    @{n="SKU";e={Get-MsolOffer -SkuPartNumber $_.SkuPartNumber}},TotalLicenses,Status | ft -AutoSize

    Write-Verbose "Resolving $($_.SkuPartNumber)"

    Get-MsolAccountSku -TenantId $TenantID -ErrorAction SilentlyContinue | select `
    @{n="SKU";e={Get-MsolOffer -SkuPartNumber $_.SkuPartNumber}}, `
    ActiveUnits,ConsumedUnits,SubscriptionIds | ft -AutoSize

    Write-Output "============================================================================================================"
}

<#
.Synopsis
   This function will show tenants with no active CSP subscriptions (no CSP benefit usage at all or just invited customers)
.EXAMPLE
   Get-MsolTenantNoActiveCSP
#>
function Get-MsolTenantNoActiveCSP
{
    [CmdletBinding()]
    Param()

    $CustomerList=@()

    $Customer = Get-MsolPartnerContract -All

    $Customer | foreach {

    Write-Verbose "Looking into tenant $($_.DefaultDomainName)"

    $Subscription = Get-MsolSubscription -TenantId $_.TenantID  -ErrorAction SilentlyContinue | `
    ? {$_.OwnerObjectId -and ($_.Status -eq "Enabled" -or $_.Status -eq "Warning")}
    if (!$Subscription) {
            Get-MsolSubscriptionUsage -Name $_.Name
            $CustomerList+=$_.Name
            }
        }

    Write-Warning "$($CustomerList.Count) CSP tenants have no active CSP subscriptions"

    $CustomerList
}

<#
.Synopsis
   This function will convert original Office SKU PartNumber name into friendly name
.EXAMPLE
   Get-MsolOffer -SkuPartNumber MCOIMP
  
   Gives you "SfB Online (Plan 1)"
#>
function Get-MsolOffer
{
    [CmdletBinding()]
    [Alias()]
    Param
    (
        # Param1 help description
        [Parameter(Mandatory=$true,
                   ValueFromPipelineByPropertyName=$true,
                   Position=0)]
        $SkuPartNumber
    )
    switch ($SkuPartNumber) {

    "AAD_BASIC" {"Azure Active Directory Basic"}
    "AAD_PREMIUM" {"Azure Active Directory Premium"}
    "RIGHTSMANAGEMENT" {"Azure Rights Management Premium"}
    "LOCKBOX" {"Customer Lockbox"}
    "EXCHANGE_ANALYTICS" {"Delve Analytics"}
    "EMS" {"Enterprise Mobility Suite"}
    "EXCHANGESTANDARD" {"Exchange Online (Plan 1)"}
    "EXCHANGEENTERPRISE" {"Exchange Online (Plan 2)"}
    "ATP_ENTERPRISE" {"Exchange Online ATP"}
    "EXCHANGEARCHIVE_ADDON" {"EOA for Exchange Online"}
    "EXCHANGEARCHIVE" {"EOA for Exchange Server"}
    "EXCHANGEDESKLESS" {"Exchange Online Kiosk"}
    "EOP_ENTERPRISE" {"Exchange Online Protection"}
    "INTUNE_A" {"Intune"}
    "INTUNE_STORAGE" {"Intune Extra Storage"}
    "ADALLOM_STANDALONE" {"Cloud App Security"}
    "EQUIVIO_ANALYTICS" {"O365 Advanced eDiscovery"}
    "O365_BUSINESS" {"O365 Business"}
    "O365_BUSINESS_ESSENTIALS" {"O365 Business Essentials"}
    "O365_BUSINESS_PREMIUM" {"O365 Business Premium"}
    "STANDARDWOFFPACK" {"O365 Enterprise E2 (Nonprofit E1)"}
    "STANDARDPACK" {"O365 Enterprise E1"}
    "ENTERPRISEPACK" {"O365 Enterprise E3"}
    "ENTERPRISEWITHSCAL" {"O365 Enterprise E4"}
    "ENTERPRISEPREMIUM" {"O365 Enterprise E5"}
    "ENTERPRISEPREMIUM_NOPSTNCONF" {"O365 Enterprise E5 w/o PSTN Conf"}
    "DESKLESSPACK" {"O365 Enterprise K1"}
    "SHAREPOINTSTORAGE" {"O365 Extra File Storage"}
    "WACONEDRIVESTANDARD" {"OneDrive for Business (Plan 1)"}
    "WACONEDRIVEENTERPRISE" {"OneDrive for Business (Plan 2)"}
    "POWER_BI_STANDARD" {"Power BI (free)"}
    "POWER_BI_PRO" {"Power BI (Pro)"}
    "OFFICESUBSCRIPTION" {"O365 ProPlus"}
    "PROJECTESSENTIALS" {"Project Lite"}
    "PROJECTONLINE_PLAN_1" {"Project Online"}
    "PROJECTCLIENT" {"Project Pro for O365"}
    "SHAREPOINTSTANDARD" {"SharePoint Online (Plan 1)"}
    "SHAREPOINTENTERPRISE" {"SharePoint Online (Plan 2)"}
    "MCOEV" {"SfB Cloud PBX"}
    "MCOIMP" {"SfB Online (Plan 1)"}
    "MCOSTANDARD" {"SfB Online (Plan 2)"}
    "MCOMEETADV" {"SfB PSTN Conferencing"}
    "MCOPLUSCAL" {"SfB Plus CAL"}
    "MCOPSTN1" {"SfB PSTN Dom. Calling"}
    "MCOPSTN2" {"SfB PSTN Dom. and Int. Calling"}
    "VISIOCLIENT" {"Visio Pro for O365"}
    "CRMIUR" {"Dynamics CRM Online Pro IUR"}
    "YAMMER_ENTERPRISE_STANDALONE" {"Yammer Enterprise"}
    "LITEPACK" {"O365 Small Business"}
    "LITEPACK_P2" {"O365 Small Business Premium"}
    "CRMPLAN1" {"Dynamics CRM Online Essential"}
    "CRMPLAN2" {"Dynamics CRM Online Basic"}
    "CRMSTANDARD" {"Dynamics CRM Online Pro"}
    }
}

Reference:
Manage Office 365 tenants with Windows PowerShell for Delegated Access Permissions (DAP) partners