Initial
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -1,6 +1,6 @@
|
||||
node_modules/
|
||||
dist/
|
||||
data/
|
||||
/data/
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
@@ -16,4 +16,4 @@ tools/*.exe
|
||||
/output
|
||||
PLAN*.MD
|
||||
PLAN-INTUNE.md
|
||||
project.txt
|
||||
project.txt
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"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:prod": "node scripts/start-api.mjs production",
|
||||
"ui:dev": "vite --host 0.0.0.0 --port 3000 --strictPort",
|
||||
|
||||
@@ -5,9 +5,6 @@ if (fs.existsSync('dist/index.html')) {
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const result = spawnSync('npm', ['run', 'build'], {
|
||||
stdio: 'inherit',
|
||||
shell: process.platform === 'win32'
|
||||
});
|
||||
const result = spawnSync(process.execPath, ['node_modules/vite/bin/vite.js', 'build'], { stdio: 'inherit' });
|
||||
|
||||
process.exit(result.status ?? 1);
|
||||
|
||||
2
scripts/smoke-api-import.mjs
Normal file
2
scripts/smoke-api-import.mjs
Normal file
@@ -0,0 +1,2 @@
|
||||
await import('../server/forms/schemas.js');
|
||||
await import('../server/services/graphService.js');
|
||||
@@ -2,12 +2,12 @@ import { spawn } from 'node:child_process';
|
||||
|
||||
const mode = process.argv[2] || 'development';
|
||||
const watch = process.argv.includes('--watch');
|
||||
const command = watch ? 'nodemon' : 'node';
|
||||
const args = watch ? ['server/index.js'] : ['server/index.js'];
|
||||
const args = watch
|
||||
? ['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',
|
||||
shell: process.platform === 'win32',
|
||||
env: {
|
||||
...process.env,
|
||||
NODE_ENV: mode
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
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',
|
||||
shell: process.platform === 'win32',
|
||||
env: {
|
||||
...process.env,
|
||||
NODE_ENV: 'production'
|
||||
|
||||
38
server/data/graphHosts.js
Normal file
38
server/data/graphHosts.js
Normal 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
297
server/data/helpCatalog.js
Normal 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);
|
||||
});
|
||||
}
|
||||
107
server/data/installerCatalog.js
Normal file
107
server/data/installerCatalog.js
Normal 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.'
|
||||
}
|
||||
];
|
||||
70
server/data/intuneCatalog.js
Normal file
70
server/data/intuneCatalog.js
Normal 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
365
server/data/psadtCatalog.js
Normal 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
|
||||
};
|
||||
}
|
||||
191
server/data/psadtValidationRules.js
Normal file
191
server/data/psadtValidationRules.js
Normal 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.'
|
||||
}
|
||||
];
|
||||
84
server/data/variableCatalog.js
Normal file
84
server/data/variableCatalog.js
Normal 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
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user