Presence
Reading presence needs Presence.Read.All. Writing it needs Presence.ReadWrite, which is in the
default delegated scope set — if you signed in before it was added, run teams auth login again to
consent to it. The write commands act on /me, so they are delegated-only and reject an app-only
token before sending anything.
Read
Read your own presence:
teams presence get --output json
Read another user:
teams presence get --user "$USER_ID" --output json
Read several at once:
teams presence get-batch --user-ids "$USER_ID_1,$USER_ID_2" --output json
Your own presence carries two fields the others do not. Microsoft Graph only returns
statusMessage.expiryDateTime and statusMessage.publishedDateTime for /me/presence; a lookup of
another user omits them.
{
"availability": "Away",
"activity": "Away",
"statusMessage": {
"message": { "content": "Back on Monday", "contentType": "text" },
"publishedDateTime": "2026-08-27T09:14:22.9411568Z",
"expiryDateTime": { "dateTime": "2026-09-01T08:00:00.0000000", "timeZone": "UTC" }
}
}
expiryDateTime is an object with dateTime and timeZone, not a string.
Set
Microsoft Graph accepts exactly five --availability/--activity pairs:
--availability | --activity |
|---|---|
Available | Available |
Busy | InACall |
Busy | InAConferenceCall |
Away | Away |
DoNotDisturb | Presenting |
Values such as Offline and InAMeeting appear when reading someone's presence but are not
accepted by presence set.
teams presence set --availability Busy --activity InACall --expiration PT1H --output json
--expiration is an ISO 8601 duration between PT5M and PT4H, checked locally before the request
is sent — an out-of-range or malformed value fails as invalid input (exit 2) rather than costing a
round trip. Leaving it out applies Graph's own five-minute default, so a presence set this way
lapses on its own either way. An agent that sets Available and then dies does not leave a green
light behind indefinitely.
Status message
teams presence status --message "In deep focus" --output json
teams presence status --message "Back Monday" --expiry "2026-09-01T08:00:00" --output json
Clear
teams presence clear --output json
Graph keys a presence session to the application that opened it, so set and clear both send that
application's ID as the session ID — a configured client_id when there is one, otherwise the
application claim on the access token itself. Both commands report the value back, so a clear run
under different configuration than the set is visible rather than silent.
clear succeeds whether or not a session was open, and says which happened:
status | Meaning |
|---|---|
presence_cleared | Graph closed an application presence session. |
no_presence_session | Graph knew of no session under that ID. Also what a retry sees when the attempt before it succeeded but its response was lost. |
Clearing reverts presence to whatever Teams calculates automatically — unless a preferred presence is set, which outranks every session. See below.
Preferred presence
Microsoft Graph keeps two writable layers. presence set opens an application presence session,
which Teams weighs against your calendar and activity. Above every session sits the user-preferred
presence — the layer the Teams client writes when you pick a status from the menu, including
Appear offline. presence set cannot reach it, which is why a set on an account that is
appearing offline returns success while the account stays offline.
teams presence set-preferred --availability Away --output json
teams presence set-preferred --availability Offline --expiration P1D --output json
teams presence clear-preferred --output json
Each of the six availabilities Graph accepts here has exactly one activity, so the command derives it and reports both back:
--availability | Activity |
|---|---|
Available | Available |
Busy | Busy |
DoNotDisturb | DoNotDisturb |
BeRightBack | BeRightBack |
Away | Away |
Offline | OffWork |
--expiration is an ISO 8601 duration in whole day, hour, minute or second units, such as P1D,
PT8H or PT30M. It is checked for shape locally but not bounded, because Graph documents defaults
rather than a range: one day for Busy and DoNotDisturb, seven days for the rest. Leaving it out
applies that default.
set-preferred answers with status: preferred_presence_set plus the availability, activity and
expiration it sent. clear-preferred answers with status: preferred_presence_cleared and takes no
session ID, because the preferred presence belongs to the user rather than to an application.
Clearing it hands control back to Teams' own calculation and to any application session still open.
Both commands need Presence.ReadWrite, the same scope as presence set, and both are
delegated-only.