PSScriptAnalyzer/Measure-ADTCompatibility.psm1
<#
.SYNOPSIS PSSCriptAnalyzer rules to check for usage of legacy PSAppDeployToolkit v3 commands or variables. .DESCRIPTION Can be used directly with PSSCriptAnalyzer or via Test-ADTCompatibility and Convert-ADTDeployment functions. .EXAMPLE Measure-ADTCompatibility -ScriptBlockAst $ScriptBlockAst .INPUTS [System.Management.Automation.Language.ScriptBlockAst] .OUTPUTS [Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord[]] .NOTES None #> function Measure-ADTCompatibility { [CmdletBinding()] [OutputType([Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord])] Param ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [System.Management.Automation.Language.ScriptBlockAst] $ScriptBlockAst ) Begin { $variableMappings = @{ AllowRebootPassThru = '$adtSession.AllowRebootPassThru' appArch = '$adtSession.AppArch' appLang = '$adtSession.AppLang' appName = '$adtSession.AppName' appRevision = '$adtSession.AppRevision' appScriptAuthor = '$adtSession.AppScriptAuthor' appScriptDate = '$adtSession.AppScriptDate' appScriptVersion = '$adtSession.AppScriptVersion' appVendor = '$adtSession.AppVendor' appVersion = '$adtSession.AppVersion' currentDate = '$adtSession.CurrentDate' currentDateTime = '$adtSession.CurrentDateTime' defaultMsiFile = '$adtSession.DefaultMsiFile' deployAppScriptDate = $null deployAppScriptFriendlyName = '$adtSession.DeployAppScriptFriendlyName' deployAppScriptParameters = '$adtSession.DeployAppScriptParameters' deployAppScriptVersion = '$adtSession.DeployAppScriptVersion' DeploymentType = '$adtSession.DeploymentType' deploymentTypeName = '$adtSession.DeploymentTypeName' DeployMode = '$adtSession.DeployMode' dirFiles = '$adtSession.DirFiles' dirSupportFiles = '$adtSession.DirSupportFiles' DisableScriptLogging = '$adtSession.DisableLogging' installName = '$adtSession.InstallName' installPhase = '$adtSession.InstallPhase' installTitle = '$adtSession.InstallTitle' logName = '$adtSession.LogName' logTempFolder = '$adtSession.LogTempFolder' scriptDirectory = '$adtSession.ScriptDirectory' TerminalServerMode = '$adtSession.TerminalServerMode' useDefaultMsi = '$adtSession.UseDefaultMsi' appDeployConfigFile = $null appDeployCustomTypesSourceCode = $null appDeployExtScriptDate = $null appDeployExtScriptFriendlyName = $null appDeployExtScriptParameters = $null appDeployExtScriptVersion = $null appDeployLogoBanner = $null appDeployLogoBannerHeight = $null appDeployLogoBannerMaxHeight = $null appDeployLogoBannerObject = $null appDeployLogoIcon = $null appDeployLogoImage = $null appDeployMainScriptAsyncParameters = $null appDeployMainScriptDate = $null appDeployMainScriptFriendlyName = $null appDeployMainScriptMinimumConfigVersion = $null appDeployMainScriptParameters = $null appDeployRunHiddenVbsFile = $null appDeployToolkitDotSourceExtensions = $null appDeployToolkitExtName = $null AsyncToolkitLaunch = $null BlockExecution = $null ButtonLeftText = $null ButtonMiddleText = $null ButtonRightText = $null CleanupBlockedApps = $null closeAppsCountdownGlobal = $null configBalloonTextComplete = '(Get-ADTStringTable).BalloonText.Complete' configBalloonTextError = '(Get-ADTStringTable).BalloonText.Error' configBalloonTextFastRetry = '(Get-ADTStringTable).BalloonText.FastRetry' configBalloonTextRestartRequired = '(Get-ADTStringTable).BalloonText.RestartRequired' configBalloonTextStart = '(Get-ADTStringTable).BalloonText.Start' configBannerIconBannerName = '(Get-ADTConfig).Assets.Banner' configBannerIconFileName = $null configBannerLogoImageFileName = '(Get-ADTConfig).Assets.Logo' configBlockExecutionMessage = '(Get-ADTStringTable).BlockExecution.Message' configClosePromptButtonClose = '(Get-ADTStringTable).ClosePrompt.ButtonClose' configClosePromptButtonContinue = '(Get-ADTStringTable).ClosePrompt.ButtonContinue' configClosePromptButtonContinueTooltip = '(Get-ADTStringTable).ClosePrompt.ButtonContinueTooltip' configClosePromptButtonDefer = '(Get-ADTStringTable).ClosePrompt.ButtonDefer' configClosePromptCountdownMessage = '(Get-ADTStringTable).ClosePrompt.CountdownMessage' configClosePromptMessage = '(Get-ADTStringTable).ClosePrompt.Message' configConfigDate = $null configConfigDetails = $null configConfigVersion = $null configDeferPromptDeadline = '(Get-ADTStringTable).DeferPrompt.Deadline' configDeferPromptExpiryMessage = '(Get-ADTStringTable).DeferPrompt.ExpiryMessage' configDeferPromptRemainingDeferrals = '(Get-ADTStringTable).DeferPrompt.RemainingDeferrals' configDeferPromptWarningMessage = '(Get-ADTStringTable).DeferPrompt.WarningMessage' configDeferPromptWelcomeMessage = '(Get-ADTStringTable).DeferPrompt.WelcomeMessage' configDeploymentTypeInstall = '(Get-ADTStringTable).DeploymentType.Install' configDeploymentTypeRepair = '(Get-ADTStringTable).DeploymentType.Repair' configDeploymentTypeUnInstall = '(Get-ADTStringTable).DeploymentType.Uninstall' configDiskSpaceMessage = '(Get-ADTStringTable).DiskSpace.Message' configInstallationDeferExitCode = '(Get-ADTConfig).UI.DeferExitCode' configInstallationPersistInterval = '(Get-ADTConfig).UI.DefaultPromptPersistInterval' configInstallationPromptToSave = '(Get-ADTConfig).UI.PromptToSaveTimeout' configInstallationRestartPersistInterval = '(Get-ADTConfig).UI.RestartPromptPersistInterval' configInstallationUIExitCode = '(Get-ADTConfig).UI.DefaultExitCode' configInstallationUILanguageOverride = '(Get-ADTConfig).UI.LanguageOverride' configInstallationUITimeout = '(Get-ADTConfig).UI.DefaultTimeout' configInstallationWelcomePromptDynamicRunningProcessEvaluation = '(Get-ADTConfig).UI.DynamicProcessEvaluation' configInstallationWelcomePromptDynamicRunningProcessEvaluationInterval = '(Get-ADTConfig).UI.DynamicProcessEvaluationInterval' configMSIInstallParams = '(Get-ADTConfig).MSI.InstallParams' configMSILogDir = 'if ($isAdmin) { (Get-ADTConfig).MSI.LogPath } else { (Get-ADTConfig).MSI.LogPathNoAdminRights }' configMSILoggingOptions = '(Get-ADTConfig).MSI.LoggingOptions' configMSIMutexWaitTime = '(Get-ADTConfig).MSI.MutexWaitTime' configMSISilentParams = '(Get-ADTConfig).MSI.SilentParams' configMSIUninstallParams = '(Get-ADTConfig).MSI.UninstallParams' configProgressMessageInstall = '(Get-ADTStringTable).Progress.MessageInstall' configProgressMessageRepair = '(Get-ADTStringTable).Progress.MessageRepair' configProgressMessageUninstall = '(Get-ADTStringTable).Progress.MessageUninstall' configRestartPromptButtonRestartLater = '(Get-ADTStringTable).RestartPrompt.ButtonRestartLater' configRestartPromptButtonRestartNow = '(Get-ADTStringTable).RestartPrompt.ButtonRestartNow' configRestartPromptMessage = '(Get-ADTStringTable).RestartPrompt.Message' configRestartPromptMessageRestart = '(Get-ADTStringTable).RestartPrompt.MessageRestart' configRestartPromptMessageTime = '(Get-ADTStringTable).RestartPrompt.MessageTime' configRestartPromptTimeRemaining = '(Get-ADTStringTable).RestartPrompt.TimeRemaining' configRestartPromptTitle = '(Get-ADTStringTable).RestartPrompt.Title' configShowBalloonNotifications = '(Get-ADTConfig).UI.BalloonNotifications' configToastAppName = '(Get-ADTConfig).UI.BalloonTitle' configToastDisable = '(Get-ADTConfig).UI.BalloonNotifications' configToolkitCachePath = '(Get-ADTConfig).Toolkit.CachePath' configToolkitCompressLogs = '(Get-ADTConfig).Toolkit.CompressLogs' configToolkitLogAppend = '(Get-ADTConfig).Toolkit.LogAppend' configToolkitLogDebugMessage = '(Get-ADTConfig).Toolkit.LogDebugMessage' configToolkitLogDir = 'if ($isAdmin) { (Get-ADTConfig).Toolkit.LogPath } else { (Get-ADTConfig).Toolkit.LogPathNoAdminRights }' configToolkitLogMaxHistory = '(Get-ADTConfig).Toolkit.LogMaxHistory' configToolkitLogMaxSize = '(Get-ADTConfig).Toolkit.LogMaxSize' configToolkitLogStyle = '(Get-ADTConfig).Toolkit.LogStyle' configToolkitLogWriteToHost = '(Get-ADTConfig).Toolkit.LogWriteToHost' configToolkitRegPath = '(Get-ADTConfig).Toolkit.RegPath' configToolkitRequireAdmin = '(Get-ADTConfig).Toolkit.RequireAdmin' configToolkitTempPath = 'if ($isAdmin) { (Get-ADTConfig).Toolkit.TempPath } else { (Get-ADTConfig).Toolkit.TempPathNoAdminRights }' configToolkitUseRobocopy = '(Get-ADTConfig).Toolkit.FileCopyMode -eq ''Robocopy''' configWelcomePromptCountdownMessage = '(Get-ADTStringTable).WelcomePrompt.Classic.CountdownMessage' configWelcomePromptCustomMessage = '(Get-ADTStringTable).WelcomePrompt.Classic.CustomMessage' CountdownNoHideSeconds = $null CountdownSeconds = $null currentTime = $null currentTimeZoneBias = $null defaultFont = $null deployModeNonInteractive = $null deployModeSilent = $null DeviceContextHandle = $null dirAppDeployTemp = $null dpiPixels = $null dpiScale = $null envOfficeChannelProperty = $null envShellFolders = $null exeMsiexec = $null exeSchTasks = $null exeWusa = $null ExitOnTimeout = $null formattedOSArch = $null formWelcomeStartPosition = $null GetAccountNameUsingSid = $null GetDisplayScaleFactor = $null GetLoggedOnUserDetails = $null GetLoggedOnUserTempPath = $null GraphicsObject = $null HKULanguages = $null HKUPrimaryLanguageShort = $null hr = $null Icon = $null installationStarted = $null InvocationInfo = $null invokingScript = $null IsOOBEComplete = 'Test-ADTOobeCompleted' IsTaskSchedulerHealthy = $null LocalPowerUsersGroup = $null LogFileInitialized = $null loggedOnUserTempPath = $null LogicalScreenHeight = $null LogTimeZoneBias = $null mainExitCode = $null Message = $null MessageAlignment = $null MinimizeWindows = $null moduleAppDeployToolkitMain = $null msiRebootDetected = $null NoCountdown = $null notifyIcon = $null OldDisableLoggingValue = $null oldPSWindowTitle = $null PersistPrompt = $null PhysicalScreenHeight = $null PrimaryWindowsUILanguage = $null ProgressRunspace = $null ProgressSyncHash = $null ReferencedAssemblies = $null ReferredInstallName = $null ReferredInstallTitle = $null ReferredLogName = $null regKeyAppExecution = $null regKeyApplications = $null regKeyDeferHistory = $null regKeyLotusNotes = $null RevertScriptLogging = $null runningProcessDescriptions = $null scriptFileName = $null scriptName = $null scriptParentPath = $null scriptPath = $null scriptRoot = $null scriptSeparator = $null ShowBlockedAppDialog = $null ShowInstallationPrompt = $null ShowInstallationRestartPrompt = $null switch = $null Timeout = $null Title = $null TopMost = $null TypeDef = $null UserDisplayScaleFactor = $null welcomeTimer = $null xmlBannerIconOptions = $null xmlConfig = $null xmlConfigFile = $null xmlConfigMSIOptions = $null xmlConfigUIOptions = $null xmlLoadLocalizedUIMessages = $null xmlToastOptions = $null xmlToolkitOptions = $null xmlUIMessageLanguage = $null xmlUIMessages = $null } $functionMappings = @{ 'Write-Log' = @{ 'NewFunction' = 'Write-ADTLogEntry' 'TransformParameters' = @{ 'Text' = { "-Message $_" } 'ContinueOnError' = { if ($_ -eq '$true') { '-ErrorAction SilentlyContinue' } else { '-ErrorAction Stop' } } } 'RemoveParameters' = @( 'AppendToLogFile' 'LogDebugMessage' 'MaxLogHistory' 'MaxLogFileSizeMB' 'WriteHost' ) } 'Exit-Script' = @{ 'NewFunction' = 'Exit-ADTScript' } 'Invoke-HKCURegistrySettingsForAllUsers' = @{ 'NewFunction' = 'Invoke-ADTAllUsersRegistryAction' 'TransformParameters' = @{ 'RegistrySettings' = { "-ScriptBlock $($_.Replace('$UserProfile', '$_'))" } } } 'Get-HardwarePlatform' = @{ 'NewFunction' = '$envHardwareType' 'RemoveParameters' = @( 'ContinueOnError' ) } 'Get-FreeDiskSpace' = @{ 'NewFunction' = 'Get-ADTFreeDiskSpace' 'TransformParameters' = @{ 'ContinueOnError' = { if ($_ -eq '$true') { '-ErrorAction SilentlyContinue' } else { '-ErrorAction Stop' } } } } 'Remove-InvalidFileNameChars' = @{ 'NewFunction' = 'Remove-ADTInvalidFileNameChars' } 'Get-InstalledApplication' = @{ 'NewFunction' = 'Get-ADTApplication' 'TransformParameters' = @{ 'ContinueOnError' = { if ($_ -eq '$true') { '-ErrorAction SilentlyContinue' } else { '-ErrorAction Stop' } } 'Exact' = '-NameMatch Exact' # Should inspect switch values here in case of -Switch:$false 'WildCard' = '-NameMatch WildCard' # Should inspect switch values here in case of -Switch:$false 'RegEx' = '-NameMatch RegEx' # Should inspect switch values here in case of -Switch:$false } } 'Remove-MSIApplications' = @{ 'NewFunction' = 'Uninstall-ADTApplication' 'TransformParameters' = @{ 'ContinueOnError' = { if ($_ -eq '$true') { '-ErrorAction SilentlyContinue' } else { '-ErrorAction Stop' } } 'Exact' = '-NameMatch Exact' # Should inspect switch values here in case of -Switch:$false 'WildCard' = '-NameMatch WildCard' # Should inspect switch values here in case of -Switch:$false 'Arguments' = { "-ArgumentList $_" } 'Parameters' = { "-ArgumentList $_" } 'AddParameters' = { "-AdditionalArgumentList $_" } 'LogName' = { "-LogFileName $_" } 'FilterApplication' = { $filterApplication = @(if ($null -eq $boundParameters.FilterApplication.Value.Extent) { $null } else { $boundParameters.FilterApplication.Value.SafeGetValue() }) $excludeFromUninstall = @(if ($null -eq $boundParameters.ExcludeFromUninstall.Value.Extent) { $null } else { $boundParameters.ExcludeFromUninstall.Value.SafeGetValue() }) $filterArray = $( foreach ($item in $filterApplication) { if ($null -ne $item) { if ($item.Count -eq 1 -and $item[0].Count -eq 3) { $item = $item[0] } # Handle the case where input is of the form @(, @('Prop', 'Value', 'Exact'), @('Prop', 'Value', 'Exact')) if ($item[2] -eq 'RegEx') { "`$_.$($item[0]) -match '$($item[1] -replace "'","''")'" } elseif ($item[2] -eq 'Contains') { $regEx = [System.Text.RegularExpressions.Regex]::Escape(($item[1] -replace "'", "''")) -replace '(?<!\\)\\ ', ' ' "`$_.$($item[0]) -match '$regEx'" } elseif ($item[2] -eq 'WildCard') { "`$_.$($item[0]) -like '$($item[1] -replace "'","''")'" } elseif ($item[2] -eq 'Exact') { if ($item[1] -is [System.Boolean]) { "`$_.$($item[0]) -eq `$$($item[1].ToString().ToLower())" } else { "`$_.$($item[0]) -eq '$($item[1] -replace "'","''")'" } } } } foreach ($item in $excludeFromUninstall) { if ($null -ne $item) { if ($item.Count -eq 1 -and $item[0].Count -eq 3) { $item = $item[0] } # Handle the case where input is of the form @(, @('Prop', 'Value', 'Exact'), @('Prop', 'Value', 'Exact')) if ($item[2] -eq 'RegEx') { "`$_.$($item[0]) -notmatch '$($item[1] -replace "'","''")'" } elseif ($item[2] -eq 'Contains') { $regEx = [System.Text.RegularExpressions.Regex]::Escape(($item[1] -replace "'", "''")) -replace '(?<!\\)\\ ', ' ' "`$_.$($item[0]) -notmatch '$regEx'" } elseif ($item[2] -eq 'WildCard') { "`$_.$($item[0]) -notlike '$($item[1] -replace "'","''")'" } elseif ($item[2] -eq 'Exact') { if ($item[1] -is [System.Boolean]) { "`$_.$($item[0]) -ne `$$($item[1].ToString().ToLower())" } else { "`$_.$($item[0]) -ne '$($item[1] -replace "'","''")'" } } } } ) $filterScript = $filterArray -join ' -and ' if ($filterScript) { "-FilterScript { $filterScript }" } } 'ExcludeFromUninstall' = { $filterApplication = @(if ($null -eq $boundParameters.FilterApplication.Value.Extent) { $null } else { $boundParameters.FilterApplication.Value.SafeGetValue() }) $excludeFromUninstall = @(if ($null -eq $boundParameters.ExcludeFromUninstall.Value.Extent) { $null } else { $boundParameters.ExcludeFromUninstall.Value.SafeGetValue() }) $filterArray = $( foreach ($item in $filterApplication) { if ($null -ne $item) { if ($item.Count -eq 1 -and $item[0].Count -eq 3) { $item = $item[0] } # Handle the case where input is of the form @(, @('Prop', 'Value', 'Exact'), @('Prop', 'Value', 'Exact')) if ($item[2] -eq 'RegEx') { "`$_.$($item[0]) -match '$($item[1] -replace "'","''")'" } elseif ($item[2] -eq 'Contains') { $regEx = [System.Text.RegularExpressions.Regex]::Escape(($item[1] -replace "'", "''")) -replace '(?<!\\)\\ ', ' ' "`$_.$($item[0]) -match '$regEx'" } elseif ($item[2] -eq 'WildCard') { "`$_.$($item[0]) -like '$($item[1] -replace "'","''")'" } elseif ($item[2] -eq 'Exact') { if ($item[1] -is [System.Boolean]) { "`$_.$($item[0]) -eq `$$($item[1].ToString().ToLower())" } else { "`$_.$($item[0]) -eq '$($item[1] -replace "'","''")'" } } } } foreach ($item in $excludeFromUninstall) { if ($null -ne $item) { if ($item.Count -eq 1 -and $item[0].Count -eq 3) { $item = $item[0] } # Handle the case where input is of the form @(, @('Prop', 'Value', 'Exact'), @('Prop', 'Value', 'Exact')) if ($item[2] -eq 'RegEx') { "`$_.$($item[0]) -notmatch '$($item[1] -replace "'","''")'" } elseif ($item[2] -eq 'Contains') { $regEx = [System.Text.RegularExpressions.Regex]::Escape(($item[1] -replace "'", "''")) -replace '(?<!\\)\\ ', ' ' "`$_.$($item[0]) -notmatch '$regEx'" } elseif ($item[2] -eq 'WildCard') { "`$_.$($item[0]) -notlike '$($item[1] -replace "'","''")'" } elseif ($item[2] -eq 'Exact') { if ($item[1] -is [System.Boolean]) { "`$_.$($item[0]) -ne `$$($item[1].ToString().ToLower())" } else { "`$_.$($item[0]) -ne '$($item[1] -replace "'","''")'" } } } } ) $filterScript = $filterArray -join ' -and ' if ($filterScript) { "-FilterScript { $filterScript }" } } } 'AddParameters' = @{ 'ApplicationType' = '-ApplicationType MSI' } } 'Get-FileVersion' = @{ 'NewFunction' = 'Get-ADTFileVersion' 'TransformParameters' = @{ 'ContinueOnError' = { if ($_ -eq '$true') { '-ErrorAction SilentlyContinue' } else { '-ErrorAction Stop' } } } } 'Get-UserProfiles' = @{ 'NewFunction' = 'Get-ADTUserProfiles' 'TransformParameters' = @{ 'ContinueOnError' = { if ($_ -eq '$true') { '-ErrorAction SilentlyContinue' } else { '-ErrorAction Stop' } } 'ExcludeSystemProfiles' = { if ($_ -eq '$false') { '-IncludeSystemProfiles' } } 'ExcludeServiceProfiles' = { if ($_ -eq '$false') { '-IncludeServiceProfiles' } } } } 'Update-Desktop' = @{ 'NewFunction' = 'Update-ADTDesktop' 'TransformParameters' = @{ 'ContinueOnError' = { if ($_ -eq '$true') { '-ErrorAction SilentlyContinue' } else { '-ErrorAction Stop' } } } } 'Refresh-Desktop' = @{ 'NewFunction' = 'Update-ADTDesktop' 'TransformParameters' = @{ 'ContinueOnError' = { if ($_ -eq '$true') { '-ErrorAction SilentlyContinue' } else { '-ErrorAction Stop' } } } } 'Update-SessionEnvironmentVariables' = @{ 'NewFunction' = 'Update-ADTEnvironmentPsProvider' 'TransformParameters' = @{ 'ContinueOnError' = { if ($_ -eq '$true') { '-ErrorAction SilentlyContinue' } else { '-ErrorAction Stop' } } } } 'Refresh-SessionEnvironmentVariables' = @{ 'NewFunction' = 'Update-ADTEnvironmentPsProvider' 'TransformParameters' = @{ 'ContinueOnError' = { if ($_ -eq '$true') { '-ErrorAction SilentlyContinue' } else { '-ErrorAction Stop' } } } } 'Copy-File' = @{ 'NewFunction' = 'Copy-ADTFile' 'TransformParameters' = @{ 'ContinueOnError' = { if ($_ -eq '$true') { '-ErrorAction SilentlyContinue' } else { '-ErrorAction Stop' } } 'ContinueFileCopyOnError' = { if ($_ -eq '$true') { '-ContinueFileCopyOnError' } else { $null } } 'UseRobocopy' = { if ($_ -eq '$true' -or $boundParameters.ContainsKey('RobocopyParams') -or $boundParameters.ContainsKey('RobocopyAdditionalParams')) { '-FileCopyMode Robocopy' } else { '-FileCopyMode Native' } } } } 'Remove-File' = @{ 'NewFunction' = 'Remove-ADTFile' 'TransformParameters' = @{ 'ContinueOnError' = { if ($_ -eq '$true') { '-ErrorAction SilentlyContinue' } else { '-ErrorAction Stop' } } } } 'Copy-FileToUserProfiles' = @{ 'NewFunction' = 'Copy-ADTFileToUserProfiles' 'TransformParameters' = @{ 'ContinueOnError' = { if ($_ -eq '$true') { '-ErrorAction SilentlyContinue' } else { '-ErrorAction Stop' } } 'ContinueFileCopyOnError' = { if ($_ -eq '$true') { '-ContinueFileCopyOnError' } else { $null } } 'UseRobocopy' = { if ($_ -eq '$true' -or $boundParameters.ContainsKey('RobocopyParams') -or $boundParameters.ContainsKey('RobocopyAdditionalParams')) { '-FileCopyMode Robocopy' } else { '-FileCopyMode Native' } } 'ExcludeSystemProfiles' = { if ($_ -eq '$false') { '-IncludeSystemProfiles' } } 'ExcludeServiceProfiles' = { if ($_ -eq '$false') { '-IncludeServiceProfiles' } } } } 'Show-InstallationPrompt' = @{ 'NewFunction' = 'Show-ADTInstallationPrompt' 'TransformParameters' = @{ 'Icon' = { if ($_ -ne 'None') { "-Icon $_" } } 'ExitOnTimeout' = { if ($_ -eq '$false') { '-NoExitOnTimeout' } } 'TopMost' = { if ($_ -eq '$false') { '-NotTopMost' } } } } 'Show-InstallationProgress' = @{ 'NewFunction' = 'Show-ADTInstallationProgress' 'TransformParameters' = @{ 'TopMost' = { if ($_ -eq '$false') { '-NotTopMost' } } 'Quiet' = '-InformationAction SilentlyContinue' # Should inspect switch values here in case of -Switch:$false } } 'Show-DialogBox' = @{ 'NewFunction' = 'Show-ADTDialogBox' 'TransformParameters' = @{ 'TopMost' = { if ($_ -eq '$false') { '-NotTopMost' } } } } 'Show-InstallationWelcome' = @{ 'NewFunction' = 'Show-ADTInstallationWelcome' 'TransformParameters' = @{ 'MinimizeWindows' = { if ($_ -eq '$false') { '-NoMinimizeWindows' } } 'TopMost' = { if ($_ -eq '$false') { '-NotTopMost' } } 'CloseAppsCountdown' = { "-CloseProcessesCountdown $_" } 'ForceCloseAppsCountdown' = { "-ForceCloseProcessesCountdown $_" } 'AllowDeferCloseApps' = '-AllowDeferCloseProcesses' # Should inspect switch values here in case of -Switch:$false 'CloseApps' = { $quoteChar = if ($boundParameters.CloseApps.Value.StringConstantType -eq 'DoubleQuoted') { '"' } else { "'" } $closeProcesses = $boundParameters.CloseApps.Value.Value.Split(',').ForEach({ $name, $description = $_.Split('=') if ($description) { "@{ Name = $quoteChar$($name)$quoteChar; Description = $quoteChar$($description)$quoteChar }" } else { "$quoteChar$($name)$quoteChar" } }) -join ', ' "-CloseProcesses $closeProcesses" } } } 'Get-WindowTitle' = @{ 'NewFunction' = 'Get-ADTWindowTitle' 'TransformParameters' = @{ 'DisableFunctionLogging' = '-InformationAction SilentlyContinue' # Should inspect switch values here in case of -Switch:$false } } 'Show-InstallationRestartPrompt' = @{ 'NewFunction' = 'Show-ADTInstallationRestartPrompt' 'TransformParameters' = @{ 'NoSilentRestart' = { if ($_ -eq '$false') { '-SilentRestart' } } 'TopMost' = { if ($_ -eq '$false') { '-NotTopMost' } } } } 'Show-BalloonTip' = @{ 'NewFunction' = 'Show-ADTBalloonTip' 'RemoveParameters' = @( 'NoWait' ) } 'Copy-ContentToCache' = @{ 'NewFunction' = 'Copy-ADTContentToCache' } 'Remove-ContentFromCache' = @{ 'NewFunction' = 'Remove-ADTContentFromCache' } 'Test-NetworkConnection' = @{ 'NewFunction' = 'Test-ADTNetworkConnection' } 'Get-LoggedOnUser' = @{ 'NewFunction' = 'Get-ADTLoggedOnUser' } 'Get-IniValue' = @{ 'NewFunction' = 'Get-ADTIniValue' 'TransformParameters' = @{ 'ContinueOnError' = { if ($_ -eq '$true') { '-ErrorAction SilentlyContinue' } else { '-ErrorAction Stop' } } } } 'Set-IniValue' = @{ 'NewFunction' = 'Set-ADTIniValue' 'TransformParameters' = @{ 'ContinueOnError' = { if ($_ -eq '$true') { '-ErrorAction SilentlyContinue' } else { '-ErrorAction Stop' } } } } 'New-Folder' = @{ 'NewFunction' = 'New-ADTFolder' 'TransformParameters' = @{ 'ContinueOnError' = { if ($_ -eq '$true') { '-ErrorAction SilentlyContinue' } else { '-ErrorAction Stop' } } } } 'Test-PowerPoint' = @{ 'NewFunction' = 'Test-ADTPowerPoint' } 'Update-GroupPolicy' = @{ 'NewFunction' = 'Update-ADTGroupPolicy' 'TransformParameters' = @{ 'ContinueOnError' = { if ($_ -eq '$true') { '-ErrorAction SilentlyContinue' } else { '-ErrorAction Stop' } } } } 'Get-UniversalDate' = @{ 'NewFunction' = 'Get-ADTUniversalDate' 'TransformParameters' = @{ 'ContinueOnError' = { if ($_ -eq '$true') { '-ErrorAction SilentlyContinue' } else { '-ErrorAction Stop' } } } } 'Test-ServiceExists' = @{ 'NewFunction' = 'Test-ADTServiceExists' 'TransformParameters' = @{ 'ContinueOnError' = { if ($_ -eq '$true') { '-ErrorAction SilentlyContinue' } else { '-ErrorAction Stop' } } } 'RemoveParameters' = @( 'ComputerName' ) } 'Disable-TerminalServerInstallMode' = @{ 'NewFunction' = 'Disable-ADTTerminalServerInstallMode' 'TransformParameters' = @{ 'ContinueOnError' = { if ($_ -eq '$true') { '-ErrorAction SilentlyContinue' } else { '-ErrorAction Stop' } } } } 'Enable-TerminalServerInstallMode' = @{ 'NewFunction' = 'Enable-ADTTerminalServerInstallMode' 'TransformParameters' = @{ 'ContinueOnError' = { if ($_ -eq '$true') { '-ErrorAction SilentlyContinue' } else { '-ErrorAction Stop' } } } } 'Configure-EdgeExtension' = @{ 'NewFunction' = { if ($boundParameters.ContainsKey('Add')) { 'Add-ADTEdgeExtension' } else { 'Remove-ADTEdgeExtension' } } # Should inspect switch values here in case of -Switch:$false 'RemoveParameters' = @( 'Add' 'Remove' ) } 'Resolve-Error' = @{ 'NewFunction' = 'Resolve-ADTErrorRecord' 'AddParameters' = @{ 'ExcludeErrorRecord' = { if (!$boundParameters.ContainsKey('GetErrorRecord') -or $boundParameters.GetErrorRecord.ConstantValue -eq $false -or $boundParameters.GetErrorRecord.Value.Extent.Text -eq '$false') { '-ExcludeErrorRecord' } } 'ExcludeErrorInvocation' = { if (!$boundParameters.ContainsKey('GetErrorInvocation') -or $boundParameters.GetErrorInvocation.ConstantValue -eq $false -or $boundParameters.GetErrorInvocation.Value.Extent.Text -eq '$false') { '-ExcludeErrorInvocation' } } 'ExcludeErrorException' = { if (!$boundParameters.ContainsKey('GetErrorException') -or $boundParameters.GetErrorException.ConstantValue -eq $false -or $boundParameters.GetErrorException.Value.Extent.Text -eq '$false') { '-ExcludeErrorException' } } 'ExcludeErrorInnerException' = { if (!$boundParameters.ContainsKey('GetErrorInnerException') -or $boundParameters.GetErrorInnerException.ConstantValue -eq $false -or $boundParameters.GetErrorInnerException.Value.Extent.Text -eq '$false') { '-ExcludeErrorInnerException' } } } } 'Get-ServiceStartMode' = @{ 'NewFunction' = 'Get-ADTServiceStartMode' 'TransformParameters' = @{ 'Name' = { "-Service $_" } 'ContinueOnError' = { if ($_ -eq '$true') { '-ErrorAction SilentlyContinue' } else { '-ErrorAction Stop' } } } 'RemoveParameters' = @( 'ComputerName' ) } 'Set-ServiceStartMode' = @{ 'NewFunction' = 'Set-ADTServiceStartMode' 'TransformParameters' = @{ 'Name' = { "-Service $_" } 'ContinueOnError' = { if ($_ -eq '$true') { '-ErrorAction SilentlyContinue' } else { '-ErrorAction Stop' } } } 'RemoveParameters' = @( 'ComputerName' ) } 'Execute-Process' = @{ 'NewFunction' = 'Start-ADTProcess' 'TransformParameters' = @{ 'Path' = { "-FilePath $_" } 'Arguments' = { "-ArgumentList $_" } 'Parameters' = { "-ArgumentList $_" } 'SecureParameters' = '-SecureArgumentList' # Should inspect switch values here in case of -Switch:$false 'IgnoreExitCodes' = { "-IgnoreExitCodes $($_.Trim('"').Trim("'") -split ',' -join ',')" } 'ExitOnProcessFailure' = { $ContinueOnError = if ($null -eq $boundParameters.ContinueOnError.Value.Extent) { $false } else { $boundParameters.ContinueOnError.Value.SafeGetValue() } $ExitOnProcessFailure = if ($null -eq $boundParameters.ExitOnProcessFailure.Value.Extent) { $true } else { $boundParameters.ExitOnProcessFailure.Value.SafeGetValue() } @('-ErrorAction Stop', '-ErrorAction SilentlyContinue')[$ContinueOnError -or !$ExitOnProcessFailure] } 'ContinueOnError' = { $ContinueOnError = if ($null -eq $boundParameters.ContinueOnError.Value.Extent) { $false } else { $boundParameters.ContinueOnError.Value.SafeGetValue() } $ExitOnProcessFailure = if ($null -eq $boundParameters.ExitOnProcessFailure.Value.Extent) { $true } else { $boundParameters.ExitOnProcessFailure.Value.SafeGetValue() } @('-ErrorAction Stop', '-ErrorAction SilentlyContinue')[$ContinueOnError -or !$ExitOnProcessFailure] } } } 'Execute-MSI' = @{ 'NewFunction' = 'Start-ADTMsiProcess' 'TransformParameters' = @{ 'Path' = { if ($_ -match '^[''"]?\{?([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}\}?[''"]?$') { "-ProductCode $_" } else { "-FilePath $_" } } 'Arguments' = { "-ArgumentList $_" } 'Parameters' = { "-ArgumentList $_" } 'AddParameters' = { "-AdditionalArgumentList $_" } 'SecureParameters' = '-SecureArgumentList' # Should inspect switch values here in case of -Switch:$false 'Transform' = { "-Transforms $(if ($_ -match "^'") { $_ -replace ';', "','" } elseif ($_ -match '^"') { $_ -replace ';', '","' } else { $_ })" } 'LogName' = { "-LogFileName $_" } 'IgnoreExitCodes' = { "-IgnoreExitCodes $($_.Trim('"').Trim("'") -split ',' -join ',')" } 'ExitOnProcessFailure' = { $ContinueOnError = if ($null -eq $boundParameters.ContinueOnError.Value.Extent) { $false } else { $boundParameters.ContinueOnError.Value.SafeGetValue() } $ExitOnProcessFailure = if ($null -eq $boundParameters.ExitOnProcessFailure.Value.Extent) { $true } else { $boundParameters.ExitOnProcessFailure.Value.SafeGetValue() } @('-ErrorAction Stop', '-ErrorAction SilentlyContinue')[$ContinueOnError -or !$ExitOnProcessFailure] } 'ContinueOnError' = { $ContinueOnError = if ($null -eq $boundParameters.ContinueOnError.Value.Extent) { $false } else { $boundParameters.ContinueOnError.Value.SafeGetValue() } $ExitOnProcessFailure = if ($null -eq $boundParameters.ExitOnProcessFailure.Value.Extent) { $true } else { $boundParameters.ExitOnProcessFailure.Value.SafeGetValue() } @('-ErrorAction Stop', '-ErrorAction SilentlyContinue')[$ContinueOnError -or !$ExitOnProcessFailure] } } } 'Execute-MSP' = @{ 'NewFunction' = 'Start-ADTMspProcess' 'TransformParameters' = @{ 'Path' = { "-FilePath $_" } } } 'Block-AppExecution' = @{ 'NewFunction' = 'Block-ADTAppExecution' } 'Unblock-AppExecution' = @{ 'NewFunction' = 'Unblock-ADTAppExecution' } 'Test-RegistryValue' = @{ 'NewFunction' = 'Test-ADTRegistryValue' 'TransformParameters' = @{ 'Value' = { "-Name $_" } } } 'Convert-RegistryPath' = @{ 'NewFunction' = 'Convert-ADTRegistryPath' 'TransformParameters' = @{ 'DisableFunctionLogging' = { if ($_ -eq '$false') { '-InformationAction Continue' } } } } 'Test-MSUpdates' = @{ 'NewFunction' = 'Test-ADTMSUpdates' 'TransformParameters' = @{ 'ContinueOnError' = { if ($_ -eq '$true') { '-ErrorAction SilentlyContinue' } else { '-ErrorAction Stop' } } } } 'Test-Battery' = @{ 'NewFunction' = 'Test-ADTBattery' } 'Start-ServiceAndDependencies' = @{ 'NewFunction' = 'Start-ADTServiceAndDependencies' 'TransformParameters' = @{ 'ContinueOnError' = { if ($_ -eq '$true') { '-ErrorAction SilentlyContinue' } else { '-ErrorAction Stop' } } } 'RemoveParameters' = @( 'ComputerName' 'SkipServiceExistsTest' ) } 'Stop-ServiceAndDependencies' = @{ 'NewFunction' = 'Stop-ADTServiceAndDependencies' 'TransformParameters' = @{ 'ContinueOnError' = { if ($_ -eq '$true') { '-ErrorAction SilentlyContinue' } else { '-ErrorAction Stop' } } } 'RemoveParameters' = @( 'ComputerName' 'SkipServiceExistsTest' ) } 'Set-RegistryKey' = @{ 'NewFunction' = 'Set-ADTRegistryKey' 'TransformParameters' = @{ 'ContinueOnError' = { if ($_ -eq '$true') { '-ErrorAction SilentlyContinue' } else { '-ErrorAction Stop' } } } } 'Remove-RegistryKey' = @{ 'NewFunction' = 'Remove-ADTRegistryKey' 'TransformParameters' = @{ 'ContinueOnError' = { if ($_ -eq '$true') { '-ErrorAction SilentlyContinue' } else { '-ErrorAction Stop' } } } } 'Remove-FileFromUserProfiles' = @{ 'NewFunction' = 'Remove-ADTFileFromUserProfiles' 'TransformParameters' = @{ 'ContinueOnError' = { if ($_ -eq '$true') { '-ErrorAction SilentlyContinue' } else { '-ErrorAction Stop' } } 'ExcludeSystemProfiles' = { if ($_ -eq '$false') { '-IncludeSystemProfiles' } } 'ExcludeServiceProfiles' = { if ($_ -eq '$false') { '-IncludeServiceProfiles' } } } } 'Get-RegistryKey' = @{ 'NewFunction' = 'Get-ADTRegistryKey' 'TransformParameters' = @{ 'Value' = { "-Name $_" } 'ContinueOnError' = { if ($_ -eq '$true') { '-ErrorAction SilentlyContinue' } else { '-ErrorAction Stop' } } } } 'Install-MSUpdates' = @{ 'NewFunction' = 'Install-ADTMSUpdates' } 'Get-SchedulerTask' = @{ 'NewFunction' = 'Get-ADTSchedulerTask' 'TransformParameters' = @{ 'ContinueOnError' = { if ($_ -eq '$true') { '-ErrorAction SilentlyContinue' } else { '-ErrorAction Stop' } } } } 'Get-PendingReboot' = @{ 'NewFunction' = 'Get-ADTPendingReboot' } 'Invoke-RegisterOrUnregisterDLL' = @{ 'NewFunction' = 'Invoke-ADTRegSvr32' 'TransformParameters' = @{ 'DLLAction' = { "-Action $_" } 'ContinueOnError' = { if ($_ -eq '$true') { '-ErrorAction SilentlyContinue' } else { '-ErrorAction Stop' } } } } 'Register-DLL' = @{ 'NewFunction' = 'Register-ADTDll' 'TransformParameters' = @{ 'ContinueOnError' = { if ($_ -eq '$true') { '-ErrorAction SilentlyContinue' } else { '-ErrorAction Stop' } } } } 'Unregister-DLL' = @{ 'NewFunction' = 'Unregister-ADTDll' 'TransformParameters' = @{ 'ContinueOnError' = { if ($_ -eq '$true') { '-ErrorAction SilentlyContinue' } else { '-ErrorAction Stop' } } } } 'Remove-Folder' = @{ 'NewFunction' = 'Remove-ADTFolder' 'TransformParameters' = @{ 'ContinueOnError' = { if ($_ -eq '$true') { '-ErrorAction SilentlyContinue' } else { '-ErrorAction Stop' } } } } 'Set-ActiveSetup' = @{ 'NewFunction' = 'Set-ADTActiveSetup' 'TransformParameters' = @{ 'ContinueOnError' = { if ($_ -eq '$true') { '-ErrorAction SilentlyContinue' } else { '-ErrorAction Stop' } } 'ExecuteForCurrentUser' = { if ($_ -eq '$false') { '-NoExecuteForCurrentUser' } } } } 'Set-ItemPermission' = @{ 'NewFunction' = 'Set-ADTItemPermission' 'TransformParameters' = @{ 'ContinueOnError' = { if ($_ -eq '$true') { '-ErrorAction SilentlyContinue' } else { '-ErrorAction Stop' } } 'File' = { "-Path $_" } 'Folder' = { "-Path $_" } 'Username' = { "-User $_" } 'Users' = { "-User $_" } 'SID' = { "-User $_" } 'Usernames' = { "-User $_" } 'Acl' = { "-Permission $_" } 'Grant' = { "-Permission $_" } 'Permissions' = { "-Permission $_" } 'Deny' = { "-Permission $_" } 'AccessControlType' = { "-PermissionType $_" } 'Add' = { "-Method $($_ -replace '^(Add|Set|Reset|Remove)(Specific|All)?$', '$1AccessRule$2')" } 'ApplyMethod' = { "-Method $($_ -replace '^(Add|Set|Reset|Remove)(Specific|All)?$', '$1AccessRule$2')" } 'ApplicationMethod' = { "-Method $($_ -replace '^(Add|Set|Reset|Remove)(Specific|All)?$', '$1AccessRule$2')" } 'Method' = { "-Method $($_ -replace '^(Add|Set|Reset|Remove)(Specific|All)?$', '$1AccessRule$2')" } } } 'New-MsiTransform' = @{ 'NewFunction' = 'New-ADTMsiTransform' 'TransformParameters' = @{ 'ContinueOnError' = { if ($_ -eq '$true') { '-ErrorAction SilentlyContinue' } else { '-ErrorAction Stop' } } } } 'Invoke-SCCMTask' = @{ 'NewFunction' = 'Invoke-ADTSCCMTask' 'TransformParameters' = @{ 'ContinueOnError' = { if ($_ -eq '$true') { '-ErrorAction SilentlyContinue' } else { '-ErrorAction Stop' } } } } 'Install-SCCMSoftwareUpdates' = @{ 'NewFunction' = 'Install-ADTSCCMSoftwareUpdates' 'TransformParameters' = @{ 'ContinueOnError' = { if ($_ -eq '$true') { '-ErrorAction SilentlyContinue' } else { '-ErrorAction Stop' } } } } 'Send-Keys' = @{ 'NewFunction' = 'Send-ADTKeys' } 'Get-Shortcut' = @{ 'NewFunction' = 'Get-ADTShortcut' 'TransformParameters' = @{ 'ContinueOnError' = { if ($_ -eq '$true') { '-ErrorAction SilentlyContinue' } else { '-ErrorAction Stop' } } } } 'Set-Shortcut' = @{ 'NewFunction' = 'Set-ADTShortcut' 'TransformParameters' = @{ 'ContinueOnError' = { if ($_ -eq '$true') { '-ErrorAction SilentlyContinue' } else { '-ErrorAction Stop' } } } } 'New-Shortcut' = @{ 'NewFunction' = 'New-ADTShortcut' 'TransformParameters' = @{ 'ContinueOnError' = { if ($_ -eq '$true') { '-ErrorAction SilentlyContinue' } else { '-ErrorAction Stop' } } } } 'Execute-ProcessAsUser' = @{ 'NewFunction' = 'Start-ADTProcessAsUser' 'TransformParameters' = @{ 'ContinueOnError' = { if ($_ -eq '$true') { '-ErrorAction SilentlyContinue' } else { '-ErrorAction Stop' } } } 'RemoveParameters' = @( 'TempPath' 'RunLevel' ) } 'Close-InstallationProgress' = @{ 'NewFunction' = 'Close-ADTInstallationProgress' 'RemoveParameters' = @( 'WaitingTime' ) } 'ConvertTo-NTAccountOrSID' = @{ 'NewFunction' = 'ConvertTo-ADTNTAccountOrSID' } 'Get-DeferHistory' = @{ 'NewFunction' = 'Get-ADTDeferHistory' } 'Set-DeferHistory' = @{ 'NewFunction' = 'Set-ADTDeferHistory' } 'Get-MsiTableProperty' = @{ 'NewFunction' = 'Get-ADTMsiTableProperty' 'TransformParameters' = @{ 'ContinueOnError' = { if ($_ -eq '$true') { '-ErrorAction SilentlyContinue' } else { '-ErrorAction Stop' } } } } 'Set-MsiProperty' = @{ 'NewFunction' = 'Set-ADTMsiProperty' 'TransformParameters' = @{ 'ContinueOnError' = { if ($_ -eq '$true') { '-ErrorAction SilentlyContinue' } else { '-ErrorAction Stop' } } } } 'Get-MsiExitCodeMessage' = @{ 'NewFunction' = 'Get-ADTMsiExitCodeMessage' } 'Get-ObjectProperty' = @{ 'NewFunction' = 'Get-ADTObjectProperty' } 'Invoke-ObjectMethod' = @{ 'NewFunction' = 'Invoke-ADTObjectMethod' } 'Get-PEFileArchitecture' = @{ 'NewFunction' = 'Get-ADTPEFileArchitecture' 'TransformParameters' = @{ 'ContinueOnError' = { if ($_ -eq '$true') { '-ErrorAction SilentlyContinue' } else { '-ErrorAction Stop' } } } } 'Test-IsMutexAvailable' = @{ 'NewFunction' = 'Test-ADTMutexAvailability' } 'New-ZipFile' = @{ 'NewFunction' = 'New-ADTZipFile' 'TransformParameters' = @{ 'ContinueOnError' = { if ($_ -eq '$true') { '-ErrorAction SilentlyContinue' } else { '-ErrorAction Stop' } } 'DestinationArchiveDirectoryPath' = { $destinationArchiveDirectoryPath = $boundParameters.DestinationArchiveDirectoryPath.Value.Value $destinationArchiveFileName = $boundParameters.DestinationArchiveFileName.Value.Value $quoteChar = if ($boundParameters.DestinationArchiveDirectoryPath.Value.StringConstantType -eq 'DoubleQuoted' -or $boundParameters.DestinationArchiveFileName.Value.StringConstantType -eq 'DoubleQuoted') { '"' } else { "'" } "-DestinationPath $quoteChar$([System.IO.Path]::Combine($destinationArchiveDirectoryPath, $destinationArchiveFileName))$quoteChar" } 'DestinationArchiveFileName' = { $destinationArchiveDirectoryPath = $boundParameters.DestinationArchiveDirectoryPath.Value.Value $destinationArchiveFileName = $boundParameters.DestinationArchiveFileName.Value.Value $quoteChar = if ($boundParameters.DestinationArchiveDirectoryPath.Value.StringConstantType -eq 'DoubleQuoted' -or $boundParameters.DestinationArchiveFileName.Value.StringConstantType -eq 'DoubleQuoted') { '"' } else { "'" } "-DestinationPath $quoteChar$([System.IO.Path]::Combine($destinationArchiveDirectoryPath, $destinationArchiveFileName))$quoteChar" } 'SourceDirectoryPath' = { "-LiteralPath $_" } 'SourceFilePath' = { "-LiteralPath $_" } 'OverWriteArchive' = '-Force' # Should inspect switch values here in case of -Switch:$false } } 'Set-PinnedApplication' = @{ 'NewFunction' = '# The function [Set-PinnedApplication] has been removed from PSAppDeployToolkit as its functionality no longer works with Windows 10 1809 or higher targets.' } } $spBinder = [System.Management.Automation.Language.StaticParameterBinder] } Process { try { # Get legacy variables [ScriptBlock]$variablePredicate = { param ([System.Management.Automation.Language.Ast]$Ast) $Ast -is [System.Management.Automation.Language.VariableExpressionAst] -and $Ast.Parent -isnot [System.Management.Automation.Language.ParameterAst] -and $Ast.VariablePath.UserPath -in $variableMappings.Keys } [System.Management.Automation.Language.Ast[]]$variableAsts = $ScriptBlockAst.FindAll($variablePredicate, $true) # Get legacy functions [ScriptBlock]$commandPredicate = { param ([System.Management.Automation.Language.Ast]$Ast) $Ast -is [System.Management.Automation.Language.CommandAst] -and $Ast.GetCommandName() -in $functionMappings.Keys } [System.Management.Automation.Language.Ast[]]$commandAsts = $ScriptBlockAst.FindAll($commandPredicate, $true) # Process all hashtable definitions that splat to legacy functions first foreach ($commandAst in $commandAsts) { $functionName = $commandAst.GetCommandName() $boundParameters = ($spBinder::BindCommand($commandAst, $true)).BoundParameters foreach ($boundParameter in $boundParameters.GetEnumerator()) { if ($boundParameter.Value.Value.Splatted) { $splatVariableName = $boundParameter.Value.Value.VariablePath.UserPath # Find the last assignment of the splat variable before the current command [ScriptBlock]$splatPredicate = { param ([System.Management.Automation.Language.Ast]$Ast) $Ast -is [System.Management.Automation.Language.AssignmentStatementAst] -and $Ast.Left.Extent.Text -match "\`$$splatVariableName$" -and ($Ast.Extent.StartLineNumber -lt $commandAst.Extent.StartLineNumber -or ($Ast.Extent.StartLineNumber -eq $commandAst.Extent.StartLineNumber -and $Ast.Extent.StartColumnNumber -lt $commandAst.Extent.StartColumnNumber)) } [System.Management.Automation.Language.Ast]$splatAst = $ScriptBlockAst.FindAll($splatPredicate, $true) | Select-Object -Last 1 if ($splatAst) { $splatModified = $false $outputMessage = New-Object System.Text.StringBuilder $outputMessage.AppendLine("Modify splat `$$splatVariableName`:") | Out-Null # Construct a hashtable in text form $replacementHashText = New-Object System.Text.StringBuilder if ($splatAst.Extent.StartLineNumber -eq $splatAst.Extent.EndLineNumber) { $splatHashLineSeparator = ' ' $splatHashItemSeparator = '; ' $splatHashIndent = 0 } else { $splatHashLineSeparator = "`n" $splatHashItemSeparator = "`n" $splatHashIndent = $splatAst.Extent.StartColumnNumber + 3 } $replacementHashText.Append("$($splatAst.Left.Extent.Text) = @{$splatHashLineSeparator") | Out-Null $replacementHashItems = foreach ($keyValuePair in $splatAst.Right.Expression.KeyValuePairs) { if ($keyValuePair.Item1.Value -in $functionMappings[$functionName].RemoveParameters) { $splatModified = $true continue } if ($keyValuePair.Item1.Value -in $functionMappings[$functionName].TransformParameters.Keys) { $splatModified = $true if ($functionMappings[$functionName].TransformParameters[$keyValuePair.Item1.Value] -is [ScriptBlock]) { # If parameter is remapped to a script block, invoke it to get the new parameter $splatNewParam = ForEach-Object -InputObject $keyValuePair.Item2 -Process $functionMappings[$functionName].TransformParameters[$keyValuePair.Item1.Value] } else { # Otherwise, use the new parameter name as-is $splatNewParam = $functionMappings[$functionName].TransformParameters[$keyValuePair.Item1.Value] } # Split splatNewParam into parameter name and value if ($splatNewParam -match "-([a-zA-Z0-9_-]+)\s*(.*)?") { $paramName = $matches[1] $paramValue = $matches[2] if ([string]::IsNullOrWhiteSpace($paramValue)) { # Assume if no value is provided it's a switch parameter, which in a hashtable for splatting, needs to be set to $true $paramValue = '$true' } "$(' ' * $splatHashIndent)$paramName = $paramValue" $outputMessage.AppendLine("$($keyValuePair.Item1.Value) = $($keyValuePair.Item2.Extent.Text) → $paramName = $paramValue") | Out-Null } } else { # Write the key-value pair as-is "$(' ' * $splatHashIndent)$($keyValuePair.Item1.Value) = $($keyValuePair.Item2.Extent.Text)" } } if ($splatModified) { $replacementHashText.Append($replacementHashItems -join $splatHashItemSeparator) | Out-Null $replacementHashText.Append("$splatHashLineSeparator$(' ' * ([math]::Max(0, $splatHashIndent - 4)))}") | Out-Null # Create a CorrectionExtent object for the suggested correction $objParams = @{ TypeName = 'Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.CorrectionExtent' ArgumentList = @( $splatAst.Extent.StartLineNumber $splatAst.Extent.EndLineNumber $splatAst.Extent.StartColumnNumber $splatAst.Extent.EndColumnNumber $replacementHashText.ToString() $MyInvocation.MyCommand.Definition "More information: https://psappdeploytoolkit.com/docs/reference/functions" ) } $correctionExtent = New-Object @objParams $suggestedCorrections = New-Object System.Collections.ObjectModel.Collection[Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.CorrectionExtent] $suggestedCorrections.Add($correctionExtent) | Out-Null # Output the diagnostic record in the format expected by the ScriptAnalyzer [Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord]@{ Message = $outputMessage.ToString().Trim() Extent = $splatAst.Extent RuleName = 'Measure-ADTCompatibility' Severity = [Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticSeverity]::Warning RuleSuppressionID = 'ADTCompatibilitySuppression' SuggestedCorrections = $suggestedCorrections } } } } } } # Process all legacy variables second foreach ($variableAst in $variableAsts) { $variableName = $variableAst.VariablePath.UserPath $newVariable = $variableMappings[$variableName] if ([string]::IsNullOrWhiteSpace($newVariable)) { $outputMessage = "The variable [`$$variableName] is deprecated and no longer available." $suggestedCorrections = $null } else { if ($newVariable -match 'ADTSession') { $outputMessage = "The variable [`$$variableName] is now a session variable and no longer directly available. Use [$newVariable] instead." } elseif ($newVariable -match 'ADTConfig') { $outputMessage = "The variable [`$$variableName] is now a config variable and no longer directly available. Use [$newVariable] instead." } elseif ($newVariable -match 'ADTString') { $outputMessage = "The variable [`$$variableName] is now a localization string variable and no longer directly available. Use [$newVariable] instead." } else { $outputMessage = "The variable [`$$variableName] is deprecated. Use [$newVariable] instead." } if ($newVariable -like '*.*' -and $variableAst.Parent.StringConstantType -in [System.Management.Automation.Language.StringConstantType]'DoubleQuoted', [System.Management.Automation.Language.StringConstantType]'DoubleQuotedHereString') { # Wrap variable in $() if it is contains a . and is used in a double-quoted string $newVariable = "`$($newVariable)" } # Create a CorrectionExtent object for the suggested correction $objParams = @{ TypeName = 'Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.CorrectionExtent' ArgumentList = @( $variableAst.Extent.StartLineNumber $variableAst.Extent.EndLineNumber $variableAst.Extent.StartColumnNumber $variableAst.Extent.EndColumnNumber $newVariable $MyInvocation.MyCommand.Definition 'More information: https://psappdeploytoolkit.com/docs/reference/variables' ) } $correctionExtent = New-Object @objParams $suggestedCorrections = New-Object System.Collections.ObjectModel.Collection[$($objParams.TypeName)] $suggestedCorrections.Add($correctionExtent) | Out-Null } # Output the diagnostic record in the format expected by the ScriptAnalyzer [Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord]@{ Message = $outputMessage Extent = $variableAst.Extent RuleName = 'Measure-ADTCompatibility' Severity = 'Warning' RuleSuppressionID = 'ADTCompatibilitySuppression' SuggestedCorrections = $suggestedCorrections } } # Redefine legacy functions last foreach ($commandAst in $commandAsts) { $functionName = $commandAst.GetCommandName() # Use a StringBuilder for the output message, but a collection for newParams, since we want to search it as we go to avoid duplicate insertions, which are possible when multiple v3 parameters are combined into one $outputMessage = New-Object System.Text.StringBuilder $newParams = New-Object System.Collections.Generic.List[System.String] if ($functionMappings[$functionName].NewFunction -match '^#') { # If function is remapped to a comment, use the comment as the message and skip parameter processing $newFunction = $functionMappings[$functionName].NewFunction $outputMessage.AppendLine($newFunction.TrimStart('#').Trim()) | Out-Null } else { # Define these parameters first since scriptblocks may reference them $boundParameters = ($spBinder::BindCommand($commandAst, $true)).BoundParameters if ($functionMappings[$functionName].NewFunction -is [ScriptBlock]) { # If function is remapped to a script block, invoke it to get the new function name $newFunction = Invoke-Command -ScriptBlock $functionMappings[$functionName].NewFunction } else { # Otherwise, use the new function name as-is $newFunction = $functionMappings[$functionName].NewFunction } $outputMessage.AppendLine("The function [$functionName] is deprecated, use [$newFunction] instead.") | Out-Null foreach ($boundParameter in $boundParameters.GetEnumerator()) { if ($boundParameter.Key -in $functionMappings[$functionName].RemoveParameters) { $outputMessage.AppendLine("-$($boundParameter.Key) is deprecated.") | Out-Null continue } if ($boundParameter.Key -in $functionMappings[$functionName].TransformParameters.Keys) { if ($functionMappings[$functionName].TransformParameters[$boundParameter.Key] -is [ScriptBlock]) { # If parameter is remapped to a script block, invoke it to get the new parameter $newParam = ForEach-Object -InputObject $boundParameter.Value.Value.Extent.Text -Process $functionMappings[$functionName].TransformParameters[$boundParameter.Key] } else { # Otherwise, use the new parameter name as-is $newParam = $functionMappings[$functionName].TransformParameters[$boundParameter.Key] } if ([string]::IsNullOrWhiteSpace($newParam)) { # If newParam is empty, assume parameter should be removed (RemoveParameters definition is preferred, but it is not suitable for conditional removals) $outputMessage.AppendLine("Removed parameter: -$($boundParameter.Key)") | Out-Null continue } if ($newParams.Contains($newParam)) { # If the new param value is already present in the new command, skip it. This can happen when 2 parameters are combined into one in the new syntax (e.g. Remove-MSIApplications -FilterApplication -ExcludeFromUninstall) continue } if ($boundParameter.Value.ConstantValue -and $boundParameter.Value.Value.ParameterName -eq $boundParameter.Key) { # This is a simple switch $outputMessage.AppendLine("-$($boundParameter.Key) → $newParam") | Out-Null } elseif ($boundParameter.Key -eq $boundParameter.Value.Value.Parent.ParameterName) { # This is a switch bound with a value, e.g. -Switch:$true $outputMessage.AppendLine("-$($boundParameter.Key) → $newParam") | Out-Null } else { # This is a regular parameter, e.g. -Path 'xxx' $outputMessage.AppendLine("-$($boundParameter.Key) $($boundParameter.Value.Value.Extent.Text) → $newParam") | Out-Null } } else { # If not removed or transformed, pass through original parameter as-is, making some assumptions about the parsed input to do so if ($boundParameter.Value.ConstantValue -and $boundParameter.Value.Value.ParameterName -eq $boundParameter.Key) { # This is a simple switch $newParam = "-$($boundParameter.Key)" } elseif ($boundParameter.Key -eq $boundParameter.Value.Value.Parent.ParameterName) { # This is a switch bound with a value, e.g. -Switch:$true $newParam = $boundParameters.Value.Value.Parent.Extent.Text } elseif ($boundParameter.Value.Value.Splatted) { # This is a splatted parameter, e.g. @params, retain the original value $NewParam = $boundParameter.Value.Value.Extent.Text } else { # This is a regular parameter, e.g. -Path 'xxx' $newParam = "-$($boundParameter.Key) $($boundParameter.Value.Value.Extent.Text)" } } if (![string]::IsNullOrWhiteSpace($newParam)) { $newParams.Add($newParam) | Out-Null } } foreach ($addParameter in $functionMappings[$functionName].AddParameters.Keys) { if ($functionMappings[$functionName].AddParameters[$addParameter] -is [ScriptBlock]) { # If parameter is remapped to a script block, invoke it to get the new parameter $newParam = ForEach-Object -InputObject $addParameter -Process $functionMappings[$functionName].AddParameters[$addParameter] } else { # Otherwise, use the new parameter name as-is $newParam = $functionMappings[$functionName].AddParameters[$addParameter] } if (![string]::IsNullOrWhiteSpace($newParam)) { $newParams.Add($newParam) | Out-Null $outputMessage.AppendLine("Add Parameter: $newParam") | Out-Null } } } # Construct the new command $newCommand = $newFunction + ' ' + ($newParams -join ' ') # Create a CorrectionExtent object for the suggested correction $objParams = @{ TypeName = 'Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.CorrectionExtent' ArgumentList = @( $commandAst.Extent.StartLineNumber $commandAst.Extent.EndLineNumber $commandAst.Extent.StartColumnNumber $commandAst.Extent.EndColumnNumber $newCommand $MyInvocation.MyCommand.Definition "More information: https://psappdeploytoolkit.com/docs/reference/functions" ) } $correctionExtent = New-Object @objParams $suggestedCorrections = New-Object System.Collections.ObjectModel.Collection[Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.CorrectionExtent] $suggestedCorrections.Add($correctionExtent) | Out-Null # Output the diagnostic record in the format expected by the ScriptAnalyzer [Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord]@{ Message = $outputMessage.ToString().Trim() Extent = $commandAst.Extent RuleName = 'Measure-ADTCompatibility' Severity = [Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticSeverity]::Warning RuleSuppressionID = 'ADTCompatibilitySuppression' SuggestedCorrections = $suggestedCorrections } } } catch { $PSCmdlet.ThrowTerminatingError($PSItem) } } } Export-ModuleMember Measure-ADTCompatibility # SIG # Begin signature block # MIIuKwYJKoZIhvcNAQcCoIIuHDCCLhgCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDc83OHK0/Sj86t # LY2BuW1E6wD6pxPgs5XELXFj3SHtDqCCE5UwggWQMIIDeKADAgECAhAFmxtXno4h # MuI5B72nd3VcMA0GCSqGSIb3DQEBDAUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQK # EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNV # BAMTGERpZ2lDZXJ0IFRydXN0ZWQgUm9vdCBHNDAeFw0xMzA4MDExMjAwMDBaFw0z # ODAxMTUxMjAwMDBaMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJ # bmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0 # IFRydXN0ZWQgUm9vdCBHNDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB # AL/mkHNo3rvkXUo8MCIwaTPswqclLskhPfKK2FnC4SmnPVirdprNrnsbhA3EMB/z # G6Q4FutWxpdtHauyefLKEdLkX9YFPFIPUh/GnhWlfr6fqVcWWVVyr2iTcMKyunWZ # anMylNEQRBAu34LzB4TmdDttceItDBvuINXJIB1jKS3O7F5OyJP4IWGbNOsFxl7s # Wxq868nPzaw0QF+xembud8hIqGZXV59UWI4MK7dPpzDZVu7Ke13jrclPXuU15zHL # 2pNe3I6PgNq2kZhAkHnDeMe2scS1ahg4AxCN2NQ3pC4FfYj1gj4QkXCrVYJBMtfb # BHMqbpEBfCFM1LyuGwN1XXhm2ToxRJozQL8I11pJpMLmqaBn3aQnvKFPObURWBf3 # JFxGj2T3wWmIdph2PVldQnaHiZdpekjw4KISG2aadMreSx7nDmOu5tTvkpI6nj3c # AORFJYm2mkQZK37AlLTSYW3rM9nF30sEAMx9HJXDj/chsrIRt7t/8tWMcCxBYKqx # YxhElRp2Yn72gLD76GSmM9GJB+G9t+ZDpBi4pncB4Q+UDCEdslQpJYls5Q5SUUd0 # viastkF13nqsX40/ybzTQRESW+UQUOsxxcpyFiIJ33xMdT9j7CFfxCBRa2+xq4aL # T8LWRV+dIPyhHsXAj6KxfgommfXkaS+YHS312amyHeUbAgMBAAGjQjBAMA8GA1Ud # EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTs1+OC0nFdZEzf # Lmc/57qYrhwPTzANBgkqhkiG9w0BAQwFAAOCAgEAu2HZfalsvhfEkRvDoaIAjeNk # aA9Wz3eucPn9mkqZucl4XAwMX+TmFClWCzZJXURj4K2clhhmGyMNPXnpbWvWVPjS # PMFDQK4dUPVS/JA7u5iZaWvHwaeoaKQn3J35J64whbn2Z006Po9ZOSJTROvIXQPK # 7VB6fWIhCoDIc2bRoAVgX+iltKevqPdtNZx8WorWojiZ83iL9E3SIAveBO6Mm0eB # cg3AFDLvMFkuruBx8lbkapdvklBtlo1oepqyNhR6BvIkuQkRUNcIsbiJeoQjYUIp # 5aPNoiBB19GcZNnqJqGLFNdMGbJQQXE9P01wI4YMStyB0swylIQNCAmXHE/A7msg # dDDS4Dk0EIUhFQEI6FUy3nFJ2SgXUE3mvk3RdazQyvtBuEOlqtPDBURPLDab4vri # RbgjU2wGb2dVf0a1TD9uKFp5JtKkqGKX0h7i7UqLvBv9R0oN32dmfrJbQdA75PQ7 # 9ARj6e/CVABRoIoqyc54zNXqhwQYs86vSYiv85KZtrPmYQ/ShQDnUBrkG5WdGaG5 # nLGbsQAe79APT0JsyQq87kP6OnGlyE0mpTX9iV28hWIdMtKgK1TtmlfB2/oQzxm3 # i0objwG2J5VT6LaJbVu8aNQj6ItRolb58KaAoNYes7wPD1N1KarqE3fk3oyBIa0H # EEcRrYc9B9F1vM/zZn4wggawMIIEmKADAgECAhAIrUCyYNKcTJ9ezam9k67ZMA0G # CSqGSIb3DQEBDAUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJ # bmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0 # IFRydXN0ZWQgUm9vdCBHNDAeFw0yMTA0MjkwMDAwMDBaFw0zNjA0MjgyMzU5NTla # MGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UE # AxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25pbmcgUlNBNDA5NiBTSEEz # ODQgMjAyMSBDQTEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDVtC9C # 0CiteLdd1TlZG7GIQvUzjOs9gZdwxbvEhSYwn6SOaNhc9es0JAfhS0/TeEP0F9ce # 2vnS1WcaUk8OoVf8iJnBkcyBAz5NcCRks43iCH00fUyAVxJrQ5qZ8sU7H/Lvy0da # E6ZMswEgJfMQ04uy+wjwiuCdCcBlp/qYgEk1hz1RGeiQIXhFLqGfLOEYwhrMxe6T # SXBCMo/7xuoc82VokaJNTIIRSFJo3hC9FFdd6BgTZcV/sk+FLEikVoQ11vkunKoA # FdE3/hoGlMJ8yOobMubKwvSnowMOdKWvObarYBLj6Na59zHh3K3kGKDYwSNHR7Oh # D26jq22YBoMbt2pnLdK9RBqSEIGPsDsJ18ebMlrC/2pgVItJwZPt4bRc4G/rJvmM # 1bL5OBDm6s6R9b7T+2+TYTRcvJNFKIM2KmYoX7BzzosmJQayg9Rc9hUZTO1i4F4z # 8ujo7AqnsAMrkbI2eb73rQgedaZlzLvjSFDzd5Ea/ttQokbIYViY9XwCFjyDKK05 # huzUtw1T0PhH5nUwjewwk3YUpltLXXRhTT8SkXbev1jLchApQfDVxW0mdmgRQRNY # mtwmKwH0iU1Z23jPgUo+QEdfyYFQc4UQIyFZYIpkVMHMIRroOBl8ZhzNeDhFMJlP # /2NPTLuqDQhTQXxYPUez+rbsjDIJAsxsPAxWEQIDAQABo4IBWTCCAVUwEgYDVR0T # AQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUaDfg67Y7+F8Rhvv+YXsIiGX0TkIwHwYD # VR0jBBgwFoAU7NfjgtJxXWRM3y5nP+e6mK4cD08wDgYDVR0PAQH/BAQDAgGGMBMG # A1UdJQQMMAoGCCsGAQUFBwMDMHcGCCsGAQUFBwEBBGswaTAkBggrBgEFBQcwAYYY # aHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEEGCCsGAQUFBzAChjVodHRwOi8vY2Fj # ZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNydDBDBgNV # HR8EPDA6MDigNqA0hjJodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRU # cnVzdGVkUm9vdEc0LmNybDAcBgNVHSAEFTATMAcGBWeBDAEDMAgGBmeBDAEEATAN # BgkqhkiG9w0BAQwFAAOCAgEAOiNEPY0Idu6PvDqZ01bgAhql+Eg08yy25nRm95Ry # sQDKr2wwJxMSnpBEn0v9nqN8JtU3vDpdSG2V1T9J9Ce7FoFFUP2cvbaF4HZ+N3HL # IvdaqpDP9ZNq4+sg0dVQeYiaiorBtr2hSBh+3NiAGhEZGM1hmYFW9snjdufE5Btf # Q/g+lP92OT2e1JnPSt0o618moZVYSNUa/tcnP/2Q0XaG3RywYFzzDaju4ImhvTnh # OE7abrs2nfvlIVNaw8rpavGiPttDuDPITzgUkpn13c5UbdldAhQfQDN8A+KVssIh # dXNSy0bYxDQcoqVLjc1vdjcshT8azibpGL6QB7BDf5WIIIJw8MzK7/0pNVwfiThV # 9zeKiwmhywvpMRr/LhlcOXHhvpynCgbWJme3kuZOX956rEnPLqR0kq3bPKSchh/j # wVYbKyP/j7XqiHtwa+aguv06P0WmxOgWkVKLQcBIhEuWTatEQOON8BUozu3xGFYH # Ki8QxAwIZDwzj64ojDzLj4gLDb879M4ee47vtevLt/B3E+bnKD+sEq6lLyJsQfmC # XBVmzGwOysWGw/YmMwwHS6DTBwJqakAwSEs0qFEgu60bhQjiWQ1tygVQK+pKHJ6l # /aCnHwZ05/LWUpD9r4VIIflXO7ScA+2GRfS0YW6/aOImYIbqyK+p/pQd52MbOoZW # eE4wggdJMIIFMaADAgECAhAK+Vu2vqIMhQ6YxvuOrAj5MA0GCSqGSIb3DQEBCwUA # MGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UE # AxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25pbmcgUlNBNDA5NiBTSEEz # ODQgMjAyMSBDQTEwHhcNMjQwOTA1MDAwMDAwWhcNMjcwOTA3MjM1OTU5WjCB0TET # MBEGCysGAQQBgjc8AgEDEwJVUzEZMBcGCysGAQQBgjc8AgECEwhDb2xvcmFkbzEd # MBsGA1UEDwwUUHJpdmF0ZSBPcmdhbml6YXRpb24xFDASBgNVBAUTCzIwMTMxNjM4 # MzI3MQswCQYDVQQGEwJVUzERMA8GA1UECBMIQ29sb3JhZG8xFDASBgNVBAcTC0Nh # c3RsZSBSb2NrMRkwFwYDVQQKExBQYXRjaCBNeSBQQywgTExDMRkwFwYDVQQDExBQ # YXRjaCBNeSBQQywgTExDMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA # uydxko2Hrl6sANJUjfdypKP60qBH5EkhfaRQAnn+e3vg2eVcbiEWIjlrMYzvK2sg # OMBbwGebqAURkFmUCKDdGxcxKeuXdaXPHWPKwc2WjYCFajrX6HofiiwNzOCdL6VE # 4PDQhPRR7SIdNNFSrx5C4ZDN1T6OH+ydX7EQF8+NBUNHRbEVdl+h9H5Aexx63afa # 8zu3g/GXluyXKbb+JHtgNJaUgFuFORTxw1TO6qH+S6Hrppf9QcAFmu4xGtkc2FSh # gv0NgWMNGDZqJr/o9sqJ2tdaZHDyr6H8PvY8egoUshF7ccgEYtEEdB9SRR8mVQik # 1w5oGTjDWjHj+8jgTpzletRywptk/m8PehVBN8ntqoSdvLLcuQVzmuPLzN/iuKh5 # sZeWvqPONApcEnZcONpXebyiUPnEePr5rZAU7hMjMw2ZPnQlMcbGvtgP2qi7m2f3 # mXFYxWjlKCxaApYHeqSFeWC8zM7OYL2HlZ+GuK4XG8jKVE6sWSW9Wk/dm0vJbasv # AgMBAAGjggICMIIB/jAfBgNVHSMEGDAWgBRoN+Drtjv4XxGG+/5hewiIZfROQjAd # BgNVHQ4EFgQU5GCU3SEqeIbhhY9eyU0LcTI75X8wPQYDVR0gBDYwNDAyBgVngQwB # AzApMCcGCCsGAQUFBwIBFhtodHRwOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwDgYD # VR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMIG1BgNVHR8Ega0wgaow # U6BRoE+GTWh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRH # NENvZGVTaWduaW5nUlNBNDA5NlNIQTM4NDIwMjFDQTEuY3JsMFOgUaBPhk1odHRw # Oi8vY3JsNC5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRDb2RlU2lnbmlu # Z1JTQTQwOTZTSEEzODQyMDIxQ0ExLmNybDCBlAYIKwYBBQUHAQEEgYcwgYQwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBcBggrBgEFBQcwAoZQ # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0Q29k # ZVNpZ25pbmdSU0E0MDk2U0hBMzg0MjAyMUNBMS5jcnQwCQYDVR0TBAIwADANBgkq # hkiG9w0BAQsFAAOCAgEAqA0ub/ilMgdIvMiBeWBoiMxe5OIblObGI7lemcP2WEqa # EASW11/wVwJU63ZwhtkQaNU4rXjf6fqy5pOUzpQXgYjSaO4D/AOMJKHlypxslFqZ # /dYpcue2xE3H7lmO4KPf8VxXuFIUqjLetU+kkh7o/Q52RabVAuOrPFKnObixy1HI # x0/5F+RuP9xhqmDbfM7l5zUAcuOCCkY7buuInEsip9BZXUiVb8K5bPR9Rk7Doat4 # FQmN72xjakcEZOMU/vg0ZgVa8nxkBXtVsjxbsr+bODn0cddHK1QHWil/PmpANkxN # 7H8tdCAZ8bTzIvvudxSLnt7ssbbQDkAyNw0btDH+MKv/l+VcYyQH51Z5xT9DvHCm # Ed774boZkP2GfTFvn7/gISEjTdOuUGstdrgSwg1zJPqgK7zWxK48xC7awpa3gwOs # 9pnyiqHG3rx84/SHUiAL2lkljsD3epmRxsWeZhZNY93xEpQHe9LBvo/t4VRjZzqU # z+pfEMPqeX/g5+mpb4ap6ZmNJuAYJFmU0LIkCLQN9mKXi1Il9WU6ifn3vYutGMSL # /BdeWP+7fM7MZLiO+1BIsBdSmV6pZVS3LRBAy3wIlbWL69mvyLCPIQ7z4dtfuzwC # 36E9k2vhzeiDQ+k1dFJDSdxTDetsck0FuD1ovhiu2caL4BdFsCWsXPLMyvu6OlYx # ghnsMIIZ6AIBATB9MGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwg # SW5jLjFBMD8GA1UEAxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25pbmcg # UlNBNDA5NiBTSEEzODQgMjAyMSBDQTECEAr5W7a+ogyFDpjG+46sCPkwDQYJYIZI # AWUDBAIBBQCggYQwGAYKKwYBBAGCNwIBDDEKMAigAoAAoQKAADAZBgkqhkiG9w0B # CQMxDAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAv # BgkqhkiG9w0BCQQxIgQgMFz+qdFFBl/hy7tPyY8KwqpR+dYyPZTasQyuF1CsFcQw # DQYJKoZIhvcNAQEBBQAEggGAZHEH7iH6qpPfP5CEfnoTzuLbUclb8nV6feuKTsFC # N1z/LGYxGJ1fSHYU7aDtRSSoyW9Ug6JAa/QRmZvT55uDxM9DeZLCrnBYK++poVoc # eV0xNAGJ2amS6zXsTx4jWZu2VGh5d1oOoIHtjNDt67aJUjJT6tVpar+qcelpOU5b # kAJU0VDVLSA7uphy7XXvsmoOsvRsMWDlUmvAuBDT27kPEcLR7oIQdgcKVUqhG4vT # 198DwYk2nlasyu2Y/lYNkU/N2e3N5EyO9gZXnmlaoecfhUkxrwYsXIR8fvF5LsCu # Gs1zKEUuG3E8+bajs4SvOZQBdyBpz/O1XbIM5YKVARcB6UPSOJW9/G68q0uK1Vdv # Lt5sI6D7N9pyEOVrpRfnIXvXDMzNoU4jnV8TboBi4ovTeC5YBmcwMK/tUPpU74Vt # Lm4ZqJuwxCO9R6XRnB97qwOcNi76YDvlc7SfQGANgWWsHZk4fZcDexV2gjcj5Xo7 # TRWBFmjsmujQ9y+xfbiQk/DVoYIXOTCCFzUGCisGAQQBgjcDAwExghclMIIXIQYJ # KoZIhvcNAQcCoIIXEjCCFw4CAQMxDzANBglghkgBZQMEAgEFADB3BgsqhkiG9w0B # CRABBKBoBGYwZAIBAQYJYIZIAYb9bAcBMDEwDQYJYIZIAWUDBAIBBQAEILXbFZbk # NWFO6QaEn48PsfzdEQWXSRhtyLOMpA3O5aqfAhBBzB+xuaoj7qxceNM8Q3NjGA8y # MDI0MTIxNjE1MTAxOFqgghMDMIIGvDCCBKSgAwIBAgIQC65mvFq6f5WHxvnpBOMz # BDANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNl # cnQsIEluYy4xOzA5BgNVBAMTMkRpZ2lDZXJ0IFRydXN0ZWQgRzQgUlNBNDA5NiBT # SEEyNTYgVGltZVN0YW1waW5nIENBMB4XDTI0MDkyNjAwMDAwMFoXDTM1MTEyNTIz # NTk1OVowQjELMAkGA1UEBhMCVVMxETAPBgNVBAoTCERpZ2lDZXJ0MSAwHgYDVQQD # ExdEaWdpQ2VydCBUaW1lc3RhbXAgMjAyNDCCAiIwDQYJKoZIhvcNAQEBBQADggIP # ADCCAgoCggIBAL5qc5/2lSGrljC6W23mWaO16P2RHxjEiDtqmeOlwf0KMCBDEr4I # xHRGd7+L660x5XltSVhhK64zi9CeC9B6lUdXM0s71EOcRe8+CEJp+3R2O8oo76EO # 7o5tLuslxdr9Qq82aKcpA9O//X6QE+AcaU/byaCagLD/GLoUb35SfWHh43rOH3bp # LEx7pZ7avVnpUVmPvkxT8c2a2yC0WMp8hMu60tZR0ChaV76Nhnj37DEYTX9ReNZ8 # hIOYe4jl7/r419CvEYVIrH6sN00yx49boUuumF9i2T8UuKGn9966fR5X6kgXj3o5 # WHhHVO+NBikDO0mlUh902wS/Eeh8F/UFaRp1z5SnROHwSJ+QQRZ1fisD8UTVDSup # WJNstVkiqLq+ISTdEjJKGjVfIcsgA4l9cbk8Smlzddh4EfvFrpVNnes4c16Jidj5 # XiPVdsn5n10jxmGpxoMc6iPkoaDhi6JjHd5ibfdp5uzIXp4P0wXkgNs+CO/CacBq # U0R4k+8h6gYldp4FCMgrXdKWfM4N0u25OEAuEa3JyidxW48jwBqIJqImd93NRxvd # 1aepSeNeREXAu2xUDEW8aqzFQDYmr9ZONuc2MhTMizchNULpUEoA6Vva7b1XCB+1 # rxvbKmLqfY/M/SdV6mwWTyeVy5Z/JkvMFpnQy5wR14GJcv6dQ4aEKOX5AgMBAAGj # ggGLMIIBhzAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADAWBgNVHSUBAf8E # DDAKBggrBgEFBQcDCDAgBgNVHSAEGTAXMAgGBmeBDAEEAjALBglghkgBhv1sBwEw # HwYDVR0jBBgwFoAUuhbZbU2FL3MpdpovdYxqII+eyG8wHQYDVR0OBBYEFJ9XLAN3 # DigVkGalY17uT5IfdqBbMFoGA1UdHwRTMFEwT6BNoEuGSWh0dHA6Ly9jcmwzLmRp # Z2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNFJTQTQwOTZTSEEyNTZUaW1lU3Rh # bXBpbmdDQS5jcmwwgZAGCCsGAQUFBwEBBIGDMIGAMCQGCCsGAQUFBzABhhhodHRw # Oi8vb2NzcC5kaWdpY2VydC5jb20wWAYIKwYBBQUHMAKGTGh0dHA6Ly9jYWNlcnRz # LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNFJTQTQwOTZTSEEyNTZUaW1l # U3RhbXBpbmdDQS5jcnQwDQYJKoZIhvcNAQELBQADggIBAD2tHh92mVvjOIQSR9lD # kfYR25tOCB3RKE/P09x7gUsmXqt40ouRl3lj+8QioVYq3igpwrPvBmZdrlWBb0Hv # qT00nFSXgmUrDKNSQqGTdpjHsPy+LaalTW0qVjvUBhcHzBMutB6HzeledbDCzFzU # y34VarPnvIWrqVogK0qM8gJhh/+qDEAIdO/KkYesLyTVOoJ4eTq7gj9UFAL1UruJ # KlTnCVaM2UeUUW/8z3fvjxhN6hdT98Vr2FYlCS7Mbb4Hv5swO+aAXxWUm3WpByXt # gVQxiBlTVYzqfLDbe9PpBKDBfk+rabTFDZXoUke7zPgtd7/fvWTlCs30VAGEsshJ # mLbJ6ZbQ/xll/HjO9JbNVekBv2Tgem+mLptR7yIrpaidRJXrI+UzB6vAlk/8a1u7 # cIqV0yef4uaZFORNekUgQHTqddmsPCEIYQP7xGxZBIhdmm4bhYsVA6G2WgNFYagL # DBzpmk9104WQzYuVNsxyoVLObhx3RugaEGru+SojW4dHPoWrUhftNpFC5H7QEY7M # hKRyrBe7ucykW7eaCuWBsBb4HOKRFVDcrZgdwaSIqMDiCLg4D+TPVgKx2EgEdeoH # NHT9l3ZDBD+XgbF+23/zBjeCtxz+dL/9NWR6P2eZRi7zcEO1xwcdcqJsyz/JceEN # c2Sg8h3KeFUCS7tpFk7CrDqkMIIGrjCCBJagAwIBAgIQBzY3tyRUfNhHrP0oZipe # WzANBgkqhkiG9w0BAQsFADBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNl # cnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdp # Q2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMjIwMzIzMDAwMDAwWhcNMzcwMzIyMjM1 # OTU5WjBjMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xOzA5 # BgNVBAMTMkRpZ2lDZXJ0IFRydXN0ZWQgRzQgUlNBNDA5NiBTSEEyNTYgVGltZVN0 # YW1waW5nIENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxoY1Bkmz # wT1ySVFVxyUDxPKRN6mXUaHW0oPRnkyibaCwzIP5WvYRoUQVQl+kiPNo+n3znIkL # f50fng8zH1ATCyZzlm34V6gCff1DtITaEfFzsbPuK4CEiiIY3+vaPcQXf6sZKz5C # 3GeO6lE98NZW1OcoLevTsbV15x8GZY2UKdPZ7Gnf2ZCHRgB720RBidx8ald68Dd5 # n12sy+iEZLRS8nZH92GDGd1ftFQLIWhuNyG7QKxfst5Kfc71ORJn7w6lY2zkpsUd # zTYNXNXmG6jBZHRAp8ByxbpOH7G1WE15/tePc5OsLDnipUjW8LAxE6lXKZYnLvWH # po9OdhVVJnCYJn+gGkcgQ+NDY4B7dW4nJZCYOjgRs/b2nuY7W+yB3iIU2YIqx5K/ # oN7jPqJz+ucfWmyU8lKVEStYdEAoq3NDzt9KoRxrOMUp88qqlnNCaJ+2RrOdOqPV # A+C/8KI8ykLcGEh/FDTP0kyr75s9/g64ZCr6dSgkQe1CvwWcZklSUPRR8zZJTYsg # 0ixXNXkrqPNFYLwjjVj33GHek/45wPmyMKVM1+mYSlg+0wOI/rOP015LdhJRk8mM # DDtbiiKowSYI+RQQEgN9XyO7ZONj4KbhPvbCdLI/Hgl27KtdRnXiYKNYCQEoAA6E # VO7O6V3IXjASvUaetdN2udIOa5kM0jO0zbECAwEAAaOCAV0wggFZMBIGA1UdEwEB # /wQIMAYBAf8CAQAwHQYDVR0OBBYEFLoW2W1NhS9zKXaaL3WMaiCPnshvMB8GA1Ud # IwQYMBaAFOzX44LScV1kTN8uZz/nupiuHA9PMA4GA1UdDwEB/wQEAwIBhjATBgNV # HSUEDDAKBggrBgEFBQcDCDB3BggrBgEFBQcBAQRrMGkwJAYIKwYBBQUHMAGGGGh0 # dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBBBggrBgEFBQcwAoY1aHR0cDovL2NhY2Vy # dHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZFJvb3RHNC5jcnQwQwYDVR0f # BDwwOjA4oDagNIYyaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1 # c3RlZFJvb3RHNC5jcmwwIAYDVR0gBBkwFzAIBgZngQwBBAIwCwYJYIZIAYb9bAcB # MA0GCSqGSIb3DQEBCwUAA4ICAQB9WY7Ak7ZvmKlEIgF+ZtbYIULhsBguEE0TzzBT # zr8Y+8dQXeJLKftwig2qKWn8acHPHQfpPmDI2AvlXFvXbYf6hCAlNDFnzbYSlm/E # UExiHQwIgqgWvalWzxVzjQEiJc6VaT9Hd/tydBTX/6tPiix6q4XNQ1/tYLaqT5Fm # niye4Iqs5f2MvGQmh2ySvZ180HAKfO+ovHVPulr3qRCyXen/KFSJ8NWKcXZl2szw # cqMj+sAngkSumScbqyQeJsG33irr9p6xeZmBo1aGqwpFyd/EjaDnmPv7pp1yr8TH # wcFqcdnGE4AJxLafzYeHJLtPo0m5d2aR8XKc6UsCUqc3fpNTrDsdCEkPlM05et3/ # JWOZJyw9P2un8WbDQc1PtkCbISFA0LcTJM3cHXg65J6t5TRxktcma+Q4c6umAU+9 # Pzt4rUyt+8SVe+0KXzM5h0F4ejjpnOHdI/0dKNPH+ejxmF/7K9h+8kaddSweJywm # 228Vex4Ziza4k9Tm8heZWcpw8De/mADfIBZPJ/tgZxahZrrdVcA6KYawmKAr7ZVB # tzrVFZgxtGIJDwq9gdkT/r+k0fNX2bwE+oLeMt8EifAAzV3C+dAjfwAL5HYCJtnw # ZXZCpimHCUcr5n8apIUP/JiW9lVUKx+A+sDyDivl1vupL0QVSucTDh3bNzgaoSv2 # 7dZ8/DCCBY0wggR1oAMCAQICEA6bGI750C3n79tQ4ghAGFowDQYJKoZIhvcNAQEM # BQAwZTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UE # CxMQd3d3LmRpZ2ljZXJ0LmNvbTEkMCIGA1UEAxMbRGlnaUNlcnQgQXNzdXJlZCBJ # RCBSb290IENBMB4XDTIyMDgwMTAwMDAwMFoXDTMxMTEwOTIzNTk1OVowYjELMAkG # A1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRp # Z2ljZXJ0LmNvbTEhMB8GA1UEAxMYRGlnaUNlcnQgVHJ1c3RlZCBSb290IEc0MIIC # IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAv+aQc2jeu+RdSjwwIjBpM+zC # pyUuySE98orYWcLhKac9WKt2ms2uexuEDcQwH/MbpDgW61bGl20dq7J58soR0uRf # 1gU8Ug9SH8aeFaV+vp+pVxZZVXKvaJNwwrK6dZlqczKU0RBEEC7fgvMHhOZ0O21x # 4i0MG+4g1ckgHWMpLc7sXk7Ik/ghYZs06wXGXuxbGrzryc/NrDRAX7F6Zu53yEio # ZldXn1RYjgwrt0+nMNlW7sp7XeOtyU9e5TXnMcvak17cjo+A2raRmECQecN4x7ax # xLVqGDgDEI3Y1DekLgV9iPWCPhCRcKtVgkEy19sEcypukQF8IUzUvK4bA3VdeGbZ # OjFEmjNAvwjXWkmkwuapoGfdpCe8oU85tRFYF/ckXEaPZPfBaYh2mHY9WV1CdoeJ # l2l6SPDgohIbZpp0yt5LHucOY67m1O+SkjqePdwA5EUlibaaRBkrfsCUtNJhbesz # 2cXfSwQAzH0clcOP9yGyshG3u3/y1YxwLEFgqrFjGESVGnZifvaAsPvoZKYz0YkH # 4b235kOkGLimdwHhD5QMIR2yVCkliWzlDlJRR3S+Jqy2QXXeeqxfjT/JvNNBERJb # 5RBQ6zHFynIWIgnffEx1P2PsIV/EIFFrb7GrhotPwtZFX50g/KEexcCPorF+CiaZ # 9eRpL5gdLfXZqbId5RsCAwEAAaOCATowggE2MA8GA1UdEwEB/wQFMAMBAf8wHQYD # VR0OBBYEFOzX44LScV1kTN8uZz/nupiuHA9PMB8GA1UdIwQYMBaAFEXroq/0ksuC # MS1Ri6enIZ3zbcgPMA4GA1UdDwEB/wQEAwIBhjB5BggrBgEFBQcBAQRtMGswJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3 # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNydDBFBgNVHR8EPjA8MDqgOKA2hjRodHRwOi8vY3JsMy5kaWdpY2VydC5j # b20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3JsMBEGA1UdIAQKMAgwBgYEVR0g # ADANBgkqhkiG9w0BAQwFAAOCAQEAcKC/Q1xV5zhfoKN0Gz22Ftf3v1cHvZqsoYcs # 7IVeqRq7IviHGmlUIu2kiHdtvRoU9BNKei8ttzjv9P+Aufih9/Jy3iS8UgPITtAq # 3votVs/59PesMHqai7Je1M/RQ0SbQyHrlnKhSLSZy51PpwYDE3cnRNTnf+hZqPC/ # Lwum6fI0POz3A8eHqNJMQBk1RmppVLC4oVaO7KTVPeix3P0c2PR3WlxUjG/voVA9 # /HYJaISfb8rbII01YBwCA8sgsKxYoA5AY8WYIsGyWfVVa88nq2x2zm8jLfR+cWoj # ayL/ErhULSd+2DrZ8LaHlv1b0VysGMNNn3O3AamfV6peKOK5lDGCA3YwggNyAgEB # MHcwYzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMTswOQYD # VQQDEzJEaWdpQ2VydCBUcnVzdGVkIEc0IFJTQTQwOTYgU0hBMjU2IFRpbWVTdGFt # cGluZyBDQQIQC65mvFq6f5WHxvnpBOMzBDANBglghkgBZQMEAgEFAKCB0TAaBgkq # hkiG9w0BCQMxDQYLKoZIhvcNAQkQAQQwHAYJKoZIhvcNAQkFMQ8XDTI0MTIxNjE1 # MTAxOFowKwYLKoZIhvcNAQkQAgwxHDAaMBgwFgQU29OF7mLb0j575PZxSFCHJNWG # W0UwLwYJKoZIhvcNAQkEMSIEIOhDSpb+gMfj+B/hNoAdK5oXsPMmpP0WsMNh6KhH # wCbzMDcGCyqGSIb3DQEJEAIvMSgwJjAkMCIEIHZ2n6jyYy8fQws6IzCu1lZ1/tdz # 2wXWZbkFk5hDj5rbMA0GCSqGSIb3DQEBAQUABIICAIHboqyU/OXuxVlO5RdrZPJa # lHcryxyzLI1cGSn+655ykFYQL5F+61MlWKpfsJI9KX/JRva4CIrxdtD1zc4rTRXi # MTNz/nIrNaY5VFvx5t0spnmXD1sIRS9r7NTOyzkHi5YWy7hm1bFbRhEMvlyJYfbE # OKieNDKtEJGAJdf8tHNVH4nrcdqmErq4GVjMoLwR416PQz6YHhyPp4dnpXJgZbVx # KMetv+szUsqMVoWVGoTLtOH2Ie9i6nGOI1PCHy8ITXb/3uqtv3DVVWz4gRvXm6Tl # YCGAFUNEaPFPIfrSBw+1oH0bu4Xgm5WwnKx3o9dyjntiGGBiPUoaQ46gdH132ygK # vfFSmPvGDAXNbCSkzRFjIIKXnQS9z/tzXSFx3zdti2j5ptxAfUU8tPuMqrIkUIB/ # SP2J+qQtFDnFYsLwjGZSPIa8PH8xOiQCpkPKV0IDrJ/AlMrFdmho+4nbw3+qBQoT # X5AH19A7S0v9hp5Qi+b2FMrsHxlcQoyGFhrX2QYQjR7uXDulH3oIEzJ6P1KJ69zW # bccwx5xL01HNFWgqlJ3B4NAAYnPmaFi48E+3Xtz4QsDGlrIrjQe7t/s/yrgo9s/w # CLv6nt5yTLl9Hi3/4PCWZowpgiNnCSFcImV0rUcCAX8eD4cAQXkOjXyhi8W5ZweK # WL3f7LdP+73lVbgqkAY6 # SIG # End signature block |