Reference¶
From the comment-based help of the module (Get-Help New-UDPivotReport -Full shows the same).
New-UDPivotReport¶
A pivot report builder for PowerShell Universal apps: readers drag fields into rows, columns, values and filters and get a table or a chart, with drill-down, templates and Excel export.
Pass the data as it comes - a DataTable from a SQL query, objects from Invoke-RestMethod or any PowerShell command. Readers build their own report: a field list with search, four zones (Rows, Columns, Values, Filters) with drag and drop and a menu on every field, sums, counts, averages and "show values as", date grouping by year, quarter, month or day, filters with value counts, table or chart (bars, lines, area, pie, heatmap), a click on a value opens the rows behind it, undo and redo, templates, and Excel (XLSX), CSV and PNG export. All of it runs in the browser (pivotkit); the server is only asked for what the event parameters do.
A view - what the report shows - is plain JSON that pivotkit checks against the data; it never
runs as code. -View sets the start view, -Templates the views offered in the Templates menu,
-TemplatePath reads view files from folders, and -TemplateStore keeps readers' own views and the
shared ones (New-UDPivotFileTemplateStore, New-UDPivotTemplateStore) with -AdminRole for who may
change shared views; -OnSaveTemplate and -OnDeleteTemplate stay for full control. Field names are
matched without regard to case.
| Parameter | Type | Description |
|---|---|---|
-Id |
String |
Component id. Default: a new GUID. Get-UDElement -Id returns the current view as .view; Set-UDElement -Id -Properties @{ view = ... } shows another view (one undo step). The browser tab keeps the reader's view under this id; without -Id the report is identified by its page, its place in the app script (line and column of the call) and its column names. Set -Id when one call builds several reports (a loop) or reports are added or removed at run time. |
-Data (required) |
Object |
Rows: a DataTable (Invoke-Sqlcmd, SqlClient, ODBC), DataRows, PSCustomObjects, hashtables or a script block returning them. DBNull becomes an empty value, dates stay dates, TimeSpans become seconds. The column names are the field names the reader sees. |
-View |
Object |
The view the report starts with (and goes back to with Reset): a hashtable or JSON, e.g. @{ rows = @('Team'); cols = @('Priority'); values = @(@{ field = 'Id'; agg = 'count' }) }. Keys: rows, cols (field names), values (field, agg: sum, count, average, min, max, ...; format: a format name), filters, sort, totals, display (table or chart), chart (type: bar, line, area, pie, heatmap). A saved template's view goes in as it is. Default: an empty report with the hint where to start. A view in the address bar (#pivot--NoAddressBar, so a copied link opens the same layout) wins over it. |
-SavedView |
Object |
The reader's own view stored by the app (from -OnViewChange or a "save as my default" action), a hashtable or JSON. A browser tab without a view of its own (in its address bar or its sessionStorage) starts with it; a tab that already shows a view keeps that one, so a view stored for the whole PSU session (shared by all tabs of the browser) never takes over another tab. Reset still goes back to -View. A view that does not pass ConvertFrom-UDPivotView is left out with a warning. |
-Templates |
Object[] |
Views offered in the Views menu (the first three also on the empty report): a list of @{ Name = 'Tickets per team'; View = -OnDeleteTemplate is set). Without Scope a Deletable entry is the reader's own, every other one shared. |
-TemplatePath |
String[] |
Folders of pivotkit view files (*.pivotkit.json, as Download view in the Views menu writes them), read on the server on every render and offered under "Shared views", read-only. Each file is checked (at most 1,000,000 characters, a view ConvertFrom-UDPivotView accepts); a broken one is left out with a warning. A module ships its views with -TemplatePath (Join-Path $PSScriptRoot 'views'). |
-TemplateStore |
Object |
Where readers keep their own views ("My views") and admins the shared ones. Without it nothing is written and Save is not offered (unless -OnSaveTemplate). Browser: pivotkit keeps each reader's views in the browser's localStorage (this browser and device only). A store of New-UDPivotFileTemplateStore (view files in a folder on the server) or New-UDPivotTemplateStore (your own storage: a database, Valkey, S3): the module registers the event handlers, saves a reader's views under their $User, and lets readers with a role of -AdminRole publish and delete shared views - checked on the server with $Roles of each event. In an app without sign-in the server cannot tell readers apart: their own views then stay in the browser, shared views come from the store. |
-AdminRole |
String[] |
Roles ($Roles) that may publish views as shared views and delete shared views (with -TemplateStore, or -OnPublishTemplate), and that see the admin panel under the report (the view as JSON, the columns and their types, timings). |
-UserName |
String |
The signed-in user the page shows views for. Default: $User of the page. Pass $User when the call runs in a script block or function defined in the app script, which does not see it (measured on PSU 2026.2.5 and 2026.3.4). The event handlers use $User of the event. |
-Roles |
String[] |
The roles of the user, for -AdminRole. Default: $Roles of the page; pass $Roles where -UserName has to be passed. |
-SourceId |
String |
The id of the data the report shows, written into view files and links (pivotkit asks before it loads a view made for another id). Default: -Id, or the key the module derives without one. |
-SourceName |
String |
The name of that data for people (in view files and the load check). Default: -Label. |
-SchemaUrl |
String |
The $schema of the view files the report writes: pivotkit's published schema by default, an https address of your own copy, or '' to leave it out. Loading never depends on it. |
-FieldDefaults |
IDictionary |
Per field name, what the report knows about the field: @{ LeadHours = @{ Agg = 'average'; Format = 'number:1'; Label = 'Lead time (h)'; Description = 'Hours from created to resolved'; Href = 'https://wiki.example.org/lead-time' }; Priority = @{ Order = 'Low', 'Normal', 'High' } }. Agg and Format: what the field gets when the reader puts it into Values (format names: number, number:2, integer, percent, percent:1, currency:EUR, compact, bytes, duration:s, duration:h, date, datetime, time); DrillFormat: the format of its values in the drill-down (text shows an id as it is); Label: the name shown for the field everywhere (views keep the field name; at most 120 characters); Description: plain text behind an "i" next to the field, in its menu and on its headers (at most 1000 characters); Href: an https link shown as "Learn more" with the description; Order: the field's own order of items on Rows and Columns; Type: string, number, date or boolean, the type its column is read as. Checked on the server: text only, https links only, sizes capped. |
-FieldDescriptions |
IDictionary |
A description per field name, e.g. from SQL Server column comments (Get-UDPivotSqlColumnDescription): @{ LeadHours = 'Hours from created to resolved' }. A Description in -FieldDefaults wins; empty values, $null and DBNull are left out. |
-Schema |
Object |
A JSON Schema of a row, or an OpenAPI 3 / Swagger 2 document with -SchemaName: a hashtable or object, JSON text, a file path, or an https URL (fetched on the server with a timeout of 15 seconds, at most 1 MB, kept 10 minutes per runspace; the browser never fetches it). The report reads titles (labels), descriptions, externalDocs links (https), types and enums (orders) of the row's properties with pivotkit-core's fieldDefaultsFromSchema; -FieldDefaults and -FieldDescriptions win over it. At most 1 MB and 64 levels. |
-SchemaName |
String |
The schema of a row in an OpenAPI document: a name in components.schemas (definitions in Swagger 2) or a local reference such as #/components/schemas/Ticket. |
-ChartOptions |
Object |
Plain JSON merged over the chart's Apache ECharts option (a hashtable or JSON text, at most 64 KB), e.g. @{ legend = @{ top = 0 }; grid = @{ left = 80 } }; it wins over the view's chart settings. pivotkit leaves out options that are markup or addresses (formatter strings, rich, link, image). |
-Tips |
String[] |
The tips above the result: On (default), Off (none, and no switch in Options), or the ids of the tips allowed (showAs, chartOverTime, pieSlices, pieColumns, chartDates, chartTrend, chartSeries, textValue, dateUngrouped, manyColumns, afterDrag, values, saveTemplate, menus, cells; the notices filterEmpty, top and chartCapped always show). Dismissed tips are remembered per report in the browser's localStorage. |
-FieldInfo |
String |
On or Off: the "i" with the field descriptions. Without it the reader switches it in Options. |
-ZoneInfo |
String |
On or Off: the "i" next to the zone titles that explains each zone. Without it the reader switches it in Options. |
-SettingInfo |
String |
On or Off: the "i" next to settings that need explaining (totals, Show as, export formats, chart labels). Without it the reader switches it ("Show explanations" in Options, Help). |
-FieldList |
String |
Open or Collapsed: how the field list starts on a wide report (collapsed: a rail of about 40 pixels). Without it the reader's last choice decides. |
-Grow |
String |
On or Off: whether the report grows past -Height to keep its result readable (the page scrolls) or stays inside it (the table scrolls). Default: Off, since the report always has a height; a card of a fixed size keeps the whole report. |
-Label |
String |
The name screen readers hear for the report (its region landmark). Several reports on one page need one name each. Default: "Pivot report". |
-Labels |
Hashtable |
Single texts of the report in your own words, merged over the language -Locale picked: @{ zones = @{ values = 'Kennzahlen' }; core = @{ grandTotal = 'Summe' } }. The keys are the ones of pivotkit-react's LABELS. |
-Locale |
String |
Language and formats: numbers, dates and sorting, and the labels (de-* German, others English). Default: en-US. The report never uses the browser's or the server's locale on its own, so a report looks the same for every reader; pass de-DE for German. |
-TimeZone |
String |
The zone dates with an offset (DateTimeOffset, a DateTime of kind Local or Utc) are shown in, as an IANA name (Europe/Berlin) or UTC. Dates without an offset - what SQL returns for datetime columns - are shown as they are. Default: the server's time zone. |
-Theme |
String |
Auto (follows the app's light/dark switch, default), Light or Dark. |
-Height |
String |
Height of the report, e.g. 640px, 80vh or 640 (pixels); the table and the field list scroll inside it. Default: one screen, the window's height minus 180 pixels for PSU's app bar and a page title, between 600 and 1400 pixels, so the whole report is on screen when the page loads; in a window narrower than 640 pixels (a phone) almost the whole window, since the zones stack above the table there. |
-FileName |
String |
Name of exported files without the extension. Default: pivot. |
-NoAddressBar |
SwitchParameter |
Keeps the reader's view out of the address bar; the browser tab then keeps it in sessionStorage only (a reload and the light/dark switch still keep it, a copied link does not carry it). By default the view, filter values included, is written into the address (#pivot- |
-NoDrillDown |
SwitchParameter |
No panel with the source rows when a value is clicked (-OnCellClick still runs). |
-ClassName |
String |
CSS class of the outer element. |
-Style |
Hashtable |
CSS styles of the outer element, e.g. @{ maxWidth = '1200px' }. |
-OnViewChange |
Endpoint |
Runs on the server after the reader changed the view (once the reader paused for 0.6 seconds). $EventData: view (the view as an object), json (the same as JSON text, to store). |
-OnCellClick |
Endpoint |
Runs on the server when the reader clicks a value or a chart point. $EventData: row, col (the key paths), rowFields, colFields, filter (one @{ field; value } per level, rows first), valueField, value, text (as shown), count (source rows behind the value) and rows (the first 100 of them). |
-OnSaveTemplate |
Endpoint |
Shows Save as (and Save on a loaded view of the reader's own) in the Views menu and runs when the reader saves. $EventData: name, view, json, scope (user). Save and a confirmed Save as send a name the reader's views already have: replace that view (an upsert by name, the same characters in the same case), never add a second one. The template appears in the menu (deletable) once the script block finished without an error; throw, or return @{ error = 'message' }, to refuse - the reader sees the message. |
-OnDeleteTemplate |
Endpoint |
Runs when the reader deletes a deletable template (after confirming in the menu). $EventData: name, scope (user or shared). Throw, or return @{ error = 'message' }, to refuse. |
-OnPublishTemplate |
Endpoint |
With -AdminRole: "Publish as shared view" on the reader's own views and Save on a shared view, for readers with one of the roles. $EventData: name, view, json. A name the shared views have replaces that view (an upsert by name). Check $Roles in it again: the browser only hides the button. |
New-UDPivotReportPlaceholder¶
A placeholder in the pivot report's own look, for New-UDDynamic -LoadingComponent: it shows the report's frame while the server builds the data.
PSU renders a component only once its properties have arrived, and the report's properties hold
all of its rows: with thousands of rows the page stays empty until the server has converted and
sent them. Put the report into New-UDDynamic and this placeholder into its -LoadingComponent:
New-UDDynamic `-Id` 'tickets-report' `-LoadingComponent` {
New-UDPivotReportPlaceholder `-Height` 640px
} `-Content` {
New-UDPivotReport `-Id` 'tickets' `-Data` $tickets `-Height` 640px
}
The placeholder comes with the page and shows pivotkit's own skeleton of the report: the field list, the toolbar, the zones and table rows as grey bars, in the report's colours (light, dark, a corporate design from the app's stylesheet); the bars pulse unless the reader asked for reduced motion. Screen readers hear "Loading the report". It also makes the browser load the module's code at once, while the server is still working on the data.
Give it the -Height, -Theme, -Locale and -Label of the report, so nothing moves when the report
replaces it.
| Parameter | Type | Description |
|---|---|---|
-Id |
String |
Component id. Default: a new GUID. |
-Height |
String |
Height, as -Height of New-UDPivotReport (e.g. 640px, 80vh or 640). Default: the report's default height. |
-Theme |
String |
Auto (follows the app's light/dark switch, default), Light or Dark. |
-Locale |
String |
The language of the text screen readers hear: German for de-*, English otherwise. Default: en-US. |
-Label |
String |
The name screen readers hear for it, as -Label of the report. |
-ClassName |
String |
CSS class of the outer element. |
-Style |
Hashtable |
CSS styles of the outer element, e.g. @{ maxWidth = '1200px' }. |
ConvertFrom-UDPivotView¶
Checks a pivot view (a report layout) and returns it as a clean object or as compact JSON.
A view is the report as JSON: the fields on Rows, Columns, Values and Filters, sorting, totals,
the chart. Views come from the browser ($EventData of -OnViewChange and -OnSaveTemplate), from
files or from a database, so treat them as untrusted input: this function is the check before
a view is stored or used.
It accepts a JSON string, a hashtable or a PSCustomObject. The view goes through one round trip
ConvertTo-Json/ConvertFrom-Json (nothing is evaluated) and must be a JSON object of at most
-MaxLength characters and at most eight levels deep. Only the keys of a pivotkit view are kept
(version, rows, cols, values, filters, derived, sort, totals, collapsed, display, chart,
formatting); rows and cols must be lists of at most 64 field names, values, filters, derived and
sort lists of at most 64 objects, display "table" or "chart". Anything else throws an error that
says what is wrong. The report itself checks every field name and setting against the data
again (pivotkit-core's normalize) and drops what does not fit.
| Parameter | Type | Description |
|---|---|---|
-InputObject (required) |
Object |
The view: a JSON string, a hashtable or a PSCustomObject (e.g. $EventData.view). |
-MaxLength |
Int32 |
The longest view accepted, in characters of compact JSON. Default: 65536. |
-AsJson |
SwitchParameter |
Return the view as compact JSON (for a file or a database column) instead of an object. |
ConvertFrom-UDPivotViewFile¶
Reads a pivotkit view file (or a saved view { name, view }) and returns its name, description, source and checked view.
A view file is the JSON pivotkit's Views menu downloads (Download view, Copy view as JSON) and a
template store keeps: format "pivotkit-view", formatVersion 1, name, description, source and the
view. This function reads one as untrusted input: at most 1,000,000 characters and 16 levels,
parsed without evaluating anything; a newer formatVersion or view version is refused (saving it
again would lose what the newer version added); the name becomes plain text of 1 to 120
characters; the view goes through ConvertFrom-UDPivotView. An object { name, view } (a saved view
as an app keeps it) is read as well; a bare view needs -Name.
| Parameter | Type | Description |
|---|---|---|
-InputObject (required) |
Object |
The view file: JSON text, a hashtable or an object. |
-Name |
String |
The name of a view file that has none (a bare view), such as the file's name. |
ConvertTo-UDPivotViewFile¶
A view as a pivotkit view file: the JSON pivotkit's Views menu loads and a template store keeps.
Checks the view with ConvertFrom-UDPivotView and writes the envelope in pivotkit's key order ($schema, format, formatVersion, name, description, createdAt, generator, source, extensions, view) with a two-space indent and a trailing newline.
| Parameter | Type | Description |
|---|---|---|
-View (required) |
Object |
The view (JSON text, a hashtable or an object). |
-Name (required) |
String |
The view's name (1 to 120 characters of plain text). |
-Description |
String |
More about it, at most 2000 characters. |
-SourceId |
String |
The id of the data the view was made for (New-UDPivotReport -SourceId, default its -Id). |
-SourceName |
String |
The name of that data, for people. |
-SchemaUrl |
String |
The $schema of the file: pivotkit's schema by default, your own copy, or '' to leave it out. |
-CreatedAt |
Nullable1` |
When it was written (UTC). Without it the file is the same bytes for the same view. |
New-UDPivotFileTemplateStore¶
A template store that keeps the readers' views as view files in a folder on the server.
For New-UDPivotReport -TemplateStore. Every signed-in reader saves views under "My views" and sees
them on every device; views in the shared folder are listed for everyone under "Shared views",
and only readers with a role of New-UDPivotReport -AdminRole publish or delete them.
Layout below -Path: users/-TemplatePath). Writes go to a new file that then
replaces the old one, under a lock per folder, so two saves at the same moment never leave half a
file or lose the count. -MaxUserViews and -MaxSharedViews cap the number of views per folder.
Without -Path the store lies next to the PSU repository ($Repository), never inside it: a
repository synced with git would pick the files up. On several PSU nodes (high availability) a
local folder is per node: use a shared folder, or a store on a database
(New-UDPivotTemplateStore).
| Parameter | Type | Description |
|---|---|---|
-Path |
String |
The folder. Default: pivot-views next to the repository folder ($Repository of the app, else $env:Data__RepositoryPath). |
-MaxUserViews |
Int32 |
The most views a reader keeps. Default: 50. |
-MaxSharedViews |
Int32 |
The most shared views. Default: 200. |
New-UDPivotTemplateStore¶
A template store on your own storage (a database, Valkey or Redis, S3): you write how a view is stored, the module does the rest.
For New-UDPivotReport -TemplateStore. The module decides who may do what (the signed-in user,
-AdminRole for shared views, checked on the server), checks every name and view, applies the
limits and writes the view file; the script blocks only store and load. Each gets one argument,
$Request:
- Get: Scope ('user' or 'shared'), User (the user name; $null for shared), UserKey (a hash of the user name, safe in a key or file name). Return the stored views: view file texts (the Json of a save), objects with Json and FileName (where it is stored), or objects with Name and View. The module checks each one again.
- Save: Scope, User, UserKey, Name (checked), FileName, Key ('users/
/ ' or 'shared/ '), Json (the view file to store) and View (the checked view). Store it under FileName, replacing what is there: for a name the scope has (the same characters in the same case, as pivotkit compares names) the module passes the FileName of that view, so a save replaces it; for a new name - .pivotkit.json that no stored view has. - Delete: Scope, User, UserKey, Name, FileName, Key.
- Publish (optional): as Save with Scope 'shared' and User the publisher. Without it, publishing calls Save with Scope 'shared'.
Throw to refuse: the reader sees the message. The script blocks run in the runspace of the app script that defined them and do not see $User or $Roles: use $Request. PSU runs event handlers in runspaces of their own, so a script block needs every module and variable it uses (Import-Module inside it).
| Parameter | Type | Description |
|---|---|---|
-Get (required) |
ScriptBlock |
Returns the views of one scope (and user). |
-Save (required) |
ScriptBlock |
Stores one view. |
-Delete (required) |
ScriptBlock |
Removes one view. |
-Publish |
ScriptBlock |
Stores a shared view, when that differs from Save with Scope 'shared'. |
-MaxUserViews |
Int32 |
The most views a reader keeps. Default: 50. |
-MaxSharedViews |
Int32 |
The most shared views. Default: 200. |
Invoke-UDPivotTemplateRequest¶
Saves, publishes or deletes a view for the report's event handlers; decides on the server who may do it.
New-UDPivotReport -TemplateStore registers event handlers that call this function with the
$EventData of the report and the $User and $Roles PSU sets for the event. A reader saves and
deletes their own views; publishing and deleting shared views needs a role of -AdminRole, checked
here with the event's $Roles - never with anything the browser sends. Returns nothing on success,
@{ error = '...' } when it refuses (the report shows the text).
| Parameter | Type | Description |
|---|---|---|
-Key (required) |
String |
The key of the report's store (Register-UDPivotTemplateStore). |
-Action (required) |
String |
Save, Publish or Delete. |
-EventData |
Object |
The report's $EventData: name, view, scope. |
-UserName |
String |
$User of the event. |
-Roles |
String[] |
$Roles of the event. |
Get-UDPivotSqlColumnDescription¶
The column descriptions of a SQL Server table or view (extended property MS_Description), as the hashtable -FieldDescriptions of New-UDPivotReport takes.
Reads sys.extended_properties for the columns of one table or view (class 1, major_id the object, minor_id the column) with the property name MS_Description - what SQL Server Management Studio writes as a column's Description - and returns column name to text, in column order. Columns without a description are left out.
Pass an open connection (-Connection: System.Data.SqlClient, Microsoft.Data.SqlClient or any
ADO.NET connection to SQL Server; it stays open) or a connection string (-ConnectionString: the
function opens and closes a connection with Microsoft.Data.SqlClient when that is loaded, for
example by the SqlServer module, else with System.Data.SqlClient, which PowerShell 7 ships).
The table name goes to SQL Server as a parameter of OBJECT_ID(), never into the query text. The
account sees only the descriptions of objects it has permissions on; an unknown table gives an
empty result.
| Parameter | Type | Description |
|---|---|---|
-Connection (required) |
IDbConnection |
An open ADO.NET connection to the database that holds the table. |
-ConnectionString (required) |
String |
A connection string to the database that holds the table. |
-Table (required) |
String |
The table or view, as OBJECT_ID() takes it: dbo.Tickets, [sales].[Order Lines] or Tickets (the user's default schema). |
-PropertyName |
String |
The extended property to read. Default: MS_Description. |
-TimeoutSec |
Int32 |
Command timeout in seconds. Default: 30. |