Spreading Christmas Cheer with PowerShell

Spreading Christmas Cheer with PowerShell

Most people use PowerShell for automation, reporting, or fixing things that are broken. This year, I decided to use it for something slightly different — spreading a bit of Christmas cheer across the office.

What started as a simple “let’s make some snow fall on the screen” quickly turned into a full festive animation running across every monitor. Snow, stars, baubles, falling gifts, Christmas trees, a big Santa face in the middle of the screen, and even a live countdown before it closes on its own. All written in PowerShell.

Why I Built It

IT can be non-stop in December. Patching, deployments, year-end changes, audits and last-minute requests all stack up. I thought it would be nice to break the routine for a moment and give the team something unexpected to smile at.

Instead of another wallpaper change or email, I wanted something that felt alive on screen — something interactive, loud and unapologetically Christmas.

PowerShell turned out to be the perfect tool for exactly that.

What the Script Does

This script launches a transparent, full-screen festive overlay across every connected monitor. It includes:

  • Falling snow, stars, gifts and baubles

  • Rows of animated Christmas trees

  • A large Santa face in the centre of each screen

  • “Merry Christmas” displayed in gold across the middle

  • A live countdown timer

  • Automatic clean exit after 30 seconds

Everything runs directly from PowerShell using Windows Forms and GDI+ drawing — no external files, no images, no media downloads.

Why PowerShell Is Perfect for This

PowerShell isn’t just for admin tasks. Because it sits on top of the full .NET framework, you can create:

  • Graphical interfaces

  • Animated overlays

  • Real-time visual effects

  • Full screen applications

And you can do it all in a single script file that runs instantly on any Windows PC.

This project is a great reminder that PowerShell doesn’t always have to be serious. Sometimes it’s allowed to be fun.

Sharing a Bit of Christmas Spirit

I ran this quietly on a few screens in the office and waited. The reactions ranged from confusion to laughter to “How on earth did you do that with PowerShell?”

That alone made it worth it.

IT teams rarely get time to stop and enjoy moments like that. If a 30-second Santa animation helps lighten the mood in a busy December, then it has done its job.

Final Thoughts

PowerShell is an incredibly powerful tool, but it’s also a creative one if you let it be. If you normally only use it for automation and fixes, try pushing it a bit further. You might surprise yourself with what it can do.

And more importantly — have some fun with it.

Merry Christmas from Digital Geekery.

The Code

<#
.SYNOPSIS
Displays a full-screen multi-monitor Christmas animation using PowerShell.

.DESCRIPTION
This script creates a festive animated overlay across all connected monitors.
It includes falling snow, stars, gifts, and baubles, animated Christmas trees,
a large central Santa face, Merry Christmas text, and a live countdown timer.
The animation automatically closes after 30 seconds.

.AUTHOR
DIGITALGEEKERY

.VERSION
1.0

.NOTES
- Designed for Windows 10 / Windows 11.
- Requires .NET Framework with Windows Forms support.
- Runs safely in user context.
- Ideal for festive fun, demos, or seasonal IT morale boosters.

.EXAMPLE
powershell.exe -ExecutionPolicy Bypass -File .\Christmas-PowerShell.ps1

#>

Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing

Add-Type -ReferencedAssemblies "System.Windows.Forms","System.Drawing" @"
using System;
using System.Windows.Forms;

public class DoubleBufferedForm : Form
{
public DoubleBufferedForm()
{
this.SetStyle(ControlStyles.AllPaintingInWmPaint |
ControlStyles.UserPaint |
ControlStyles.OptimizedDoubleBuffer, true);
this.UpdateStyles();
}
}
"@

$rand = New-Object System.Random
$script:secondsLeft = 30
$script:lastSecondTick = [Environment]::TickCount

$forms = @()

foreach ($screen in [System.Windows.Forms.Screen]::AllScreens) {

$form = New-Object DoubleBufferedForm
$form.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::None
$form.Bounds = $screen.Bounds
$form.TopMost = $true
$form.BackColor = [System.Drawing.Color]::Black
$form.TransparencyKey = $form.BackColor
$form.ShowInTaskbar = $false

$flakes = @()
$ground = @{}

for ($i = 0; $i -lt 600; $i++) {

$type = $rand.Next(1, 5)
$icon = "snow"
$color = [System.Drawing.Color]::White

switch ($type) {
2 { $icon = "star"; $color = [System.Drawing.Color]::Gold }
3 { $icon = "gift"; $color = [System.Drawing.Color]::Red }
4 { $icon = "ball"; $color = [System.Drawing.Color]::DeepPink }
}

$flakes += [PSCustomObject]@{
X = $rand.Next($screen.Bounds.Left, $screen.Bounds.Right)
Y = $rand.Next($screen.Bounds.Top - 300, $screen.Bounds.Bottom)
Size = $rand.Next(6, 14)
Speed = $rand.Next(1, 5)
Drift = $rand.NextDouble() * 2.5 - 1.25
Alpha = 230
Landed = $false
Type = $icon
Color = $color
}
}

for ($x = $screen.Bounds.Left; $x -lt $screen.Bounds.Right; $x++) {
$ground[$x] = $screen.Bounds.Bottom - 40
}

$form.Tag = [PSCustomObject]@{
Screen = $screen
Flakes = $flakes
Ground = $ground
}

$form.Add_Paint({
param($sender, $e)

$data = $sender.Tag
$screen = $data.Screen
$flakes = $data.Flakes

$e.Graphics.SmoothingMode = [System.Drawing.Drawing2D.SmoothingMode]::HighQuality

# 🎄 Trees
for ($tx = $screen.Bounds.Left; $tx -lt $screen.Bounds.Right; $tx += 180) {

$treeBase = $screen.Bounds.Bottom - 10

$treeBrush = New-Object System.Drawing.SolidBrush ([System.Drawing.Color]::DarkGreen)
$trunkBrush = New-Object System.Drawing.SolidBrush ([System.Drawing.Color]::SaddleBrown)

$e.Graphics.FillEllipse($treeBrush, $tx + 10, $treeBase - 80, 80, 70)
$e.Graphics.FillEllipse($treeBrush, $tx + 20, $treeBase - 120, 60, 60)
$e.Graphics.FillRectangle($trunkBrush, $tx + 42, $treeBase - 5, 16, 12)

$treeBrush.Dispose()
$trunkBrush.Dispose()
}

# 🎅 BIG CENTRED SANTA FACE
$centreX = $screen.Bounds.Left + ($screen.Bounds.Width / 2) - 120
$centreY = $screen.Bounds.Top + ($screen.Bounds.Height / 2) - 120

$faceBrush = New-Object System.Drawing.SolidBrush ([System.Drawing.Color]::Bisque)
$beardBrush = New-Object System.Drawing.SolidBrush ([System.Drawing.Color]::White)
$hatBrush = New-Object System.Drawing.SolidBrush ([System.Drawing.Color]::Red)

$e.Graphics.FillEllipse($faceBrush, $centreX + 40, $centreY + 40, 160, 160)
$e.Graphics.FillEllipse($beardBrush, $centreX + 20, $centreY + 100, 200, 140)
$e.Graphics.FillRectangle($hatBrush, $centreX + 40, $centreY + 10, 160, 40)

$faceBrush.Dispose()
$beardBrush.Dispose()
$hatBrush.Dispose()

# 🎄 MERRY CHRISTMAS TEXT (CENTRE)
$font = New-Object System.Drawing.Font("Segoe UI", 48, [System.Drawing.FontStyle]::Bold)
$textBrush = New-Object System.Drawing.SolidBrush ([System.Drawing.Color]::Gold)

$msg = "MERRY CHRISTMAS"
$textSize = $e.Graphics.MeasureString($msg, $font)

$textX = $screen.Bounds.Left + ($screen.Bounds.Width / 2) - ($textSize.Width / 2)
$textY = $centreY - 80

$e.Graphics.DrawString($msg, $font, $textBrush, $textX, $textY)

$font.Dispose()
$textBrush.Dispose()

# ❄ Falling items
foreach ($flake in $flakes) {

$brush = New-Object System.Drawing.SolidBrush (
[System.Drawing.Color]::FromArgb($flake.Alpha, $flake.Color)
)

if ($flake.Type -eq "gift") {
$e.Graphics.FillRectangle($brush, $flake.X, $flake.Y, $flake.Size, $flake.Size)
}
else {
$e.Graphics.FillEllipse($brush, $flake.X, $flake.Y, $flake.Size, $flake.Size)
}

$brush.Dispose()
}

# ⏱ Countdown
$countFont = New-Object System.Drawing.Font("Segoe UI", 22, [System.Drawing.FontStyle]::Bold)
$countBrush = New-Object System.Drawing.SolidBrush ([System.Drawing.Color]::White)

$countText = "Closing in $script:secondsLeft seconds"
$e.Graphics.DrawString($countText, $countFont, $countBrush, $screen.Bounds.Left + 20, $screen.Bounds.Top + 20)

$countFont.Dispose()
$countBrush.Dispose()
})

$forms += $form
}

# Animation timer
$timer = New-Object System.Windows.Forms.Timer
$timer.Interval = 30
$timer.Add_Tick({

if ([Environment]::TickCount - $script:lastSecondTick -ge 1000) {
if ($script:secondsLeft -gt 0) { $script:secondsLeft-- }
$script:lastSecondTick = [Environment]::TickCount
}

foreach ($form in $forms) {

$data = $form.Tag
$screen = $data.Screen
$flakes = $data.Flakes
$ground = $data.Ground

foreach ($flake in $flakes) {

if (-not $flake.Landed) {

$flake.Y += $flake.Speed
$flake.X += $flake.Drift

if ($flake.X -lt $screen.Bounds.Left) { $flake.X = $screen.Bounds.Right }
if ($flake.X -gt $screen.Bounds.Right) { $flake.X = $screen.Bounds.Left }

$xInt = [int][Math]::Round($flake.X)

if ($flake.Y + $flake.Size -ge $ground[$xInt]) {
$flake.Landed = $true
}
}
else {
if ($rand.NextDouble() -lt 0.02) {
$flake.Y = $screen.Bounds.Top
$flake.X = $rand.Next($screen.Bounds.Left, $screen.Bounds.Right)
$flake.Landed = $false
}
}
}

$form.Invalidate()
}
})

$timer.Start()

# Auto close
$closeTimer = New-Object System.Windows.Forms.Timer
$closeTimer.Interval = 30000
$closeTimer.Add_Tick({
$timer.Stop()
foreach ($form in $forms) { $form.Close() }
})
$closeTimer.Start()

# ✅ Show ALL forms correctly
foreach ($form in $forms) {
$form.Show()
}

while ($forms | Where-Object { $_.Visible }) {
[System.Windows.Forms.Application]::DoEvents()
Start-Sleep -Milliseconds 50
}

Total
0
Shares
Previous Post

Rufus: The Ultimate Tool for Creating Bootable USB Drives

Related Posts

How to Find Duplicate Files Using PowerShell

For one of the projects, I needed a PowerShell script to find duplicate files in the shared network folder of a file server. There are a number of third-party tools for finding and removing duplicate files in Windows, but most of them are commercial or are not suitable for automatic scenarios.Because files may have different
Read More