├── requirements.psd1
├── StartVMOnTimer
├── function.json
└── run.ps1
├── StopVMOnTimer
├── function.json
└── run.ps1
├── host.json
├── profile.ps1
├── LICENSE
├── README.md
└── azuredeploy.json
/requirements.psd1:
--------------------------------------------------------------------------------
1 | @{
2 | Az = '1.*'
3 | }
4 |
--------------------------------------------------------------------------------
/StartVMOnTimer/function.json:
--------------------------------------------------------------------------------
1 | {
2 | "disabled": false,
3 | "bindings": [
4 | {
5 | "name": "Timer",
6 | "type": "timerTrigger",
7 | "direction": "in",
8 | "schedule": "0 0 8 * * *"
9 | }
10 | ]
11 | }
--------------------------------------------------------------------------------
/StopVMOnTimer/function.json:
--------------------------------------------------------------------------------
1 | {
2 | "disabled": false,
3 | "bindings": [
4 | {
5 | "name": "Timer",
6 | "type": "timerTrigger",
7 | "direction": "in",
8 | "schedule": "0 0 20 * * *"
9 | }
10 | ]
11 | }
--------------------------------------------------------------------------------
/host.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0",
3 | "managedDependency": {
4 | "enabled": true
5 | },
6 | "logging": {
7 | "logLevel": {
8 | "default": "Trace"
9 | },
10 | "fileLoggingMode": "always"
11 | },
12 | "functionTimeout": "00:10:00"
13 | }
--------------------------------------------------------------------------------
/profile.ps1:
--------------------------------------------------------------------------------
1 | # Azure Functions profile.ps1
2 | #
3 | # This profile.ps1 will get executed every "cold start" of your Function App.
4 | # "cold start" occurs when:
5 | #
6 | # * A Function App starts up for the very first time
7 | # * A Function App starts up after being de-allocated due to inactivity
8 | #
9 | # You can define helper functions, run commands, or specify environment variables
10 | # NOTE: any variables defined that are not environment variables will get reset after the first execution
11 |
12 | # Authenticate with Azure PowerShell using MSI.
13 | # Remove this if you are not planning on using MSI or Azure PowerShell.
14 | if ($env:MSI_SECRET -and (Get-Module -ListAvailable Az.Accounts)) {
15 | Connect-AzAccount -Identity
16 | }
17 |
18 | # Uncomment the next line to enable legacy AzureRm alias in Azure PowerShell.
19 | # Enable-AzureRmAlias
20 |
21 | # You can also define functions or aliases that can be referenced in any of your PowerShell functions.
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Eamon O'Reilly
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/StopVMOnTimer/run.ps1:
--------------------------------------------------------------------------------
1 | # Input bindings are passed in via param block.
2 | param($Timer)
3 |
4 | # Specify the VMs that you want to stop. Modify or comment out below based on which VMs to check.
5 | $VMResourceGroupName = "Contoso"
6 | #$VMName = "ContosoVM1"
7 | #$TagName = "AutomaticallyStop"
8 |
9 | # Stop on error
10 | $ErrorActionPreference = 'stop'
11 |
12 | # Check if managed identity has been enabled and granted access to a subscription, resource group, or resource
13 | $AzContext = Get-AzContext -ErrorAction SilentlyContinue
14 | if (-not $AzContext.Subscription.Id)
15 | {
16 | Throw ("Managed identity is not enabled for this app or it has not been granted access to any Azure resources. Please see https://docs.microsoft.com/en-us/azure/app-service/overview-managed-identity for additional details.")
17 | }
18 |
19 | try
20 | {
21 | # Get a single vm, vms in a resource group, or all vms in the subscription
22 | if ($null -ne $VMResourceGroupName -and $null -ne $VMName)
23 | {
24 | Write-Information ("Getting VM in resource group " + $VMResourceGroupName + " and VMName " + $VMName)
25 | $VMs = Get-AzVM -ResourceGroupName $VMResourceGroupName -Name $VMName
26 | }
27 | elseif ($null -ne $VMResourceGroupName)
28 | {
29 | Write-Information("Getting all VMs in resource group " + $VMResourceGroupName)
30 | $VMs = Get-AzVM -ResourceGroupName $VMResourceGroupName
31 | }
32 | else
33 | {
34 | Write-Information ("Getting all VMs in the subscription")
35 | $VMs = Get-AzVM
36 | }
37 |
38 | # Check if VM has the specified tag on it and filter to those.
39 | If ($null -ne $TagName)
40 | {
41 | $VMs = $VMs | Where-Object {$_.Tags.Keys -eq $TagName}
42 | }
43 |
44 | # Stop the VM if it is running
45 | $ProcessedVMs = @()
46 |
47 | foreach ($VirtualMachine in $VMs)
48 | {
49 | $VM = Get-AzVM -ResourceGroupName $VirtualMachine.ResourceGroupName -Name $VirtualMachine.Name -Status
50 | if ($VM.Statuses.Code[1] -eq 'PowerState/running')
51 | {
52 | Write-Information ("Stopping VM " + $VirtualMachine.Id)
53 | $ProcessedVMs += $VirtualMachine.Id
54 | Stop-AzVM -Id $VirtualMachine.Id -Force -AsJob | Write-Information
55 | }
56 | }
57 | # Sleep here a few seconds to make sure that the command gets processed before the script ends
58 | if ($ProcessedVMs.Count -gt 0)
59 | {
60 | Start-Sleep 10
61 | }
62 | }
63 | catch
64 | {
65 | throw $_.Exception.Message
66 | }
67 |
--------------------------------------------------------------------------------
/StartVMOnTimer/run.ps1:
--------------------------------------------------------------------------------
1 | # Input bindings are passed in via param block.
2 | param($Timer)
3 |
4 | # Specify the VMs that you want to start. Modify or comment out below based on which VMs to check.
5 | $VMResourceGroupName = "Contoso"
6 | #$VMName = "ContosoVM1"
7 | #$TagName = "AutomaticallyStart"
8 |
9 | # Stop on error
10 | $ErrorActionPreference = 'stop'
11 |
12 | # Check if managed identity has been enabled and granted access to a subscription, resource group, or resource
13 | $AzContext = Get-AzContext -ErrorAction SilentlyContinue
14 | if (-not $AzContext.Subscription.Id)
15 | {
16 | Throw ("Managed identity is not enabled for this app or it has not been granted access to any Azure resources. Please see https://docs.microsoft.com/en-us/azure/app-service/overview-managed-identity for additional details.")
17 | }
18 |
19 | try
20 | {
21 | # Get a single vm, vms in a resource group, or all vms in the subscription
22 | if ($null -ne $VMResourceGroupName -and $null -ne $VMName)
23 | {
24 | Write-Information ("Getting VM in resource group " + $VMResourceGroupName + " and VMName " + $VMName)
25 | $VMs = Get-AzVM -ResourceGroupName $VMResourceGroupName -Name $VMName
26 | }
27 | elseif ($null -ne $VMResourceGroupName)
28 | {
29 | Write-Information("Getting all VMs in resource group " + $VMResourceGroupName)
30 | $VMs = Get-AzVM -ResourceGroupName $VMResourceGroupName
31 | }
32 | else
33 | {
34 | Write-Information ("Getting all VMs in the subscription")
35 | $VMs = Get-AzVM
36 | }
37 |
38 | # Check if VM has the specified tag on it and filter to those.
39 | If ($null -ne $TagName)
40 | {
41 | $VMs = $VMs | Where-Object {$_.Tags.Keys -eq $TagName}
42 | }
43 |
44 | # Start the VM if it is deallocated
45 | $ProcessedVMs = @()
46 |
47 | foreach ($VirtualMachine in $VMs)
48 | {
49 | $VM = Get-AzVM -ResourceGroupName $VirtualMachine.ResourceGroupName -Name $VirtualMachine.Name -Status
50 | if ($VM.Statuses.Code[1] -eq 'PowerState/deallocated')
51 | {
52 | Write-Information ("Starting VM " + $VirtualMachine.Id)
53 | $ProcessedVMs += $VirtualMachine.Id
54 | Start-AzVM -Id $VirtualMachine.Id -AsJob | Write-Information
55 | }
56 | }
57 | # Sleep here a few seconds to make sure that the command gets processed before the script ends
58 | if ($ProcessedVMs.Count -gt 0)
59 | {
60 | Start-Sleep 10
61 | }
62 | }
63 | catch
64 | {
65 | throw $_.Exception.Message
66 | }
67 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://portal.azure.com/#create/Microsoft.Template/uri/https%3a%2f%2fraw.githubusercontent.com%2feamonoreilly%2fStartStopPowerShellFunction%2fmaster%2fazuredeploy.json)
2 |
3 |
4 |
5 |
6 | # Sample to start / stop VMs on a schedule
7 |
8 | Create an Azure function application and deploy functions that starts or stops virtual machines in the specified resource group, subscription, or by tag on a schedule.
9 |
10 | ## Prerequisites
11 |
12 | Before running this sample, you must have the following:
13 |
14 | + Install [Azure Core Tools version 2.x](https://docs.microsoft.com/en-us/azure/azure-functions/functions-run-local)
15 |
16 | + Install the [Azure CLI](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli)
17 |
18 | ### Create a new resource group and function application on Azure
19 |
20 | Run the following PowerShell command and specify the value for the function application name in the TemplateParameterObject hashtable.
21 |
22 | ```powershell
23 | New-AzResourceGroup -Name -Location
24 |
25 | New-AzResourceGroupDeployment -ResourceGroupName -TemplateParameterObject @{"functionAppName" = ""} -TemplateUri "https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/101-functions-managed-identity/azuredeploy.json" -verbose
26 | ```
27 |
28 | This should create a new resource group with a function application and a managed service identity enabled. The id of the service principal for the MSI should be returned as an output from the deployment.
29 |
30 | Example: principalId String cac1fa06-2ad8-437d-99f6-b75edaae2921
31 |
32 | ### Grant the managed service identity contributor access to the subscription or resource group so it can perform actions
33 |
34 | The below command sets the access at the subscription level.
35 |
36 | ```powershell
37 | $Context = Get-AzContext
38 | New-AzRoleAssignment -ObjectId -RoleDefinitionName Contributor -Scope "/subscriptions/$($Context.Subscription)"
39 | ```
40 |
41 | ### Clone repository or download files to local machine
42 |
43 | + Download the repository files or clone to local machine.
44 |
45 | + Change to the PowerShell/StartStopVMOnTimer directory.
46 |
47 | ### Get the local.settings.json values from the function application created in Azure
48 |
49 | ```powershell
50 | func azure functionapp fetch-app-settings
51 | ```
52 |
53 | This should create a local.settings.json file in the StartStopVMOnTimer directory beside the host.json with the settings from the Azure function app.
54 |
55 | ### Test the functions locally
56 |
57 | Start the function with the following command
58 |
59 | ```powershell
60 | func start
61 | ```
62 |
63 | You can then call a trigger function by performing a post against the function on the admin api. Open up another Powershell console session and run:
64 |
65 | ```powershell
66 | Invoke-RestMethod "http://localhost:7071/admin/functions/StartVMOnTimer" -Method post -Body '{}' -ContentType "application/json"
67 | ```
68 |
69 | Modify the values for each of the below variables in run.ps1 as needed.
70 |
71 | ```powershell
72 | # Specify the VMs that you want to stop. Modify or comment out below based on which VMs to check.
73 | $VMResourceGroupName = "Contoso"
74 | #$VMName = "ContosoVM1"
75 | #$TagName = "AutomaticallyStart"
76 | ```
77 |
78 | Modify the start and stop time in the function.json file. They are currently set to 8am and 8pm UTC. You can change the timezone by modifying the application setting WEBSITE_TIME_ZONE. You can also pass in a parameter 'timezone' to the above [ARM template](https://raw.githubusercontent.com/eamonoreilly/AzureFunctions/master/PowerShell/ConsumptionAppWithTemplate/azuredeploy.json) that was used to create the function application if you want a different timezone so that daylight savings time will be honored.
79 |
80 | ```json
81 | {
82 | "disabled": false,
83 | "bindings": [
84 | {
85 | "name": "Timer",
86 | "type": "timerTrigger",
87 | "direction": "in",
88 | "schedule": "0 0 20 * * *"
89 | }
90 | ]
91 | }
92 | ```
93 |
94 | ## Publish the functions to the function application in Azure
95 |
96 | ```powershell
97 | func azure functionapp publish
98 | ```
--------------------------------------------------------------------------------
/azuredeploy.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
3 | "contentVersion": "1.0.0.0",
4 | "parameters": {
5 | "functionAppName": {
6 | "type": "string",
7 | "defaultValue": "[uniqueString(resourceGroup().id)]",
8 | "metadata": {
9 | "description": "Specify the name of the function application"
10 | }
11 | },
12 | "location": {
13 | "type": "string",
14 | "defaultValue": "[resourceGroup().location]",
15 | "metadata": {
16 | "description": "Specify the location for the function application resources"
17 | }
18 | },
19 | "ApplicationInsightsLocation": {
20 | "type": "string",
21 | "defaultValue": "West Europe",
22 | "allowedValues": [
23 | "East US",
24 | "South Central US",
25 | "North Europe",
26 | "West Europe",
27 | "Southeast Asia",
28 | "West US 2",
29 | "Central India",
30 | "Canada Central",
31 | "UK South"
32 | ],
33 | "metadata": {
34 | "description": "Specify the region for Application Insights data"
35 | }
36 | },
37 | "runtimeStack": {
38 | "type": "string",
39 | "defaultValue": "powershell",
40 | "allowedValues": [
41 | "powershell",
42 | "dotnet",
43 | "node",
44 | "java"
45 | ],
46 | "metadata": {
47 | "description": "Pick the language runtime that you want enabled"
48 | }
49 | },
50 | "timezone": {
51 | "type": "string",
52 | "defaultValue": "UTC",
53 | "allowedValues": [
54 | "Dateline Standard Time",
55 | "UTC-11",
56 | "Aleutian Standard Time",
57 | "Hawaiian Standard Time",
58 | "Marquesas Standard Time",
59 | "Alaskan Standard Time",
60 | "UTC-09",
61 | "Pacific Standard Time (Mexico)",
62 | "UTC-08",
63 | "Pacific Standard Time",
64 | "US Mountain Standard Time",
65 | "Mountain Standard Time (Mexico)",
66 | "Mountain Standard Time",
67 | "Central America Standard Time",
68 | "Central Standard Time",
69 | "Easter Island Standard Time",
70 | "Central Standard Time (Mexico)",
71 | "Canada Central Standard Time",
72 | "SA Pacific Standard Time",
73 | "Eastern Standard Time (Mexico)",
74 | "Eastern Standard Time",
75 | "Haiti Standard Time",
76 | "Cuba Standard Time",
77 | "US Eastern Standard Time",
78 | "Turks And Caicos Standard Time",
79 | "Paraguay Standard Time",
80 | "Atlantic Standard Time",
81 | "Venezuela Standard Time",
82 | "Central Brazilian Standard Time",
83 | "SA Western Standard Time",
84 | "Pacific SA Standard Time",
85 | "Newfoundland Standard Time",
86 | "Tocantins Standard Time",
87 | "E. South America Standard Time",
88 | "SA Eastern Standard Time",
89 | "Argentina Standard Time",
90 | "Greenland Standard Time",
91 | "Montevideo Standard Time",
92 | "Magallanes Standard Time",
93 | "Saint Pierre Standard Time",
94 | "Bahia Standard Time",
95 | "UTC-02",
96 | "Mid-Atlantic Standard Time",
97 | "Azores Standard Time",
98 | "Cape Verde Standard Time",
99 | "UTC",
100 | "Morocco Standard Time",
101 | "GMT Standard Time",
102 | "Greenwich Standard Time",
103 | "W. Europe Standard Time",
104 | "Central Europe Standard Time",
105 | "Romance Standard Time",
106 | "Sao Tome Standard Time",
107 | "Central European Standard Time",
108 | "W. Central Africa Standard Time",
109 | "Jordan Standard Time",
110 | "GTB Standard Time",
111 | "Middle East Standard Time",
112 | "Egypt Standard Time",
113 | "E. Europe Standard Time",
114 | "Syria Standard Time",
115 | "West Bank Standard Time",
116 | "South Africa Standard Time",
117 | "FLE Standard Time",
118 | "Israel Standard Time",
119 | "Kaliningrad Standard Time",
120 | "Sudan Standard Time",
121 | "Libya Standard Time",
122 | "Namibia Standard Time",
123 | "Arabic Standard Time",
124 | "Turkey Standard Time",
125 | "Arab Standard Time",
126 | "Belarus Standard Time",
127 | "Russian Standard Time",
128 | "E. Africa Standard Time",
129 | "Iran Standard Time",
130 | "Arabian Standard Time",
131 | "Astrakhan Standard Time",
132 | "Azerbaijan Standard Time",
133 | "Russia Time Zone 3",
134 | "Mauritius Standard Time",
135 | "Saratov Standard Time",
136 | "Georgian Standard Time",
137 | "Caucasus Standard Time",
138 | "Afghanistan Standard Time",
139 | "West Asia Standard Time",
140 | "Ekaterinburg Standard Time",
141 | "Pakistan Standard Time",
142 | "India Standard Time",
143 | "Sri Lanka Standard Time",
144 | "Nepal Standard Time",
145 | "Central Asia Standard Time",
146 | "Bangladesh Standard Time",
147 | "Omsk Standard Time",
148 | "Myanmar Standard Time",
149 | "SE Asia Standard Time",
150 | "Altai Standard Time",
151 | "W. Mongolia Standard Time",
152 | "North Asia Standard Time",
153 | "N. Central Asia Standard Time",
154 | "Tomsk Standard Time",
155 | "China Standard Time",
156 | "North Asia East Standard Time",
157 | "Singapore Standard Time",
158 | "W. Australia Standard Time",
159 | "Taipei Standard Time",
160 | "Ulaanbaatar Standard Time",
161 | "Aus Central W. Standard Time",
162 | "Transbaikal Standard Time",
163 | "Tokyo Standard Time",
164 | "North Korea Standard Time",
165 | "Korea Standard Time",
166 | "Yakutsk Standard Time",
167 | "Cen. Australia Standard Time",
168 | "AUS Central Standard Time",
169 | "E. Australia Standard Time",
170 | "AUS Eastern Standard Time",
171 | "West Pacific Standard Time",
172 | "Tasmania Standard Time",
173 | "Vladivostok Standard Time",
174 | "Lord Howe Standard Time",
175 | "Bougainville Standard Time",
176 | "Russia Time Zone 10",
177 | "Magadan Standard Time",
178 | "Norfolk Standard Time",
179 | "Sakhalin Standard Time",
180 | "Central Pacific Standard Time",
181 | "Russia Time Zone 11",
182 | "New Zealand Standard Time",
183 | "UTC+12",
184 | "Fiji Standard Time",
185 | "Kamchatka Standard Time",
186 | "Chatham Islands Standard Time",
187 | "UTC+13",
188 | "Tonga Standard Time",
189 | "Samoa Standard Time",
190 | "Line Islands Standard Time"
191 | ],
192 | "metadata": {
193 | "description": "Pick the timezone to use for the function"
194 | }
195 | }
196 | },
197 | "variables": {
198 | "hostingPlanName": "[parameters('functionAppName')]",
199 | "storageAccountName": "[concat('storage', uniquestring(resourceGroup().id))]",
200 | "repoUrl": "https://github.com/eamonoreilly/StartStopPowerShellFunction",
201 | "branch": "master"
202 | },
203 | "resources": [
204 | {
205 | "name": "[parameters('functionAppName')]",
206 | "type": "Microsoft.Web/sites",
207 | "apiVersion": "2018-02-01",
208 | "location": "[parameters('location')]",
209 | "kind": "functionapp",
210 | "dependsOn": [
211 | "[resourceId('Microsoft.Web/serverfarms/', variables('hostingPlanName'))]",
212 | "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]",
213 | "[resourceId('microsoft.insights/components/', parameters('functionAppName'))]"
214 | ],
215 | "identity": {
216 | "type": "SystemAssigned"
217 | },
218 | "properties": {
219 | "siteConfig": {
220 | "appSettings": [
221 | {
222 | "name": "FUNCTIONS_WORKER_RUNTIME",
223 | "value": "[parameters('runtimeStack')]"
224 | },
225 | {
226 | "name": "AzureWebJobsStorage",
227 | "value": "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2017-06-01').keys[0].value)]"
228 | },
229 | {
230 | "name": "FUNCTIONS_EXTENSION_VERSION",
231 | "value": "~2"
232 | },
233 | {
234 | "name": "APPINSIGHTS_INSTRUMENTATIONKEY",
235 | "value": "[reference(resourceId('microsoft.insights/components/', parameters('functionAppName')), '2018-05-01-preview').InstrumentationKey]"
236 | },
237 | {
238 | "name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING",
239 | "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')),'2017-06-01').keys[0].value)]"
240 | },
241 | {
242 | "name": "WEBSITE_CONTENTSHARE",
243 | "value": "[toLower(parameters('functionAppName'))]"
244 | },
245 | {
246 | "name": "WEBSITE_TIME_ZONE",
247 | "value": "[parameters('timezone')]"
248 | }
249 | ]
250 | },
251 | "name": "[parameters('functionAppName')]",
252 | "clientAffinityEnabled": false,
253 | "serverFarmId": "[resourceId('Microsoft.Web/serverfarms/', variables('hostingPlanName'))]"
254 | },
255 | "resources": [
256 | {
257 | "apiVersion": "2015-08-01",
258 | "name": "web",
259 | "type": "sourcecontrols",
260 | "dependsOn": [
261 | "[resourceId('Microsoft.Web/Sites/', parameters('functionAppName'))]"
262 | ],
263 | "properties": {
264 | "RepoUrl": "[variables('repoURL')]",
265 | "branch": "[variables('branch')]",
266 | "IsManualIntegration": true
267 | }
268 | }
269 | ]
270 | },
271 | {
272 | "type": "Microsoft.Web/serverfarms",
273 | "apiVersion": "2018-11-01",
274 | "name": "[variables('hostingPlanName')]",
275 | "location": "[parameters('location')]",
276 | "properties": {
277 | "name": "[variables('hostingPlanName')]"
278 | },
279 | "sku": {
280 | "name": "Y1",
281 | "tier": "Dynamic",
282 | "size": "Y1",
283 | "family": "Y",
284 | "capacity": 0
285 | }
286 | },
287 | {
288 | "apiVersion": "2017-06-01",
289 | "type": "Microsoft.Storage/storageAccounts",
290 | "name": "[variables('storageAccountName')]",
291 | "location": "[parameters('location')]",
292 | "sku": {
293 | "name": "Standard_LRS"
294 | }
295 | },
296 | {
297 | "apiVersion": "2018-05-01-preview",
298 | "name": "[parameters('functionAppName')]",
299 | "type": "Microsoft.Insights/components",
300 | "location": "[parameters('ApplicationInsightsLocation')]",
301 | "tags": {
302 | "[concat('hidden-link:', resourceId('Microsoft.Web/sites/', parameters('functionAppName')))]": "Resource"
303 | },
304 | "properties": {
305 | "ApplicationId": "[parameters('functionAppName')]"
306 | }
307 | }
308 | ],
309 | "outputs": {
310 | "principalId": {
311 | "type": "string",
312 | "value": "[reference(concat(resourceId('Microsoft.Web/sites/', parameters('functionAppName')), '/providers/Microsoft.ManagedIdentity/Identities/default'), '2015-08-31-PREVIEW').principalId]"
313 | }
314 | }
315 | }
--------------------------------------------------------------------------------