Using GitHub Copilot to Work with Dataverse

In the previous article, we looked at how to edit Canvas Power Apps with GitHub Copilot. This was accomplished with the help of Power Apps skills. Let’s continue with the same theme and look what we can do with the GitHub Copilot CLI’s Dataverse skills.
Dataverse skills are essentially the following:
- dv-connect can connect to the Dataverse environment.
- dv-data can create, update, and delete data from Dataverse tables. It can therefore manipulate data.
- dv-metadata can create new tables, columns, relations, forms and views.
- dv-overview is a top-level skill that guides tasks to the right skills
- dv-query can read and analyze data from Dataverse tables
- dv-solution can, for example, create a solution package, add components to it, and export it to the desired environment.
What’s so great about this then?
You can have AI do typical tasks that you have previously manually clicked together in the maker portal.

Let’s explore this ability in a little more detail with an example.
Example – Data model for a device register
Before starting, you must install the following on the machine:
- PowerShell v6 or later
- GitHub Copilot CLI (GitHub Copilot license required, starting at 0€)
And after this, Dataverse skills are installed.
copilot plugin Marketplace add microsoft/Dataverse-skills
copilot plugin install dataverse@dataverse-skills
Data model design
A typical starting point in the low-code world is that the customer has an Excel-based solution (or the beginning of a solution), but it is seen that it will not be able to meet all current or future needs. They want the right application to replace it.
This Excel file often contains one table with all the information. Below is an example of such a device register.

Each device has the following information:
- Name
- Condition
- Owner
- In which building is the device located?
- On which floor of the building is the device located?
The necessary information is all here, but for the application we want a more sensible data model.
Let’s upload Excel to our working folder and ask GitHub Copilot to design a proper data model based on it.
There is devices.xlsx file in this directory. There is a list of devices. Plan data model for dataverse to store this
information. I like to have: device condition as choice, device owner to be lookup to system user table. And please
separate buildings and floors in their own tables. Make plan for datamodel in datamodel.md file.

Copilot asks for permission if it needs to do something on my computer, such as read the contents of a file or create a new file.

The end result looks exactly what I was looking for.

The whole plan is as follows.
# Dataverse Data Model – Device Management
## Source Data (devices.xlsx)
| Device | Condition | Owner | Building | Floor |
|---------|-----------|-------------|----------|-----------|
| MacBook | New | Timo Pertilä | Main | 1st floor |
| MacBook | Poor | Timo Pertilä | Main | 2nd floor |
| MacBook | Good | Timo Pertilä | FAQ | 3rd floor |
---
## Tables
### 1. Building (`cr_building`)
Stores physical buildings.
| Column | Type | Notes |
|----------------|--------------|------------------------|
| `cr_buildingid`| GUID (PK) | Auto-generated |
| `cr_name` | Single Line Text (required) | eg "Main", "FAQ" |
| `createdon` | Date & Time | Standard audit column |
| `modifiedon` | Date & Time | Standard audit column |
---
### 2. Floor (`cr_floor`)
Stores floors within buildings. Each floor belongs to exactly one building.
| Column | Type | Notes |
|-----------------|------------------------|---------------------------|
| `cr_floorid` | GUID (PK) | Auto-generated |
| `cr_name` | Single Line Text (required) | eg "1st floor", "2nd floor" |
| `cr_building` | Lookup → `cr_building` | Required – parent building |
| `createdon` | Date & Time | Standard audit column |
| `modifiedon` | Date & Time | Standard audit column |
---
### 3. Device (`cr_device`)
Main table that stores device records.
| Column | Type | Notes |
|-----------------|-----------------------------|-------------------------------------------|
| `cr_deviceid` | GUID (PK) | Auto-generated |
| `cr_name` | Single Line Text (required) | Device name / model, eg "MacBook" |
| `cr_condition` | **Choice** (required) | Values: `New`, `Good`, `Poor` (extensible) |
| `cr_owner` | Lookup → `systemuser` | Device owner (Dataverse system user) |
| `cr_floor` | Lookup → `cr_floor` | Floor where device is located |
| `createdon` | Date & Time | Standard audit column |
| `modifiedon` | Date & Time | Standard audit column |
> **Note:** Building is derivable via the Floor lookup (`cr_floor → cr_building`), so no direct building column is needed on Device. This avoids redundancy and keeps data consistent.
---
## Choice: Device Condition
Global choice set `cr_devicecondition`:
| Label | Value |
|-------|-------|
| New | 1 |
| Good | 2 |
| Poor | 3 |
---
## Relationships
```
systemuser (1) ─────────────────── (N) cr_device
│
cr_building (1) ──── (N) cr_floor (1) ──┘ (via cr_floor lookup)
```
| Relationship | Type | From Table | To Table |
|---------------------------|------------|--------------|--------------|
| Building → Floors | 1:N | `cr_building` | `cr_floor` |
| Floor → Devices | 1:N | `cr_floor` | `cr_device` |
| SystemUser → Devices | 1:N | `systemuser` | `cr_device` |
---
## ER Diagram
```
┌─────────────────┐ ┌─────────────────┐
│ cr_building │ │ systemuser │
│─────────────────│ │─────────────────│
│ cr_buildingid │ │ systemuserid │
│ cr_name │ │ fullname │
└────────┬────────┘ └────────┬────────┘
│ 1:N │ 1:N
▼ │
┌─────────────────┐ │
│ cr_floor │ │
│───────────────│ │
│ cr_floorid │ │
│ cr_name │ │
│ cr_building │◄── lookup │
└────────────────────│
1:N │
▼ ▼
┌────────────────────────────────────────────────────
│ cr_device │
││──────────────│
│ cr_deviceid │
│ cr_name │
│ cr_condition (Choice: New/Good/Poor) │
│
cr_floor (Lookup → systemuser) │ │
└─────────────────────────────────────
You can freely edit the data model at this point. Yourself or with the help of Copilot. But let’s go with this for now.
Creating a data model
Next, we ask Copilot to create the tables according to the plan in the given environment. We want everything to be done in the Devices Demo solution with the existing Timo Pertilä publisher.
This looks good! Can you create a solution for this (Devices Demo) using Timo Pertilä publisher. Then create needed custom tables with sample data. Use this environment:
https://make.powerapps.com/environments/a238d77b-b9b4-e570-8464-6833e6a98d56 in tenant f8c98920-c3d7-46b3-b802-ae70afd4b77a
Copilot spends its time thinking about how to connect to the right environment and how the whole task should be done. But using the tools it has been given, it progresses towards the goal.
Along the way, it will, for example, find an existing publisher in the environment to use.

In practice, it writes a python script that creates the tables and columns in Dataverse.
It all takes a while, but in the end everything is created as it should be.

Excel content is pre-created in tables.

Even the LookUp fields are elegantly named.

Almost 1000 lines of Python code were needed for all of this.
Updating forms and views
Finally, we ask Copilot to add the necessary fields to the views and forms.
Could you modify views and forms to be like following:
Default Views (for looking Active items)
- Floor: Name, Building
- Building: Name
- Device: Name, Condition, Owner, Floor, Building (from the floor table), created on
Main Forms
- Floor: Name, Building, Created on, owner, subgrid showing devices
- Building: Name, Created on, owner
- Device: Name, Condition, Owner, Floor, created on, owner
Copilot immediately starts planning changes.

It takes a while, but in the end everything is done the way I wanted.

I was a little nervous about the floor form , but it came out just right.

Finally, let’s try something i hate to do myself.
Deleting a column
I want to remove the column describing the device’s health from the device. But it’s already included in the form and view. So I first have to remove it from everywhere it’s used and only then can I actually delete it.
Let’s give this boring task to Copilot.
can you remove the condition column from the device table?
Copilot immediately understood what it needed to do to make the removal successful.

This didn’t take long. The column has been removed from the view, the form, and finally completely. Awesome!

Creating a model-driven application
Finally, we will test whether Copilot can also create a model-based application. This is not described in its capabilities.
Can you create a model driven app?
The end result is an empty application. On the other hand, I just asked to create an application.

Next we ask to add the necessary tables to the application.
Add also tables to the app (devices, buildings, flows and users)
This puzzle took a really long time. Along the way, Copilot created 6 identical empty apps. But it finally (almost) got this one right. For some strange reason, the Accounts table was also hidden in the app without asking.

Summary
It’s hard not to like this. Even though the tasks take a long time (I could put these together much faster myself), it’s better to do something a little more useful yourself, when Copilot clicks new columns into the tables and fixes the basic views and forms. Or removes a column to be deleted from forms and views so that it can be deleted.