PowerShell module for managing video files (MP4, MKV, etc.) directly from the terminal or other scripts.
- .NET 10 SDK (10.0.300 or later; see
global.json) - PowerShell 7.6+
- FFmpeg (
ffmpegandffprobeonPATH) — required for most cmdlets
Optional tools used by specific workflows:
| Tool | Used by |
|---|---|
mkvtoolnix (mkvextract) | Matroska VobSub extraction in Convert-VideoFile, Export-Subtitles, and related workflows |
Tesseract OCR language data (eng.traineddata) | Image subtitle OCR via libse (Convert-ImageSubtitlesToSrt, Export-Subtitles, Invoke-SubtitleOcrRepair) |
dotnet buildBuild the module, then launch an interactive session with the module imported:
.\scripts\Launch.ps1Launch.ps1 builds if needed, opens a new PowerShell 7.6 window, imports the Debug build, and prints the process ID for attaching a debugger. Use -Configuration Release for a Release build.
After dotnet build, import the module from the build output:
Import-Module .\src\MediaForgePS\bin\Debug\net10.0\MediaForgePS.psd1 -Force.\scripts\Build.ps1 -Configuration Release -Build
.\scripts\Pack-Module.ps1 -Configuration ReleaseThis stages artifacts/MediaForgePS and artifacts/MediaForgePS.<version>.zip (not a C# NuGet package). CI uploads that zip as the pack artifact.
Cmdlet help is shipped as MAML (en-US\MediaForgePS.dll-Help.xml). After importing:
Get-HelpGet-MediaFile-Full
Get-HelpConvert-VideoFile-ExamplesMarkdown help source lives in src\MediaForgePS\docs. Regenerate MAML with .\scripts\Update-Help.ps1 after changing cmdlets or help content.
dotnet testdotnet test tests/MediaForgePS.Tests/MediaForgePS.Tests.csprojComponent tests exercise cmdlets with real ffmpeg/ffprobe (no mocks). They are skipped automatically when media tools or test assets are missing.
dotnet test tests/MediaForgePS.ComponentTests/MediaForgePS.ComponentTests.csprojSee tests/MediaForgePS.ComponentTests/TestAssets/README.md for test media assets.
./scripts/Build.ps1 -Build -Test runs dotnet test then Pester. Standalone:
.\tests\MediaForgePS.Tests\Run-PesterTests.ps1
.\tests\MediaForgePS.Tests\Run-PesterTests.ps1 -ModuleConfiguration ReleasePacks the Gallery module layout and imports it for a short cmdlet smoke:
dotnet test tests/MediaForgePS.E2ETests/MediaForgePS.E2ETests.csprojSee tests/README.md for more detail on each test project.
Before committing, ensure:
dotnet buildpasses without errorsdotnet format --verify-no-changespasses- All tests pass
MediaForgePS/
├── src/
│ └── MediaForgePS/ # Main module project
│ ├── Cmdlets/ # C# cmdlet implementations
│ ├── Models/ # Media and encoding types
│ ├── Services/ # FFmpeg, conversion, and workflow services
│ ├── docs/ # platyPS Markdown help source
│ └── MediaForgePS.psm1 # Module root script
├── tests/
│ ├── MediaForgePS.Tests/ # Unit tests (xUnit + Pester)
│ ├── MediaForgePS.ComponentTests/ # Cmdlet tests with real ffmpeg/ffprobe
│ └── MediaForgePS.E2ETests/ # Pack/import module smoke (E2E)
├── scripts/ # Build, help, and dev-session scripts
└── .github/workflows/ # CI/CD workflows
MediaForgePS exposes 18 cmdlets for media inspection, conversion, subtitles, chapters, and TV-library workflows. Full Get-Help text is built from Markdown under src/MediaForgePS/docs. Regenerate with .\scripts\Update-Help.ps1 after changing cmdlets or help content.
| Goal | Cmdlet |
|---|---|
| Convert a folder of videos to MP4 with English audio mapping and optional caption extraction | Convert-VideoFile |
Convert a list of files with encoder presets (x264, x265, nvenc) and optional custom mappings | Convert-MediaFiles |
| Convert one file with full control over video and audio settings | Convert-MediaFileAdvanced |
Convert-VideoFile is the opinionated, directory-oriented workflow (default encoder: nvenc). Convert-MediaFiles is the flexible batch cmdlet (default encoder: x265 when -DefaultVideoEncoder is omitted). Both output .mp4 files.
| Cmdlet | Description |
|---|---|
Get-MediaFile | Media file metadata (format, streams, chapters) via ffprobe |
Get-AudioStreams | Suggested English audio track mappings for conversion |
Export-MediaStream | Extract one stream (video, audio, subtitle) without re-encoding |
# Inspect a file before converting$media=Get-MediaFile-Path ".\movie.mkv"$media.Streams|Where-Object Type -eq'audio'|Format-Table Index, Codec, Language
# Extract the first audio stream without re-encodingExport-MediaStream-InputPath ".\movie.mkv"-OutputPath ".\audio.m4a"-Type Audio -Index 0| Cmdlet | Description |
|---|---|
Convert-VideoFile | Batch video-to-MP4 conversion with auto audio mapping and optional caption extraction |
Convert-MediaFiles | Batch conversion with configurable encoder and audio mappings |
Convert-MediaFileAdvanced | Single-file conversion with explicit encoding settings |
New-VideoEncodingSettings | Build VideoEncodingSettings for conversion cmdlets |
New-AudioTrackMapping | Build copy or encode audio mappings |
# Convert everything in a folder (default: NVENC HEVC)Convert-VideoFile-InputPath "C:\Videos\Season1"-Recurse
# Batch convert with x265 and auto-detected English audioConvert-MediaFiles-InputPath "C:\Source\*.mkv"-OutputDirectory "C:\Out"-DefaultVideoEncoder x265
# Full control over a single file$settings=New-VideoEncodingSettings-Codec libx265 -CRF 20-Preset slow
$mappings=Get-AudioStreams-InputPath "C:\movie.mkv"Convert-MediaFileAdvanced-InputPath "C:\movie.mkv"-OutputPath "C:\Out\movie.mp4"`-VideoEncodingSettings $settings-AudioTrackMappings $mappingsGet-AudioStreams returns mappings for English audio only: DTS streams are copied; other codecs are encoded to AAC with channel-based bitrates.
| Cmdlet | Description |
|---|---|
Export-Subtitles | Extract English subtitles; -Ocr Auto|Skip|Force controls image subtitle OCR |
Convert-ImageSubtitlesToSrt | SUP/SUB → SRT via libse and Tesseract (alias: Convert-SupToSrt) |
Repair-Subtitles | Fix common OCR errors in SRT files |
Invoke-SubtitleOcrRepair | OCR image subtitles then repair the converted SRT files |
Several cmdlets accept -Ocr with values Auto (default), Skip, or Force:
- Auto — OCR image subtitles only when the source has a single exported subtitle format and it is not SRT.
- Force — OCR all exported image subtitle files.
- Skip — extract only; no OCR or repair.
# Extract English subtitles and OCR image-based tracks when neededExport-Subtitles-InputPath "C:\Videos\movie.mkv"-Ocr Auto
# Convert existing SUP files on disk, then repair OCR outputInvoke-SubtitleOcrRepair-InputPath "C:\Subs"-Recurse
# Fix OCR mistakes in SRT files in placeRepair-Subtitles-InputPath "C:\Subs\*.srt"Export-Subtitles has alias Export-RepairedSubtitles. Folder input processes *.mkv files only.
| Cmdlet | Description |
|---|---|
Split-Chapters | Split a file by chapter ranges |
Split-SeriesChapters | Split by chapters with TVDb episode naming |
Invoke-SeasonScan | Fetch TVDb episode metadata for a season |
Invoke-VideoCopy | Copy episodes into a folder using TVDb naming |
Invoke-SeriesProcessing | Full season workflow (folders, scan, copy, chapters, captions) |
Invoke-BonusFileProcessing | Convert and organize Plex bonus content |
# Full season workflow: TVDb scan, copy, chapters, captionsInvoke-SeriesProcessing`-Title "My Show"-Season 1`-InputPath "C:\Source"-FilePatterns "*.mkv"`-OutputPath "P:\TV"`-TvDbSeriesUrl "https://thetvdb.com/series/12345"`-ExtractChapters -Ocr Auto
# Split a combined season file into named episodes$ranges=1..10|ForEach-Object { @{ Start=$_; End=$_ } }
Split-SeriesChapters-Title "My Show"-Season 1-InputFile "C:\season1.mkv"`-ChapterRanges $ranges-TvDbSeriesUrl "https://thetvdb.com/series/12345"# Process Plex bonus content (trailers, featurettes, etc.)Invoke-BonusFileProcessing-InputPath "C:\Extras\Movie"-OutputPath "P:\Movies\Movie"Invoke-SeriesProcessing runs these steps in order: create folder structure, scan TVDb via the official API (TVDB_API_KEY), copy episodes, optionally extract chapters, optionally extract captions with OCR. It fails if TVDb returns no episodes or no files are copied.
See src/MediaForgePS/docs for per-cmdlet help source and docs/platyPS-help-walkthrough.md for the help authoring workflow.