diff --git a/documentation/development-docs/azure-powershell-developer-guide.md b/documentation/development-docs/azure-powershell-developer-guide.md index 87bda47c3f84..f1e290384da2 100644 --- a/documentation/development-docs/azure-powershell-developer-guide.md +++ b/documentation/development-docs/azure-powershell-developer-guide.md @@ -40,7 +40,7 @@ The Azure PowerShell Developer Guide was created to help with the development an - [After Development](#after-development) - [Misc](#misc) - [Publish to PowerShell Gallery](#publish-to-powershell-gallery) - - [AsJob Parameters](#asjob-parameters) + - [AsJob Parameter](#asjob-parameter) - [Argument Completers](#argument-completers) - [Resource Group Completer](#resource-group-completers) - [Location Completer](#location-completer) @@ -52,8 +52,6 @@ The following prerequisites should be completed before contributing to the Azure - Install [Visual Studio 2015](https://www.visualstudio.com/downloads/) - Install the latest version of [Git](https://git-scm.com/downloads) -- Install the latest version of [WiX](http://wixtoolset.org/releases/) - - After installation, ensure that the path to "WiX Toolset\bin" has been added to your `PATH` environment variable - Install the [`platyPS` module](https://github.com/Azure/azure-powershell/blob/preview/documentation/development-docs/help-generation.md#installing-platyps) - Set the PowerShell [execution policy](https://technet.microsoft.com/en-us/library/ee176961.aspx) to **Unrestricted** for the following versions of PowerShell: - `C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe` @@ -116,8 +114,6 @@ By default, we build the `dll-Help.xml` files (used to display the help content msbuild build.proj /p:SkipHelp=true ``` -_Note_: when [updating the installer](#updating-the-installer), you **should not** skip the help generation step, as it removes the `dll-Help.xml` files from the wxi file. - ## Running Tests With the same terminal open from the previous section, run the cmdlet `Invoke-CheckinTests` to run all of the tests in the project @@ -142,10 +138,9 @@ Before development, you must meet with the Azure PowerShell team to have a desig Before submitting a design review, please be sure that you have read the [Azure PowerShell Design Guidelines](./azure-powershell-design-guidelines.md) document. -Please email the **azdevxpsdr** alias to set up this review and include the following information: -- Short description of the top-level scenarios -- Proposed cmdlet syntax -- Sample output of cmdlets +Please submit a design review here: https://github.com/Azure/azure-powershell-cmdlet-review-pr + +_Note_: You will need to be part of the GitHub Azure org to see this repository. Please go to [this link](aka.ms/azuregithub) to become part of the Azure org. We recommend using the `platyPS` module to easily generate markdown files that contains the above information and including the files in the email. diff --git a/documentation/development-docs/piping-in-powershell.md b/documentation/development-docs/piping-in-powershell.md index 49c2b7004d73..d16dc71d3da7 100644 --- a/documentation/development-docs/piping-in-powershell.md +++ b/documentation/development-docs/piping-in-powershell.md @@ -1,4 +1,141 @@ -# Piping in PowerShell +# Azure PowerShell Piping Scenarios + +There are two main scenarios that we wish to enable in cmdlets for Azure PowerShell: +- piping by value using an `InputObject` parameter +- piping by property name using a `ResourceId` parameter + +## Using the `InputObject` parameter + +### Short explanation +For all resources, `InputObject` should be implemented for the Remove/Set/Update cmdlets (and any other cmdlet where an existing resource is being operated on). The implementation of this will be a new parameter set: + +```powershell +Remove/Set/Update-AzureRm -InputObject +``` + +For all child resources, `InputObject` should also be implemented for the Get/New cmdlets. The implementation of this will be a new parameter set: + +```powershell +Get/New-AzureRm -ParentObject +``` + +### Long explanation +This scenario should be used when piping objects around within the same module. For example, if you have a set of `Get-AzureRmFoo`, `Remove-AzureRmFoo`, and `Set-AzureRmFoo` cmdlets, the `Remove-AzureRmFoo` and `Set-AzureRmFoo` cmdlets should have a parameter set that takes the `InputObject` parameter of type `PSFoo` so that a user can do the following: + +```powershell +# --- Piping scenario --- +# Setting and removing an individual object +Get-AzureRmFoo -Name "FooName" -ResourceGroupName "RG" | Set-AzureRmFoo +Get-AzureRmFoo -Name "FooName" -ResourceGroupName "RG" | Remove-AzureRmFoo + +# Setting and removing a collection of objects +Get-AzureRmFoo | Set-AzureRmFoo +Get-AzureRmFoo | Remove-AzureRmFoo + + +# --- Non-piping scenario --- +# Setting and removing an individual object +$foo = Get-AzureRmFoo -Name "FooName" -ResourceGroupName "RG" +Set-AzureRmFoo -InputObject $foo +Remove-AzureRmFoo -InputObject $foo + +# Setting and removing a collection of objects +Get-AzureRmFoo | ForEach-Object { Set-AzureRmFoo -InputObject $_ } +Get-AzureRmFoo | ForEach-Object { Remove-AzureRmFoo -InputObject $_ } +``` + +Another time that this scenario applies is when you have cmdlets for child resources that need information about the parent (top-level) resource. For example you can pipe in the whole parent object to the `New-AzureRmFooBar` and `Get-AzureRmFooBar` cmdlets to get the child resources, and then pipe the child resource object to the `Remove-AzureRmFooBar` and `Set-AzureRmFooBar` cmdlets. + +```powershell +# --- Piping scenario --- +# Getting all of child resources from all of the parent resources and removing them +Get-AzureRmFoo | Get-AzureRmFooBar | Remove-AzureRmFooBar + +# Getting all of the child resources from all of the parent resources in a resource group and removing them +Get-AzureRmFoo -ResourceGroupName "RG" | Get-AzureRmFooBar | Remove-AzureRmFooBar + +# Getting all of the child resources from a specific parent resource and removing them +Get-AzureRmFoo -ResourceGroupName "RG" -Name "FooName" | Get-AzureRmFooBar | Remove-AzureRmFooBar + + +# --- Non-piping scenario --- +# Getting all of the child resources from a specific parent resource and removing them +$foo = Get-AzureRmFoo -ResourceGroupName "RG" -Name "FooName" +$fooBar = Get-AzureRmFooBar -InputObject $foo +Remove-AzureRmFooBar -InputObject $fooBar +``` + +## Using the `ResourceId` parameter + +### Short explanation +For all resources, `ResourceId` should be implemented for the Remove/Set/Update cmdlets (and any other cmdlet where an existing resource is being operated on). The implementation of this will be a new parameter set: + +```powershell +Remove/Set/Update-AzureRm -ResourceId +``` + +For all child resources, `ResourceId` should also be implemented for the Get/New cmdlets. The implementation of this will be a new parameter set: + +```powershell +Get/New-AzureRm -ParentResourceId +``` + +### Long explanation + +In this scenario, we are using the generic cmdlets found in the `AzureRM.Resources` module. These cmdlets, `Find-AzureRmResource` and `Get-AzureRmResource`, return a `PSCustomObject` that has a `ResourceId` property, which is the unique identifier for the given resource. Since this identifier can parsed to get the name and resource group name for a top-level resource, we can create a parameter set that has a `ResourceId` parameter that accepts its value from the pipeline by property name, allowing us to accept piping from these generic cmdlets. + +```powershell +# --- Piping scenario --- +# Remove all Foo objects in the current subscription +Find-AzureRmResource -ResourceType Microsoft.Foo/foo | Remove-AzureRmFoo + +# Remove all Foo objects in a given resource group +Find-AzureRmResource -ResourceType Microsoft.Foo/foo -ResourceGroupEquals "RG" | Remove-AzureRmFoo + +# Remove a specific Foo object +Find-AzureRmResource -ResourceGroupEquals "RG" -ResourceNameEquals "FooName" | Remove-AzureRmFoo + + +# -- Non-piping scenario --- +# Removing all Foo objects in the current subscription +Find-AzureRmResource -ResourceType Microsoft.Foo/foo | ForEach-Object { Remove-AzureRmFoo -ResourceId $_.ResourceId } + +# Remove all Foo objects in a given resource group +Find-AzureRmResource -ResourceType Microsoft.Foo/foo -ResourceGroupEquals "RG" | ForEach-Object { Remove-AzureRmFoo -ResourceId $_.ResourceId } + +# Remove a specific Foo object +Find-AzureRmResource -ResourceGroupEquals "RG" -ResourceNameEquals "FooName" | ForEach-Object { Remove-AzureRmFoo -ResourceId $_.ResourceId } +``` + +To implement this scenario, please see the [`ResourceIdentifier`](https://github.com/Azure/azure-powershell/blob/preview/src/ResourceManager/Common/Commands.ResourceManager.Common/Utilities/Models/ResourceIdentifier.cs) class in the `Commands.ResourceManager.Common` project. This class will allow you to create a `ResourceIdentifier` object that accepts a `ResourceId` string in its constructor and has properties `ResourceName`, `ResourceGroupName`, and others. + +## Summary +For all Remove/Set/Update cmdlets (and any other cmdlet where an existing resource is being operated on), you will have three parameter sets (and potentially a multiple of three if you have initially have multiple parameter sets): +```powershell +Remove/Set/Update-AzureRm +Remove/Set/Update-AzureRm -InputObject +Remove/Set/Update-AzureRm -ResourceId +``` +For example, for child resource "Widget" with parent "Foo", there will be these three parameter sets for Remove: +```powershell +Remove-AzureRmWidget -ResourceGroupName -FooName -Name +Remove-AzureRmWidget -InputObject +Remove-AzureRmWidget -ResourceId +``` +For all child resources, Get/New cmdlets will also have these three parameter sets: +```powershell +Get/New-AzureRm +Get-AzureRm -InputObject +Get/New-AzureRm -ResourceId +``` +For example, for child resource "Widget" with parent "Foo", there will be these three parameter sets for New: +```powershell +New-AzureRmWidget -ResourceGroupName -FooName -Name +New-AzureRmWidget -WidgetObject -Name +New-AzureRmWidget -WidgetResourceId -Name +``` + +# Piping in PowerShell (additional information) ## Understanding Piping @@ -107,88 +244,6 @@ public override void ExecuteCmdlet() } ``` -## Azure PowerShell Piping Scenarios - -There are two main scenarios that we wish to enable in cmdlets for Azure PowerShell: -- piping by value using an `InputObject` parameter -- piping by property name using a `ResourceId` parameter - -### Using the `InputObject` parameter - -This scenario should be used when piping objects around within the same module. For example, if you have a set of `Get-AzureRmFoo`, `Remove-AzureRmFoo`, and `Set-AzureRmFoo` cmdlets, the `Remove-AzureRmFoo` and `Set-AzureRmFoo` cmdlets should have a parameter set that takes the `InputObject` parameter of type `PSFoo` so that a user can do the following: - -```powershell -# --- Piping scenario --- -# Setting and removing an individual object -Get-AzureRmFoo -Name "FooName" -ResourceGroupName "RG" | Set-AzureRmFoo -Get-AzureRmFoo -Name "FooName" -ResourceGroupName "RG" | Remove-AzureRmFoo - -# Setting and removing a collection of objects -Get-AzureRmFoo | Set-AzureRmFoo -Get-AzureRmFoo | Remove-AzureRmFoo - - -# --- Non-piping scenario --- -# Setting and removing an individual object -$foo = Get-AzureRmFoo -Name "FooName" -ResourceGroupName "RG" -Set-AzureRmFoo -InputObject $foo -Remove-AzureRmFoo -InputObject $foo - -# Setting and removing a collection of objects -Get-AzureRmFoo | ForEach-Object { Set-AzureRmFoo -InputObject $_ } -Get-AzureRmFoo | ForEach-Object { Remove-AzureRmFoo -InputObject $_ } -``` - -Another time that this scenario applies is when you have cmdlets for child resources that need information about the parent (top-level) resource. For example you can pipe in the whole parent object to the `New-AzureRmFooBar` and `Get-AzureRmFooBar` cmdlets to get the child resources, and then pipe the child resource object to the `Remove-AzureRmFooBar` and `Set-AzureRmFooBar` cmdlets. - -```powershell -# --- Piping scenario --- -# Getting all of child resources from all of the parent resources and removing them -Get-AzureRmFoo | Get-AzureRmFooBar | Remove-AzureRmFooBar - -# Getting all of the child resources from all of the parent resources in a resource group and removing them -Get-AzureRmFoo -ResourceGroupName "RG" | Get-AzureRmFooBar | Remove-AzureRmFooBar - -# Getting all of the child resources from a specific parent resource and removing them -Get-AzureRmFoo -ResourceGroupName "RG" -Name "FooName" | Get-AzureRmFooBar | Remove-AzureRmFooBar - - -# --- Non-piping scenario --- -# Getting all of the child resources from a specific parent resource and removing them -$foo = Get-AzureRmFoo -ResourceGroupName "RG" -Name "FooName" -$fooBar = Get-AzureRmFooBar -InputObject $foo -Remove-AzureRmFooBar -InputObject $fooBar -``` - -### Using the `ResourceId` parameter - -In this scenario, we are using the generic cmdlets found in the `AzureRM.Resources` module. These cmdlets, `Find-AzureRmResource` and `Get-AzureRmResource`, return a `PSCustomObject` that has a `ResourceId` property, which is the unique identifier for the given resource. Since this identifier can parsed to get the name and resource group name for a top-level resource, we can create a parameter set that has a `ResourceId` parameter that accepts its value from the pipeline by property name, allowing us to accept piping from these generic cmdlets. - -```powershell -# --- Piping scenario --- -# Remove all Foo objects in the current subscription -Find-AzureRmResource -ResourceType Microsoft.Foo/foo | Remove-AzureRmFoo - -# Remove all Foo objects in a given resource group -Find-AzureRmResource -ResourceType Microsoft.Foo/foo -ResourceGroupEquals "RG" | Remove-AzureRmFoo - -# Remove a specific Foo object -Find-AzureRmResource -ResourceGroupEquals "RG" -ResourceNameEquals "FooName" | Remove-AzureRmFoo - - -# -- Non-piping scenario --- -# Removing all Foo objects in the current subscription -Find-AzureRmResource -ResourceType Microsoft.Foo/foo | ForEach-Object { Remove-AzureRmFoo -ResourceId $_.ResourceId } - -# Remove all Foo objects in a given resource group -Find-AzureRmResource -ResourceType Microsoft.Foo/foo -ResourceGroupEquals "RG" | ForEach-Object { Remove-AzureRmFoo -ResourceId $_.ResourceId } - -# Remove a specific Foo object -Find-AzureRmResource -ResourceGroupEquals "RG" -ResourceNameEquals "FooName" | ForEach-Object { Remove-AzureRmFoo -ResourceId $_.ResourceId } -``` - -To implement this scenario, please see the [`ResourceIdentifier`](https://github.com/Azure/azure-powershell/blob/preview/src/ResourceManager/Common/Commands.ResourceManager.Common/Utilities/Models/ResourceIdentifier.cs) class in the `Commands.ResourceManager.Common` project. This class will allow you to create a `ResourceIdentifier` object that accepts a `ResourceId` string in its constructor and has properties `ResourceName`, `ResourceGroupName`, and others. - ## More Information -For more information on piping, see the article ["Understanding the Windows PowerShell Pipeline"](https://msdn.microsoft.com/en-us/powershell/scripting/getting-started/fundamental/understanding-the-windows-powershell-pipeline). \ No newline at end of file +For more information on piping, see the article ["Understanding the Windows PowerShell Pipeline"](https://msdn.microsoft.com/en-us/powershell/scripting/getting-started/fundamental/understanding-the-windows-powershell-pipeline).