Skip to content

Commit

Permalink
Merge pull request #6427 from Azure/maddieclayton-patch-2
Browse files Browse the repository at this point in the history
Move wiki changes to docs
  • Loading branch information
Maddie Clayton authored Jun 8, 2018
2 parents dc4027b + 8ca6a0a commit 900d8de
Show file tree
Hide file tree
Showing 2 changed files with 143 additions and 93 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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`
Expand Down Expand Up @@ -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
Expand All @@ -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.

Expand Down
223 changes: 139 additions & 84 deletions documentation/development-docs/piping-in-powershell.md
Original file line number Diff line number Diff line change
@@ -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<ExampleResource> -InputObject <TypeOfExampleResource> <Other parameters that cannot be obtained from TypeOfExampleResource>
```

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<ExampleResource> -ParentObject <TypeOfParentOfExampleResource> <Other parameters that cannot be obtained from TypeOfParentOfExampleResource>
```

### 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 <additional parameters>
Get-AzureRmFoo -Name "FooName" -ResourceGroupName "RG" | Remove-AzureRmFoo
# Setting and removing a collection of objects
Get-AzureRmFoo | Set-AzureRmFoo <additional parameters>
Get-AzureRmFoo | Remove-AzureRmFoo
# --- Non-piping scenario ---
# Setting and removing an individual object
$foo = Get-AzureRmFoo -Name "FooName" -ResourceGroupName "RG"
Set-AzureRmFoo -InputObject $foo <additional parameters>
Remove-AzureRmFoo -InputObject $foo
# Setting and removing a collection of objects
Get-AzureRmFoo | ForEach-Object { Set-AzureRmFoo -InputObject $_ <additional parameters> }
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<ExampleResource> -ResourceId <string (accepts ExampleResource ResourceId> <Other parameters that cannot be obtained from ExampleResource 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<ExampleResource> -ParentResourceId <string (accepts ResourceId of the parent of ExampleResource> <Other parameters that cannot be obtained from the ResourceId of the parent of ExampleResource>
```

### 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<ExampleResource> <parameters that are required to identify ExampleResource> <Other parameters>
Remove/Set/Update-AzureRm<ExampleResource> -InputObject <TypeOfExampleResource> <Other parameters that cannot be obtained from TypeOfExampleResource>
Remove/Set/Update-AzureRm<ExampleResource> -ResourceId <string (accepts ExampleResource ResourceId> <Other parameters that cannot be obtained from ExampleResource ResourceId>
```
For example, for child resource "Widget" with parent "Foo", there will be these three parameter sets for Remove:
```powershell
Remove-AzureRmWidget -ResourceGroupName <string> -FooName <string> -Name <string>
Remove-AzureRmWidget -InputObject <Widget>
Remove-AzureRmWidget -ResourceId <string>
```
For all child resources, Get/New cmdlets will also have these three parameter sets:
```powershell
Get/New-AzureRm<ExampleResource> <parameters needed to identify/create ExampleResource>
Get-AzureRm<ExampleResource> -InputObject <TypeOfParentOfExampleResource> <Other parameters that cannot be obtained from TypeOfParentOfExampleResource>
Get/New-AzureRm<ExampleResource> -ResourceId <string (accepts ResourceId of the parent of ExampleResource> <Other parameters that cannot be obtained from the ResourceId of the parent of ExampleResource>
```
For example, for child resource "Widget" with parent "Foo", there will be these three parameter sets for New:
```powershell
New-AzureRmWidget -ResourceGroupName <string> -FooName <String> -Name <string>
New-AzureRmWidget -WidgetObject <Foo> -Name <string>
New-AzureRmWidget -WidgetResourceId <string> -Name <string>
```

# Piping in PowerShell (additional information)

## Understanding Piping

Expand Down Expand Up @@ -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 <additional parameters>
Get-AzureRmFoo -Name "FooName" -ResourceGroupName "RG" | Remove-AzureRmFoo
# Setting and removing a collection of objects
Get-AzureRmFoo | Set-AzureRmFoo <additional parameters>
Get-AzureRmFoo | Remove-AzureRmFoo
# --- Non-piping scenario ---
# Setting and removing an individual object
$foo = Get-AzureRmFoo -Name "FooName" -ResourceGroupName "RG"
Set-AzureRmFoo -InputObject $foo <additional parameters>
Remove-AzureRmFoo -InputObject $foo
# Setting and removing a collection of objects
Get-AzureRmFoo | ForEach-Object { Set-AzureRmFoo -InputObject $_ <additional parameters> }
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).
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).

0 comments on commit 900d8de

Please sign in to comment.