cli-microsoft365 icon indicating copy to clipboard operation
cli-microsoft365 copied to clipboard

New command: `m365 pp chatbot list`

Open appieschot opened this issue 3 years ago • 13 comments

Usage

m365 pp chatbot list

Description

Lists Microsoft Power Platform chatbots

Options

Option Description
-e, --environment <environment> The name of the environment for which to retrieve available chatbots

Examples

Retrieves all chatbots for the default environment

m365 pp chatbot list -e "Default-2ca3eaa5-140f-4175-8261-3272edf9f339"

Additional Info

We should spend a few minutes to check if this is possible; the PowerShell cmdlets are not supporting this and there is no documentation, but I do see URL's with: /providers/microsoft.powerapps/apis/shared_bot for chatbots linked to apps and in the PVA webinterface https://powervamg.eu-il107.gateway.prod.island.powerapps.com/api/botmanagement/v1/environments/envName/bots is called, a URL we can retrieve from the runtime endpoints the same way we retrieve the https://europe.api.bap.microsoft.com URL.

appieschot avatar Sep 06 '22 09:09 appieschot

Add private channel to the specified Microsoft Teams team with owner UPN

What's that second example doing there?

martinlingstuyl avatar Sep 06 '22 12:09 martinlingstuyl

That should totally be deleted! (and is done so ;))

appieschot avatar Sep 06 '22 12:09 appieschot

Did you already get this working using our fabulous m365 request command? 😉

martinlingstuyl avatar Sep 06 '22 12:09 martinlingstuyl

@martinlingstuyl no :( looks like we are missing either a scope on our app reg or it is not being passed on correctly ;-). But havent spend more time than just pasting in the URL to see what happens, will see if we can get a token for this endpoint with the current app reg.

image

appieschot avatar Sep 06 '22 13:09 appieschot

@appieschot, this is one of those endpoints where the URL does not equal the resource that is registered in Azure AD. You might want to try specifying the --resource option. I'm not sure which resource you need though. Maybe https://management.azure.com works, or https://api.powerapps.com or https://api.bap.microsoft.com.

aka:

m365 request --url "url" --resource "https://management.azure.com"

martinlingstuyl avatar Sep 06 '22 13:09 martinlingstuyl

I don't know if the endpoint is called from the UI using a bearer token? Probably not, but if so, you could decode it to see what the token audience is.

martinlingstuyl avatar Sep 06 '22 13:09 martinlingstuyl

@martinlingstuyl decoding is next on the list, wanted to push #3655 first 😂

appieschot avatar Sep 06 '22 13:09 appieschot

Hmm, not a resource we can use or so it seems. The UI uses the following ID for the token 96ff4394-9197-43aa-b393-6a41652e21f8 (Dynamics 365 AI for Customer Service Bot).. Will investigate if we have other API's we can use!

appieschot avatar Sep 06 '22 14:09 appieschot

Long story short I do not think we can get this to work. In the Power Platform UI they use GraphQL to get the chatbots from an API (with random graphql prefix that is put to the window._makerConfig, so that is a no go for us.

The https://powervamg.eu-il107.gateway.prod.island.powerapps.com/api/botmanagement/ andpoint can be used, but does require us to have access to the Dynamics 365 AI for Customer Service Bot with id 96ff4394-9197-43aa-b393-6a41652e21f8 living in tenant f8cdef31-a31e-4b4a-93e4-5f571e91255a and I have the feeling they will not allow CLI to be connected to that app 😉.

Leaves us with a single implementation option and that is to read the Chatbot dataverse table: https://www.expiscornovus.com/2021/09/08/list-all-power-virtual-agents/

If we implement #3653 we can spec a m365 pp dataverse table row list or m365 pp dataverse row list command to list all rows in a specified table. That one can then be used to build this command I would say. I'll put this one on hold untill we have dataverse one in specced and in place.

appieschot avatar Sep 07 '22 11:09 appieschot

So is the skinny that we should close this issue because right now, there's no way for us to implement it?

waldekmastykarz avatar Sep 09 '22 15:09 waldekmastykarz

@waldekmastykarz happy to close the command, but as soon as we have #3653 implemented we could use that command to retrieve the required values and provide this command for ppl who are not aware on how to get values from dataverse :)

appieschot avatar Sep 17 '22 13:09 appieschot

Let me see if I understand it correctly: while there's no API that we can use, we can grab the list of chatbots from Dataverse, is that correct @appieschot?

waldekmastykarz avatar Sep 18 '22 17:09 waldekmastykarz

That is correct; there is a fixed dataverse table present if you create chatbots and they hold the references and names to those chatbots

appieschot avatar Sep 19 '22 07:09 appieschot

@appieschot I'm removing the on hold label because the blocking issue has been implemented 🚀

Jwaegebaert avatar Nov 02 '22 11:11 Jwaegebaert

Wellll.... We can't get table rows yet but well get there soon enough 🦾

appieschot avatar Nov 02 '22 13:11 appieschot

Hi All,

There is also an api for this: dynamicsApiUrl/api/data/v9.0/bots to which you can give a fetchXml parameter for more specific info from the bot

Greets

nicodecleyre avatar Nov 13 '22 19:11 nicodecleyre

That's great news, If I understand correct we can use that API to retrieve bots and include a --details if we need more details?

appieschot avatar Nov 14 '22 09:11 appieschot

That's great news, If I understand correct we can use that API to retrieve bots and include a --details if we need more details?

Maybe we should include the details response with the fetchXml standard, because a call without the fetchXml doesn't say much.

For example, the response from the call dynamicsApiUrl/api/data/v9.0/bots without fetchXml parameter returns:

{
    "value": [
        {
            "@odata.etag": "W/\"1411208\"",
            "authenticationtrigger": 0,
            "_owningbusinessunit_value": "6da087c1-1c4d-ed11-bba1-000d3a2caf7f",
            "statuscode": 1,
            "createdon": "2022-11-13T19:11:35Z",
            "statecode": 0,
            "schemaname": "new_bot_9be05428a2794aa3ae548449c2cc2722",
            "_ownerid_value": "5fa787c1-1c4d-ed11-bba1-000d3a2caf7f",
            "overwritetime": "1900-01-01T00:00:00Z",
            "name": "test",
            "solutionid": "fd140aae-4df4-11dd-bd17-0019b9312238",
            "ismanaged": false,
            "versionnumber": 1411208,
            "language": 1033,
            "_modifiedby_value": "5f91d7a7-5f46-494a-80fa-5c18b0221351",
            "_modifiedonbehalfby_value": "5fa787c1-1c4d-ed11-bba1-000d3a2caf7f",
            "modifiedon": "2022-11-13T19:11:37Z",
            "componentstate": 0,
            "botid": "9be05428-a279-4aa3-ae54-8449c2cc2722",
            "_createdby_value": "5fa787c1-1c4d-ed11-bba1-000d3a2caf7f",
            "componentidunique": "468e0999-568f-4f68-b345-34bf0eb2f5b7",
            "authenticationmode": 1,
            "_owninguser_value": "5fa787c1-1c4d-ed11-bba1-000d3a2caf7f",
            "accesscontrolpolicy": 0,
            "runtimeprovider": 0,
            "_publishedby_value": null,
            "authenticationconfiguration": null,
            "authorizedsecuritygroupids": null,
            "overriddencreatedon": null,
            "applicationmanifestinformation": null,
            "importsequencenumber": null,
            "synchronizationstatus": null,
            "template": null,
            "_providerconnectionreferenceid_value": null,
            "configuration": null,
            "utcconversiontimezonecode": null,
            "publishedon": null,
            "_createdonbehalfby_value": null,
            "iconbase64": null,
            "supportedlanguages": null,
            "_owningteam_value": null,
            "timezoneruleversionnumber": null,
            "iscustomizable": {
                "Value": true,
                "CanBeChanged": true,
                "ManagedPropertyLogicalName": "iscustomizableanddeletable"
            }
        }
    ]
}

but the response from the call dynamicsApiUrl/api/data/v9.0/bots with fetchXml parameter returns:

{
    "value": [
        {
            "@odata.etag": "W/\"versionnumber\"",
            "botid": "9be05428-a279-4aa3-ae54-8449c2cc2722",
            "language": 1033,
            "overwriteTime": "1900-01-01T00:00:00Z",
            "botModifiedOn": "2022-11-13T19:11:37Z",
            "displayName": "test",
            "schemaName": "new_bot_9be05428a2794aa3ae548449c2cc2722",
            "solutionId": "fd140aae-4df4-11dd-bd17-0019b9312238",
            "componentIdUnique": "468e0999-568f-4f68-b345-34bf0eb2f5b7",
            "stateCode": 0,
            "statusCode": 1,
            "isManaged": false,
            "accessControlPolicy": 0,
            "botModifiedBy": "SYSTEM",
            "ownerId": "5fa787c1-1c4d-ed11-bba1-000d3a2caf7f",
            "componentState": 0,
            "authenticationMode": 1,
            "versionNumber": 1411208,
            "owner": "De Cleyre, Nico",
            "createdOn": "2022-11-13T19:11:35Z",
            "authenticationTrigger": 0,
            "cdsBotId": "9be05428-a279-4aa3-ae54-8449c2cc2722"
        }
    ]
}

where the fetchXml parameter is the following xml:

<fetch mapping='logical' version='1.0' >
  <entity name='bot'>
<attribute name='accesscontrolpolicy' alias='accessControlPolicy' />,<attribute name='applicationmanifestinformation' alias='applicationManifestInformation' />,<attribute name='authenticationmode' alias='authenticationMode' />,<attribute name='authenticationtrigger' alias='authenticationTrigger' />,<attribute name='authorizedsecuritygroupids' alias='authorizedSecurityGroupIds' />,<attribute name='componentidunique' alias='componentIdUnique' />,<attribute name='componentstate' alias='componentState' />,<attribute name='configuration' alias='configuration' />,<attribute name='createdon' alias='createdOn' />,<attribute name='importsequencenumber' alias='importSequenceNumber' />,<attribute name='ismanaged' alias='isManaged' />,<attribute name='language' alias='language' />,<attribute name='modifiedon' alias='botModifiedOn' />,<attribute name='overriddencreatedon' alias='overriddenCreatedOn' />,<attribute name='overwritetime' alias='overwriteTime' />,<attribute name='iconbase64' alias='iconBase64' />,<attribute name='publishedon' alias='publishedOn' />,<attribute name='schemaname' alias='schemaName' />,<attribute name='solutionid' alias='solutionId' />,<attribute name='statecode' alias='stateCode' />,<attribute name='statuscode' alias='statusCode' />,<attribute name='timezoneruleversionnumber' alias='timezoneRuleVersionNumber' />,<attribute name='utcconversiontimezonecode' alias='utcConversionTimezoneCode' />,<attribute name='versionnumber' alias='versionNumber' />,<attribute name='name' alias='displayName' />,<attribute name='botid' alias='cdsBotId' />,<attribute name='ownerid' alias='ownerId' />,<attribute name='synchronizationstatus' alias='synchronizationStatus' />
    <link-entity name='systemuser' to='ownerid' from='systemuserid' link-type='inner' >
      <attribute name='fullname' alias='owner' />
    </link-entity>
    <link-entity name='systemuser' to='modifiedby' from='systemuserid' link-type='inner' >
      <attribute name='fullname' alias='botModifiedBy' />
    </link-entity>
  </entity>
</fetch>

my opinion: we should always log the response from the api with the fetchXml parameter

nicodecleyre avatar Nov 14 '22 09:11 nicodecleyre

Totally agree! So oppened up

appieschot avatar Nov 18 '22 10:11 appieschot

Can i work on this one?

nicodecleyre avatar Nov 21 '22 16:11 nicodecleyre