A wrong warning about unused variable, but that variable used later in code:

+1
I've seen this as well with Insiders build + latest everything. But it's not consistent and sometimes I just have to restart the powershell session
I tried running Script Analyzer on its own against the original repro and I'm seeing the warning. Here's the repro:
In the file repro.ps1:
$a = 0
$b = @(1, 2)
$b | ForEach-Object {
$a += 1
}
Write-Host $a
in a terminal:
Install-Module -Name PSScriptAnalyzer
Invoke-ScriptAnalyzer -Path path/to/repro.ps1 -Settings PSGallery -Recurse
The output:
RuleName Severity ScriptName Line Message
-------- -------- ---------- ---- -------
PSUseDeclaredVarsMoreThanAssignment Warning repro2.ps1 4 The variable 'a' is assigned but never used.
I think this warning is appropriate. In your example, $a in the original assignment and the $a inside the foreach block are in two different scopes. Try this:
$a = 1
& {
$a = 2
}
$a

I don't believe there is an accurate way for PSScriptAnalyzer to guess that your intention is to use the $a variable in the parent scope, and it has to assume that you have assigned an unused variable.
There are various issues with false positives of this rule that would probably need to be re-written from the ground up using a different technique to overcome its limitations. I plan to collate all those issues in a meta-issue at some point.
Here is my example. $RemoveCount is reported as unused. $RemoveError is not
$BaseDir = "C:\Temp\attest"
get-childitem $BaseDir*_AttestListing.csv | foreach {
$CSVfile=$_
write-log "Processing data file: $($CSVfile.name)" -verbose
$RemoveCount = 0
$RemoveError = $false
import-csv $CSVfile |foreach{
$line = $_
if ($line."Remove Member?" -match "[yYxX]") {
echo "Removing $($line."Member Name") from $($line."Group Name")"
#write-log "Removing $("$_.Member Name") from $("$_.Group Name")" -verbose
If (Remove-Member($line)) {
$RemoveCount = $RemoveCount + 1
} else {
$RemoveError = $true
}
}
}
if ($RemoveError -eq $true){
Write-log "Error processing changes for: $($CSVFile.fullname)" -verbose
# If error removing, file is not renamed and must be processed manually
} else {
if ($RemoveCount -eq 0) {
Write-log "No changes processed for $($CSVFile.fullname)" -verbose
}Else {
Write-log "$RemoveCount members removed from $($CSVFile.fullname)" -verbose
}
Try {
Rename-item $CSVfile.fullname "$($CSVFile.basename)_processed.csv"
}
Catch {}
}
}
+1
The directive to suppress messages also does not work:
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseDeclaredVarsMoreThanAssignments","")]
$smtpserver_a = "smtp.example.com"
$smtpserver_b = "smtp.example.com" < error
$smtpserver_c = "smtp.example.com" < error
$smtpserver_d = "smtp.example.com" < error
Anyone know how to suppress this in the visual code settings?
@guyWicks Your example case already got fixed in PR #836 and will be in the upcoming release of 1.17 that is hopefully going to be released in the next days.
The Suppressionattribute needs to be on a function or Param() block in order to work.
VsVode has a setting to define a relative path to a PSSA settings file where you can define and customize the rules to be used inside VSCode. I would not recommend turning off this rule though because it is still useful despite some false positives. Most warnings produced by different code analysis tools needs human judgement, please keep that in mind. It is always a trade off between being able to determine 100% that something is wrong and warning on the possibility that something could be wrong.
Thanks for this.
For future reference, this now works as I expected:
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseDeclaredVarsMoreThanAssignments","")]
param()
$smtpserver_a = "smtp.example.com" # no error
$smtpserver_b = "smtp.example.com" # no error
$smtpserver_c = "smtp.example.com" # no error
$smtpserver_d = "smtp.example.com" #no error
Agree with your recommendation to use this suppression with caution - in my particular use-case I have a common file that stores global configuration variables so these are not used in this file, but in other files. You may legitimately criticise this design model :)
If the warning appears in variables you're referencing inside a Foreach-Object, or other construct, then specifying a scope on the variable seems to appease the warning.
To borrow/modify @mattmcnabb's example:
$a = 1
& {
$script:a = 2
}
$a
I don't believe there is an accurate way for PSScriptAnalyzer to guess that your intention is to use the $a variable in the parent scope, and it has to assume that you have assigned an unused variable.
I think that method _is_ $script: (or global, or local): https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_scopes?view=powershell-6
This is definitely still an issue in the latest VSCode v1.51.1

Most helpful comment
There are various issues with false positives of this rule that would probably need to be re-written from the ground up using a different technique to overcome its limitations. I plan to collate all those issues in a meta-issue at some point.