PowerApp UI Component Tree Generator. Generate visual component trees from PowerApp .msapp or .zip containing .msapp files with UI hierarchy, PowerFx expressions, and template metadata.
When asking Copilot or coding tools for Power Fx expressions, they often return hallucinations or verbose answers without understanding the UI hierarchy structure. This tool extracts UI hierarchy and associated Power Fx from PowerApp msapp or zip files to provide proper context to LLMs.
Key Benefits:
- Provides accurate UI component hierarchy for AI context
- Extracts only relevant Power Fx expressions (filters noise)
- Enables better AI-assisted PowerApp development
- Eliminates hallucinations by providing real app structure
# Install the dependencies and run the script.
uv sync
# Build Windows executable (pacingest.exe)
pyinstaller --onefile --name pacingest powerapp_tree_generator.py# Template
pacingest "<INPUT_ZIP_OR_MSAPP_PATH>" --template --powerfx --metadata --output "<OUTPUT_FILE>"
# Basic tree
pacingest sample.msapp
# With component type metadata
pacingest sample.msapp --metadata
# With template names
pacingest sample.msapp --template
# With PowerFx expressions (complex data handling Power Fx only)
pacingest sample.msapp --powerfx
# All options combined & Save to file
pacingest sample.msapp --metadata --template --powerfx --output tree.txt
# Works with zip files containing msapp files
pacingest archive.zip --metadata| Option | Description |
|---|---|
path |
Path to .msapp or .zip file (required) |
--metadata |
Show component types and variants |
--template |
Show template names |
--powerfx |
Show complex PowerFx expressions (filters SVG/theme data) |
--output |
Save output to file |
The sample.zip app is sourced from the following URL.
Rijksmuseum Sample App
βββ App [type:appinfo]
β βββ Host [type:hostControl]
βββ Advanced Search [type:screen]
β βββ Image2_1 [type:image]
β βββ ico_Home [type:icon]
β βββ lbl_AdvSearch [type:label]
β βββ SearchBox1_1 [type:cat_PowerCAT.SearchBox]
β βββ lbl_PrincipalMaker [type:label]
β βββ txt_PrincipalMaker [type:text]
β βββ FluentDetailsList1_1 [type:cat_PowerCAT.FluentDetailsList]
β β βββ objectNumber1_1 [type:pcfDataField]
β β βββ longTitle1_1 [type:pcfDataField]
β β βββ headerImage1_1 [type:pcfDataField]
β β βββ Link1_1 [type:pcfDataField]
β β βββ WebURL1_1 [type:pcfDataField]
β βββ lbl_Language [type:label]
β βββ drp_Language [type:dropdown]
β βββ lbl_Century [type:label]
β βββ txt_Century [type:text]
β βββ lbl_ResultsperPage [type:label]
β βββ txt_ResultperPage [type:text]
β βββ btn_SearchCollectionFlow [type:button]
β βββ grp_AdvSearchItems [type:group]
βββ Home [type:screen]
βββ Image2 [type:image]
βββ Pivot1 [type:cat_PowerCAT.Pivot]
βββ SearchBox1 [type:cat_PowerCAT.SearchBox]
βββ FluentDetailsList1 [type:cat_PowerCAT.FluentDetailsList]
βββ objectNumber1 [type:pcfDataField]
βββ principalOrFirstMaker1 [type:pcfDataField]
βββ longTitle1 [type:pcfDataField]
βββ headerImage1 [type:pcfDataField]
βββ Link1 [type:pcfDataField]
βββ WebURL1 [type:pcfDataField]
Expand
Rijksmuseum Sample App
βββ App [type:appinfo]
β fx[OnStart]: Set(
β AppTheme,
β {
β palette: {
β themePrimary: "#FFFFFF",
β themeLighterAlt: "#767676",
β themeLighter: "#a6a6a6",
β themeLight: "#c8c8c8",
β themeTertiary: "#d0d0d0",
β themeSecondary: "#dadada",
β themeDarkAlt: "#eaeaea",
β themeDark: "#f4f4f4",
β themeDarker: "#f8f8f8",
β neutralLighterAlt: "#0b0b0b",
β neutralLighter: "#151515",
β neutralLight: "#252525",
β neutralQuaternaryAlt: "#2f2f2f",
β neutralQuaternary: "#373737",
β neutralTertiaryAlt: "#595959",
β neutralTertiary: "#4d3b1d",
β neutralSecondary: "#99763a",
β neutralPrimaryAlt: "#e0ad55",
β neutralPrimary: "#ffc561",
β neutralDark: "#ffd387",
β black: "#ffdfa6",
β white: "#000000"
β }
β }
β );
β Set(
β AppThemeJson,
β JSON(
β AppTheme,
β JSONFormat.IndentFour
β )
β );
β
β ClearCollect(
β searchCollectionFirst100,
β 'Rijksmuseum(IndependentPublisher)'.GetCollection(
β "nl",
β {
β p: 1,
β ps: 100
β }
β )
β );
β ClearCollect(
β searchCollectionResultTop100,
β AddColumns(
β Ungroup(
β searchCollectionFirst100.artObjects,
β "artObjects"
β ),
β "WebURL",webImage.url,"Link",links.web)
β );
β
β βββ Host [type:hostControl]
βββ Advanced Search [type:screen]
β βββ Image2_1 [type:image]
β βββ ico_Home [type:icon]
β βββ lbl_AdvSearch [type:label]
β βββ SearchBox1_1 [type:cat_PowerCAT.SearchBox]
β βββ lbl_PrincipalMaker [type:label]
β βββ txt_PrincipalMaker [type:text]
β βββ FluentDetailsList1_1 [type:cat_PowerCAT.FluentDetailsList]
β β fx[columns_Items]: Table(
β β {
β β ColDisplayName: "βοΈ Principal/First Maker",
β β ColName: "principalOrFirstMaker",
β β ColResizable: true,
β β ColWidth: 200,
β β ColRowHeader: true
β β },
β β {
β β ColDisplayName: "π’ Object Number",
β β ColName: "objectNumber",
β β ColResizable: true,
β β ColWidth: 150,
β β ColRowHeader: true
β β },
β β {
β β ColDisplayName: "π° Title",
β β ColName: "longTitle",
β β ColBold: true,
β β ColWidth: 300,
β β ColRowHeader: true,
β β ColResizable: true,
β β ColMultiLine: true
β β },
β β {
β β ColDisplayName: "πΌοΈ Image",
β β ColName: "WebURL",
β β ColBold: true,
β β ColWidth: 100,
β β ColRowHeader: true,
β β ColResizable: true,
β β ColCellType: "image",
β β ColImageWidth: 60,
β β ColImagePadding: 6
β β },
β β {
β β ColDisplayName: "πLink",
β β ColName: "Link",
β β ColBold: true,
β β ColWidth: 400,
β β ColRowHeader: true,
β β ColResizable: true,
β β ColCellType: "link",
β β ColMultiLine: true
β β }
β β )
β β fx[Items]: If(
β β Len(SearchBox1_1.SearchText) >= 3,
β β SortByColumns(
β β Search(
β β colAdvSearchTable,
β β SearchBox1_1.SearchText,
β β "principalOrFirstMaker",
β β "longTitle",
β β "objectNumber"
β β ),
β β ctxSortCol,
β β If(
β β ctxSortAsc,
β β SortOrder.Ascending,
β β SortOrder.Descending
β β )
β β ),
β β SortByColumns(
β β colAdvSearchTable,
β β ctxSortCol,
β β If(
β β ctxSortAsc,
β β SortOrder.Ascending,
β β SortOrder.Descending
β β )
β β )
β β )
β β fx[OnChange]: If(Self.EventName="Sort",
β β UpdateContext({
β β ctxSortCol:Self.SortEventColumn,
β β ctxSortAsc:If(Self.SortEventDirection='PowerCAT.FluentDetailsList.SortEventDirection'.Ascending,true,false)
β β })
β β );
β β
β β If(Self.EventName="CellAction", Launch(Self.Selected.Link))
β β βββ objectNumber1_1 [type:pcfDataField]
β β βββ longTitle1_1 [type:pcfDataField]
β β βββ headerImage1_1 [type:pcfDataField]
β β βββ Link1_1 [type:pcfDataField]
β β βββ WebURL1_1 [type:pcfDataField]
β βββ lbl_Language [type:label]
β βββ drp_Language [type:dropdown]
β βββ lbl_Century [type:label]
β βββ txt_Century [type:text]
β βββ lbl_ResultsperPage [type:label]
β βββ txt_ResultperPage [type:text]
β βββ btn_SearchCollectionFlow [type:button]
β β fx[OnSelect]: ClearCollect(
β β colAdvSearch,
β β RijksmuseumSearchCollection.Run(
β β drp_Language.Selected.Value,
β β txt_PrincipalMaker.Text,
β β Value(txt_ResultperPage.Text),
β β Value(txt_Century.Text)
β β )
β β );
β β ClearCollect(
β β colAdvSearchTable,
β β AddColumns(colAdvSearch,
β β "WebURL",webImage.url,"Link",links.web)
β β )
β βββ grp_AdvSearchItems [type:group]
βββ Home [type:screen]
βββ Image2 [type:image]
βββ Pivot1 [type:cat_PowerCAT.Pivot]
β fx[Items]: Table(
β {
β ItemKey: "Home",
β ItemDisplayName: "Home",
β ItemIconName: "Home"
β },
β {
β ItemKey : "SearchCollection",
β ItemDisplayName: "Search Collection",
β ItemIconName: "SearchData"
β }
β )
β fx[OnSelect]: Switch(
β Self.SelectedKey,
β "Home",
β searchCollectionResultTop100,
β "SearchCollection",
β Navigate('Advanced Search',ScreenTransition.Cover)
β )
βββ SearchBox1 [type:cat_PowerCAT.SearchBox]
βββ FluentDetailsList1 [type:cat_PowerCAT.FluentDetailsList]
fx[columns_Items]: Table(
{
ColDisplayName: "βοΈ Principal/First Maker",
ColName: "principalOrFirstMaker",
ColResizable: true,
ColWidth: 200,
ColRowHeader: true
},
{
ColDisplayName: "π’ Object Number",
ColName: "objectNumber",
ColResizable: true,
ColWidth: 150,
ColRowHeader: true
},
{
ColDisplayName: "π° Title",
ColName: "longTitle",
ColBold: true,
ColWidth: 300,
ColRowHeader: true,
ColResizable: true,
ColMultiLine: true
},
{
ColDisplayName: "πΌοΈ Image",
ColName: "WebURL",
ColBold: true,
ColWidth: 100,
ColRowHeader: true,
ColResizable: true,
ColCellType: "image",
ColImageWidth: 60,
ColImagePadding: 6
},
{
ColDisplayName: "πLink",
ColName: "Link",
ColBold: true,
ColWidth: 400,
ColRowHeader: true,
ColResizable: true,
ColCellType: "link",
ColMultiLine: true
}
)
fx[Items]: If(
Len(SearchBox1.SearchText) >= 3,
SortByColumns(
Search(
searchCollectionResultTop100,
SearchBox1.SearchText,
"principalOrFirstMaker",
"longTitle",
"objectNumber"
),
ctxSortCol,
If(
ctxSortAsc,
SortOrder.Ascending,
SortOrder.Descending
)
),
SortByColumns(
searchCollectionResultTop100,
ctxSortCol,
If(
ctxSortAsc,
SortOrder.Ascending,
SortOrder.Descending
)
)
)
fx[OnChange]: If(Self.EventName="Sort",
UpdateContext({
ctxSortCol:Self.SortEventColumn,
ctxSortAsc:If(Self.SortEventDirection='PowerCAT.FluentDetailsList.SortEventDirection'.Ascending,true,false)
})
);
If(Self.EventName="CellAction", Launch(Self.Selected.Link))
βββ objectNumber1 [type:pcfDataField]
βββ principalOrFirstMaker1 [type:pcfDataField]
βββ longTitle1 [type:pcfDataField]
βββ headerImage1 [type:pcfDataField]
βββ Link1 [type:pcfDataField]
βββ WebURL1 [type:pcfDataField]
Future enhancement plan using Model Context Protocol (MCP):
See Power Platform MCP Documentation for integration details.
# Install the CLI globally using the .NET tool install command:
dotnet tool install --global Microsoft.PowerApps.CLI.Tool
# Verify the installation
pac
# Check mcp installation location
pac copilot mcp
# Verify your authentication profiles
pac auth list
pac auth create
pac auth select
pac auth who