This commit is contained in:
2026-06-25 12:30:55 -05:00
parent f31fcd9e84
commit 8c60e154a7
13 changed files with 1163 additions and 13 deletions

2
.gitignore vendored
View File

@@ -1,6 +1,6 @@
node_modules/ node_modules/
dist/ dist/
data/ /data/
.env .env
.env.* .env.*
!.env.example !.env.example

View File

@@ -5,7 +5,7 @@
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "concurrently -n API,UI -c cyan,magenta \"npm run api:dev\" \"npm run ui:dev\"", "dev": "concurrently -n API,UI -c cyan,magenta \"npm run api:dev\" \"npm run ui:dev\"",
"prod": "node scripts/ensure-build.mjs && concurrently -n API,UI -c cyan,magenta \"npm run api:prod\" \"npm run ui:prod\"", "prod": "node scripts/ensure-build.mjs && node scripts/smoke-api-import.mjs && concurrently -n API,UI -c cyan,magenta \"npm run api:prod\" \"npm run ui:prod\"",
"api:dev": "node scripts/start-api.mjs development --watch", "api:dev": "node scripts/start-api.mjs development --watch",
"api:prod": "node scripts/start-api.mjs production", "api:prod": "node scripts/start-api.mjs production",
"ui:dev": "vite --host 0.0.0.0 --port 3000 --strictPort", "ui:dev": "vite --host 0.0.0.0 --port 3000 --strictPort",

View File

@@ -5,9 +5,6 @@ if (fs.existsSync('dist/index.html')) {
process.exit(0); process.exit(0);
} }
const result = spawnSync('npm', ['run', 'build'], { const result = spawnSync(process.execPath, ['node_modules/vite/bin/vite.js', 'build'], { stdio: 'inherit' });
stdio: 'inherit',
shell: process.platform === 'win32'
});
process.exit(result.status ?? 1); process.exit(result.status ?? 1);

View File

@@ -0,0 +1,2 @@
await import('../server/forms/schemas.js');
await import('../server/services/graphService.js');

View File

@@ -2,12 +2,12 @@ import { spawn } from 'node:child_process';
const mode = process.argv[2] || 'development'; const mode = process.argv[2] || 'development';
const watch = process.argv.includes('--watch'); const watch = process.argv.includes('--watch');
const command = watch ? 'nodemon' : 'node'; const args = watch
const args = watch ? ['server/index.js'] : ['server/index.js']; ? ['node_modules/nodemon/bin/nodemon.js', 'server/index.js']
: ['server/index.js'];
const child = spawn(command, args, { const child = spawn(process.execPath, args, {
stdio: 'inherit', stdio: 'inherit',
shell: process.platform === 'win32',
env: { env: {
...process.env, ...process.env,
NODE_ENV: mode NODE_ENV: mode

View File

@@ -1,8 +1,7 @@
import { spawn } from 'node:child_process'; import { spawn } from 'node:child_process';
const child = spawn('vite', ['preview', '--host', '0.0.0.0', '--port', '3000', '--strictPort'], { const child = spawn(process.execPath, ['node_modules/vite/bin/vite.js', 'preview', '--host', '0.0.0.0', '--port', '3000', '--strictPort'], {
stdio: 'inherit', stdio: 'inherit',
shell: process.platform === 'win32',
env: { env: {
...process.env, ...process.env,
NODE_ENV: 'production' NODE_ENV: 'production'

38
server/data/graphHosts.js Normal file
View File

@@ -0,0 +1,38 @@
// Allow-list of Microsoft Graph and Entra (Azure AD) login hosts across the
// public, US Government, DoD, and China sovereign clouds. User-supplied Graph
// connection URLs are validated against this list so the server cannot be
// pointed at arbitrary internal endpoints (SSRF).
export const ALLOWED_GRAPH_HOSTS = new Set([
'graph.microsoft.com',
'graph.microsoft.us',
'dod-graph.microsoft.us',
'microsoftgraph.chinacloudapi.cn'
]);
export const ALLOWED_AUTHORITY_HOSTS = new Set([
'login.microsoftonline.com',
'login.microsoftonline.us',
'login.partner.microsoftonline.cn',
'login.chinacloudapi.cn'
]);
function hostnameOf(url) {
try {
const parsed = new URL(String(url));
if (parsed.protocol !== 'https:') return null;
return parsed.hostname.toLowerCase();
} catch {
return null;
}
}
export function isAllowedGraphHost(url) {
const host = hostnameOf(url);
return Boolean(host && ALLOWED_GRAPH_HOSTS.has(host));
}
export function isAllowedAuthorityHost(url) {
const host = hostnameOf(url);
return Boolean(host && ALLOWED_AUTHORITY_HOSTS.has(host));
}

297
server/data/helpCatalog.js Normal file
View File

@@ -0,0 +1,297 @@
import { psadtCatalog } from './psadtCatalog.js';
const powershellCoreUrl = 'https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/?view=powershell-5.1';
function article(id, category, title, summary, sections, tags = []) {
return { id, category, title, summary, sections, tags };
}
function section(heading, body = [], code = '') {
return { heading, body, code };
}
function apiExample(method, route, description, body = '') {
const code = [
'$base = "http://localhost:3000"',
'$token = (Invoke-RestMethod -Method Post -Uri "$base/api/auth/login" -ContentType "application/json" -Body (@{ email = "admin@posh.local"; password = "change-me-now" } | ConvertTo-Json)).token',
'$headers = @{ Authorization = "Bearer $token" }',
body
? `Invoke-RestMethod -Method ${method} -Uri "$base${route}" -Headers $headers -ContentType "application/json" -Body (${body} | ConvertTo-Json -Depth 10)`
: `Invoke-RestMethod -Method ${method} -Uri "$base${route}" -Headers $headers`
].join('\n');
return section(`${method} ${route}`, [description], code);
}
const operationsArticles = [
article('ops-overview', 'Operations', 'Application Operations Overview', 'How operators move through POSHManager day to day.', [
section('Daily workflow', [
'Build scripts in the Scripts workspace, assign credentials to hosts in Host Library and Credential Vault, create RunPlans, execute jobs, then review job and system logs.',
'The UI is intentionally API-first. Every create, update, delete, execute, migration, and publishing action calls the Express API so automation can use the same workflows.'
]),
section('Navigation map', [
'Dashboard shows metrics, charts, recent jobs, and configurable widgets.',
'Scripts contains the VS Code-style Monaco PowerShell editor, script library, variable studio, and metadata panel.',
'PSADT contains the deployment factory, verifier, migration wizard, and Intune Publishing Wizard.',
'Hosts, Credential Vault, RunPlans, Logs, Users & Groups, and Config are separate operational surfaces.'
])
], ['dashboard', 'operations', 'navigation']),
article('ops-scripts', 'Operations', 'Scripts And Variables', 'Create folders, author scripts, use variables, and keep versions.', [
section('Script storage', [
'Use the Script Library rail to create folders and scripts. Right-click folders or scripts for contextual create/delete actions.',
'Scripts are versioned by the API. Saving an existing script creates a new script_versions row.'
]),
section('Variables', [
'Open Variable Studio from the script toolbar. POSHManager runtime variables can be inserted as PowerShell variables or token syntax.',
'Custom variables are encrypted at rest and can be personal, shared, or group-scoped.',
'PSADT reference variables are cataloged for authoring, but POSHManager does not fake PSADT runtime values. Those are available only inside a valid PSADT session.',
'The editor autocomplete suggests PowerShell cmdlets, PSADT functions, PSADT snippets, POSHManager variables, custom variables, and Asset Library reference tokens.'
])
], ['scripts', 'variables', 'monaco']),
article('ops-assets', 'Operations', 'Asset Library', 'Upload, organize, link, preview, and reference package assets.', [
section('What belongs here', [
'Use Assets for installers, archives, icons, detection scripts, configs, PSADT Files content, SupportFiles content, and reusable files referenced by normal PowerShell scripts.',
'The library has its own folder tree, separate from script folders, so deployment package content can be organized by app, vendor, platform, or lifecycle stage.',
'Uploaded files are handled by multer and stored under the API FileLocker tree by asset type: packages, images, scripts, configs, documents, or generic.'
]),
section('Using assets in scripts and packages', [
'Each asset has a reference token such as {{asset:ast_123}}. Insert the token from the asset details panel into a script when you need the API container file path during RunPlan execution.',
'Each asset also has a package path such as Files/setup.exe or SupportFiles/config.json. PSADT and Intune package-building workflows use that path to stage content into the correct deployment structure.',
'Assets can be linked to scripts, RunPlans, PSADT profiles, or Intune deployment plans with a role such as installer, support-file, icon, detection-script, or reference.'
])
], ['assets', 'packages', 'psadt', 'intune', 'uploads']),
article('ops-hosts-runplans', 'Operations', 'Hosts, Credential Vault, RunPlans, And Jobs', 'Manage target systems and execute scripts safely.', [
section('Hosts and credentials', [
'Create credentials in Credential Vault first, then attach them to hosts. Secrets are encrypted using AES-256-GCM.',
'Hosts support WinRM, SSH, local, and API transport metadata. PowerShell remoting and firewall prerequisites must be configured outside POSHManager.'
]),
section('RunPlans', [
'A RunPlan joins one script with one or more hosts. The backend creates a job and host-level log rows during execution.',
'RunPlans can be personal, shared, or group-scoped. Use the execute action to queue the plan.'
]),
section('Logs', [
'Job logs are aggregated by job and host. System Logs show Winston request/application logs for API request and response troubleshooting.'
])
], ['hosts', 'credentials', 'runplans', 'jobs', 'logs']),
article('ops-admin-config', 'Operations', 'Administration And Configuration', 'Manage users, groups, settings, themes, and deployment variables.', [
section('Users and groups', [
'Users & Groups is a dedicated administration menu item. Add users and groups through modal create flows.',
'Scripts, RunPlans, variables, PSADT profiles, and Intune deployment plans can use personal, shared, or group visibility.'
]),
section('Configuration', [
'Config is grouped into collapsible sections for Deployment, Authentication, Execution, Runtime, and Other settings, with Microsoft Graph Intune environments managed in the Config / Intune panel.',
'Settings can be controlled through the UI and environment variables for Docker deployment. Trusted origins, server FQDN, Entra fields, PowerShell binary, and script execution switch are key operational settings.'
])
], ['admin', 'groups', 'settings', 'docker'])
];
const apiArticles = [
article('api-auth-bootstrap', 'API', 'Authentication And Bootstrap API', 'Login, profile, health, and bootstrap examples with PowerShell.', [
apiExample('Post', '/api/auth/login', 'Authenticate with local credentials and receive a JWT token.', '@{ email = "admin@posh.local"; password = "change-me-now" }'),
apiExample('Get', '/api/auth/me', 'Return the current authenticated user.'),
apiExample('Put', '/api/auth/profile', 'Update display name, profile fields, and avatar URL.', '@{ displayName = "POSH Admin"; email = "admin@posh.local"; jobTitle = "Platform Administrator"; phone = ""; timezone = "America/Chicago"; avatarUrl = "" }'),
apiExample('Get', '/api/bootstrap', 'Return dashboard summary, settings payload, and Entra status.'),
section('Notes', [
'Use the Bearer token returned by /api/auth/login for every protected request.',
'The default development login is seeded only when the users table is empty. Change defaults for real deployments.'
])
], ['api', 'auth', 'bootstrap', 'powershell']),
article('api-library', 'API', 'Script Library API', 'Folder and script API usage with PowerShell examples.', [
apiExample('Get', '/api/folders', 'List visible folders.'),
apiExample('Post', '/api/folders', 'Create a script folder.', '@{ name = "Deployments"; parentId = $null; visibility = "shared" }'),
apiExample('Get', '/api/scripts', 'List visible scripts.'),
apiExample('Post', '/api/scripts', 'Create a script and initial version.', '@{ name = "Health Check.ps1"; folderId = $null; description = "Simple host health check"; content = "Get-Date"; visibility = "personal" }'),
apiExample('Put', '/api/scripts/scr_123', 'Update a script. Replace scr_123 with the script id.', '@{ name = "Health Check.ps1"; folderId = $null; description = "Updated"; content = "Get-ComputerInfo"; visibility = "personal" }')
], ['api', 'scripts', 'folders']),
article('api-assets', 'API', 'Asset Library API', 'Upload and manage package assets with PowerShell examples.', [
apiExample('Get', '/api/assets/folders', 'List visible asset folders.'),
apiExample('Post', '/api/assets/folders', 'Create an asset folder.', '@{ name = "Contoso VPN"; parentId = $null; description = "VPN package assets"; visibility = "shared" }'),
apiExample('Get', '/api/assets', 'List visible assets with referenceToken, packagePath, checksum, viewUrl, and downloadUrl metadata.'),
section('POST /api/assets', [
'Upload an asset with multipart form-data. The file field must be named file; metadata fields such as folderId, name, description, packagePath, visibility, and groupId travel alongside it.',
'The API uses multer to stage uploads into FileLocker/_incoming, then promotes them into FileLocker/assets/<bucket>/<assetId>/<filename>.'
], '$file = "/packages/install-notes.txt"\n$form = @{ file = Get-Item $file; folderId = ""; name = "install-notes.txt"; description = "Package note"; packagePath = "SupportFiles/install-notes.txt"; visibility = "shared" }\nInvoke-RestMethod -Method Post -Uri "$base/api/assets" -Headers $headers -Form $form'),
apiExample('Get', '/api/assets/ast_123/download', 'Download an asset. Replace ast_123 with the asset id.'),
apiExample('Post', '/api/assets/ast_123/links', 'Link an asset to a script, RunPlan, PSADT profile, or Intune deployment.', '@{ targetType = "script"; targetId = "scr_123"; linkRole = "reference"; packagePath = "SupportFiles/install-notes.txt" }')
], ['api', 'assets', 'uploads', 'packages']),
article('api-hosts-credentials-runplans', 'API', 'Hosts, Credentials, RunPlans, Jobs, And Logs API', 'Manage execution targets and inspect results through the API.', [
apiExample('Post', '/api/credentials', 'Create an encrypted username/password credential.', '@{ name = "WinRM Admin"; kind = "username_password"; username = "CONTOSO\\svc-posh"; secret = "change-me"; visibility = "personal" }'),
apiExample('Post', '/api/hosts', 'Create a managed host.', '@{ name = "APP01"; address = "app01.contoso.local"; fqdn = "app01.contoso.local"; osFamily = "windows"; transport = "winrm"; port = 5986; credentialId = $null; tags = @("prod","web"); notes = "" }'),
apiExample('Post', '/api/runplans', 'Create a RunPlan. hostIds should contain existing host ids.', '@{ name = "Patch Validation"; description = "Run validation script"; scriptId = "scr_123"; visibility = "shared"; parallel = $true; hostIds = @("hst_123") }'),
apiExample('Post', '/api/runplans/rp_123/execute', 'Execute a RunPlan and create a job. Replace rp_123 with the RunPlan id.'),
apiExample('Get', '/api/jobs', 'List job history.'),
apiExample('Get', '/api/jobs/job_123', 'Read one job with host rows and logs.'),
apiExample('Get', '/api/logs/system', 'Read system/request logs from the Winston log stream.')
], ['api', 'credentials', 'hosts', 'runplans', 'jobs']),
article('api-psadt', 'API', 'PSADT And Intune API', 'Use the PSADT catalog, verifier, migration wizard, profiles, and Intune publishing plans through API calls.', [
apiExample('Get', '/api/psadt/catalog', 'Return PSADT source links, module/function/ADMX catalogs, snippets, and Intune publishing guidance.'),
apiExample('Post', '/api/psadt/validate', 'Validate raw PSADT script content.', '@{ platform = "intune"; content = "Invoke-AppDeployToolkit.exe -DeploymentType Install" }'),
apiExample('Post', '/api/psadt/migration/plan', 'Plan a legacy script migration to PSADT 4.2.0.', `@{ targetVersion = "4.2.0"; content = "Deploy-Application.ps1\`nExecute-Process -Path setup.exe\`n$appName = 'Legacy App'" }`),
apiExample('Post', '/api/psadt/profiles', 'Create a reusable PSADT deployment profile.', '@{ name = "Edge Enterprise"; appVendor = "Microsoft"; appName = "Edge"; appVersion = "126.0"; appArch = "x64"; appLang = "EN"; appRevision = "01"; templateVersion = "v4"; deploymentType = "Install"; deployMode = "Auto"; requireAdmin = $true; zeroConfig = $false; suppressReboot = $false; closeProcesses = @(); installTasks = @(@{ type = "exe"; phase = "Install"; filePath = "setup.exe"; arguments = "/S"; secureArguments = $false }); uiPlan = @{ welcome = $true }; configPlan = @{}; admxPlan = @{}; visibility = "shared" }'),
apiExample('Post', '/api/psadt/intune/deployments', 'Create an Intune Publishing Wizard plan.', '@{ name = "Edge Pilot"; sourceFolder = "C:\\Packages\\Edge\\PSADT"; intunewinFile = "Edge.intunewin"; commandStyle = "v4"; installBehavior = "system"; restartBehavior = "return-code"; uiMode = "native-v4"; requirements = @{ architecture = "x64"; minOs = "Windows 10 22H2"; diskSpaceMb = 512; runAs32Bit = $false }; installCommand = "Invoke-AppDeployToolkit.exe -DeploymentType Install"; uninstallCommand = "Invoke-AppDeployToolkit.exe -DeploymentType Uninstall"; detectionType = "custom-script"; detectionRule = "Write-Output detected"; returnCodes = @(@{ code = 0; type = "success"; meaning = "OK" }, @{ code = 1602; type = "retry"; meaning = "Deferred" }, @{ code = 3010; type = "softReboot"; meaning = "Reboot" }); assignments = @(@{ ring = "Pilot"; intent = "available"; groupName = "IT Pilot"; notes = "Validate" }); status = "ready"; visibility = "shared" }')
], ['api', 'psadt', 'intune', 'migration'])
,
article('api-graph-intune', 'API', 'Microsoft Graph Intune Tracking API', 'Configure Graph environments in Config / Intune and sync Intune deployment status for PSADT publishing plans.', [
apiExample('Post', '/api/graph/connections', 'Create a Microsoft Graph environment. In the UI this belongs under Config / Intune. The client secret is encrypted and never returned.', '@{ name = "Production Intune"; tenantId = "contoso.onmicrosoft.com"; clientId = "00000000-0000-0000-0000-000000000000"; clientSecret = "secret"; cloud = "global"; graphBaseUrl = "https://graph.microsoft.com"; authorityHost = "https://login.microsoftonline.com"; defaultApiVersion = "v1.0"; enabled = $true; visibility = "shared" }'),
apiExample('Post', '/api/graph/connections/graph_123/test', 'Test token acquisition and Intune app read access. Replace graph_123 with the connection id.'),
apiExample('Get', '/api/graph/connections/graph_123/mobile-apps?q=Edge', 'List Intune mobile apps visible to the Graph app registration.'),
apiExample('Post', '/api/psadt/intune/deployments/intune_123/graph/link', 'Link a POSHManager Intune deployment plan to an Intune mobileApp id.', '@{ connectionId = "graph_123"; graphAppId = "intune-mobile-app-id" }'),
apiExample('Post', '/api/psadt/intune/deployments/intune_123/graph/sync', 'Sync device/user install status and failure details from Microsoft Graph Intune reports.', '@{ connectionId = "graph_123"; graphAppId = "intune-mobile-app-id"; mode = "reports" }'),
apiExample('Get', '/api/psadt/intune/deployments/intune_123/graph/status', 'Read stored status rows, failure rows, and sync run history for a deployment.')
], ['api', 'graph', 'intune', 'failures'])
];
const psadtArticles = [
article('psadt-integration-overview', 'PSADT', 'PSADT Integration Overview', 'How POSHManager supports PSAppDeployToolkit authoring, verification, migration, and publishing.', [
section('What is modeled', [
'POSHManager catalogs PSADT variables, functions, ADMX policy surface, deployment structure, launch commands, snippets, and upstream v4 template shape.',
'Profiles generate Invoke-AppDeployToolkit scaffolds and Intune-ready commands. The verifier checks known best practices and gotchas. The migration wizard upgrades common legacy patterns.'
]),
section('What is not faked', [
'POSHManager does not emulate PSADT runtime session variables. They exist when PSADT opens an ADTSession during deployment.',
'POSHManager does not redistribute PSADT modules/templates. Operators bring the actual PSADT deployment package content.'
])
], ['psadt', 'integration']),
article('psadt-authoring', 'PSADT', 'Authoring PSADT Scripts', 'Use profiles, variables, snippets, and generated scaffolds to create package scripts.', [
section('Recommended authoring path', [
'Create a PSADT profile with application metadata, deployment type, install tasks, close-process list, and UI plan.',
'Render or create the script from the profile, then continue editing in the Scripts workspace.',
'Use Variable Studio for PSADT variables and POSHManager custom variables. Use snippets for common UI, installer, reboot, and logging patterns.'
]),
section('Session guidance', [
'Current v4 scaffolds use ADTSession metadata, package-local module import, Remove-ADTHashtableNullOrEmptyValues, Open-ADTSession, phase invocation, and Close-ADTSession.',
'DeployMode should remain Auto unless the package intentionally requires Interactive, NonInteractive, or Silent.'
])
], ['psadt', 'authoring', 'profiles']),
article('psadt-verifier-migration', 'PSADT', 'Best Practice Verifier And Migration Wizard', 'Validate and migrate PSADT scripts before publishing.', [
section('Verifier targets', [
'Validate a saved script, a rendered PSADT profile, or pasted raw content. Choose platform context such as Intune so platform-specific rules apply.',
'Findings include severity, rule id, category, line/excerpt, and remediation.'
]),
section('Migration wizard', [
'The migration wizard plans automatic replacements and manual review steps for saved scripts or raw legacy content.',
'Automatic replacements include common legacy function names, Deploy-Application naming, and $appName-style variables.',
'Manual review flags include ServiceUI wrappers, raw msiexec, missing Open-ADTSession, legacy phase shape, and missing DeferRunInterval for Intune deferrals.'
])
], ['psadt', 'verifier', 'migration']),
article('psadt-intune-deploy', 'PSADT', 'Deploying PSADT Applications With Intune', 'End-to-end PSADT Win32 app publishing guidance.', [
section('Core workflow', [
'Place installers in Files and supporting files in SupportFiles. Keep icons/assets, config, and strings in the correct PSADT folders.',
'Edit Invoke-AppDeployToolkit.ps1 for variables, pre/main/post install, uninstall, and repair logic.',
'Wrap the entire PSADT folder with the Microsoft Win32 Content Prep Tool into a .intunewin package.',
'Create a Windows app (Win32) in Intune, upload the package, configure commands, requirements, detection, return codes, and assignments.'
]),
section('Commands and UI context', [
'For PSADT v4 packages, prefer Invoke-AppDeployToolkit.exe -DeploymentType Install and Invoke-AppDeployToolkit.exe -DeploymentType Uninstall.',
'Older v3 examples often use Deploy-Application.exe -DeploymentType "Install" -DeployMode "Interactive". Keep this only for legacy compatibility packages.',
'Install behavior should normally be System. PSADT v4.1+ supports native user-session UI for Intune SYSTEM installs without ServiceUI. ServiceUI should be legacy-only.'
]),
section('Return codes and detection', [
'Map 0 as success, 1602 as retry/user defer, 3010 as soft reboot, and keep custom PSADT app codes out of 60000-68999.',
'Some historical guidance uses 1703 as a soft reboot mapping; POSHManager includes it for compatibility.',
'Use MSI product code, file/version, registry, or custom PowerShell detection. Custom scripts should be fast, side-effect free, and return success only when the app is installed.'
])
], ['psadt', 'intune', 'deployment', 'serviceui'])
,
article('psadt-graph-tracking', 'PSADT', 'Tracking Intune Deployments With Microsoft Graph', 'Use Graph environments to view deployment reach, failures, devices, and users.', [
section('Graph environment setup', [
'Create a Microsoft Entra app registration with application permissions such as DeviceManagementApps.Read.All for read-only tracking. Use DeviceManagementApps.ReadWrite.All only when you intend to manage Intune app objects or assignments.',
'Store tenant id, client id, and client secret in Config / Intune Graph environments. Client secrets are encrypted and hidden after save.',
'Use Test to validate token acquisition and read access to deviceAppManagement.'
]),
section('Deployment tracking workflow', [
'Create or open an Intune Publishing Wizard plan, then link it to a Graph environment and Intune mobileApp id.',
'Sync status to read Intune report data into POSHManager. Stored rows include device name, user principal name, install state, error code, detail, and raw Graph/report data.',
'Use the failures count and status table to quickly identify who and which devices failed, then correlate with Intune Management Extension logs and PSADT logs.'
]),
section('Graph reporting notes', [
'POSHManager prefers Intune reporting endpoints for install status tracking because older mobileApp deviceStatuses/userStatuses relationships have changed over time.',
'Microsoft Graph returns request ids and status codes that should be kept for troubleshooting tenant permission, throttling, and report availability issues.',
'This brings POSHManager closer to full Intune publishing and package lifecycle management. Package content/module redistribution is still a separate future capability unless explicitly implemented.'
])
], ['psadt', 'graph', 'intune', 'tracking', 'failures'])
];
const cmdletArticles = [
article('cmdlets-core-reference', 'PowerShell', 'Microsoft.PowerShell.Core Cmdlet Reference', 'Common core cmdlets and links to the Microsoft reference.', [
section('Reference source', [
`Microsoft documents the Microsoft.PowerShell.Core snap-in and common cmdlets at ${powershellCoreUrl}. The snap-in is loaded automatically by Windows PowerShell and cannot be imported or removed like a normal module.`
]),
section('Common cmdlets', [
'Get-Help: display help for commands and concepts.',
'Get-Command: discover cmdlets, functions, aliases, and applications.',
'Get-Module and Import-Module: inspect and import modules.',
'Invoke-Command: run commands locally or against remote sessions.',
'New-PSSession, Enter-PSSession, Get-PSSession, Remove-PSSession: manage PowerShell remoting sessions.',
'Start-Job, Get-Job, Receive-Job, Stop-Job, Remove-Job, Wait-Job: manage background jobs.',
'ForEach-Object and Where-Object: pipeline iteration and filtering.',
'Set-StrictMode: enforce safer script practices.',
'Update-Help and Save-Help: maintain local help content.'
]),
section('Discovery examples', [], 'Get-Help Invoke-Command -Detailed\nGet-Command -Module Microsoft.PowerShell.Core\nGet-Command *PSSession*\nUpdate-Help -Force')
], ['powershell', 'cmdlets', 'reference']),
article('cmdlets-remoting', 'PowerShell', 'PowerShell Remoting Cmdlets', 'Useful cmdlets for WinRM/PSSession workflows used around POSHManager.', [
section('Session workflow', [
'Enable-PSRemoting configures a computer to receive remote commands. This must be done on targets outside POSHManager.',
'New-PSSession creates reusable remote sessions. Invoke-Command can run commands through a session or directly against computers.',
'Get-PSSession shows current sessions. Remove-PSSession closes them.'
], '$session = New-PSSession -ComputerName "APP01"\nInvoke-Command -Session $session -ScriptBlock { Get-Service }\nGet-PSSession\nRemove-PSSession $session'),
section('Interactive troubleshooting', [
'Enter-PSSession starts an interactive remote shell. Exit-PSSession returns to the local shell.',
'Use Test-WSMan outside the Core module to verify WinRM reachability before adding a host.'
], 'Enter-PSSession -ComputerName "APP01"\nExit-PSSession')
], ['powershell', 'remoting', 'winrm']),
article('cmdlets-jobs-pipeline', 'PowerShell', 'Jobs And Pipeline Cmdlets', 'Common cmdlets for async work and object processing.', [
section('Jobs', [
'Start-Job runs a command in the background. Get-Job inspects state, Receive-Job collects output, Stop-Job stops work, Wait-Job blocks until completion, and Remove-Job cleans up.',
'Use jobs for local async work. POSHManager jobs are application records and not the same thing as PowerShell Start-Job jobs.'
], '$job = Start-Job -ScriptBlock { Get-Process }\nWait-Job $job\nReceive-Job $job\nRemove-Job $job'),
section('Pipeline processing', [
'Where-Object filters pipeline objects. ForEach-Object performs an action for each item.',
'Prefer object properties over text parsing whenever possible.'
], 'Get-Service | Where-Object Status -eq "Running" | ForEach-Object { $_.Name }')
], ['powershell', 'jobs', 'pipeline'])
];
function snippetArticles() {
const catalog = psadtCatalog();
const snippetItems = (catalog.snippets || []).map((snippet) => section(snippet.title, [
`${snippet.category} snippet for ${snippet.functionName}. Use Send to editor from the old snippet flow or copy the snippet from Help.`
], snippet.body));
return [
article('snippets-psadt', 'Snippets', 'PSADT Snippet Library', 'Common PSADT examples moved into searchable help.', snippetItems, ['snippets', 'psadt', 'examples']),
article('snippets-api-powershell', 'Snippets', 'PowerShell API Snippets', 'Reusable PowerShell snippets for POSHManager API automation.', [
section('Login helper', [], '$base = "http://localhost:3000"\n$token = (Invoke-RestMethod -Method Post -Uri "$base/api/auth/login" -ContentType "application/json" -Body (@{ email = "admin@posh.local"; password = "change-me-now" } | ConvertTo-Json)).token\n$headers = @{ Authorization = "Bearer $token" }'),
section('Create script and RunPlan', [], '$script = Invoke-RestMethod -Method Post -Uri "$base/api/scripts" -Headers $headers -ContentType "application/json" -Body (@{ name = "Inventory.ps1"; content = "Get-ComputerInfo"; visibility = "personal" } | ConvertTo-Json)\n$plan = Invoke-RestMethod -Method Post -Uri "$base/api/runplans" -Headers $headers -ContentType "application/json" -Body (@{ name = "Inventory"; scriptId = $script.id; parallel = $true; hostIds = @() } | ConvertTo-Json -Depth 5)')
], ['snippets', 'api', 'powershell'])
];
}
export function helpCatalog() {
return [
...operationsArticles,
...apiArticles,
...psadtArticles,
...cmdletArticles,
...snippetArticles()
];
}
export function helpCategories() {
return [...new Set(helpCatalog().map((item) => item.category))].sort();
}
export function helpSearch(query = '', category = '') {
const needle = query.trim().toLowerCase();
return helpCatalog().filter((item) => {
const categoryMatch = !category || item.category === category;
if (!needle) return categoryMatch;
const haystack = [
item.title,
item.summary,
item.category,
...(item.tags || []),
...item.sections.flatMap((part) => [part.heading, ...(part.body || []), part.code || ''])
].join(' ').toLowerCase();
return categoryMatch && haystack.includes(needle);
});
}

View File

@@ -0,0 +1,107 @@
// Knowledge base of common Windows installer technologies and their silent
// install/uninstall command lines. Command templates use placeholders:
// {file} the installer file name/path
// {productCode} the MSI product code (MSI/MSP)
// {app} the installed app folder (operator fills in)
// {packageName} the MSIX/AppX package name
// Confidence reflects how reliably the technology can be inferred from a file
// name alone; binary signature sniffing (Phase 5) raises it.
export const INSTALLER_TECHNOLOGIES = [
{
id: 'msi',
label: 'Windows Installer (MSI)',
extensions: ['.msi'],
install: 'msiexec.exe /i "{file}" /qn /norestart',
uninstall: 'msiexec.exe /x "{productCode}" /qn /norestart',
psadtInstall: "Start-ADTMsiProcess -Action Install -FilePath '{file}'",
psadtUninstall: "Start-ADTMsiProcess -Action Uninstall -ProductCode '{productCode}'",
detection: 'msi',
notes: 'MSI is silent with /qn. Use the product code for uninstall and detection.'
},
{
id: 'msp',
label: 'Windows Installer Patch (MSP)',
extensions: ['.msp'],
install: 'msiexec.exe /p "{file}" /qn /norestart',
uninstall: '',
psadtInstall: "Start-ADTMsiProcess -Action Patch -FilePath '{file}'",
detection: 'msi',
notes: 'MSP applies a patch to an installed MSI.'
},
{
id: 'inno',
label: 'Inno Setup',
extensions: ['.exe'],
hints: ['inno'],
install: '"{file}" /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP-',
uninstall: '"%ProgramFiles%\\{app}\\unins000.exe" /VERYSILENT /SUPPRESSMSGBOXES /NORESTART',
psadtInstall: "Start-ADTProcess -FilePath '{file}' -ArgumentList '/VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP-'",
detection: 'registry-uninstall',
notes: 'Inno Setup uses /VERYSILENT; the uninstaller is unins000.exe in the install folder.'
},
{
id: 'nsis',
label: 'NSIS (Nullsoft)',
extensions: ['.exe'],
hints: ['nsis'],
install: '"{file}" /S',
uninstall: '"%ProgramFiles%\\{app}\\uninstall.exe" /S',
psadtInstall: "Start-ADTProcess -FilePath '{file}' -ArgumentList '/S'",
detection: 'registry-uninstall',
notes: 'NSIS uses an uppercase /S for silent install.'
},
{
id: 'installshield',
label: 'InstallShield',
extensions: ['.exe'],
hints: ['installshield'],
install: '"{file}" /s /v"/qn"',
uninstall: '"{file}" /s /x /v"/qn"',
psadtInstall: "Start-ADTProcess -FilePath '{file}' -ArgumentList '/s /v\"/qn\"'",
detection: 'registry-uninstall',
notes: 'InstallShield; older versions may require a recorded response file (.iss).'
},
{
id: 'wix-burn',
label: 'WiX Burn bundle',
extensions: ['.exe'],
hints: ['bundle', 'burn'],
install: '"{file}" /quiet /norestart',
uninstall: '"{file}" /uninstall /quiet /norestart',
psadtInstall: "Start-ADTProcess -FilePath '{file}' -ArgumentList '/quiet /norestart'",
detection: 'registry-uninstall',
notes: 'WiX Burn bootstrapper uses /quiet /norestart.'
},
{
id: 'squirrel',
label: 'Squirrel (Electron)',
extensions: ['.exe'],
hints: ['squirrel'],
install: '"{file}" --silent',
uninstall: '"{file}" --uninstall --silent',
psadtInstall: "Start-ADTProcess -FilePath '{file}' -ArgumentList '--silent'",
detection: 'registry-uninstall',
notes: 'Squirrel installers (many Electron apps) use --silent.'
},
{
id: 'msix',
label: 'MSIX / AppX',
extensions: ['.msix', '.msixbundle', '.appx', '.appxbundle'],
install: 'Add-AppxProvisionedPackage -Online -PackagePath "{file}" -SkipLicense',
uninstall: 'Remove-AppxProvisionedPackage -Online -PackageName "{packageName}"',
psadtInstall: "Add-AppxProvisionedPackage -Online -PackagePath '{file}' -SkipLicense",
detection: 'appx',
notes: 'MSIX/AppX provisioned package; detection via Get-AppxPackage.'
},
{
id: 'exe',
label: 'Generic EXE',
extensions: ['.exe'],
install: '"{file}" /S',
uninstall: '',
psadtInstall: "Start-ADTProcess -FilePath '{file}' -ArgumentList '/S'",
detection: 'registry-uninstall',
notes: 'Unknown EXE installer; confirm the silent switch with the vendor. Common switches: /S, /silent, /quiet, /VERYSILENT.'
}
];

View File

@@ -0,0 +1,70 @@
export const intuneCoverage = {
appType: 'Windows app (Win32)',
publishingSteps: [
{ id: 'source', title: 'Prepare source', summary: 'Place installers in Files and supporting content in SupportFiles, Assets, Config, or Strings as appropriate.' },
{ id: 'commands', title: 'Program commands', summary: 'Use Invoke-AppDeployToolkit.exe for PSADT v4 packages; keep legacy Deploy-Application.exe only for v3 compatibility packages.' },
{ id: 'requirements', title: 'Requirements', summary: 'Model architecture, minimum Windows version, disk needs, and 32-bit execution flags before upload.' },
{ id: 'detection', title: 'Detection', summary: 'Choose MSI product code, file/version, registry, or custom PowerShell detection with clear installed/not-installed behavior.' },
{ id: 'returns', title: 'Return codes', summary: 'Map PSADT and installer exit codes so Intune retries, succeeds, or requests reboot correctly.' },
{ id: 'assignments', title: 'Assignments', summary: 'Publish to pilot, broad, and exclusion rings with intent and group notes.' },
{ id: 'review', title: 'Review', summary: 'Confirm UI context, ServiceUI compatibility, Graph app id, logs, and package readiness.' }
],
packaging: [
{ area: 'Package source', guidance: 'Package the entire PSADT deployment folder with Microsoft Win32 Content Prep Tool so Invoke-AppDeployToolkit.exe sits at the content root for v4 packages.' },
{ area: 'Files folder', guidance: 'Place application installers in Files; PSADT installer helpers resolve files relative to that folder.' },
{ area: 'SupportFiles folder', guidance: 'Place helper scripts, transforms, configuration files, or content copied during post-install tasks in SupportFiles.' },
{ area: 'Assets / Config / Strings', guidance: 'Use Assets for icons, Config for toolkit settings such as paths/UI behavior, and Strings for localized prompt text.' },
{ area: 'Install command', guidance: 'PSADT v4: Invoke-AppDeployToolkit.exe -DeploymentType Install. Legacy v3 compatibility: Deploy-Application.exe -DeploymentType "Install" -DeployMode "Interactive".' },
{ area: 'Uninstall command', guidance: 'PSADT v4: Invoke-AppDeployToolkit.exe -DeploymentType Uninstall. Legacy v3 compatibility: Deploy-Application.exe -DeploymentType "Uninstall" -DeployMode "Interactive".' },
{ area: 'Install behavior', guidance: 'System is recommended for enterprise PSADT deployments; PSADT v4.1+ handles user-session UI without ServiceUI.' },
{ area: 'Device restart behavior', guidance: 'Use return-code driven reboot behavior so PSADT can pass 3010/1703 soft reboot signals, or suppress reboot passthrough when Intune should see success.' }
],
returnCodes: [
{ code: 0, type: 'success', meaning: 'Success' },
{ code: 1602, type: 'retry', meaning: 'User deferred/cancelled; Intune recognizes this natively.' },
{ code: 1703, type: 'softReboot', meaning: 'Legacy PSADT soft reboot mapping used in some Intune deployment examples.' },
{ code: 1641, type: 'softReboot', meaning: 'MSI initiated reboot.' },
{ code: 3010, type: 'softReboot', meaning: 'Soft reboot required.' },
{ code: 60008, type: 'failed', meaning: 'PSADT initialization failure.' },
{ code: '60000-68999', type: 'reserved', meaning: 'Reserved PSADT built-in range; do not use for custom app codes.' },
{ code: '69000-69999', type: 'customScript', meaning: 'Recommended custom Invoke-AppDeployToolkit.ps1 range.' },
{ code: '70000-79999', type: 'extension', meaning: 'Recommended extension module range.' }
],
detectionRules: [
{ type: 'MSI product code', bestFor: 'Single MSI packages', notes: 'Prefer when zero-config MSI packaging is used and the product code is stable.' },
{ type: 'File/version', bestFor: 'EXE installers and vendor apps', notes: 'Check a stable executable path and ProductVersion/FileVersion.' },
{ type: 'Registry', bestFor: 'Apps with Add/Remove Programs entries or custom install markers', notes: 'Use HKLM uninstall keys or a package-specific marker value.' },
{ type: 'Custom PowerShell', bestFor: 'Complex detection', notes: 'Return exit 0 and write output when installed; keep script fast and side-effect free.' }
],
requirements: [
{ key: 'Architecture', values: ['x64', 'x86', 'both'], guidance: 'Match the package architecture and the Intune requirement rule.' },
{ key: 'Minimum OS', values: ['Windows 10 22H2', 'Windows 11 23H2', 'Windows 11 24H2'], guidance: 'Keep this aligned with your enterprise baseline and vendor support.' },
{ key: 'Run as 32-bit', values: ['false', 'true'], guidance: 'Use only for installers or detection scripts that require 32-bit registry/file redirection.' }
],
uiCompatibility: [
{ mode: 'native-v4', label: 'PSADT v4 native UI', guidance: 'Preferred. PSADT v4.1+ can display user prompts from Intune SYSTEM installs without ServiceUI.' },
{ mode: 'serviceui-legacy', label: 'Legacy ServiceUI bridge', guidance: 'Use only for older PSADT/v3 compatibility packages that intentionally bundle ServiceUI/Invoke-ServiceUI.' },
{ mode: 'silent', label: 'Silent / non-interactive', guidance: 'Use for required background installs that should not prompt or defer.' }
],
assignmentRings: [
{ name: 'Pilot', intent: 'available or required', guidance: 'Small operator or IT validation group; collect PSADT logs and Intune device status.' },
{ name: 'Broad', intent: 'required', guidance: 'Main production group after pilot success.' },
{ name: 'Exclusion', intent: 'exclude', guidance: 'Break-glass group for blocked apps, special users, or conflicting devices.' }
],
managementActions: [
{ action: 'Upload package', apiStatus: 'planned', guidance: 'Future Graph integration should create/update Win32 app content versions.' },
{ action: 'Create app metadata', apiStatus: 'planned', guidance: 'Map POSHManager PSADT profile metadata to Intune Win32 app display information.' },
{ action: 'Configure install/uninstall commands', apiStatus: 'supported-template', guidance: 'Commands are generated today and should be used when creating Intune apps.' },
{ action: 'Configure return codes', apiStatus: 'supported-template', guidance: 'Return-code table is modeled today for operator copy/automation.' },
{ action: 'Configure detection rules', apiStatus: 'supported-template', guidance: 'Detection patterns are modeled today; future Graph integration can write them directly.' },
{ action: 'Assign rings', apiStatus: 'planned', guidance: 'Future Graph integration should manage required/available assignments and exclusions.' },
{ action: 'Monitor deployment', apiStatus: 'planned', guidance: 'Future Graph integration should pull device/user install status and correlate PSADT logs.' }
],
gotchas: [
'Do not wrap PSADT with ServiceUI.exe for Intune; PSADT v4.1+ has native user-session UI handling.',
'Use -DeferRunInterval when deferrals are enabled so Intune retry timing does not repeatedly prompt users.',
'Avoid hard-coding -DeployMode unless required; Auto is the upstream default and respects session/process/OOBE detection.',
'Map 1602 as retry/user defer, 3010 as soft reboot, and keep custom PSADT app codes out of 60000-68999.',
'Test packages as SYSTEM with the launch helper patterns before broad Intune assignment.'
]
};

365
server/data/psadtCatalog.js Normal file
View File

@@ -0,0 +1,365 @@
import { intuneCoverage } from './intuneCatalog.js';
export const psadtSources = [
{ id: 'github', title: 'PSAppDeployToolkit GitHub repository', url: 'https://github.com/psappdeploytoolkit/psappdeploytoolkit' },
{ id: 'new-deployment', title: 'Creating a new deployment', url: 'https://psappdeploytoolkit.com/docs/getting-started/creating-a-new-deployment' },
{ id: 'requirements', title: 'Requirements', url: 'https://psappdeploytoolkit.com/docs/getting-started/requirements' },
{ id: 'release-notes', title: 'Release Notes', url: 'https://psappdeploytoolkit.com/docs/getting-started/release-notes' },
{ id: 'upgrade-v41', title: 'Upgrade Guidance: v4 to v4.1', url: 'https://psappdeploytoolkit.com/docs/getting-started/upgrade-guidance-4x-to-v41' },
{ id: 'faq', title: 'FAQ', url: 'https://psappdeploytoolkit.com/docs/getting-started/faq' },
{ id: 'structure', title: 'Deployment Structure', url: 'https://psappdeploytoolkit.com/docs/deployment-concepts/deployment-structure' },
{ id: 'invoke', title: 'Invoke-AppDeployToolkit', url: 'https://psappdeploytoolkit.com/docs/deployment-concepts/invoke-appdeploytoolkit' },
{ id: 'zero-config', title: 'Zero-Config Deployment', url: 'https://psappdeploytoolkit.com/docs/deployment-concepts/zero-config-deployment' },
{ id: 'how-to-deploy', title: 'How to Deploy', url: 'https://psappdeploytoolkit.com/docs/usage/how-to-deploy' },
{ id: 'ui', title: 'Adding UI Elements', url: 'https://psappdeploytoolkit.com/docs/usage/adding-ui-elements' },
{ id: 'customize', title: 'Customizing Deployments', url: 'https://psappdeploytoolkit.com/docs/usage/customizing-deployments' },
{ id: 'installing', title: 'Installing Applications', url: 'https://psappdeploytoolkit.com/docs/usage/installing-applications' },
{ id: 'admx', title: 'ADMX Templates', url: 'https://psappdeploytoolkit.com/docs/usage/admx/admx-templates' },
{ id: 'exit-codes', title: 'Exit Codes', url: 'https://psappdeploytoolkit.com/docs/4.1.x/reference/exit-codes' }
];
export const psadtModuleMetadata = {
upstreamRepo: 'https://github.com/psappdeploytoolkit/psappdeploytoolkit',
moduleVersion: '4.2.0',
moduleGuid: '8c3c366b-8606-4576-9f2d-4051144f7ca2',
frontendTemplate: 'src/PSAppDeployToolkit/opt/Frontend/v4/Invoke-AppDeployToolkit.ps1',
publicFunctionCount: 142,
admxPolicyCount: 40
};
const publicFunctionNames = `Add-ADTEdgeExtension
Add-ADTFont
Add-ADTModuleCallback
Block-ADTAppExecution
Clear-ADTModuleCallback
Close-ADTInstallationProgress
Close-ADTNotifyIcon
Close-ADTSession
Complete-ADTFunction
Convert-ADTRegistryPath
Convert-ADTValueType
Convert-ADTValuesFromRemainingArguments
ConvertTo-ADTNTAccountOrSID
Copy-ADTContentToCache
Copy-ADTFile
Copy-ADTFileToUserProfiles
Disable-ADTTerminalServerInstallMode
Dismount-ADTWimFile
Enable-ADTTerminalServerInstallMode
Export-ADTEnvironmentTableToSessionState
Get-ADTApplication
Get-ADTBoundParametersAndDefaultValues
Get-ADTCommandTable
Get-ADTConfig
Get-ADTDeferHistory
Get-ADTEnvironmentTable
Get-ADTEnvironmentVariable
Get-ADTExecutableInfo
Get-ADTFileVersion
Get-ADTFreeDiskSpace
Get-ADTIniSection
Get-ADTIniValue
Get-ADTLoggedOnUser
Get-ADTModuleCallback
Get-ADTMsiExitCodeMessage
Get-ADTMsiTableProperty
Get-ADTObjectProperty
Get-ADTOperatingSystemInfo
Get-ADTPEFileArchitecture
Get-ADTPendingReboot
Get-ADTPowerShellProcessPath
Get-ADTPresentationSettingsEnabledUsers
Get-ADTRegistryKey
Get-ADTRunningProcesses
Get-ADTServiceStartMode
Get-ADTSession
Get-ADTShortcut
Get-ADTStringTable
Get-ADTUserNotificationState
Get-ADTUserProfiles
Get-ADTUserToastNotificationMode
Get-ADTWindowTitle
Initialize-ADTFunction
Initialize-ADTModule
Initialize-ADTModuleIfUninitialized
Install-ADTMSUpdates
Install-ADTSCCMSoftwareUpdates
Invoke-ADTAllUsersRegistryAction
Invoke-ADTCommandWithRetries
Invoke-ADTFunctionErrorHandler
Invoke-ADTObjectMethod
Invoke-ADTRegSvr32
Invoke-ADTSCCMTask
Mount-ADTWimFile
New-ADTErrorRecord
New-ADTFolder
New-ADTLogFileName
New-ADTMsiTransform
New-ADTShortcut
New-ADTTemplate
New-ADTValidateScriptErrorRecord
New-ADTZipFile
Open-ADTSession
Out-ADTPowerShellEncodedCommand
Register-ADTDll
Remove-ADTContentFromCache
Remove-ADTDesktopShortcut
Remove-ADTEdgeExtension
Remove-ADTEnvironmentVariable
Remove-ADTFile
Remove-ADTFileFromUserProfiles
Remove-ADTFolder
Remove-ADTFont
Remove-ADTHashtableNullOrEmptyValues
Remove-ADTIniSection
Remove-ADTIniValue
Remove-ADTInvalidFileNameChars
Remove-ADTModuleCallback
Remove-ADTRegistryKey
Reset-ADTDeferHistory
Resolve-ADTErrorRecord
Select-ADTUniqueObject
Send-ADTKeys
Set-ADTActiveSetup
Set-ADTDeferHistory
Set-ADTEnvironmentVariable
Set-ADTIniSection
Set-ADTIniValue
Set-ADTItemPermission
Set-ADTMsiProperty
Set-ADTPowerShellCulture
Set-ADTRegistryKey
Set-ADTServiceStartMode
Set-ADTShortcut
Show-ADTBalloonTip
Show-ADTDialogBox
Show-ADTHelpConsole
Show-ADTInstallationProgress
Show-ADTInstallationPrompt
Show-ADTInstallationRestartPrompt
Show-ADTInstallationWelcome
Show-ADTNotifyIcon
Start-ADTMsiProcess
Start-ADTMsiProcessAsUser
Start-ADTMspProcess
Start-ADTMspProcessAsUser
Start-ADTProcess
Start-ADTProcessAsUser
Start-ADTServiceAndDependencies
Stop-ADTServiceAndDependencies
Test-ADTBattery
Test-ADTCallerIsAdmin
Test-ADTEspActive
Test-ADTMSUpdates
Test-ADTMicrophoneInUse
Test-ADTModuleInitialized
Test-ADTMutexAvailability
Test-ADTNetworkConnection
Test-ADTOobeCompleted
Test-ADTPowerPoint
Test-ADTRegistryValue
Test-ADTServiceExists
Test-ADTSessionActive
Test-ADTUserInFocusMode
Test-ADTUserIsBusy
Unblock-ADTAppExecution
Uninstall-ADTApplication
Unregister-ADTDll
Update-ADTDesktop
Update-ADTEnvironmentPsProvider
Update-ADTGroupPolicy
Write-ADTLogEntry`;
function functionCategory(name) {
if (/^(Show|Close).*Installation|^Show-ADT|NotifyIcon|Dialog|Balloon|HelpConsole/.test(name)) return 'User Interface';
if (/^(Start|Install|Uninstall).*Msi|Msp|Process|Application|Updates|SCCM|RegSvr32|Dll/.test(name)) return 'Installer and process';
if (/Registry|ActiveSetup|Ini|Shortcut|File|Folder|Font|Content|Zip|Wim|EnvironmentVariable/.test(name)) return 'Filesystem registry config';
if (/Session|Module|Function|Callback|Config|StringTable|CommandTable/.test(name)) return 'Toolkit session';
if (/User|LoggedOn|PowerPoint|Battery|Network|Oobe|Esp|PendingReboot|OperatingSystem|Service|Mutex|Caller|Microphone|Window|Desktop|GroupPolicy|TerminalServer/.test(name)) return 'Device user state';
return 'Utilities';
}
export const psadtFunctionCatalog = publicFunctionNames.split('\n').map((name) => ({
name,
category: functionCategory(name),
snippet: `${name} `
}));
export const psadtAdmxPolicies = [
['Logo', 'Assets', 'SOFTWARE\\Policies\\PSAppDeployToolkit\\Config\\Assets'],
['LogoDark', 'Assets', 'SOFTWARE\\Policies\\PSAppDeployToolkit\\Config\\Assets'],
['Banner', 'Assets', 'SOFTWARE\\Policies\\PSAppDeployToolkit\\Config\\Assets'],
['TaskbarIcon', 'Assets', 'SOFTWARE\\Policies\\PSAppDeployToolkit\\Config\\Assets'],
['InstallParams', 'MSI', 'SOFTWARE\\Policies\\PSAppDeployToolkit\\Config\\MSI'],
['LoggingOptions', 'MSI', 'SOFTWARE\\Policies\\PSAppDeployToolkit\\Config\\MSI'],
['MutexWaitTime', 'MSI', 'SOFTWARE\\Policies\\PSAppDeployToolkit\\Config\\MSI'],
['SilentParams', 'MSI', 'SOFTWARE\\Policies\\PSAppDeployToolkit\\Config\\MSI'],
['UninstallParams', 'MSI', 'SOFTWARE\\Policies\\PSAppDeployToolkit\\Config\\MSI'],
['CachePath', 'Toolkit', 'SOFTWARE\\Policies\\PSAppDeployToolkit\\Config\\Toolkit'],
['CompanyName', 'Toolkit', 'SOFTWARE\\Policies\\PSAppDeployToolkit\\Config\\Toolkit'],
['CompressLogs', 'Toolkit', 'SOFTWARE\\Policies\\PSAppDeployToolkit\\Config\\Toolkit'],
['FileCopyMode', 'Toolkit', 'SOFTWARE\\Policies\\PSAppDeployToolkit\\Config\\Toolkit'],
['LogAppend', 'Toolkit', 'SOFTWARE\\Policies\\PSAppDeployToolkit\\Config\\Toolkit'],
['LogDebugMessage', 'Toolkit', 'SOFTWARE\\Policies\\PSAppDeployToolkit\\Config\\Toolkit'],
['LogMaxHierarchy', 'Toolkit', 'SOFTWARE\\Policies\\PSAppDeployToolkit\\Config\\Toolkit'],
['LogMaxHistory', 'Toolkit', 'SOFTWARE\\Policies\\PSAppDeployToolkit\\Config\\Toolkit'],
['LogMaxSize', 'Toolkit', 'SOFTWARE\\Policies\\PSAppDeployToolkit\\Config\\Toolkit'],
['LogPath', 'Toolkit', 'SOFTWARE\\Policies\\PSAppDeployToolkit\\Config\\Toolkit'],
['LogPathNoAdminRights', 'Toolkit', 'SOFTWARE\\Policies\\PSAppDeployToolkit\\Config\\Toolkit'],
['LogToHierarchy', 'Toolkit', 'SOFTWARE\\Policies\\PSAppDeployToolkit\\Config\\Toolkit'],
['LogToSubfolder', 'Toolkit', 'SOFTWARE\\Policies\\PSAppDeployToolkit\\Config\\Toolkit'],
['LogStyle', 'Toolkit', 'SOFTWARE\\Policies\\PSAppDeployToolkit\\Config\\Toolkit'],
['LogWriteToHost', 'Toolkit', 'SOFTWARE\\Policies\\PSAppDeployToolkit\\Config\\Toolkit'],
['LogHostOutputToStdStreams', 'Toolkit', 'SOFTWARE\\Policies\\PSAppDeployToolkit\\Config\\Toolkit'],
['RegPath', 'Toolkit', 'SOFTWARE\\Policies\\PSAppDeployToolkit\\Config\\Toolkit'],
['RegPathNoAdminRights', 'Toolkit', 'SOFTWARE\\Policies\\PSAppDeployToolkit\\Config\\Toolkit'],
['TempPath', 'Toolkit', 'SOFTWARE\\Policies\\PSAppDeployToolkit\\Config\\Toolkit'],
['TempPathNoAdminRights', 'Toolkit', 'SOFTWARE\\Policies\\PSAppDeployToolkit\\Config\\Toolkit'],
['BalloonNotifications', 'UI', 'SOFTWARE\\Policies\\PSAppDeployToolkit\\Config\\UI'],
['FluentAccentColor', 'UI', 'SOFTWARE\\Policies\\PSAppDeployToolkit\\Config\\UI'],
['FluentAccentColorDark', 'UI', 'SOFTWARE\\Policies\\PSAppDeployToolkit\\Config\\UI'],
['DialogStyle', 'UI', 'SOFTWARE\\Policies\\PSAppDeployToolkit\\Config\\UI'],
['DefaultExitCode', 'UI', 'SOFTWARE\\Policies\\PSAppDeployToolkit\\Config\\UI'],
['DefaultPromptPersistInterval', 'UI', 'SOFTWARE\\Policies\\PSAppDeployToolkit\\Config\\UI'],
['DefaultTimeout', 'UI', 'SOFTWARE\\Policies\\PSAppDeployToolkit\\Config\\UI'],
['DeferExitCode', 'UI', 'SOFTWARE\\Policies\\PSAppDeployToolkit\\Config\\UI'],
['LanguageOverride', 'UI', 'SOFTWARE\\Policies\\PSAppDeployToolkit\\Config\\UI'],
['PromptToSaveTimeout', 'UI', 'SOFTWARE\\Policies\\PSAppDeployToolkit\\Config\\UI'],
['RestartPromptPersistInterval', 'UI', 'SOFTWARE\\Policies\\PSAppDeployToolkit\\Config\\UI']
].map(([name, category, key]) => ({ name, category, key }));
export const psadtLaunchCommands = [
{ name: 'Install interactive', command: 'Invoke-AppDeployToolkit.exe -DeploymentType Install -DeployMode Interactive' },
{ name: 'Install silent', command: 'Invoke-AppDeployToolkit.exe -DeploymentType Install -DeployMode Silent' },
{ name: 'Uninstall interactive', command: 'Invoke-AppDeployToolkit.exe -DeploymentType Uninstall -DeployMode Interactive' },
{ name: 'Uninstall silent', command: 'Invoke-AppDeployToolkit.exe -DeploymentType Uninstall -DeployMode Silent' },
{ name: 'Repair interactive', command: 'Invoke-AppDeployToolkit.exe -DeploymentType Repair -DeployMode Interactive' },
{ name: 'Repair silent', command: 'Invoke-AppDeployToolkit.exe -DeploymentType Repair -DeployMode Silent' },
{ name: 'Install interactive as SYSTEM for testing', command: 'PsExec64.exe /accepteula /s /i Invoke-AppDeployToolkit.exe -DeploymentType Install -DeployMode Interactive' },
{ name: 'Install silent as SYSTEM for testing', command: 'PsExec64.exe /accepteula /s Invoke-AppDeployToolkit.exe -DeploymentType Install -DeployMode Silent' }
];
export const psadtSupportMatrix = [
{ area: 'Deployment creation', sourceId: 'new-deployment', support: 'profile', status: 'supported', implementation: 'PSADT profile wizard can create v4/v3-compatible script skeletons and script library entries.' },
{ area: 'Requirements', sourceId: 'requirements', support: 'verifier', status: 'supported', implementation: 'Verifier flags scripts that declare unsupported PowerShell versions and records PSADT platform requirements.' },
{ area: 'Release-note gotchas', sourceId: 'release-notes', support: 'verifier', status: 'supported', implementation: 'Verifier checks known gotchas such as ServiceUI usage, Fluent UI prompt icon usage, raw MSI handling, and old deployment names.' },
{ area: 'v4 to v4.1 upgrade guidance', sourceId: 'upgrade-v41', support: 'verifier', status: 'supported', implementation: 'Verifier checks RequireAdmin/AppProcessesToClose placement, removed config keys, session cleanup, and deprecated patterns.' },
{ area: 'FAQ guidance', sourceId: 'faq', support: 'verifier', status: 'supported', implementation: 'Verifier catches missing ADTSession assumptions, global module imports, Intune defer retry concerns, and user-context RequireAdmin guidance.' },
{ area: 'Upstream module coverage', sourceId: 'github', support: 'catalog', status: 'supported', implementation: 'Catalog tracks the upstream 4.2.0 module metadata, all 142 public functions, launch helpers, and 40 ADMX policies.' },
{ area: 'Template structure', sourceId: 'structure', support: 'reference', status: 'supported', implementation: 'Structure table tracks Invoke-AppDeployToolkit.ps1, PSAppDeployToolkit, Files, SupportFiles, Assets, Config, and Strings.' },
{ area: 'ADTSession properties', sourceId: 'invoke', support: 'profile', status: 'supported', implementation: 'Profiles store app metadata, success/reboot codes, RequireAdmin, and close-process definitions.' },
{ area: 'Install/Uninstall/Repair phases', sourceId: 'invoke', support: 'generator', status: 'supported', implementation: 'Renderer emits Install-ADTDeployment, Uninstall-ADTDeployment, and Repair-ADTDeployment phase blocks.' },
{ area: 'Zero-config MSI', sourceId: 'zero-config', support: 'profile', status: 'supported', implementation: 'Zero-config toggle emits an empty AppName and a Files-folder checklist for single MSI/MST/MSP/WIM packages.' },
{ area: 'Deployment commands', sourceId: 'how-to-deploy', support: 'generator', status: 'supported', implementation: 'Renderer produces Invoke-AppDeployToolkit.exe and PowerShell command lines for Intune/package documentation.' },
{ area: 'UI elements', sourceId: 'ui', support: 'snippets', status: 'supported', implementation: 'Snippet library covers welcome, progress, prompts, restart prompts, dialog boxes, and help console.' },
{ area: 'Customization', sourceId: 'customize', support: 'checklist', status: 'supported', implementation: 'Profiles carry config, strings, assets, log, and CompressLogs guidance for package readiness.' },
{ area: 'Application installers', sourceId: 'installing', support: 'snippets', status: 'supported', implementation: 'Snippet library covers Start-ADTProcess, Start-ADTProcessAsUser, and Start-ADTMsiProcess.' },
{ area: 'ADMX / Intune policy', sourceId: 'admx', support: 'checklist', status: 'supported', implementation: 'ADMX checklist tracks policy files, Intune import, Central Store, and HKLM policy path.' }
,{ area: 'Exit codes', sourceId: 'exit-codes', support: 'verifier', status: 'supported', implementation: 'Verifier flags reserved built-in exit code ranges and recommends custom script/extension ranges.' }
];
export const psadtStructureRows = [
{ path: 'Invoke-AppDeployToolkit.ps1', purpose: 'Main deployment script and phase logic.', required: true },
{ path: 'Invoke-AppDeployToolkit.exe', purpose: 'Wrapper executable for hidden PowerShell launches and command-line options.', required: false },
{ path: 'PSAppDeployToolkit/', purpose: 'Core module files; should not be modified in deployments.', required: true },
{ path: 'PSAppDeployToolkit.Extensions/', purpose: 'Optional custom functions/extensions.', required: false },
{ path: 'Files/', purpose: 'Installer media such as EXE, MSI, MST, MSP, WIM, archives, and configs.', required: true },
{ path: 'SupportFiles/', purpose: 'Registry files, configuration templates, shortcuts, docs, licenses, and support payloads.', required: false },
{ path: 'Assets/', purpose: 'AppIcon.png, classic banners, logos, and UI branding images.', required: false },
{ path: 'Config/config.psd1', purpose: 'Toolkit behavior, MSI parameters, logging, UI, security, and performance settings.', required: true },
{ path: 'Strings/strings.psd1', purpose: 'Localized UI strings and deployment messaging.', required: true },
{ path: 'PSAppDeployToolkit/ADMX/', purpose: 'PSADT ADMX/ADML policy templates for Group Policy or Intune.', required: false }
];
export const psadtInvokeParameters = [
{ name: '-DeploymentType', values: ['Install', 'Uninstall', 'Repair'], description: 'Selects install, uninstall, or repair deployment flow.' },
{ name: '-DeployMode', values: ['Interactive', 'Silent', 'NonInteractive'], description: 'Controls UI behavior and whether interactive prompts are allowed.' },
{ name: '-SuppressRebootPassThru', values: ['switch'], description: 'Suppresses 3010 reboot-required passthrough exit codes.' },
{ name: '-TerminalServerMode', values: ['switch'], description: 'Changes to user install mode for RDS/Citrix systems.' },
{ name: '-DisableLogging', values: ['switch'], description: 'Disables file logging.' },
{ name: '/Debug', values: ['exe only'], description: 'Opens a visible debug window with live logging.' },
{ name: '/32', values: ['exe only'], description: 'Launches with x86 PowerShell.' },
{ name: '/Core', values: ['exe only'], description: 'Launches with PowerShell Core.' },
{ name: '-File', values: ['*.ps1'], description: 'Runs a custom script file instead of Invoke-AppDeployToolkit.ps1.' }
];
export const psadtSnippets = [
{
id: 'welcome-close-processes',
title: 'Welcome prompt with close processes',
category: 'UI',
functionName: 'Show-ADTInstallationWelcome',
body: "Show-ADTInstallationWelcome -CloseProcesses $adtSession.AppProcessesToClose -AllowDefer -DeferTimes 3 -CheckDiskSpace"
},
{
id: 'progress',
title: 'Installation progress',
category: 'UI',
functionName: 'Show-ADTInstallationProgress',
body: "Show-ADTInstallationProgress -StatusMessage 'Installing application. Please wait...'"
},
{
id: 'custom-prompt',
title: 'Custom installation prompt',
category: 'UI',
functionName: 'Show-ADTInstallationPrompt',
body: "Show-ADTInstallationPrompt -Title 'Deployment notice' -Message 'The application will now be installed.' -ButtonRightText 'OK'"
},
{
id: 'restart-prompt',
title: 'Restart prompt',
category: 'UI',
functionName: 'Show-ADTInstallationRestartPrompt',
body: 'Show-ADTInstallationRestartPrompt -CountdownSeconds 600 -CountdownNoHideSeconds 60'
},
{
id: 'dialog',
title: 'Generic dialog box',
category: 'UI',
functionName: 'Show-ADTDialogBox',
body: "Show-ADTDialogBox -Text 'Deployment completed.' -Icon Information -Buttons OK"
},
{
id: 'help-console',
title: 'Toolkit help console',
category: 'UI',
functionName: 'Show-ADTHelpConsole',
body: 'Show-ADTHelpConsole'
},
{
id: 'start-process',
title: 'Install EXE',
category: 'Install',
functionName: 'Start-ADTProcess',
body: "Start-ADTProcess -FilePath 'setup.exe' -ArgumentList '/S' -WaitForChildProcesses -SuccessExitCodes @(0, 3010)"
},
{
id: 'start-process-user',
title: 'Run process as active user',
category: 'Install',
functionName: 'Start-ADTProcessAsUser',
body: "Start-ADTProcessAsUser -FilePath '%LOCALAPPDATA%\\Programs\\SomeApp\\Uninstall.exe' -ArgumentList '/S' -ExpandEnvironmentVariables"
},
{
id: 'start-msi',
title: 'Install MSI with transform',
category: 'Install',
functionName: 'Start-ADTMsiProcess',
body: "Start-ADTMsiProcess -Action 'Install' -FilePath 'SomeApp.msi' -Transforms 'SomeApp.mst' -AdditionalArgumentList 'SERIAL=12345' -SecureArgumentList"
}
];
export function psadtCatalog() {
return {
module: psadtModuleMetadata,
sources: psadtSources,
supportMatrix: psadtSupportMatrix,
structure: psadtStructureRows,
invokeParameters: psadtInvokeParameters,
functions: psadtFunctionCatalog,
admxPolicies: psadtAdmxPolicies,
launchCommands: psadtLaunchCommands,
intune: intuneCoverage,
snippets: psadtSnippets
};
}

View File

@@ -0,0 +1,191 @@
export const psadtValidationRules = [
{
id: 'REQ-PSVERSION-MINIMUM',
severity: 'warning',
category: 'Requirements',
sourceId: 'requirements',
title: 'PowerShell version requirement is below PSADT v4 support floor',
description: 'PSADT v4 supports Windows PowerShell 5.1 and PowerShell 7.4+. Lower #requires values can hide unsupported runtime assumptions.',
remediation: 'Use Windows PowerShell 5.1 or PowerShell 7.4+ for PSADT v4 deployments.'
},
{
id: 'UPG-REQUIREADMIN-CONFIG',
severity: 'error',
category: 'v4.1 upgrade',
sourceId: 'upgrade-v41',
title: 'RequireAdmin appears to be configured outside ADTSession',
description: 'PSADT v4.1 moved RequireAdmin out of Config.psd1 and into the deployment session properties.',
remediation: 'Set RequireAdmin in $adtSession, e.g. RequireAdmin = $true or RequireAdmin = $false.'
},
{
id: 'UPG-REMOVED-CONFIG-DETECTION',
severity: 'error',
category: 'v4.1 upgrade',
sourceId: 'upgrade-v41',
title: 'Removed OOBE/session detection config option found',
description: 'Toolkit.OobeDetection and Toolkit.SessionDetection were removed from Config.psd1 in v4.1.',
remediation: 'Move this decision to deployment/session options such as NoOobeDetection or NoSessionDetection when needed.'
},
{
id: 'UPG-APP-PROCESSES-SESSION',
severity: 'warning',
category: 'v4.1 upgrade',
sourceId: 'upgrade-v41',
title: 'Close-processes are not centralized in AppProcessesToClose',
description: 'PSADT v4.1 recommends defining AppProcessesToClose in the ADTSession object and reusing it across phases.',
remediation: 'Move repeated process definitions into $adtSession.AppProcessesToClose and pass that to Show-ADTInstallationWelcome.'
},
{
id: 'UPG-MISSING-SESSION-CLEANUP',
severity: 'warning',
category: 'v4.1 upgrade',
sourceId: 'upgrade-v41',
title: 'Open-ADTSession is used without removing null or empty session values',
description: 'The v4.1 template strips null/empty values from the ADTSession hashtable before Open-ADTSession.',
remediation: 'Call Remove-ADTHashtableNullOrEmptyValues before Open-ADTSession when you build the session hashtable manually.'
},
{
id: 'REPO-MODULE-VERSION-DRIFT',
severity: 'warning',
category: 'Upstream parity',
sourceId: 'github',
title: 'Generated/imported module version is behind upstream 4.2.0',
description: 'The upstream repo template currently imports PSAppDeployToolkit module version 4.2.0.',
remediation: 'Update ModuleVersion pins and generated templates to 4.2.0 unless you intentionally target an older package.'
},
{
id: 'REPO-DEPLOYMODE-NO-AUTO',
severity: 'info',
category: 'Upstream parity',
sourceId: 'github',
title: 'DeployMode is hard-coded instead of allowing Auto',
description: 'The upstream v4 frontend template defaults DeployMode to Auto and says not to hard-code it unless required.',
remediation: 'Prefer omitting -DeployMode or using Auto unless the deployment specifically requires Interactive, NonInteractive, or Silent.'
},
{
id: 'LEGACY-V3-FUNCTION',
severity: 'error',
category: 'Legacy v3 pattern',
sourceId: 'release-notes',
title: 'Legacy v3 function name found',
description: 'PSADT v4 renamed many common v3 functions to ADT-prefixed equivalents.',
remediation: 'Use the v4 function mapping and replace legacy function names such as Execute-Process, Execute-MSI, Write-Log, and Show-InstallationWelcome.'
},
{
id: 'LEGACY-DEPLOY-APPLICATION',
severity: 'warning',
category: 'Legacy v3 pattern',
sourceId: 'release-notes',
title: 'Legacy Deploy-Application naming found',
description: 'PSADT v4 renamed Deploy-Application.ps1/exe to Invoke-AppDeployToolkit.ps1/exe.',
remediation: 'Use Invoke-AppDeployToolkit.ps1 and Invoke-AppDeployToolkit.exe in v4 packages.'
},
{
id: 'LEGACY-DEPLOYMENT-VARIABLE',
severity: 'warning',
category: 'ADTSession',
sourceId: 'faq',
title: 'Legacy deployment variable found',
description: 'Deployment variables such as $appName and $appVersion are stored on $adtSession in PSADT v4.',
remediation: 'Use $adtSession.AppName, $adtSession.AppVersion, and related ADTSession properties.'
},
{
id: 'FAQ-ENV-VAR-BEFORE-SESSION',
severity: 'info',
category: 'ADTSession',
sourceId: 'faq',
title: 'Toolkit environment variables require an ADTSession',
description: 'PSADT environment variables are available after opening an ADTSession or exporting the environment table.',
remediation: 'Ensure Open-ADTSession or Export-ADTEnvironmentTableToSessionState runs before relying on PSADT environment variables.'
},
{
id: 'INTUNE-SERVICEUI',
severity: 'critical',
category: 'Intune/security',
sourceId: 'release-notes',
title: 'ServiceUI usage found',
description: 'PSADT v4.1 no longer requires ServiceUI for Intune UI display and the release notes call out security risk in token manipulation approaches.',
remediation: 'Remove ServiceUI workarounds and rely on PSADT v4.1 native user-session UI handling.'
},
{
id: 'INTUNE-DEFER-RUN-INTERVAL',
severity: 'warning',
category: 'Intune/retry',
sourceId: 'faq',
title: 'Deferral prompt lacks DeferRunInterval',
description: 'Intune retries quickly after a 1602 defer result. PSADT FAQ recommends DeferRunInterval to prevent repeated close-app prompts.',
remediation: 'Add -DeferRunInterval when using AllowDefer for Intune-targeted deployments.'
},
{
id: 'UI-PROMPT-ICON-FLUENT',
severity: 'warning',
category: 'UI',
sourceId: 'release-notes',
title: 'Show-ADTInstallationPrompt uses -Icon',
description: 'The v4.1.8 template removed -Icon from Show-ADTInstallationPrompt because it is not supported in Fluent UI.',
remediation: 'Remove -Icon from Show-ADTInstallationPrompt or switch to a function that supports the desired icon behavior.'
},
{
id: 'INSTALL-RAW-MSIEXEC',
severity: 'warning',
category: 'Installer',
sourceId: 'installing',
title: 'Raw msiexec usage found',
description: 'PSADT provides Start-ADTMsiProcess for MSI install/uninstall/repair/patch handling and logging.',
remediation: 'Use Start-ADTMsiProcess instead of calling msiexec.exe directly where possible.'
},
{
id: 'INSTALL-PROCESS-NO-WAIT-CHILD',
severity: 'info',
category: 'Installer',
sourceId: 'release-notes',
title: 'Start-ADTProcess may exit before child installers finish',
description: 'PSADT v4.1 added -WaitForChildProcesses for installers that hand off to child processes.',
remediation: 'Consider -WaitForChildProcesses for setup.exe installers that spawn child processes and exit early.'
},
{
id: 'EXIT-RESERVED-BUILTIN',
severity: 'error',
category: 'Exit codes',
sourceId: 'exit-codes',
title: 'Reserved PSADT built-in exit code used as custom code',
description: 'Exit codes 60000-68999 are reserved for built-in PSADT exit codes.',
remediation: 'Use 69000-69999 for custom Invoke-AppDeployToolkit.ps1 exit codes or 70000-79999 for extension module codes.'
},
{
id: 'EXIT-CUSTOM-RANGE',
severity: 'info',
category: 'Exit codes',
sourceId: 'exit-codes',
title: 'Custom exit code range detected',
description: 'Exit codes 69000-69999 are recommended for user customized Invoke-AppDeployToolkit.ps1 exit codes.',
remediation: 'Confirm the code is documented in the package and deployment platform return-code mapping.'
},
{
id: 'FAQ-GLOBAL-MODULE-IMPORT',
severity: 'warning',
category: 'Packaging',
sourceId: 'faq',
title: 'Global PSADT module import found',
description: 'The FAQ notes packages can include the toolkit module, while central module installs risk running tested packages against newer module versions.',
remediation: 'Prefer package-local PSAppDeployToolkit module files unless you intentionally govern a central module lifecycle.'
},
{
id: 'DEPRECATED-GET-ADTOBJECTPROPERTY',
severity: 'warning',
category: 'Deprecation',
sourceId: 'github',
title: 'Deprecated Get-ADTObjectProperty usage found',
description: 'The upstream function help marks Get-ADTObjectProperty as deprecated and scheduled for removal in PSAppDeployToolkit 4.3.0.',
remediation: 'Replace Get-ADTObjectProperty usage with direct object/property access or a supported helper before upgrading to 4.3.0.'
},
{
id: 'USERCONTEXT-REQUIREADMIN',
severity: 'warning',
category: 'User context',
sourceId: 'faq',
title: 'User-context process with RequireAdmin enabled',
description: 'The FAQ recommends RequireAdmin = $false for user-context application installs.',
remediation: 'Set $adtSession.RequireAdmin to $false when the deployment is intended to run in user context.'
}
];

View File

@@ -0,0 +1,84 @@
function variable(name, category, description, source = 'psadt') {
return {
id: `${source}:${name}`,
name,
syntax: `$${name}`,
token: `{{${name}}}`,
category,
description,
source,
readOnly: true
};
}
export const poshManagerVariables = [
variable('POSHM_JOB_ID', 'POSHManager Runtime', 'Current POSHManager job id.', 'poshmanager'),
variable('POSHM_RUNPLAN_ID', 'POSHManager Runtime', 'RunPlan id that launched the execution.', 'poshmanager'),
variable('POSHM_SCRIPT_ID', 'POSHManager Runtime', 'Script id being executed.', 'poshmanager'),
variable('POSHM_SCRIPT_NAME', 'POSHManager Runtime', 'Script display name being executed.', 'poshmanager'),
variable('POSHM_HOST_ID', 'POSHManager Runtime', 'Target host id for the current execution.', 'poshmanager'),
variable('POSHM_HOST_NAME', 'POSHManager Runtime', 'Target host display name.', 'poshmanager'),
variable('POSHM_HOST_ADDRESS', 'POSHManager Runtime', 'Target host address used by remoting.', 'poshmanager'),
variable('POSHM_HOST_TRANSPORT', 'POSHManager Runtime', 'Transport selected for the target host.', 'poshmanager'),
variable('POSHM_TRIGGERED_BY', 'POSHManager Runtime', 'User id that launched the RunPlan.', 'poshmanager')
];
export const psadtVariables = [
variable('appDeployMainScriptFriendlyName', 'PSADT Toolkit Name', 'Friendly name for the main deployment script.'),
variable('appDeployToolkitName', 'PSADT Toolkit Name', 'PSAppDeployToolkit name.'),
variable('appDeployMainScriptVersion', 'PSADT Script Info', 'Version of the main deployment script.'),
variable('culture', 'PSADT Culture', 'Current culture information.'),
variable('currentLanguage', 'PSADT Culture', 'Current language code.'),
variable('currentUILanguage', 'PSADT Culture', 'Current UI language code.'),
...[
'envAllUsersProfile', 'envAppData', 'envArchitecture', 'envCommonDesktop', 'envCommonDocuments',
'envCommonProgramFiles', 'envCommonProgramFilesX86', 'envCommonStartMenu', 'envCommonStartMenuPrograms',
'envCommonStartUp', 'envCommonTemplates', 'envComputerName', 'envComputerNameFQDN', 'envHomeDrive',
'envHomePath', 'envHomeShare', 'envLocalAppData', 'envLogicalDrives', 'envProgramData', 'envProgramFiles',
'envProgramFilesX86', 'envPublic', 'envSystem32Directory', 'envSystemDrive', 'envSystemRAM', 'envSystemRoot',
'envTemp', 'envUserCookies', 'envUserDesktop', 'envUserFavorites', 'envUserInternetCache',
'envUserInternetHistory', 'envUserMyDocuments', 'envUserName', 'envUserProfile', 'envUserSendTo',
'envUserStartMenu', 'envUserStartMenuPrograms', 'envUserStartUp', 'envWinDir'
].map((name) => variable(name, 'PSADT Environment', 'Environment/session variable populated by PSADT.')),
...[
'envLogonServer', 'envMachineADDomain', 'envMachineDNSDomain', 'envMachineWorkgroup', 'envUserDNSDomain',
'envUserDomain', 'IsMachinePartOfDomain', 'MachineDomainController'
].map((name) => variable(name, 'PSADT Domain', 'Domain and directory context populated by PSADT.')),
...[
'envOS', 'envOSArchitecture', 'envOSName', 'envOSProductType', 'envOSProductTypeName', 'envOSServicePack',
'envOSVersion', 'envOSVersionBuild', 'envOSVersionMajor', 'envOSVersionMinor', 'envOSVersionRevision',
'Is64Bit', 'IsDomainControllerOS', 'IsServerOS', 'IsWorkStationOS'
].map((name) => variable(name, 'PSADT Operating System', 'Operating system detail populated by PSADT.')),
variable('Is64BitProcess', 'PSADT Process', 'Whether the active PowerShell process is 64-bit.'),
variable('psArchitecture', 'PSADT Process', 'PowerShell process architecture.'),
...[
'envCLRVersion', 'envCLRVersionBuild', 'envCLRVersionMajor', 'envCLRVersionMinor', 'envCLRVersionRevision',
'envHost', 'envPSVersion', 'envPSVersionBuild', 'envPSVersionMajor', 'envPSVersionMinor',
'envPSVersionRevision', 'envPSVersionTable'
].map((name) => variable(name, 'PSADT PowerShell', '.NET CLR, host, or PowerShell version detail populated by PSADT.')),
...[
'CurrentProcessSID', 'CurrentProcessToken', 'IsAdmin', 'IsLocalServiceAccount', 'IsLocalSystemAccount',
'IsNetworkServiceAccount', 'IsProcessUserInteractive', 'IsServiceAccount', 'LocalSystemNTAccount',
'ProcessNTAccount', 'ProcessNTAccountSID', 'SessionZero'
].map((name) => variable(name, 'PSADT Permissions', 'Process identity, token, and permission context populated by PSADT.')),
variable('MSIProductCodeRegExPattern', 'PSADT Regex', 'Regular expression pattern for MSI product codes.'),
variable('Shell', 'PSADT COM', 'Shell COM object created by PSADT.'),
variable('ShellApp', 'PSADT COM', 'Shell application COM object created by PSADT.'),
...[
'CurrentConsoleUserSession', 'CurrentLoggedOnUserSession', 'LoggedOnUserSessions', 'RunAsActiveUser', 'UsersLoggedOn'
].map((name) => variable(name, 'PSADT Logged On Users', 'Logged-on user session context populated by PSADT.')),
...[
'envOfficeBitness', 'envOfficeChannel', 'envOfficeVars', 'envOfficeVersion'
].map((name) => variable(name, 'PSADT Office', 'Microsoft Office discovery variable populated by PSADT.')),
variable('invalidFileNameChars', 'PSADT Miscellaneous', 'Invalid file name character list.'),
variable('LocalAdministratorsGroup', 'PSADT Miscellaneous', 'Localized local administrators group.'),
variable('LocalUsersGroup', 'PSADT Miscellaneous', 'Localized local users group.'),
variable('RunningTaskSequence', 'PSADT Miscellaneous', 'Whether execution is running inside a task sequence.')
];
export function fullVariableCatalog() {
return {
builtIns: poshManagerVariables,
psadt: psadtVariables
};
}