Static Sites are Simple

James Brundage | MVP February 24, 2026
Source

Static Sites are simple. They're just files, and mostly text. Here's a PowerShell one-liner to make a really simple static site: "

Hello World

" > ./index.html We make static sites with whatever language we want, and we can publish them about anywhere for free. We can can stick them on https://github.com/. We just create a repository and publish them with GitHub Pages. We can use a free server, like https://neocities.org or https://wisp.place We can find the last server on the planet supporting FTP and put our files up there, too. It's all just copy/paste. There are plenty of frameworks to use, but today let's see how simple it is to make a static site without building a whole framework.
We can use GitHub pages to host our site for free, and we can use PowerShell to deploy it. We only really need two files to get going: One GitHub Workflow One or more scripts The GitHub Workflow Our workflow exists to call our scripts and publish our page. We want to put this file in ./.github/workflows/deploy.yml This is just a standard GitHub pages workflow, with a few bonus points: It runs automatically about once a day, or on demand It maps the published url to $env:page_url It runs a script with the name of the workflow It allows you to set a repository variable with a Google Analytics ID It's pretty carefully documented, but we don't have to read it: we can just copy/paste it into the repo and call it a day. To make this step a bit easier, I've pushed this workflow to: https://poshweb.org/workflows/deploy.yml New-Item -ItemType File -Path ./.github/workflows/deploy.yml -Force -Value ( Invoke-RestMethod https://poshweb.org/workflows/deploy.yml ) Here's the workflow you'll be deploying

Simple workflow for deploying static content to GitHub Pages

name: deploy

on:

Runs on pushes

push:

and run on a schedule

schedule: # for those that don't speak cron, this runs: # * At the first minute (1) # * Every 21st hour (1/21) # * Every day of the year (* * *) - cron: '1 1/21 * * *'

Allows you to run this workflow manually from the Actions tab

workflow_dispatch:

Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages

permissions: contents: read pages: write id-token: write

Allow only one concurrent deployment, and cancel any in-progress deployments if a new one is triggered

concurrency: group: "pages" cancel-in-progress: true

jobs:

GitHub Pages use a single job, named deploy.

deploy: # By using an environment, we avoid locking environment: name: github-pages # and we can control where it is deployed. url: ${{ steps.deployment.outputs.page_url }} runs-on: ubuntu-latest steps: # Check out our repository - name: Checkout uses: actions/checkout@main with: # Using fetch-depth: 0 to ensure we get the full history of the repository fetch-depth: 0 # Setup GitHub Pages - name: Setup Pages uses: actions/configure-pages@main # To Build Pages in PowerShell, we just call a script
- name: Build Pages # set the shell to pwsh shell: pwsh # and then call any script we would like to build the page. # By default, this can use the same name as the workflow # (in this case, just deploy.ps1) run: . "./$env:GITHUB_WORKFLOW.ps1" # This approach makes it easier to logically organize workflow scripts. # We will also map the page_url to an environment variable, so our scripts can access it. env: page_url: ${{ steps.deployment.outputs.page_url }} analytics_id: ${{vars.ANALYTICSID}} - name: Upload artifact uses: actions/upload-pages-artifact@main with: # Upload the contents to the GitHub Pages artifact path: './'
- name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@main The site is built and deployed with .deploy.ps1 The Scripts The scripts can be as complicated or simple as you want them to be. So if we wanted to deploy hello world, all we need is: "

Hello World

" > ./index.html We can certainly style things up a bit. One easy way to do this is to create an array of content, and just output little bits of html. @( # We can just throw html into quotes "" "" "" "" ""

By joining input with newlines, we're treating any pipelined input the same

$allInput -join [Environment]::Newline "

" "" Then we can do something very simply, like convert a README.md into html and pipe it to layout. ConvertFrom-Markdown -Path ./README.md | Select -Expand Html | ./layout > ./index.html Static Sites are simple. This post is designed to get you started, and hopefully help you realize how PowerShell can generate static sites flexibly without a framework. Please, try making some static sites with PowerShell. It's simple and fun.

Discussion in the ATmosphere

Loading comments...