149 lines
7.6 KiB
JavaScript
149 lines
7.6 KiB
JavaScript
const replacements = [
|
|
{ id: 'MIG-FN-EXECUTE-PROCESS', label: 'Execute-Process to Start-ADTProcess', pattern: /\bExecute-Process\b/g, replacement: 'Start-ADTProcess', automatic: true },
|
|
{ id: 'MIG-FN-EXECUTE-MSI', label: 'Execute-MSI to Start-ADTMsiProcess', pattern: /\bExecute-MSI\b/g, replacement: 'Start-ADTMsiProcess', automatic: true },
|
|
{ id: 'MIG-FN-EXECUTE-MSP', label: 'Execute-MSP to Start-ADTMspProcess', pattern: /\bExecute-MSP\b/g, replacement: 'Start-ADTMspProcess', automatic: true },
|
|
{ id: 'MIG-FN-WELCOME', label: 'Show-InstallationWelcome to Show-ADTInstallationWelcome', pattern: /\bShow-InstallationWelcome\b/g, replacement: 'Show-ADTInstallationWelcome', automatic: true },
|
|
{ id: 'MIG-FN-PROMPT', label: 'Show-InstallationPrompt to Show-ADTInstallationPrompt', pattern: /\bShow-InstallationPrompt\b/g, replacement: 'Show-ADTInstallationPrompt', automatic: true },
|
|
{ id: 'MIG-FN-PROGRESS', label: 'Show-InstallationProgress to Show-ADTInstallationProgress', pattern: /\bShow-InstallationProgress\b/g, replacement: 'Show-ADTInstallationProgress', automatic: true },
|
|
{ id: 'MIG-FN-RESTART', label: 'Show-InstallationRestartPrompt to Show-ADTInstallationRestartPrompt', pattern: /\bShow-InstallationRestartPrompt\b/g, replacement: 'Show-ADTInstallationRestartPrompt', automatic: true },
|
|
{ id: 'MIG-FN-LOG', label: 'Write-Log to Write-ADTLogEntry', pattern: /\bWrite-Log\b/g, replacement: 'Write-ADTLogEntry', automatic: true },
|
|
{ id: 'MIG-FN-REMOVE-MSI', label: 'Remove-MSIApplications to Uninstall-ADTApplication', pattern: /\bRemove-MSIApplications\b/g, replacement: 'Uninstall-ADTApplication', automatic: true },
|
|
{ id: 'MIG-FN-HKCU', label: 'Invoke-HKCURegistrySettingsForAllUsers to Invoke-ADTAllUsersRegistryAction', pattern: /\bInvoke-HKCURegistrySettingsForAllUsers\b/g, replacement: 'Invoke-ADTAllUsersRegistryAction', automatic: true },
|
|
{ id: 'MIG-NAME-DEPLOY-PS1', label: 'Deploy-Application.ps1 to Invoke-AppDeployToolkit.ps1', pattern: /\bDeploy-Application\.ps1\b/g, replacement: 'Invoke-AppDeployToolkit.ps1', automatic: true },
|
|
{ id: 'MIG-NAME-DEPLOY-EXE', label: 'Deploy-Application.exe to Invoke-AppDeployToolkit.exe', pattern: /\bDeploy-Application\.exe\b/g, replacement: 'Invoke-AppDeployToolkit.exe', automatic: true },
|
|
{ id: 'MIG-VAR-APPNAME', label: '$appName to $adtSession.AppName', pattern: /\$appName\b/g, replacement: '$adtSession.AppName', automatic: true },
|
|
{ id: 'MIG-VAR-APPVERSION', label: '$appVersion to $adtSession.AppVersion', pattern: /\$appVersion\b/g, replacement: '$adtSession.AppVersion', automatic: true },
|
|
{ id: 'MIG-VAR-APPVENDOR', label: '$appVendor to $adtSession.AppVendor', pattern: /\$appVendor\b/g, replacement: '$adtSession.AppVendor', automatic: true },
|
|
{ id: 'MIG-VAR-APPARCH', label: '$appArch to $adtSession.AppArch', pattern: /\$appArch\b/g, replacement: '$adtSession.AppArch', automatic: true },
|
|
{ id: 'MIG-VAR-APPLANG', label: '$appLang to $adtSession.AppLang', pattern: /\$appLang\b/g, replacement: '$adtSession.AppLang', automatic: true },
|
|
{ id: 'MIG-VAR-APPREVISION', label: '$appRevision to $adtSession.AppRevision', pattern: /\$appRevision\b/g, replacement: '$adtSession.AppRevision', automatic: true },
|
|
{ id: 'MIG-MODULE-420', label: 'Pin PSAppDeployToolkit ModuleVersion to 4.2.0', pattern: /ModuleVersion\s*=\s*['"][0-9.]+['"]/g, replacement: "ModuleVersion = '4.2.0'", automatic: true }
|
|
];
|
|
|
|
const manualChecks = [
|
|
{
|
|
id: 'MANUAL-SERVICEUI',
|
|
severity: 'critical',
|
|
pattern: /\b(ServiceUI\.exe|Invoke-ServiceUI\.ps1)\b/i,
|
|
title: 'Remove ServiceUI launch wrappers',
|
|
guidance: 'PSADT v4.1+ provides native user-session UI for Intune. Remove ServiceUI and test with SYSTEM context launch helpers.'
|
|
},
|
|
{
|
|
id: 'MANUAL-TEMPLATE-SHAPE',
|
|
severity: 'warning',
|
|
pattern: /function\s+(Install|Uninstall|Repair)-ADTDeployment/i,
|
|
title: 'Older function-based deployment phase shape detected',
|
|
guidance: 'Review the migrated script against the upstream v4 template that uses New-Variable phase scriptblocks and Open-ADTSession.'
|
|
},
|
|
{
|
|
id: 'MANUAL-RAW-MSIEXEC',
|
|
severity: 'warning',
|
|
pattern: /\bmsiexec(?:\.exe)?\b/i,
|
|
title: 'Raw msiexec call needs installer review',
|
|
guidance: 'Prefer Start-ADTMsiProcess or Start-ADTMspProcess so logging, success codes, and reboot handling stay consistent.'
|
|
},
|
|
{
|
|
id: 'MANUAL-INTUNE-DEFER',
|
|
severity: 'warning',
|
|
pattern: /Show-ADTInstallationWelcome[^\n\r]*-AllowDefer\b(?![^\n\r]*-DeferRunInterval)/i,
|
|
title: 'Intune deferral flow should include DeferRunInterval',
|
|
guidance: 'Add -DeferRunInterval to avoid repeated Intune retry prompts after a 1602 defer result.'
|
|
}
|
|
];
|
|
|
|
export function planPsadtMigration(content = '', options = {}) {
|
|
const source = String(content || '');
|
|
const steps = [];
|
|
let automaticCount = 0;
|
|
|
|
for (const rule of replacements) {
|
|
const matches = [...source.matchAll(rule.pattern)].filter((match) => !isCommentLine(source, match.index || 0));
|
|
if (!matches.length) continue;
|
|
automaticCount += matches.length;
|
|
steps.push({
|
|
id: rule.id,
|
|
type: 'replace',
|
|
automatic: rule.automatic,
|
|
status: 'ready',
|
|
title: rule.label,
|
|
count: matches.length,
|
|
lines: matches.slice(0, 8).map((match) => lineNumber(source, match.index || 0)),
|
|
replacement: rule.replacement
|
|
});
|
|
}
|
|
|
|
for (const rule of manualChecks) {
|
|
const match = rule.pattern.exec(source);
|
|
if (!match || isCommentLine(source, match.index || 0)) continue;
|
|
steps.push({
|
|
id: rule.id,
|
|
type: 'manual-review',
|
|
automatic: false,
|
|
status: 'review',
|
|
severity: rule.severity,
|
|
title: rule.title,
|
|
guidance: rule.guidance,
|
|
lines: [lineNumber(source, match.index || 0)]
|
|
});
|
|
}
|
|
|
|
if (!/Open-ADTSession/i.test(source)) {
|
|
steps.push({
|
|
id: 'MANUAL-OPEN-ADTSESSION',
|
|
type: 'manual-review',
|
|
automatic: false,
|
|
status: 'review',
|
|
severity: 'warning',
|
|
title: 'Open-ADTSession not detected',
|
|
guidance: 'Latest PSADT scripts should initialize the module and open an ADTSession before invoking phase logic.',
|
|
lines: []
|
|
});
|
|
}
|
|
|
|
return {
|
|
targetVersion: options.targetVersion || '4.2.0',
|
|
summary: {
|
|
steps: steps.length,
|
|
automatic: steps.filter((step) => step.automatic).length,
|
|
manual: steps.filter((step) => !step.automatic).length,
|
|
replacements: automaticCount
|
|
},
|
|
steps,
|
|
migratedContent: applyPsadtMigration(source)
|
|
};
|
|
}
|
|
|
|
export function applyPsadtMigration(content = '') {
|
|
let migrated = String(content || '');
|
|
for (const rule of replacements) {
|
|
migrated = replaceOutsideComments(migrated, rule.pattern, rule.replacement);
|
|
}
|
|
migrated = migrated.replace(/(Show-ADTInstallationPrompt[^\n\r]*)\s-Icon\s+\S+/gi, '$1');
|
|
if (!/POSHManager PSADT migration notes/i.test(migrated)) {
|
|
migrated = [
|
|
'# POSHManager PSADT migration notes:',
|
|
'# - Automatic replacements were applied for known v3/v4 legacy names and variables.',
|
|
'# - Review manual migration findings before deploying through Intune or any production channel.',
|
|
'',
|
|
migrated
|
|
].join('\n');
|
|
}
|
|
return migrated;
|
|
}
|
|
|
|
function replaceOutsideComments(content, pattern, replacement) {
|
|
return content.split(/\r?\n/).map((line) => {
|
|
if (line.trimStart().startsWith('#')) return line;
|
|
return line.replace(pattern, replacement);
|
|
}).join('\n');
|
|
}
|
|
|
|
function isCommentLine(content, index) {
|
|
const line = content.slice(0, index).split(/\r?\n/).length;
|
|
return content.split(/\r?\n/)[line - 1]?.trimStart().startsWith('#');
|
|
}
|
|
|
|
function lineNumber(content, index) {
|
|
return content.slice(0, index).split(/\r?\n/).length;
|
|
}
|