@@ -2573,30 +2573,78 @@ function Measure-ADTCompatibility
25732573 }
25742574 [System.Management.Automation.Language.Ast []]$commandAsts = $ScriptBlockAst.FindAll ($commandPredicate , $true )
25752575
2576- # Process all hashtable definitions that splat to legacy functions first
2576+ # 1. Process all variable contents used by legacy functions
25772577 foreach ($commandAst in $commandAsts )
25782578 {
25792579 $functionName = $commandAst.GetCommandName ()
25802580 $boundParameters = ($spBinder ::BindCommand($commandAst , $true )).BoundParameters
25812581
25822582 foreach ($boundParameter in $boundParameters.GetEnumerator ())
25832583 {
2584- if ($boundParameter.Value.Value.Splatted )
2584+ # Process all variables used that require transformation
2585+ $parameterName = $boundParameter.Key
2586+ $variableName = $boundParameter.Value.Value.VariablePath.UserPath
2587+
2588+ if ($variableName -and $functionMappings .$functionName.TransformParameters .$parameterName -is [ScriptBlock ])
25852589 {
2586- $splatVariableName = $boundParameter.Value.Value.VariablePath.UserPath
2590+ # Find the last assignment of the variable before the current command
2591+ [ScriptBlock ]$variableAssignmentPredicate = {
2592+ param ([System.Management.Automation.Language.Ast ]$Ast )
2593+ $Ast -is [System.Management.Automation.Language.AssignmentStatementAst ] -and $Ast.Left.Extent.Text -match " \`$ $variableName $" -and ($Ast.Extent.StartLineNumber -lt $commandAst.Extent.StartLineNumber -or ($Ast.Extent.StartLineNumber -eq $commandAst.Extent.StartLineNumber -and $Ast.Extent.StartColumnNumber -lt $commandAst.Extent.StartColumnNumber ))
2594+ }
2595+ [System.Management.Automation.Language.Ast ]$variableAssignmentAst = $ScriptBlockAst.FindAll ($variableAssignmentPredicate , $true ) | Select-Object - Last 1
2596+
2597+ if ($variableAssignmentAst )
2598+ {
2599+ $newVariableContent = ForEach-Object - InputObject $variableAssignmentAst.Right.Extent.Text - Process $functionMappings [$functionName ].TransformParameters[$parameterName ]
2600+ $newVariableContent = $newVariableContent -replace ' ^-\w+\s+`?' # Remove -Parameter name + space, plus potential backtick/linebreak
2601+
2602+ $outputMessage = " Modify variable:`n $ ( $variableAssignmentAst.Left.Extent.Text ) ` = $newVariableContent "
2603+
2604+ # Create a CorrectionExtent object for the suggested correction
2605+ $objParams = @ {
2606+ TypeName = ' Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.CorrectionExtent'
2607+ ArgumentList = @ (
2608+ $variableAssignmentAst.Extent.StartLineNumber
2609+ $variableAssignmentAst.Extent.EndLineNumber
2610+ $variableAssignmentAst.Extent.StartColumnNumber
2611+ $variableAssignmentAst.Extent.EndColumnNumber
2612+ " $ ( $variableAssignmentAst.Left.Extent.Text ) = $newVariableContent "
2613+ $MyInvocation.MyCommand.Definition
2614+ ' More information: https://psappdeploytoolkit.com/docs/reference/variables'
2615+ )
2616+ }
2617+ $correctionExtent = New-Object @objParams
2618+ $suggestedCorrections = New-Object System.Collections.ObjectModel.Collection[$ ($objParams.TypeName )]
2619+ $suggestedCorrections.Add ($correctionExtent ) | Out-Null
2620+
2621+ # Output the diagnostic record in the format expected by the ScriptAnalyzer
2622+ [Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord ]@ {
2623+ Message = $outputMessage
2624+ Extent = $variableAssignmentAst.Extent
2625+ RuleName = ' Measure-ADTCompatibility'
2626+ Severity = ' Warning'
2627+ RuleSuppressionID = ' ADTCompatibilitySuppression'
2628+ SuggestedCorrections = $suggestedCorrections
2629+ }
2630+ }
2631+ }
25872632
2633+ # Process all hashtable definitions that splat to legacy functions
2634+ if ($boundParameter.Value.Value.Splatted )
2635+ {
25882636 # Find the last assignment of the splat variable before the current command
25892637 [ScriptBlock ]$splatPredicate = {
25902638 param ([System.Management.Automation.Language.Ast ]$Ast )
2591- $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 ))
2639+ $Ast -is [System.Management.Automation.Language.AssignmentStatementAst ] -and $Ast.Left.Extent.Text -match " \`$ $variableName $" -and ($Ast.Extent.StartLineNumber -lt $commandAst.Extent.StartLineNumber -or ($Ast.Extent.StartLineNumber -eq $commandAst.Extent.StartLineNumber -and $Ast.Extent.StartColumnNumber -lt $commandAst.Extent.StartColumnNumber ))
25922640 }
25932641 [System.Management.Automation.Language.Ast ]$splatAst = $ScriptBlockAst.FindAll ($splatPredicate , $true ) | Select-Object - Last 1
25942642
25952643 if ($splatAst )
25962644 {
25972645 $splatModified = $false
25982646 $outputMessage = New-Object System.Text.StringBuilder
2599- $outputMessage.AppendLine (" Modify splat `$ $splatVariableName `:" ) | Out-Null
2647+ $outputMessage.AppendLine (" Modify splat `$ $variableName `:" ) | Out-Null
26002648
26012649 # Construct a hashtable in text form
26022650 $replacementHashText = New-Object System.Text.StringBuilder
@@ -2695,7 +2743,7 @@ function Measure-ADTCompatibility
26952743 }
26962744 }
26972745
2698- # Process all legacy variables second
2746+ # 2. Process all legacy variables
26992747 foreach ($variableAst in $variableAsts )
27002748 {
27012749 $variableName = $variableAst.VariablePath.UserPath
@@ -2760,7 +2808,7 @@ function Measure-ADTCompatibility
27602808 }
27612809 }
27622810
2763- # Redefine legacy functions last
2811+ # 3. Redefine legacy functions
27642812 foreach ($commandAst in $commandAsts )
27652813 {
27662814 $functionName = $commandAst.GetCommandName ()
0 commit comments