...
1#!/usr/bin/env pwsh
2
3# Copyright (c) Microsoft Corporation. All rights reserved.
4# Licensed under the MIT License.
5
6#Requires -Version 6.0
7#Requires -PSEdition Core
8#Requires -Modules @{ModuleName='Az.Accounts'; ModuleVersion='1.6.4'}
9#Requires -Modules @{ModuleName='Az.Resources'; ModuleVersion='1.8.0'}
10
11[CmdletBinding(DefaultParameterSetName = 'Default')]
12param (
13 [Parameter(ParameterSetName = 'Default', Position = 0)]
14 [string] $ServiceDirectory,
15
16 [Parameter(ParameterSetName = 'Default')]
17 [ValidatePattern('^[-a-zA-Z0-9\.\(\)_]{0,80}(?<=[a-zA-Z0-9\(\)])$')]
18 [string] $BaseName,
19
20 [Parameter(ParameterSetName = 'ResourceGroup')]
21 [ValidatePattern('^[-\w\._\(\)]+$')]
22 [string] $ResourceGroupName,
23
24 [Parameter()]
25 [ValidatePattern('^[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}$')]
26 [string] $SubscriptionId,
27
28 [Parameter()]
29 [ValidateRange(1, 7*24)]
30 [int] $DeleteAfterHours = 48
31)
32
33. $PSScriptRoot/SubConfig-Helpers.ps1
34
35# By default stop for any error.
36if (!$PSBoundParameters.ContainsKey('ErrorAction')) {
37 $ErrorActionPreference = 'Stop'
38}
39
40function Log($Message) {
41 Write-Host ('{0} - {1}' -f [DateTime]::Now.ToLongTimeString(), $Message)
42}
43
44function Retry([scriptblock] $Action, [int] $Attempts = 5) {
45 $attempt = 0
46 $sleep = 5
47
48 while ($attempt -lt $Attempts) {
49 try {
50 $attempt++
51 return $Action.Invoke()
52 } catch {
53 if ($attempt -lt $Attempts) {
54 $sleep *= 2
55
56 Write-Warning "Attempt $attempt failed: $_. Trying again in $sleep seconds..."
57 Start-Sleep -Seconds $sleep
58 } else {
59 Write-Error -ErrorRecord $_
60 }
61 }
62 }
63}
64
65# Support actions to invoke on exit.
66$exitActions = @({
67 if ($exitActions.Count -gt 1) {
68 Write-Verbose 'Running registered exit actions'
69 }
70})
71
72# Make sure $ResourceGroupName is set.
73if (!$ResourceGroupName) {
74 # Make sure $BaseName is set.
75 if (!$BaseName) {
76 $UserName = GetUserName
77 $BaseName = GetBaseName $UserName $ServiceDirectory
78 Log "BaseName was not set. Using default base name '$BaseName'"
79 }
80
81 $ResourceGroupName = "rg-$BaseName"
82}
83
84# This script is intended for interactive users. Make sure they are logged in or fail.
85$context = Get-AzContext
86if (!$context) {
87 throw "You must be already logged in to use this script. Run 'Connect-AzAccount' and try again."
88}
89
90# If no subscription was specified, try to select the Azure SDK Developer Playground subscription.
91# Ignore errors to leave the automatically selected subscription.
92if ($SubscriptionId) {
93 $currentSubcriptionId = $context.Subscription.Id
94 if ($currentSubcriptionId -ne $SubscriptionId) {
95 Log "Selecting subscription '$SubscriptionId'"
96 $null = Select-AzSubscription -Subscription $SubscriptionId
97
98 $exitActions += {
99 Log "Selecting previous subscription '$currentSubcriptionId'"
100 $null = Select-AzSubscription -Subscription $currentSubcriptionId
101 }
102
103 # Update the context.
104 $context = Get-AzContext
105 }
106} else {
107 Log "Attempting to select subscription 'Azure SDK Developer Playground (faa080af-c1d8-40ad-9cce-e1a450ca5b57)'"
108 $null = Select-AzSubscription -Subscription 'faa080af-c1d8-40ad-9cce-e1a450ca5b57' -ErrorAction Ignore
109
110 # Update the context.
111 $context = Get-AzContext
112
113 $SubscriptionId = $context.Subscription.Id
114 $PSBoundParameters['SubscriptionId'] = $SubscriptionId
115}
116
117# Use cache of well-known team subs without having to be authenticated.
118$wellKnownSubscriptions = @{
119 'faa080af-c1d8-40ad-9cce-e1a450ca5b57' = 'Azure SDK Developer Playground'
120 'a18897a6-7e44-457d-9260-f2854c0aca42' = 'Azure SDK Engineering System'
121 '2cd617ea-1866-46b1-90e3-fffb087ebf9b' = 'Azure SDK Test Resources'
122}
123
124# Print which subscription is currently selected.
125$subscriptionName = $context.Subscription.Id
126if ($wellKnownSubscriptions.ContainsKey($subscriptionName)) {
127 $subscriptionName = '{0} ({1})' -f $wellKnownSubscriptions[$subscriptionName], $subscriptionName
128}
129
130Log "Selected subscription '$subscriptionName'"
131
132# try..finally will also trap Ctrl+C.
133try {
134 Log "Getting resource group '$ResourceGroupName'"
135
136 $resourceGroup = Get-AzResourceGroup -Name $ResourceGroupName
137
138 # Update DeleteAfter
139 $deleteAfter = [DateTime]::UtcNow.AddHours($DeleteAfterHours).ToString('o')
140
141 Log "Updating DeleteAfter to '$deleteAfter'"
142 Write-Warning "Any clean-up scripts running against subscription '$SubscriptionId' may delete resource group '$ResourceGroupName' after $DeleteAfterHours hours."
143 $resourceGroup.Tags['DeleteAfter'] = $deleteAfter
144
145 Log "Updating resource group '$ResourceGroupName'"
146 Retry {
147 # Allow the resource group to write to output.
148 Set-AzResourceGroup -Name $ResourceGroupName -Tag $resourceGroup.Tags
149 }
150} finally {
151 $exitActions.Invoke()
152}
153
154<#
155.SYNOPSIS
156Updates a resource group previously deployed for a service directory.
157
158.DESCRIPTION
159Updates a resource group that was created using New-TestResources.ps1.
160You can use this, for example, to update the `DeleteAfterHours` property
161to keep an existing resource group deployed for a longer period of time.
162
163.PARAMETER ServiceDirectory
164A directory under 'sdk' in the repository root - optionally with subdirectories
165specified - in which to discover ARM templates named 'test-resources.json'.
166This can also be an absolute path or specify parent directories.
167
168.PARAMETER BaseName
169A name to use in the resource group and passed to the ARM template as 'baseName'.
170This will update the resource group named 'rg-<baseName>'
171
172.PARAMETER ResourceGroupName
173The name of the resource group to update.
174
175.PARAMETER SubscriptionId
176Optional subscription ID to use when deleting resources when logging in as a
177provisioner. You can also use Set-AzContext if not provisioning.
178
179If you do not specify a SubscriptionId and are not logged in, one will be
180automatically selected for you by the Connect-AzAccount cmdlet.
181
182Once you are logged in (or were previously), the selected SubscriptionId
183will be used for subsequent operations that are specific to a subscription.
184
185.PARAMETER DeleteAfterHours
186Positive integer number of hours from the current time to set the
187'DeleteAfter' tag on the created resource group. The computed value is a
188timestamp of the form "2020-03-04T09:07:04.3083910Z".
189
190An optional cleanup process can delete resource groups whose "DeleteAfter"
191timestamp is less than the current time.
192
193.EXAMPLE
194Update-TestResources.ps1 keyvault -DeleteAfterHours 24
195
196Update the 'rg-${USERNAME}keyvault` resource group to be deleted after 24
197hours from now if a clean-up script is running against the current subscription.
198
199.EXAMPLE
200Update-TestResources.ps1 -ResourceGroupName rg-userkeyvault -Subscription fa9c6912-f641-4226-806c-5139584b89ca
201
202Update the 'rg-userkeyvault' resource group to be deleted after 48
203hours from now if a clean-up script is running against the subscription 'fa9c6912-f641-4226-806c-5139584b89ca'.
204
205#>
View as plain text