---
title: "Building a Notion PowerShell Module: Part 3"
description: "Learn the next steps of building a PowerShell Notion module in this in-depth PowerShell tutorial by ATA Learning!"
canonical: "https://adamtheautomator.com/notion-powershell-3/"
---

# Building a Notion PowerShell Module: Part 3

> Learn the next steps of building a PowerShell Notion module in this in-depth PowerShell tutorial by ATA Learning!

Source: https://adamtheautomator.com/notion-powershell-3/

---

ATA Learning

Tap to hide

[

ATA Learning

](/)

*   [Home](/)
*   [Tutorials](/tutorials/)
*   [Instructors](/author/)
*   [Advertising](/advertising/)
*   [Recommended Resources](/resources/)
*   [About Adam](/about-adam/)

Search for:  

*   [](https://twitter.com/adbertram)
*   [](https://github.com/Adam-the-Automator)
*   [](https://www.linkedin.com/company/adam-the-automator-llc)
*   [](/feed/)

![Building a Notion PowerShell Module: Part 3](https://adamtheautomator.com/wp-content/uploads/2023/10/Notion-PowerShell.jpg)

# Building a Notion PowerShell Module: Part 3

[![](https://secure.gravatar.com/avatar/f08b754bc0dce1c76685f6afa93185ecfb6f861fd14f993286e06bba69eaeb8b?s=192&d=mm&r=g)Adam Listek](https://adamtheautomator.com/author/alistek/)10 November 20234 min. read

Categories: [IT Ops](/category/it-ops/)

Tags:[PowerShell](/tag/powershell/)

Table of Contents

*   [Prerequisites](#prerequisites)
*   [The Power of Notion Databases](#the-power-of-notion-databases)
*   [Creating a Page](#creating-a-page)
*   [Creating the Database](#creating-the-database)
*   [Creating a Page in the Database](#creating-a-page-in-the-database)
*   [Adding to the Module](#adding-to-the-module)
*   [Next Steps](#next-steps)

Building on the previous two Notion tutorials, you have learned how to create a Notion integration token and retrieve, update, and delete Notion blocks via PowerShell and the Notion API.

Even more powerful are Notion’s Databases. Relational databases help to organize data logically and provide opportunities for analysis. With Notion, store pages within Databases with additional properties. In this tutorial, learn how to create a page, database, and database item. Build upon the Notion PowerShell module to continue expanding functionality.

## Prerequisites

To follow along in this tutorial, you only need a Notion account and [PowerShell](https://learn.microsoft.com/en-us/powershell/scripting/install/installing-powershell-on-windows?view=powershell-7.3); here, PowerShell v7.3.7 is in use.

## The Power of Notion Databases

Though you may think of pages as standalone, within Notion, they are also integral to Databases. Therefore, combining the Page operations with those of Databases helps to understand the linkage. In Notion, Databases may have properties of many different types, such as Selects, Checkboxes, or Numbers.

### Creating a Page

First, you need a place to put the database. To demonstrate this, [create a new page using the `/pages` endpoint](https://developers.notion.com/reference/post-page). The resulting `id` will be the GUID used as the `parent_id` of the new Database.

```powershell
$APIKey     = 'secret_sK5Qir0UAgkLF1iauP5iMsq1vq3YW5S9o5GvF7M8PjK'
$APIURI     = 'https://api.notion.com/v1'
$APIVersion = '2022-06-28'
$GUID       = 'a2b3646d-e941-4df4-874d-56153139b618'

$Params = @{
    "Headers" = @{
        "Authorization"  = "Bearer {0}" -F $APIKey
        "Content-type"   = "application/json"
        "Notion-Version" = "{0}" -F $APIVersion
    }
    "Method"  = 'POST'
    "URI"     = ("{0}/pages" -F $APIURI, [GUID]::new($GUID))
    "Body"    = @{
        "parent" = @{
            "type"    = 'page_id'
            "page_id" = $GUID
        }
        "properties" = @{
            "title" = @(
                @{
                    "text" = @{"content" = "Test" }
                }
            )
        }
        "children" = @()
    } | ConvertTo-JSON -Depth 100
}

$Result = Invoke-RestMethod @Params
```

![Result of creating a new page.](https://adamtheautomator.com/wp-content/uploads/2023/11/image-63.png)

Result of creating a new page.

### Creating the Database

With the page newly created, you will use the `page_id` parent [with the `/databases` endpoint](https://developers.notion.com/reference/create-a-database) to create a new Database with a [single required Title](https://developers.notion.com/reference/page-property-values#title) property. There is a required `title` property that gives the Database its unique name as well.

```powershell
$Params = @{
    "Headers" = @{
        "Authorization"  = "Bearer {0}" -F $APIKey
        "Content-type"   = "application/json"
        "Notion-Version" = "{0}" -F $APIVersion
    }
    "Method"  = 'POST'
    "URI"     = ("{0}/databases" -F $APIURI)
    "Body"    = @{
        "parent" = @{
            "type"    = "page_id"
            "page_id" = $Result.id
        }
        "title" = @(
            @{
                "type" = "text"
                "text" = @{
                  "content" = "Test"
                  "link" = $null
                }
            }
        )
        "properties" = @{
            "Name" = @{
                "type" = "title"
                "title" = @{}
            }
						"Checkbox" = @{
                "type" = "checkbox"
                "checkbox" = @{}
            }
            "Number" = @{
                "type" = "number"
                "number" = @{
                  "format" = "number_with_commas"
                }
            }
        }
    } | ConvertTo-Json -Depth 100
}

$Result = Invoke-RestMethod @Params
```

![Result of creating a new database.](https://adamtheautomator.com/wp-content/uploads/2023/11/image-62.png)

Result of creating a new database.

### Creating a Page in the Database

Finally, to store data within the Database, you must create a new item: a full Notion page. As the page item exists in the database, it has the added benefit of any additional properties. In the example above, you created a [checkbox](https://developers.notion.com/reference/property-object#checkbox) and [number](https://developers.notion.com/reference/property-object#number) property.

```powershell
$Params = @{
    "Headers" = @{
        "Authorization"  = "Bearer {0}" -F $APIKey
        "Content-type"   = "application/json"
        "Notion-Version" = "{0}" -F $APIVersion
    }
    "Method"  = 'POST'
    "URI"     = ("{0}/pages" -F $APIURI)
    "Body"    = @{
        "parent" = @{
            "type"        = "database_id"
            "database_id" = $Result.id
        }
        "properties" = @{
            "Name" = @{
                "title" = @(
                    @{
                        "text" = @{"content" = "This is a Test Task"}
                    }
                )
             }
             "Checkbox" = @{
                "checkbox" = $True
             }
             "Number" = @{
                "number" = 1000
             }
        }
    } | ConvertTo-Json -Depth 100
}

$Result = Invoke-RestMethod @Params
```

![Result of creating a new database item.](https://adamtheautomator.com/wp-content/uploads/2023/11/image-61.png)

Result of creating a new database item.

## Adding to the Module

To round out the module, three new functions will be created. These functions will be:

*   `New-NotionPage`
*   `New-NotionDatabase`

You may wonder why there isn’t a `New-NotionDatabase`. As technically you are calling the same endpoint, `/pages`, for both Databases and Pages, you can extend your `New-NotionPage` function to cover both use cases.

Introduced in this function is the [concept of parameter sets](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_parameter_sets?view=powershell-7.3). Parameter sets offer a way to separate parameters into logical groupings and only allow those that belong together. Defined below is the `DefaultParameterSetName` within the `CmdletBinding` declaration. This gives a default for the function.

It’s necessary to define all the parameter sets each parameter belongs in. If a parameter must be in both, then multiple declarations must be used.

**New-NotionPage**

```powershell
Function New-NotionPage {
    [CmdletBinding(SupportsShouldProcess = $True, DefaultParameterSetName = 'Page')]
  
    Param(
        [String]$APIKey,
        [String]$APIVersion,
        [ValidateScript( { [System.URI]::IsWellFormedUriString( $_ ,[System.UriKind]::Absolute ) } )][String]$APIURI,

        [Parameter(ValueFromPipelineByPropertyName = $True)]
        [Alias("ID")]
        [ValidateScript( { Try { If ( [GUID]::Parse( $_ ) ) { $True } } Catch { $False } } )][String]$GUID,

        [Parameter(Mandatory, ParameterSetName = 'Page')]
        $Title,

        $Content,

        [Parameter(ParameterSetName = 'Database')]
        $Properties,

        [Parameter(ParameterSetName = 'Database')]
        [Switch]$Database
    )
  
    Process {
        $Body = @{
            "parent"     = $Null
            "properties" = $Null
        }

        If ($Database) {
            $Body.properties = $Properties
            $Body.parent = @{
                "type"    = 'database_id'
                "database_id" = [GUID]::New($GUID)
            }
        } Else {
            $Body.parent = @{
                "type"    = 'page_id'
                "page_id" = [GUID]::New($GUID)
            }
            $Body.properties = @{
                "title" = @(
                    @{
                        "text" = @{ "content" = $Title }
                    }
                )
            }          
        }

        If ($Content) {
            $Body.Add("children", $content)
        }

        Write-Verbose ($Body | Out-String)

        $Params = @{
            "Headers" = @{
                "Authorization"  = "Bearer {0}" -F $APIKey
                "Content-type"   = "application/json"
                "Notion-Version" = "{0}" -F $APIVersion
            }
            "Method" = 'POST'
            "URI"    = ("{0}/pages" -F $APIURI)
            "Body"   = $Body | ConvertTo-JSON -Depth 100
        }

        Write-Verbose "[Process] Params: $($Params | Out-String)"

        If ($PSCmdlet.ShouldProcess($GUID,"Adding Page")) {
            Try {
                $Result = Invoke-RestMethod @Params -ErrorAction 'Stop'
            } Catch {
                $Message = ($Error[0].ErrorDetails.Message | ConvertFrom-JSON).message

                Write-Error "Command Failed to Run: $Message"
            }

            If ($Result) {
                $Result
            }
        }
    }
}
```

**New-NotionDatabase**

```powershell
Function New-NotionDatabase {
    [CmdletBinding(SupportsShouldProcess = $True)]
  
    Param(
      [String]$APIKey,
      [String]$APIVersion,
      [ValidateScript( { [System.URI]::IsWellFormedUriString( $_ ,[System.UriKind]::Absolute ) } )][String]$APIURI,
  
      [Parameter(ValueFromPipelineByPropertyName = $True)]
      [Alias("ID")]
      [ValidateScript( { Try { If ( [GUID]::Parse( $_ ) ) { $True } } Catch { $False } } )][String]$GUID,

      [Parameter(Mandatory)]
      $Title,
  
      $Properties
    )
  
    Process {
        $Params = @{
            "Headers" = @{
                "Authorization"  = "Bearer {0}" -F $APIKey
                "Content-type"   = "application/json"
                "Notion-Version" = "{0}" -F $APIVersion
            }
            "Method" = 'POST'
            "URI"    = ("{0}/databases" -F $APIURI)
            "Body"   = @{
                "parent" = @{
                    "type"    = 'page_id'
                    "page_id" = [GUID]::New($GUID)
                }
                "title" = @(
                    @{
                        "type" = "text"
                        "text" = @{
                          "content" = $Title
                          "link" = $Null
                        }
                    }
                )
                "properties" = $Properties
            } | ConvertTo-JSON -Depth 100
        }

        Write-Verbose "[Process] Params: $($Params | Out-String)"

        If ($PSCmdlet.ShouldProcess($GUID,"Adding Database")) {
            Try {
                $Result = Invoke-RestMethod @Params -ErrorAction 'Stop'
            } Catch {
                $Message = ($Error[0].ErrorDetails.Message | ConvertFrom-JSON).message

                Write-Error "Command Failed to Run: $Message"
            }

            If ($Result) {
                $Result
            }
        }
    }
}
```

When run together, you can see the results are the same as if you were to run the individual API calls, but in a more user-friendly nomenclature. By passing in the resulting objects from the previous calls you can simplify creation of child pages and objects.

```powershell
$Parent = 'a2b3646de9414df4874d56153139b618'

$Result = New-NotionPage -GUID $Parent -Title "Database Page"

$Database = New-NotionDatabase -GUID $Result.id -Title "Test Database" -Properties @{
    "Name" = @{
        "type" = "title"
        "title" = @{}
    }
    "Checkbox" = @{
        "type" = "checkbox"
        "checkbox" = @{}
    }
    "Number" = @{
        "type" = "number"
        "number" = @{
          "format" = "number_with_commas"
        }
    }
}

$Item = New-NotionPage -Database -GUID $Database.id -Properties @{
    "Name" = @{
        "title" = @(
            @{
                "text" = @{"content" = "This is a Test Task"}
            }
        )
     }
     "Checkbox" = @{
        "checkbox" = $True
     }
     "Number" = @{
        "number" = 1000
     }
}
```

![New containing page.](https://adamtheautomator.com/wp-content/uploads/2023/11/image-60.png)

New containing page.

![The full-page database.](https://adamtheautomator.com/wp-content/uploads/2023/11/image-59.png)

The full-page database.

![Resulting database with subsequently added item.](https://adamtheautomator.com/wp-content/uploads/2023/11/image-58.png)

Resulting database with subsequently added item.

## Next Steps

The next step is to add a few supporting functions to the module to create stronger typing of available block types and additional usability. The following few articles will wrap up the function and finish creating a usable and full-featured module!

Share this article

[Share on X](https://twitter.com/intent/tweet?url=https%3A%2F%2Fadamtheautomator.com%2Fnotion-powershell-3%2F&text=Building%20a%20Notion%20PowerShell%20Module%3A%20Part%203)[Share on Facebook](https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fadamtheautomator.com%2Fnotion-powershell-3%2F)[Share on LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fadamtheautomator.com%2Fnotion-powershell-3%2F)

## Related Posts

![](https://adamtheautomator.com/wp-content/uploads/publisher/2e05d9c85b2b81feb24af1f04a889143/3eab14af9dabf46fbd333914ce6ccf46f84117d2394d3e7218c186cd249bb7e2.webp)

### [PowerShell or Power Automate: Stop Automation Mistakes](/powershell-vs-power-automate/)

Score six factors to choose between PowerShell and Power Automate: target system, complexity, data volume, team skills, cost, governance.

![](https://adamtheautomator.com/wp-content/uploads/2026/06/26995-troubleshoot-dns-issues-powershell-codex.webp)

### [Troubleshoot DNS Issues with PowerShell](/troubleshoot-dns-issues-powershell/)

Troubleshoot DNS issues with PowerShell by testing name resolution, DNS client settings, cache entries, and network connectivity in a repeatable workflow.

![](https://adamtheautomator.com/wp-content/uploads/2025/10/image_2025-10-24_095322075.png)

### [Migrating from PowerShell 6 to 7.5: Breaking Changes/New Features](/migrating-powershell-6-to-7-5/)

Migrate from PowerShell Core 6 to 7.5: breaking changes, features, and testing tips.

## Categories

*   [IT Ops](/category/it-ops/)
*   [Cloud](/category/cloud/)
*   [DevOps](/category/devops/)
*   [Home Ops](/category/home-ops/)
*   [Information Security](/category/infosec/)
*   [Software Development](/category/software-development/)

## Site

*   [Home](/)
*   [Tutorials](/tutorials/)
*   [Instructors](/author/)
*   [Advertising](/advertising/)
*   [Recommended Resources](/resources/)
*   [About Adam](/about-adam/)

Copyright 2026© ATA Learning | [Privacy Policy](/privacy/)
