> For the complete documentation index, see [llms.txt](https://docs.openiam.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.openiam.com/connector-configuration/microsoft/16-teams.md).

# Microsoft Teams connector

This page describes how to install and configure the Microsoft Teams connector in OpenIAM.

The Teams connector lets OpenIAM keep Microsoft Teams settings in step with the identities it already manages. Its working surface is narrow and worth stating plainly: it **updates objects that already exist in Teams** — users and application instances — and it **assigns, changes and removes phone numbers**. It does not create Teams objects, and it does not manage teams, channels or memberships.

The connector is a .NET/PowerShell connector: it runs as a Windows service on a host that can reach the Microsoft 365 tenant, drives the **MicrosoftTeams PowerShell module**, and exchanges requests with OpenIAM over RabbitMQ.

| Operation                                              | Supported                                            |
| ------------------------------------------------------ | ---------------------------------------------------- |
| Update an existing user or application instance (Save) | ✅                                                    |
| Assign, change or remove a phone number                | ✅ — part of save                                     |
| Search                                                 | ✅                                                    |
| Test connection                                        | ✅                                                    |
| Create                                                 | ❌ — save fails if the object is not already in Teams |
| Delete                                                 | ❌ — refused, unless you supply a custom handler      |
| Suspend / resume                                       | ❌ — refused, unless you supply a custom handler      |
| Reset password                                         | ❌ — refused, unless you supply a custom handler      |
| Check a password (Login)                               | ❌ — refused, unless you supply a custom handler      |

The five refused operations are not silent failures: the connector returns *"\<operation> is not supported"* and the request fails. Accounts, passwords and account state belong to the connector that owns the underlying identity — Active Directory or Entra ID — and Teams inherits them from there. See [Custom handlers](#custom-handlers) if you need one of them anyway.

## Use cases

* **Giving a joiner their phone number** as part of provisioning, and taking it back when they leave, so a number is never left assigned to someone who has gone.
* **Keeping Teams voice settings in step with HR data** — enterprise voice, phone number type and assignment category following a move between departments or sites.
* **Managing resource accounts** — the application instances Teams uses for services rather than people — with the same phone-number handling as users.
* **Reading Teams data back into OpenIAM** for reconciliation, so the phone numbers and voice settings recorded in OpenIAM match what Teams actually holds.

## Versions and compatibility

The connector drives the **MicrosoftTeams PowerShell module**, so what it supports is what that module supports rather than a version range of its own. Microsoft's own [Application-based authentication in Teams PowerShell Module](https://learn.microsoft.com/en-us/microsoftteams/teams-powershell-application-authentication) states which module versions support certificate authentication, and lists the cmdlets that application authentication does **not** cover — worth reading before relying on a particular operation.

## Prerequisites

The operating system, `.NET Framework` and PowerShell requirements are the same for every .NET/PowerShell connector and are listed once in [Installing PowerShell connectors](/connector-configuration/microsoft/1-powershellconnectorinstallation.md#basic-requirements). Beyond those, the Teams connector needs:

* The **MicrosoftTeams PowerShell module** on the connector host.
* An **internet connection** from the connector host to the Microsoft 365 tenant.
* An **Entra ID application** with a certificate, the two Graph permissions and the Teams Administrator role — see [Application authentication](#application-authentication-entra-id).

### Installing the MicrosoftTeams PowerShell module

Check whether the module is already present:

```powershell
Get-Module MicrosoftTeams -ListAvailable
```

An empty result means it is not installed. Install it for all users, because the connector runs as a service account rather than as you:

```powershell
Install-Module -Name MicrosoftTeams -Scope AllUsers
```

Run the first command again to confirm — it should now report the module, its version and its exported commands. Microsoft's [Install Microsoft Teams PowerShell](https://learn.microsoft.com/en-us/microsoftteams/teams-powershell-install) covers the module in full.

## Installing the connector

Every .NET/PowerShell connector installs the same way. See [Installing PowerShell connectors](/connector-configuration/microsoft/1-powershellconnectorinstallation.md) for the installer, running several connectors on one host, and removing or updating an installation.

## Starting, stopping, and restarting

The installer registers a pair of Windows services named after the connector name you supply. See [Installing PowerShell connectors](/connector-configuration/microsoft/1-powershellconnectorinstallation.md#starting-stopping-and-restarting).

## Command-line parameters and properties

The connector takes no command-line parameters. Queue names, concurrency, logging, simulation mode and the RabbitMQ settings live in `Connector.config`, documented for the whole family in [Using PowerShell connectors](/connector-configuration/microsoft/2-powershellconnectorsusage.md#working-with-the-connector-configuration).

## Verifying the connector is running

{% stepper %}
{% step %}
Confirm the connector's Windows services are running on the host.
{% endstep %}

{% step %}
Check that the connector's request queue in RabbitMQ has a consumer.
{% endstep %}

{% step %}
Run **Test Connection** on the managed system in the Webconsole.
{% endstep %}

{% step %}
Run one real operation — a search — to prove the path end to end.
{% endstep %}
{% endstepper %}

Test Connection is a genuine check rather than a ping. The connector reads the tenant ID, application ID and certificate thumbprint from the managed system, refuses the test if any of the three is empty, and then opens a real `Connect-MicrosoftTeams` session with them. A passing test therefore means the application registration, the certificate and the tenant all line up.

## Troubleshooting

Connector troubleshooting is covered for the whole family in [Using PowerShell connectors](/connector-configuration/microsoft/2-powershellconnectorsusage.md), including where the logs are and how to replay a request. The table below covers what is specific to Teams.

| Symptom                                                  | Likely cause                                                                           | Resolution                                                                    |
| -------------------------------------------------------- | -------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
| `Could not find object: <identity>`                      | Save was sent for an identity that does not exist in Teams. The connector updates only | Create the object in Teams, or in the connector that owns it, first           |
| `<operation> is not supported`                           | Delete, suspend, resume, reset password and login are refused by design                | Route the operation to a [custom handler](#custom-handlers) if you need it    |
| `Test connection - hostUrl should be set to a TenantID`  | The managed system's **URL** is empty                                                  | Set it to the tenant ID, not a hostname                                       |
| `Test connection - userId should be set to the ClientID` | The managed system's **Login** is empty                                                | Set it to the application (client) ID                                         |
| `Test connection - pswd is supposed to be a thumbprint`  | The managed system's **Password** is empty                                             | Set it to the certificate thumbprint                                          |
| A search is refused before it runs                       | The query failed the read-only check                                                   | See [Reconciliation and synchronization](#reconciliation-and-synchronization) |

## Registering the connector in OpenIAM

The connector's request queue name in OpenIAM has to match the queue in the connector's own `Connector.config` exactly. Getting the connection parameters out of OpenIAM and into the installer is covered in [Installing PowerShell connectors](/connector-configuration/microsoft/1-powershellconnectorinstallation.md#getting-connection-parameters-with-openiam).

## Configuring the managed system

Follow the standard steps in [Configure a managed system](/administration-guide/lifecycle/configure-managed-system.md). Three fields carry Teams-specific values:

| Field        | Value                                                            |
| ------------ | ---------------------------------------------------------------- |
| **URL**      | The **Directory (tenant) ID**                                    |
| **Login**    | The application's **Application (client) ID**                    |
| **Password** | The **thumbprint** of the certificate you generated and uploaded |

Both IDs are on the application's **Overview** page in Entra ID:

<figure><img src="https://2965242200-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F0uHWHRgcad6P03ehqgmX%2Fuploads%2Fgit-blob-6e720897f693f19aeb2cede4675140cd5ffba204%2F16-teams-18-Managed-system.png?alt=media" alt="The Overview page of the application registration, with the Application client ID and the Directory tenant ID shown among the essentials"><figcaption></figcaption></figure>

### Connector scope

One managed system drives one kind of object. The **`ConnectorScopes`** attribute on the managed system chooses which:

| Value         | What it manages                                                                          | Looked up and written with                                            |
| ------------- | ---------------------------------------------------------------------------------------- | --------------------------------------------------------------------- |
| `User`        | Teams users. **The default** when the attribute is not set                               | `Get-CsOnlineUser` / `Set-CsUser`                                     |
| `Application` | Application instances — the resource accounts Teams uses for services rather than people | `Get-CsOnlineApplicationInstance` / `Set-CsOnlineApplicationInstance` |

To manage both, configure two managed systems.

### Custom handlers

Search, delete, password, suspend and resume can each be routed to a script of your own instead of the connector's built-in path, by setting `SEARCH_HANDLER`, `DELETE_HANDLER`, `PASSWORD_HANDLER`, `SUSPEND_HANDLER` or `RESUME_HANDLER` on the managed system. A handler takes over that operation entirely — which is also the only way to make delete, suspend, resume or password operations do anything, since the connector's own versions refuse them.

## Application authentication (Entra ID)

The connector authenticates to the tenant with a certificate rather than a password. That takes two things: a certificate on the connector host, and an application in Entra ID that trusts it.

### The certificate

Generate the certificate **on the machine running the connector**, so the private key stays there and never travels. Set your own CN, and run this in an **elevated** PowerShell — writing to `Cert:\LocalMachine\My` needs administrator rights:

{% code overflow="wrap" %}

```powershell
$certname = "Teams_connector"
New-SelfSignedCertificate -Subject "CN=$certname" -CertStoreLocation "Cert:\LocalMachine\My" -KeyExportPolicy Exportable -KeySpec Signature -KeyLength 2048 -KeyAlgorithm RSA -HashAlgorithm SHA256 -NotAfter (Get-Date).AddYears(10)
```

{% endcode %}

### Creating the application in Entra ID

Registering an application, giving it a certificate, granting it permissions and assigning it a directory role are Microsoft's procedures, and Microsoft keeps them current as the portal moves: [Create a Microsoft Entra application and service principal](https://learn.microsoft.com/en-us/entra/identity-platform/howto-create-service-principal-portal). What follows is what this connector needs along the way, and what each screen looks like once it is right.

{% stepper %}
{% step %}
**Register the application**

Any name will do. Set **Supported account types** to **Single tenant**.

<figure><img src="https://2965242200-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F0uHWHRgcad6P03ehqgmX%2Fuploads%2Fgit-blob-2d5e3f63c3f48ecccf8e6247897e12335c9a23f9%2F16-teams-03-new-registration.png?alt=media" alt="The Register an application form with a name entered and Supported account types set to Single tenant only"><figcaption></figcaption></figure>
{% endstep %}

{% step %}
**Upload the certificate**

Export the certificate generated above from the Windows certificate store **without its private key** — the same MMC procedure the Exchange connector uses, shown at [The certificate](/connector-configuration/microsoft/6-exchange.md#the-certificate). On the application's **Certificates & secrets** page, open the **Certificates** tab and upload the exported `.cer`.

<figure><img src="https://2965242200-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F0uHWHRgcad6P03ehqgmX%2Fuploads%2Fgit-blob-20aa0fd547b72ccb981bcd07d10aa4bfc91eb368%2F16-teams-07-Certificate4%20(1).png?alt=media" alt="The Upload certificate dialog with the exported .cer file chosen and a description entered, above the line naming the accepted file types cer, pem and crt"><figcaption></figcaption></figure>

The certificate then appears on the **Certificates** tab with its thumbprint — the value the OpenIAM managed system takes as its password.

<figure><img src="https://2965242200-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F0uHWHRgcad6P03ehqgmX%2Fuploads%2Fgit-blob-0f7ac47f6e908706746b874cb819950f00e82e22%2F16-teams-08-Certificate5.png?alt=media" alt="The Certificates and secrets page showing Certificates (1), the uploaded certificate listed with its thumbprint, description, start date and expiry"><figcaption></figcaption></figure>
{% endstep %}

{% step %}
**Grant the API permissions**

Under **API permissions → Add a permission → Microsoft Graph**, choose **Application permissions** — not **Delegated**, because the connector runs as a background service with no signed-in user — then tick `Organization.Read.All` and `User.Read.All`.

<figure><img src="https://2965242200-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F0uHWHRgcad6P03ehqgmX%2Fuploads%2Fgit-blob-916a3bf50749f9c7a64718fc942fd0a7cc2f2bb3%2F16-teams-11-API-permissions3%20(1).png?alt=media" alt="The Request API permissions panel for Microsoft Graph with Application permissions selected rather than Delegated, and Organization.Read.All ticked in the filtered permission list"><figcaption></figcaption></figure>

Then **Grant admin consent**. An application permission that has been added but not consented to does not take effect, so both have to end up showing as granted.

<figure><img src="https://2965242200-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F0uHWHRgcad6P03ehqgmX%2Fuploads%2Fgit-blob-c777a7b92631485064831a33b41b8fde8b2294ed%2F16-teams-09-API-permissions%20(1).png?alt=media" alt="The Configured permissions table listing Organization.Read.All and User.Read.All, both of type Application, both with a green granted status"><figcaption></figcaption></figure>
{% endstep %}

{% step %}
**Assign the Teams Administrator role**

In **Microsoft Entra roles and administrators**, open **Teams Administrator → Assignments → Add assignments** and add the application. The finished assignment is the quickest confirmation that the Entra side is done.

<figure><img src="https://2965242200-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F0uHWHRgcad6P03ehqgmX%2Fuploads%2Fgit-blob-df0d2bb99ed34e9e27406551b22f47de2087562d%2F16-teams-17-Add-application2.png?alt=media" alt="The Teams Administrator Assignments list showing the application assigned, with type ServicePrincipal and directory scope"><figcaption></figcaption></figure>
{% endstep %}
{% endstepper %}

## Attribute mapping and policy map

Attributes reach Teams through the policy map on the managed system, as they do for every connector — see [Configure a managed system](/administration-guide/lifecycle/configure-managed-system.md). What is specific to Teams is **which names are accepted** and **where each one is sent**.

### The accepted names are resolved at run time

The connector does not hold a fixed list of attributes. On each save it asks PowerShell what the target cmdlet accepts, and passes through whatever matches:

| Scope                        | Names accepted are those of       |
| ---------------------------- | --------------------------------- |
| `User`                       | `Set-CsUser`                      |
| `Application`                | `Set-CsOnlineApplicationInstance` |
| Phone numbers, on assignment | `Set-CsPhoneNumberAssignment`     |
| Phone numbers, on removal    | `Remove-CsPhoneNumberAssignment`  |

An attribute the cmdlet does not recognize is dropped rather than rejected, so a typo in the policy map fails quietly. The tables below are the attributes deployments use most — treat them as common examples, not as the full set, and check the cmdlet's own reference for anything beyond them.

{% hint style="info" %}
Because the list comes from the installed module, it moves when the module is updated. A new MicrosoftTeams release can add an attribute without any change to the connector.
{% endhint %}

### Phone number assignment

Phone numbers do not go to `Set-CsUser` with everything else — they have their own cmdlets, and two things decide what happens:

1. **`ModifyPhoneNumber` opens the path.** Unless it is `true`, every phone-number attribute is ignored and the save touches only the ordinary attributes.
2. **The operation on `PhoneNumber` decides the direction.** Adding or replacing a value assigns the number through `Set-CsPhoneNumberAssignment`; deleting the value removes the assignment through `Remove-CsPhoneNumberAssignment`; leaving it unchanged does nothing.

When `ModifyPhoneNumber` is `true`, the phone-number attributes are routed to those cmdlets and withheld from the object update, so nothing is sent twice.

| Attribute                | Description                                                                      | Type    |
| ------------------------ | -------------------------------------------------------------------------------- | ------- |
| `ModifyPhoneNumber`      | Opens the phone-number path. The attributes below apply only when this is `true` | boolean |
| `PhoneNumber`            | The number itself. Its operation decides assign versus remove                    | string  |
| `PhoneNumberType`        | The type of number — for example a calling-plan or direct-routing number         | string  |
| `AssignmentCategory`     | The assignment category for the number                                           | string  |
| `EnterpriseVoiceEnabled` | Enables or disables enterprise voice                                             | boolean |
| `ReverseNumberLookup`    | Sets reverse number lookup                                                       | string  |
| `Notify`                 | Emails the user about the phone number change                                    | boolean |

### Object attributes

Beyond phone numbers, each scope takes the attributes of its own cmdlet. These are the ones in common use:

| Attribute       | Scope         | Description                         | Type   |
| --------------- | ------------- | ----------------------------------- | ------ |
| `DisplayName`   | `User`        | Sets the display name               | string |
| `ApplicationId` | `User`        | Sets the application ID             | string |
| `AcsResourceId` | `User`        | Sets the ACS resource ID            | string |
| `LineURI`       | `Application` | The resource account's phone number | string |

## Reconciliation and synchronization

How synchronization and reconciliation work in general is covered in the Administration guide — see [*Synchronize and import data*](/administration-guide/lifecycle/synchronize-and-import-data.md) and [*Configure reconciliation*](/administration-guide/lifecycle/configure-reconciliation.md). This section covers only what is specific to this connector.

For synchronization, set a search string in the ***SQL Query / Directory Filter*** field on the synchronization page (Webconsole → **Provisioning** → **Synchronization** → **Edit** your profile). This string defines what the connector reads from Teams.

Common examples:

* `Get-CsOnlineUser` — returns the tenant's Teams users.
* `Get-CsOnlineApplicationInstance` — returns the application instances, for a managed system whose scope is `Application`.

The connector runs this string as a PowerShell expression, and checks it first. It has to be **one pipeline that only reads**:

* One statement — no `;` separators, no conditions, loops, assignments or function definitions.
* A reading verb. Anything that changes state is refused, so `Get-` and `Select-Object` are fine while `Set-`, `New-` and `Remove-` are not. For Teams, `Connect-MicrosoftTeams` and `Disconnect-MicrosoftTeams` are refused by name as well — a query that re-authenticates or closes the session is not a search.

A query that fails the check stops the synchronization with a message saying which rule it broke. Shape the data in a transformation script rather than in the query.

Only the properties named as attributes on the managed system are returned; everything else the cmdlet emits is discarded. If the connector is configured with a batch size, results are sent to OpenIAM in batches of that size rather than in one response.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.openiam.com/connector-configuration/microsoft/16-teams.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
