Setup Actions are my small escape hatch for things that do not belong in Flyoobe's settings database.
Think of rebuilding the icon cache, creating a restore point, opening a Windows tool, or running one final post-install command. I wanted this to stay boring in the best possible way: a little PowerShell, an optional INI file, and no plugin framework hiding behind it.
Nothing runs just because an action exists. You either start it yourself or explicitly add a recipe-safe action to a recipe.
You can enable the feature under Settings > Advanced > Setup Actions. The Setup Actions page lets you import an action and open the local Actions folder.
For a small personal action, a single .ps1 is enough:
# Description: Clears my application's local cache.
# Author: Your name
$ErrorActionPreference = 'Stop'
try {
Remove-Item "$env:LOCALAPPDATA\MyApp\Cache\*" -Recurse -Force
Write-Output 'Cache cleared.'
exit 0
}
catch {
Write-Error $_
exit 1
}Import the script from the Setup Actions page. Flyoobe copies it into Data\Actions and uses the file name as its visible name. With no extra metadata it becomes a manual-only Utility action.
These optional headers are understood for single scripts:
# Id: clear-my-cache
# Description: Clears my application's local cache.
# Version: 1.0
# Author: Your name
# Phase: Utility
# RequiresAdmin: false
# RecipeAllowed: false
# Warning: This closes MyApp before clearing its cache.
# Options: Clear cache; Show cache folderKeep the headers within the first 40 lines and use one comment per field. If you want translations or plan to share the action, use a package instead.
This is the format I use for actions that ship with Flyoobe:
my-action/
|- action.ini
`- run.ps1
Pick action.ini when importing it. Flyoobe validates the package and copies the whole folder into Data\Actions\<Id>. You can include helper files too; the script can find them through $PSScriptRoot.
Here is a complete action.ini:
[Action]
Id=default-power-plan
Name=Default power plan
Name.de=Standard-Energieplan
Description=Choose one of the built-in Windows power plans.
Description.de=W盲hle einen der integrierten Windows-Energiepl盲ne.
Version=1.0
Author=Your name
Phase=Finish
RequiresAdmin=false
RecipeAllowed=true
Script=run.ps1| Field | Required | What it does |
|---|---|---|
Id |
Yes | Stable action ID. Use letters, numbers, dots, underscores, or hyphens. Start with a letter or number. |
Name |
Yes | The name shown in Flyoobe. |
Name.<locale> |
No | A translated name, for example Name.de. |
Description |
No | A short explanation of the action. |
Description.<locale> |
No | A translated description. |
Version |
No | Informational version. Defaults to 1.0. |
Author |
No | Shown in the action details. |
Phase |
Yes | Prepare, Finish, or Utility. |
RequiresAdmin |
No | Set this to true if Flyoobe needs to be running as administrator. |
RecipeAllowed |
No | Allows the action to be exported to and run by recipes. Has no effect on Utility actions. |
Warning |
No | Extra confirmation text shown before a manual run. |
Warning.<locale> |
No | A translated warning. |
Script |
Yes | Relative path to a .ps1 inside the package folder. |
The script must stay inside its package folder. Flyoobe rejects paths that try to escape it.
This is the only dynamic UI feature I added on purpose. Put an Options line near the top of the script and separate the choices with semicolons:
# Options: Balanced; High Performance; Power Saver
param([string]$choice)
$ErrorActionPreference = 'Stop'
try {
switch ($choice) {
'Balanced' { powercfg.exe -setactive SCHEME_BALANCED }
'High Performance' { powercfg.exe -setactive SCHEME_MIN }
'Power Saver' { powercfg.exe -setactive SCHEME_MAX }
default { throw "Unknown option: $choice" }
}
if ($LASTEXITCODE -ne 0) { throw "powercfg failed with exit code $LASTEXITCODE." }
Write-Output "Selected: $choice"
exit 0
}
catch {
Write-Error $_
exit 1
}Flyoobe passes the selected text as the first positional argument. The parameter name is up to you, so both of these work:
param([string]$choice)param([string]$Option)Option text is written to recipes. Treat it like a stable ID. If you rename an option, a recipe containing the old text is invalid. That is intentional; the new Setup Actions core does not guess what old values might have meant.
| Phase | Run manually | Run from a recipe |
|---|---|---|
Prepare |
Yes | Before Flyoobe applies the other recipe changes |
Finish |
Yes | After Flyoobe applies the other recipe changes |
Utility |
Yes | Never; this is manual-only |
A recipe action needs both a recipe phase and explicit permission:
Phase=Finish
RecipeAllowed=trueRecipes only store the action ID and, if there is a dropdown, the selected option. They never contain PowerShell code or a local script path. This also means the same action must already be installed on the PC that imports the recipe.
Please only mark an action as recipe-safe if it is predictable, non-interactive, and safe to run as part of a confirmed batch.
Flyoobe starts Windows PowerShell with -NoProfile, -NonInteractive, -ExecutionPolicy Bypass, and -File. Standard output and standard error appear live on the action page.
Use Write-Output for useful progress. Avoid filling the log with noise. More importantly, return a non-zero exit code when something fails. Printing a red-looking sentence is not enough; Flyoobe can only trust the process result.
This is the pattern I recommend:
$ErrorActionPreference = 'Stop'
try {
Write-Output 'Starting...'
# Do the work here.
Write-Output 'Finished.'
exit 0
}
catch {
Write-Error $_
exit 1
}When you call a native .exe, check $LASTEXITCODE yourself. A failed native command does not automatically make PowerShell fail.
- Keep the script small enough that another person can actually review it.
- Do not hide commands in encoded strings.
- Do not download and execute changing remote code unless that is the whole point of the action. If it is, say so clearly in
Warning. - Only set
RequiresAdmin=truewhen it is really needed. Flyoobe does not silently elevate scripts. - Keep interactive tools, launchers, and user-driven utilities out of recipes.
- Quote paths and use
$PSScriptRootfor files shipped inside a package. - Use
throworexit 1for failure paths. Do not rely on a scary-looking output message.
The new core has one execution model. There are no external console modes, special log hosts, arbitrary input boxes, category filters, or magic suffixes such as (console) and (silent).
The only script-driven UI metadata is # Options:. That keeps the code small and makes an action much easier to understand, review, export, and remove again.
The package does not appear
- Check that
Id,Name,Phase, andScriptexist inaction.ini. - Make sure
Scriptpoints to a real.ps1inside the package folder. - Make sure Setup Actions are enabled under Settings > Advanced.
The dropdown does not appear
- Put
# Options:within the first 40 lines. - Separate choices with semicolons.
Flyoobe says the action succeeded after an error
- End the failure path with
exit 1. - Check
$LASTEXITCODEafter calling native programs.
A recipe cannot find the action
- Install the same action ID on that PC first.
- Keep the option text unchanged.
- Check that the phase is
PrepareorFinishandRecipeAllowed=true.