Share via


Command Line Standard

This document is focused at developers of command line utilities. Collectively, our goal is to present a consistent, composable command line user experience. Achieving that allows a user to learn a core set of concepts (syntax, naming, behaviors, etc) and then be able to translate that knowledge into working with a large set of commands. Those commands should be able to output standardized streams of data in a standardized format to allow easy composition without the burden of parsing streams of output text. This document is written to be independent of any specific implementation of a shell, set of utilities or command creation technologies; however, Appendix J - Using Windows Powershell to implement the Microsoft Command Line Standard shows how using Windows PowerShell will provide implementation of many of these guidelines for free.

On This Page

Introduction
Summary List of Guidance
Details
Command Name Example
Navigating and Operating on Namespaces
Appendix A - Standardized Verb Sets and Verb Names
Appendix B - Standardized Parameters
Appendix C - Standardized Error Message Templates
Appendix D - Standardized Globbing
Appendix E - Standardized Data Example
Appendix F - CliXmlDataStream Data Schema
Appendix G: Navigation Examples
Appendix H: Standardized Help Tags
Appendix I: Win32 Code to Write Output
Appendix J - Using Windows PowerShell to implement the Microsoft Command Line Standard
Appendix K - Error Record Schema
Appendix L - Enhanced Interoperability Guidance
Appendix M - Typed-CSV (TCSV) Data Format
Appendix N - Argument Parsing Pseudo code

Introduction

In order to provide a consistent, composable user experience, across a wide range of commands, this document provides guidance on:

  1. Consistent verb and parameter naming conventions.

  2. Consistent command syntax

  3. Common behaviors.

  4. Consistent error messages and exit codes.

  5. Schema-enhanced data-streams and formatting.

This document builds upon the traditional command line compositional model. That traditional model had the following three characteristics:

  • Commands are standalone processes that accept a sequence of text parameters (that might have been typed on a command line), accept data from STDIN, write results to STDOUT, write error messages to STDERR, and exit with a code indicating success or failure.

  • Commands are focused on performing specific operations. The user composes a sequence of commands to implement a task or user-scenario.

  • Composition is achieved by picking out the important elements of one command’s output and providing as parameters or data to another command.

If you create command-line tools that have these three characteristics, you will have achieved UNIX level interoperability. Building upon that, there are Enhanced and Optimal levels of interoperability. This document primarily focuses on the Optimal level of interoperability, but guidelines for Enhanced interoperability are available in Appendix H - Enhanced Interoperability Guidance . Enhanced interoperability provides a stepping stone for existing commands. As a first step, you can elevate them to Enhanced interoperability on the way to achieving Optimal interoperability.

This document is structured as a progressive disclosure: The Summary List of Guidance section is a two page summary. The Details section provides details and background for each guideline in the summary. The Appendixes provide reference material necessary to implement the guidelines.

Summary List of Guidance

Command Names

Required:

  • Command names must be well-formed names consisting of a noun and a verb in the form: verb-noun.

Verbs

Required:

  • Commands must use verbs from the list of standard verbs in Appendix A.

Recommended:

  • Developers should implement as many verbs in the defined Verb groupings (Verb Sets) as makes sense for their feature.

Noun Names

Recommended:

  • Commands should avoid using the noun names Windows PowerShell has reserved (See Section 3.3 Nouns).

  • Commands should use their product or feature name (or abbreviation) to prefix their noun.

Consistent Syntax

Required:

  • Commands must use the “-“ character for parameter delimitation; a colon (:) or whitespace to separate the parameter name and its arguments and a comma (,) to separate multiple values within an argument.

Input

Required:

  • Commands must accept text or CliXml input (using CliXmlDataStream Schema defined in Appendix E - Standardized Data Schema ) in STDIN.

Recommended:

  • Commands should accept Typed-CSV (TCSV) input in STDIN.

  • Commands should provide a -InputFormat [XML | TCSV | TEXT ] parameter to allow the user to identify what type of data will be coming in on STDIN.

Parameters

Required:

  • Commands must support -?, -Help, -Version, -Verbose, and -Debug for all commands.

  • Commands must support -WhatIf and -Confirm for any operation which has a side-effect.

  • Commands must support -ErrorAction to determine behavior when errors occur.

  • Parameter names must be case-insensitive.

  • Passwords must not be accepted as a parameter argument.

Recommended:

  • Commands should choose parameters from the standards specified in Appendix B.

  • Commands should support -SelectProperty to specify which properties to output on STDOUT.

  • Commands should allow the user to specify just enough of a parameter name to disambiguate it from other parameter names and provide a one or two character shortcut to specify a verbose parameter name.

  • Commands should document their parameter names using Pascal casing rules (capitalize the start of every word).

Targeting

Recommended:

  • Commands should use wildcard expansion for input globbing (Appendix D - Globbing).

  • Commands should use common parameters for specifying the target of a command (e.g. -Name, -ID, -File, -ComputerName) .

  • Commands should support multi-value targets as well as the -Include and -Exclude parameters.

  • Commands should support the -Filter parameter to specify a domain-specific query or filter.

Output Formatting

Required:

  • Output must be written using the logic illustrated in Appendix I: Win32 code to write output to properly address globalization requirements.

  • Commands must support the -OutputFormat parameter to allow users to specify their desired format and the -OutputPreamble to configure schema enhanced data streams

  • Commands must use the value of the environmental variable CliDataStreamSchema when -OutputFormat is not specified.

  • Commands must support at least one format of schema-enhanced dataStreams (TCSV or CliXml).

Recommended:

  • Commands should support CliXml Appendix F - CliXmlDataStream Data Schema and Appendix K - Error Record Schema and tag which stream (DEBUG, ERROR, OUTPUT VERBOSE, or WARNING) the data came from. Commands must output CliXml when the environmental variable CliXmlStreams is set to TRUE. Commands must output XML using CliXmlDataStream schema.

  • Commands should support other XML schemas where there is a community of tools that will consume that output (e.g. CimXml).

Exit, Errors, and Others

Required:

  • Error messages (as well as VERBOSE and DEBUG messages) must be written to STDERR.

  • Commands must terminate with an exit code indicating success (0) or failure (non-zero).

Recommended:

  • Commands should use the exit codes and standardized error messages defined in Appendix C. Augment those standardized error messages with specific detailed error messages.

  • Commands should tell the user (on STDERR) the Syntax of a command if they specify a syntactically invalid command.

Details

3.1 Command Names
Command names must be well-formed names consisting of a noun and a verb in the form: verb-noun. Each noun will specify a specific part of the system to operate on. For example, the “Service” noun operates on Windows Services. The operations (or actions) are defined by the verbs. For example, we can “Start” a Service or “Stop” a Service. The command names for these operations are: “Start-Service” and “Stop-Service”. (Note the use of the “-” character to separate the verb and noun.)

3.2 Verbs
Commands must choose a verb from the list of standard verbs in Appendix A. Verbs are the backbone of a consistent user experience. The user should be able to perform 80-90% of all operations on the system using fewer than 50 verbs. Administrators can learn those 50 verbs and then make successful guesses about what to type when they need to perform a new operation or they encounter a new object. Suppose we have lots of types of things running on a system: Processes, Services, WebServices, BackUpJobs, Disks etc and that the user wants to stop them. We standardize on the verb Stop. The resultant commands are Stop-Process, Stop-Service, Stop-WebService, Stop-BackupJob, Stop-Disk etc. Notice that our desire to manage everything with fewer than 50 verbs causes us to make some difficult decisions. “Kill” is the traditional verb for processes, “cancel” has a nuance that is different from stop, “terminate” might be a more appropriate for particular nouns. All of these considerations seem important when you look at a single noun. However, to deliver an admin-coherent system, we must converge on a small set of verbs.

Note

Parameters can be used to provide more precision or specificity to a verb. For example, “Stop-WebService -Drain” could be used to indicate that existing work items should be completed before stopping the service (a new verb is not required).

Fifty verbs are still quite a few to learn and remember. To facilitate learning and increase retention, we put them into defined groupings called “Verb Sets” and associate most verbs with a corresponding PAIR verb (e.g. Start pairs with Stop, Get pairs with Set).

The verb sets are:

  1. Common Object Verbs Some of these will be used with almost every noun. For example, many nouns will support the “New” and “Remove” verbs.

  2. Data Verbs These are used with data intensive operations and include “Compare” and “Merge”.

  3. Lifecycle Verbs These are envisioned to be used with activities. The lifecycle verbs include “Start”, “Stop” and “Resume”.

  4. Diagnostic Verbs As the name implies, these are for diagnostic purposes. The set includes “Measure”, “Test” and “Debug”.

  5. Communications Verbs This set includes “Send” and “Receive”.

The complete list of Verb Sets is in Appendix A - Standardized Verb Sets and Verb Names. Developers should implement as many verbs in the defined Verb groupings (Verb Sets) as makes sense for their feature. Users will learn and remember the verbs in sets. If you support a particular verb, they will guess that you’ll support more verbs in that set (e.g. if you support Stop, you should probably support Start and, perhaps, Suspend and Resume).Note that in most cases a particular noun will use verbs from more than one verb set. At the same time, most nouns will not use all the verbs in any one set.

3.3 Noun Names
Commands should avoid using the nouns Windows Powershell has reserved. Nouns identify the type of object being operated upon. As a general rule, each feature team will pick their own noun names and standardization will be limited to common sub noun names. Avoid using nouns that Windows Powershell will use. If your command uses one of these reserved nouns, it is likely that customers will need to use the full pathname to your command. This is the list of generic nouns that Windows Powershell has reserved:

Alias

ChildItem

Cmdlet

Command

Content

Drive

History

Item

List

Location

Object

Path

Property

PropertyValue

Provider

RunSpace

Table

Variable

PS*

 

Commands should use their product or feature name (or abbreviation) to prefix their noun. Many teams will have similar noun names. For instance, many database teams might create the command “new-table”. To avoid collisions, it is best to prefix common noun names with the product or feature name. e.g. “New-SqlTable”

3.4 Consistent Syntax
Here is an example of the standard Command Line Interface (CLI) syntax:$ Verb-Noun -Parameter1 Value1 -Parameter2 Value2,Value3,Value4Commands must use a dash (-) for parameter delimination; a colon (:) or whitespace to separate the parameter name and its arguments and a comma ( ,) to separate multiple values within an argument. More formally, commands should support the following syntax:

<command> := <commandName> <parameterOrArgument>* ['-' <argumentString>*]
<parameterOrArgument> := 
                        <dash><parameterName>  <space>+ <argumentString> |
                        <dash><parameterName> ‘:’ <space>* <argumentString> |
                        '-'<parameterName> | 
                        <argumentString>
  • “*” means 0 or more.

  • +” means 1 or more.

  • <dash> can be any of ASCII dash (0x002d), endash (0x2013), emdash (0x2014) or horizontal bar (0x2015).

  • <parameterName> is any sequence starting with an alpha character followed by zero or more alphanumeric characters.

  • <argumentString> is any sequence of characters.

See Appendix N - Argument Parsing Pseudo code for details on how to implement a compliant argument parser. Quoting is not addressed by this grammar as it is handled by the invoked application. In general though, it is assumed that there is some mechanism to allow argument strings to contain arbitrary characters including spaces. A parameter name without a trailing ‘:’ must both match the syntactic requirements (i.e. start with a dash) and be recognized by the command as a valid parameter. If the token is not recognized as a valid parameter, it shall be treated as an argument if appropriate. A parameter of the form -name: must be followed by an argument.A parameter of the form -name (no trailing colon) must be followed by an argument except in the case were the parameter is considered to be a Switch parameter. In this case no argument is required and the presence of the parameter is to be treated as though it were given an explicit argument of true. If you wish to pass a false value to a Switch parameter, the -name: pattern must be used. The sequence ‘—‘ (dashdash) indicates the end of parameters. All tokens after dashdash will be treated as arguments.

3.5 Input
Whenever possible, design your command to operate over a set of data instead of a single data instance. This allows better composition of command sequences which reduces the need for admin programming and simplifies error reporting and handling.Commands must accept text or CliXml input (XML using CliXmlDataStream Schema defined in Appendix E - Standardized Data Schema ) in STDIN. The typical way to achieve this is to read text from STDIN and process it as data records. In addition to this, you should allow data records encoded in XML from STDIN. Commands should accept Typed-CSV (TCSV) input in STDIN. When processing text data records from STDIN, you might need to specify syntax to allow multiple fields. TCSV records are the preferred way to achieve this. See Appendix M - Typed-CSV (TCSV) Data Format for a definition of this data format.Commands should provide a -InputFormat [XML | TCSV | TEXT ] parameter to allow the user to identify what type of data will be coming in on STDIN. If you allow multiple types of input, you’ll need a way to allow the user to specify what type of input they have provided. Use the parameter -InputFormat which takes a KEYWORD to accomplish this.

3.6 Parameters
Providing a common, consistent set of parameters across commands is necessary to provide a good user experience. Reducing the number of verbs in command names means that parameters will be used to specify more precise operations. Providing a common set of parameters with consistent semantics provides users with ready solutions to common problems.

Commands should choose parameters from the standards specified in Appendix B. Standardized Parameters : A set of common parameters has been standardized to:

  1. Refine the meaning of a verb. (e.g. -At -After and -Before are used with the verb “Add” in place of the verbs “Append”, “Attach”, “Concatenate” and “Insert”.)

  2. Specify a date time related parameter (e.g. -Modified, -Before -Since)

  3. Request a format (e.g. -Encoding, -Width, -Wrap)

  4. Specify a common property or resource (e.g. -Count, -Description, -Name)

  5. Specify a quantity (e.g. -All, -Count, -Scope)

Users, like CSS for example, need to quickly tell what specifically they are working with and what its capabilities are. They need visibility into what it is doing and how it is doing it. All commands must support -?, -Help, -Version, -Verbose and -Debug.

  • -? - provide help about this command. When outputting this data in XML format, use the tags in Appendix H: Help Tags. Data goes to STDOUT.

  • -Help - same as -?.

  • -Version - tell the user what version of the command they are running, what company produced the command and what product it was shipped in. Data goes to STDOUT.

  • -Verbose - provide user-level information about what each operation is doing. Data goes to STDERR.

  • -Debug - provide CSS/Developer-level information about what is happening. Data goes to STDERR.

Administrators need a command line environment which allows them to tell what is going to happen before they commit themselves. Commands must support -Whatif and -Confirm for any command which has a side effect.

  • Confirm - ask the user before doing any operation which has a side effect (i.e. the operation modifies the system. In general, GETS do not have side effects but SETS do). The prompt should be issued to STDERR and take the following form:Continue with this operation?stop-process on CcmExec () #Specify your operation on this line[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help :

  • WhatIf - tell the user what operation would have occurred but don’t do the operation. This information should go to STDOUT and each line should start with the comment char ‘#’ to indicate that the operation did not occur. .e.g# stop-process on lsass

Users need fine control over what happens when things go wrong. This is especially important when operating on sets of input. Sometimes the user will want to continue processing, other times they’ll want to stop. Commands must support -ErrorAction to determine behavior when errors occur. This must take the following values:

  • Continue - Issue a non-terminating error and continue processing.

  • Stop - Issue a terminating error and stop the command.

  • Inquire - Issue an error and ask the user whether to continue processing or stop. Use the same prompt as -Confirm.

  • SilentlyContinue - Suppress error message and continue processing. The default value should be Continue.

Windows is a case-preserving, case-insensitive platform. This should be reflected in our processing of parameter names. Parameter names must be case-insensitive.

You must not encourage unsafe scripting practices such as storing passwords in clear text in script files. Passwords must not be accepted as parameter arguments.

Outputting objects in XML format can sometimes be quite verbose. Commands should support -SelectProperty to specify which properties to output on STDOUT. SelectProperty should take a list of property names to output.

Commands should allow the user to specify just enough of a parameter name to disambiguate it from other parameter names and provide a one or two character shortcut to specify a verbose parameter name. Verbosity is a user’s friend when reading a script and their enemy when typing during an interactive session. We need to support both. You need to support verbose parameter names, so start by defining those. Next, consider supporting a well-defined 1 or 2 letter name (a parameter alias) for the same parameters. For example, “-File” could also be “-F”

If the only parameter starting with “F” was “-Filename”, you would allow the user to type any of the following and recognize it as -FileName:

  • -Filename

  • -Filenam

  • -File

  • -Fi

  • -F

(Some skipped for the sake of brevity.)Commands should document their parameter names using Pascal casing rules (capitalize the start of every word). For example, . -SelectProperty. This makes it easier to read.

3.7 Targeting
Most commands are targeted at an object or a set of objects. For instance, Stop-Process targets a process or a set of processes. Copy-File targets a file or set of files. The purpose of many existing scripts is to get the right set of objects to operate on and to pass them to a command. Many scripts could be eliminated and many more could be made simpler by providing a common, rich model for specifying the target of a command.

Commands should use common parameter names for specifying targets (e.g. -Name, -Id, -Location, -File, etc).

Commands should use wildcard expansion for input globbling (Appendix D - Globbing;). (e.g. lsa*, *.txt, [a-c]*). Use the back-quote character ‘`’ as an escape character if this is required for your resource.

Commands should support multi-value targets as well as the -Include and -Exclude parameters. Multi-value targets should be separated by commas (,) (e.g. -Name a,b,c,d*,e ). Use -Include to identify things that should be included in the target list. Use -Exclude to identify things to eliminate from that target list. For example, to get all files that start with “a” that are not XML or CS files: -File a* -Exclude *.xml,*.cs.

Note

The semantics of -exclude should be to eliminate items from a list of things about to be operated upon. In other words, it must be evaluated AFTER the other targeting rules.

Commands should support the -Filter parameter to specify a domain-specific query or filter.

3.8 Output Formatting
Commands must standardize the way they output results to provide a common user experience and to facilitate command composition. Composing multiple commands means that commands must output results using a common schema that is easily detected so that the output can be processed to feed into other commands. Output must be written using the logic illustrated in Appendix I: Win32 code to write output to properly address globalization requirements.

Many commands will choose to output data in multiple formats. At a minimum, they must be able to output programmatic-friendly, schema-enhanced data streams. Schema enhanced data streams start with a Preamble indicated by the character sequence “#< “ followed by the name of the data schema in use (e.g. CliXml, TCSV, etc). The preamble can optionally continue with multiple lines of the format “# NAME VALUE”. These lines can provide additional information about the data such as when, where, and by whom it was created. The preamble is terminated with a blank line and followed by the body.

Many of today’s scripts are all about outputting the data in different formats or parsing the output to manipulate the data and output or act upon it. To support a rich scripting environment. Commands must support the -OutputFormat parameter to allow users to specify their desired format and the -OutputPreamble to configure schema enhanced data streams.

Standard values for -OutputFormat are:

  • TCSV

  • HTML

  • LIST

  • TABLE

  • WIDE(Output only the Name or ID in multiple columns.)

  • CLIXML

Standard values for -OutputPreamble are:

  • NONE (This allows CLIXML data to be processed as text)

  • BRIEF (Single line indicating schema)

  • FULL (multiple lines providing additional data about the data)

Note

-OutputPremable only applies to some OutputFormats (e.g. CliXML and TCSV).

Commands must use of the value of the environmental variable CliDataStreamSchema when -OutputFormat is not specified.

Commands must support at least one format of schema-enhanced dataStreams (TCSV or CliXml).

Commands should support CliXml Appendix F - CliXmlDataStream Data Schema and Appendix K - Error Record Schema and tag which stream (DEBUG, ERROR, OUTPUT VERBOSE, or WARNING) the data came from.

Commands must output CliXml when the environmental variable CliXmlStreams is set to TRUE. Commands must output XML using CliXmlDataStream schema.

Users want uniform control over what information is displayed when and fine control over that information. Developers must analyze the data that they are outputting and tag it with the “virtual stream” tag. The OUTPUT virtual stream will be emitted on STDOUT and all others will be emitted on STDERR. Developers can output anything on any virtual stream except the ERROR stream. The ERROR stream must emit error records in the schema defined in Appendix K - Error Record Schema.

Virtual Stream Definitions:•

  • DEBUG - Developer-focused activity/information (not localized).

  • ERROR - Messages indicating the failure to process a record or object (localized).

  • OUTPUT - Results of successful processing (localized).

  • VERBOSE - User-focused activity/information (localized).

  • WARNING - Processing irregularity occurred (able to complete the operation but something could be off) (localized).

3.9 Exit, Errors, and Others
To facilitate command composition, the only thing that should be output on STDOUT is command results. Error messages (as well as VERBOSE and DEBUG messages) must be written to STDERR. When scripting with commands, the admin has to know whether a command succeeded or not. Commands must terminate with an exit code indicating success (0) or failure (non-zero).There are existing Microsoft standards for the generation of error messages which provide guidance about such things as being very specific, providing recovery actions etc. Those are all good guidelines and you should follow them. They do however produce a problem for the command line user. Most command line users want to operate on the level of recognition vs. reading. They’ll want a verbose error message long enough to understand the issue and then they’ll want a pithy message that they can recognize and respond to. Commands should use the exit codes and standardized error messages defined in Appendix C. Augment those standardized error messages with specific detailed error messages. One of the most common errors that will occur is getting the command line syntax wrong. Commands should tell the user (on STDERR) the syntax of a command if they specify a syntactically invalid command.

Command Name Example

Assume we have a feature named “Burp”. The main component of our feature is a service. We decide to use our feature name as part of the noun, so that we end up with the noun “BurpService”.

As we look over the verb tables we see that the lifecycle verbs match most of our basic control needs. For our service we need:

  • Disable

  • Enable

  • Install

  • Restart

  • Start

  • Stop

  • Uninstall

After careful examination we note that our service can not be suspended so we don’t need the “Suspend” and “Resume” verbs. We also may note that in a previous service, that our new BurpService is modeled on, we used “kill” to stop the service. Looking at the tables, we decide that stop conveys the same meaning to the user so we decide to use the verb “Stop” instead of “Kill”.

Next we look at the common object verbs. Notice that for the BurpService we can retrieve and set useful information. In the past we might have used “Find” and “Write” but when we search for this, we see that these verbs are not in the list and that the correct verbs to use are “Set” and ”Get”.

Thus we end up with the command names: Disable-BurpService, Enable-BurpService, Install-BurpService, Restart-BurpService, Start-BurpService, Stop-BurpService, Uninstall-BurpService, Get-BurpService, and Set-BurpService.

There is a set of commands that are important enough to warrant special attention, namely the commands to navigate and operate on namespaces. The most familiar example of this is navigating Filesystems (e.g. cd, pushd, popd) and operating on files (e.g. cat, rm, mkdir). There are many other namespaces such as WMI, AD, Registry, XML, etc. If you provide an interactive utility which navigates a namespace, you should provide an implementation of the following common model.

A namespace is a named set of objects organized into a hierarchy. That hierarchy is called a Drive. The hierarchy is comprised of a set of Locations identified by strings call Paths. The syntax for a Location is “Drive:Path”. At each location there can be one or more of the following elements: ChildItem, Item, Property, Content, Permission, Relation. See Appendix G: Navigation Examples

Note that the model makes no attempt to standardize the syntax for a Path or the data structures for any of the elements. The properties and content of a REGISTRY location are very different from that of a Filesystem or an XML document. The syntax for an AD path is very different from a Filesystem (children are appended to the left with a “,” delimiter).

With this basic model in place, we can apply the rest of the command line standard to produce a set of commands to navigate and manage any space. See Appendix G for a table of commands and their Filesystem equivalents. Notice that the targets of the commands can be relative or absolute (e.g. Get-Content c:\Burp\bar.txt or Set-Location c:\Burp;Get-Content bar.txt )

Appendix A - Standardized Verb Sets and Verb Names

The following table is organized as follows:

The leftmost column is the list of verbs, followed by a column with the verb definition.

  1. The “common parameters” are the parameters most often used with that verb. Note that not all parameters in the list will be supported for each verb. For example when removing a file it may not be necessary to support an “-Erase” option. However, there may be times when security, or other reasons, dictates that the item not just be removed from the system, but that the bits be erased. In that case, the preferred parameter is “-Erase”.

  2. The next column lists the “obsolete” verbs. Recall that earlier it was noted that one of the goals is to converge the language used to administrate a system to a set of well-understood, common terms. Part of that effort requires obsolescing some of the words that could be used to imply the same operations.

  3. The last column is the pair of the verb. While not required, often times when a noun supports a verb, it will also support the pair.

Note that there are several verb tables. The first, the “common object verbs”, are the verbs that will be used with most nouns. As noted previously, any one noun probably will not support all the verbs in this set. However, all nouns will probably support some of these.

The other verb sets are more specific to a particular type of noun or a particular activity. These include data verbs, lifecycle verbs, diagnostic verbs, and communications verbs.

Common Object Verb Set

Common object Verbs

Definition

Common Parameters

Obsoletes

Pair

Add

Add, append or attach an element

At, After, Before, Create, Filter, Force, ID, Name, Value

append, attach, concatenate, insert

Remove

Clear

Remove all the elements or content of a container

 

flush,erase, release, unmark, unset,nullify

 

Copy

Copy a resource to another name or another container

Container, Destination, Overwrite, Recurse, Strict

duplicate, clone, replicate

 

Get

-object -content -ChildItem

All, As, Compatible, Continuous, Count, Encoding, Exclude, Filter, Include, ID, Interval, Name, Path, Property, Recurse, Scope, Sortby

read, open, cat, type, dir, obtain, dump, acquire, examine, find, search

Set

Lock

     

Unlock

Move

Move a resource

 

transfer, name, migrate

 

New

create a new resource

Description, ID, Name, Value

create, generate, build, make, allocate

Remove

Remove

Remove a resource from a container

(Get), Drain, Erase, Force

delete, disconnect, detach, drop, purge, flush, erase, release

Add/New

Rename

Give a resource a new name

     

Set

-object -content -ChildItem

Passthru,

write, reset, assign, configure

Get

Unlock

     

Lock

Data Verbs

Definition

Common Parameters

Obsoletes

Pair

Checkpoint

Create a snapshot of the current state of data or configuration so that it could be Restored later

Description, Name, Scope

Diff

Restore

Compare

Compare this resource with another one and produce a set of differences

 

Diff

 

Convert

Change from one encoding to another or from one unit base to another (e.g. feet to meters)

     

Export

Make a copy of a set of resources using an interchange format

(get), Add, As, AsScript, Delete, Description, FileName, Location, Strict, Whatif

extract,backup

Import

Import

Create a set of resources using an interchange format

FileName, Location

bulk load, load

Export

Initialize

Prepare a resource for use. Assign a beginning value to something

 

erase, renew, rebuild, reinitialize, setup

 

Limit

Limit the consumption of a resource or apply a constraint on a resource

 

quota

 

Merge

Take multiple instances and create a single instance

 

coalesce

 

Restore

Rollback state to a predefined snapshot/checkpoint

   

Checkpoint

Update

update or refresh a resource from a source of truth

 

refresh, renew, recalculate, reindex

 

Lifecycle Verbs

Definition

Common Parameters

Obsoletes

Pair

Disable

Stop and/or configure something to be unavailable (e.g unable to not start again)

   

Enable

Enable

Configure to be available (e.g. able to start)

   

Disable

Install

Settle in an indicated place or condition (optionally initializing for use)

 

setup, load

Uninstall

Restart

Terminate existing activity and begin it again (with the same or checkpointed configuration)

 

recycle

 

Resume

Begin an activity again after it was suspended

   

Suspend

Start

Begin an activity

 

launch, initiate, boot

Stop

Stop

Discontinue or cease an activity

 

end, kill, terminate, cancel

Start

Suspend

Suspend an activity temporarily

 

pause

Resume

Uninstall

     

Install

Diagnostics verb

Definition

Common Parameters

Obsoletes

Pair

Debug

Interact with a resource or activity for the purpose of finding a flaw or better understanding of what is occurring.

     

Measure

calculate/identify resources consumed by a specified operation or retrieve statistics about a resource

     

Ping

Determine whether a resource is alive and responding to requests

     

Resolve

Map a shorthand name will be bound to a long name

 

where, which

 

Test

Verify the operational validity or consistency of a resource

 

diagnose, verify, analyze, salvage

 

Trace

Trace activities performed by a specified operation

     

Communications

Definition

Common Parameters

Obsoletes

Pair

Send

Convey by an intermediary to a destination

 

put, broadcast, mail, fax,

receive

Receive

Take or acquire from a source

 

read, accept, peek,

send

Connect

Associate subsequent activities with a resource

   

disconnect

Disconnect

     

connect

Appendix B - Standardized Parameters

The parameter list shown below is designed to be used in conjunction with the parameters listed with the verbs in the table at Appendix A.

Start by selecting a verb from the verb table. Next, determine which of the verb’s common parameters (listed in the same row of the table) you should support. If you need additional parameters, search the parameter table, shown below, and see if an existing parameter name covers the scenario you need. Using these two tables should cover a large percentage of scenarios. It is however expected that many commands will have unique parameters. In that case the command writer should add the command specific parameters as needed.

Parameter

Type

Definition

Ubiquitous Parameters

Confirm

Boolean

Ask user before operation is performed

Description

String

Admins should be able to describe anything that they create to help them remember what it is and why it exists. Sometimes this can't be persisted but it can still be included in an Event

PassThru

Boolean

For those Cmdlets that would direct output to somewhere other than stdout.

Scope

Keyword

User, AllUsers, OS, Machine, Cluster, Domain, Local, Global, Script

Verbose

Boolean

progress of operation is displayed on the progress stream

Whatif

Boolean

Show what would occur if the command ran for real. (e.g. log activities that would take place)

Activity Parameters

CaseSensitive

Boolean

true = case sensitive, false = ignorecase

Command

String

What command should be run

Compatible

String

Identifies what semantics to be compatible with (used for backward compatiblity when changing semantics)

Compress

Boolean

Whether to compress the data

Compress

Keyword

How to compress the data

Continuous

Boolean

Keep getting more information

Create

Boolean

Determines whether to create a resource if one does not already exist

Delete

Boolean

Delete resources when done

Drain

Boolean

Wait for current activities to complete.

Encrypt

Boolean

-

Encrypt

Keyword

Type of encryption to use

Erase

Int32

Specifies the number of times a resource should be erased when it is deleted

ErrorLevel

int32

Level of problem to report

ErrorLimit

int32

Maximum number of errors that should occur before command is cancelled.

Exclude

String

-

Exclude

Keyword

-

Fast

Boolean

-

Filter

string

-

Follow

Boolean

Track progress of an activity

Force

Boolean

-

Ignore

Array of Keywords

-

Include

String

-

Include

Keyword

-

Incremental

Boolean

-

Insert

Boolean

-

Interactive

Boolean

-

Interval

hashtable of keyword/values

e.g. -interval {resumescan<=15, retry<=3}

Log

Boolean

progress of operation is displayed on the progress stream

Migrate

boolean

-

Notify

Boolean

Tell user about completion of an operation

Notify

Email Address

Tell user about completion of an operation

Overwrite

Boolean

-

Prompt

String

-

ReadOnly

Boolean

vs -Write

Recurse

Boolean

-

Repair

Boolean or string

-

Retry

int32

-

Select

Array of Keywords

List of items to select

SortBy

String

-

Strict

Boolean

Consider any error a fatal error

Temp

Pathname

Location of where to put temporary data

Temp

Boolean

Changes are temporary

TimeOut

Int specifying Milliseconds

-

Trace

Boolean

Internal operations are displayed on the progress stream

Truncate

Boolean

-

Update

Boolean

Same as VERB

Verify

Boolean

Perform a test to ensure that operation occurred

Wait

Int32

#of seconds cmd will wait for required resources to become available

Wait

Boolean

Wait for user input before continuing

Warning

Boolean

Controls whether optional warning messages are displayed

Write

Boolean

vs -Readonly

Date and Time Parameters

Accessed

Boolean

Specifies which time -Before or -Since refers to. Incompatible with -Modified or -Created

After

DateTimeExpression

-

Before

DateTimeExpression

-

Created

Boolean

Specifies which time -Before or -Since refers to. Incompatible with -Modified or -Accessed

Modified

Boolean

Specifies which time -Before or -Since refers to. Incompatible with -Created or -Accessed

TimeStamp

Boolean

Set or Get Timestamp

Format Parameters

As

Keyword

TCSV, Text, Script, XML, etc

Ascending

Boolean

-

Binary

Boolean

-

Char

int32

-

Descending

Boolean

-

Elapsed

Boolean

Show elapsed Time

Encoding

Keyword

ASCII UTF8, Unicode, UTF7

Exact

Boolean

-

Format

String

-

NewLine

Boolean

-

Shortname

Boolean

Use short names (e.g. 8.3 for filesystem)

Width

int32

-

Wrap

Boolean

-

Property Parameters

Cache

keyword

-

Count

Int32

-

Default

Boolean

-

From

ResourceName

reference object to get information from

Id

???

-

Input

FileSpec

-

LineCount

Int32

-

LogName

string

-

Location

String

-

Name

String

-

Output

FileSpec

-

Owner

??

-

Parameter

Hashtable

Mechanism to pass attribute/values through a common command

Password

password

-

Priority

Int32

-

Property

string

Property Name

Reason

UserDescriptionString

Why is this happening

Regex

Boolean

Use regex instead of wildcarding for this command

Statistic

Keyword

-

Size

int32

-

Speed

Pair of int32

Baud rate (input,output)

State

Array of Keywords

Named state (e.g. KEYDOWN)

Value

object

-

Version

VersionSpecifier

-

Quantity Parameters

All

Boolean

-

Allocation

Int32

Number of items to allocate

BlockCount

int64

-

Count

int64

-

Maximum

Int32

Maximum number of items

Minimum

Int32

Minimum number of items

Most

Boolean

Sensible subset of all

Unique

Boolean

-

Resource Parameters

AssemblyName

String

-

ApplicationName

string

-

AttributeName

string

FileSystem attributes

ClassName

String

e.g. type

ClusterName

String

-

ComputerName

String

-

DirectoryName

string

-

DomainName

String

Domain Name

DriveName

string

Drive name e.g. C:

EventName

String

Event Name (e.g. CRIMSON URI)

FileName

String

-

InterfaceName

String

Network Interface Name

IpAddress

IpAddress

-

JobName

String

-

MacName

MacAddress

-

ComputerName

string

Computer to operate on

ParentID

-

-

PortName

string

Int for networking but string for other types of port (eg Biztalk)

PrinterName

String

-

TID

-

Transaction ID

TypeName

string

Type of resource to operate on

URL

string

-

UserName

string

-

Security Parameters

ACL

-

-

CertFile

FileName

A file containing a Base64 or DER encoded x.509 certificate or a PKCS#12 file containing at-least one certificate and key.

CertIssuerName

String

A string indicating the Issuer of a certificate, or a substring.

CertRequestFileName

String

A file containing a Base64 or DER encoded PKCS #10 certificate request.

CertSerialNumber

String

Serial number issued by cert authority

CertStoreLocation

String

Location of certificate store. Typically a file path

CertSubjectName

String

A string indicating the Issuer of a certificate, or a substring.

CertUsage

String

A string representing the enhanced key usage or key usage. Can be represented as a bit bask, a bit, a oid or a string.

CSPName

String

Name of the certificate service provider (CSP)

CSPType

Integer

Type of CSP

Group

String

A collection of principals

KeyAlgorithm

String

Key generation algorithm

KeyContainerName

String

Name of the key container

KeyLength

Int

Key length in number of bits

Operation

String

An action that can be performed on a protected object

PrincipalName

String

Unique identifiable entity

Privilege

Array of Privs

-

Privilege

string

The ability to perform an operation

Role

String

Group of operations

SaveCred

Boolean

Use save credentials

SID

String

Unique identifier representing a principal

Trusted

Boolean

-

TrustLevel

Keywords (Internet, intranet, fulltrust etc)

-

Appendix C - Standardized Error Message Templates

The table below shows a list of Error Message Template strings. Elements in {}s are meant to be substituted but the other sigils are meant to be used to facilitate the easy visual parsing of the error messages. Thus the string “Insufficient Privilege to [{action}] ({resource}:{type})” would be used to generate the following error messages:Insufficient Privilege to [Delete] (C:\windows\system32\Burp.dll:FILE)Insufficient Privilege to [Modify] (HKLM:\software\microsoft\Burp:REGKEY)Insufficient Privilege to [STOP] (15:PROCESS)

Category ID

Exit Code

Template String

Condition

NoError

0

 

No Error

Close

1

CloseError: ({targetname}:{type}) [{action}], ‘{reason}’

A close error occurred

DeadlockDetected

2

DeadlockDetected: ({targetname}:{type})

A deadlock was detected

Device

3

DeviceError: ({targetname}:{type}) [{action}], ‘{reason}’

A device error occurred

InvalidArgument

4

InvalidArgument: ({targetname}:{type}) [{action}], ‘{reason}’

Invalid Argument

InvalidCategory

5

Unrecognized error category {ErrorCategory}: ({resource}:{type}) [{action}], ‘{reason}’

Use of an unrecognized error category

InvalidData

6

InvalidData: ({targetname}:{type}) [{action}], '{reason}'

The data is not valid for the operation

InvalidOperation

7

InvalidOperation: ({targetname}:{type}) [{action}] ‘{reason}’

The operation is not valid

InvalidResult

8

InvalidResult: ({targetname}:{type}) [{action}], ‘{reason}’

A result that falls outside of allows parameters. Underflow or Overflow

InvalidType

9

InvalidType: {type} ({targetname})

The type of the object is invalid for the target operation

Metadata

10

MetadataError: ({targetname}) ‘{reason}’

A Metadata error has occurred

NotImplemented

11

NotImplemented: [{action}] ({targetname})

The requested action is not implemented for the target

NotInstalled

12

NotInstalled: ({targetname})

Resource may be a cmdlet name or the underlying resource that a cmdlet may require. This is only used if it can be distinguished from “ResourceUnavailable” above and is known to not be installed.

NotSpecified

13

NotSpecified: ({Targetname}:{type}): [{action}], ‘{Reason}’

An unspecified error

ObjectNotFound

14

ObjectNotFound: ({targetname}:{type})

object can not be found (This can be a file, directory, system, resource, etc)

Open

15

OpenError: ({targetname}:{type}).: '{reason}'

An open error has occurred

OperationTimeout

16

OperationTimeout: ({targetname}:{type}]) [{action}]

The operation has timed out

Parser

17

ParseError ({targetname}:{type})

The parser error has occurred

PermissionDenied

18

PermissionDenied: [{action}] ({targetname}:{type})

Operation not permitted

Read

19

ReadError: ({targetname}:{type}) [{action}], ‘{reason}’

A read error has occurred

ResourceBusy

20

ResourceBusy: ({targetname}:{type})

The resource is busy

ResourceExists

21

ResourceExists: ({targetname}:{type})

The resource exists

ResourceUnavailable

22

ResourceUnavailable : ({targetname}:{type})

The resource is currently unavailable. A network resource that is temporarily not ready.

Syntax

23

SyntaxError: ({targetname}:{type})

A Syntax Error has occurred

Write

24

WriteError: ({targetname}:{type}) [{action}], ‘{reason}’

A Write Error has occurred

Generic

999

 

Provided for those errors that are not satisfied by the above categories

Appendix D - Standardized Globbing

Globbing, which is similar to wildcard expansion, is typically used as an input filter. For example, a command may take a path as an input. Within that path globbing may be used to select multiple objects to operate on. A common case is in the file system where a user wants to see all files residing in the current folder (i.e. dir *). Commands should either support the full POSIX 1003.2, 3.13 specifications for globbing or the following simplified subset:

?

A question-mark is a pattern that shall match any single character.

*

An asterisk is a pattern that shall match multiple characters

[

The open bracket shall introduce a pattern bracket expression.

Example:

PS> get-childitem
    Directory: FileSystem::C:\test
Mode    LastWriteTime     Length Name
----    -------------     ------ ----
-a---   Oct 04 14:38          0  a
-a---   Oct 04 14:38          0  abc
-a---   Oct 04 14:38          0  b
-a---   Oct 04 14:38          0  c
-a---   Oct 04 14:38          0  d
-a---   Oct 04 14:38          0  def
-a---   Oct 04 14:38          0  ghi
-a---   Oct 04 14:38          0  XRAY

PS> get-childitem ?
    Directory: FileSystem::C:\test
Mode    LastWriteTime     Length Name
----    -------------     ------ ----
-a---   Oct 04 14:38          0  a
-a---   Oct 04 14:38          0  b
-a---   Oct 04 14:38          0  c
-a---   Oct 04 14:38          0  d

PS> get-childitem [abc]
    Directory: FileSystem::C:\test
Mode    LastWriteTime     Length Name
----    -------------     ------ ----
-a---   Oct 04 14:38          0  a
-a---   Oct 04 14:38          0  b
-a---   Oct 04 14:38          0  c

PS> get-childitem [ad]*
    Directory: FileSystem::C:\test
Mode    LastWriteTime     Length Name
----    -------------     ------ ----
-a---   Oct 04 14:38          0  a
-a---   Oct 04 14:38          0  abc
-a---   Oct 04 14:38          0  d
-a---   Oct 04 14:38          0  def

PS> get-childitem [^abc]*
    Directory: FileSystem::C:\test
Mode    LastWriteTime     Length Name
----    -------------     ------ ----
-a---   Oct 04 14:38          0  d
-a---   Oct 04 14:38          0  def
-a---   Oct 04 14:38          0  ghi
-a---   Oct 04 14:38          0  XRAY

PS> get-childitem [^a-m]*
    Directory: FileSystem::C:\test
Mode    LastWriteTime     Length Name
----    -------------     ------ ----
-a---   Oct 04 14:38          0  XRAY

Appendix E - Standardized Data Example

Appendix F provides the Standardized Data Schema. Here we include a couple of C# classes and show the XML that it is serialized to as an aid to understand the Schema.

Note

This leverages many of the XSD types defined in https://www.w3.org/TR/xmlschema-2/ . This schema is in no way tied to .NET. Whenever you see something that looks like a .NET type name (e.g. contents of the <TYPEHIERARCHY>) it is merely a STRING “hint” to the user. This is made clear in Appendix F - CliXmlDataStream Data Schema. Win32 developers can use any string they want in this section, though they are cautioned to avoid using a string which would conflict with a .NET type name.

public class Zazu
    {
        public string p_String = "Zazu";
        public int p_Int = 3;
    }
    public class Bar
    {
        public char p_Char = 'c';
        public Guid p_Guid = 
                     new Guid("8E3867A3-8586-11D1-B16A-00C0F0283628");
        public byte p_UnsignedByte = 3;
        public DateTime p_DateTime = new DateTime(2004,10,1);
        public Decimal p_Decimal = new Decimal(44);
        public Double p_Double = 3.1415;
        public TimeSpan p_TimeSpan = new TimeSpan(1, 1, 1);
        public float p_Float = 3.1415F;
        public int p_Int = 3;
        public long p_Long = 3;
        public sbyte p_Sbyte = 3;
        public short p_Short = 3;
        public byte[] p_ByteArray = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
        public string p_String = "stringInstance";
        public ushort p_UnsignedShort = 3;
        public uint p_Uint = 3;
        public ulong p_Ulong = 3;
        public string p_Nil = null;
        public Zazu p_Zazu = new Zazu();
    }

<Objs Version="1.1" xmlns="https://schemas.microsoft.com/powershell/2004/04">
<Obj RefId="RefId-0">
<TN RefId="RefId0">
<T>myCmdlets.Bar</T>
<T>System.Object</T>
</TN><Props>
<C N="p_Char">99</C>
<G N="p_Guid">8e3867a3-8586-11d1-b16a-00c0f0283628</G>
<By N="p_UnsignedByte">3</By>
<DT N="p_DateTime">2004-10-01T00:00:00</DT>
<D N="p_Decimal">44</D>
<Db N="p_Double">3.1415</Db>
<TS N="p_TimeSpan">PT1H1M1S</TS>
<Sg N="p_Float">3.1415</Sg>
<I32 N="p_Int">3</I32>
<I64 N="p_Long">3</I64>
<SB N="p_Sbyte">3</SB>
<I16 N="p_Short">3</I16>
<BA N="p_ByteArray">AAECAwQFBgcICQ==</BA>
<S N="p_String">stringInstance</S>
<U16 N="p_UnsignedShort">3</U16>
<U32 N="p_Uint">3</U32>
<U64 N="p_Ulong">3</U64>
<Nil N="p_Nil" />
<Obj N="p_Zazu" RefId="RefId-1">
<TN RefId="RefId-1">
<T>myCmdlets.Zazu</T>
<T>System.Object</T>
</TN><Props>
<S N="p_String">Zazu</S>
<I32 N="p_Int">3</I32>
</Props>
</Obj>
</Props>
</Obj>
</Objs>

Appendix F - CliXmlDataStream Data Schema

This leverages many of the XSD types defined in https://www.w3.org/TR/xmlschema-2/ . This schema is in no way tied to .NET.

Appendix G: Navigation Examples

Namespace Command

Filesystem Command

Set-location c:\test

Cd c:\test

Get-location

pwd

Get-childitem

Dir

Get-childitem d:\wango

Dir d:\wango

Get-content Burp.txt

Type Burp.txt

Get-content c:\test\Burp.txt

Type c:\test\Burp.txt

New-item bar -type directory

Mkdir bar

Remove-item tango.txt

Del tango.txt

Rename-item tango.txt zazu.txt

Rename tango.txt zazu.txt

Copy-item tango zazu

Cp tango zazu

Set-location hklm:\software\Microsoft

 

Get-property WBEM

 

Set-property WBEM PROP1 VALUE1

 

New-Property WBEM prop2

 

Remove-property wbem prop2

 

Set-location xml:\Burp.xml\root\element

 

Get-content data

 

Appendix H: Standardized Help Tags

Field Name

Description

alertSet

These are special notes (like caution, warning, behavior while remoting, security issues, support info, etc) that need to be given to the user. For example, a note for the “format” cmdlet would say, “All your data will be lost by performing operation”. Support info might include the URLs of newsgroups where the user can look in for support on the help item.

commandDescription

This is a short description of the tool. Guidance is 12 words maximum,.

commandErrors

Describes the errors that the cmdlet throws. Warning and non-critical errors are also covered. Contains error tags.

commandExamples

One or more example(s) that show the usage of the tool/feature. Each example contains the codeExample, remarks, and results tags.

commandParameters

The parameters to the cmdlet.

commandSyntax

This describes how a tool/feature is used. Each of the parameters/switches of the tool are described in more detail under commandParameters.

Configuration

The required settings/configuration information/environment variables for the cmdlet

Copyright

A copyright message for the help content. This field is not displayed by default.

Description

Detailed description of the DocItem. This could be many pages long.

inputTypes

This describes the types of Input Object (DataObject) that the cmdlet expects as input. Contains inputType tags.

name

Name of the tool/feature.E.g.: dir, file, “Shell Internals”.

noun

The noun name of the command. This field is used for searching; it is not displayed by default.

This section shows the layout of the XML for help. Optional elements and attributes are shown in italics; content is in boldface.

<commandHelp>

  <commandDetails>
    <name>sample-command</name>
    <commandDescription>short description</commandDescription>
    <synonyms>
      <synonym>samp</synonym>
    </synonyms>
    <commandCopyright>(c) 2004 Microsoft</commandCopyright>
    <verb>sample</verb>
    <noun>command</noun>
    <version>1.0</version>
    <vendor>
      <name>Microsoft Corporation</name>
      <products>
        <product>Microsoft Command Shell</product>
      </products>
    </vendor>
  </commandDetails>

  <description>
    <para>
      text
      <parameterNameInline>parameter name</parameterNameInline>
      <parameterValueInline>parameter value</parameterValueInline>
      <commandInline>command example</commandInline>
    <para>
    <list class="ordered|unordered">
      <listItem>
        <para>text</para>
      </listItem>
    </list>
    <definitionList>
      <definitionListItem>
        <term>term</term>
        <definition>
          <para>text</para>
        </definition>
      </definitionListItem>
    </definitionList>
  </description>

  <commandSyntax>
    <commandSyntaxItem>
      <name>sample-command</name>
      <commandSyntaxParameter>
        <commandParameterName required="true">
          -Parameter1
        </commandParameterName>
        <commandParameterValue required="true" variableLength="true"
                               type="literal">
          ParamValue1
        </commandParameterValue>
      </commandSyntaxParameter>
      <commandSyntaxParameter>
        <commandParameterName required="true">
          -Parameter2
        </commandParameterName>
        <commandParameterValueGroup required="true">
          <commandParameterValue>
            ParamValue21
          </commandParameterValue>
          <commandParameterValue>
            ParamValue22
          </commandParameterValue>
        </commandParameterValueGroup>
      </commandSyntaxParameter>
    </commandSyntaxItem>
  </commandSyntax>

  <commandParameters>
    <commandParameter required="true" variableLength="true"
                      globbing="true" pipelineInput="true"
                      position="0">
      <name>-Parameter2</name>
      <commandParameterValue required="true" variableLength="true"
                             type="literal">
        ParamValue2
      </commandParameterValue>
      <type>
        <name>Typename</name>
        <uri href="href" uri="uri" ref="ref">
          <summary>URI summary</summary>
        </uri>
      </type>
      <description>
        <para>text</para>
      </description>
      <defaultValue>default Value</defaultValue>
      <validation>
        <minCount>1</minCount>
        <maxCount>2</maxCount>
        <minLength>1</minLength>
        <maxLength>10</maxLength>
        <minRange>5</minRange>
        <maxRange>10</maxRange>
        <commandParameterValueGroup required="true">
          <commandParameterValue>
            ParamValue21
          </commandParameterValue>
          <commandParameterValue>
            ParamValue22
          </commandParameterValue>
        </commandParameterValueGroup>
      </validation>
    </commandParameter>
  </commandParameters>

  <inputTypes>
    <inputType>
      <type>
        <name>Typename</name>
        <uri href="href" uri="uri" ref="ref">
          <summary>URI summary</summary>
        </uri>
      </type>
      <description>
        <para>text</para>
      </description>
    </inputType>
  </inputTypes>

  <returnTypes>
    <returnType>
      <type>
        <name>Typename</name>
        <uri href="href" uri="uri" ref="ref">
          <summary>URI summary</summary>
        </uri>
      </type>
      <description>
        <para>text</para>
      </description>
    </returnType>
  </returnTypes>

  <terminatingCommandErrors>
    <terminatingCommandError>
      <type>
        <name>Typename</name>
        <uri href="href" uri="uri" ref="ref">
          <summary>URI summary</summary>
        </uri>
      </type>
      <description>
        <para>text</para>
      </description>
      <errorId>error-id</errorId>
      <suggestedAction>text</suggestedAction>
      <targetObjectType>
        <name>Typename</name>
        <uri href="href" uri="uri" ref="ref">
          <summary>URI summary</summary>
        </uri>
      </targetObjectType>
      <category>category</category>
    </terminatingCommandError>
  </terminatingCommandErrors>

  <nonTerminatingCommandErrors>
    <nonTerminatingCommandError>
      <type>
        <name>Typename</name>
        <uri href="href" uri="uri" ref="ref">
          <summary>URI summary</summary>
        </uri>
      </type>
      <description>
        <para>text</para>
      </description>
      <errorId>error-id</errorId>
      <suggestedAction>text</suggestedAction>
      <targetObjectType>
        <name>Typename</name>
        <uri href="href" uri="uri" ref="ref">
          <summary>URI summary</summary>
        </uri>
      </targetObjectType>
      <category>category</category>
    </nonTerminatingCommandError>
  </nonTerminatingCommandErrors>

  <alertSet class="note|configuration">
    <title>title</title>
    <alert>
      <para>text</para>
    </alert>
  </alertSet>

  <commandExamples>
    <commandExample>
      <commandLines>
        <commandLine>
          <commandText>$&gt; </commandText>
          <commandText input="true" newline="true">
            sample-command
          </commandText>
          <commandText>output</commandText>
        </commandLine>
      </commandLines>
      <description>
        <para>text</para>
      </description>
    </commandExample>
  </commandExamples>

  <relatedLinks type="seeAlso">
    <navigationLink>
      <linkText>text</linkText>
      <uri href="href" uri="uri" ref="ref">
        <summary>URI summary</summary>
      </uri>
    </navigationLink>
  </relatedLinks>

</commandHelp>

Appendix I: Win32 Code to Write Output

void
MyWriteConsole(
    HANDLE  fp,
    LPWSTR  lpBuffer,
    DWORD   cchBuffer
    )
{   if(!lpBuffer || !cchBuffer)
    {   assert(false);
        return;
    }
    //
    // Jump through hoops for output because:
    //
    //    1.  printf() family chokes on international output (stops
    //        printing when it hits an unrecognized character)
    //    2.  WriteConsole() works great on international output but
    //        fails if the handle has been redirected (i.e., when the
    //        output is piped to a file)
    //    3.  WriteFile() works great when output is piped to a file
    //        but only knows about bytes, so Unicode characters are
    //        printed as two Ansi characters.

    if (FILE_TYPE_CHAR == FileType(fp))
    {   WriteConsole(fp, lpBuffer, cchBuffer, &cchBuffer, NULL);
    }
    else if (g_fUnicodeOutput)
    {   //Buffer bounds are passed correctly.
        WriteFile(fp, lpBuffer, cchBuffer*sizeof(WCHAR), &cchBuffer, NULL);
    }
    else
    {   int nSizeAnsiBuffer = WideCharToMultiByte(CP_OEMCP,
                                                  0,
                                                  lpBuffer,
                                                  cchBuffer,
                                                  NULL,
                                                  0,
                                                  NULL,
                                                  NULL);
        if(nSizeAnsiBuffer > 0)
        {
            LPSTR  lpAnsiBuffer = (LPSTR) LocalAlloc(LPTR, nSizeAnsiBuffer);

            if (lpAnsiBuffer != NULL)
            {
                cchBuffer = WideCharToMultiByte(CP_OEMCP,
                                                0,
                                                lpBuffer,
                                                cchBuffer,
                                                lpAnsiBuffer,
                                                nSizeAnsiBuffer,
                                                NULL,
                                                NULL);

                if (cchBuffer != 0)
                {
                    WriteFile(fp, lpAnsiBuffer, nSizeAnsiBuffer, &cchBuffer, NULL);
                }
                LocalFree(lpAnsiBuffer);
            }
        }
    }
}

Appendix J - Using Windows PowerShell to implement the Microsoft Command Line Standard

This document defines a set of guidelines to provide a consistent, composable command line user experience. Developers can implement these guidelines however they chose, however if they implement Windows PowerShell Cmdlets, they will get much of this for free. Specifically:

Command Names

Windows PowerShell Cmdlets ensure proper verb-noun naming.

Consistent Syntax

Windows PowerShell handles the parsing of the command line entirely. Your Cmdlet class specifies a set of metadata which then drives the Windows PowerShell parser.

Input

Windows PowerShell accepts and encodes input (either directly or through a set of utility functions) from a wide range of formats including XML, TCSV, ADO, PropertyBags, etc. This input is used to populate your Cmdlets public properties before calling your Cmdlet’s ProcessRecord() method.

Parameters

Windows PowerShell implements for -?, -Help, -Version, -Verbose and -Debug. Your command will be responsible for supplying the data for these functions either through well defined data elements (e.g. help files) or by calling well defined APIs (e.g. WriteVerbose() and WriteDebug()).

Targeting

Windows PowerShell provides an extensible globbing model which allows development of type-specific globbers which can be used by any command.

Output Formatting

Cmdlets provide their results as a stream of .NET objects to Windows PowerShell which then handles formatting and outputting them. Windows PowerShell will format output to a wide (and growing) range of output types and formats including LIST, TABLE, Wide, XML, HTML, ASCII, UTF7, UTF8, UTF32, UNICODE, and BigEndianUnicode.

Windows PowerShell will respect the environmental variable CliXmlStreams and render all streams in XML using CliXmlDataStream Schema.

When outputting to CliXml, Windows PowerShell provides a declarative mechanism to map your .NET objects into CliXml but has a default serialization policy if no declarations are provided (It serializes the public known-type [those defined in Appendix F - Standardized Data Schema] properties of your object graph to a depth of 2 where unknown types are transformed into property bags which add a level to the object graph. Properties beyond the depth 2 are rendered to strings.)

Errors

Windows PowerShell ensures that all errors, verbose and debug statements are written to STDERR and will properly set the exit code of the process. Windows PowerShell provides a set of APIs which make it easy to support and output Standardized Error Messages. Windows PowerShell will provide the user the syntax of the command if they specify a syntactically invalid command.

Appendix K - Error Record Schema

The following schema describes the error information that must be emitted by an application. It is a proper subset of the Windows PowerShell ErrorRecord.

<xsd:schema targetNamespace=https://schemas.microsoft.com/msh/2004/04
xmlns:msh=https://schemas.microsoft.com/msh/2004/04
elementFormDefault="qualified"
xmlns:xsd="https://www.w3.org/2001/XMLSchema">
<!-- ErrorRecord is the toplevel element -->
 <xsd:element name="ErrorRecord" type="msh:ErrorRecord">
<!-- Definition of complex type ErrorRecord -->
  <xsd:complexType name="ErrorRecord">
   <xsd:complexType name="Exception" minOccurs="0" maxOccurs="0" />
   <xsd:element name="Message" use="optional" type="xsd;string" />
  </xsd:complexType>
  <xsd:element name="TargetObject" minOccurs="0" maxOccurs="1" type="xsd:string" />
<!-- Define CategoryInfo -->
  <xsd:complexType name="CategoryInfo">
   <xsd:attribute name="Category" use="optional" type="xsd:string" />
   <xsd:attribute name="Activity" use="optional" type="xsd:string" />
   <xsd:attribute name="Reason" use="optional" type="xsd:string" />
   <xsd:attribute name="TargetName" use="optional" type="xsd:string" />
   <xsd:attribute name="TargetType" use="optional" type="xsd:string" />
  </xsd:complexType>
  <xsd:element name="FullyQualifiedErrorId" minOccurs="0" maxOccurs="1" type="xsd:string" />
<!-- Define ErrorDetails -->
  <xsd:complexType name="ErrorDetails">
   <xsd:attribute name="Message" use="required" type="xsd:string" />
   <xsd:attribute name="RecommendAction" use="optional" type="xsd:string" />
  </xsd:complexType>
<!--Define InvocationInfo -->
  <xsd:complexType name="InvocationInfo">
   <xsd:complexType name="MyCommand">
    <xsd:attribute name="Name" use="mandatory" type="xsd:string" />
    <xsd:attribute name="Vendor" use="mandatory" type="xsd:string" />
    <xsd:attribute name="Version" use="mandatory" type="xsd:string" />
    <xsd:attribute name="Product" use="mandatory" type="xsd:string" />
   </xsd:complexType>
   <xsd:attribute name="InvocationName" use="mandatory" type="xsd:string" />
  </xsd:complexType>
 </xsd:element>
</xsd:schema>

Appendix L - Enhanced Interoperability Guidance

There are three levels of interoperability: UNIX, Enhanced, and Optimal. UNIX interoperability refers to the traditional “write text to STDOUT and exit with 0 if successful” model. Summary List of Guidance documents the guidance to achieve Optimal interoperability. This section contains guidelines to achieve Enhanced interoperability. Enhanced interoperability provides developers with a small set of concrete steps that they can do to improve existing commands on the way to achieving Optimal interoperability.

Consistent Syntax

Required:

  • Commands must use the “-“ character for parameter delimitation; the “:” character or whitespace to separate parameters and their arguments and the “,” character to separate multiple values.

Parameters

Required:

  • Commands must support -?, -Help, -Version, -Verbose, and -Debug for all commands.

  • Parameter names must be case-insensitive.

Output Formatting

Required:

  • Output must be written using the logic illustrated in Appendix I: Win32 code to write output to properly address globalization requirements.

  • Commands must support the -OutputFormat parameter to allow users to specify their desired format and the -OutputPreamble to configure schema enhanced data streams

  • Commands must use of the value of the environmental variable CliDataStreamSchema when -OutputFormat is not specified.

  • Commands must support at least one format of schema-enhanced dataStreams (TCSV or CliXml).

Exit, Errors, and Others

Required:

  • Error messages (as well as VERBOSE and DEBUG messages) must be written to stderr.

  • Commands must terminate with an exit coding indicating success (0) or failure (non-zero).

Appendix M - Typed-CSV (TCSV) Data Format

This appendix describes the Typed-CSV (Comma Separated Values) serialization format. This format will be used when importing and exporting data (import-CSV and export-CSV command) and when data needs to be serialized across process boundaries. While XML is generally considered a more modern solution for data exchange, there are bandwidth critical situations where CSV is a better alternative because of the lower overhead. This format serves as a low overhead data exchange format. Using CSV will be possible when the data is a homogenous collection of objects and the object properties are of simple types.

The CSV format is commonly used but its definition remains fuzzy. This appendix builds upon the common CSV practices and defines the precise formatting rules for TCSV.

The TCSV Data stream format

  • Each record is one line ...but

  • A record separator may consist of a line feed (ASCII/LF=0x0A), or a carriage return and line feed pair (ASCII/CRLF=0x0D 0x0A).

  • ...but: fields may contain embedded line-breaks so a record may span more than one line.

  • Fields are separated with commas.

  • Example John,Doe,120 any st.,"Anytown, WW",08123

  • Leading and trailing space-characters adjacent to comma field separators are ignored.

  • So John , Doe ,... resolves to "John" and "Doe", etc. Space characters can be spaces, or tabs.

  • Fields with embedded commas must be delimited with double-quote characters.

  • In the above example. "Anytown, WW" had to be delimited in double quotes because it had an embedded comma.

  • Fields that contain double quote characters must be surrounded by double-quotes, and the embedded double-quotes must each be represented by a pair of consecutive double quotes.

  • So, John "Da Man" Doe would convert to "John ""Da Man""",Doe, 120 any st.,...

  • A field that contains embedded line-breaks must be surrounded by double-quotes

  • So:

  • Field 1: Conference room 1

  • Field 2:

  • John,

  • Please bring the M. Mathers file for review

  • -J.L.

  • Field 3: 10/18/2002

  • ...

  • would convert to:

  • Conference room 1, "John,

  • Please bring the M. Mathers file for review

  • -J.L.

  • ",10/18/2002,...

  • Note that this is a single TCSV record, even though it takes up more than one line in the TCSV data stream . This works because the line breaks are embedded inside the double quotes of the field.

  • Fields with leading or trailing spaces must be delimited with double-quote characters.

  • So to preserve the leading and trailing spaces around the last name above: John ," Doe ",...

  • Fields may always be delimited with double quotes.

  • The delimiters will always be discarded.

  • The first record in a TCSV data stream must be a header record containing column (field) names

  • The header row is encoded just like any other CSV record in accordance with the rules above. A header row for the multi-line example above, might be:

  • Location, Notes, "Start Date", ...

  • The second record in a TCSV data stream must be a type-definition record containing datatypes for the columns defined in the first record.

  • The type-defintion row is encoded just like any other CSV record in accordance with the rules above. The typesnames must be from the list of types defined in Appendix F - CliXmlDataStream Data Schema.

  • Empty fields will be interpreted as missing values.

Appendix N - Argument Parsing Pseudo code

The code below serves as pseudo code for an implementation for argument parsing. It is written in Windows PowerShell to ensure that it works, to use constructs that have clearly defined semantics, and to express complex logic in a pithy way.

#################################################################
#
# Utility routine to convert an argument to the target type.
# This routine also handles array conversions...
#
function convert-argument ([string] $argument, [type] $type)
{
#
# Arguments should be split into arrays on comma boundries
# Split always produces an array so a scalar argument ends
# up as an array anyway...
# Note: quoting of commas is not shown here. A literal comma
# would have to be quoted with a backquote...
#
$result = $argument.split(",")

#
# If the target type is an array, simply convert the string
# array into the target array
#
if ($type.IsArray)
{
$result -as $type
}
else 
{
if ($result.length -gt 1) {
write-error -term "can't assign an array argument to a scalar"
}
$result[0] -as $type
}
}

#################################################################
#
# Parse an array of arguments in a manner consistent with msh
#
# $arglist is an array of strings to be parsed
# $signature is a hash table describing the signature for this command
# Entries take the form of
#name = [type]
# The result of the parse will be to return a hash table
# mapping actual parameters to their values, including the type conversions
#
function parse ($signature, $arglist)
{
$i = 0
$argsLength = $arglist.length

# The $result hash table holding the parsed results
# Any unclaimed arguments will be in the __rest member.
$result = @{};

# an array holding the unclaimed argument values...
$rest = @()

:firstloop
while ($i -lt $argsLength)
{
switch -regex ($arglist[$i])
{

#
# Process arguments of the form
# -foo: 123
# in this form, arguments must be present in the signature array
# and always take an argument
#
'^-([a-zA-Z][a-zA-Z0-9]*):$' {
$argName = $matches[1]
$type = $signature[$argName]
if (! $type)
{
write-error -term "-$argName is not a valid argument"
}

$i += 1
if ($i -ge $argsLength)
{
write-error -term "missing argument to -$argName"
}
$result[$argName] = convert-argument $arglist[$i] $type
break;
}

#
# Process arguments of the form
# -foo:123
# That is, no space between the colon and the argument
# In this case, argument is part of this array element
#
'^-([a-zA-Z][a-zA-Z0-9]*):(.+)$' {
$argName = $matches[1]
$argument = $matches[2]
$type = $signature[$argName]
if (! $type)
{
write-error -term "-$argName is not a valid argument"
}

$result[$argName] = convert-argument $argument $type
break;
}

#
# Process arguments of the form
# -foo 123
# or
#-foo
# in this form, if the argument is in the signature,
# and it's type is boolean, no arg is required or permitted.
# If it's not boolean, then an argument must be provided
# If the parameter is not in the signature set, then it's
# treated as a positional
# argument.
#
'^-([a-zA-z][a-zA-Z0-9]*)$' {
$argName = $matches[1]
$type = $signature[$argName]

# if it's not explicitly a parameter, it's an argument
if (! $type)
{
$rest += $_
}
elseif ($type -eq [bool])
{
$result[$argName] = [bool]1;
}
else
{
$i += 1
if ($i -ge $argsLength)
{
write-error -term "missing argument to -$argName"
}
$result[$argName] = convert-argument $arglist[$i] $type
}
break;
}

#
# Handle the -- end-of-options indicator
# everything after this is simply an argument
#
'^--$' {
$i += 1;
break firstLoop;
}

#
# Things that don't start with a - are just arguments
#
default {
$rest += $_
}

} # end switch

$i += 1
}

#
# Now process any remaining arguments and add them to __rest
:secondLoop
while ($i -lt $argsLength)
{
$rest += $arglist[$i]
$i += 1
}

$result["__rest"] = $rest

$result
}

# end parse
#
#################################################################

#################################################################
#
# Define an example signature
#
$sig = @{
foo = [int]
bar = [bool]
baz = [string]
buz = [double]
biz = [double[]]
}

#
# And a test function...
#
function testparse {
parse $sig $args
}

trap {
write-host ("parse error: " + $_.message)
continue
}

#
# examples using parse
#

"`nExample 1"
testparse -foo: 2 -zork -bar -buz 3.14 -baz: "Hello world"

"`nExample 2 using --"
testparse -foo: 2 -zork -bar -buz 3.14 -- -baz: "Hello world"

"`nExample 3 - colon after boolean argument"
testparse -foo: 2 -zork -bar: false -buz 3.14 -baz: "Hello world"

"`nExample 4"
testparse -foo: 2 -zork -bar -buz 3.14 -baz: "Hello world" -- `
-some -nonargument -flags

"`nExample 5 - doesn't use testparse because msh parsing will split at the :"
parse $sig "-foo:2","-zork","-bar","-buz",3.14,"-baz:","Hello world","--", `
"-some","-nonargument","flags"

"`nExample 6"
testparse -foo: 2 -zork -bar -buz 3.14 -baz: "Hello world" -biz "1,2,3"

"`nExample 7 - assigning a scalar to an array"
testparse -foo: 2 -zork -bar -buz 3.14 -baz: "Hello world" -biz 1

"`nExample 8 - assigning an array to a scalar - this will fail..."
testparse -foo: 2 -zork -bar -buz 3.14 -baz: "Hello world,a,b"