Skip to content

Commit 1fea7e7

Browse files
isra-felYeming Liu
andauthored
Add "Table Format" to design guidelines (#27682)
Co-authored-by: Yeming Liu <[email protected]>
1 parent bcdca63 commit 1fea7e7

File tree

5 files changed

+129
-35
lines changed

5 files changed

+129
-35
lines changed

documentation/development-docs/design-guidelines/azure-powershell-exceptions.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ throw new AzPSArgumentException(
3737
nameof(EnableNodeAutoScaling),
3838
desensitizedMessage: Resources.AksNodePoolAutoScalingParametersMustAppearTogether);
3939
``````
40-
40+
4141
- An code example for from *AzPSCloudException*
4242

4343
The source code is [KubeCmdletBase.cs](https://github.com/Azure/azure-powershell/blob/77b1e37e11179e59333edd825b2459435cab8726/src/Aks/Aks/Commands/KubeCmdletBase.cs).

documentation/development-docs/design-guidelines/cmdlet-best-practices.md

Lines changed: 69 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,86 @@
11
# Cmdlet Best Practices
22

3-
### Cmdlet Naming Conventions
3+
- [Cmdlet Naming Conventions](#cmdlet-naming-conventions)
4+
- [Verb-Noun Format](#verb-noun-format)
5+
- [Noun Prefix](#noun-prefix)
6+
- [Pascal Case](#pascal-case)
7+
- [Acronyms](#acronyms)
8+
- [Specific Noun and Noun Singularity](#specific-noun-and-noun-singularity)
9+
- [Set vs. Update](#set-vs-update)
10+
- [Cmdlet Alias](#cmdlet-alias)
11+
- [Output Type](#output-type)
12+
- [Valid Output Types](#valid-output-types)
13+
- [Returning Wrapped SDK Types](#returning-wrapped-sdk-types)
14+
- [Returning No Output](#returning-no-output)
15+
- [Enumerate Collection When WriteObject()](#enumerate-collection-when-writeobject)
16+
- [Output Format](#output-format)
17+
- [`ShouldProcess`](#shouldprocess)
18+
- [When to Add the Force Parameter](#when-to-add-the-force-parameter)
19+
- [`AsJob`](#asjob)
20+
- [Required Parameter Sets](#required-parameter-sets)
21+
- [Interactive Parameter Set](#interactive-parameter-set)
22+
- [ResourceId Parameter Set](#resourceid-parameter-set)
23+
- [InputObject Parameter Set](#inputobject-parameter-set)
24+
25+
26+
## Cmdlet Naming Conventions
427

528
The following are naming conventions to keep in mind when coming up with a name for your cmdlet.
629

7-
#### Verb-Noun Format
30+
### Verb-Noun Format
831

932
Cmdlet names should follow the _Verb-Noun_ format, where the verb is from the [list of approved PowerShell verbs](https://learn.microsoft.com/en-us/powershell/scripting/developer/cmdlet/approved-verbs-for-windows-powershell-commands), and the noun is a specific noun describing a resource within your service.
1033

11-
#### Noun Prefix
34+
### Noun Prefix
1235

1336
For ARM cmdlets, the noun must be prefixed with `Az`.
1437

15-
#### Pascal Case
38+
### Pascal Case
1639

1740
From the [_Strongly Encouraged Development Guidelines_](https://learn.microsoft.com/en-us/powershell/scripting/developer/cmdlet/strongly-encouraged-development-guidelines#use-pascal-case-for-cmdlet-names-sd02):
1841

1942
> _Use Pascal case for cmdlet names. In other words, capitalize the first letter of the verb and all terms used in the noun. For example, "Clear-ItemProperty"._
2043
21-
#### Acronyms
44+
### Acronyms
2245
Do capitalize both characters of two-character acronyms. For example, New-Az*VM*, Remove-AzCosmos*DB*Table.
2346

24-
Do capitalize only the first character of acronyms with three or more characters, which aligned with Pascal case. for example, Restart-Az*Vmss*, New-Az*Sql*Database.
47+
Do capitalize only the first character of acronyms with three or more characters, which aligned with Pascal case. for example, Restart-Az*Vmss*, New-Az*Sql*Database.
2548

26-
#### Specific Noun and Noun Singularity
49+
### Specific Noun and Noun Singularity
2750

2851
From the [_Strongly Encouraged Development Guidelines_](https://learn.microsoft.com/en-us/powershell/scripting/developer/cmdlet/strongly-encouraged-development-guidelines#use-a-specific-noun-for-a-cmdlet-name-sd01):
2952

3053
> _Nouns used in cmdlet naming need to be very specific so that the user can discover your cmdlets. Prefix generic nouns such as "server" with a shortened version of the product name. For example, if a noun refers to a server that is running an instance of Microsoft SQL Server, use a noun such as "SQLServer". The combination of specific nouns and the short list of approved verbs enable the user to quickly discover and anticipate functionality while avoiding duplication among cmdlet names._
3154
>
3255
> _To enhance the user experience, the noun that you choose for a cmdlet name should be singular. For example, use the name `Get-Process` instead of `Get-Processes`. It is best to follow this rule for all cmdlet names, even when a cmdlet is likely to act upon more than one item._
3356
34-
#### Set vs. Update
57+
### Set vs. Update
3558

3659
If your cmdlet is performing a **PATCH** operation (_i.e._, a partial replacement on the server), then the cmdlet should use the verb `Update`.
3760

3861
If your cmdlet is performing a **PUT** operation (_i.e._, a full replacement on the server), the cmdlet should use the verb `Set`.
3962

40-
#### Cmdlet Alias
63+
### Cmdlet Alias
4164

4265
If you there is a separate nomenclature for your service and/or resource, or if you would like to shorten the name of the cmdlet so it's easier to remember, you can add an alias attribute to your cmdlet to allow for this functionality.
4366

44-
### Output Type
67+
## Output Type
4568

4669
Specified by the `OutputType` attribute, this piece of metadata lets the user know what the type of the object returned by the cmdlet is (found in the **Outputs** section of a cmdlet's help content). The type specified here should always be a single element and not an enumeration of elements (_e.g._, `PSVirtualMachine` instead of `List<PSVirtualMachine>`).
4770

48-
#### Valid Output Types
71+
### Valid Output Types
4972

5073
If the cmdlet returns an object, the type of the object returned must be defined; the output type for a cmdlet should _never_ be `object`, `PSObject`, `PSCustomObject` or the like. Returning these types of objects makes it difficult for the user to anticipate what properties will be found on the object returned from the cmdlet, as well as makes it impossible for the breaking change analyzer to detect if a breaking change was introduced to the cmdlet as the type is not defined.
5174

5275
In order to preserve proper piping scenarios, the output type for a cmdlet should _never_ be a `string`. If a cmdlet is expected to return a `string`, the suggestion is to introduce a new type that encapsulates the `string` information as a property and return that object. The PowerShell language revolves around objects and passing them around cmdlets; returning `string` objects can introduce inconsistencies in the piping experience for users.
5376

54-
#### Returning Wrapped SDK Types
77+
### Returning Wrapped SDK Types
5578

5679
In most cases, cmdlets will be returning an object corresponding to a resource that a user is performing an action on. Rather than returning the .NET SDK type for that resource (exposing .NET SDK types in PowerShell cmdlets is _strongly_ discouraged), we suggest creating a new class that wraps this .NET SDK type, allowing for breaking changes in the underlying type while avoiding breaking changes in the PowerShell type.
5780

5881
For example, the `Get-AzVM` cmdlet uses the .NET SDK to retrieve objects of the `VirtualMachine` type, but a new class, `PSVirtualMachine`, was created to wrap the type from the .NET SDK, and is returned by the cmdlet. If, in the future, the `VirtualMachine` type in the .NET SDK has a property removed, that property can still be maintained in PowerShell by adding it to the `PSVirtualMachine` type and recreating the value, thus avoiding a breaking change in the corresponding cmdlet(s).
5982

60-
#### Returning No Output
83+
### Returning No Output
6184

6285
In the case where your cmdlet doesn't return any output (_e.g._, deleting, starting, stopping a resource), the cmdlet should implement the `-PassThru` parameter and the `OutputType` should be set to `bool`. The `-PassThru` parameter is a `SwitchParameter` set by the user to signal that they would like to receive output from a cmdlet which does not return anything. If the `-PassThru` parameter is provided, you should return the value `true` so the user is made aware that the operation was successful. If the operation was unsuccessful, then the cmdlet should throw an exception.
6386

@@ -88,7 +111,7 @@ public class MySampleCmdlet : MyBaseCmdlet
88111
}
89112
```
90113

91-
#### Enumerate Collection When WriteObject()
114+
### Enumerate Collection When WriteObject()
92115

93116
When returning a collection of objects, the cmdlet should enumerate the collection. This ensures that the objects are written to the pipeline one at a time, which is the expected behavior for PowerShell cmdlets.
94117

@@ -109,7 +132,32 @@ foreach (var resource in resources)
109132
WriteObject(resources, true);
110133
```
111134

112-
### `ShouldProcess`
135+
## Output Format
136+
137+
PowerShell supports several output formats, including `table`, `list`, and `wide`. The default output format for Azure PowerShell cmdlets is `table`, which is the most readable for displaying a list of resources. Here's an example:
138+
139+
```powershell
140+
PS > Get-AzVM
141+
142+
ResourceGroupName Name Location VmSize OsType NIC
143+
----------------- ---- -------- ------ ------ ---
144+
TEST1 test1 eastus Standard_DS1_v2 Windows test1
145+
TEST1 test2 westus Standard_DS1_v2 Windows test2
146+
TEST1 test3 eastus Standard_DS1_v2 Windows test3
147+
TEST2 test4 westus Standard_DS1_v2 Windows test4
148+
TEST2 test5 eastus Standard_DS1_v2 Windows test5
149+
```
150+
151+
The idea about table format is for users to be able to quickly scan the output and find the information they are looking for. To achieve this, follow the golden rule of thumb: **show only the MVPs (most valuable properties)**.
152+
153+
It's obvious that important properties need to be displayed, but be careful not to overcrowd the output with too many properties. PowerShell console has a limited width, so if there are too many columns, the output may be truncated and lose the meaning of being quickly readable.
154+
155+
A practical way of designing the table format is:
156+
157+
1. List the properties from the most important to the least important.
158+
2. Take the most important properties until (a) the width of the console is filled or (b) the rest of the properties are not important enough to be displayed.
159+
160+
## `ShouldProcess`
113161

114162
If a cmdlet makes any changes to an object on the server (_e.g._, create, delete, update, start, stop a resource), the cmdlet should implement `ShouldProcess`. This property adds the `-WhatIf` and `-Confirm` parameters to the cmdlet:
115163

@@ -138,13 +186,13 @@ public class MySampleCmdlet : MyBaseCmdlet
138186

139187
More information about `ShouldProcess` can be found in the [_Should Process and Confirm Impact_](./should-process-confirm-impact.md) document.
140188

141-
#### When to Add the Force Parameter
189+
### When to Add the Force Parameter
142190

143191
The `-Force` parameter is reserved for special scenarios where additional confirmation from the user is required. From the above document on [_Should Process and Confirm Impact_](./should-process-confirm-impact.md) document:
144192

145193
> _Some cmdlets require additional confirmation. For example, if a cmdlet would destroy existing resources in some circumstances, the cmdlet might detect that condition and prompt the user to verify before continuing. Overwriting an existing resource during resource creation, overwriting a file when downloading data, deleting a resource that is currently in use, or deleting a container that contains additional resources are all example of this pattern. To implement additional confirmation, and allow scripts to opt out of additional prompts, the above pattern is enhanced with calls to `ShouldContinue()` and the `-Force` parameter._
146194
147-
### `AsJob`
195+
## `AsJob`
148196

149197
All long running operations must implement the `-AsJob` parameter, which will allow the user to create jobs in the background. For more information about PowerShell jobs and the `-AsJob` parameter, read [this doc](https://learn.microsoft.com/en-us/powershell/azure/using-psjobs).
150198

@@ -167,20 +215,20 @@ $subscriptions = $job | Receive-Job
167215

168216
To set a custom job name, please use [`SetBackgroupJobDescription`](https://github.com/Azure/azure-powershell-common/blob/main/src/Common/AzurePSCmdlet.cs#L810). The default job description is: "Long Running Operation for '{cmdlet name}' on resource '{resource name}'"
169217

170-
### Required Parameter Sets
218+
## Required Parameter Sets
171219

172220
In most Azure PowerShell cmdlets, there is a bare minimum of three parameter sets that need to be implemented.
173221

174-
#### Interactive Parameter Set
222+
### Interactive Parameter Set
175223

176224
This parameter set should be implemented by _every_ cmdlet - in most cases, the user provides the name of the resource that they are acting upon (`-Name`) and the resource group in which they are acting in (`-ResourceGroupName`).
177225

178226
The interactive parameter set **will always be the default parameter set** for a cmdlet (specified by the `DefaultParameterSetName` property in the `Cmdlet` attribute). This means that when PowerShell is unable to determine which parameter set a user is in, it will default to the interactive parameter set and prompt the user to provide values for the missing mandatory parameters.
179227

180-
#### ResourceId Parameter Set
228+
### ResourceId Parameter Set
181229

182230
This parameter set should be implemented by _every_ cmdlet - the user is able to provide a `-ResourceId` string or GUID from the Azure Portal, or from one of the generic resources cmdlets (more information about this scenario can be found in the [`piping-best-practices.md`](./piping-best-practices.md#using-the--resourceid-parameter) document), and act upon the given resource associated with the id. The typical `-Name` and `-ResourceGroupName` parameters are replaced by a single `-ResourceId` parameter of type string.
183231

184-
#### InputObject Parameter Set
232+
### InputObject Parameter Set
185233

186234
This parameter should be implemented by _most_ cmdlets - the user is able to take the object returned from the `Get`, `New`, or `Set` cmdlets (or other cmdlets that return the common resource) and provide it to the `-InputObject` parameter for a cmdlet that acts upon the same resource (more information about this scenario can be found in the [`piping-best-practices.md`](./piping-best-practices.md#using-the--inputobject-parameter) document). The typical `-Name` and `-ResourceGroupName` parameters are retrieved from the `-InputObject` that the user is passing through.

documentation/development-docs/design-guidelines/module-best-practices.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# Module Best Practices
22

3+
- [Module Metadata](#module-metadata)
4+
- [Module Naming](#module-naming)
5+
- [Module Manifest](#module-manifest)
6+
- [Module Dependencies](#module-dependencies)
7+
- [Common Assemblies](#common-assemblies)
8+
- [SDK Assemblies](#sdk-assemblies)
9+
- [Other Assemblies](#other-assemblies)
10+
311
## Module Metadata
412

513
### Module Naming

documentation/development-docs/design-guidelines/parameter-best-practices.md

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,32 @@
11
# Parameter Best Practices
22

3+
- [Parameter Guidelines](#parameter-guidelines)
4+
- [Parameter Naming Conventions](#parameter-naming-conventions)
5+
- [Standard Parameter Name](#standard-parameter-name)
6+
- [Pascal Case](#pascal-case)
7+
- [Acronyms](#acronyms)
8+
- [Singularity](#singularity)
9+
- [Parameter Alias](#parameter-alias)
10+
- [Parameter Types](#parameter-types)
11+
- [Valid Parameter Types](#valid-parameter-types)
12+
- [Consistent Parameter Types](#consistent-parameter-types)
13+
- [Array vs. Enumerable Types](#array-vs-enumerable-types)
14+
- [Secret Parameters](#secret-parameters)
15+
- [Bool vs. SwitchParameter](#bool-vs-switchparameter)
16+
- [Argument Completers](#argument-completers)
17+
- [Resource Group Completer](#resource-group-completer)
18+
- [Resource Name Completer](#resource-name-completer)
19+
- [Location Completer](#location-completer)
20+
- [Generic Argument Completer](#generic-argument-completer)
21+
- [Parameter Set Guidelines](#parameter-set-guidelines)
22+
- [Parameter Set Naming Conventions](#parameter-set-naming-conventions)
23+
- [Pascal Case](#pascal-case-1)
24+
- [Attribute Guidelines](#attribute-guidelines)
25+
- [Mutually Exclusive Parameter Sets](#mutually-exclusive-parameter-sets)
26+
- [Positional Parameters Limit](#positional-parameters-limit)
27+
- [ValueFromPipeline Limit](#valuefrompipeline-limit)
28+
- [Appendix: Parameter Syntax](#appendix-parameter-syntax)
29+
330
## Parameter Guidelines
431

532
### Parameter Naming Conventions
@@ -61,7 +88,7 @@ From the [_Strongly Encouraged Development Guidelines_](https://learn.microsoft.
6188

6289
For parameters whose type is string and which represent a value that should be kept secret in some fashion (such as a password, secret, key, etc.), the type of the parameter should be [SecureString](https://learn.microsoft.com/dotnet/api/system.security.securestring) to limit the exposure of sensitive string data from unexpected leakage during cmdlet execution. The practice also applies to output properties whose type is string and that should be kept in secret.
6390

64-
Please notice that DO NOT use `SecureString` for encryption purposes. We only recommend to use `SecureString` as a wrapper of string to prevent unexpected leakage of information as string may still be exposed to any process or operation that has access to raw memory.
91+
Please notice that DO NOT use `SecureString` for encryption purposes. We only recommend to use `SecureString` as a wrapper of string to prevent unexpected leakage of information as string may still be exposed to any process or operation that has access to raw memory.
6592

6693
From [How secure is SecureString?](https://learn.microsoft.com/dotnet/api/system.security.securestring#how-secure-is-securestring)
6794

@@ -170,8 +197,8 @@ Allowing the user to pipe an object from one cmdlet to another is a major scenar
170197

171198
## Appendix: Parameter Syntax
172199

173-
In PowerShell documentation, square brackets (`[]`) indicate optional.
174-
Convention is as follows:
200+
In PowerShell documentation, square brackets (`[]`) indicate optional.
201+
Convention is as follows:
175202

176203
```powershell
177204
command-name
@@ -181,18 +208,18 @@ command-name
181208
[-OptionalParameterName] <RequiredParameterValue>
182209
```
183210

184-
Using `New-Alias` cmdlet as an example:
211+
Using `New-Alias` cmdlet as an example:
185212

186213
```powershell
187-
New-Alias
188-
[-Name] <string> -required 'positional' parameter
189-
[-Value] <string>
190-
[-Description <string>] -optional parameter
191-
[-Force] -optional switch parameter (all switch parameters are optional, non-positional)
214+
New-Alias
215+
[-Name] <string> # required 'positional' parameter
216+
[-Value] <string>
217+
[-Description <string>] # optional parameter
218+
[-Force] # optional switch parameter (all switch parameters are optional, non-positional)
192219
[-Option {None | ReadOnly | Constant | Private | AllScope}]
193-
[-PassThru]
194-
[-Scope <string>]
195-
[-Confirm]
196-
[-WhatIf]
220+
[-PassThru]
221+
[-Scope <string>]
222+
[-Confirm]
223+
[-WhatIf]
197224
[<CommonParameters>]
198225
```

documentation/development-docs/design-guidelines/piping-best-practices.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,17 @@
22

33
_Note_: for the below examples, the string "TopLevelResource" would be replaced with the name of your top-level resource (_e.g._, "VirtualMachine", "VirtualNetwork", "SqlServer"), and the string "ChildResource" would be replaced with the name of your child resource (_e.g._, "VirtualMachineExtension", "VirtualNetworkPeering", "SqlDatabase")
44

5+
- [Piping in PowerShell](#piping-in-powershell)
6+
- [Understanding Piping](#understanding-piping)
7+
- [Piping in Azure PowerShell](#piping-in-azure-powershell)
8+
- [Using the `-InputObject` Parameter](#using-the--inputobject-parameter)
9+
- [Short explanation](#short-explanation)
10+
- [Long explanation](#long-explanation)
11+
- [Using the `-ResourceId` Parameter](#using-the--resourceid-parameter)
12+
- [Short explanation](#short-explanation-1)
13+
- [Long explanation](#long-explanation-1)
14+
- [Full examples](#full-examples)
15+
516
## Piping in PowerShell
617

718
### Understanding Piping

0 commit comments

Comments
 (0)