Skip to content

PSUseConsistentIndentation double-indents attribute bodies that open a scriptblock ([Attr({ … })]) #2216

Description

Prerequisites

  • I have read the documentation and my issue is not covered there.
  • I have searched the existing issues and my issue is not already reported.

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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions