diff --git a/packages/Teams/dotnet/Actions/GetMeetingInfo.cs b/packages/Teams/dotnet/Actions/GetMeetingInfo.cs
new file mode 100644
index 0000000000..a95eaa52a5
--- /dev/null
+++ b/packages/Teams/dotnet/Actions/GetMeetingInfo.cs
@@ -0,0 +1,104 @@
+// Licensed under the MIT License.
+// Copyright (c) Microsoft Corporation. All rights reserved.
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Threading;
+using System.Threading.Tasks;
+using AdaptiveExpressions.Properties;
+using Microsoft.Bot.Builder.Dialogs;
+using Microsoft.Bot.Builder.Teams;
+using Microsoft.Bot.Connector;
+using Newtonsoft.Json;
+
+namespace Microsoft.Bot.Components.Teams.Actions
+{
+ ///
+ /// Calls TeamsInfo.GetMeetingInfoAsync and sets the result to a memory property.
+ ///
+ public class GetMeetingInfo : Dialog
+ {
+ ///
+ /// Class identifier.
+ ///
+ [JsonProperty("$kind")]
+ public const string Kind = "Teams.GetMeetingInfo";
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Optional, source file full path.
+ /// Optional, line number in source file.
+ [JsonConstructor]
+ public GetMeetingInfo([CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0)
+ : base()
+ {
+ RegisterSourceLocation(callerPath, callerLine);
+ }
+
+ ///
+ /// Gets or sets an optional expression which if is true will disable this action.
+ ///
+ ///
+ /// "user.age > 18".
+ ///
+ ///
+ /// A boolean expression.
+ ///
+ [JsonProperty("disabled")]
+ public BoolExpression Disabled { get; set; }
+
+ ///
+ /// Gets or sets property path to put the value in.
+ ///
+ ///
+ /// Property path to put the value in.
+ ///
+ [JsonProperty("property")]
+ public StringExpression Property { get; set; }
+
+ ///
+ /// Gets or sets the expression to get the value to use for meeting id.
+ ///
+ ///
+ /// The expression to get the value to use for meeting id. Default value is turn.activity.channelData.meeting.id.
+ ///
+ [JsonProperty("meetingId")]
+ public StringExpression MeetingId { get; set; } = "=turn.activity.channelData.meeting.id";
+
+ ///
+ public override async Task BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ if (options is CancellationToken)
+ {
+ throw new ArgumentException($"{nameof(options)} cannot be a cancellation token");
+ }
+
+ if (Disabled != null && Disabled.GetValue(dc.State))
+ {
+ return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
+ }
+
+ if (dc.Context.Activity.ChannelId != Channels.Msteams)
+ {
+ throw new InvalidOperationException($"{Kind} works only on the Teams channel.");
+ }
+
+ string meetingId = MeetingId.GetValueOrNull(dc.State);
+ var result = await TeamsInfo.GetMeetingInfoAsync(dc.Context, meetingId, cancellationToken: cancellationToken).ConfigureAwait(false);
+
+ if (Property != null)
+ {
+ dc.State.SetValue(Property.GetValue(dc.State), result);
+ }
+
+ return await dc.EndDialogAsync(result, cancellationToken: cancellationToken).ConfigureAwait(false);
+ }
+
+ ///
+ protected override string OnComputeId()
+ {
+ return $"{GetType().Name}[{MeetingId?.ToString() ?? string.Empty},{Property?.ToString() ?? string.Empty}]";
+ }
+ }
+}
diff --git a/packages/Teams/dotnet/Schemas/Actions/Teams.GetMeetingInfo.schema b/packages/Teams/dotnet/Schemas/Actions/Teams.GetMeetingInfo.schema
new file mode 100644
index 0000000000..39d3fedb45
--- /dev/null
+++ b/packages/Teams/dotnet/Schemas/Actions/Teams.GetMeetingInfo.schema
@@ -0,0 +1,38 @@
+{
+ "$schema": "https://schemas.botframework.com/schemas/component/v1.0/component.schema",
+ "$role": "implements(Microsoft.IDialog)",
+ "title": "Get meeting information",
+ "description": "Get teams meeting information.",
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string",
+ "title": "Id",
+ "description": "Optional id for the dialog"
+ },
+ "property": {
+ "$ref": "schema:#/definitions/stringExpression",
+ "title": "Property",
+ "description": "Property (named location to store information).",
+ "examples": [
+ "dialog.meetingInfo"
+ ]
+ },
+ "meetingId": {
+ "$ref": "schema:#/definitions/stringExpression",
+ "title": "Meeting id",
+ "description": "Meeting Id or expression to a meetingId to use to get the meeting information. Default value is the current turn.activity.channelData.meeting.id.",
+ "examples": [
+ "=turn.activity.channelData.meeting.id"
+ ]
+ },
+ "disabled": {
+ "$ref": "schema:#/definitions/booleanExpression",
+ "title": "Disabled",
+ "description": "Optional condition which if true will disable this action.",
+ "examples": [
+ "=user.age > 3"
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/Teams/dotnet/Schemas/Actions/Teams.GetMeetingInfo.uischema b/packages/Teams/dotnet/Schemas/Actions/Teams.GetMeetingInfo.uischema
new file mode 100644
index 0000000000..9f79a1de99
--- /dev/null
+++ b/packages/Teams/dotnet/Schemas/Actions/Teams.GetMeetingInfo.uischema
@@ -0,0 +1,6 @@
+{
+ "$schema": "https://schemas.botframework.com/schemas/ui/v1.0/ui.schema",
+ "menu": {
+ "submenu": ["Microsoft Teams", "Get Teams Info"]
+ }
+}
\ No newline at end of file
diff --git a/packages/Teams/dotnet/Schemas/TriggerConditions/Teams.OnMeetingEnd.schema b/packages/Teams/dotnet/Schemas/TriggerConditions/Teams.OnMeetingEnd.schema
new file mode 100644
index 0000000000..e339419fb0
--- /dev/null
+++ b/packages/Teams/dotnet/Schemas/TriggerConditions/Teams.OnMeetingEnd.schema
@@ -0,0 +1,9 @@
+{
+ "$schema": "https://schemas.botframework.com/schemas/component/v1.0/component.schema",
+ "$role": [ "implements(Microsoft.ITrigger)", "extends(Microsoft.OnCondition)" ],
+ "title": "On meeting end",
+ "description": "Actions triggered when a Teams Meeting is ended",
+ "type": "object",
+ "required": [
+ ]
+}
diff --git a/packages/Teams/dotnet/Schemas/TriggerConditions/Teams.OnMeetingEnd.uischema b/packages/Teams/dotnet/Schemas/TriggerConditions/Teams.OnMeetingEnd.uischema
new file mode 100644
index 0000000000..98cfcc870a
--- /dev/null
+++ b/packages/Teams/dotnet/Schemas/TriggerConditions/Teams.OnMeetingEnd.uischema
@@ -0,0 +1,7 @@
+{
+ "$schema": "https://schemas.botframework.com/schemas/ui/v1.0/ui.schema",
+ "trigger": {
+ "submenu": "Microsoft Teams",
+ "label": "On meeting end"
+ }
+}
diff --git a/packages/Teams/dotnet/Schemas/TriggerConditions/Teams.OnMeetingStart.schema b/packages/Teams/dotnet/Schemas/TriggerConditions/Teams.OnMeetingStart.schema
new file mode 100644
index 0000000000..e30ddfff41
--- /dev/null
+++ b/packages/Teams/dotnet/Schemas/TriggerConditions/Teams.OnMeetingStart.schema
@@ -0,0 +1,9 @@
+{
+ "$schema": "https://schemas.botframework.com/schemas/component/v1.0/component.schema",
+ "$role": [ "implements(Microsoft.ITrigger)", "extends(Microsoft.OnCondition)" ],
+ "title": "On meeting start",
+ "description": "Actions triggered when a Teams Meeting is started",
+ "type": "object",
+ "required": [
+ ]
+}
diff --git a/packages/Teams/dotnet/Schemas/TriggerConditions/Teams.OnMeetingStart.uischema b/packages/Teams/dotnet/Schemas/TriggerConditions/Teams.OnMeetingStart.uischema
new file mode 100644
index 0000000000..440af4b889
--- /dev/null
+++ b/packages/Teams/dotnet/Schemas/TriggerConditions/Teams.OnMeetingStart.uischema
@@ -0,0 +1,7 @@
+{
+ "$schema": "https://schemas.botframework.com/schemas/ui/v1.0/ui.schema",
+ "trigger": {
+ "submenu": "Microsoft Teams",
+ "label": "On meeting start"
+ }
+}
diff --git a/packages/Teams/dotnet/TeamsBotComponent.cs b/packages/Teams/dotnet/TeamsBotComponent.cs
index cf2cd3cc6e..1eb4cef0aa 100644
--- a/packages/Teams/dotnet/TeamsBotComponent.cs
+++ b/packages/Teams/dotnet/TeamsBotComponent.cs
@@ -42,6 +42,8 @@ public override void ConfigureServices(IServiceCollection services, IConfigurati
services.AddSingleton(sp => new DeclarativeType(OnTeamsChannelRenamed.Kind));
services.AddSingleton(sp => new DeclarativeType(OnTeamsChannelRestored.Kind));
services.AddSingleton(sp => new DeclarativeType(OnTeamsFileConsent.Kind));
+ services.AddSingleton(sp => new DeclarativeType(OnTeamsMeetingStart.Kind));
+ services.AddSingleton(sp => new DeclarativeType(OnTeamsMeetingEnd.Kind));
services.AddSingleton(sp => new DeclarativeType(OnTeamsMECardButtonClicked.Kind));
services.AddSingleton(sp => new DeclarativeType(OnTeamsMEConfigQuerySettingUrl.Kind));
@@ -68,6 +70,7 @@ public override void ConfigureServices(IServiceCollection services, IConfigurati
// Actions
+ services.AddSingleton(sp => new DeclarativeType(GetMeetingInfo.Kind));
services.AddSingleton(sp => new DeclarativeType(GetMeetingParticipant.Kind));
services.AddSingleton(sp => new DeclarativeType(GetMember.Kind));
services.AddSingleton(sp => new DeclarativeType(GetPagedMembers.Kind));
diff --git a/packages/Teams/dotnet/TriggerConditions/OnTeamsMeetingEnd.cs b/packages/Teams/dotnet/TriggerConditions/OnTeamsMeetingEnd.cs
new file mode 100644
index 0000000000..c99285ab01
--- /dev/null
+++ b/packages/Teams/dotnet/TriggerConditions/OnTeamsMeetingEnd.cs
@@ -0,0 +1,37 @@
+// Licensed under the MIT License.
+// Copyright (c) Microsoft Corporation. All rights reserved.
+
+using System.Collections.Generic;
+using System.Runtime.CompilerServices;
+using AdaptiveExpressions;
+using Microsoft.Bot.Builder.Dialogs;
+using Microsoft.Bot.Builder.Dialogs.Adaptive.Conditions;
+using Microsoft.Bot.Connector;
+using Newtonsoft.Json;
+
+namespace Microsoft.Bot.Components.Teams.Conditions
+{
+ ///
+ /// Actions triggered when a Teams Meeting End event is received.
+ ///
+ ///
+ /// turn.activity.value has meeting data.
+ ///
+ public class OnTeamsMeetingEnd : OnEventActivity
+ {
+ [JsonProperty("$kind")]
+ public new const string Kind = "Teams.OnMeetingEnd";
+
+ [JsonConstructor]
+ public OnTeamsMeetingEnd(List