New PowerShell functions are extensively tested before they eventually are merged into the free PowerShell module donelandtools
.
If you’d like to have a peek, or participate in testing, you’ll find the latest function source codes here.
Cleaning Computer Disk Drives: Get-FolderSize
You can never have enough disk space on a computer, and with older notebooks, disk drives seem to always be low on space.
That’s especially critical when you try and perform major upgrades. For example, if you plan to upgrade from Windows 10 to Windows 11, this requires 10-20GB of free disk space.
Unfortunately, many software vendors start to make Windows 11 a requirement for their software. For example, Fusion360
announced there will be no new versions running on Windows 10, and beginning 2026, Windows 11 will be required.
It’s hard to clean up disk space, though, especially since many Gigabytes of wasted data are hidden away in deeply nested subfolders, and often such folders are marked hidden and not visible in Windows Explorer.
That’s when Get-FolderSize
comes to the rescue: it examines folder trees (like your personal user profile) and even entire disks, then reports the sizes of all folders and subfolders (including hidden) individually. This way you can clearly identify the actual folders that hog massive data.
It also reports back the largest file found in each folder.
Here is a sample call that examines drive C:\
for any folder larger than 1000MB, including normally hidden folders:
Get-ChildItem -Path c:\ -Recurse -Force -ErrorAction Ignore -File |
Get-FolderSize -ThresholdSizeMB 1000 |
Out-GridView
The result is displayed in real time in a gridview window. Once all results are in, you can sort the list by clicking column headers. That makes it simple to identify the folders occupying the most space.
Obviously, you can’t just delete such folders and hope for the best. Many folders are vital, and deleting them would cause havok. But identifying these folders as a first step gives you a clue where it is worthwhile investigating further. When in doubt, I discussed folder paths with one of the readily available AI Chats (like ChatGPT or perplexity.ai), and this way it was simple to identify the purpose of unknown subfolders, and more often than not identify space hogs that could be safely deleted.
Test Findings
To my honest surprise, the tool found quite a lot of gigabytes of unneeded data that could easily be removed:
- VSCode:
This editor is great, however it seems to hog massive amounts of temporary data in a variety of subfolders that may stem from long-ago projects, and would be automatically re-downloaded on demand if needed in the future. - ArduinoIDE 15.0:
This IDE proved to be a space hog, keeping massive amounts of ZIP files in a subfolder called staging. Apparently, these ZIP files are unpacked during installation but then left behind, not needed anymore during normal operation. - Installation Location:
Most software installs on
C:\
by default, so this drive quickly fills up. Tools likeKiCAD
,Fusion360
, and 3D slicers turned out to occupy Gigabytes of data.- Uninstall all software that you don’t really need.
- Reinstall all software that you do need, and freshly install it to a better location. For example, my notebook has a
D:\
partition with plenty of free space. I ended up uninstallingKiCAD
, then reinstalling it on my driveD:
, relieving the memory pressure from the holyC:\
drive.Fusion360
, also a huge memory hog, unfortunately cannot be configured to use any drive other thanC:\
.
Make sure to also run cleanmgr.exe
with local Admin privileges, then initiate a system scan. There may be gigabytes of wasted space in log files or older windows installation remnants that can be easily freed with this tool.
Happy Results
When I started this, my notebook had 2.3-4.7GB free space on C:\
. It was a constant struggle to clean up files to keep things going.
After a 30 minute cleanup session, and with the help of Get-FolderSize
, my drive C:\
now has 21.8GB free space, and I was finally able to upgrade to Windows 11. The notebook feels and works much better now with a fresh OS and plenty of space.
My notebook originally did not qualify for a Windows 11 upgrade despite being from 2018. I then learned that while there are many items on the prerequisite check list that make sense, most older computers are hit by CPU requirements that feel weird: even an Intel i5 with plenty of power is (officially) not supported to perform a Windows 11 upgrade. I then used a PowerShell script to force an upgrade on my old i5 notebook to Windows 11, and it runs smoothly ever since. Just make sure you download the appropriate Windows 11 ISO Image that in fact matches your current Windows 10 edition, or else your existing license will not be transitioned, and you need a new one.
Converting Images To WebP
Over time, this website has grown quite large. Picture files contribute to this size. I originally chose .png
files to support transparency. However, .png
format isn’t very space efficient.
Today, better image formats are available, among them .webp
. This format provides all the benefits of .png
files, including transparency, while cutting down file size by roughly 50% at the same resolution and quality.
All modern browsers and tools today support .webp
picture format, so I decided to transition from .png
to .webp
.
In order to convert .png
files easily to .webp
, I looked into using the free google tool cwebp.exe
which is available for all major operating systems and can be downloaded as part of the libwebp
.
Examining Picture Files
At first, I created the function Get-PsoImageDetail
which returns picture format, size, and image dimensions:
function Get-PsoImageDetail
{
param
(
[Alias('FullName')]
[String]
[Parameter(Mandatory,ValueFromPipeline,ValueFromPipelineByPropertyName)]
$Path
)
begin
{
Add-Type -AssemblyName System.Drawing
class ImageDetail
{
[int]$Height
[int]$Width
[System.Drawing.Imaging.ImageFormat]$Format
[string]$Path
}
$formatTranslate = [System.Drawing.Imaging.ImageFormat].GetProperties().Name -ne 'Guid' |
ForEach-Object -Begin { $h = @{} } -Process {
$h[[System.Drawing.Imaging.ImageFormat]::$_.Guid.Guid] = $_
} -end { $h }
}
process
{
try
{
[System.Drawing.Image]$image = [System.Drawing.Image]::FromFile($Path)
$format = $formatTranslate[$image.RawFormat.Guid.Guid]
[ImageDetail]@{
Path = $Path
Height = $image.Height
Width = $image.Width
Format = $format
}
$image.Dispose()
}
catch
{
# image file format could not be identified
# this may occur when "new" image formats such as "webp" are encountered
# since the tools in this module deal with processing and converting "older" formats to more modern formats,
# if a file cannot be identified, it is assumed that it already is a modern file, and
# consequently, the file is ignored (by not emitted the info object)
Write-Warning "Unsupported image format: $Path"
}
}
}
Simply pipe any number of image files into the function:
Get-ChildItem D:\samplePics | Get-PsoImageDetail
The result looks similar to this:
Height Width Format Path
------ ----- ------ ----
478 522 Png D:\samplePics\audio-xy-c15h_angle_t.png
592 421 Png D:\samplePics\audio-xy-c15h_back_t.png
593 421 Png D:\samplePics\audio-xy-c15h_top_t.png
(...)
Converting PNG to WEBP
Next, I created the function Convert-PngToWebP
that internally uses the free google tool cwebp.exe
:
function Convert-PngToWebP
{
<#
.SYNOPSIS
Converts png images to webp format to save space.
.DESCRIPTION
uses the tool cwebp.exe from google to convert images to webp format in an effort to reduce file size
transparency is preserved, the conversion is lossless
#>
[CmdletBinding(DefaultParameterSetName='Width')]
param
(
# path to original image file
[Alias('FullName')]
[String]
[Parameter(Mandatory,ValueFromPipeline,ValueFromPipelineByPropertyName,Position=0)]
$Path,
# desired width in px
# images that are larger than this will be downscaled to MaxWidth
# images that are smaller than MaxWidth retain their dimensions provided you specified the original
# image width in -Width, else image files that are smaller than -MaxWidth will be upscaled.
# if this parameter is omitted, or if its value is 0 or less, image dimensions are not altered.
[int]
$MaxWidth=0,
# original image height in px
[Parameter(ValueFromPipelineByPropertyName,ParameterSetName='Height')]
[int]
$Height=-1,
# original image width in px
[Parameter(ValueFromPipelineByPropertyName,ParameterSetName='Width')]
[int]
$Width=-1
)
begin
{
# find the convert tool
$toolPath = Join-Path -Path $PSScriptRoot -ChildPath 'bin\cwebp.exe'
$exists = Test-Path -Path $toolPath
if (!$exists)
{
Write-Warning "File $toolPath not found. You may have to download the free library first and extract the tool: https://storage.googleapis.com/downloads.webmproject.org/releases/webp/index.html"
throw 'cwebp.exe not found'
}
class ConversionInfo
{
[int]$Width
[int]$Height
[int]$NewSize
[int]$OldSize
[double]$CompressionRatio
[string]$InPath
[string]$OutPath
[string[]]$Option
}
$parser = @{
OutPath = "'(.*?)'"
InPath = "^File:\s{1,}(.*?)$"
Dimension = "^Dimension:\s{1,}(.*?)$"
NewSize = "^Output:\s{1,}(.*?) bytes$"
Option = "^ \* (.*?)$"
}
}
process
{
# new path for image to be created
# new image file will be in the same folder as original image file
$newPath = [System.Io.Path]::ChangeExtension($Path, '.webp')
$retainDimensions = ($MaxWidth -le 0) -or ( ($Width -gt 0) -and ($Width -lt $MaxWidth))
# console tool is called in a separate scriptblock so its output streams can
# be manipulated. When console tools run inside "PowerShell ISE", their regular
# output stream is mis-directed to the error stream, appearing in red and formatted
# like errors - even though no error occured
# to prevent, the error stream is explicitly redirected to the output stream,
# then post-processed:
& {
if ($retainDimensions)
{
# retain original image dimensions:
& $toolPath $Path -lossless -o $newPath
}
else
{
# rescale image to MaxWidth
& $toolPath -resize $MaxWidth 0 $Path -lossless -o $newPath
}
} 2>&1 | ForEach-Object -Begin {
$h = [ConversionInfo]::new()
} -Process {
$message = $_.Exception.Message
foreach($key in $parser.Keys)
{
$pattern = $parser[$key]
if ($message -match $pattern)
{
if ($key -eq 'Dimension')
{
$dimensions = $matches[1] -split ' x '
$h.Width = $dimensions[0] -as [int]
$h.Height = $dimensions[1] -as [int]
}
elseif ($key -eq 'Option')
{
$h.$key += $matches[1]
}
else
{
$h.$key = $matches[1]
}
break
}
}
} -end {
$h.OldSize = (Get-Item -Path $h.InPath).Length
$h.CompressionRatio = [Math]::Round( ($h.NewSize * 100 / $h.OldSize), 1)
$h
}
}
}
Initially, I planned to also resize images to smaller sizes (which cwebp.exe
can also do), however I quickly realized that for unknown reasons, downscaled pictures turned out to be larger than simply converting pictures and keeping their sizes.
I can only speculate that the way how cwebp.exe
re-scales images introduces pixel noise that may cause less efficient storage. So while Convert-PngToWebP
can still resize images, I am currently not using this feature.
Instead, I am simply using the function to batch-convert .png
images to .webp
format:
Get-ChildItem 'C:\pics\Signal Processing\Level Shifter\images' -Filter *.png | Convert-PngToWebP
The function automatically picks up the text status messages emitted by cwebp.exe
and converts them to structured objects. The result looks similar to this:
Width : 522
Height : 478
NewSize : 132204
OldSize : 235187
CompressionRatio : 56.2
InPath : D:\samplePics\audio-xy-c15h_angle_t.png
OutPath : D:\samplePics\audio-xy-c15h_angle_t.webp
Option : {Lossless features used: PREDICTION CROSS-COLOR-TRANSFORM SUBTRACT-GREEN, Precision Bits: histogram=4 transform=4 cache=0}
Width : 421
Height : 592
NewSize : 150160
OldSize : 259313
CompressionRatio : 57.9
InPath : D:\samplePics\audio-xy-c15h_back_t.png
OutPath : D:\samplePics\audio-xy-c15h_back_t.webp
Option : {Lossless features used: PREDICTION CROSS-COLOR-TRANSFORM SUBTRACT-GREEN, Precision Bits: histogram=4 transform=4 cache=0}
(...)
Slow Website?
This website is very fast, and pages should appear instantly. If this site is slow for you, then your routing may be messed up, and this issue does not only affect done.land, but potentially a few other websites and downloads as well. Here are simple steps to speed up your Internet experience and fix issues with slow websites and downloads..
Comments
Please do leave comments below. I am using utteran.ce, an open-source and ad-free light-weight commenting system.
Here is how your comments are stored
Whenever you leave a comment, a new github issue is created on your behalf.
-
All comments become trackable issues in the Github Issues section, and I (and you) can follow up on them.
-
There is no third-party provider, no disrupting ads, and everything remains transparent inside github.
Github Users Yes, Spammers No
To keep spammers out and comments attributable, all you do is log in using your (free) github account and grant utteranc.es the permission to submit issues on your behalf.
If you don’t have a github account yet, go get yourself one - it’s free and simple.
If for any reason you do not feel comfortable with letting the commenting system submit issues for you, then visit Github Issues directly, i.e. by clicking the red button Submit Issue at the bottom of each page, and submit your issue manually. You control everything.
Discussions
For chit-chat and quick questions, feel free to visit and participate in Discussions. They work much like classic forums or bulletin boards. Just keep in mind: your valued input isn’t equally well trackable there.
(content created Jul 19, 2025 - last updated Jul 21, 2025)