Skip to content
Kamil Nowinski edited this page Jul 26, 2025 · 24 revisions

This documentation is based on the solid foundation of the dbatools project and is intended to provide a consistent and maintainable approach to developing and contributing to the FabricTools PowerShell module. The standards outlined here are subject to change as the project evolves, and contributions are welcome to help improve and refine these practices.

Standards for FabricTools

This document outlines the standards and practices for contributing to the FabricTools PowerShell module. It is intended to ensure consistency, maintainability, and quality across the codebase.

There are MANY things that are not currently consistent across the module at the current time. This document contains the standards for the expected state and shall be used as the guidance for future development and contributions.

Important

Having said that, we do not expect you to follow (as of now) any guidance listed below and marked with 🔒 icon.

In general, if not specified here the standards will follow the Powershell Community Standards as outlined in the PowerShell and Best Practice Style Guide as the guideline for the code. If not specified there then the PowerShell documentation shall be taken as the standard.

Do Nots

  1. Do not depend on or incorporate commands from external modules unless you have explicit permissions/approval (via an issue) from the module owner.
  2. Do not use the built-in write output commands (e.g. Write-Output, Write-Host, Write-Verbose). Use Write-Message private cmdlet which uses the PSFramework module for logging and outputting messages.
  3. Do not use any backticks for line continuation.
  4. Do not return an error, a warning or any information message if there is nothing to return. For example - Get-FabricLakehouse should not return an error if there are no lakehouses, it should just return nothing. Get-FabricLakehouse -lakehouseName 'MyLakehouse' should not return anything if a Lakehouse does not exist.
  5. Do not use return in the code. The last line of the function will be returned automatically.
  6. Do not use aliases in the code. All function calls should use the full function name. This is to ensure that the code is readable and understandable by all users, and also to avoid any confusion with other aliases that may be defined in the user's environment.

Naming Convention

Identifier type Rules for naming Example
Commands (Advanced Functions) {Approved verb}-{singular nouns} UpperCamelCase Get-FabricWorkspace
Parameters UpperCamelCase [guid] $WorkspaceId
Variables lowerCamelCase $apiEndpointUrl = 'url'
Constants SCREAMING_SNAKE_CASE int MAX_COUNT = 10

Commands

Naming Convention: UpperCamelCase

Verb

We only utilize the approved verbs in PowerShell. For a list of approved verbs the cmdlet Get-Verb will list them.

Noun

On the noun side it can be composed of more than one joined word using Pascal Case (aka Upper Camel Case) and only singular nouns. The noun part should be singular and descriptive of what the cmdlet operates on. It should be specific enough to understand its purpose but not overly complex.
All of our public commands (aka Advanced Functions) have the Fabric prefix on the noun and are singular in name.

Parameters

Naming Convention: UpperCamelCase

Parameters, referring to inputs for the commands, are to use camel caps where each word is capitalized (e.g. SqlInstance).

Unless circumstances dictate otherwise any command should support multiple objects being passed as input and support piping.

ℹ️ This is a work in progress, and we are still working on the piping support.

Mandatory should only be specified on the parameter if it is being set $true, since $false is the default.

When a command requires a Workspace, the parameter should be named Workspace and should accept multiple workspaces.

When a command requires a resource name, the parameter should be named Name and should accept multiple names. The parameter should also support piping from other commands that return that resource type eg Set-FabricLakehouse should accept piping from Get-FabricLakehouse.

When a command requires an ID, the parameter should be named Id and should accept multiple IDs. The parameter should also support piping from other commands that return that resource type (e.g. Get-FabricLakehouse).

ℹ️ This is a work in progress, and we are still working on the piping support.

The exception to these rules are when there are greater than one resource type. In this scenario, the parameter Name shall be used for the resource first in the function name and all other parameters shall be named ResourceTypeName (e.g. LakehouseName, WarehouseName, DataPipelineName, etc.). The same rules apply for the parameter Id.

ℹ️ This is a work in progress, and we are still working on the piping support.

Variables

Naming Convention: lowerCamelCase

When referencing the parameters/inputs within code they should use the camel caps (e.g. $Lakehouses) but other processing variables should utilize camel casing such as $lakehouseName.

Documentation

This refers to the Comment-Based Help (CBH) that is required for each command. All public commands in the module are required to have CBH (we test for this in PR processing). It requires to be function name in the first line of each function file, before CBH section.
The documentation should be complete and at a minimum include the following sections for CBH (some will repeat):

function New-FabricWorkspace
{
<#
.SYNOPSIS
    Short description of the function.

.DESCRIPTION
    This section should be more descriptive and longer than above one.

.PARAMETER
    This will be one for each parameter input the command utilizes

.NOTES
    Tags: SqlDatabase, deployment
    Author: First LastName (@twitterHandle), YourWebSite.net

    Website: https://fabrictools.io
    Copyright: (c) 2025 by FabricTools, licensed under MIT
    License: MIT https://opensource.org/licenses/MIT

.EXAMPLE
#>

// Code here

}

The NOTES section will be required to contain the website, copyright and license information as well as the Initial author and changelog.

TODO: Ensure that there can be a LINK section for the help.

Examples

The examples provide a way for users to see how the command can be used for various scenarios or combinations of parameters/inputs. A good start of examples to provide are given below:

  • Splatting (when needed)
  • Piping input from other commands (e.g. Get-FabricNoun ... | Set-FabricNoun ...)
  • Passing in multiple values to a given parameter (where supported)
  • Outputting only certain properties, or otherwise manipulating output for a certain purpose
  • All strings should be enclosed in single quotes unless there is a need for variable expansion or special characters, in which case string formatting should be used.

Examples Formatting

The format of the examples should include a view as if you are on an interactive prompt running the command. So a sample where you may have multiple calls:

    <#
    .EXAMPLE
        $data = Get-FabricNoun -WorkspaceId 'guid' ....
        $data | Set-FabricNoun ...
    #>

Where you may do a multi-line call on the command line you will include the >> just as the PowerShell prompt would:

    <#
    .EXAMPLE
        PS C:\> $files = Get-ChildItem C:\temp
        PS C:\> foreach ($f in $files) {
        >> Verb-FabricNoun -WorkspaceId 'guid' -Name $f ....
        >> }
    #>

If an example uses more than two/three parameters, or if including all parameters in a single line would make the example difficult to read, the parameters should be presented in a splatting format. Splatting involves creating a hash table of parameters and passing it to the command using the @ symbol. This improves readability and maintainability of the examples.

    <#
    .EXAMPLE
        Verb-FabricNoun -WorkspaceId 'guid' -Name $objectName 
    
    .EXAMPLE
        $params = @{
          Workspace = 'WorkspaceName'
          SetId     = 'xxxx-yyyy'
          Format    = 'json'
          }
        Verb-FabricNoun @params
    #>

If only one or two parameters are used and the example remains clear and concise, parameters may be specified directly in the command line.

Function Code

The code for the function should be formatted in a way that is easy to read and understand.
The following are some guidelines for formatting the code:

  1. Use 4 spaces for indentation (no tabs).
  2. Formatting strings: both "$value" and "{0}" -f $value are allowed to be used.

Begin/Process/End Blocks

  1. Use the Begin, Process, and End blocks to separate the code into logical sections as defined in Input processing methods.
  2. Each public function should execute Confirm-TokenState at the beginning.
  3. Every new public function which accept -WorkspaceId parameter, should also handle pipeline for workspaces.

Execute API

Each public function must use Invoke-FabricRestMethod to communicate with Fabric or Power BI api endpoint and retrieve outcome to $response variable. Please bear in mind:

  1. GET is optional and defult parameter for Method, however we recommend to provide it for readability.
  2. Do not use backticks to create multiline parameters:
    # DO NOT use backticks (`) moving forward:

    $response = Invoke-FabricRestMethod `
        -Uri $apiEndpointUrl `
        -Method Post

We will gradually remove such code when changes to a function's logic are needed.

  1. For readability and to avoid small mistakes - we ask to use splatting:
    $apiParams = @{
        Uri    = $apiEndpointUrl
        Method = 'Post'
        Body   = $bodyJson
    }
    $response = Invoke-FabricRestMethod @apiParams

Splatting is mandatory for executing Invoke-FabricRestMethod function only, not everywhere.

Validate response

Function Invoke-FabricRestMethod sets additional variables (script scope) when receiving the API response. They are:

  • $script:statusCode = $statusCode
  • $script:responseHeader = $responseHeader

Try to use them for read-only purposes.
Validate block must validate the response. Sometimes only statusCode = 200 is expected, in other cases a function can return more codes. All documented codes should be handle appropriately.

Since July 2025, the private function (Test-FabricApiResponse) is developed to handle all returned codes for you. The function is executed when param HandleResponse is set to $true for backward compatibility. There is no longer a need to handle response separately in public function code, unless there is a specific reason to do so.

Old version of code

Warning

Do not apply this pattern for new functions.

    if ($PSCmdlet.ShouldProcess($apiEndpointUrl, "Delete Workspace"))
    {
        # Step 3: Make the API request
        $response = Invoke-FabricRestMethod `
            -Uri $apiEndpointUrl `
            -Method Delete
    }

    # Step 4: Validate the response code
    if ($statusCode -ne 200)
    {
        Write-Message -Message "Unexpected response code: $statusCode from the API." -Level Error
        Write-Message -Message "Error: $($response.message)" -Level Error
        Write-Message "Error Code: $($response.errorCode)" -Level Error
        return $null
    }

    Write-Message -Message "Workspace '$WorkspaceId' deleted successfully!" -Level Info
    return $null

New version of code

Using Invoke-FabricRestMethod with HandleResponse supports the following features:

  • Call API
  • Handles Status Code from a response (200, 201, 202)
  • Supports LRO (Long-Running Operations) - code 202
  • Pagination (automatically detected when continuation token exists in api response)
  • Standard messages (this feature is being tested)

Note

Use this pattern for any new function.

    # Step: Make the API request & validate response
    if ($PSCmdlet.ShouldProcess($apiEndpointUrl, "Delete Deployment Pipeline"))
    {
        $apiParameters = @{
            Uri = $apiEndpointUrl
            Method = 'DELETE'
            HandleResponse = $true
            TypeName = "deployment pipeline"
            ObjectIdOrName = $DeploymentPipelineId
        }
        $response = Invoke-FabricRestMethod @apiParameters
    }

    # Step: Handle results
    $response

New functions with LRO on API will implement NoWait switch parameter that enables user to avoid waiting for response when not needed. Take a look at this example: New-FabricSQLDatabase.ps1

Pagination and adding data to response

When pagination is available for an API function, it is strongly recommended to implement correct handling of the paginated response (i.e., handling $continuationToken) to ensure all data is retrieved:

ℹ️ There are few blocks of code needed to handle pagination. For an example - please take a look at code from Get-FabricEventhouse function.

🔒 Handle results and return

Avoid using the return keyword in your functions. Just place the object variable on its own.

TODO. We need an agreement for new functions.
Currently it looks like below:

    # Step 9: Handle results
    if ($eventhouse) {
        Write-Message -Message "Eventhouse found in the Workspace '$WorkspaceId'." -Level Debug
        return $eventhouse
    } else {
        Write-Message -Message "No Eventhouse found matching the provided criteria." -Level Warning
        return $null
    }

ℹ️ The above example comes from Get-FabricEventhouse function.

Default View

Aliases

Function and Parameter aliases must be kept for at least two major versions to ensure that backward compatibility is maintained. However, new commands should not have aliases created for them.

🔒 KN: Can we introduce this since version 1.0, as the module is new and has never been promoted as production-ready?

Input Parameters & Alias Naming Conventions

a. WorkspaceId - Alias: 'Id' is permitted only if there are no other parameters named 'Id' to prevent ambiguity.
b. WorkspaceName - Alias: 'Name' is permitted only if there are no other parameters named 'Name'.
c. DisplayName - Alias: 'Name' is allowed only in New or Update functions.
d. Description - No alias allowed; use full parameter name.

Note

Always use the full parameter name as the primary identifier.
Aliases should only be introduced when necessary and safe to avoid confusion or coding mistakes.

Alias Example

This is OK:

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [Alias("Id")]
        [guid]$WorkspaceId,

        [Parameter(Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [string]$WorkspaceName
    )

In this case, the Id alias is not allowed:

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [guid]$WorkspaceId,

        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [guid]$LakehouseId
    )

Output

Each public function should return the result from API.
Ideally, the result should be return like-to-like, with exceptions when:

  1. Result contains "value" element as a wrapper for the major data - value should be return.
  2. 🔒 Error details should be return when error returned from API. By default it contains the following columns: x, y, z
  3. 🔒 If the API response includes properties with nested objects or arrays, and the user specifies the -Explode switch parameter, the function should flatten (unfold) these nested structures into separate objects or properties for easier consumption.

Example

Suppose the API returns the following response:

{
  "value": [
    {
      "Id": "1",
      "Name": "Item1",
      "Details": {
        "Type": "A",
        "Status": "Active"
      }
    },
    {
      "Id": "2",
      "Name": "Item2",
      "Details": {
        "Type": "B",
        "Status": "Inactive"
      }
    }
  ]
}

With the -Explode switch, the function should output:

Id Name Type Status
1 Item1 A Active
2 Item2 B Inactive

OutputType

There should be an OutputType attribute on the function to indicate what type of object is returned by the command. This is important for users to know what to expect when using the command and for PowerShell to provide IntelliSense and other features.

Try / Catch / Finally

Use try/catch/finally blocks to handle errors and exceptions in the code. This is important for ensuring that the code is robust and can handle unexpected situations gracefully. Do not use try/catch for code logic or workflow control. Use it only for error handling.

PSFramework

🔒 Note: This is a work in progress, and we are still working on the PSFramework integration.
Use the PSFramework module for configuration, logging and outputting messages. This is important for ensuring that the code is consistent and can be easily maintained. The PSFramework module provides a consistent way to log messages and output information, and it also provides a way to configure the logging behavior and enables logging to a number of different targets (e.g. file, event log, database, KQL etc.).

TODO: Example of usage

Remove- functions

Always use CmdletBinding attribute.

Any public (advanced) function that removes resources (i.e., functions with the Remove- verb) must implement the following pattern to ensure safe and user-confirmed operations:

[CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')]

This ensures that the function supports PowerShell's -WhatIf and -Confirm parameters, allowing users to preview changes and require confirmation before performing high-impact actions. Setting ConfirmImpact = 'High' prompts for confirmation by default, which is appropriate for operations that delete or remove resources.

ℹ️ For example: Remove-FabricEventstream function.

FabricTools

Unfold the pages links above to navigate the Wiki.

Coding Standards

GitHub and Git

Clone this wiki locally