A Windows shell automation console application that provides a JSON-based command interface for controlling Windows applications, audio settings, themes, and window management.
AutoShell is part of the TypeAgent project. It runs as a console application that reads JSON commands from stdin and executes Windows shell operations. This enables programmatic control of the Windows desktop environment.
- Application Management: Launch, close, and switch between applications using friendly names
- Window Management: Maximize, minimize, and tile windows side-by-side
- Audio Control: Set volume levels, mute/unmute, and restore previous volume
- Theme & Personalization: Apply themes, set wallpaper, toggle transparency, and configure title bar colors
- Virtual Desktop Management: Create, switch, pin, and move windows across virtual desktops
- Display Settings: Set resolution, brightness, scaling, orientation, color temperature, and blue light filter
- Network & Connectivity: Wi-Fi, Bluetooth, airplane mode, and metered connection controls
- Mouse & Touchpad: Cursor speed, pointer size, scroll lines, touchpad settings, and cursor trail
- Taskbar Customization: Alignment, auto-hide, badges, Task View, Widgets, and multi-monitor display
- Accessibility: Narrator, Magnifier, Sticky Keys, Filter Keys, and mono audio
- Privacy Controls: Manage camera, microphone, and location access
- Power Management: Battery saver levels and power mode configuration
- System Settings: Notifications, game mode, focus assist, time settings, and multi-monitor behavior
- File Explorer: Toggle file extensions and hidden/system file visibility
- Windows 10/11
- .NET 8
- Microsoft.WindowsAPICodePack.Shell NuGet package
- System.Text.Json (built-in)
- Node.js ≥ 20 and pnpm (for generating
.pas.jsonschemas from TypeScript)
AutoShell requires .pas.json schema files generated by the TypeScript action schema compiler (asc). Build the TS side first, then the dotnet project:
# 1. Build TS desktop package (generates .pas.json schemas)
cd ts
pnpm install
pnpm run --filter @typeagent/action-schema-compiler... build
pnpm run -C packages/agents/desktop asc:all
# 2. Build AutoShell
cd ../dotnet
dotnet build autoShell/autoShell.csprojIf you've already run pnpm run build in the ts/ workspace, step 1 is already done.
AutoShell runs in two modes:
Interactive mode (default): Run the application and send JSON commands via stdin, one per line:
dotnet run --project autoShell.csproj
{"actionName":"Volume","parameters":{"targetVolume":50}}
{"actionName":"Mute","parameters":{"on":true}}
{"actionName":"quit","parameters":{}}
Command-line mode: Pass a JSON command (or array) as an argument for one-shot execution:
autoShell.exe {"actionName":"Volume","parameters":{"targetVolume":50}}
autoShell.exe [{"actionName":"Volume","parameters":{"targetVolume":50}},{"actionName":"Mute","parameters":{"on":true}}]
Each command returns a JSON ActionResult on stdout:
{"success":true,"message":"Volume set to 50"}
{"success":false,"message":"Invalid parameters for 'Volume': ..."}| Command | Parameter | Description |
|---|---|---|
ApplyTheme |
Theme name | Applies a Windows theme |
CloseProgram |
Application name | Closes an application |
ConnectWifi |
{"ssid": "name", "password": "pass"} |
Connects to a Wi-Fi network |
CreateDesktop |
JSON array of names | Creates one or more virtual desktops |
Debug |
(none) | Launches the debugger |
DisconnectWifi |
(none) | Disconnects from the current Wi-Fi network |
LaunchProgram |
Application name | Opens an application (or raises if already running) |
ListAppNames |
(none) | Outputs installed applications as JSON |
ListResolutions |
(none) | Outputs available display resolutions as JSON |
ListThemes |
(none) | Outputs installed themes as JSON |
ListWifiNetworks |
(none) | Lists available Wi-Fi networks as JSON |
Maximize |
Application name | Maximizes the application window |
Minimize |
Application name | Minimizes the application window |
MoveWindowToDesktop |
{"process": "app", "desktop": "name"} |
Moves a window to a specific virtual desktop |
Mute |
true/false |
Mutes or unmutes system audio |
NextDesktop |
(none) | Switches to the next virtual desktop |
PinWindow |
Application name | Pins a window to appear on all virtual desktops |
PreviousDesktop |
(none) | Switches to the previous virtual desktop |
quit |
(none) | Exits the application |
RestoreVolume |
(none) | Restores previously saved volume level |
SetScreenResolution |
"WIDTHxHEIGHT" or {"width": W, "height": H} |
Sets the display resolution |
SetTextSize |
100-225 |
Sets system text scaling percentage |
SetThemeMode |
"light", "dark", "toggle", or boolean |
Sets light/dark mode |
SetWallpaper |
File path | Sets the desktop wallpaper |
SwitchDesktop |
Index or name | Switches to a virtual desktop by index or name |
SwitchTo |
Application name | Brings application window to foreground |
Tile |
"app1,app2" |
Tiles two applications side-by-side |
ToggleAirplaneMode |
true/false |
Enables or disables Windows airplane mode |
ToggleNotifications |
(none) | Toggles the Windows notification center |
Volume |
0-100 |
Sets system volume percentage |
AdjustVolume |
{"direction": "up"/"down", "amount": 10} |
Adjusts volume relatively (default ±10%) |
| Command | Parameter | Description |
|---|---|---|
BluetoothToggle |
{"enableBluetooth": true/false} |
Toggles Bluetooth on/off |
EnableMeteredConnections |
(none) | Opens network status settings |
EnableWifi |
{"enable": true/false} |
Enables or disables Wi-Fi |
| Command | Parameter | Description |
|---|---|---|
AdjustColorTemperature |
(none) | Opens Night light settings |
AdjustScreenBrightness |
{"brightnessLevel": "increase"/"decrease"} |
Adjusts screen brightness ±10% |
AdjustScreenOrientation |
(none) | Opens display settings |
DisplayResolutionAndAspectRatio |
(none) | Opens display settings |
DisplayScaling |
{"sizeOverride": "150"} |
Opens display settings; targets a DPI percentage |
EnableBlueLightFilterSchedule |
{"nightLightScheduleDisabled": true/false} |
Enables or disables blue light filter schedule |
RotationLock |
{"enable": true/false} |
Enables or disables rotation lock |
| Command | Parameter | Description |
|---|---|---|
ApplyColorToTitleBar |
{"enableColor": true/false} |
Applies accent color to title bars |
EnableTransparency |
{"enable": true/false} |
Enables or disables transparency effects |
HighContrastTheme |
(none) | Opens high contrast settings |
SystemThemeMode |
{"mode": "light"/"dark"} |
Sets the system theme mode |
| Command | Parameter | Description |
|---|---|---|
AutoHideTaskbar |
{"hideWhenNotUsing": true/false} |
Auto-hides the taskbar |
DisplaySecondsInSystrayClock |
{"enable": true/false} |
Shows seconds in system tray clock |
DisplayTaskbarOnAllMonitors |
{"enable": true/false} |
Displays taskbar on all monitors |
ShowBadgesOnTaskbar |
{"enableBadging": true/false} |
Shows or hides badges on taskbar |
TaskbarAlignment |
{"alignment": "left"/"center"} |
Sets taskbar alignment |
TaskViewVisibility |
{"visibility": true/false} |
Shows or hides Task View button |
ToggleWidgetsButtonVisibility |
{"visibility": "show"/"hide"} |
Shows or hides Widgets button |
| Command | Parameter | Description |
|---|---|---|
AdjustMousePointerSize |
(none) | Opens mouse pointer settings |
CursorTrail |
{"enable": true/false, "length": 2-12} |
Enables/disables cursor trail (length: 2–12) |
EnableTouchPad |
(none) | Opens touchpad settings |
EnhancePointerPrecision |
{"enable": true/false} |
Enables or disables pointer precision |
MouseCursorSpeed |
{"speedLevel": 1-20} |
Sets mouse cursor speed (default 10) |
MousePointerCustomization |
(none) | Opens mouse pointer settings |
MouseWheelScrollLines |
{"scrollLines": 1-100} |
Sets mouse wheel scroll lines (default 3) |
SetPrimaryMouseButton |
{"primaryButton": "left"/"right"} |
Sets primary mouse button |
ToggleMouseSonar |
{"enable": true/false} |
Enables/disables "Find my pointer" Ctrl ring |
TouchpadCursorSpeed |
(none) | Opens touchpad settings |
| Command | Parameter | Description |
|---|---|---|
ManageCameraAccess |
{"accessSetting": "allow"/"deny"} |
Manages camera access |
ManageLocationAccess |
{"accessSetting": "allow"/"deny"} |
Manages location access |
ManageMicrophoneAccess |
{"accessSetting": "allow"/"deny"} |
Manages microphone access |
| Command | Parameter | Description |
|---|---|---|
BatterySaverActivationLevel |
{"thresholdValue": 0-100} |
Sets battery saver activation level |
SetPowerModeOnBattery |
(none) | Opens power settings |
SetPowerModePluggedIn |
(none) | Opens power settings |
| Command | Parameter | Description |
|---|---|---|
EnableFilterKeysAction |
(none) | Toggles Filter Keys |
EnableMagnifier |
(none) | Toggles Magnifier |
EnableNarratorAction |
(none) | Toggles Narrator |
EnableStickyKeys |
(none) | Toggles Sticky Keys |
MonoAudioToggle |
(none) | Toggles mono audio |
| Command | Parameter | Description |
|---|---|---|
ShowFileExtensions |
{"enable": true/false} |
Shows or hides file extensions |
ShowHiddenAndSystemFiles |
{"enable": true/false} |
Shows or hides hidden and system files |
| Command | Parameter | Description |
|---|---|---|
AutomaticDSTAdjustment |
{"enable": true/false} |
Enables or disables automatic DST adjustment |
AutomaticTimeSettingAction |
(none) | Opens date/time settings |
EnableGameMode |
(none) | Opens Game Mode settings |
EnableQuietHours |
(none) | Opens quiet hours / focus assist settings |
MinimizeWindowsOnMonitorDisconnectAction |
(none) | Opens display settings |
RememberWindowLocations |
(none) | Opens display settings |
Launch a program:
{"LaunchProgram": "notepad"} Set the system volume at 50%:
{"Volume": 50} Tile notepad on the left and calculator on the right of the screen:
{"Tile": "notepad,calculator"} Apply the 'dark' Windows theme:
{"ApplyTheme": "dark"} Set dark mode:
{"SetThemeMode": "dark"}Toggle between light and dark mode:
{"SetThemeMode": "toggle"}Mute the system audio:
{"Mute": true} Set the desktop wallpaper:
{"SetWallpaper": "C:\\Users\\Public\\Pictures\\wallpaper.jpg"}Quit AutoShell:
{"quit": null}Create a new virtual desktop named "Design Work":
{"CreateDesktop": "Design Work"}Toggle the Windows notification center:
{"ToggleNotifications": true}Enable airplane mode:
{"ToggleAirplaneMode": true}Disable airplane mode:
{"ToggleAirplaneMode": false}List available Wi-Fi networks:
{"ListWifiNetworks": true}Connect to a Wi-Fi network:
{"ConnectWifi": {"ssid": "MyNetwork", "password": "MyPassword123"}}Set system text size to 125%:
{"SetTextSize": 125}List available display resolutions:
{"ListResolutions": true}Set display resolution to 1920x1080:
{"SetScreenResolution": "1920x1080"}Set display resolution with specific refresh rate:
{"SetScreenResolution": "1920x1080@144"}Set display resolution using JSON object:
{"SetScreenResolution": {"width": 2560, "height": 1440, "refreshRate": 60}}Enable cursor trail with length 7:
{"CursorTrail": "{\"enable\":true,\"length\":7}"}Disable cursor trail:
{"CursorTrail": "{\"enable\":false}"}AutoShell recognizes these friendly names (case-insensitive):
chrome,edge,microsoft edgeword,winword,excel,powerpoint,power point,outlookvisual studio,visual studio codenotepad,paint,paint 3d,calculatorfile explorer,control panel,task managercmd,powershellsnipping tool,magnifierspotify,copilot,m365 copilot
Additionally, AutoShell automatically discovers all installed Windows Store applications by their display names.
AutoShell uses a handler-based architecture with dependency injection. All platform-specific (P/Invoke, COM, WMI) code is isolated behind service interfaces, keeping handlers thin and fully unit-testable.
A Roslyn source generator (autoShell.Generators) reads the .pas.json schema files at build time and generates strongly-typed C# record classes for each action's parameters. Handlers can use these generated types via AddAction<T> instead of manually extracting fields from JsonElement.
autoShell/
├── AutoShell.cs # Entry point — stdin/stdout command loop
├── ActionDispatcher.cs # Routes JSON keys to handlers; Create() wires all dependencies
├── IAppRegistry.cs # App registry interface (shared across handlers)
├── WindowsAppRegistry.cs # Maps friendly app names to paths and AppUserModelIDs
├── Handlers/
│ ├── IActionHandler.cs # Handler interface (SupportedActions + Handle)
│ ├── ActionHandlerBase.cs # Base class — AddAction/AddAction<T> registration + dispatch
│ ├── AppActionHandler.cs # LaunchProgram, CloseProgram, ListAppNames
│ ├── AudioActionHandler.cs # Volume, Mute, RestoreVolume
│ ├── DisplayActionHandler.cs # SetScreenResolution, ListResolutions, SetTextSize
│ ├── NetworkActionHandler.cs # ConnectWifi, ToggleAirplaneMode, etc.
│ ├── SystemActionHandler.cs # Debug, ToggleNotifications
│ ├── ThemeActionHandler.cs # ApplyTheme, ListThemes, SetThemeMode, SetWallpaper
│ ├── VirtualDesktopActionHandler.cs # CreateDesktop, SwitchDesktop, PinWindow, etc.
│ ├── WindowActionHandler.cs # Maximize, Minimize, SwitchTo, Tile
│ └── Settings/
│ ├── SettingsHandlerBase.cs # Extends ActionHandlerBase with registry patterns
│ ├── AccessibilitySettingsHandler.cs
│ ├── DisplaySettingsHandler.cs
│ ├── FileExplorerSettingsHandler.cs
│ ├── MouseSettingsHandler.cs
│ ├── PersonalizationSettingsHandler.cs
│ ├── PowerSettingsHandler.cs
│ ├── PrivacySettingsHandler.cs
│ ├── SystemSettingsHandler.cs
│ └── TaskbarSettingsHandler.cs
├── Services/ # Interfaces + Windows implementations
│ ├── IAudioService.cs / WindowsAudioService.cs
│ ├── IBrightnessService.cs / WindowsBrightnessService.cs
│ ├── IDebuggerService.cs / WindowsDebuggerService.cs
│ ├── IDisplayService.cs / WindowsDisplayService.cs
│ ├── INetworkService.cs / WindowsNetworkService.cs
│ ├── IProcessService.cs / WindowsProcessService.cs
│ ├── IRegistryService.cs / WindowsRegistryService.cs
│ ├── ISystemParametersService.cs / WindowsSystemParametersService.cs
│ ├── IVirtualDesktopService.cs / WindowsVirtualDesktopService.cs
│ ├── IWindowService.cs / WindowsWindowService.cs
│ └── Interop/
│ ├── CoreAudioInterop.cs # COM interop definitions for Windows audio
│ └── UIAutomation.cs # UI Automation helpers (last-resort)
├── Logging/
│ ├── ILogger.cs # Logging interface (Error, Warning, Info, Debug)
│ └── ConsoleLogger.cs # Colored console + diagnostics output
└── autoShell.Tests/ # unit, integration, and E2E tests
autoShell.Generators/ # Roslyn source generator (netstandard2.0)
├── ActionParamsGenerator.cs # IIncrementalGenerator entry point
├── SchemaParser.cs # Parses .pas.json → ActionDefinition list
└── RecordEmitter.cs # Generates C# records from ActionDefinitions
- ActionDispatcher.Create() is the composition root — it creates all concrete services and wires them into handlers. Tests bypass this and inject mocks directly.
- Single handler hierarchy — All handlers inherit from
ActionHandlerBase, which providesAddAction(name, handler)andAddAction<T>(name, handler)registration with dictionary-based dispatch. Actions are registered once in the constructor;SupportedActionsandHandle()are auto-derived. - Source-generated parameter records — The
.pas.jsonschema files ints/packages/agents/desktop/dist/are the single source of truth for action definitions. A Roslyn source generator reads them at build time and produces strongly-typed C# records (e.g.,MuteParams,VolumeParams) in theautoShell.Handlers.Generatednamespace. Handlers useAddAction<T>to get auto-deserialized parameters. - SettingsHandlerBase extends
ActionHandlerBasewith registry-specific convenience methods:AddRegistryToggleAction,AddRegistryMapAction, andAddOpenSettingsAction. These internally delegate toAddActionwith wrapper lambdas. Specialized actions useAddSpecializedActiondirectly. - Handlers are thin — they receive typed parameters and delegate to services. No P/Invoke or COM code lives in handlers.
- Services own all platform calls — P/Invoke, COM, WMI, and registry access are encapsulated behind interfaces (
I*Service/Windows*Service). - ILogger abstracts all diagnostic output with four levels: Error (red), Warning (yellow), Info (cyan), and Debug (diagnostics only).
ConsoleLoggerpreserves the original colored formatting.
The autoShell.Generators project is a Roslyn incremental source generator that runs automatically during every build of autoShell.csproj. It reads the .pas.json schema files and generates strongly-typed C# parameter records so handlers don't need to manually extract fields from raw JSON.
How it works:
- The
.pas.jsonfiles fromts/packages/agents/desktop/dist/are included asAdditionalFilesinautoShell.csproj - During compilation, the Roslyn compiler loads
autoShell.Generators.dllas an analyzer ActionParamsGenerator(theIIncrementalGeneratorentry point) filters for.pas.jsonfiles and passes each to the pipelineSchemaParserextracts action definitions — action name, parameter names, and types — from the schema JSON structureRecordEmitterproduces C# source for each action, emittinginternal recordclasses with[JsonPropertyName]attributes- The compiler compiles the generated records alongside the hand-written source code
Project structure:
| File | Purpose |
|---|---|
ActionParamsGenerator.cs |
IIncrementalGenerator entry point — wires the pipeline |
SchemaParser.cs |
Parses .pas.json → list of ActionDefinition (action name + parameter fields) |
RecordEmitter.cs |
Generates C# record source from ActionDefinition list |
Generated output:
The generated .g.cs files are emitted to autoShell/Generated/ for inspection (gitignored — they're build artifacts). Each .pas.json schema produces one file:
| Schema | Generated file | Example records |
|---|---|---|
desktopSchema.pas.json |
desktopSchema.pas.g.cs |
VolumeParams, MuteParams, LaunchProgramParams |
taskbarSchema.pas.json |
taskbarSchema.pas.g.cs |
AutoHideTaskbarParams, TaskbarAlignmentParams |
displaySchema.pas.json |
displaySchema.pas.g.cs |
DisplayScalingParams, RotationLockParams |
| ... | ... | ... |
Type mapping:
.pas.json type |
C# type | Default |
|---|---|---|
number |
int |
0 |
boolean |
bool |
false |
string |
string |
"" |
string-union |
string |
"" |
type-union |
resolved inner type | varies |
| Optional field | nullable (int?, bool?, string?) |
null |
Constraints:
- Targets
netstandard2.0(Roslyn requirement for source generators) - References
Microsoft.CodeAnalysis.CSharpandSystem.Text.JsonasPrivateAssets="all" - Referenced by
autoShell.csprojasOutputItemType="Analyzer"withReferenceOutputAssembly="false"
This section walks through adding a new action end-to-end. There are three categories of actions, each with a different amount of work required.
For actions that toggle a registry value or map a string parameter to a registry entry, you only need to add a line in an existing settings handler constructor. No new files, no new classes.
Example — adding a new registry toggle:
// In an existing SettingsHandler constructor (e.g., SystemSettingsHandler.cs):
AddRegistryToggleAction("MyNewToggle", new RegistryToggleConfig(
KeyPath: @"SOFTWARE\Microsoft\Windows\CurrentVersion\MyFeature",
ValueName: "Enabled",
ParameterName: "enable",
OnValue: 1,
OffValue: 0,
DisplayName: "My New Feature"
));That's it. The base class handles parameter extraction, registry writes, and success/failure responses. Other config-driven options:
AddRegistryMapAction— maps a string parameter (e.g.,"left"/"center") to registry valuesAddOpenSettingsAction— opens a Windows Settings URI (e.g.,ms-settings:display)
For actions that need custom logic but fit within an existing handler's domain.
1. Define the action in the TypeScript schema (e.g., ts/packages/agents/desktop/src/actionsSchema.ts):
The TypeScript type definitions are the single source of truth. The asc compiler transforms them into .pas.json files, which the Roslyn source generator then reads to produce C# parameter records.
// In the appropriate *Schema.ts file:
export type MyNewAction = {
actionName: "MyAction";
parameters: {
level: number;
name?: string;
};
};Then regenerate the schema:
cd ts/packages/agents/desktop
pnpm run asc:allAfter building, this generates:
// Auto-generated in autoShell.Handlers.Generated namespace
internal record MyActionParams
{
[JsonPropertyName("level")]
public int Level { get; init; } = 0;
[JsonPropertyName("name")]
public string? Name { get; init; } = null;
}2. Register and handle the action in the appropriate handler:
using autoShell.Handlers.Generated;
internal class AudioActionHandler : ActionHandlerBase
{
public AudioActionHandler(IAudioService audio)
{
// ... existing actions ...
AddAction<MyActionParams>("MyAction", HandleMyAction);
}
private ActionResult HandleMyAction(MyActionParams p)
{
// p.Level and p.Name are already deserialized and typed
return ActionResult.Ok($"Did something with level {p.Level}");
}
}That's all the C# you need. The dispatcher automatically discovers the action through the handler's SupportedActions.
For actions that require a new Windows API or a new domain.
1. Define the schema in the TypeScript schema file and run pnpm run asc:all (same as Option B, step 1).
2. Create a service interface and implementation:
// Services/IMyService.cs
internal interface IMyService
{
void DoSomething(int level);
}
// Services/WindowsMyService.cs
internal class WindowsMyService : IMyService
{
public void DoSomething(int level)
{
// P/Invoke, COM, WMI, etc.
}
}3. Create a handler:
// Handlers/MyActionHandler.cs
using autoShell.Handlers.Generated;
using autoShell.Services;
internal class MyActionHandler : ActionHandlerBase
{
private readonly IMyService _myService;
public MyActionHandler(IMyService myService)
{
_myService = myService;
AddAction<MyActionParams>("MyAction", HandleMyAction);
}
private ActionResult HandleMyAction(MyActionParams p)
{
_myService.DoSomething(p.Level);
return ActionResult.Ok($"Done at level {p.Level}");
}
}4. Wire it in ActionDispatcher.Create():
// In ActionDispatcher.cs, Create() method:
dispatcher.Register(
// ... existing handlers ...
new MyActionHandler(new WindowsMyService())
);5. Add the service to the testable Create() overload so tests can inject a mock.
The source generator maps .pas.json types to C# as follows:
| Schema type | C# type | Default value |
|---|---|---|
number |
int |
0 |
boolean |
bool |
false |
string |
string |
"" |
string-union |
string |
"" |
| Optional field | nullable (int?, bool?, string?) |
null |
- Action type defined in TypeScript schema (
*Schema.ts) - Schemas regenerated with
pnpm run asc:all - Handler method registered with
AddAction<T>in the constructor - Handler registered in
ActionDispatcher.Create()(if new handler) - Service interface + implementation created (if new Windows API)
- Unit tests added for the handler logic
-
dotnet test --filter "Category!=E2E"passes
Copyright (c) Microsoft Corporation. Licensed under the MIT License.
This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft trademarks or logos is subject to and must follow Microsoft's Trademark & Brand Guidelines.