Skip to content

Commit 2426c52

Browse files
committed
Merge pull request Azure#1983 from vivsriaus/CaptureRG
Add Export-AzureRmResourceGroup cmdlet
2 parents 0815c28 + e044f73 commit 2426c52

23 files changed

+1584
-27
lines changed

setup/azurecmdfiles.wxi

Lines changed: 80 additions & 0 deletions
Large diffs are not rendered by default.

src/ResourceManager/Resources/Commands.ResourceManager/Cmdlets/Commands.Resources.Rest.csproj

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@
116116
<Compile Include="Entities\Policy\PolicyRule.cs" />
117117
<Compile Include="Entities\Providers\ResourceProviderDefinition.cs" />
118118
<Compile Include="Entities\Providers\ResourceTypeDefinition.cs" />
119+
<Compile Include="Entities\ResourceGroup\ExportTemplateParameters.cs" />
119120
<Compile Include="Entities\ResourceGroup\ResourceBatchMoveParameters.cs" />
120121
<Compile Include="Entities\Resources\Resource.cs" />
121122
<Compile Include="Entities\Resources\ResourcePlan.cs" />
@@ -136,6 +137,7 @@
136137
<Compile Include="Handlers\CmdletInfoHandler.cs" />
137138
<Compile Include="Handlers\UserAgentHandler.cs" />
138139
<Compile Include="Implementation\FindAzureResourceGroupCmdlet.cs" />
140+
<Compile Include="Implementation\ExportAzureResourceGroupCmdlet.cs" />
139141
<Compile Include="Implementation\SaveAzureResourceGroupDeploymentTemplateCmdlet.cs" />
140142
<Compile Include="Implementation\GetAzureResourceGroupDeploymentOperationCmdlet.cs" />
141143
<Compile Include="Implementation\Lock\GetAzureResourceLockCmdlet.cs" />
@@ -191,6 +193,14 @@
191193
<Link>AzureRM.Resources.psd1</Link>
192194
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
193195
</None>
196+
<Content Include="Microsoft.Azure.Commands.ResourceManager.Cmdlets.format.ps1xml">
197+
<SubType>Designer</SubType>
198+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
199+
</Content>
200+
<Content Include="Microsoft.Azure.Commands.ResourceManager.Cmdlets.Types.ps1xml">
201+
<SubType>Designer</SubType>
202+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
203+
</Content>
194204
<None Include="MSSharedLibKey.snk" />
195205
<None Include="packages.config">
196206
<SubType>Designer</SubType>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// ----------------------------------------------------------------------------------
2+
//
3+
// Copyright Microsoft Corporation
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
// ----------------------------------------------------------------------------------
14+
15+
namespace Microsoft.Azure.Commands.ResourceManager.Cmdlets.Entities.ResourceGroups
16+
{
17+
using Newtonsoft.Json;
18+
19+
/// <summary>
20+
/// The export template request definition object.
21+
/// </summary>
22+
public class ExportTemplateParameters
23+
{
24+
/// <summary>
25+
/// Gets or sets the target resource group.
26+
/// </summary>
27+
[JsonProperty(Required = Required.Default)]
28+
public string Options { get; set; }
29+
30+
/// <summary>
31+
/// Gets or sets the list of resources in the resource group.
32+
/// </summary>
33+
[JsonProperty(Required = Required.Always)]
34+
public string[] Resources { get; set; }
35+
}
36+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
// ----------------------------------------------------------------------------------
2+
//
3+
// Copyright Microsoft Corporation
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
// ----------------------------------------------------------------------------------
14+
15+
namespace Microsoft.Azure.Commands.ResourceManager.Cmdlets.Implementation
16+
{
17+
using System.Management.Automation;
18+
using Microsoft.Azure.Commands.ResourceManager.Cmdlets.Components;
19+
using Microsoft.Azure.Commands.ResourceManager.Cmdlets.Entities.ErrorResponses;
20+
using Microsoft.Azure.Commands.ResourceManager.Cmdlets.Entities.ResourceGroups;
21+
using Microsoft.Azure.Commands.ResourceManager.Cmdlets.Extensions;
22+
using Microsoft.Azure.Commands.ResourceManager.Cmdlets.Utilities;
23+
using Microsoft.WindowsAzure.Commands.Utilities.Common;
24+
using Newtonsoft.Json.Linq;
25+
26+
/// <summary>
27+
/// Captures the specifies resource group as a template and saves it to a file on disk.
28+
/// </summary>
29+
[Cmdlet(VerbsData.Export, "AzureRmResourceGroup"), OutputType(typeof(PSObject))]
30+
public class ExportAzureResourceGroupCmdlet : ResourceManagerCmdletBase
31+
{
32+
/// <summary>
33+
/// Gets or sets the resource group name parameter.
34+
/// </summary>
35+
[Alias("ResourceGroup")]
36+
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The resource group name.")]
37+
[ValidateNotNullOrEmpty]
38+
public string ResourceGroupName { get; set; }
39+
40+
/// <summary>
41+
/// Gets or sets the file path.
42+
/// </summary>
43+
[Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true, HelpMessage = "The output path of the template file.")]
44+
[ValidateNotNullOrEmpty]
45+
public string Path { get; set; }
46+
47+
/// <summary>
48+
/// Export template parameter with default value.
49+
/// </summary>
50+
[Parameter(Mandatory = false, HelpMessage = "Export template parameter with default value.")]
51+
public SwitchParameter IncludeParameterDefaultValue { get; set; }
52+
53+
/// <summary>
54+
/// Export template with comments.
55+
/// </summary>
56+
[Parameter(Mandatory = false, HelpMessage = "Export template with comments.")]
57+
public SwitchParameter IncludeComments { get; set; }
58+
59+
/// <summary>
60+
/// Gets or sets the force parameter.
61+
/// </summary>
62+
[Parameter(Mandatory = false, HelpMessage = "Do not ask for confirmation.")]
63+
public SwitchParameter Force { get; set; }
64+
65+
/// <summary>
66+
/// Executes the cmdlet.
67+
/// </summary>
68+
protected override void OnProcessRecord()
69+
{
70+
base.OnProcessRecord();
71+
72+
var resourceId = this.GetResourceId();
73+
74+
var apiVersion = this.DetermineApiVersion(resourceId: resourceId).Result;
75+
76+
var parameters = new ExportTemplateParameters
77+
{
78+
Resources = new string [] {"*"},
79+
Options = this.GetExportOptions() ?? null
80+
};
81+
82+
var operationResult = this.GetResourcesClient()
83+
.InvokeActionOnResource<JObject>(
84+
resourceId: resourceId,
85+
action: Constants.ExportTemplate,
86+
parameters: parameters.ToJToken(),
87+
apiVersion: apiVersion,
88+
cancellationToken: this.CancellationToken.Value)
89+
.Result;
90+
91+
var managementUri = this.GetResourcesClient()
92+
.GetResourceManagementRequestUri(
93+
resourceId: resourceId,
94+
apiVersion: apiVersion,
95+
action: Constants.ExportTemplate);
96+
97+
var activity = string.Format("POST {0}", managementUri.PathAndQuery);
98+
var resultString = this.GetLongRunningOperationTracker(activityName: activity, isResourceCreateOrUpdate: false)
99+
.WaitOnOperation(operationResult: operationResult);
100+
101+
var template = JToken.FromObject(JObject.Parse(resultString)["template"]);
102+
103+
if(JObject.Parse(resultString)["error"] != null)
104+
{
105+
ExtendedErrorInfo error;
106+
if(JObject.Parse(resultString)["error"].TryConvertTo(out error))
107+
{
108+
WriteWarning(string.Format("{0} : {1}", error.Code, error.Message));
109+
foreach(var detail in error.Details)
110+
{
111+
WriteWarning(string.Format("{0} : {1}", detail.Code, detail.Message));
112+
}
113+
}
114+
}
115+
116+
string path = FileUtility.SaveTemplateFile(
117+
templateName: this.ResourceGroupName,
118+
contents: template.ToString(),
119+
outputPath: string.IsNullOrEmpty(this.Path) ? System.IO.Path.Combine(CurrentPath(), this.ResourceGroupName) : this.TryResolvePath(this.Path),
120+
overwrite: this.Force,
121+
confirmAction: ConfirmAction);
122+
123+
WriteObject(PowerShellUtilities.ConstructPSObject(null, "Path", path));
124+
}
125+
126+
/// <summary>
127+
/// Gets the export template options
128+
/// </summary>
129+
private string GetExportOptions()
130+
{
131+
string options = string.Empty;
132+
if(this.IncludeComments.IsPresent)
133+
{
134+
options += "IncludeComments";
135+
}
136+
if(this.IncludeParameterDefaultValue.IsPresent)
137+
{
138+
options = string.IsNullOrEmpty(options) ? "IncludeParameterDefaultValue" : options + ",IncludeParameterDefaultValue";
139+
}
140+
return string.IsNullOrEmpty(options) ? null : options;
141+
}
142+
143+
/// <summary>
144+
/// Gets the resource Id from the supplied PowerShell parameters.
145+
/// </summary>
146+
protected string GetResourceId()
147+
{
148+
return ResourceIdUtility.GetResourceId(
149+
subscriptionId: DefaultContext.Subscription.Id,
150+
resourceGroupName: this.ResourceGroupName,
151+
resourceType: null,
152+
resourceName: null);
153+
}
154+
}
155+
}

src/ResourceManager/Resources/Commands.ResourceManager/Cmdlets/Implementation/GetAzureResourceGroupDeploymentOperationCmdlet.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ private void RunCmdlet()
7979
getFirstPage: () => this.GetResources(),
8080
getNextPage: nextLink => this.GetNextLink<JObject>(nextLink),
8181
cancellationToken: this.CancellationToken,
82-
action: resources => this.WriteObject(sendToPipeline: resources.CoalesceEnumerable().SelectArray(resource => resource.ToPsObject()), enumerateCollection: true));
82+
action: resources => this.WriteObject(sendToPipeline: resources.CoalesceEnumerable().SelectArray(resource => resource.ToPsObject("System.Management.Automation.PSCustomObject#DeploymentOperation")), enumerateCollection: true));
8383
}
8484

8585
/// <summary>

src/ResourceManager/Resources/Commands.ResourceManager/Cmdlets/Implementation/Policy/GetAzurePolicyAssignment.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,13 +100,15 @@ private async Task<ResponseWithContinuation<JObject[]>> GetResources()
100100
{
101101
string resourceId = this.Id ?? this.GetResourceId();
102102

103+
var apiVersion = string.IsNullOrWhiteSpace(this.ApiVersion) ? Constants.PolicyApiVersion : this.ApiVersion;
104+
103105
if (IsResourceGet(resourceId))
104106
{
105107
var resource = await this
106108
.GetResourcesClient()
107109
.GetResource<JObject>(
108110
resourceId: resourceId,
109-
apiVersion: Constants.PolicyApiVersion,
111+
apiVersion: apiVersion,
110112
cancellationToken: this.CancellationToken.Value,
111113
odataQuery: null)
112114
.ConfigureAwait(continueOnCapturedContext: false);
@@ -122,7 +124,7 @@ private async Task<ResponseWithContinuation<JObject[]>> GetResources()
122124
.GetResourcesClient()
123125
.ListObjectColleciton<JObject>(
124126
resourceCollectionId: resourceId,
125-
apiVersion: Constants.PolicyApiVersion,
127+
apiVersion: apiVersion,
126128
cancellationToken: this.CancellationToken.Value,
127129
odataQuery: filter)
128130
.ConfigureAwait(continueOnCapturedContext: false);
@@ -137,7 +139,7 @@ private async Task<ResponseWithContinuation<JObject[]>> GetResources()
137139
.GetResourcesClient()
138140
.ListObjectColleciton<JObject>(
139141
resourceCollectionId: resourceId,
140-
apiVersion: Constants.PolicyApiVersion,
142+
apiVersion: apiVersion,
141143
cancellationToken: this.CancellationToken.Value,
142144
odataQuery: filter)
143145
.ConfigureAwait(continueOnCapturedContext: false);

src/ResourceManager/Resources/Commands.ResourceManager/Cmdlets/Implementation/Policy/GetAzurePolicyDefinition.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,13 +85,15 @@ private async Task<ResponseWithContinuation<JObject[]>> GetResources()
8585
{
8686
string resourceId = this.Id ?? this.GetResourceId();
8787

88+
var apiVersion = string.IsNullOrWhiteSpace(this.ApiVersion) ? Constants.PolicyApiVersion : this.ApiVersion;
89+
8890
if (!string.IsNullOrEmpty(ResourceIdUtility.GetResourceName(resourceId)))
8991
{
9092
var resource = await this
9193
.GetResourcesClient()
9294
.GetResource<JObject>(
9395
resourceId: resourceId,
94-
apiVersion: Constants.PolicyApiVersion,
96+
apiVersion: apiVersion,
9597
cancellationToken: this.CancellationToken.Value)
9698
.ConfigureAwait(continueOnCapturedContext: false);
9799
ResponseWithContinuation<JObject[]> retVal;
@@ -105,7 +107,7 @@ private async Task<ResponseWithContinuation<JObject[]>> GetResources()
105107
.GetResourcesClient()
106108
.ListObjectColleciton<JObject>(
107109
resourceCollectionId: resourceId,
108-
apiVersion: Constants.PolicyApiVersion,
110+
apiVersion: apiVersion,
109111
cancellationToken: this.CancellationToken.Value)
110112
.ConfigureAwait(continueOnCapturedContext: false);
111113
}

src/ResourceManager/Resources/Commands.ResourceManager/Cmdlets/Implementation/Policy/NewAzurePolicyAssignment.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,13 @@ protected override void OnProcessRecord()
6868
throw new PSInvalidOperationException("The supplied PolicyDefinition object is invalid.");
6969
}
7070
string resourceId = GetResourceId();
71+
72+
var apiVersion = string.IsNullOrWhiteSpace(this.ApiVersion) ? Constants.PolicyApiVersion : this.ApiVersion;
7173

7274
var operationResult = this.GetResourcesClient()
7375
.PutResource(
7476
resourceId: resourceId,
75-
apiVersion: Constants.PolicyApiVersion,
77+
apiVersion: apiVersion,
7678
resource: this.GetResource(),
7779
cancellationToken: this.CancellationToken.Value,
7880
odataQuery: null)
@@ -81,7 +83,7 @@ protected override void OnProcessRecord()
8183
var managementUri = this.GetResourcesClient()
8284
.GetResourceManagementRequestUri(
8385
resourceId: resourceId,
84-
apiVersion: Constants.PolicyApiVersion,
86+
apiVersion: apiVersion,
8587
odataQuery: null);
8688

8789
var activity = string.Format("PUT {0}", managementUri.PathAndQuery);

src/ResourceManager/Resources/Commands.ResourceManager/Cmdlets/Implementation/Policy/NewAzurePolicyDefinition.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,13 @@ protected override void OnProcessRecord()
6666
{
6767
base.OnProcessRecord();
6868
string resourceId = GetResourceId();
69-
69+
70+
var apiVersion = string.IsNullOrWhiteSpace(this.ApiVersion) ? Constants.PolicyApiVersion : this.ApiVersion;
71+
7072
var operationResult = this.GetResourcesClient()
7173
.PutResource(
7274
resourceId: resourceId,
73-
apiVersion: Constants.PolicyApiVersion,
75+
apiVersion: apiVersion,
7476
resource: this.GetResource(),
7577
cancellationToken: this.CancellationToken.Value,
7678
odataQuery: null)
@@ -79,7 +81,7 @@ protected override void OnProcessRecord()
7981
var managementUri = this.GetResourcesClient()
8082
.GetResourceManagementRequestUri(
8183
resourceId: resourceId,
82-
apiVersion: Constants.PolicyApiVersion,
84+
apiVersion: apiVersion,
8385
odataQuery: null);
8486

8587
var activity = string.Format("PUT {0}", managementUri.PathAndQuery);

src/ResourceManager/Resources/Commands.ResourceManager/Cmdlets/Implementation/Policy/RemoveAzurePolicyAssignment.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ private void RunCmdlet()
7878
{
7979
base.OnProcessRecord();
8080
string resourceId = this.Id ?? this.GetResourceId();
81+
var apiVersion = string.IsNullOrWhiteSpace(this.ApiVersion) ? Constants.PolicyApiVersion : this.ApiVersion;
82+
8183
this.ConfirmAction(
8284
this.Force,
8385
string.Format("Are you sure you want to delete the following policy assignment: {0}", resourceId),
@@ -88,15 +90,15 @@ private void RunCmdlet()
8890
var operationResult = this.GetResourcesClient()
8991
.DeleteResource(
9092
resourceId: resourceId,
91-
apiVersion: Constants.PolicyApiVersion,
93+
apiVersion: apiVersion,
9294
cancellationToken: this.CancellationToken.Value,
9395
odataQuery: null)
9496
.Result;
9597

9698
var managementUri = this.GetResourcesClient()
9799
.GetResourceManagementRequestUri(
98100
resourceId: resourceId,
99-
apiVersion: Constants.PolicyApiVersion,
101+
apiVersion: apiVersion,
100102
odataQuery: null);
101103

102104
var activity = string.Format("DELETE {0}", managementUri.PathAndQuery);

src/ResourceManager/Resources/Commands.ResourceManager/Cmdlets/Implementation/Policy/RemoveAzurePolicyDefinition.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ private void RunCmdlet()
7171
{
7272
base.OnProcessRecord();
7373
string resourceId = this.Id ?? this.GetResourceId();
74+
var apiVersion = string.IsNullOrWhiteSpace(this.ApiVersion) ? Constants.PolicyApiVersion : this.ApiVersion;
75+
7476
this.ConfirmAction(
7577
this.Force,
7678
string.Format("Are you sure you want to delete the following policy definition: {0}", resourceId),
@@ -81,15 +83,15 @@ private void RunCmdlet()
8183
var operationResult = this.GetResourcesClient()
8284
.DeleteResource(
8385
resourceId: resourceId,
84-
apiVersion: Constants.PolicyApiVersion,
86+
apiVersion: apiVersion,
8587
cancellationToken: this.CancellationToken.Value,
8688
odataQuery: null)
8789
.Result;
8890

8991
var managementUri = this.GetResourcesClient()
9092
.GetResourceManagementRequestUri(
9193
resourceId: resourceId,
92-
apiVersion: Constants.PolicyApiVersion,
94+
apiVersion: apiVersion,
9395
odataQuery: null);
9496

9597
var activity = string.Format("DELETE {0}", managementUri.PathAndQuery);

0 commit comments

Comments
 (0)