Envoke, the portmanteau of Environment and Invoke, automatically launches and arranges your desktop applications at Windows startup. Define your apps and time-of-day schedules in a single JSON config, and Envoke selects the right set for the moment; work hours, home hours, or any custom profile you create.
Key features:
- Config-driven - define apps and schedules in one JSON file, no scripting required
- Environment switching - auto-selects Work, Home, or any custom profile based on day and hour
- Parallel launching - apps in the same priority group launch concurrently on PowerShell 7+
- Window maximization - each app's window is detected and maximized after launch
- One run per boot - a registry-based boot guard prevents duplicate launches
- Quick Start
- Configuration
- App Discovery Reference
- Task Scheduler Setup
- Manual Testing
- Tips and FAQ
- Troubleshooting
- Verifying Your Setup
- Project Structure
- Acknowledgments
- License / Contributing
1. Install the module.
Install-Module Envoke -Scope CurrentUserOr clone the repository directly:
git clone https://github.com/aporonaut/Envoke.git
cd Envoke2. Configure your apps.
copy Envoke\config.example.jsonc Envoke\config.jsonOpen Envoke\config.json in a text editor, remove all comment lines (lines starting with //), and replace the placeholder paths with your actual app paths.
Important:
ConvertFrom-Jsondoes not support JSONC comments. Remove all//lines before saving, or the config will fail to parse.
See Envoke/config.example.jsonc for the full annotated template with examples for every app type.
3. Set up Task Scheduler.
schtasks /Create /XML "EnvokeTask.xml" /TN "Envoke"After import, open Task Scheduler (taskschd.msc), find the Envoke task, go to the Actions tab, and update the path in the Arguments field to point to your actual Envoke.vbs location.
4. Verify your setup.
Import-Module .\Envoke\Envoke.psd1
Test-EnvkInstallationA table of check results appears with Pass/Fail/Warn status and actionable messages for any issues found.
Prerequisites
| Requirement | Details |
|---|---|
| Operating System | Windows 10 or Windows 11 |
| PowerShell 5.1 | Included with Windows - no installation needed |
| PowerShell 7+ (optional) | Enables parallel app launching |
Check your PowerShell version:
$PSVersionTable.PSVersionInstall PowerShell 7+ (optional):
winget install --id Microsoft.PowerShell --source wingetIf you have PowerShell 5.1 only, everything works - apps just launch sequentially instead of in parallel.
Configuration lives in a single JSON file: Envoke\config.json.
Create your config from the template:
copy Envoke\config.example.jsonc Envoke\config.jsonOpen the file, remove all // comment lines (required - JSON does not support comments), and fill in your app paths.
VS Code tip: The
$schemafield in the config enables IntelliSense, autocomplete, and inline validation while editing. Keep that line in yourconfig.json.
See Envoke/config.example.jsonc for a fully commented template with examples for every app type - standard Win32 apps, UWP/Store apps, Electron apps, and background apps.
The config has three top-level sections:
settings (optional) - global behavior controls:
windowTimeoutSeconds: how long to wait for each app's window to appear (default: 120)parallelLimit: max concurrent app launches per priority group on PS 7+ (default: 5)forceSequential: set totrueto always launch apps one at a time (default: false)
apps - the application catalog. Define each app once with its path, process name, and default arguments. Apps referenced by multiple environments are listed here once.
environments - named launch profiles. Each environment lists which apps to launch (by name from the catalog) and optionally when to activate (by day and hour). An environment without a schedule block is the fallback - it activates when no scheduled environment matches.
When the script runs at boot, it evaluates each environment's schedule against the current day and hour:
- If the current day is in the environment's
dayslist and the current hour is betweenstartHourandendHour, that environment is selected. - If no scheduled environment matches, the fallback environment (no
scheduleblock) is selected. - If multiple environments match, the
priorityfield on the environment resolves the overlap - higher priority wins. If priorities tie, the first match by config order is used.
When configuring apps, you need three things: the file path to launch it, the process name for window detection, and for UWP/Store apps, the AppUserModelId. Use the commands below to find each.
Apps on the system PATH (e.g., explorer.exe):
Get-Command app.exe | Select-Object SourceApps installed via Start Menu shortcut (resolves the .lnk to the actual .exe):
$shortcut = Get-ChildItem "$env:APPDATA\Microsoft\Windows\Start Menu" -Recurse -Filter "*AppName*.lnk" | Select-Object -First 1
(New-Object -ComObject WScript.Shell).CreateShortcut($shortcut.FullName).TargetPathVerify a file path exists:
Test-Path "C:\path\to\app.exe"Launch the app, then run:
Get-Process | Where-Object { $_.MainWindowTitle -ne '' } | Select-Object ProcessName, MainWindowTitle | Format-Table -AutoSizeThe ProcessName column is what you put in the processName field in the config.
Electron apps (VS Code, Teams, Slack, ClickUp, etc.) often spawn a child process with a different name than the launcher executable. Always verify with the command above - use the name from
ProcessName, not the.exefile name.
Microsoft Store apps use a special path format: shell:AppsFolder\{AppUserModelId}.
Get-StartApps | Where-Object { $_.Name -like '*AppName*' }Example output:
Name AppID
---- -----
Teams MSTeams_8wekyb3d8bbwe!MSTeams
In your config, use:
"path": "shell:AppsFolder\\MSTeams_8wekyb3d8bbwe!MSTeams"| What you need | Command |
|---|---|
| File path (PATH apps) | Get-Command app.exe | Select-Object Source |
| File path (Start Menu shortcut) | See Find an app's file path above |
| Process name | Get-Process | Where-Object { $_.MainWindowTitle -ne '' } | Select-Object ProcessName, MainWindowTitle |
| UWP / Store AppUserModelId | Get-StartApps | Where-Object { $_.Name -like '*AppName*' } |
| Verify file path | Test-Path "C:\path\to\app.exe" |
| Verify PATH executable | Get-Command app.exe -ErrorAction SilentlyContinue |
Envoke runs at Windows logon via Task Scheduler. There are two ways to set it up.
1. Import the template:
schtasks /Create /XML "C:\path\to\repo\EnvokeTask.xml" /TN "Envoke"Replace C:\path\to\repo with the actual path to your cloned repository.
2. Update the VBS path:
The imported task uses a placeholder path. You must update it:
- Open Task Scheduler: press
Win+R, typetaskschd.msc, press Enter - In the left panel, click Task Scheduler Library
- Find and double-click the Envoke task
- Click the Actions tab
- Select the action and click Edit
- In the Arguments field, replace the placeholder path with your actual path: "C:\Users\YourName\Documents\Envoke\Envoke.vbs"
- Click OK on all dialogs
What the XML configures:
- Trigger: at user logon, with a 30-second delay to let the desktop fully load
- Action:
wscript.execallingEnvoke.vbs(windowless execution) - No administrator rights required
Click to expand manual Task Scheduler setup
- Open Task Scheduler:
Win+R->taskschd.msc-> Enter - In the Actions panel (right side), click Create Task (not "Create Basic Task")
- General tab:
- Name:
Envoke - Ensure "Run only when user is logged on" is checked (no elevation needed)
- Name:
- Triggers tab: Click New
- Begin the task: At log on
- Specific user: your account
- Check Delay task for:
30 seconds - Click OK
- Actions tab: Click New
- Action: Start a program
- Program/script:
wscript.exe - Add arguments:
"C:\path\to\your\Envoke.vbs" - Click OK
- Conditions tab:
- Uncheck "Stop if the computer switches to battery power"
- Settings tab:
- Check "Allow task to be run on demand"
- If task is already running: Do not start a new instance
- Click OK to save
Why the VBS wrapper?
The Task Scheduler action calls wscript.exe Envoke.vbs rather than powershell.exe Envoke.ps1 directly. This is intentional: the -WindowStyle Hidden flag in Task Scheduler is unreliable and often shows a brief PowerShell window at logon. The VBS wrapper (wscript.exe + window style 0) reliably suppresses the window every time.
The VBS wrapper also includes the required PowerShell flags so you never need to edit it:
-STA- required by UIAutomationClient for window detection-NonInteractive- suppresses prompts that would block a windowless process-ExecutionPolicy Bypass- prevents execution policy from blocking the script
Before relying on Task Scheduler, test the script directly from a PowerShell prompt.
Test Work environment (bypasses boot guard, does not affect registry):
.\Envoke.ps1 -SkipBootGuard -Environment WorkTest Home environment:
.\Envoke.ps1 -SkipBootGuard -Environment HomeParameters:
| Parameter | Type | Description |
|---|---|---|
-ConfigPath |
String | Path to a custom config file. Omit to use the default search order. |
-Environment |
String | Force a specific environment (e.g., Work, Home). Omit for automatic schedule-based selection. |
-SkipBootGuard |
Switch | Bypass the boot guard; allow repeated runs without affecting boot-session tracking. |
-EnableDebug |
Switch | Enable DEBUG-level log entries for verbose output. Use with -SkipBootGuard for test runs. |
-Sequential |
Switch | Force sequential app launching regardless of PS version or config settings. Useful for troubleshooting. |
What to look for when testing:
- Each configured app should launch and its window should maximize
- The log file updates at
$env:LOCALAPPDATA\Envoke\Logs\ - No error messages appear in the console output
How do I add a new app?
- Add an entry to the
appscatalog inconfig.jsonwith itspath,processName, andarguments - Add a reference to the app in the desired environment's
appslist - See
Envoke/config.example.jsoncfor examples of each app type
How do I add a custom environment?
Add a new key to the environments block with a schedule (or omit it for a fallback). Example:
"Evening": {
"schedule": {
"days": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
"startHour": 18,
"endHour": 23
},
"apps": [
{ "name": "Browser" },
{ "name": "ChatApp" }
]
}Can I have overlapping schedules?
Yes. When multiple environments match the current day and hour, the environment-level priority field resolves the overlap - higher priority wins. If priorities tie, the first match by config order is used. In interactive debug mode, you are prompted to choose.
How do I disable parallel launching?
Set "forceSequential": true in the settings block of your config, or pass -Sequential to Envoke.ps1 when testing.
The config fails to parse - what's wrong?
The most common cause is leaving // comment lines in config.json. Remove all lines starting with //. Only pure JSON is valid; JSONC comments are not supported by ConvertFrom-Json.
Task Scheduler fires but nothing happens.
The VBS path in the Task Scheduler action is wrong. Open Task Scheduler, find the Envoke task, go to the Actions tab, and verify the path in the Arguments field matches your actual Envoke.vbs location.
Apps launch but windows do not maximize.
The -STA flag is missing from the PowerShell invocation. If you are running the VBS wrapper via Task Scheduler, this flag is already included - check that the task is actually calling wscript.exe Envoke.vbs and not powershell.exe directly. If running PowerShell directly in a test, add -STA to your PowerShell invocation.
"Module not found" error in the log.
The Envoke\ module folder must be in the same directory as Envoke.ps1. Verify the folder structure is intact and that you have not moved any files out of the cloned repo folder.
Task fires too early - apps fail before the desktop is ready.
Increase the startup delay in the Task Scheduler trigger. The included XML uses 30 seconds. For slower machines or cold boots:
- Open Task Scheduler -> double-click
Envoke - Go to the Triggers tab -> edit the logon trigger
- Increase the delay to 60 seconds (or more if needed)
App path not found.
Verify the path exists:
Test-Path "C:\path\to\your\app.exe"For UWP apps, verify the AppUserModelId:
Get-StartApps | Where-Object { $_.Name -like '*AppName*' }The boot guard is preventing a re-run during testing.
By design, the script only runs once per boot session. For repeated testing, use -SkipBootGuard:
.\Envoke.ps1 -SkipBootGuard -Environment WorkWhere is the log file?
explorer $env:LOCALAPPDATA\Envoke\LogsThe log file name includes the date; logs older than 30 days are rotated automatically.
After configuring the app and setting up Task Scheduler, run the built-in diagnostic:
Import-Module .\Envoke\Envoke.psd1
Test-EnvkInstallationThe function checks four areas and prints a summary table:
| Area | What is checked |
|---|---|
| Module | PS version, UIAutomationClient assembly |
| Config | File exists, parses as valid JSON, app paths resolve |
| Task Scheduler | Envoke task exists with correct trigger |
| Permissions | Log directory is writable, registry path is accessible |
Each check reports Pass, Fail, or Warn with a message explaining what to do if anything is not right.
To check a config file in a non-default location:
Test-EnvkInstallation -ConfigPath "D:\MyConfigs\config.json"Envoke/
├── Envoke.ps1 Entry point - imports the module and calls Invoke-EnvkStartup
├── Envoke.vbs VBS wrapper - called by wscript.exe from Task Scheduler at logon
├── EnvokeTask.xml Importable Task Scheduler task template
└── Envoke/
├── Envoke.psd1 Module manifest (lists all exported functions)
├── config.example.jsonc Fully annotated configuration template
├── config.schema.json JSON Schema - enables VS Code IntelliSense when editing config
├── Public/ Exported functions (Test-EnvkInstallation, Invoke-EnvkStartup, etc.)
└── Private/ Internal helpers (not imported into your session)
The structure above reflects the repository layout. When installed via Install-Module, the module lands in the standard PowerShell module path ($env:PSModulePath).
Envoke was designed and prototyped by hand, then enhanced and productionized with Claude Code as structured by the GSD workflow system, created by TÂCHES (@glittercowboy).
GSD is a lightweight and powerful meta-prompting, context engineering, and spec-driven development system for Claude Code. I've used this project (Envoke) to test a few other similar systems, GSD is the one I liked most in terms of software engineering completeness.
It works for both greenfield and brownfield projects, minimises context rot, and methodically goes through a discuss → research → plan → execute → test → debug cycle repeating through phases that break the project down into targeted contexts.
If you build with Claude Code, it's worth a look.
This project is licensed under the MIT License - free to use, modify, and distribute with attribution.
Contributions are welcome. To get started:
- Report a bug - open an issue with steps to reproduce and your PowerShell version (
$PSVersionTable.PSVersion) - Request a feature - open an issue describing the use case before writing code
- Submit a PR - fork the repo, make your changes, and open a pull request against
main
Before submitting a PR:
- Test your changes manually with
-SkipBootGuard -Environment Workand-Environment Home - Follow existing code patterns - PascalCase Verb-Noun functions, comment-based help on public functions,
Write-EnvkLogfor output - Keep scope focused - one fix or feature per PR



