Prerequisites
Summary
PSUseConsistentIndentation (and therefore Invoke-Formatter) double-indents the body of an attribute that opens a scriptblock, e.g. [ArgumentCompleter({...})]. The body gets IndentationSize * 2 and the closing })] gets IndentationSize * 1.
This looks like the same root cause as #2159 (hashtable inside a method call: the LParen and the AtCurly each add an indentation level). Here the two adjacent openers are ( and { from a type/attribute literal instead of @{, so [AttributeName({ hits it too. #2159 was fixed on main by #2173 ("only the last unclosed opener on a line affects indentation"), but neither that fix nor #2159 covers the attribute form, and it is still broken in the latest release 1.25.0.
Steps to reproduce
$code = @'
[ArgumentCompleter({
Param($commandName, $parameterName)
$validKeys = @('a', 'b')
$validKeys | Where-Object { $_ } | ForEach-Object { "$_=" }
})]
'@
$settings = @{
IncludeRules = @('PSUseConsistentIndentation')
Rules = @{
PSUseConsistentIndentation = @{
Enable = $true
IndentationSize = 4
Kind = 'tab'
}
}
}
Invoke-Formatter -ScriptDefinition $code -Settings $settings
Expected behavior
One level of indentation for the body, matching the opener line, and the closing })] at the opener's level:
[ArgumentCompleter({
Param($commandName, $parameterName)
$validKeys = @('a', 'b')
$validKeys | Where-Object { $_ } | ForEach-Object { "$_=" }
})]
Actual behavior
Two levels for the body and one level for the closing })]:
[ArgumentCompleter({
Param($commandName, $parameterName)
$validKeys = @('a', 'b')
$validKeys | Where-Object { $_ } | ForEach-Object { "$_=" }
})]
The same happens with spaces (Kind = 'space', IndentationSize = 4) and with NewLineAfterOpenBrace/PSPlaceOpenBrace not involved at all — PSUseConsistentIndentation alone is enough.
It also affects other attribute forms that open a scriptblock, e.g.
[ValidateScript({
$_ -gt 0
})]
and the buggy output is not idempotent in a harmless way: because the opener line itself is not re-indented, re-running the formatter keeps the body at the wrong level, and any tool that re-applies formatting sees a permanent diff.
Environment
PSVersion: 7.6.6
PSEdition: Core
OS: Windows 11 (26100)
PSScriptAnalyzer: 1.25.0
Also reproduced with PSScriptAnalyzer 1.24.0 (bundled with ms-vscode.powershell 2025.4.0) and with Windows PowerShell 5.1 / 26100 (Desktop edition), so it is not host- or edition-specific.
Related
Prerequisites
Summary
PSUseConsistentIndentation(and thereforeInvoke-Formatter) double-indents the body of an attribute that opens a scriptblock, e.g.[ArgumentCompleter({...})]. The body getsIndentationSize * 2and the closing})]getsIndentationSize * 1.This looks like the same root cause as #2159 (hashtable inside a method call: the
LParenand theAtCurlyeach add an indentation level). Here the two adjacent openers are(and{from a type/attribute literal instead of@{, so[AttributeName({hits it too. #2159 was fixed onmainby #2173 ("only the last unclosed opener on a line affects indentation"), but neither that fix nor #2159 covers the attribute form, and it is still broken in the latest release 1.25.0.Steps to reproduce
Expected behavior
One level of indentation for the body, matching the opener line, and the closing
})]at the opener's level:Actual behavior
Two levels for the body and one level for the closing
})]:The same happens with spaces (
Kind = 'space',IndentationSize = 4) and withNewLineAfterOpenBrace/PSPlaceOpenBracenot involved at all —PSUseConsistentIndentationalone is enough.It also affects other attribute forms that open a scriptblock, e.g.
and the buggy output is not idempotent in a harmless way: because the opener line itself is not re-indented, re-running the formatter keeps the body at the wrong level, and any tool that re-applies formatting sees a permanent diff.
Environment
Also reproduced with PSScriptAnalyzer 1.24.0 (bundled with ms-vscode.powershell 2025.4.0) and with Windows PowerShell 5.1 / 26100 (Desktop edition), so it is not host- or edition-specific.
Related
PSUseConsistentIndentation: Hashtable inside method call gets double-indented (sameLParen+XCurlydouble count; fixed by Improve pipeline indentation handling in UseConsistentIndentation rule #2173)({.whereand.foreachmethods is incorrect" (adjacent-opener family)