Atribuir licenças com o Windows PowerShell

Faça as etapas a seguir para atribuir licenças com o PowerShell no Azure Active Directory (AD) para usuários do Insights do Microsoft Viva (anteriormente Workplace Analytics).

Pré-requisitos de instalação

  1. Instale o módulo do PowerShell do Azure AD seguindo estas etapas:

    1. Abra um prompt de Windows PowerShell de comando elevado.

    2. Insira o seguinte comando:

      Install-Module *AzureAD*
      
  2. Execute o módulo do PowerShell do Azure AD:

    1. Inicie o PowerShell.

    2. Insira o seguinte comando:

      Import-Module *AzureAD*
      

Atribuindo licenças

O Viva Insights só pode extrair dados das contas de usuários que têm licenças válidas Insights Viva.

  1. Para atribuir uma licença Insights Viva a um usuário:

    Com o PowerShell aberto, inicie o Módulo de Importação e entre no Azure AD executando os seguintes comandos:

    Import-Module *AzureAD*
    
    Connect-AzureAD
    

    Para entrar, você precisa de credenciais com privilégios de administrador.

    Azure Active Directory logon.

  2. Copie e colar os seguintes dados de variável na linha de comando do PowerShell e execute-os:

     $UserToLicense = Get-AzureADUser -SearchString '<usertolicense@domain.com>'
     $LicenseSku = Get-AzureADSubscribedSku | Where {$_.SkuPartNumber -eq 'WorkPlace_Analytics'}
     $License = New-Object -TypeName Microsoft.Open.AzureAD.Model.AssignedLicense
     $License.SkuId = $LicenseSku.SkuId
     $AssignedLicenses = New-Object -TypeName Microsoft.Open.AzureAD.Model.AssignedLicenses
    
  3. Para atribuir uma licença, copie e colar o seguinte código na linha de comando do PowerShell e execute-o:

     $AssignedLicenses.AddLicenses = $License
     Set-AzureADUserLicense -ObjectId $UserToLicense.ObjectId -AssignedLicenses $AssignedLicenses
    
  4. Para verificar se a licença foi atribuída, copie e colar o seguinte código na linha de comando do PowerShell e execute-a:

     Get-AzureADUserLicenseDetail -ObjectId $UserToLicense.ObjectId | Select -Expand ServicePlans | Where {$_.ServicePlanName -eq "Workplace_Analytics"}
    

    Depois que este último comando for executado, você verá uma entrada na linha de comando. Se não for, ou se uma mensagem de erro mostrar, a licença não foi atribuída com êxito.

Exibir licenças disponíveis em seu locatário

Para exibir licenças disponíveis para seu locatário e o uso atual, execute o seguinte no PowerShell:

Connect-MsolService

Agora que você está conectado ao locatário Microsoft 365, execute o seguinte seguinte:

Get-MsolAccountSku

Adicionar licenças em massa

Se você precisar atribuir licenças do Viva Insights a um grande número de usuários, poderá usar o script de licença em massa para o Microsoft 365 PowerShell fornecido nesta seção.

Requisitos de software

O script Insights licença em massa do Viva usa o módulo Azure Active Directory PowerShell para fazer as alterações de licenciamento necessárias em suas identidades de locatário. Para garantir que o módulo Azure Active Directory PowerShell seja instalado:

  1. Abra Windows PowerShell como administrador e execute o seguinte comando:

    Set-ExecutionPolicy RemoteSigned
    
  2. Quando uma mensagem de confirmação é exibida, aceite a alteração para permitir que scripts locais do PowerShell seja executado.

  3. Depois que a política de execução for definida corretamente no computador, execute o seguinte cmdlet:

     Install-Module -Name MSOnline -Repository PSGallery
    

Observação

Se o cmdlet não for executado, você poderá executar uma versão mais antiga do Windows Management Framework (WMF). Nesse caso, baixe e instale o assistente de login necessário e o módulo Azure Active Directory PowerShell por meio do MSI. Para obter instruções para instalar esses pacotes necessários, consulte Conexão para Microsoft 365 PowerShell.

Requisitos de entrada

O script Insights licença em massa do Viva usa um .csv de referência como entrada. O script faz referência a cada endereço listado no arquivo .csv e tenta atribuir a licença do Viva Insights a todos os usuários.

Cada usuário que já recebe uma licença mantém todo o licenciamento atual. Novos usuários receberão uma licença Insights Viva. A .csv entrada deve ter uma única coluna com o header "Email" que contém todos os endereços de email.

Para obter mais detalhes sobre como formatar o arquivo de .csv de entrada, consulte o exemplo .csv arquivo de exportação.

Descrição do script

O Add-WpALicense.ps1 script foi projetado para atribuir licenças do Viva Insights a identidades Microsoft 365 com base .csv entrada de endereço de email. A entrada de endereço de email é usada para identificar a identidade Microsoft 365 correta com base nos atributos UserPrincipalName e ProxyAddresses do objeto MSOL (Microsoft Online) e tenta atribuir uma licença à identidade Microsoft 365.

Executar o script

  1. Crie uma pasta C:\Scripts se ela ainda não existir.

  2. Copie o script a seguir e o colar em um editor de texto e salve o script como C:\Scripts\Add-WpALicense.ps1.

    <#
    .NOTES
     Title:    Add-WpALicense.ps1
     Date:     February 25th, 2020
     Version:  1.0.4
    .SYNOPSIS
     This script is designed to add Workplace Analytics licenses to a .csv list of email addresses that correlate to Microsoft 365 identities.
    .DESCRIPTION
     Add-WpALicense is designed to assign Workplace Analytics licenses to Microsoft 365 identities based on .csv e-mail address input. The e-mail address input will be used to identify the correct Office365 identity based on the UserPrincipalName and ProxyAddresses attributes of the MSOL object and try to assign a license to the identity.
    .PARAMETER CSV
     The .csv input file contains all of the email addresses that are given a license. Use Email as the header and when save the file with the UTF-8 encoded format.
    .PARAMETER LicenseSKU
     The WORKPLACE_ANALYTICS LicenseSKU will be applied to a user that's found. The script tries to automatically apply a license SKU. If a license SKU is provided, the script tries to match it with the domain. An example SKU is CONTOSO:WORKPLACE_ANALYTICS.
     .EXAMPLE
     .\Add-WpALicense.ps1 -CSV c:\users\user123\desktop\inputCSV -LicenseSku CONTOSO:WORKPLACE_ANALYTICS
    
     The script would ingest the .csv file from the specified location in this example and try to apply the MSOL license SKU of CONTOSO:WORKPLACE_ANALYTICS to all users that are found in the MSOL structure of the tenant.
        #>
        param
        (
        [parameter(Mandatory=$true,Position=0,HelpMessage="Please provide a CSV file that has the Email column header.")]
        [ValidateNotNullorEmpty()]
        [string]$CSV,
        [parameter(Mandatory=$true,Position=1,HelpMessage="Please provide the exact name of the Workplace Analytics MSOL Account SKU license for the applicable tenant.")]
        [ValidateNotNullorEmpty()]
        [string]$LicenseSKU
        )
        #Simple function to connect to Microsoft 365 MSOL PowerShell.
        Function Connect-O365PowerShell {
            try {
                Import-Module MSOnline -ErrorAction Stop
                Write-Output "Successfully imported the Azure Active Directory PowerShell module, proceeding..."
            }
            catch {
                Write-Error -Message "Windows Azure Active Directory PowerShell module could not be found, please install the module and run this script again!"
                break
            }
            if(Get-Module -Name MSOnline) {
                try {
                    Connect-MsolService -ErrorAction Stop
                    Write-Output "Successfully connected to Microsoft 365 MSOL, proceeding..."
                }
                catch {
                    Write-Error "Could not connect to Microsoft 365 MSOL due to the following exception.`r`n$($_.Exception.Message)"
                    break
                }
            }
        }
        #Simple function to get to MSOL SKU information.
        Function Get-WorkplaceAnalyticsSku {
            param ($searchString)
            $O365MsolSKUs = Get-MsolAccountSku
            try {
                $wpaSku = $O365MsolSKUs | Where-Object { $_.AccountSkuId -like $searchString }
                if ($wpaSku) {
                    Write-Host "Office365 tenant possesses the correct WorkplaceAnalytics license, proceeding..."
                    [int]$availableLicenses = $wpaSku.ActiveUnits - $wpaSku.ConsumedUnits
                    Write-Host "Using Sku: $($wpaSku.AccountSkuId), Total Licenses: $($wpaSku.ActiveUnits), Used Licenses: $($wpaSku.ConsumedUnits), Available Licenses: $($availableLicenses)"
                    return $wpaSku
                }
                else {
                    Write-Error "Script could not find matching WorkplaceAnalytics license using $searchString on Office365 tenant. Here are the available SKU's for this tenant:"
                    Write-warning ($O365MsolSKUs | out-string)
                    write-warning "Please Rerun script and specify a SKU above with parameter -LicenseSKU {sku} including the appropriate WORKPLACE_ANALYTICS SKU"  
                    exit 1
                }
            }
            catch {
                 Write-Error "Failed to determine the Office365 tenant licenses, script cannot proceed!`n$_."
                 exit 1
            }
        }
        #Start-Transcript to keep a simple log of all stream output of the successes and failures of the execution and to set StrictMode.
        Start-Transcript
        Set-StrictMode -version 2
        #Simple if block to test the CSV parameter input and confirm the path is valid and contains a file.
        if (!(Test-Path $CSV)) {
          Write-Error "CSV file could not be found, please ensure that the location is correct and you have the proper permissions to read the file then try again.`r`n$($_.Exception.Message)"
        break
        }
        Write-Output "CSV file was found, proceeding..."
        try {
           #If the CSV is valid, this tries to import the contents into a user's CSV array that's used for processing.
           [array]$users = @(Import-Csv $CSV -ErrorAction Stop)
            Write-Output "CSV file was imported to process successfully, proceeding..."
         }
         catch {
            Write-Error "Failed to import CSV for processing due to the following exception.`r`n$($_.Exception.Message)"
            break
         }
        #After CSV formatting is verified, check for Email values in the file.
        if(($users.count) -le 0) {
           Write-Error "The CSV provided did not contain any valid SMTP data. Please check the CSV file and try again."
           break
        }
        Write-Host "Found $($users.count) items in the CSV to process"
        #Check the CSV contains the proper Email header.
        if ($users | Get-Member Email) {
           Write-Host "CSV file is valid, proceeding..."
        }
        else {
           Write-Warning "CSV is missing Email header. Please check the CSV file specified and update the CSV to include the header: Email"
           break
         }
         #Calling Connect-O365PowerShell function to establish connection.
         try {
             Connect-O365PowerShell -ErrorAction Stop
         }
         catch {
            Write-Error "Failed to successfully connect to Azure Active Directory PowerShell due to the following exception.`r`n$($_.Exception.Message)"
            break
         }
         #Try to pull MSOL SKUs.
         if ([string]::isnullorempty($LicenseSku)) {
            $wpaSearch = "*:WORKPLACE_ANALYTICS"
         }
         else {
            $wpaSearch = "*$LicenseSku*"
         }
         $WpaLicenseSku = Get-WorkplaceAnalyticsSku -searchString $wpaSearch
         $NumofSuccessfullyLicensed = 0
         $NumofErrorLicensed = 0
         $NumOfAlreadyLicensed = 0
         $NumOfUsersNotFound = 0
         [System.Collections.ArrayList]$UsersNotFound =@()
         [System.Collections.ArrayList]$UsersFailedtoLicense =@()
         #If the user's array contains the Email member who is created by importing a CSV and the object count of the user's array is greater than zero (0), the processing block is entered and a foreach loop is used to process the array contents.
         Foreach($user in $users) {
            #An attempt is made to find the user through the UserPrincipalName parameter. If an error occurs, the catch block will try to find the user through a ProxyAddresses attribute regex comparison. An absolute match after the colon of the address in the array is required to increase the accuracy of the find.
            $userIndex = $users.Indexof($user)
            Write-Progress -Activity "Assigning Workplace Analytics Licenses, currently on $($userIndex + 1) of $($users.Count) Currently searching for user $($user.Email)" -PercentComplete ($userIndex / $users.Count * 100) -Id 1
            try {
                $msolUser = Get-MsolUser -UserPrincipalName $user.Email -ErrorAction Stop
             }
             catch {
                Write-Warning "Failed to find user $($user.Email) through UPN lookup, attempting ProxyAddress attribute...`n$_"
                $msolUser = Get-MsolUser -All | Where-Object {$_.ProxyAddresses -match "\:$($user.Email)"}
             }
             if($msolUser) {
                 #If the msolUser variable is not null, the following block will be entered where an attempt is made to add the LicenseSKU parameter to the MSOL user.
                 if ($msolUser.Licenses.AccountSkuId -contains $WpaLicenseSKU.AccountSkuId) {
                    Write-Warning "User $($msolUser.UserPrincipalName) was found but is already licensed for WorkplaceAnalytics, skipping licensing."
                    $NumOfAlreadyLicensed++
                 }
                 else {
                    Write-Output "User $($user.Email) found, attempting to license..."
                    try {
                       Set-MsolUserLicense -UserPrincipalName $msolUser.UserPrincipalName -AddLicenses $WpaLicenseSKU.AccountSkuId -ErrorAction Stop | Out-Null
                       Write-Output "Successfully licensed user $($msolUser.UserPrincipalName) with $($WpaLicenseSKU.AccountSkuId) license."
                       $NumofSuccessfullyLicensed++
                     }
                     catch {
                        Write-Error "Failed to license user $($msolUser.UserPrincipalName) due to the following exception.`r`n$($_.Exception.Message)"
                        $NumofErrorLicensed++
                        $UsersFailedtoLicense.Add($user.Email) | Out-Null
                     }
                 }
             }
             else {
                $NumOfUsersNotFound++
                $NumofErrorLicensed++
                $UsersNotFound.Add($user.Email) | Out-Null
                Write-Error "Could not find user $($user.Email), skipping!"
                continue
             }
         }
         if ($UsersFailedtoLicense.count -ne 0) {
             Write-Output "`nThe following $($UsersFailedtoLicense.count) failed to License:`n"
             Write-Output $UsersFailedtoLicense
         }
         if ($UsersNotFound.Count -ne 0) {
             Write-Output "`nThe following $($UsersNotFound.count) users were not found:`n"
             Write-Output $UsersNotFound
         }
         $finaloutput = "`nScript completed, Total number of users licensed:$NumofSuccessfullyLicensed"
         $finaloutput += "`nTotal number of users that were already licensed:$NumOfAlreadyLicensed"
         $finaloutput += "`nErrors encountered:$NumofErrorLicensed"
         $finaloutput += "`nTotal users not found:$NumOfUsersNotFound"
    
         Write-Output $finaloutput
       Stop-Transcript
    

    Depois que o ambiente do PowerShell for preparado e o arquivo de entrada for construído, confirme se o arquivo de usuário CSV está no mesmo diretório que o script e, em seguida, você pode executar o script.

  3. Inicie Windows PowerShell e execute o seguinte comando:

     C:\Scripts\Add-WpALicense.ps1 -CSV <CSVLocation> -LicenseSku <WpALicenseSKU>    
    

    Observação

    O deve conter o caminho completo para o arquivo de entrada <CSVLocation> CSV, como C:\Scripts\InputFile.csv. E <WpALicenseSKU> deve conter a SKU de Licença MSOL, por exemplo: CONTOSO:WORKPLACE_ANALYTICS.

  4. Quando solicitado, insira as Microsoft 365 de administrador global para o locatário onde as licenças devem ser adicionadas.

    Se todas as entradas necessárias são atendidas, o script é executado agora na lista CSV e, em seguida, as licenças são atribuídas aos usuários. Durante a execução do script, todos os sucessos e falhas são mostrados na linha de comando e uma transcrição é salva na pasta Documentos.

Perguntas frequentes

Algo deu errado durante a execução do script. Há um log das ações de script?

Sim, você pode encontrar uma transcrição de script para cada execução na pasta Documentos para a pessoa que executou o script.

Uma entrada de endereço de email funcionará se não for UserPrincipalName de qualquer identidade MSOL?

A lógica de script tenta primeiro encontrar a identidade MSOL por meio do UserPrincipalName usando o endereço de email do arquivo CSV. Se essa tentativa falhar, o script tentará encontrar qualquer objeto MSOL que contenha o endereço de email do arquivo CSV dentro da propriedade ProxyAddresses. Se um usuário ainda não puder ser encontrado, o email será considerado não existir e será ignorado.

Isso funciona com a Autenticação Multifa factor (MFA)?

Esse script funciona com Autenticação Multifato porque o cmdlet Connect-MsolService suporta Azure Active Directory Autenticação (ADAL).

Solução de problemas

Erro: o CSV fornecido não continha dados SMTP válidos. Verifique o arquivo CSV e tente novamente.

Verifique se o arquivo CSV contém o header apropriado e endereços de email válidos para análise.

Erro: não foi possível encontrar o usuário user1@contoso.com, ignorando!

Verifique se o email é resolvido corretamente.

Erro: a propriedade 'AccountSkuId' não pode ser encontrada neste objeto. Verifique se a propriedade existe.

Verifique se o usuário tem a licença EXO adequada.

Erro: o arquivo CSV não pôde ser encontrado...

Confirme se o arquivo correto é especificado ao definir e se o usuário que está executando o script tem permissões -CSV para ler o arquivo.

Se o script for bem-sucedido, mas os relatórios de saída: Script concluído, mas o número total de usuários licenciados é zero (0).

  1. Confirme se o usuário ainda não está licenciado.
  2. Confirme se o usuário está usando o plano Exchange Online correto.
  3. Confirme se o UPN ou o endereço de email proxy dos usuários são resolvidos no ambiente.