Skip to content

Commit 342be7e

Browse files
committed
Backtrace variable assignments
1 parent 3e97bff commit 342be7e

File tree

1 file changed

+55
-7
lines changed

1 file changed

+55
-7
lines changed

src/PSAppDeployToolkit.Tools/PSScriptAnalyzer/Measure-ADTCompatibility.psm1

Lines changed: 55 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)