M365 Toolbox is a web-based console for approved Microsoft 365 PowerShell operations. It combines a React frontend, an Express API, a Redis-backed BullMQ queue, a PostgreSQL-backed run store, a dedicated PowerShell worker, and a toolbox-native script catalog so admins can launch reports and response workflows from the browser, authenticate with Microsoft device code, and review results without leaving the app.
- Presents a categorized script catalog for Microsoft 365 operations
- Runs allowlisted PowerShell scripts through a controlled backend wrapper
- Requires sign-in with local Toolbox users or Microsoft Entra ID
- Enforces role-based authorization for administrators, privileged users, and restricted users
- Prompts for Microsoft device-code sign-in when a script requires authentication
- Tracks run status, command details, stdout, stderr, exit code, and artifacts
- Renders HTML reports inline in the UI and supports direct download
- Stores favorites in the browser for faster access to common workflows
The current catalog includes 59 toolbox-native scripts across categories such as Identity, Exchange, Security, SharePoint, Teams, Reporting, Licensing, Devices, Operations, Collaboration, and Incident Response.
backend/Express API, queue integration, run tracking, artifact endpoints, and worker health reportingfrontend/React/Vite UI with the resizable sidebar, category icons, dark mode, favorites, dashboard shortcuts, run details, and inline report previewscripts/Toolbox-native PowerShell scripts, the script wrapper, and shared report helpersscripts/catalog/JSON catalog files that define script metadata, fields, risk, and runner behavioroutput/Generated report artifacts written by backend runsdocker-compose.ymlSingle Docker Compose deployment for local and self-hosted use, including PostgreSQL, Redis, a one-shot migration job, the backend, the PowerShell worker, and the frontend.env.exampleExample environment file for self-hosted deployments
- Resizable left sidebar for the script catalog
- Search and category browsing in the catalog
- Category icons in the sidebar for faster scanning
- Read-only versus remediation mode labeling and filtering
- Favorites toggle and favorites-only filtering
- Dark mode toggle
- Better dashboard home screen with quick stats and shortcuts
- Recent favorites and most-used shortcuts on the dashboard
- Persistent run history in the UI
- Queue-aware execution with queued run status
- Run cancellation from the UI
- Structured run logs, timestamps, and clearer run-state feedback
- Artifact browser for HTML, CSV, XLSX, text, and log downloads
- ZIP bundle download for full run artifact packages
- Inline HTML report preview after successful runs, with the report brought into focus automatically
- Device-code modal that surfaces the sign-in code, copy action, and login URL
- Approval confirmation prompt for remediation workflows
- Action profiles and high-impact action guidance for the compromised-account workflow
- Backend status view for Redis, queue, worker heartbeat, script mount, and output path readiness
- GitHub repository link in the sidebar footer
Core workflows and reporting:
scripts/M365-CompromisedAccountRemediation.ps1Contains and investigates compromised accounts with review-only and containment profiles, recent sign-in review, optional delegate cleanup and protocol lock-down, and a richer incident dashboard.scripts/M365-MfaReport.ps1Builds a tenant-wide MFA coverage report with admin-risk visibility.scripts/M365-UsageReport.ps1Creates OneDrive, SharePoint, and mailbox usage dashboards.scripts/M365-LicensingReport.ps1Reviews subscribed SKUs, assigned licenses, and unlicensed users.scripts/M365-GuestAccessReport.ps1Audits guest accounts, invitation state, stale guests, and external domains.scripts/M365-ConditionalAccessReport.ps1Summarizes Conditional Access policies, state, scope, and grant controls.scripts/M365-MailForwardingAudit.ps1Finds mailbox forwarding and inbox rules that redirect mail.scripts/M365-SharedMailboxReport.ps1Reviews shared mailboxes, forwarding, visibility, and delegate counts.scripts/M365-ImapMigrationPreflight.ps1Validates mounted IMAP migration CSV readiness, Exchange Online sign-in, and source IMAP endpoint availability.scripts/M365-ImapMigrationBatch.ps1Creates or reuses an Exchange Online IMAP migration endpoint, creates a migration batch from CSVData, and can optionally start it.scripts/M365-ImapMigrationStatus.ps1Exports current Exchange Online migration batch summary and per-user migration status.scripts/M365-SignInRiskReport.ps1Shows risky users and detections when Identity Protection data is licensed and available.scripts/M365-TeamsExternalAccessReport.ps1Reviews Teams guest exposure, ownership gaps, and external membership.scripts/M365-SharePointSharingReport.ps1Combines SharePoint tenant sharing settings with site usage inventory.scripts/M365-SecureScoreSnapshot.ps1Captures the latest Secure Score snapshot and top improvement controls.scripts/M365-AdminRoleAudit.ps1Audits privileged role assignments and MFA hygiene for admin accounts.
Audit, hygiene, and operations reports:
scripts/M365-InactiveUsersReport.ps1Identifies inactive accounts and likely license-reclaim candidates.scripts/M365-AppConsentAudit.ps1Reviews enterprise app consent grants and high-privilege delegated scopes.scripts/M365-MailboxPermissionAudit.ps1Audits Full Access and Send As delegation across mailboxes.scripts/M365-ExternalSharingLinksReport.ps1Reviews SharePoint external sharing posture and site-level sharing link counts.scripts/M365-DistributionGroupAudit.ps1Audits distribution group ownership, membership, and external sender exposure.scripts/M365-ServiceHealthSnapshot.ps1Captures current Microsoft 365 service health and active advisories.scripts/M365-AuthenticationPolicyReport.ps1Reviews security defaults and authentication methods policy posture.scripts/M365-PrivilegedAppAudit.ps1Inventories service principal credentials and non-human identity exposure.scripts/M365-DkimDmarcReport.ps1Reviews accepted domains for DKIM signing and DMARC presence.scripts/M365-GroupLifecycleReport.ps1Audits Microsoft 365 group ownership, renewal activity, and lifecycle hygiene.
Latest additions:
scripts/M365-CAPolicyCoverageReport.ps1Maps Conditional Access inclusion and exclusion coverage across users, groups, guests, and apps.scripts/M365-LegacyAuthExposureReport.ps1Surfaces recent legacy-authentication sign-ins and affected users.scripts/M365-PIMRoleActivationReport.ps1Reviews active and eligible privileged role schedule instances from Entra ID.scripts/M365-DeviceComplianceSnapshot.ps1Summarizes Intune-managed device compliance, ownership, and platform mix.scripts/M365-B2BDirectConnectReport.ps1Reviews cross-tenant access defaults and B2B direct connect posture.scripts/M365-MailTransportRulesAudit.ps1Audits Exchange Online mail transport rules and test/audit mode coverage.scripts/M365-DefenderIncidentSnapshot.ps1Captures current Defender incidents, severity, and status.scripts/M365-PrivilegedGroupAudit.ps1Reviews sensitive groups for owner gaps and membership exposure.scripts/M365-PasswordResetReadinessReport.ps1Estimates self-service password reset readiness from registered auth methods.scripts/M365-OneDriveExternalSharingReport.ps1Reviews OneDrive usage and highlights large or highly active personal sites.scripts/M365-MFARegistrationCampaignReport.ps1Reviews MFA registration campaign settings and rollout posture.scripts/M365-EnterpriseAppsInventory.ps1Inventories enterprise applications for ownership, visibility, and risk review.scripts/M365-GuestInvitationFailures.ps1Surfaces guest invitation issues and onboarding failures for follow-up.scripts/M365-MailboxAutoReplyAudit.ps1Reviews mailbox automatic replies for external exposure and operational awareness.scripts/M365-CalendarSharingAudit.ps1Audits mailbox calendar sharing posture and external visibility.scripts/M365-RoleEligibleAssignmentsReport.ps1Reviews eligible privileged role assignments and standing access exposure.scripts/M365-AnonymousLinkExposureReport.ps1Highlights anonymous sharing links and externally accessible content exposure.scripts/M365-TeamsOwnershipAudit.ps1Reviews Microsoft Teams ownership gaps and governance hygiene.scripts/M365-AppCredentialExpiryReport.ps1Finds expiring or stale application credentials that need rotation.scripts/M365-MailflowConnectorAudit.ps1Reviews inbound and outbound Exchange Online connectors, relay paths, and TLS posture.scripts/M365-BreakGlassAccountAudit.ps1Reviews emergency access accounts for privilege, MFA, and recent sign-in visibility.scripts/M365-ImpossibleTravelReview.ps1Highlights rapid country-to-country sign-in changes for the same user.scripts/M365-MailboxLoginAnomalyReview.ps1Reviews mailbox-related sign-ins with suspicious client, failure, or access patterns.scripts/M365-ExternalTenantTrustReview.ps1Summarizes cross-tenant partner trust settings and guest domain concentration.scripts/M365-PrivilegedUserSignInReview.ps1Reviews recent sign-in visibility for privileged users across directory roles.scripts/M365-InboxRuleThreatHunt.ps1Hunts for suspicious inbox rules that forward, redirect, hide, or delete messages.scripts/M365-ConditionalAccessGapReview.ps1Highlights Conditional Access policies with exclusions, missing controls, or weak enforcement.scripts/M365-MFAExclusionAudit.ps1Audits MFA-enforcing policies that still exclude users, groups, or roles.scripts/M365-DormantAdminAccountReview.ps1Finds privileged accounts with little or no recent sign-in activity.scripts/M365-SharedMailboxAbuseReview.ps1Reviews shared mailboxes for forwarding, risky delegates, and inbox rule abuse signals.scripts/M365-TransportRuleThreatHunt.ps1Flags transport rules with redirect, bypass, delete, or routing threat signals.scripts/M365-BreakGlassAccountHardeningReview.ps1Reviews likely break-glass accounts for MFA, state, and hardening posture.scripts/M365-OAuthAppRiskReview.ps1Highlights OAuth-enabled apps with delegated grants, risky scopes, and credential risk.
The catalog loader lives in backend/src/data/scripts.js, the catalog source files live in scripts/catalog, and the PowerShell entry scripts live in scripts.
The backend loads script metadata from the JSON catalog, accepts validated run requests, persists queued run records in PostgreSQL, and hands execution to BullMQ. A separate PowerShell worker container reads queued jobs, launches scripts/Invoke-ToolboxScript.ps1, captures structured events and artifacts, and writes incremental logs, artifacts, approvals, and result metadata back to PostgreSQL while keeping report files in output/.
The backend tracks:
- selected script id
- generated command line
- stdout
- stderr
- structured log entries
- run status
- queued, running, canceling, completed, failed, canceled, and interrupted lifecycle states
- exit code
- timestamps
- artifact inventory for exported files
The Settings page can store reusable company mappings in PostgreSQL. Administrators add a Company Name and a Tenant ID or Domain, then operators type either the company name, tenant id, or domain in a script tenant field to resolve it before launch.
Company mappings can be imported or exported as CSV. Use two columns:
Company Name,Tenant ID or Domain
Contoso,contoso.onmicrosoft.com
Fabrikam,fabrikam.com
Northwind,00000000-0000-0000-0000-000000000000The header row is optional but recommended. If a company name contains a comma, wrap it in quotes, for example "Contoso, Ltd.",contoso.onmicrosoft.com.
M365 Toolbox shows a login page before the app shell. The backend creates a local administrator on startup if it does not already exist:
- username:
admin - password:
admin - role:
administrator
The password is stored as a bcrypt hash, and the default account is marked for password change. After first login, open Settings and change the password before using the toolbox for production work. Existing admin accounts are never overwritten or reset by startup.
Roles are enforced by the backend:
administrator: can run every script, edit company mappings, edit authentication settings, manage local users, assign user roles, and manage Microsoft group role mappings.privileged_user: can run every script, but cannot edit administrator-only settings.restricted_user: can run only non-remediation scripts. Remediation and high-impact workflows are blocked with403even if called directly through the API.
Local users authenticate with the username and password stored in PostgreSQL. Administrators can manage local users from Settings → Users, including creating users, editing profile details, assigning roles, resetting local passwords, and removing users. The app prevents administrators from removing their own signed-in account or leaving the toolbox without another administrator. Microsoft users authenticate in the SPA through MSAL, then the backend validates the Microsoft access token against Entra OpenID/JWKS metadata and creates a Toolbox session cookie. Microsoft user roles are assigned from Entra group role mappings when the user signs in.
Administrators configure Microsoft login in the Toolbox UI under Settings → Microsoft App Registration Configuration. Use the local admin account for the initial setup, then switch to Microsoft sign-in after the configuration and group mappings are saved.
This integration uses a browser SPA sign-in flow with MSAL. Do not create or paste a client secret into Toolbox; the app only stores tenant/app IDs and validates Microsoft access tokens on the backend.
- A Microsoft Entra tenant ID.
- Permission to create or update Entra app registrations.
- At least one Entra security group for Toolbox access. Use group object IDs whenever possible.
- The public Toolbox frontend origin:
- local development:
http://localhost:5173 - default production compose:
http://localhost:8080 - hosted production example:
https://toolbox.example.com
- local development:
The redirect URI must exactly match the origin shown in the Toolbox Settings page under Redirect URI.
- In Microsoft Entra admin center, open App registrations → New registration.
- Name it, for example
M365 Toolbox API. - Use
Accounts in this organizational directory onlyunless you intentionally support another tenant model. - After creation, copy the
Application (client) ID. This is the ToolboxBackend API Audiencevalue. - Open
Expose an API. - Set the Application ID URI to
api://<backend-api-client-id>if Entra has not already generated one. - Add a delegated scope:
- Scope name:
access_as_user - Who can consent:
Admins and usersorAdmins only, depending on tenant policy - Admin consent display name:
Access M365 Toolbox - Admin consent description:
Allows the Toolbox frontend to call the Toolbox API as the signed-in user - State: enabled
- Scope name:
- Open
Token configurationand add agroupsclaim to access tokens. Prefer group object IDs. If your tenant emits group overage claims because the user belongs to many groups, Microsoft login will be rejected until the token contains usable group claims for this API.
- In App registrations → New registration, create another app, for example
M365 Toolbox Frontend. - In
Authentication, add a platform of typeSingle-page application. - Add the Toolbox frontend origin as the redirect URI, for example
https://toolbox.example.comorhttp://localhost:5173for local development. - Keep implicit grant unchecked unless you have a separate reason to enable it. MSAL uses the authorization-code-with-PKCE flow for SPAs.
- Copy the
Application (client) ID. This is the ToolboxFrontend Client IDvalue. - In
API permissions, add a permission →My APIs→ select the backend API app → delegated permissions →access_as_user. - Grant admin consent if your tenant requires it.
- Sign in with the local administrator account.
- Open Settings →
Microsoft App Registration Configuration. - Fill in:
Tenant ID: your Entra tenant ID.Frontend Client ID: the application/client ID of the frontend SPA app.Backend API Audience: the application/client ID of the backend API app. Toolbox derives the login scope asapi://<backend-api-client-id>/access_as_user.Authority URL: optional. Leave blank to usehttps://login.microsoftonline.com/<tenant-id>, or set that exact tenant authority if needed.
- Check
Enable Microsoft login. - Save the Microsoft configuration.
Under Entra Group Role Mappings, add one or more mappings:
Entra Group Name: a human-readable group name for operators.Group Object ID: the Entra group object ID. This is strongly recommended because token group names are not always emitted.Assigned Role: one of:administrator: can run every script and manage settings.privileged_user: can run every script but cannot manage administrator-only settings.restricted_user: can run non-remediation scripts only.
Role resolution prefers group object IDs. Group-name matching is only used when a mapping has no object ID and the token contains safe group-name claims. If no mapping matches, or if Microsoft sends group overage claims instead of actual groups, login fails with an authorization error.
- Sign out of Toolbox or open a private browser window.
- Select
Sign in with Microsofton the login page. - Complete the Microsoft prompt.
- Confirm the Toolbox user menu shows your Microsoft identity and expected role.
If sign-in fails, verify the redirect URI, tenant ID, frontend client ID, backend API audience, API permission, admin consent, group claims, and group object ID mapping.
High-level flow:
Frontend
-> API backend
-> BullMQ / Redis
-> PowerShell worker
-> Artifacts + PostgreSQL run store
Runtime controls available through environment variables:
MAX_CONCURRENT_RUNSLimits how many worker jobs can execute at the same time. Extra runs stay queued until a slot opens.DATABASE_URLControls how the API and worker connect to PostgreSQL for run history, logs, artifacts, approvals, and result metadata.RUN_STATE_DIRControls the directory used for worker heartbeat files and optional legacy file-run imports.OUTPUT_DIRControls where generated artifacts and worker heartbeat files are written.TOOLBOX_SCRIPT_MOUNT_ROOTControls where the worker resolves toolbox PowerShell scripts.REDIS_URLControls how the API and worker connect to Redis for BullMQ.ARTIFACT_TOKEN_SECRETSigns short-lived artifact, HTML preview, and ZIP bundle URLs.AUTH_SESSION_SECRETSigns Toolbox HTTP-only session cookies. Use a long random value in production.AUTH_SESSION_TTL_SECONDSOptional session lifetime override. Defaults to 8 hours.
By default, Docker mounts:
./scriptsto/toolbox-scripts./outputto/app/output
Local and container startup both run Prisma migrations before the API or worker starts. You can also run them manually:
npm run db:migrateTo import legacy JSON run files from older builds into PostgreSQL:
npm run migrate:file-runsThe importer skips duplicate run ids, preserves artifacts on disk, and does not delete the old JSON files automatically.
The IMAP migration workflows orchestrate Exchange Online migration cmdlets. They do not connect to source IMAP mailboxes from Node, React, or local script code, and they do not implement a custom mailbox copy engine. Microsoft 365 migration services perform the mailbox sync after Exchange Online PowerShell creates the endpoint and batch.
Available workflows:
M365 IMAP Migration PreflightValidates the CSV path and schema, connects to Exchange Online, tests IMAP endpoint availability, and writes a readiness report.M365 IMAP Migration BatchCreates or reuses the IMAP migration endpoint, creates the migration batch from CSVData, optionally starts it, and exports batch/per-user artifacts.M365 IMAP Migration StatusReads an existing migration batch and exports the current summary and per-user statistics.
Prerequisites:
- The signed-in admin needs sufficient Exchange Online permissions to manage migration endpoints and batches.
- Target Microsoft 365 mailboxes must already exist and be licensed before migration.
- The source IMAP server must be reachable by Microsoft 365 migration services on the selected host, port, and security mode.
- IMAP migration moves mail only. It does not migrate contacts, calendars, tasks, mailbox rules, permissions, or client profiles.
- Mailbox size, item, and message size behavior still follows Exchange Online migration service limits.
CSV security and format:
Mailbox passwords must not be entered into the browser. Store the migration CSV in a local folder that is mounted into the backend container, then provide the container path in the toolbox form or set M365_TOOLBOX_IMAP_MIGRATION_CSV_PATH. The scripts validate the CSV and redact sensitive values from logs, reports, diagnostics, and artifact names.
Expected CSV headers:
EmailAddress,UserName,Password,UserRoot
target.user@contoso.com,<source-user>,<source-password>,Required headers are EmailAddress, UserName, and Password. UserRoot is optional for IMAP servers that require a virtual shared folder root.
Example compose mount:
services:
backend:
volumes:
- ./scripts:/toolbox-scripts:ro
- ./output:/app/output
- ./migration-input:/migration-input:ro
environment:
M365_TOOLBOX_IMAP_MIGRATION_CSV_PATH: /migration-input/imap-mailboxes.csvRecommended operating sequence:
- Run
M365 IMAP Migration Preflightwith the endpoint name, IMAP server, port, security mode, and CSV path or environment-backed path. - If preflight is ready, run
M365 IMAP Migration Batchwith the same endpoint settings and a unique batch name. Select auto-start only when you are ready for Microsoft 365 to begin syncing. - Run
M365 IMAP Migration Statuswith the batch name to review batch summary and per-user migration progress.
- The frontend loads the script catalog from the backend API.
- You select a script from the sidebar and fill in its approved input fields.
- The backend transforms those values into a controlled
pwshinvocation. - The script runs and the UI polls for status updates.
- If the backend concurrency limit is busy, the run stays queued until a slot opens.
- If a remediation workflow is selected, the UI requires explicit approval confirmation before launch.
- If a Microsoft device-code prompt appears in stdout or stderr, the UI opens a sign-in modal with the code, a copy button, and a direct login link.
- If the script generates artifacts, the backend serves them back for browsing, preview, and download.
- If an HTML report is generated, the UI collapses the other run cards and scrolls the report preview into view.
Docker Compose is the easiest way to deploy the project because it builds both services, wires the frontend to the backend, and mounts the folders used for scripts and generated output.
What Compose starts:
postgresInternal PostgreSQL service for persistent run history, logs, artifacts, approvals, and result metadatabackendNode/Express API, run persistence, queue endpoints, and artifact servingworkerDedicated PowerShell execution container that consumes BullMQ jobsredisInternal Redis service for BullMQ queues, retries, and dead-letter handlingfrontendNginx container serving the built React app
Named containers in the default and production compose files:
m365-toolbox-postgresm365-toolbox-redism365-toolbox-backendm365-toolbox-workerm365-toolbox-frontend
What Compose mounts:
./scriptsinto the backend container at/toolbox-scriptsas read-only./scriptsinto the worker container at/toolbox-scriptsas read-only./outputinto the backend container at/app/outputfor generated artifacts./outputinto the worker container at/app/outputfor generated artifacts
What Compose exposes:
http://localhost:5173for the frontendhttp://localhost:3001for the backend API
Compose setup:
docker-compose.ymlSingle Compose file for both local and self-hosted deployments.env.exampleCopy this to.envand set production values before deploying on a server
For server deployments, provide a .env file for Docker Compose. Docker Compose uses it for substitutions such as ${ARTIFACT_TOKEN_SECRET}, ${AUTH_SESSION_SECRET}, ${FRONTEND_ORIGIN}, and ${FRONTEND_PORT}.
The .env file is not created automatically. Create it once per deployment environment and include the values below.
Copy .env.example to .env and replace the example values:
FRONTEND_ORIGIN=https://toolbox.example.com
FRONTEND_PORT=5173
ARTIFACT_TOKEN_SECRET=replace-with-a-long-random-secret
AUTH_SESSION_SECRET=replace-with-another-long-random-secret
# CORS_ALLOW_PRIVATE_NETWORK=true
# DATABASE_URL=postgresql://m365:m365password@postgres:5432/m365_toolboxMinimum recommended production values:
FRONTEND_ORIGINARTIFACT_TOKEN_SECRETAUTH_SESSION_SECRET
Optional values:
FRONTEND_PORTDATABASE_URLPOSTGRES_DBPOSTGRES_USERPOSTGRES_PASSWORDREDIS_URLCORS_ALLOW_PRIVATE_NETWORK
Leave DATABASE_URL commented unless you are using an external PostgreSQL database. The bundled PostgreSQL service works with the default connection string already defined in docker-compose.yml.
Generate strong secrets with OpenSSL. Run this command twice and use a different value for each secret:
openssl rand -base64 48Example production .env after replacing placeholders:
FRONTEND_ORIGIN=https://m365toolbox.example.com
FRONTEND_PORT=5173
ARTIFACT_TOKEN_SECRET=generated-artifact-secret-goes-here
AUTH_SESSION_SECRET=generated-session-secret-goes-here
# CORS_ALLOW_PRIVATE_NETWORK=trueVariable notes:
FRONTEND_ORIGINPublic URL used by backend CORS validation. Set this to the exact browser-facing origin, for examplehttps://toolbox.example.com. Do not include a path.FRONTEND_PORTHost port mapped to the frontend container. Defaults to5173when omitted.ARTIFACT_TOKEN_SECRETRequired in production. Use a long random value. It signs artifact, HTML preview, and ZIP bundle links.AUTH_SESSION_SECRETRequired in production. Use a different long random value for HTTP-only login sessions. M365 Toolbox now fails fast at startup in production if this variable is missing.CORS_ALLOW_PRIVATE_NETWORKOptional. Defaults to disabled. Settrueonly when you intentionally want to allow browser origins on private IPv4 networks like10.x,192.168.x, or172.16-31.xin addition toFRONTEND_ORIGINand localhost.DATABASE_URLOptional. Leave commented when using the bundled PostgreSQL service. Set it only when using an external or platform-managed database.
Verify Docker Compose can read the file:
docker compose configIf the command prints the fully rendered Compose configuration, the .env file is being loaded correctly.
Keep .env private. Do not commit it, paste it into tickets, or share it in logs.
Default deployment steps:
From the repository root:
docker compose up -d --buildThe stack runs in this order:
postgresandredisstartmigrateruns Prisma migrations oncebackendstarts and becomes healthyworkerstartsfrontendstarts after the backend health check passes
After deployment:
- Frontend:
http://localhost:5173unless overridden byFRONTEND_PORT - Backend health from inside Docker:
http://backend:3001/api/health
Useful Docker Compose commands:
docker compose ps
docker compose logs -f
docker compose logs -f backend
docker compose logs -f worker
docker compose logs -f redis
docker compose logs -f frontend
docker compose downSelf-hosted deployment:
From the repository root:
docker compose up -d --buildRecommended production overrides:
FRONTEND_ORIGINPublic frontend URL used by backend CORS validation, for examplehttps://m365toolbox.domain.comFRONTEND_PORTHost port mapped to the frontend container when you do not want the default5173DATABASE_URLOptional PostgreSQL connection string override if you are not using the bundledpostgresservice defaultsARTIFACT_TOKEN_SECRETStrong secret used for signed artifact and report preview linksAUTH_SESSION_SECRETStrong secret used for HTTP-only login sessions
Example:
$env:FRONTEND_ORIGIN="https://toolbox.example.com"
$env:FRONTEND_PORT="80"
$env:ARTIFACT_TOKEN_SECRET="replace-with-a-long-random-secret"
$env:AUTH_SESSION_SECRET="replace-with-another-long-random-secret"
docker compose up -d --build- runtime values are expected to be supplied by the platform UI
Recommended variables for Coolify or Portainer:
FRONTEND_ORIGINSet this to the public URL of the deployed frontend, for examplehttps://toolbox.example.com. The backend normalizes the value to its origin, so an optional trailing slash or pasted path is tolerated.FRONTEND_PORTOptional host port override if you are not using a platform-managed proxyDATABASE_URLOptional PostgreSQL connection string override if your platform manages the database separatelyARTIFACT_TOKEN_SECRETRequired HMAC secret used for signed artifact, HTML preview, and ZIP bundle linksAUTH_SESSION_SECRETRequired secret used for HTTP-only login sessions
When to rebuild:
- Rebuild
backendandworkerif you change backend code or PowerShell module installation - Rebuild
frontendif you change the React UI and want the containerized build updated - Rebuild everything if you change shared package metadata or Dockerfiles
- You do not need an image rebuild for normal edits inside
scripts/orscripts/catalog/when those folders are mounted from the host
Examples:
docker compose build backend
docker compose up -d backend worker redisdocker compose build frontend
docker compose up -d frontendNotes for deployment:
- The backend persists run history in PostgreSQL, so completed runs remain visible after backend and worker restarts.
- Generated artifacts remain in the host
output/folder because it is mounted into the container. - Scripts are loaded from the host
scripts/folder, so keep that directory in place on the machine running Docker Compose. - The Coolify or Portainer-friendly compose file stores artifacts in a Docker-managed volume instead of the host
output/folder.
Install workspace dependencies from the repository root:
npm installThe repo includes a committed package-lock.json, so CI uses npm ci for repeatable installs.
Start both apps together:
npm run devThat starts:
- API backend on
http://localhost:3001 - PowerShell worker in watch mode
- frontend dev server on
http://localhost:5173
Before local development, make sure Redis is available on redis://127.0.0.1:6379 or set REDIS_URL to your local Redis endpoint. The frontend Vite config proxies /api requests to the backend during local development.
- Run history is persisted in PostgreSQL so completed runs survive backend and worker restarts.
- Running or queued jobs are marked as interrupted if the backend restarts before they finish.
- Toolbox-native scripts are served only from
scripts/; there is no external PowerShell repository mount. - Shared helpers such as
Shared-ToolboxReport.ps1support common HTML dashboard rendering and output handling. - The backend API exposes script listing, run creation, run status, cancellation, artifact listing, artifact download, HTML preview, queue status, and backend status endpoints.
- Input values are validated on the backend before PowerShell execution starts.
- Run retention is controlled by backend retention settings so old run records do not accumulate forever.
- CORS is restricted to configured origins, localhost, and private IPv4 ranges.
The current implementation focuses on safe execution, persistent run visibility, and better operator feedback. The next natural product steps are:
- richer approval workflows with requester and approver identities
- stronger artifact management and retention controls
- localization when multilingual support becomes a priority
- alternative auth flows such as certificate-based or app-based execution where appropriate