From 42930efc69338ba5dbc40b8944c3c8a3ac1757a2 Mon Sep 17 00:00:00 2001 From: d6p <43806862+d6p@users.noreply.github.com> Date: Thu, 4 Oct 2018 13:49:00 +0200 Subject: [PATCH 01/66] Create SafeKit farm cluster quickstart template --- safekit-cluster-farm/README.md | 60 ++ safekit-cluster-farm/azuredeploy.json | 242 +++++++ .../azuredeploy.parameters.json | 21 + safekit-cluster-farm/images/farmarch.png | Bin 0 -> 32376 bytes safekit-cluster-farm/metadata.json | 11 + .../nestedtemplates/cfgFarm.json | 93 +++ .../nestedtemplates/cluster.json | 653 ++++++++++++++++++ .../nestedtemplates/createvip.json | 43 ++ .../nestedtemplates/installCluster.json | 136 ++++ .../nestedtemplates/installModule.json | 101 +++ .../nestedtemplates/safekitdepl.json | 111 +++ .../scripts/InstallSafeKit.ps1 | 61 ++ .../scripts/InstallSafeKit.sh | 24 + safekit-cluster-farm/scripts/UpdateSafeKit.sh | 7 + safekit-cluster-farm/scripts/cfgFarm.ps1 | 39 ++ .../scripts/configCluster.ps1 | 88 +++ .../scripts/installAzureRM.ps1 | 17 + .../scripts/installCluster.ps1 | 33 + .../scripts/installCluster.sh | 11 + .../scripts/installModule.ps1 | 31 + safekit-cluster-farm/scripts/uploadcerts.ps1 | 47 ++ 21 files changed, 1829 insertions(+) create mode 100644 safekit-cluster-farm/README.md create mode 100644 safekit-cluster-farm/azuredeploy.json create mode 100644 safekit-cluster-farm/azuredeploy.parameters.json create mode 100644 safekit-cluster-farm/images/farmarch.png create mode 100644 safekit-cluster-farm/metadata.json create mode 100644 safekit-cluster-farm/nestedtemplates/cfgFarm.json create mode 100644 safekit-cluster-farm/nestedtemplates/cluster.json create mode 100644 safekit-cluster-farm/nestedtemplates/createvip.json create mode 100644 safekit-cluster-farm/nestedtemplates/installCluster.json create mode 100644 safekit-cluster-farm/nestedtemplates/installModule.json create mode 100644 safekit-cluster-farm/nestedtemplates/safekitdepl.json create mode 100644 safekit-cluster-farm/scripts/InstallSafeKit.ps1 create mode 100644 safekit-cluster-farm/scripts/InstallSafeKit.sh create mode 100644 safekit-cluster-farm/scripts/UpdateSafeKit.sh create mode 100644 safekit-cluster-farm/scripts/cfgFarm.ps1 create mode 100644 safekit-cluster-farm/scripts/configCluster.ps1 create mode 100644 safekit-cluster-farm/scripts/installAzureRM.ps1 create mode 100644 safekit-cluster-farm/scripts/installCluster.ps1 create mode 100644 safekit-cluster-farm/scripts/installCluster.sh create mode 100644 safekit-cluster-farm/scripts/installModule.ps1 create mode 100644 safekit-cluster-farm/scripts/uploadcerts.ps1 diff --git a/safekit-cluster-farm/README.md b/safekit-cluster-farm/README.md new file mode 100644 index 000000000000..b9fb4b4e44a0 --- /dev/null +++ b/safekit-cluster-farm/README.md @@ -0,0 +1,60 @@ +# Evidian SafeKit - Load Balancing Cluster with Failover in Azure - Farm Module + + + + + +`Tags: load balancing, cluster, failover, high availability, business continuity, disaster recovery, evidian, safekit, farm` + +* [Description](#description) +* [Deployed resources](#resources) +* [How to use](#use) +* [More information](#more) + +## Description + +![How the Evidian SafeKit farm cluster implements load balancing and failover in Azure?](images/farmarch.png) + +On the previous figure, + +* the critical application is running in all servers of the farm +* users are connected to a virtual IP address which is configured in the Azure load balancer +* SafeKit brings a generic health probe for the load balancer When the farm module is stopped in a server, the health probe returns NOK to the load balancer which stops the load balancing of requests to the server. The same behavior happens when there is a **hardware failure** +* in each server, SafeKit monitors the critical application with process checkers and custom checkers +* SafeKit restarts automatically the critical application in a server when there is a **software failure** thanks to restart scripts +* a connector for the SafeKit web console is installed in each server. Thus, the load balancing cluster can be managed in a very simple way to avoid **human errors** + +## Deployed resources + +In term of VMs, this template deploys: + +* from 2 to 4 VMs (Windows or Linux) spanning 2 or 3 availability zone(s) +* each VM has a public IP address (Standard SKU) +* the SafeKit free trial is installed in all VMs +* a SafeKit farm module is configured in all VMs + +In term of load balancer, this template deploys: + +* a public load balancer (standard SKU) +* a public IP (Standard SKU) is associated with the public load balancer and plays the role of the virtual IP +* alls VMs are in the backend pool of the load balancer +* a health probe checks the farm module state on all VMs +* a load balancing rule for external port 9453 / internal port 9453 is set to test the load balanced virtual IP + +## How to use + +Click the "Deploy to Azure" button at the beginning of this document to deploy the load balancing cluster. Please create a new resource group. + +After deployment, go to the resource group's 'Microsoft.Template' deployment output panel (Home > Resource Groups > YourResourceGroup - Deployments) and: + +* visit the credential url to install the client and CA certificates in your web browser +* after certificates installation, start the web console of the cluster +* test the load balanced virtual IP address with the test URL in the output + + + +## More information on **Evidian SafeKit** in Azure + +* [Azure: The Simplest Load Balancing Cluster with Failover](https://www.evidian.com/products/high-availability-software-for-application-clustering/azure-load-balancing-cluster-failover/) +* [Azure: The Simplest High Availability Cluster with Synchronous Replication and Failover](https://www.evidian.com/products/high-availability-software-for-application-clustering/azure-high-availability-cluster-synchronous-replication-failover/) + diff --git a/safekit-cluster-farm/azuredeploy.json b/safekit-cluster-farm/azuredeploy.json new file mode 100644 index 000000000000..afa8655321f9 --- /dev/null +++ b/safekit-cluster-farm/azuredeploy.json @@ -0,0 +1,242 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "OS": { + "type": "string", + "metadata": { + "description": "Operating System to install" + }, + "defaultValue": "2016-Datacenter", + "allowedValues": [ + "2016-Datacenter", + "2019-Datacenter", + "Linux CentOS" + ] + }, + "clusterNodes": { + "type": "int", + "metadata": { + "description": "number of VM nodes to create" + }, + "defaultValue": 2, + "allowedValues": [ + 2, + 3, + 4 + ] + }, + "vmSize": { + "type": "string", + "metadata": { + "description": "the VM size for all nodes" + }, + "defaultValue": "Standard_A2_v2" + }, + "adminUser": { + "type": "string", + "metadata": { + "description": "User for the Virtual Machines." + } + }, + "adminPassword": { + "type": "securestring", + "metadata": { + "description": "Password for the Virtual Machines." + } + }, + "VIPDnsLabel": { + "type": "string", + "metadata": { + "description": "Public VIP dns label. VIP fqdn will be like ..cloudapp.azure.com and must be globally unique." + } + }, + "VMDnsPrefix": { + "type": "string", + "metadata": { + "description": "Public VM IP dns label prefix. VM fqdn will be like vm..cloudapp.azure.com and must be unique." + } + }, + "azurePwsh": { + "type": "string", + "metadata": { + "description": "install azure powershell module (optional)" + }, + "defaultValue": "no", + "allowedValues": [ + "yes", + "no" + ] + }, + "location": { + "type": "string", + "metadata": { + "description": "resources location (region must support Availability Zones)" + }, + "allowedValues": [ + "centralus", + "eastus2", + "francecentral", + "northeurope", + "westeurope", + "westus2" + ] + }, + "safekitFileUri": { + "type": "string", + "metadata": { + "description": "url of SafeKit package (optional, default to the appropriate Evidian website url)." + }, + "defaultValue": "default" + }, + "_artifactsLocation": { + "type": "string", + "metadata": { + "description": "base URL of deployment resources (template,subtemplates,scripts)" + }, + "defaultValue": "https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/safekit-cluster-farm/" + }, + "_artifactsLocationSasToken": { + "type": "securestring", + "metadata": { + "description": "The sasToken required to access _artifactsLocation. When the template is deployed using the accompanying scripts, a sasToken will be automatically generated. Use the defaultValue if the staging location is not secured." + }, + "defaultValue": "" + } + }, + "variables": { + "clusternodes": "[parameters('clusterNodes')]", + "vmname": "VM1", + "moduleName": "farm", + "cltemplate": "[uri(parameters('_artifactsLocation'),'nestedtemplates/cluster.json')]", + "ostype": "[if(equals(parameters('OS'), 'Linux CentOS'),'linux','windows')]", + "skcfgmoduletemplate": "[concat(uri(parameters('_artifactsLocation'),'nestedtemplates/cfgFarm.json'),parameters('_artifactsLocationSasToken'))]", + "safekitpkgUrl": { + "windows": "https://support.evidian.com/solutions/downloads/safekit/cloud/platforms/windows/current_versions/safekit_cloud.msi", + "linux": "https://support.evidian.com/solutions/downloads/safekit/cloud/platforms/linux/current_versions/safekit_cloud.bin" + }, + "farmUrl": { + "windows": "https://support.evidian.com/solutions/downloads/safekit/cloud/application_modules/windows/farm.safe", + "linux": "https://support.evidian.com/solutions/downloads/safekit/cloud/application_modules/linux/farm.safe" + } + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2018-05-01", + "name": "safekitCluster", + "properties": { + "mode": "Incremental", + "templateLink": { + "uri": "[variables('cltemplate')]", + "contentVersion": "1.0.0.0" + }, + "parameters": { + "OS": { + "value": "[parameters('OS')]" + }, + "clusterNodes": { + "value": "[variables('clusterNodes')]" + }, + "vmSize": { + "value": "[parameters('vmSize')]" + }, + "adminUser": { + "value": "[parameters('adminUser')]" + }, + "adminPassword": { + "value": "[parameters('adminPassword')]" + }, + "moduleUrl": { + "value": "[variables('farmUrl')[variables('ostype')]]" + }, + "moduleName": { + "value": "[variables('moduleName')]" + }, + "VIPDnsLabel": { + "value": "[parameters('VIPDnsLabel')]" + }, + "VMDnsPrefix": { + "value": "[parameters('VMDnsPrefix')]" + }, + "Loadbalancer": { + "value": "External" + }, + "location": { + "value": "[parameters('location')]" + }, + "safekitFileUri": { + "value": "[if(equals(parameters('safekitFileUri'),'default'),variables('safekitpkgUrl')[variables('ostype')],parameters('safekitFileUri'))]" + }, + "_artifactsLocation": { + "value": "[parameters('_artifactsLocation')]" + }, + "_artifactsLocationSasToken": { + "value": "[parameters('_artifactsLocationSasToken')]" + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2018-05-01", + "name": "safekitModuleConfig", + "dependsOn": [ + "safekitCluster" + ], + "properties": { + "mode": "Incremental", + "templateLink": { + "uri": "[variables('skcfgmoduletemplate')]", + "contentVersion": "1.0.0.0" + }, + "parameters": { + "vmname": { + "value": "[variables('vmname')]" + }, + "ostype": { + "value": "[variables('ostype')]" + }, + "moduleName": { + "value": "[variables('moduleName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "_artifactsLocation": { + "value": "[parameters('_artifactsLocation')]" + }, + "_artifactsLocationSasToken": { + "value": "[parameters('_artifactsLocationSasToken')]" + } + } + } + } + ], + "outputs": { + "FIRST GET THE CREDENTIALS": { + "type": "string", + "value": "[reference('safekitCluster').outputs['Credentials Url'].value]" + }, + "LOGIN TO GET THE CREDENTIALS": { + "type": "string", + "value": "[reference('safekitCluster').outputs['Credentials Url Login'].value]" + }, + "START THE CONSOLE": { + "type": "string", + "value": "[concat(reference('safekitCluster').outputs['Console Url'].value,'?firewallDialog=false')]" + }, + "TEST THE VIRTUAL IP": { + "type": "string", + "value": "[reference('safekitCluster').outputs['Mosaic URL'].value]" + }, + "ADMINUSER": { + "type": "string", + "value": "[parameters('adminUser')]" + }, + "VM1": { + "type": "string", + "value": "[reference('safekitCluster').outputs.fqdn.value]" + } + } +} \ No newline at end of file diff --git a/safekit-cluster-farm/azuredeploy.parameters.json b/safekit-cluster-farm/azuredeploy.parameters.json new file mode 100644 index 000000000000..20d8137b22da --- /dev/null +++ b/safekit-cluster-farm/azuredeploy.parameters.json @@ -0,0 +1,21 @@ +{ + "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "adminUser": { + "value": "GEN-UNIQUE" + }, + "adminPassword": { + "value": "GEN-PASSWORD" + }, + "VIPDnsLabel": { + "value": "GEN-UNIQUE-13" + }, + "VMDnsPrefix": { + "value": "GEN-UNIQUE-10" + }, + "location": { + "value": "westus2" + } + } +} \ No newline at end of file diff --git a/safekit-cluster-farm/images/farmarch.png b/safekit-cluster-farm/images/farmarch.png new file mode 100644 index 0000000000000000000000000000000000000000..e7e5c2205b38ef7cced7c8419c3b45c2b12ed6cb GIT binary patch literal 32376 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%0D8IO`knQueiK_H5^1QSd)={>2ms2N$gm5m`R%?C z)F+E*XoQRZ3p_%I*(?9W{D2xJ!18<@Dikiii!S3iz)&3#dk! zaj|cBWKhumrW1*j-*Eosho5YlEmSC1cAU%m9lqbW4D4za-8A12f6g~Mci#wTBGnQj zC1IqZbP*=ln82{MS~-Icqi>930PwE+4WR5AtcenPP!n3Y_5dzkQiRETJ3lbu`}*Z5 zBV6;DF$sBSVs$>w9O1s0u|ER0#oI-ov;H2kg=4rtRcUqR`J-0pJP9KB7y3-d$7#Sq z^rRliN>~qj0Gz&R10MmbbP$DlTbP0v$wd#E*_?5xQ;oq=i*?}sO$EU<9kcQtmOoGy zKhLI<^$;~MAKRLXB=jD>E8`THEu|(wJYVC}jl(*6qdKvUFq+{JNXTn}eXuYc6-KlI zBle+WEaW9Sj3NPCQV)yv?fXHY-$U2Ph^;u|nzPUc%wp--MrR^r=wNITz-At*D9(bPDrt?8w?=s)yoD2zADJ0u22;O-9w z|2H_*HUD4MtUp@}NI_=*2O!-EVs!m?+y6;X3;@=3bb-$tk2ap&sAXNU)7$Z1pCVkJ v68PUA^{pu;Bwggym7q5g7@a=wFG}d{8jI!4=NF*z`#;j+@?zB@hQa>}t2)Q# literal 0 HcmV?d00001 diff --git a/safekit-cluster-farm/metadata.json b/safekit-cluster-farm/metadata.json new file mode 100644 index 000000000000..b690f0fee84c --- /dev/null +++ b/safekit-cluster-farm/metadata.json @@ -0,0 +1,11 @@ +{ + "$schema": "https://aka.ms/azure-quickstart-templates-metadata-schema#", + "type": "QuickStart", + "itemDisplayName": "Evidian SafeKit Farm Cluster", + "description": "This template deploys a load balancing cluster with failover on 2 to 4 Windows or Linux VMs in different availability zones", + "summary": "Evidian SafeKit farm cluster on Windows or Linux", + "githubUsername": "d6p", + "dateUpdated": "2019-1-14" +} + + diff --git a/safekit-cluster-farm/nestedtemplates/cfgFarm.json b/safekit-cluster-farm/nestedtemplates/cfgFarm.json new file mode 100644 index 000000000000..005abe9fa7d5 --- /dev/null +++ b/safekit-cluster-farm/nestedtemplates/cfgFarm.json @@ -0,0 +1,93 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "vmname": { + "type": "string", + "metadata": { + "description": "vm name" + } + }, + "ostype": { + "type": "string", + "metadata": { + "description": "OS type (windows, linux)" + }, + "defaultValue": "windows" + }, + "moduleName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "url of the application module to install on all nodes" + } + }, + "location": { + "type": "string", + "metadata": { + "description": "resources location" + } + }, + "_artifactsLocation": { + "type": "string", + "metadata": { + "description": "base URL of deployment resources (template,subtemplates,scripts)" + }, + "defaultValue": "[deployment().properties.templateLink.uri]" + }, + "_artifactsLocationSasToken": { + "type": "securestring", + "metadata": { + "description": "The sasToken required to access _artifactsLocation. When the template is deployed using the accompanying scripts, a sasToken will be automatically generated. Use the defaultValue if the staging location is not secured." + }, + "defaultValue": "" + } + }, + "variables": { + "cfgModuleuri": "[concat(uri(parameters('_artifactsLocation'),'scripts/cfgFarm.ps1'),parameters('_artifactsLocationSasToken'))]", + "properties": { + "windows": { + "publisher": "Microsoft.Compute", + "type": "CustomScriptExtension", + "typeHandlerVersion": "1.9", + "autoUpgradeMinorVersion": true, + "settings": { + "fileUris": [ + "[variables('cfgModuleuri')]" + ] + }, + "protectedSettings":{ + "commandToExecute": "[concat('powershell -ExecutionPolicy Unrestricted -File .\\cfgFarm.ps1 -safekitcmd C:/safekit/safekit -safekitmod C:/safekit/modules -MName \"',parameters('moduleName'),'\"')]" + } + }, + "linux": { + "publisher": "Microsoft.Azure.Extensions", + "type": "CustomScript", + "typeHandlerVersion": "2.0", + "autoUpgradeMinorVersion": true, + "settings": { + "skipDos2Unix": false, + "timestamp": 1, + "fileUris": [ + "[variables('cfgModuleuri')]" + ] + }, + "protectedSettings":{ + "commandToExecute": "[concat('pwsh ./cfgFarm.ps1 -safekitcmd /opt/safekit/safekit -safekitmod /opt/safekit/modules -MName \"',parameters('moduleName'),'\"')]" + } + } + } + }, + "resources": [ + { + "name": "[concat(parameters('vmname'),'/safekit')]", + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2018-06-01", + "location": "[parameters('location')]", + "properties": "[variables('properties')[parameters('ostype')]]" + } + ], + "outputs": { + + } +} \ No newline at end of file diff --git a/safekit-cluster-farm/nestedtemplates/cluster.json b/safekit-cluster-farm/nestedtemplates/cluster.json new file mode 100644 index 000000000000..db12328de3dd --- /dev/null +++ b/safekit-cluster-farm/nestedtemplates/cluster.json @@ -0,0 +1,653 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "OS": { + "type": "string", + "metadata": { + "description": "Operating System to install" + } + }, + "clusterNodes": { + "type": "int", + "metadata": { + "description": "number of VM nodes to create" + }, + "defaultValue": 2, + "allowedValues": [ + 1, + 2, + 3, + 4 + ] + }, + "vmSize": { + "type": "string", + "metadata": { + "description": "the VM size for all nodes" + }, + "defaultValue": "Standard_A2_v2" + }, + "adminUser": { + "type": "string", + "metadata": { + "description": "User for the Virtual Machines." + } + }, + "adminPassword": { + "type": "securestring", + "metadata": { + "description": "Password for the Virtual Machines." + } + }, + "moduleUrl": { + "type": "string", + "metadata": { + "description": "url of the application module to install on all nodes (optional)" + }, + "defaultValue": "" + }, + "moduleName": { + "type": "string", + "metadata": { + "description": "name of the application module to install on all nodes (optional)" + }, + "defaultValue": "mirror" + }, + "VIPDnsLabel": { + "type": "string", + "metadata": { + "description": "Public VIP dns label (optional. If set, an additionnal Standard SKU, unassociated public IP will be created)" + }, + "defaultValue": "" + }, + "VMDnsPrefix": { + "type": "string", + "metadata": { + "description": "Public VM IP dns label prefix" + } + + }, + "Loadbalancer": { + "type": "string", + "metadata": { + "description": "loadbalancer (optional. If set, a loadbalancer will be created, with the VIP as frontend and the VMs in the backend pool." + }, + "defaultValue": "none", + "allowedValues": [ + "External", + "none" + ] + }, + "azurePwsh": { + "type": "string", + "metadata": { + "description": "install azure powershell module (optional)" + }, + "defaultValue": "no", + "allowedValues": [ + "yes", + "no" + ] + }, + "location": { + "type": "string", + "metadata": { + "description": "resources location" + } + }, + "safekitFileUri": { + "type": "string", + "metadata": { + "description": "url of safekit package" + }, + "defaultValue": "" + }, + "_artifactsLocation": { + "type": "string", + "metadata": { + "description": "base URL of deployment resources (template,subtemplates,scripts)" + }, + "defaultValue": "[deployment().properties.templateLink.uri]" + }, + "_artifactsLocationSasToken": { + "type": "securestring", + "metadata": { + "description": "The sasToken required to access _artifactsLocation. When the template is deployed using the accompanying scripts, a sasToken will be automatically generated. Use the defaultValue if the staging location is not secured." + }, + "defaultValue": "" + } + }, + "variables": { + "allvms": [ + "VM1", + "VM2", + "VM3", + "VM4" + ], + "vms": "[take(variables('allvms'),parameters('clusterNodes'))]", + "cltemplate": "[uri(parameters('_artifactsLocation'),'nested/cluster.json')]", + "frontEndIPConfigName": "[concat(parameters('VIPDnsLabel'),'LBFE')]", + "lbPoolName": "[concat(parameters('VIPDnsLabel'),'BEP')]", + "lbProbeName": "[concat(parameters('VIPDnsLabel'),'LBP')]", + "lbName": "[concat(parameters('VIPDnsLabel'),'LB')]", + "NetworkContributor": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/','4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "ostype": "[if(equals(parameters('OS'), 'Linux CentOS'),'linux','windows')]", + "adminUsername": "[if(empty(parameters('adminUser')),concat('admin',resourceGroup().name),parameters('adminUser'))]", + "ips": [ + "10.0.0.10", + "10.0.0.11", + "10.0.0.12", + "10.0.0.13" + ], + "sktemplate": "[concat(uri(parameters('_artifactsLocation'), 'nestedtemplates/safekitdepl.json'),parameters('_artifactsLocationSasToken'))]", + "skclustertemplate": "[concat(uri(parameters('_artifactsLocation'), 'nestedtemplates/installCluster.json'),parameters('_artifactsLocationSasToken'))]", + "createviptemplate": "[concat(uri(parameters('_artifactsLocation'),'nestedtemplates/createvip.json'),parameters('_artifactsLocationSasToken'))]", + "skmoduletemplate": "[concat(uri(parameters('_artifactsLocation'),'nestedtemplates/installModule.json'),parameters('_artifactsLocationSasToken'))]", + "NSGName": "SafeKit-NSG", + "storageAccountName": "[concat(uniquestring(resourceGroup().id,parameters('location')), 'stor')]", + "lbPoolID": "[if(equals(parameters('LoadBalancer'),'none'),'',resourceId('Microsoft.Network/loadBalancers/backendAddressPools',variables('lbName'),variables('lbPoolName')))]", + "lbaddrpool1": [ + { + "id": "[variables('lbPoolID')]" + } + ], + "lbaddrpool0": [ + + ], + "lbaddrpool": "[if(greater(length(variables('lbPoolID')),0),variables('lbaddrpool1'),variables('lbaddrpool0'))]", + "WindowsStorageProfile": { + "imageReference": { + "publisher": "MicrosoftWindowsServer", + "offer": "WindowsServer", + "sku": "[parameters('OS')]", + "version": "latest" + }, + "osDisk": { + "createOption": "FromImage" + } + }, + "CentosStorageProfile": { + "imageReference": { + "publisher": "OpenLogic", + "offer": "CentOS", + "sku": "7.5", + "version": "latest" + }, + "osDisk": { + "createOption": "fromImage" + }, + "dataDisks": [ + + ] + }, + "linuxConfiguration": { + "disablePasswordAuthentication": "false" + }, + "addressPrefix": "10.0.0.0/16", + "virtualNetworkName": "[concat(resourceGroup().name,'VNET')]", + "subnetName": "Subnet", + "subnetPrefix": "10.0.0.0/24" + }, + "resources": [ + { + "type": "Microsoft.Network/virtualNetworks", + "apiVersion": "2018-08-01", + "name": "[variables('virtualNetworkName')]", + "location": "[parameters('location')]", + "properties": { + "addressSpace": { + "addressPrefixes": [ + "[variables('addressPrefix')]" + ] + }, + "subnets": [ + { + "name": "[variables('subnetName')]", + "properties": { + "addressPrefix": "[variables('subnetPrefix')]" + } + } + ] + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2018-05-01", + "name": "optionalVip", + "properties": { + "mode": "Incremental", + "templateLink": { + "uri": "[variables('createviptemplate')]", + "contentVersion": "1.0.0.0" + }, + "parameters": { + "location": { + "value": "[parameters('location')]" + }, + "VIPDnsLabel": { + "value": "[parameters('VIPDnsLabel')]" + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2018-05-01", + "name": "optionalLB", + "dependsOn": [ + "optionalVip" + ], + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [ + { + "condition": "[and(not(empty(parameters('VIPDnsLabel'))),not(equals(parameters('Loadbalancer'),'none')))]", + "type": "Microsoft.Network/loadBalancers", + "apiVersion": "2018-08-01", + "name": "[variables('lbName')]", + "location": "[parameters('location')]", + "sku": { + "name": "Standard" + }, + "properties": { + "frontendIPConfigurations": [ + { + "name": "[variables('frontEndIPConfigName')]", + "properties": { + "publicIPAddress": { + "id": "[resourceId('Microsoft.Network/publicIPAddresses',concat('pip',parameters('VIPDnsLabel')))]" + } + } + } + ], + "backendAddressPools": [ + { + "name": "[variables('lbPoolName')]" + } + ], + "loadBalancingRules": [ + { + "name": "LBRule", + "properties": { + "frontendIPConfiguration": { + "id": "[resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations',variables('lbName'),variables('frontEndIPConfigName'))]" + }, + "backendAddressPool": { + "id": "[resourceId('Microsoft.Network/loadBalancers/backendAddressPools',variables('lbName'),variables('lbPoolName'))]" + }, + "protocol": "tcp", + "frontendPort": 9453, + "backendPort": 9453, + "enableFloatingIP": false, + "idleTimeoutInMinutes": 5, + "probe": { + "id": "[resourceId('Microsoft.Network/loadBalancers/probes',variables('lbName'),variables('lbProbeName'))]" + } + } + } + ], + "probes": [ + { + "name": "[variables('lbProbeName')]", + "properties": { + "protocol": "http", + "port": 9010, + "requestPath": "[concat('/var/modules/',parameters('moduleName'),'/ready.txt')]", + "intervalInSeconds": 5, + "numberOfProbes": 2 + } + } + ] + } + } + ] + } + } + }, + { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2018-02-01", + "name": "[variables('storageAccountName')]", + "location": "[parameters('location')]", + "sku": { + "name": "Standard_LRS" + }, + "kind": "Storage", + "properties": { + + } + }, + { + "type": "Microsoft.Network/networkSecurityGroups", + "apiVersion": "2018-07-01", + "name": "[variables('NSGName')]", + "location": "[parameters('location')]", + "properties": { + "securityRules": [ + { + "name": "remoteaccess", + "properties": { + "description": "Allow Remote Access", + "protocol": "Tcp", + "sourcePortRange": "*", + "destinationPortRange": "[if(equals(variables('ostype'),'linux'),'22','3389')]", + "sourceAddressPrefix": "Internet", + "destinationAddressPrefix": "*", + "access": "Allow", + "priority": 100, + "direction": "Inbound" + } + }, + { + "name": "secconsole", + "properties": { + "description": "Allow Web Console Security Access", + "protocol": "Tcp", + "sourcePortRange": "*", + "destinationPortRange": "9001", + "sourceAddressPrefix": "Internet", + "destinationAddressPrefix": "*", + "access": "Allow", + "priority": 110, + "direction": "Inbound" + } + }, + { + "name": "webconsole", + "properties": { + "description": "Allow Web Console Access", + "protocol": "Tcp", + "sourcePortRange": "*", + "destinationPortRange": "9453", + "sourceAddressPrefix": "Internet", + "destinationAddressPrefix": "*", + "access": "Allow", + "priority": 120, + "direction": "Inbound" + } + } + ] + } + }, + { + "type": "Microsoft.Network/publicIPAddresses", + "apiVersion": "2018-07-01", + "name": "[concat('pip',variables('vms')[copyIndex()])]", + "location": "[parameters('location')]", + "copy": { + "name": "publicIpLoop", + "count": "[length(variables('vms'))]" + }, + "sku": { + "name": "Standard", + "tier": "Regional" + }, + "properties": { + "publicIPAllocationMethod": "Static", + "dnsSettings": { + "domainNameLabel": "[toLower(concat(parameters('VMDnsPrefix'),variables('vms')[copyIndex()]))]" + } + } + }, + { + "type": "Microsoft.Network/networkInterfaces", + "apiVersion": "2018-07-01", + "name": "[concat('nic',variables('vms')[copyIndex()])]", + "location": "[parameters('location')]", + "copy": { + "name": "interfaceLoop", + "count": "[length(variables('vms'))]" + }, + "dependsOn": [ + "optionalLB", + "[resourceId('Microsoft.Network/publicIPAddresses/',concat('pip',variables('vms')[copyIndex()]))]", + "[resourceId('Microsoft.Network/networkSecurityGroups/',variables('NSGName'))]", + "[variables('virtualNetworkName')]" + ], + "properties": { + "networkSecurityGroup": { + "id": "[resourceId('Microsoft.Network/networkSecurityGroups/',variables('NSGName'))]" + }, + "ipConfigurations": [ + { + "name": "ipconfig1", + "properties": { + "privateIPAllocationMethod": "Static", + "privateIPAddress": "[variables('ips')[copyIndex()]]", + "publicIPAddress": { + "id": "[resourceId('Microsoft.Network/publicIPAddresses/', concat('pip',variables('vms')[copyIndex()]))]" + }, + "subnet": { + "id": "[resourceId('Microsoft.Network/virtualNetworks/subnets',variables('virtualNetworkName'),'Subnet')]" + }, + "loadBalancerBackendAddressPools": "[variables('lbaddrpool')]" + } + } + ] + } + }, + { + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2018-06-01", + "name": "[variables('vms')[copyIndex()]]", + "location": "[parameters('location')]", + "copy": { + "name": "vmLoop", + "count": "[length(variables('vms'))]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts/', variables('storageAccountName'))]", + "[resourceId('Microsoft.Network/networkInterfaces/',concat('nic',variables('vms')[copyIndex()]) )]" + ], + "zones": "[split(string(add(mod(copyIndex(),3),1)), ',')]", + "identity": { + "type": "systemAssigned" + }, + "properties": { + "hardwareProfile": { + "vmSize": "[parameters('vmSize')]" + }, + "osProfile": { + "computerName": "[variables('vms')[copyIndex()]]", + "adminUsername": "[variables('adminUsername')]", + "adminPassword": "[parameters('adminPassword')]", + "linuxConfiguration": "[if(equals(variables('ostype'),'linux'),variables('linuxConfiguration'),'')]" + }, + "storageProfile": "[if(equals(parameters('OS'),'Linux CentOS'),variables('CentosStorageProfile'),variables('windowsStorageProfile'))]", + "networkProfile": { + "networkInterfaces": [ + { + "id": "[resourceId('Microsoft.Network/networkInterfaces/', concat('nic',variables('vms')[copyIndex()]))]" + } + ] + }, + "diagnosticsProfile": { + "bootDiagnostics": { + "enabled": true, + "storageUri": "[reference(resourceId(resourceGroup().name,'Microsoft.Storage/storageAccounts/', variables('storageAccountName'))).primaryEndpoints.blob]" + } + } + } + }, + { + "condition": "[equals(parameters('azurePwsh'),'yes')]", + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2016-07-01", + "name": "[guid(resourceGroup().id,variables('vms')[copyIndex()])]", + "copy": { + "name": "roleLoop", + "count": "[length(variables('vms'))]" + }, + "dependsOn": [ + "[variables('vms')[copyIndex()]]" + ], + "properties": { + "roleDefinitionId": "[variables('NetworkContributor')]", + "principalId": "[reference(concat('Microsoft.Compute/virtualMachines/', variables('vms')[copyIndex()]), '2018-06-01', 'Full').identity.principalId]" + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2018-05-01", + "name": "[concat('safekitInstall',variables('vms')[copyIndex()])]", + "copy": { + "name": "skCopy", + "count": "[length(variables('vms'))]" + }, + "dependsOn": [ + "[variables('vms')[copyIndex()]]" + ], + "properties": { + "mode": "Incremental", + "templateLink": { + "uri": "[variables('sktemplate')]", + "contentVersion": "1.0.0.0" + }, + "parameters": { + "location": { + "value": "[parameters('location')]" + }, + "vmname": { + "value": "[variables('vms')[copyIndex()]]" + }, + "ostype": { + "value": "[variables('ostype')]" + }, + "azurePwsh": { + "value": "[parameters('azurePwsh')]" + }, + "capassword": { + "value": "[parameters('AdminPassword')]" + }, + "safekitFileUri": { + "value": "[parameters('safekitFileUri')]" + }, + "_artifactsLocation": { + "value": "[parameters('_artifactsLocation')]" + }, + "_artifactsLocationSasToken": { + "value": "[parameters('_artifactsLocationSasToken')]" + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2018-05-01", + "name": "safekitClusterConfig", + "dependsOn": [ + "skCopy" + ], + "properties": { + "mode": "Incremental", + "templateLink": { + "uri": "[variables('skclustertemplate')]", + "contentVersion": "1.0.0.0" + }, + "parameters": { + "location": { + "value": "[parameters('location')]" + }, + "ostype": { + "value": "[variables('ostype')]" + }, + "vmname": { + "value": "[variables('vms')[0]]" + }, + "vmList": { + "value": "[variables('vms')]" + }, + "fqdn": { + "value": "[reference(resourceId(resourceGroup().name,'Microsoft.Network/publicIPAddresses/',concat('pip',variables('vms')[0]))).dnsSettings.fqdn]" + }, + "privateIps": { + "value": "[variables('ips')]" + }, + "VMDnsPrefix": { + "value": "[parameters('VMDnsPrefix')]" + }, + "lblist": { + "value": "[if(greater(length(parameters('VIPDnsLabel')),0),reference('optionalVip').outputs.fqdn.value,'')]" + }, + "capassword": { + "value": "[parameters('AdminPassword')]" + }, + "_artifactsLocation": { + "value": "[parameters('_artifactsLocation')]" + }, + "_artifactsLocationSasToken": { + "value": "[parameters('_artifactsLocationSasToken')]" + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2018-05-01", + "name": "safekitModuleConfig", + "dependsOn": [ + "safekitClusterConfig" + ], + "properties": { + "mode": "Incremental", + "templateLink": { + "uri": "[variables('skmoduletemplate')]", + "contentVersion": "1.0.0.0" + }, + "parameters": { + "location": { + "value": "[parameters('location')]" + }, + "ostype": { + "value": "[variables('ostype')]" + }, + "vmname": { + "value": "[variables('vms')[0]]" + }, + "moduleUrl": { + "value": "[parameters('moduleUrl')]" + }, + "moduleName": { + "value": "[parameters('moduleName')]" + }, + "_artifactsLocation": { + "value": "[parameters('_artifactsLocation')]" + }, + "_artifactsLocationSasToken": { + "value": "[parameters('_artifactsLocationSasToken')]" + } + } + } + } + ], + "outputs": { + "adminUser": { + "type": "string", + "value": "[variables('adminUserName')]" + }, + "fqdn": { + "type": "string", + "value": "[reference(resourceId(resourceGroup().name,'Microsoft.Network/publicIPAddresses/',concat('pip',variables('vms')[0]))).dnsSettings.fqdn]" + }, + "Credentials Url": { + "type": "string", + "value": "[concat('https://',reference(resourceId(resourceGroup().name,'Microsoft.Network/publicIPAddresses/',concat('pip',variables('vms')[0]))).dnsSettings.fqdn,':9001/adduser.html')]" + }, + "Credentials Url Login": { + "type": "string", + "value": "user: CA_admin, password: the value of AdminPassword" + }, + "Console Url": { + "type": "string", + "value": "[concat('https://',reference(resourceId(resourceGroup().name,'Microsoft.Network/publicIPAddresses/',concat('pip',variables('vms')[0]))).dnsSettings.fqdn,':9453/deploy.html')]" + }, + "Mosaic URL": { + "type": "string", + "value": "[concat('https://',reference('optionalVip').outputs.fqdn.value,':9453/cgi-bin/mosaic?mode=mosaic&arg0=',parameters('moduleName'))]" + } + } +} \ No newline at end of file diff --git a/safekit-cluster-farm/nestedtemplates/createvip.json b/safekit-cluster-farm/nestedtemplates/createvip.json new file mode 100644 index 000000000000..54a91d4d1b64 --- /dev/null +++ b/safekit-cluster-farm/nestedtemplates/createvip.json @@ -0,0 +1,43 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "VIPDnsLabel": { + "type": "string", + "metadata": { + "description": "Public VIP dns label (optional. If set, an additionnal Standard SKU, unassociated public IP will be created)" + }, + "defaultValue": "" + }, + "location": { + "type": "string", + "metadata": { + "description": "resources location" + } + } + }, + "resources": [ + { + "condition": "[not(empty(parameters('VIPDnsLabel')))]", + "type": "Microsoft.Network/publicIPAddresses", + "apiVersion": "2018-07-01", + "name": "[concat('pip',parameters('VIPDnsLabel'))]", + "location": "[parameters('location')]", + "sku": { + "name": "Standard" + }, + "properties": { + "publicIPAllocationMethod": "Static", + "dnsSettings": { + "domainNameLabel": "[toLower(parameters('VIPDnsLabel'))]" + } + } + } + ], + "outputs": { + "fqdn": { + "type": "string", + "value": "[if(empty(parameters('VIPDnsLabel')),'',reference(concat('pip',parameters('VIPDnsLabel'))).dnsSettings.fqdn)]" + } + } +} \ No newline at end of file diff --git a/safekit-cluster-farm/nestedtemplates/installCluster.json b/safekit-cluster-farm/nestedtemplates/installCluster.json new file mode 100644 index 000000000000..5ef4eb8ef3a3 --- /dev/null +++ b/safekit-cluster-farm/nestedtemplates/installCluster.json @@ -0,0 +1,136 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "vmname": { + "type": "string", + "metadata": { + "description": "vm name" + } + }, + "ostype": { + "type": "string", + "metadata": { + "description": "OS type (windows, linux)" + }, + "defaultValue": "windows" + }, + "vmList": { + "type": "array", + "metadata": { + "description": "vm names" + } + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "first vm public ip name" + } + }, + "privateIps": { + "type": "array", + "metadata": { + "description": "vm private ip list" + } + }, + "VMDnsPrefix":{ + "type": "string", + "metadata": { + "description": "Public VM IP dns label prefix" + } + }, + "lblist": { + "type": "string", + "metadata": { + "description": "dns name of loadbalancer" + }, + "defaultValue": "" + }, + "capassword": { + "type": "securestring", + "metadata": { + "description": "password for CA server access" + } + }, + "location": { + "type": "string", + "metadata": { + "description": "resources location" + } + }, + "_artifactsLocation": { + "type": "string", + "metadata": { + "description": "base URL of deployment resources (template,subtemplates,scripts)" + }, + "defaultValue": "[deployment().properties.templateLink.uri]" + }, + "_artifactsLocationSasToken": { + "type": "securestring", + "metadata": { + "description": "The sasToken required to access _artifactsLocation. When the template is deployed using the accompanying scripts, a sasToken will be automatically generated. Use the defaultValue if the staging location is not secured." + }, + "defaultValue": "" + } + }, + "variables": { + "pwconfscripturi": "[concat(uri(parameters('_artifactsLocation'),'scripts/configCluster.ps1'),parameters('_artifactsLocationSasToken'))]", + "pwcertscripturi": "[concat(uri(parameters('_artifactsLocation'),'scripts/uploadcerts.ps1'),parameters('_artifactsLocationSasToken'))]", + "pwiscripturi": "[concat(uri(parameters('_artifactsLocation'),'scripts/installCluster.ps1'),parameters('_artifactsLocationSasToken'))]", + "shelliscripturi": "[concat(uri(parameters('_artifactsLocation'),'scripts/installCluster.sh'),parameters('_artifactsLocationSasToken'))]", + "domain": "[skip(parameters('fqdn'),indexOf(parameters('fqdn'),'.'))]", + "publicipfmt": "[concat(parameters('VMDnsPrefix'),'%VM%',variables('domain'))]", + "privateiplistarg": "[replace(string(parameters('privateIps')),'\"','')]", + "vmlistarg": "[replace(string(parameters('vmList')),'\"','')]", + "windowsfileuris": [ + "[variables('pwcertscripturi')]", + "[variables('pwconfscripturi')]", + "[variables('pwiscripturi')]" + ], + "linuxfileuris": [ + "[variables('pwcertscripturi')]", + "[variables('pwconfscripturi')]", + "[variables('shelliscripturi')]" + ], + "properties": { + "windows": { + "publisher": "Microsoft.Compute", + "type": "CustomScriptExtension", + "typeHandlerVersion": "1.9", + "autoUpgradeMinorVersion": true, + "settings": { + "fileUris": "[variables('windowsfileuris')]" + }, + "protectedSettings": { + "commandToExecute": "[concat('powershell -ExecutionPolicy Unrestricted -File .\\InstallCluster.ps1 -vmlist \"', variables('vmlistarg'),'\" -publicipfmt \"',variables('publicipfmt'),'\" -privateiplist \"',variables('privateiplistarg'),'\" -lblist \"',parameters('lblist'),'\" -Passwd \"',parameters('capassword'),'\"')]" + } + }, + "linux": { + "publisher": "Microsoft.Azure.Extensions", + "type": "CustomScript", + "typeHandlerVersion": "2.0", + "autoUpgradeMinorVersion": true, + "settings": { + "skipDos2Unix": false, + "timestamp": 1, + "fileUris": "[variables('linuxfileuris')]" + }, + "protectedSettings": { + "commandToExecute": "[concat('sh installCluster.sh \"',variables('vmlistarg'),'\" \"',variables('publicipfmt'),'\" \"',variables('privateiplistarg'),'\" \"',parameters('lblist'),'\" \"',parameters('capassword'),'\"') ]" + } + } + } + }, + "resources": [ + { + "name": "[concat(parameters('vmname'),'/safekit')]", + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2018-06-01", + "location": "[parameters('location')]", + "properties": "[variables('properties')[parameters('ostype')]]" + } + ], + "outputs": { + + } +} \ No newline at end of file diff --git a/safekit-cluster-farm/nestedtemplates/installModule.json b/safekit-cluster-farm/nestedtemplates/installModule.json new file mode 100644 index 000000000000..116d3d93ad9b --- /dev/null +++ b/safekit-cluster-farm/nestedtemplates/installModule.json @@ -0,0 +1,101 @@ + { + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "vmname": { + "type": "string", + "metadata": { + "description": "vm name" + } + }, + "ostype":{ + "type": "string", + "metadata": { + "description": "OS type (windows, linux)" + }, + "defaultValue": "windows" + }, + "moduleUrl": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "url of the application module to install on all nodes" + } + }, + "moduleName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "url of the application module to install on all nodes" + } + }, + "location":{ + "type": "string", + "metadata":{ + "description": "resources location" + } + }, + "_artifactsLocation":{ + "type":"string", + "metadata":{ + "description":"base URL of deployment resources (template,subtemplates,scripts)" + }, + "defaultValue":"[deployment().properties.templateLink.uri]" + }, + "_artifactsLocationSasToken": { + "type": "securestring", + "metadata": { + "description": "The sasToken required to access _artifactsLocation. When the template is deployed using the accompanying scripts, a sasToken will be automatically generated. Use the defaultValue if the staging location is not secured." + }, + "defaultValue": "" + } + }, + "variables":{ + "installModuleuri":"[concat(uri(parameters('_artifactsLocation'),'scripts/installModule.ps1'),parameters('_artifactsLocationSasToken'))]", + "properties" : { + "windows": { + "publisher": "Microsoft.Compute", + "type": "CustomScriptExtension", + "typeHandlerVersion": "1.9", + "autoUpgradeMinorVersion": true, + "settings": { + "fileUris": [ + "[parameters('moduleUrl')]", + "[variables('installModuleuri')]" + ] + }, + "protectedSettings":{ + "commandToExecute": "[concat('powershell -ExecutionPolicy Unrestricted -File .\\installModule.ps1 -safekitcmd C:/safekit/safekit -MName \"',parameters('moduleName'),'\"')]" + } + }, + "linux" : { + "publisher": "Microsoft.Azure.Extensions", + "type": "CustomScript", + "typeHandlerVersion": "2.0", + "autoUpgradeMinorVersion": true, + "settings": { + "skipDos2Unix":false, + "timestamp": 1, + "fileUris": [ + "[parameters('moduleUrl')]", + "[variables('installModuleuri')]" + ] + }, + "protectedSettings":{ + "commandToExecute": "[concat('pwsh ./installModule.ps1 -safekitcmd /opt/safekit/safekit -MName \"',parameters('moduleName'),'\"')]" + } + } + } + }, + "resources":[ + { + "name": "[concat(parameters('vmname'),'/safekit')]", + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2018-06-01", + "location": "[parameters('location')]", + "properties": "[variables('properties')[parameters('ostype')]]" + } + ], + "outputs": {} + } + \ No newline at end of file diff --git a/safekit-cluster-farm/nestedtemplates/safekitdepl.json b/safekit-cluster-farm/nestedtemplates/safekitdepl.json new file mode 100644 index 000000000000..0ae2b9b1391e --- /dev/null +++ b/safekit-cluster-farm/nestedtemplates/safekitdepl.json @@ -0,0 +1,111 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "vmname": { + "type": "string", + "metadata": { + "description": "vm name" + } + }, + "ostype": { + "type": "string", + "metadata": { + "description": "os type" + }, + "defaultValue": "windows" + }, + "capassword": { + "type": "securestring", + "metadata": { + "description": "password for CA server access" + } + }, + "azurePwsh": { + "type": "string", + "metadata": { + "description": "install azure powershell module (optional)" + }, + "defaultValue": "no", + "allowedValues": [ + "yes", + "no" + ] + }, + "safekitFileUri": { + "type": "string", + "metadata": { + "description": "url of safekit package" + }, + "defaultValue": "" + }, + "location": { + "type": "string", + "metadata": { + "description": "resources location" + } + }, + "_artifactsLocation": { + "type": "string", + "metadata": { + "description": "base URL of deployment resources (template,subtemplates,scripts)" + }, + "defaultValue": "[deployment().properties.templateLink.uri]" + }, + "_artifactsLocationSasToken": { + "type": "securestring", + "metadata": { + "description": "The sasToken required to access _artifactsLocation. When the template is deployed using the accompanying scripts, a sasToken will be automatically generated. Use the defaultValue if the staging location is not secured." + }, + "defaultValue": "" + } + }, + "variables": { + "pwazrmuri": "[concat(uri(parameters('_artifactsLocation'),'scripts/installAzureRM.ps1'),parameters('_artifactsLocationSasToken'))]", + "pwscripturi": "[concat(uri(parameters('_artifactsLocation'),'scripts/InstallSafeKit.ps1'),parameters('_artifactsLocationSasToken'))]", + "skpkg": "[last(split(parameters('safekitFileUri'),'/'))]", + "shellscripturi": "[concat(uri(parameters('_artifactsLocation'),'scripts/InstallSafeKit.sh'),parameters('_artifactsLocationSasToken'))]", + "skuri": "[parameters('safekitFileUri')]", + "fileUrisW": "[if(equals(parameters('azurePwsh'),'yes'),createArray(variables('skuri'),variables('pwscripturi'),variables('pwazrmuri')),createArray(variables('skuri'),variables('pwscripturi')))]", + "fileUrisL": "[if(equals(parameters('azurePwsh'),'yes'),createArray(variables('skuri'),variables('shellscripturi'),variables('pwazrmuri')),createArray(variables('skuri'),variables('shellscripturi')))]", + "properties": { + "windows": { + "publisher": "Microsoft.Compute", + "type": "CustomScriptExtension", + "typeHandlerVersion": "1.9", + "autoUpgradeMinorVersion": true, + "settings": { + "fileUris": "[variables('fileUrisW')]" + }, + "protectedSettings":{ + "commandToExecute": "[concat('powershell -ExecutionPolicy Unrestricted -File .\\InstallSafekit.ps1 -SkFile ',variables('skpkg'),' -Passwd \"',parameters('capassword'),'\"')]" + } + }, + "linux": { + "publisher": "Microsoft.Azure.Extensions", + "type": "CustomScript", + "typeHandlerVersion": "2.0", + "autoUpgradeMinorVersion": true, + "settings": { + "skipDos2Unix": false, + "fileUris": "[variables('fileUrisL')]" + }, + "protectedSettings": { + "commandToExecute": "[concat('sh InstallSafeKit.sh ./', variables('skpkg'), ' \"',parameters('capassword'),'\"')]" + } + } + } + }, + "resources": [ + { + "name": "[concat(parameters('vmname'),'/safekit')]", + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2018-06-01", + "location": "[parameters('location')]", + "properties": "[variables('properties')[parameters('ostype')]]" + } + ], + "outputs": { + + } +} \ No newline at end of file diff --git a/safekit-cluster-farm/scripts/InstallSafeKit.ps1 b/safekit-cluster-farm/scripts/InstallSafeKit.ps1 new file mode 100644 index 000000000000..39c056ba2a29 --- /dev/null +++ b/safekit-cluster-farm/scripts/InstallSafeKit.ps1 @@ -0,0 +1,61 @@ +param( + [string] $SkFile, + [string] $Passwd +) + +function Log { + param( + [string] $m + ) + + $Stamp = (Get-Date).toString("yyyy/MM/dd HH:mm:ss") + Add-Content ./installsk.log "$stamp [InstallSafeKit.ps1] $m" +} + +Log $vmlist +Log $modname + +if( ! (Test-Path -Path "/safekit" )) { + +if( ! (Test-Path -Path "$skFile" )){ + + Log "Download $SkFile failed. Check calling template fileUris property." + exit -1 +} + +Log "Installing ..." +$arglist = @( + "/i", + "$SkFile", + "/qn", + "/l*vx", + "loginst.txt", + "DODESKTOP='0'" +) + +Start-Process msiexec.exe -ArgumentList $arglist -Wait +Log "Install Azure RM" + +if(Test-Path -Path "./installAzureRm.ps1") { + & ./installAzureRm.ps1 +} + +Log "Applying firewall rules" +& \safekit\private\bin\firewallcfg.cmd add + +Log "Starting CA helper service" +$cwd = Get-Location +try{ + cd /safekit/web/bin + & ./startcaserv.cmd "$Passwd" +}finally{ + set-location $cwd +} + +} +else{ + Log "safekit already installed" +} +Log "end of script" + + diff --git a/safekit-cluster-farm/scripts/InstallSafeKit.sh b/safekit-cluster-farm/scripts/InstallSafeKit.sh new file mode 100644 index 000000000000..2a7a0ad3defc --- /dev/null +++ b/safekit-cluster-farm/scripts/InstallSafeKit.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +echo "Install SafeKit from `ls ./*.bin`" + + +chmod +x ./safekit*.bin +./safekit*.bin + + +yum -y localinstall ./safekit*.rpm +#rm ./safekit*.bin ./safekit*.rpm + +echo "Install powershell" +# Register the Microsoft RedHat repository +curl https://packages.microsoft.com/config/rhel/7/prod.repo | sudo tee /etc/yum.repos.d/microsoft.repo +yum update powershell +# Install PowerShell +yum install -y powershell +if [ -f "installAzureRM.ps1" ]; then + pwsh ./installAzureRM.ps1 -linux +fi +echo "starting CA helper service" +cd /opt/safekit/web/bin +./startcaserv "$2" \ No newline at end of file diff --git a/safekit-cluster-farm/scripts/UpdateSafeKit.sh b/safekit-cluster-farm/scripts/UpdateSafeKit.sh new file mode 100644 index 000000000000..a97b094a5c4b --- /dev/null +++ b/safekit-cluster-farm/scripts/UpdateSafeKit.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +/opt/safekit/safekit shutdown +/opt/safekit/safekit uninstall + +echo "Install SafeKit" +yum -y localinstall $1 diff --git a/safekit-cluster-farm/scripts/cfgFarm.ps1 b/safekit-cluster-farm/scripts/cfgFarm.ps1 new file mode 100644 index 000000000000..06d0e111b8b2 --- /dev/null +++ b/safekit-cluster-farm/scripts/cfgFarm.ps1 @@ -0,0 +1,39 @@ +param( + [string] $safekitcmd, + [string] $safekitmod, + [string] $MName +) + + + +function Log { + param( + [string] $m + ) + + $Stamp = (Get-Date).toString("yyyy/MM/dd HH:mm:ss") + Add-Content ./installsk.log "$stamp $m" +} + +Log $safekitcmd +Log $MName + +if ($MName){ + + $ucfg = [Xml] (Get-Content "$safekitmod/$MName/conf/userconfig.xml") + $ucfg.safe.service.farm.lan.name="default" + + + $ucfg.Save("$safekitmod/$MName/conf/userconfig.xml") + Log "$ucfg.OuterXml" + + + $res = & $safekitcmd -H "*" -E $MName + Log "$MName => $res" + + & $safekitcmd -H "*" start -m $MName +} + +Log "end of script" + + diff --git a/safekit-cluster-farm/scripts/configCluster.ps1 b/safekit-cluster-farm/scripts/configCluster.ps1 new file mode 100644 index 000000000000..dace9f62f759 --- /dev/null +++ b/safekit-cluster-farm/scripts/configCluster.ps1 @@ -0,0 +1,88 @@ +param( + [string] $publicipfmt, + [string] $privateiplist, + [string] $vmlist, + [string] $lblist, + [string] $Passwd +) + +$safekitcmd=$env:SAFEKITCMD +$safevar=$env:SAFEVAR +$safewebconf=$env:SAFEWEBCONF +$logdir=$pwd + +function Log { + param( + [string] $m + ) + + $Stamp = (Get-Date).toString("yyyy/MM/dd HH:mm:ss") + Add-Content "$logdir/installsk.log" "$stamp [configCluster.ps1] $m" +} + +Log $vmlist +Log $publicipfmt +Log $privateiplist +Log $lblist + +if ($vmlist){ + $vmargs=@() + $lbargs=@() + $privateipargs=@() + $targets=@() + + "[" | Out-File -Encoding ASCII -FilePath "$safewebconf/ipnames.json" + "[" | Out-File -Encoding ASCII -FilePath "$safewebconf/ipv4.json" + + + $vmargs += ([regex]::Replace($vmlist,'[\[\]]','') -split ',') + $privateipargs += ([regex]::Replace($privateiplist,'[\[\]]','') -split ',') + if($lblist){ + $lbargs += ($lblist -split ',') + } + Log "configuring cluster.xml and certificates input files" + + $str = "" + if($publicipfmt){ + $str +="" + + for ($i=0; $i -lt $vmargs.Length; $i++){ + $dnsname=$($publicipfmt).Replace('%VM%',$($vmargs[$i])).ToLower() + $str += "" + "`"$dnsname`"," | Out-File -Append -Encoding ASCII -FilePath "$safewebconf/ipnames.json" + } + + $str += "" + } + + for($i=0; $i -lt $lbargs.Length; $i++){ + $dnsname = $($lbargs[$i]) + if($dnsname.Length){ + "`"$dnsname`"," | Out-File -Append -Encoding ASCII -FilePath "$safewebconf/ipnames.json" + } + } + "null]" | Out-File -Append -Encoding ASCII -FilePath "$safewebconf/ipnames.json" + + + $str +="" + for ($i=0; $i -lt $vmargs.Length; $i++){ + $str += "" + "`"$($privateipargs[$i])`"," | Out-File -Append -Encoding ASCII -FilePath "$safewebconf/ipv4.json" + $targets += $($privateipargs[$i]) + } + "null]" | Out-File -Append -Encoding ASCII -FilePath "$safewebconf/ipv4.json" + + $str += "" + $str | Out-File -Encoding utf8 $safevar\cluster\cluster.xml + & $safekitcmd cluster config 2>&1 + $res= & $safekitcmd -H "[http],*" -G 2>&1 + Log "result = $res" + if( Test-Path "./uploadcerts.ps1") { + & ./uploadcerts.ps1 -skbase "$env:SAFEBASE" -targets $targets -userpwd "CA_admin:$Passwd" + } +} + +Log "end of script" + + + diff --git a/safekit-cluster-farm/scripts/installAzureRM.ps1 b/safekit-cluster-farm/scripts/installAzureRM.ps1 new file mode 100644 index 000000000000..e808b410004b --- /dev/null +++ b/safekit-cluster-farm/scripts/installAzureRM.ps1 @@ -0,0 +1,17 @@ +param( + [switch] $linux=$false +) + +if ( $linux ) { + +Install-Module AzureRM.NetCore -SkipPublisherCheck -Force +Import-Module AzureRM.Netcore + +}else{ + +Install-PackageProvider -name Nuget -MinimumVersion 2.8.5.201 -Force +Install-Module AzureRM -SkipPublisherCheck -Force + +Import-Module AzureRM + +} \ No newline at end of file diff --git a/safekit-cluster-farm/scripts/installCluster.ps1 b/safekit-cluster-farm/scripts/installCluster.ps1 new file mode 100644 index 000000000000..270c680fdadd --- /dev/null +++ b/safekit-cluster-farm/scripts/installCluster.ps1 @@ -0,0 +1,33 @@ +param( + [string] $publicipfmt, + [string] $privateiplist, + [string] $vmlist, + [string] $lblist, + [string] $Passwd +) + +$targetDir = "." + +function Log { + param( + [string] $m + ) + + $Stamp = (Get-Date).toString("yyyy/MM/dd HH:mm:ss") + Add-Content ./installsk.log "$stamp [installCluster.ps1] $m" +} + +Log $vmlist +Log $publicipfmt +Log $privateiplist + +$env:SAFEBASE="/safekit" +$env:SAFEKITCMD="/safekit/safekit.exe" +$env:SAFEVAR="/safekit/var" +$env:SAFEWEBCONF="/safekit/web/conf" + +& ./configCluster.ps1 -vmlist $vmlist -publicipfmt $publicipfmt -privateiplist $privateiplist -lblist $lblist -Passwd $Passwd + +Log "end of script" + + diff --git a/safekit-cluster-farm/scripts/installCluster.sh b/safekit-cluster-farm/scripts/installCluster.sh new file mode 100644 index 000000000000..b02640e0a772 --- /dev/null +++ b/safekit-cluster-farm/scripts/installCluster.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +echo $* + +# Start PowerShell config script +export SAFEKITCMD="/opt/safekit/safekit" +export SAFEVAR="/var/safekit" +export SAFEWEBCONF="/opt/safekit/web/conf" +export SAFEBASE="/opt/safekit" +export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/opt/safekit/private/bin" +pwsh ./configCluster.ps1 -vmlist "$1" -publicipfmt "$2" -privateiplist "$3" -lblist "$4" -Passwd "$5" diff --git a/safekit-cluster-farm/scripts/installModule.ps1 b/safekit-cluster-farm/scripts/installModule.ps1 new file mode 100644 index 000000000000..890150f36e4c --- /dev/null +++ b/safekit-cluster-farm/scripts/installModule.ps1 @@ -0,0 +1,31 @@ +param( + [string]$safekitcmd, + [string]$MName, + [string]$modulepkg, + [string]$modulecfgscript +) + +if( $modulepkg ){ + $module = $modulepkg.Split(',') | Get-ChildItem +} +else{ + $module = [array] (Get-ChildItem "*.safe") +} + +if($module.Length){ + $module[0] | %{ + if($_){ + if($MName -and ($($MName.Length) -gt 0)) { + $modulename=$MName + }else{ + $modulename = $($_.name.Replace(".safe","")) + } + + & $safekitcmd module install -m $modulename $_.fullname + if($modulecfgscript -and (Test-Path "./$modulecfgscript")){ + & ./$modulecfgscript + } + & $safekitcmd -H "*" -E $modulename + } + } +} \ No newline at end of file diff --git a/safekit-cluster-farm/scripts/uploadcerts.ps1 b/safekit-cluster-farm/scripts/uploadcerts.ps1 new file mode 100644 index 000000000000..6201a6353834 --- /dev/null +++ b/safekit-cluster-farm/scripts/uploadcerts.ps1 @@ -0,0 +1,47 @@ +param( + [string[]] $targets, + [string] $userpwd="CA_admin:CA_admin", + [string] $skbase="/safekit" +) + +$curlcmd="$skbase/private/bin/curl.exe" +$safeweb="$skbase/web" + +if (Test-Path "$safeweb/conf/ca"){ + Write-Host "CA already initialized, skipping certificate generation" +}else{ +$caname = "/CN=Safekit CA" + +try{ + $meta = Invoke-RestMethod -Headers @{"Metadata"="true"} -URI "http://169.254.169.254/metadata/instance?api-version=2017-08-01" -Method get + if($meta) { + $caname = "/CN=SafeKit CA for Azure $($meta.compute.resourceGroupName) cluster" + } +}catch{} + +$cwd = Get-Location +try{ + cd "$safeweb/bin" + & ./initssl sca "$caname" + & $curlcmd "-k" "-u" "$userpwd" "-X" "POST" "-F" "action=swhttps" "https://localhost:9001/caserv" +}finally{ + cd $cwd +} +} + +for($i=1; $i -lt $targets.Length; $i++) { + $targetip = $($targets[$i]) + + Write-Host "uploading cert to $targetip" + + & $curlcmd "-k" "-u" "$userpwd" "-X" "POST" "-F" "file=@$safeweb/conf/cacert.crt" "-F" "action=import" "-F" "target=T_CA" "-F" "add=yes" "https://$($targetip):9001/caserv" + & $curlcmd "-k" "-u" "$userpwd" "-X" "POST" "-F" "file=@$safeweb/conf/cacert.crt" "-F" "action=import" "-F" "target=T_CCA" "-F" "add=yes" "https://$($targetip):9001/caserv" + & $curlcmd "-k" "-u" "$userpwd" "-X" "POST" "-F" "file=@$safeweb/conf/server.crt" "-F" "action=import" "-F" "target=T_SC" "-F" "add=yes" "https://$($targetip):9001/caserv" + & $curlcmd "-k" "-u" "$userpwd" "-X" "POST" "-F" "file=@$safeweb/conf/server.key" "-F" "action=import" "-F" "target=T_SK" "-F" "add=yes" "https://$($targetip):9001/caserv" + & $curlcmd "-k" "-u" "$userpwd" "-X" "POST" "-F" "file=@$safeweb/conf/admin.crt" "-F" "action=import" "-F" "target=T_CC" "-F" "add=yes" "https://$($targetip):9001/caserv" + & $curlcmd "-k" "-u" "$userpwd" "-X" "POST" "-F" "file=@$safeweb/conf/admin.key" "-F" "action=import" "-F" "target=T_CK" "-F" "add=yes" "https://$($targetip):9001/caserv" + & $curlcmd "-k" "-u" "$userpwd" "-X" "POST" "-F" "file=@$safeweb/conf/proxy.crtkey" "-F" "action=import" "-F" "target=T_PCCK" "-F" "add=yes" "https://$($targetip):9001/caserv" + & $curlcmd "-k" "-u" "$userpwd" "-X" "POST" "-F" "file=@$safeweb/conf/sslclient.crl" "-F" "action=import" "-F" "target=T_CRL" "-F" "add=yes" "https://$($targetip):9001/caserv" + & $curlcmd "-k" "-u" "$userpwd" "-X" "POST" "-F" "action=swhttps" "https://$($targetip):9001/caserv" + & $curlcmd "-k" "-u" "$userpwd" "-X" "POST" "-F" "action=shutdown" "https://$($targetip):9001/caserv" +} \ No newline at end of file From 6a4c541b91861eabbea5bf34d007834519a7e388 Mon Sep 17 00:00:00 2001 From: d6p <43806862+d6p@users.noreply.github.com> Date: Mon, 14 Jan 2019 17:35:24 +0100 Subject: [PATCH 02/66] fix date format --- safekit-cluster-farm/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/safekit-cluster-farm/metadata.json b/safekit-cluster-farm/metadata.json index b690f0fee84c..1175d52fb538 100644 --- a/safekit-cluster-farm/metadata.json +++ b/safekit-cluster-farm/metadata.json @@ -5,7 +5,7 @@ "description": "This template deploys a load balancing cluster with failover on 2 to 4 Windows or Linux VMs in different availability zones", "summary": "Evidian SafeKit farm cluster on Windows or Linux", "githubUsername": "d6p", - "dateUpdated": "2019-1-14" + "dateUpdated": "2019-01-14" } From 92275bf59101a46535f83a0eb98fbe310fd9bd50 Mon Sep 17 00:00:00 2001 From: d6p <43806862+d6p@users.noreply.github.com> Date: Tue, 22 Jan 2019 12:56:28 +0100 Subject: [PATCH 03/66] implement requested changes --- safekit-cluster-farm/README.md | 15 +++++++-------- safekit-cluster-farm/azuredeploy.json | 7 +++++-- .../nestedtemplates/cfgFarm.json | 6 ++---- .../nestedtemplates/cluster.json | 16 +++++++--------- .../nestedtemplates/installCluster.json | 6 ++---- .../nestedtemplates/installModule.json | 6 ++---- .../nestedtemplates/safekitdepl.json | 6 ++---- 7 files changed, 27 insertions(+), 35 deletions(-) diff --git a/safekit-cluster-farm/README.md b/safekit-cluster-farm/README.md index b9fb4b4e44a0..40f61827d253 100644 --- a/safekit-cluster-farm/README.md +++ b/safekit-cluster-farm/README.md @@ -4,8 +4,6 @@ -`Tags: load balancing, cluster, failover, high availability, business continuity, disaster recovery, evidian, safekit, farm` - * [Description](#description) * [Deployed resources](#resources) * [How to use](#use) @@ -17,12 +15,12 @@ On the previous figure, -* the critical application is running in all servers of the farm -* users are connected to a virtual IP address which is configured in the Azure load balancer -* SafeKit brings a generic health probe for the load balancer When the farm module is stopped in a server, the health probe returns NOK to the load balancer which stops the load balancing of requests to the server. The same behavior happens when there is a **hardware failure** -* in each server, SafeKit monitors the critical application with process checkers and custom checkers -* SafeKit restarts automatically the critical application in a server when there is a **software failure** thanks to restart scripts -* a connector for the SafeKit web console is installed in each server. Thus, the load balancing cluster can be managed in a very simple way to avoid **human errors** +* the critical application is running in all servers of the farm, +* users are connected to a virtual IP address which is configured in the Azure load balancer. +SafeKit brings a generic health probe for the load balancer. When the farm module is stopped in a server, the health probe returns NOK to the load balancer which stops the load balancing of requests to the server. The same behavior happens when there is a **hardware failure**. +* in each server, SafeKit monitors the critical application with process checkers and custom checkers; +* SafeKit restarts automatically the critical application in a server when there is a **software failure** thanks to the restart scripts; +* a connector for the SafeKit web console is installed in each server. Thus, the load balancing cluster can be managed in a very simple way to avoid **human errors**. ## Deployed resources @@ -58,3 +56,4 @@ After deployment, go to the resource group's 'Microsoft.Template' deployment out * [Azure: The Simplest Load Balancing Cluster with Failover](https://www.evidian.com/products/high-availability-software-for-application-clustering/azure-load-balancing-cluster-failover/) * [Azure: The Simplest High Availability Cluster with Synchronous Replication and Failover](https://www.evidian.com/products/high-availability-software-for-application-clustering/azure-high-availability-cluster-synchronous-replication-failover/) +`Tags: load balancing, cluster, failover, high availability, business continuity, disaster recovery, evidian, safekit, farm` \ No newline at end of file diff --git a/safekit-cluster-farm/azuredeploy.json b/safekit-cluster-farm/azuredeploy.json index afa8655321f9..00c8128dde67 100644 --- a/safekit-cluster-farm/azuredeploy.json +++ b/safekit-cluster-farm/azuredeploy.json @@ -49,13 +49,15 @@ "type": "string", "metadata": { "description": "Public VIP dns label. VIP fqdn will be like ..cloudapp.azure.com and must be globally unique." - } + }, + "defaultValue": "[concat(uniqueString(resourceGroup().id),'vip')]" }, "VMDnsPrefix": { "type": "string", "metadata": { "description": "Public VM IP dns label prefix. VM fqdn will be like vm..cloudapp.azure.com and must be unique." - } + }, + "defaultValue": "[uniqueString(resourceGroup().id)]" }, "azurePwsh": { "type": "string", @@ -78,6 +80,7 @@ "eastus2", "francecentral", "northeurope", + "southeastasia", "westeurope", "westus2" ] diff --git a/safekit-cluster-farm/nestedtemplates/cfgFarm.json b/safekit-cluster-farm/nestedtemplates/cfgFarm.json index 005abe9fa7d5..3114b3b444a0 100644 --- a/safekit-cluster-farm/nestedtemplates/cfgFarm.json +++ b/safekit-cluster-farm/nestedtemplates/cfgFarm.json @@ -32,15 +32,13 @@ "type": "string", "metadata": { "description": "base URL of deployment resources (template,subtemplates,scripts)" - }, - "defaultValue": "[deployment().properties.templateLink.uri]" + } }, "_artifactsLocationSasToken": { "type": "securestring", "metadata": { "description": "The sasToken required to access _artifactsLocation. When the template is deployed using the accompanying scripts, a sasToken will be automatically generated. Use the defaultValue if the staging location is not secured." - }, - "defaultValue": "" + } } }, "variables": { diff --git a/safekit-cluster-farm/nestedtemplates/cluster.json b/safekit-cluster-farm/nestedtemplates/cluster.json index db12328de3dd..78f4ca8a5abe 100644 --- a/safekit-cluster-farm/nestedtemplates/cluster.json +++ b/safekit-cluster-farm/nestedtemplates/cluster.json @@ -107,15 +107,13 @@ "type": "string", "metadata": { "description": "base URL of deployment resources (template,subtemplates,scripts)" - }, - "defaultValue": "[deployment().properties.templateLink.uri]" + } }, "_artifactsLocationSasToken": { "type": "securestring", "metadata": { "description": "The sasToken required to access _artifactsLocation. When the template is deployed using the accompanying scripts, a sasToken will be automatically generated. Use the defaultValue if the staging location is not secured." - }, - "defaultValue": "" + } } }, "variables": { @@ -468,7 +466,7 @@ "diagnosticsProfile": { "bootDiagnostics": { "enabled": true, - "storageUri": "[reference(resourceId(resourceGroup().name,'Microsoft.Storage/storageAccounts/', variables('storageAccountName'))).primaryEndpoints.blob]" + "storageUri": "[reference(resourceId('Microsoft.Storage/storageAccounts/', variables('storageAccountName'))).primaryEndpoints.blob]" } } } @@ -562,7 +560,7 @@ "value": "[variables('vms')]" }, "fqdn": { - "value": "[reference(resourceId(resourceGroup().name,'Microsoft.Network/publicIPAddresses/',concat('pip',variables('vms')[0]))).dnsSettings.fqdn]" + "value": "[reference(resourceId('Microsoft.Network/publicIPAddresses/',concat('pip',variables('vms')[0]))).dnsSettings.fqdn]" }, "privateIps": { "value": "[variables('ips')]" @@ -631,11 +629,11 @@ }, "fqdn": { "type": "string", - "value": "[reference(resourceId(resourceGroup().name,'Microsoft.Network/publicIPAddresses/',concat('pip',variables('vms')[0]))).dnsSettings.fqdn]" + "value": "[reference(resourceId('Microsoft.Network/publicIPAddresses/',concat('pip',variables('vms')[0]))).dnsSettings.fqdn]" }, "Credentials Url": { "type": "string", - "value": "[concat('https://',reference(resourceId(resourceGroup().name,'Microsoft.Network/publicIPAddresses/',concat('pip',variables('vms')[0]))).dnsSettings.fqdn,':9001/adduser.html')]" + "value": "[concat('https://',reference(resourceId('Microsoft.Network/publicIPAddresses/',concat('pip',variables('vms')[0]))).dnsSettings.fqdn,':9001/adduser.html')]" }, "Credentials Url Login": { "type": "string", @@ -643,7 +641,7 @@ }, "Console Url": { "type": "string", - "value": "[concat('https://',reference(resourceId(resourceGroup().name,'Microsoft.Network/publicIPAddresses/',concat('pip',variables('vms')[0]))).dnsSettings.fqdn,':9453/deploy.html')]" + "value": "[concat('https://',reference(resourceId('Microsoft.Network/publicIPAddresses/',concat('pip',variables('vms')[0]))).dnsSettings.fqdn,':9453/deploy.html')]" }, "Mosaic URL": { "type": "string", diff --git a/safekit-cluster-farm/nestedtemplates/installCluster.json b/safekit-cluster-farm/nestedtemplates/installCluster.json index 5ef4eb8ef3a3..8b3d41f51960 100644 --- a/safekit-cluster-farm/nestedtemplates/installCluster.json +++ b/safekit-cluster-farm/nestedtemplates/installCluster.json @@ -62,15 +62,13 @@ "type": "string", "metadata": { "description": "base URL of deployment resources (template,subtemplates,scripts)" - }, - "defaultValue": "[deployment().properties.templateLink.uri]" + } }, "_artifactsLocationSasToken": { "type": "securestring", "metadata": { "description": "The sasToken required to access _artifactsLocation. When the template is deployed using the accompanying scripts, a sasToken will be automatically generated. Use the defaultValue if the staging location is not secured." - }, - "defaultValue": "" + } } }, "variables": { diff --git a/safekit-cluster-farm/nestedtemplates/installModule.json b/safekit-cluster-farm/nestedtemplates/installModule.json index 116d3d93ad9b..d925084306b6 100644 --- a/safekit-cluster-farm/nestedtemplates/installModule.json +++ b/safekit-cluster-farm/nestedtemplates/installModule.json @@ -39,15 +39,13 @@ "type":"string", "metadata":{ "description":"base URL of deployment resources (template,subtemplates,scripts)" - }, - "defaultValue":"[deployment().properties.templateLink.uri]" + } }, "_artifactsLocationSasToken": { "type": "securestring", "metadata": { "description": "The sasToken required to access _artifactsLocation. When the template is deployed using the accompanying scripts, a sasToken will be automatically generated. Use the defaultValue if the staging location is not secured." - }, - "defaultValue": "" + } } }, "variables":{ diff --git a/safekit-cluster-farm/nestedtemplates/safekitdepl.json b/safekit-cluster-farm/nestedtemplates/safekitdepl.json index 0ae2b9b1391e..852b489f0d65 100644 --- a/safekit-cluster-farm/nestedtemplates/safekitdepl.json +++ b/safekit-cluster-farm/nestedtemplates/safekitdepl.json @@ -49,15 +49,13 @@ "type": "string", "metadata": { "description": "base URL of deployment resources (template,subtemplates,scripts)" - }, - "defaultValue": "[deployment().properties.templateLink.uri]" + } }, "_artifactsLocationSasToken": { "type": "securestring", "metadata": { "description": "The sasToken required to access _artifactsLocation. When the template is deployed using the accompanying scripts, a sasToken will be automatically generated. Use the defaultValue if the staging location is not secured." - }, - "defaultValue": "" + } } }, "variables": { From 731288729ca9eceb2d6a92bdb7016b3b9a28078f Mon Sep 17 00:00:00 2001 From: Nerya Cohen Date: Tue, 22 Jan 2019 16:18:21 +0200 Subject: [PATCH 04/66] add template files --- .../README.md | 14 +++ .../azuredeploy.json | 87 +++++++++++++++++++ .../azuredeploy.parameters.json | 21 +++++ .../metadata.json | 9 ++ 4 files changed, 131 insertions(+) create mode 100644 201-storage-advanced-threat-protection-create/README.md create mode 100644 201-storage-advanced-threat-protection-create/azuredeploy.json create mode 100644 201-storage-advanced-threat-protection-create/azuredeploy.parameters.json create mode 100644 201-storage-advanced-threat-protection-create/metadata.json diff --git a/201-storage-advanced-threat-protection-create/README.md b/201-storage-advanced-threat-protection-create/README.md new file mode 100644 index 000000000000..a5703597362d --- /dev/null +++ b/201-storage-advanced-threat-protection-create/README.md @@ -0,0 +1,14 @@ +# Deploy an Azure Storage Account with Advanced Threat Protection enabled + + + + + + + + +This template allows you to deploy an Azure Storage Account with Advanced Threat Protection enabled. + +Storage Advanced Threat Protection is a unified package for advanced Storage security capabilities. + +For more information on Storage Advanced Threat Protection, see the [official documentation]( https://docs.microsoft.com/en-us/azure/storage/common/storage-advanced-threat-protection). \ No newline at end of file diff --git a/201-storage-advanced-threat-protection-create/azuredeploy.json b/201-storage-advanced-threat-protection-create/azuredeploy.json new file mode 100644 index 000000000000..92e6a70294fe --- /dev/null +++ b/201-storage-advanced-threat-protection-create/azuredeploy.json @@ -0,0 +1,87 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "storageAccountName": { + "type": "string", + "defaultValue": "storagewatp1", + "metadata": { + "description": "The name must be unique across all existing storage account names in Azure. It must be 3 to 24 characters long, and can contain only lowercase letters and numbers." + } + }, + "storageAccountLocation": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Storage account location, default is same as resource group location." + } + }, + "storageAccountType": { + "type": "string", + "defaultValue": "StorageV2", + "allowedValues": [ + "StorageV2", + "Storage" + ], + "metadata": { + "description": "Storage Account type, for more info see 'https://docs.microsoft.com/en-us/azure/storage/common/storage-account-overview'." + } + }, + "storageAccountReplication": { + "type": "string", + "defaultValue": "Standard_LRS", + "allowedValues": [ + "Standard_LRS", + "Standard_GRS", + "Standard_ZRS", + "Premium_LRS" + ], + "metadata": { + "description": "Storage Account replication, for more info see 'https://docs.microsoft.com/en-us/azure/storage/common/storage-redundancy'." + } + }, + "advancedThreatProtectionEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Enable or disable Advanced Threat Protection." + } + } + }, + "variables": { + "storageAccountName": "[parameters('storageAccountName')]" + }, + "resources": [ + { + "type": "Microsoft.Storage/storageAccounts", + "name": "[variables('storageAccountName')]", + "location": "[parameters('storageAccountLocation')]", + "apiVersion": "2018-07-01", + "sku": { + "name": "[parameters('storageAccountReplication')]" + }, + "kind": "[parameters('storageAccountType')]", + "properties": {}, + "resources": [ + { + "condition": "[parameters('advancedThreatProtectionEnabled')]", + "type": "providers/advancedThreatProtectionSettings", + "name": "Microsoft.Security/current", + "apiVersion": "2017-08-01-preview", + "dependsOn": [ + "[concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName'))]" + ], + "properties": { + "isEnabled": true + } + } + ] + } + ], + "outputs": { + "storageAccountName": { + "type": "string", + "value": "[variables('storageAccountName')]" + } + } +} \ No newline at end of file diff --git a/201-storage-advanced-threat-protection-create/azuredeploy.parameters.json b/201-storage-advanced-threat-protection-create/azuredeploy.parameters.json new file mode 100644 index 000000000000..b596945d5807 --- /dev/null +++ b/201-storage-advanced-threat-protection-create/azuredeploy.parameters.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "storageAccountName": { + "value": "GEN-UNIQUE" + }, + "storageAccountLocation": { + "value": "[resourceGroup().location]" + }, + "storageAccountKind": { + "value": "StorageV2" + }, + "storageAccountType": { + "value": "Standard_LRS" + }, + "advancedThreatProtectionEnabled": { + "value": true + } + } +} \ No newline at end of file diff --git a/201-storage-advanced-threat-protection-create/metadata.json b/201-storage-advanced-threat-protection-create/metadata.json new file mode 100644 index 000000000000..3448c17a5f15 --- /dev/null +++ b/201-storage-advanced-threat-protection-create/metadata.json @@ -0,0 +1,9 @@ +{ + "$schema": "https://aka.ms/azure-quickstart-templates-metadata-schema#", + "type": "QuickStart", + "itemDisplayName": "Storage account with Advanced Threat Protection", + "description": "This template allows you to deploy an Azure Storage account with Advanced Threat Protection enabled.", + "summary": "Deploy an Azure Storage account with Advanced Threat Protection enabled.", + "githubUsername": "neryaco", + "dateUpdated": "2019-01-22" +} \ No newline at end of file From b1b22de1a4cd6f7aa64f276baf5df9792c9de75c Mon Sep 17 00:00:00 2001 From: Nerya Cohen Date: Tue, 22 Jan 2019 16:27:56 +0200 Subject: [PATCH 05/66] Update azuredeploy.parameters.json --- .../azuredeploy.parameters.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/201-storage-advanced-threat-protection-create/azuredeploy.parameters.json b/201-storage-advanced-threat-protection-create/azuredeploy.parameters.json index b596945d5807..11b4aa486de2 100644 --- a/201-storage-advanced-threat-protection-create/azuredeploy.parameters.json +++ b/201-storage-advanced-threat-protection-create/azuredeploy.parameters.json @@ -8,10 +8,10 @@ "storageAccountLocation": { "value": "[resourceGroup().location]" }, - "storageAccountKind": { + "storageAccountType": { "value": "StorageV2" }, - "storageAccountType": { + "storageAccountReplication": { "value": "Standard_LRS" }, "advancedThreatProtectionEnabled": { From 16c093afd4dc91b776b9e4caaceb184b6997f2dd Mon Sep 17 00:00:00 2001 From: Nerya Cohen Date: Tue, 22 Jan 2019 16:31:31 +0200 Subject: [PATCH 06/66] removed storageAccountLocation from parameters file --- .../azuredeploy.parameters.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/201-storage-advanced-threat-protection-create/azuredeploy.parameters.json b/201-storage-advanced-threat-protection-create/azuredeploy.parameters.json index 11b4aa486de2..9398cfb365f7 100644 --- a/201-storage-advanced-threat-protection-create/azuredeploy.parameters.json +++ b/201-storage-advanced-threat-protection-create/azuredeploy.parameters.json @@ -5,9 +5,6 @@ "storageAccountName": { "value": "GEN-UNIQUE" }, - "storageAccountLocation": { - "value": "[resourceGroup().location]" - }, "storageAccountType": { "value": "StorageV2" }, From 0d47675da4b53e4c22541ddd2e941c9c4a0f31eb Mon Sep 17 00:00:00 2001 From: Nerya Cohen Date: Tue, 22 Jan 2019 17:45:29 +0200 Subject: [PATCH 07/66] some changes requested in PR --- .../azuredeploy.json | 14 +++++--------- .../azuredeploy.parameters.json | 2 +- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/201-storage-advanced-threat-protection-create/azuredeploy.json b/201-storage-advanced-threat-protection-create/azuredeploy.json index 92e6a70294fe..ec202d831e4c 100644 --- a/201-storage-advanced-threat-protection-create/azuredeploy.json +++ b/201-storage-advanced-threat-protection-create/azuredeploy.json @@ -4,7 +4,6 @@ "parameters": { "storageAccountName": { "type": "string", - "defaultValue": "storagewatp1", "metadata": { "description": "The name must be unique across all existing storage account names in Azure. It must be 3 to 24 characters long, and can contain only lowercase letters and numbers." } @@ -16,7 +15,7 @@ "description": "Storage account location, default is same as resource group location." } }, - "storageAccountType": { + "storageAccountKind": { "type": "string", "defaultValue": "StorageV2", "allowedValues": [ @@ -48,19 +47,16 @@ } } }, - "variables": { - "storageAccountName": "[parameters('storageAccountName')]" - }, "resources": [ { "type": "Microsoft.Storage/storageAccounts", - "name": "[variables('storageAccountName')]", + "name": "[parameters('storageAccountName')]", "location": "[parameters('storageAccountLocation')]", "apiVersion": "2018-07-01", "sku": { "name": "[parameters('storageAccountReplication')]" }, - "kind": "[parameters('storageAccountType')]", + "kind": "[parameters('storageAccountKind')]", "properties": {}, "resources": [ { @@ -69,7 +65,7 @@ "name": "Microsoft.Security/current", "apiVersion": "2017-08-01-preview", "dependsOn": [ - "[concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName'))]" + "[concat('Microsoft.Storage/storageAccounts/', parameters('storageAccountName'))]" ], "properties": { "isEnabled": true @@ -81,7 +77,7 @@ "outputs": { "storageAccountName": { "type": "string", - "value": "[variables('storageAccountName')]" + "value": "[parameters('storageAccountName')]" } } } \ No newline at end of file diff --git a/201-storage-advanced-threat-protection-create/azuredeploy.parameters.json b/201-storage-advanced-threat-protection-create/azuredeploy.parameters.json index 9398cfb365f7..b198b97158b9 100644 --- a/201-storage-advanced-threat-protection-create/azuredeploy.parameters.json +++ b/201-storage-advanced-threat-protection-create/azuredeploy.parameters.json @@ -5,7 +5,7 @@ "storageAccountName": { "value": "GEN-UNIQUE" }, - "storageAccountType": { + "storageAccountKind": { "value": "StorageV2" }, "storageAccountReplication": { From b283112582bbb3dddd90e94c68a6960fe8144fcc Mon Sep 17 00:00:00 2001 From: Jonathan Gao Date: Thu, 24 Jan 2019 15:11:44 -0500 Subject: [PATCH 08/66] refresh the two basic key vault templates --- 101-key-vault-create/README.md | 17 +- 101-key-vault-create/azuredeploy.json | 163 ++++++++---------- .../azuredeploy.parameters.json | 3 + 101-key-vault-create/metadata.json | 6 +- 201-key-vault-secret-create/README.md | 23 ++- 201-key-vault-secret-create/azuredeploy.json | 140 +++++++++------ .../azuredeploy.parameters.json | 75 ++++---- 201-key-vault-secret-create/metadata.json | 8 +- 8 files changed, 233 insertions(+), 202 deletions(-) diff --git a/101-key-vault-create/README.md b/101-key-vault-create/README.md index 9de2a302bb56..8c1f96681998 100644 --- a/101-key-vault-create/README.md +++ b/101-key-vault-create/README.md @@ -1,4 +1,4 @@ -# Create Key Vault +# Create an Azure Key Vault @@ -7,4 +7,17 @@ -This template creates a Key Vault. For more information, go to: http://azure.microsoft.com/en-us/documentation/services/key-vault/ +This template creates an Azure Key Vault. If you are new to Azure Key Vault, see: + +- [Azure Key Vault service](https://azure.microsoft.com/services/key-vault/) +- [Azure Key Vault documentation](https://docs.microsoft.com/azure/key-vault/) +- [Azure Key Vault template reference](https://docs.microsoft.com/azure/templates/microsoft.keyvault/allversions) +- [Quickstart templates](https://azure.microsoft.com/resources/templates/?resourceType=Microsoft.Keyvault) + +If you are new to the template development, see: + +- [Azure Resource Manager documentation](https://docs.microsoft.com/en-us/azure/azure-resource-manager/) +- [Use Azure Key Vault to pass secure parameter value during deployment](https://docs.microsoft.com/azure/azure-resource-manager/resource-manager-keyvault-parameter) +- [Tutorial: Integrate Azure Key Vault in Resource Manager Template deployment](https://docs.microsoft.com/azure/azure-resource-manager/resource-manager-tutorial-use-key-vault) + +Tags: Azure Key Vault, Key Vault, Secrets, Resource Manager, Resource Manager templates, ARM templates diff --git a/101-key-vault-create/azuredeploy.json b/101-key-vault-create/azuredeploy.json index 0020176192a7..bd2deb553dc7 100644 --- a/101-key-vault-create/azuredeploy.json +++ b/101-key-vault-create/azuredeploy.json @@ -2,121 +2,110 @@ "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { - "keyVaultName": { + "name": { "type": "string", "metadata": { - "description": "Name of the Vault" + "description": "Name of the key vault" } }, - "tenantId": { - "type": "string", - "defaultValue": "[subscription().tenantId]", - "metadata": { - "description": "Tenant Id of the subscription. Get using Get-AzureRmSubscription cmdlet or Get Subscription API" - } - }, - "objectId": { + "location": { "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Object Id of the AD user. Get using Get-AzureRmADUser or Get-AzureRmADServicePrincipal cmdlets" - } - }, - "keysPermissions": { - "type": "array", - "defaultValue": [ - "list" - ], - "metadata": { - "description": "Permissions to keys in the vault. Valid values are: all, create, import, update, get, list, delete, backup, restore, encrypt, decrypt, wrapkey, unwrapkey, sign, and verify." - } - }, - "secretsPermissions": { - "type": "array", - "defaultValue": [ - "list" - ], - "metadata": { - "description": "Permissions to secrets in the vault. Valid values are: all, get, set, list, and delete." + "description": "Location for all resources." } }, - "skuName": { + "tenantId": { "type": "string", - "defaultValue": "Standard", - "allowedValues": [ - "Standard", - "Premium" - ], - "metadata": { - "description": "SKU for the vault" - } - }, - "enableVaultForDeployment": { - "type": "bool", - "defaultValue": false, - "allowedValues": [ - true, - false - ], - "metadata": { - "description": "Specifies if the vault is enabled for a VM deployment" - } - }, - "enableVaultForDiskEncryption": { - "type": "bool", - "defaultValue": false, - "allowedValues": [ - true, - false - ], - "metadata": { - "description": "Specifies if the azure platform has access to the vault for enabling disk encryption scenarios." - } - }, - "enabledForTemplateDeployment": { - "type": "bool", - "defaultValue": false, - "allowedValues": [ - true, - false - ], + "defaultValue": "[subscription().tenantId]", "metadata": { - "description": "Specifies whether Azure Resource Manager is permitted to retrieve secrets from the key vault." + "description": "Tenant Id of the Azure subscription used for authenticating requests to the key vault. Get it by using Get-AzureRmSubscription cmdlet." } }, - "location": { + "objectId": { "type": "string", - "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Location for all resources." + "description": "The object ID of the Azure AD user for the key vault. Get it by using Get-AzureRmADUser or Get-AzureRmADServicePrincipal cmdlets" } } }, + "variables": { + "enabledForDeployment": false, + "enabledForDiskEncryption": false, + "enabledForTemplateDeployment": false, + "sku": "Standard" + }, "resources": [ { "type": "Microsoft.KeyVault/vaults", - "name": "[parameters('keyVaultName')]", + "name": "[parameters('name')]", "apiVersion": "2016-10-01", "location": "[parameters('location')]", "properties": { - "enabledForDeployment": "[parameters('enableVaultForDeployment')]", - "enabledForDiskEncryption": "[parameters('enableVaultForDiskEncryption')]", - "enabledForTemplateDeployment": "[parameters('enabledForTemplateDeployment')]", + "enabledForDeployment": "[variables('enabledForDeployment')]", + "enabledForDiskEncryption": "[variables('enabledForDiskEncryption')]", + "enabledForTemplateDeployment": "[variables('enabledForTemplateDeployment')]", "tenantId": "[parameters('tenantId')]", - "accessPolicies": [ - { - "tenantId": "[parameters('tenantId')]", - "objectId": "[parameters('objectId')]", - "permissions": { - "keys": "[parameters('keysPermissions')]", - "secrets": "[parameters('secretsPermissions')]" + "accessPolicies": { + "value": [ + { + "objectId": "[parameters('objectID')]", + "tenantId": "[parameters('tenantID')]", + "permissions": { + "keys": [ + "Get", + "List", + "Update", + "Create", + "Import", + "Delete", + "Recover", + "Backup", + "Restore" + ], + "secrets": [ + "Get", + "List", + "Set", + "Delete", + "Recover", + "Backup", + "Restore" + ], + "certificates": [ + "Get", + "List", + "Update", + "Create", + "Import", + "Delete", + "Recover", + "Backup", + "Restore", + "ManageContacts", + "ManageIssuers", + "GetIssuers", + "ListIssuers", + "SetIssuers", + "DeleteIssuers" + ] + } } - } - ], + ] + }, "sku": { - "name": "[parameters('skuName')]", + "name": "[variables('sku')]", "family": "A" + }, + "networkAcls": { + "value": { + "defaultAction": "Allow", + "bypass": "AzureServices", + "virtualNetworkRules": [], + "ipRules": [] + } } } } ] -} +} \ No newline at end of file diff --git a/101-key-vault-create/azuredeploy.parameters.json b/101-key-vault-create/azuredeploy.parameters.json index c403468035fc..49cf35851558 100644 --- a/101-key-vault-create/azuredeploy.parameters.json +++ b/101-key-vault-create/azuredeploy.parameters.json @@ -5,6 +5,9 @@ "keyVaultName": { "value": "GEN-UNIQUE" }, + "tenantId": { + "value": "GEN-AAD-TENANTid" + }, "objectId": { "value": "GEN-AAD-OBJECTID" } diff --git a/101-key-vault-create/metadata.json b/101-key-vault-create/metadata.json index a8fdbdf16d8a..22387d4e2379 100644 --- a/101-key-vault-create/metadata.json +++ b/101-key-vault-create/metadata.json @@ -1,11 +1,11 @@ { "$schema": "https://aka.ms/azure-quickstart-templates-metadata-schema#", "type": "QuickStart", - "itemDisplayName": "Create a Key Vault", - "description": "This template creates a Key Vault and assigns permissions to the supplied objectId (principal).", + "itemDisplayName": "Create an Azure Key Vault", + "description": "This template creates an Azure Key Vault.", "summary": "This template creates a Key Vault and assigns permissions to the supplied objectId (principal).", "githubUsername": "seanbamsft", - "dateUpdated": "2017-09-08" + "dateUpdated": "2019-01-24" } diff --git a/201-key-vault-secret-create/README.md b/201-key-vault-secret-create/README.md index 070a2bff7855..e14513815c5b 100644 --- a/201-key-vault-secret-create/README.md +++ b/201-key-vault-secret-create/README.md @@ -1,3 +1,5 @@ +# Create an Azure Key Vault and a list of secrets + @@ -5,9 +7,22 @@ -This template helps you to create a Key Vault. It allows to create and set multiple access policies and Secrets while creating the Vault. If you are new to [Key Vault check this out](https://azure.microsoft.com/en-us/services/key-vault/). A full walk through of this template is available [here](http://www.rahulpnath.com/blog/managing-azure-key-vault-using-azure-resource-manager-arm-templates/). +This template creates a key vault with a multiple access policies, and a list of secrets. Instead of just using an array for the secret creation, this template wraps an array in a [secureObject](https://docs.microsoft.com/azure/azure-resource-manager/resource-group-authoring-templates#parameters). Using a secureObject instead of an array type means that the values you pass, cannot be read back in the portal after the deployment. + +Resource iteration is used in this template. For more information, see + +- [Create multiple instances](https://docs.microsoft.com/azure/azure-resource-manager/resource-group-create-multiple) +- [Tutorial: create multiple instances](https://docs.microsoft.com/azure/azure-resource-manager/resource-manager-tutorial-create-multiple-instances) + +If you are new to Azure Key Vault, see: + +- [Azure Key Vault service](https://azure.microsoft.com/services/key-vault/) +- [Azure Key Vault documentation](https://docs.microsoft.com/azure/key-vault/) +- [Azure Key Vault template reference](https://docs.microsoft.com/azure/templates/microsoft.keyvault/allversions) +- [Quickstart templates](https://azure.microsoft.com/resources/templates/?resourceType=Microsoft.Keyvault) + +If you are new to the template development, see: -Instead of just using an array for the secret creation, this template wraps an array in a [secureObject](https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-authoring-templates#parameters). -Using a secureObject instead of an array type means that the values you pass, cannot be read back in the portal after the deployment. +- [Azure Resource Manager documentation](https://docs.microsoft.com/en-us/azure/azure-resource-manager/) -Tags: Azure Key Vault, Key Vault, Secrets +Tags: Azure Key Vault, Key Vault, Secrets, Resource Manager, Resource Manager templates, ARM templates diff --git a/201-key-vault-secret-create/azuredeploy.json b/201-key-vault-secret-create/azuredeploy.json index 99c3090b14f6..956ef102d3f1 100644 --- a/201-key-vault-secret-create/azuredeploy.json +++ b/201-key-vault-secret-create/azuredeploy.json @@ -2,55 +2,30 @@ "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { - "keyVaultName": { + "name": { "type": "string", "metadata": { - "description": "Name of the Key Vault" + "description": "Name of the key vault." } }, - "tenantId": { + "location": { "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Tenant Id for the subscription and use assigned access to the vault. Available from the Get-AzureRMSubscription PowerShell cmdlet" - } - }, - "accessPolicies": { - "type": "array", - "defaultValue": "{}", - "metadata": { - "description": "Access policies object {\"tenantId\":\"\",\"objectId\":\"\",\"permissions\":{\"keys\":[\"\"],\"secrets\":[\"\"]}}" + "description": "Location of the key vault." } }, - "vaultSku": { + "tenantId": { "type": "string", - "defaultValue": "Standard", - "allowedValues": [ - "Standard", - "Premium" - ], + "defaultValue": "[subscription().tenantId]", "metadata": { - "description": "SKU for the vault" + "description": "Tenant Id of the Azure subscription used for authenticating requests to the key vault. Get it by using Get-AzureRmSubscription cmdlet." } }, - "enabledForDeployment": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Specifies if the vault is enabled for VM or Service Fabric deployment" - } - }, - "enabledForTemplateDeployment": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Specifies if the vault is enabled for ARM template deployment" - } - }, - "enableVaultForVolumeEncryption": { - "type": "bool", - "defaultValue": false, + "objectId": { + "type": "string", "metadata": { - "description": "Specifies if the vault is enabled for volume encryption" + "description": "The object ID of the Azure AD user for the key vault. Get it by using Get-AzureRmADUser or Get-AzureRmADServicePrincipal cmdlets" } }, "secretsObject": { @@ -59,50 +34,103 @@ "metadata": { "description": "all secrets {\"secretName\":\"\",\"secretValue\":\"\"} wrapped in a secure object" } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Location for all resources." - } } }, + "variables": { + "enabledForDeployment": false, + "enabledForTemplateDeployment": false, + "enabledForDiskEncryption": false, + "sku": "Standard" + }, "resources": [ { "type": "Microsoft.KeyVault/vaults", - "name": "[parameters('keyVaultName')]", - "apiVersion": "2015-06-01", + "name": "[parameters('name')]", "location": "[parameters('location')]", + "apiVersion": "2018-02-14", "tags": { "displayName": "KeyVault" }, "properties": { - "enabledForDeployment": "[parameters('enabledForDeployment')]", - "enabledForTemplateDeployment": "[parameters('enabledForTemplateDeployment')]", - "enabledForVolumeEncryption": "[parameters('enableVaultForVolumeEncryption')]", + "enabledForDeployment": "[variables('enabledForDeployment')]", + "enabledForTemplateDeployment": "[variables('enabledForTemplateDeployment')]", + "enabledForDiskEncryption": "[variables('enabledForDiskEncryption')]", "tenantId": "[parameters('tenantId')]", - "accessPolicies": "[parameters('accessPolicies')]", + "accessPolicies": { + "value": [ + { + "objectId": "[parameters('objectID')]", + "tenantId": "[parameters('tenantID')]", + "permissions": { + "keys": [ + "Get", + "List", + "Update", + "Create", + "Import", + "Delete", + "Recover", + "Backup", + "Restore" + ], + "secrets": [ + "Get", + "List", + "Set", + "Delete", + "Recover", + "Backup", + "Restore" + ], + "certificates": [ + "Get", + "List", + "Update", + "Create", + "Import", + "Delete", + "Recover", + "Backup", + "Restore", + "ManageContacts", + "ManageIssuers", + "GetIssuers", + "ListIssuers", + "SetIssuers", + "DeleteIssuers" + ] + } + } + ] + }, "sku": { - "name": "[parameters('vaultSku')]", + "name": "[variables('sku')]", "family": "A" + }, + "networkAcls": { + "value": { + "defaultAction": "Allow", + "bypass": "AzureServices", + "virtualNetworkRules": [], + "ipRules": [] + } } } }, { "type": "Microsoft.KeyVault/vaults/secrets", - "name": "[concat(parameters('keyVaultName'), '/', parameters('secretsObject').secrets[copyIndex()].secretName)]", - "apiVersion": "2015-06-01", + "name": "[concat(parameters('name'), '/', parameters('secretsObject').secrets[copyIndex()].secretName)]", + "apiVersion": "2018-02-14", + "dependsOn": [ + "[concat('Microsoft.KeyVault/vaults/', parameters('name'))]" + ], "properties": { "value": "[parameters('secretsObject').secrets[copyIndex()].secretValue]" }, - "dependsOn": [ - "[concat('Microsoft.KeyVault/vaults/', parameters('keyVaultName'))]" - ], "copy": { "name": "secretsCopy", "count": "[length(parameters('secretsObject').secrets)]" } } ] -} +} \ No newline at end of file diff --git a/201-key-vault-secret-create/azuredeploy.parameters.json b/201-key-vault-secret-create/azuredeploy.parameters.json index 226382a0783b..771a03224a1f 100644 --- a/201-key-vault-secret-create/azuredeploy.parameters.json +++ b/201-key-vault-secret-create/azuredeploy.parameters.json @@ -1,46 +1,29 @@ - { - "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "keyVaultName": { - "value": "testVault" - }, - "tenantId": { - "value": "example-guid" - }, - "accessPolicies": { - "value": [ - { - "tenantId": "example-guid", - "objectId": "example-guid", - "permissions": { - "keys": ["all"], - "secrets": ["all"] - } - }, - { - "tenantId": "example-guid", - "objectId": "example-guid", - "permissions": { - "keys": ["all"], - "secrets": ["all"] - } - } - ] - }, - "secretsObject": { - "value": { - "secrets": [ - { - "secretName": "exampleSecret1", - "secretValue": "secretVaule1" - }, - { - "secretName": "exampleSecret2", - "secretValue": "secretValue2" - } - ] - } - } - } - } \ No newline at end of file +{ + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "name": { + "value": "GEN-UNIQUE" + }, + "tenantId": { + "value": "GEN-AAD-TENANTID" + }, + "objectId": { + "value": "GEN-AAD-OBJECTID" + }, + "secretsObject": { + "value": { + "secrets": [ + { + "secretName": "exampleSecret1", + "secretValue": "secretVaule1" + }, + { + "secretName": "exampleSecret2", + "secretValue": "secretValue2" + } + ] + } + } + } +} \ No newline at end of file diff --git a/201-key-vault-secret-create/metadata.json b/201-key-vault-secret-create/metadata.json index 8e0c6eceac00..6eeac196eeb3 100644 --- a/201-key-vault-secret-create/metadata.json +++ b/201-key-vault-secret-create/metadata.json @@ -1,11 +1,11 @@ { "$schema": "https://aka.ms/azure-quickstart-templates-metadata-schema#", "type": "QuickStart", - "itemDisplayName": "Create Key Vault", - "description": "This template creates a Key Vault and creates secrets within the vault as passed along with the parameters", - "summary": "Creates a Key Vault with dynammic list of Secrets", + "itemDisplayName": "Create a Key Vault and a list of secrets", + "description": "This template creates a Key Vault and a list of secrets within the key vault as passed along with the parameters", + "summary": "Creates a Key Vault with a list of secrets", "githubUsername": "rahulpnath", - "dateUpdated": "2017-10-23" + "dateUpdated": "2019-01-24" } From 7d6e57eb9f6ae6be60b4ebe33fe289dac24688f2 Mon Sep 17 00:00:00 2001 From: Jonathan Gao Date: Thu, 24 Jan 2019 15:18:19 -0500 Subject: [PATCH 09/66] refresh the two basic key vault templates --- 201-key-vault-secret-create/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/201-key-vault-secret-create/README.md b/201-key-vault-secret-create/README.md index e14513815c5b..98b9dbc26f03 100644 --- a/201-key-vault-secret-create/README.md +++ b/201-key-vault-secret-create/README.md @@ -24,5 +24,7 @@ If you are new to Azure Key Vault, see: If you are new to the template development, see: - [Azure Resource Manager documentation](https://docs.microsoft.com/en-us/azure/azure-resource-manager/) +- [Use Azure Key Vault to pass secure parameter value during deployment](https://docs.microsoft.com/azure/azure-resource-manager/resource-manager-keyvault-parameter) +- [Tutorial: Integrate Azure Key Vault in Resource Manager Template deployment](https://docs.microsoft.com/azure/azure-resource-manager/resource-manager-tutorial-use-key-vault) Tags: Azure Key Vault, Key Vault, Secrets, Resource Manager, Resource Manager templates, ARM templates From 5589e22a5e58953d6a37c429c322d4b48f600e94 Mon Sep 17 00:00:00 2001 From: Jonathan Gao Date: Thu, 24 Jan 2019 15:19:54 -0500 Subject: [PATCH 10/66] minor edits --- 101-key-vault-create/azuredeploy.json | 6 +++--- 201-key-vault-secret-create/azuredeploy.json | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/101-key-vault-create/azuredeploy.json b/101-key-vault-create/azuredeploy.json index bd2deb553dc7..c0e6f8de3959 100644 --- a/101-key-vault-create/azuredeploy.json +++ b/101-key-vault-create/azuredeploy.json @@ -5,14 +5,14 @@ "name": { "type": "string", "metadata": { - "description": "Name of the key vault" + "description": "Name of the key vault." } }, "location": { "type": "string", "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Location for all resources." + "description": "Location for the key vault." } }, "tenantId": { @@ -25,7 +25,7 @@ "objectId": { "type": "string", "metadata": { - "description": "The object ID of the Azure AD user for the key vault. Get it by using Get-AzureRmADUser or Get-AzureRmADServicePrincipal cmdlets" + "description": "The object ID of the Azure AD user for the key vault. Get it by using Get-AzureRmADUser or Get-AzureRmADServicePrincipal cmdlets." } } }, diff --git a/201-key-vault-secret-create/azuredeploy.json b/201-key-vault-secret-create/azuredeploy.json index 956ef102d3f1..4ea7967b2545 100644 --- a/201-key-vault-secret-create/azuredeploy.json +++ b/201-key-vault-secret-create/azuredeploy.json @@ -25,14 +25,14 @@ "objectId": { "type": "string", "metadata": { - "description": "The object ID of the Azure AD user for the key vault. Get it by using Get-AzureRmADUser or Get-AzureRmADServicePrincipal cmdlets" + "description": "The object ID of the Azure AD user for the key vault. Get it by using Get-AzureRmADUser or Get-AzureRmADServicePrincipal cmdlets." } }, "secretsObject": { "type": "secureObject", "defaultValue": "{}", "metadata": { - "description": "all secrets {\"secretName\":\"\",\"secretValue\":\"\"} wrapped in a secure object" + "description": "all secrets {\"secretName\":\"\",\"secretValue\":\"\"} wrapped in a secure object." } } }, From 18b3b28fcd456ea908c1b444cd83c7ee5b0137d6 Mon Sep 17 00:00:00 2001 From: Jonathan Gao Date: Thu, 24 Jan 2019 15:45:10 -0500 Subject: [PATCH 11/66] update the parameter files --- .../azuredeploy.parameters.json | 4 ++-- .../azuredeploy.parameters.json | 4 ++-- 201-key-vault-with-logging-create/README.md | 18 ++++++++++++++++-- .../metadata.json | 6 +++--- 4 files changed, 23 insertions(+), 9 deletions(-) diff --git a/101-key-vault-create/azuredeploy.parameters.json b/101-key-vault-create/azuredeploy.parameters.json index 49cf35851558..afc29ddc5862 100644 --- a/101-key-vault-create/azuredeploy.parameters.json +++ b/101-key-vault-create/azuredeploy.parameters.json @@ -6,10 +6,10 @@ "value": "GEN-UNIQUE" }, "tenantId": { - "value": "GEN-AAD-TENANTid" + "value": "GEN-GUID" }, "objectId": { - "value": "GEN-AAD-OBJECTID" + "value": "GEN-GUID" } } } \ No newline at end of file diff --git a/201-key-vault-secret-create/azuredeploy.parameters.json b/201-key-vault-secret-create/azuredeploy.parameters.json index 771a03224a1f..2301d3c341d6 100644 --- a/201-key-vault-secret-create/azuredeploy.parameters.json +++ b/201-key-vault-secret-create/azuredeploy.parameters.json @@ -6,10 +6,10 @@ "value": "GEN-UNIQUE" }, "tenantId": { - "value": "GEN-AAD-TENANTID" + "value": "GEN-GUID" }, "objectId": { - "value": "GEN-AAD-OBJECTID" + "value": "GEN-GUID" }, "secretsObject": { "value": { diff --git a/201-key-vault-with-logging-create/README.md b/201-key-vault-with-logging-create/README.md index 85a059fa739c..e448ec1d1754 100644 --- a/201-key-vault-with-logging-create/README.md +++ b/201-key-vault-with-logging-create/README.md @@ -1,3 +1,4 @@ +# Create an Azure Key Vault with logging enabled @@ -5,6 +6,19 @@ -This template helps you to create a Key Vault with diagnostics enabled. It allows to create and set multiple access policies while creating the Vault. If you are new to [Key Vault check this out](https://azure.microsoft.com/en-us/services/key-vault/). A full walk through of this template is available [here](https://www.codeisahighway.com/creating-azure-key-vault-with-logging-using-azure-resource-manager-arm-templates/). +This template creates an Azure Key Vault with diagnostics/logging enabled. For more information, see [Azure Key Vault Logging]https://docs.microsoft.com/azure/key-vault/key-vault-logging). -Tags: Azure Key Vault, Key Vault, Diagnostics, Resource Locks \ No newline at end of file +If you are new to Azure Key Vault, see: + +- [Azure Key Vault service](https://azure.microsoft.com/services/key-vault/) +- [Azure Key Vault documentation](https://docs.microsoft.com/azure/key-vault/) +- [Azure Key Vault template reference](https://docs.microsoft.com/azure/templates/microsoft.keyvault/allversions) +- [Quickstart templates](https://azure.microsoft.com/resources/templates/?resourceType=Microsoft.Keyvault) + +If you are new to the template development, see: + +- [Azure Resource Manager documentation](https://docs.microsoft.com/en-us/azure/azure-resource-manager/) +- [Use Azure Key Vault to pass secure parameter value during deployment](https://docs.microsoft.com/azure/azure-resource-manager/resource-manager-keyvault-parameter) +- [Tutorial: Integrate Azure Key Vault in Resource Manager Template deployment](https://docs.microsoft.com/azure/azure-resource-manager/resource-manager-tutorial-use-key-vault) + +Tags: Azure Key Vault, Key Vault, Secrets, Resource Manager, Resource Manager templates, ARM templates, diagnostics, resource locks, logging diff --git a/201-key-vault-with-logging-create/metadata.json b/201-key-vault-with-logging-create/metadata.json index bb5adc5c542e..c785dd141fcc 100644 --- a/201-key-vault-with-logging-create/metadata.json +++ b/201-key-vault-with-logging-create/metadata.json @@ -1,11 +1,11 @@ { "$schema": "https://aka.ms/azure-quickstart-templates-metadata-schema#", "type": "QuickStart", - "itemDisplayName": "Create Key Vault with logging", - "description": "This template creates a Key Vault and a storage account that is used for logging. It optionally creates resource locks to protect your Key Vault and storage resources.", + "itemDisplayName": "Create Key Vault with logging enabled", + "description": "This template creates an Azure Key Vault and an Azure Storage account that is used for logging. It optionally creates resource locks to protect your Key Vault and storage resources.", "summary": "Creates and optionally secures a Key Vault with logging linked to a storage account.", "githubUsername": "slapointe", - "dateUpdated": "2017-02-15" + "dateUpdated": "2019-01-24" } From 19070a521266a2682dca57ba3cd5d2006014fd85 Mon Sep 17 00:00:00 2001 From: Jonathan Gao Date: Fri, 25 Jan 2019 10:09:48 -0500 Subject: [PATCH 12/66] fix a parameter name --- 101-key-vault-create/azuredeploy.json | 4 ++-- 201-key-vault-secret-create/azuredeploy.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/101-key-vault-create/azuredeploy.json b/101-key-vault-create/azuredeploy.json index c0e6f8de3959..a47748ca15f0 100644 --- a/101-key-vault-create/azuredeploy.json +++ b/101-key-vault-create/azuredeploy.json @@ -49,8 +49,8 @@ "accessPolicies": { "value": [ { - "objectId": "[parameters('objectID')]", - "tenantId": "[parameters('tenantID')]", + "objectId": "[parameters('objectId')]", + "tenantId": "[parameters('tenantId')]", "permissions": { "keys": [ "Get", diff --git a/201-key-vault-secret-create/azuredeploy.json b/201-key-vault-secret-create/azuredeploy.json index 4ea7967b2545..956ffc6b1b62 100644 --- a/201-key-vault-secret-create/azuredeploy.json +++ b/201-key-vault-secret-create/azuredeploy.json @@ -59,8 +59,8 @@ "accessPolicies": { "value": [ { - "objectId": "[parameters('objectID')]", - "tenantId": "[parameters('tenantID')]", + "objectId": "[parameters('objectId')]", + "tenantId": "[parameters('tenantId')]", "permissions": { "keys": [ "Get", From dfdd9ee33f85539f79ea8c7ea363e0629fd729f7 Mon Sep 17 00:00:00 2001 From: Jonathan Gao Date: Fri, 25 Jan 2019 11:05:00 -0500 Subject: [PATCH 13/66] fix a template issue --- 101-key-vault-create/azuredeploy.json | 90 +++++++++---------- .../azuredeploy.parameters.json | 2 +- 201-key-vault-secret-create/azuredeploy.json | 90 +++++++++---------- .../azuredeploy.parameters.json | 2 +- 4 files changed, 90 insertions(+), 94 deletions(-) diff --git a/101-key-vault-create/azuredeploy.json b/101-key-vault-create/azuredeploy.json index a47748ca15f0..b397be53cd18 100644 --- a/101-key-vault-create/azuredeploy.json +++ b/101-key-vault-create/azuredeploy.json @@ -46,53 +46,51 @@ "enabledForDiskEncryption": "[variables('enabledForDiskEncryption')]", "enabledForTemplateDeployment": "[variables('enabledForTemplateDeployment')]", "tenantId": "[parameters('tenantId')]", - "accessPolicies": { - "value": [ - { - "objectId": "[parameters('objectId')]", - "tenantId": "[parameters('tenantId')]", - "permissions": { - "keys": [ - "Get", - "List", - "Update", - "Create", - "Import", - "Delete", - "Recover", - "Backup", - "Restore" - ], - "secrets": [ - "Get", - "List", - "Set", - "Delete", - "Recover", - "Backup", - "Restore" - ], - "certificates": [ - "Get", - "List", - "Update", - "Create", - "Import", - "Delete", - "Recover", - "Backup", - "Restore", - "ManageContacts", - "ManageIssuers", - "GetIssuers", - "ListIssuers", - "SetIssuers", - "DeleteIssuers" - ] - } + "accessPolicies": [ + { + "objectId": "[parameters('objectId')]", + "tenantId": "[parameters('tenantId')]", + "permissions": { + "keys": [ + "Get", + "List", + "Update", + "Create", + "Import", + "Delete", + "Recover", + "Backup", + "Restore" + ], + "secrets": [ + "Get", + "List", + "Set", + "Delete", + "Recover", + "Backup", + "Restore" + ], + "certificates": [ + "Get", + "List", + "Update", + "Create", + "Import", + "Delete", + "Recover", + "Backup", + "Restore", + "ManageContacts", + "ManageIssuers", + "GetIssuers", + "ListIssuers", + "SetIssuers", + "DeleteIssuers" + ] } - ] - }, + } + ], "sku": { "name": "[variables('sku')]", "family": "A" diff --git a/101-key-vault-create/azuredeploy.parameters.json b/101-key-vault-create/azuredeploy.parameters.json index afc29ddc5862..04ba8be9f817 100644 --- a/101-key-vault-create/azuredeploy.parameters.json +++ b/101-key-vault-create/azuredeploy.parameters.json @@ -3,7 +3,7 @@ "contentVersion": "1.0.0.0", "parameters": { "keyVaultName": { - "value": "GEN-UNIQUE" + "value": "GEN-KEYVAULT-NAME" }, "tenantId": { "value": "GEN-GUID" diff --git a/201-key-vault-secret-create/azuredeploy.json b/201-key-vault-secret-create/azuredeploy.json index 956ffc6b1b62..d45e42fdfc2d 100644 --- a/201-key-vault-secret-create/azuredeploy.json +++ b/201-key-vault-secret-create/azuredeploy.json @@ -56,53 +56,51 @@ "enabledForTemplateDeployment": "[variables('enabledForTemplateDeployment')]", "enabledForDiskEncryption": "[variables('enabledForDiskEncryption')]", "tenantId": "[parameters('tenantId')]", - "accessPolicies": { - "value": [ - { - "objectId": "[parameters('objectId')]", - "tenantId": "[parameters('tenantId')]", - "permissions": { - "keys": [ - "Get", - "List", - "Update", - "Create", - "Import", - "Delete", - "Recover", - "Backup", - "Restore" - ], - "secrets": [ - "Get", - "List", - "Set", - "Delete", - "Recover", - "Backup", - "Restore" - ], - "certificates": [ - "Get", - "List", - "Update", - "Create", - "Import", - "Delete", - "Recover", - "Backup", - "Restore", - "ManageContacts", - "ManageIssuers", - "GetIssuers", - "ListIssuers", - "SetIssuers", - "DeleteIssuers" - ] - } + "accessPolicies": [ + { + "objectId": "[parameters('objectId')]", + "tenantId": "[parameters('tenantId')]", + "permissions": { + "keys": [ + "Get", + "List", + "Update", + "Create", + "Import", + "Delete", + "Recover", + "Backup", + "Restore" + ], + "secrets": [ + "Get", + "List", + "Set", + "Delete", + "Recover", + "Backup", + "Restore" + ], + "certificates": [ + "Get", + "List", + "Update", + "Create", + "Import", + "Delete", + "Recover", + "Backup", + "Restore", + "ManageContacts", + "ManageIssuers", + "GetIssuers", + "ListIssuers", + "SetIssuers", + "DeleteIssuers" + ] } - ] - }, + } + ], "sku": { "name": "[variables('sku')]", "family": "A" diff --git a/201-key-vault-secret-create/azuredeploy.parameters.json b/201-key-vault-secret-create/azuredeploy.parameters.json index 2301d3c341d6..21b42c7a9052 100644 --- a/201-key-vault-secret-create/azuredeploy.parameters.json +++ b/201-key-vault-secret-create/azuredeploy.parameters.json @@ -3,7 +3,7 @@ "contentVersion": "1.0.0.0", "parameters": { "name": { - "value": "GEN-UNIQUE" + "value": "GEN-KEYVAULT-NAME" }, "tenantId": { "value": "GEN-GUID" From c8185475e1c8464b2b43c6aea68da418b9951bb0 Mon Sep 17 00:00:00 2001 From: Jonathan Gao Date: Mon, 28 Jan 2019 16:25:20 -0500 Subject: [PATCH 14/66] add a secret to the 101 sample --- 101-key-vault-create/README.md | 2 +- 101-key-vault-create/azuredeploy.json | 24 ++++++++++++++++++++++++ 101-key-vault-create/metadata.json | 4 ++-- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/101-key-vault-create/README.md b/101-key-vault-create/README.md index 8c1f96681998..388eccfb225c 100644 --- a/101-key-vault-create/README.md +++ b/101-key-vault-create/README.md @@ -7,7 +7,7 @@ -This template creates an Azure Key Vault. If you are new to Azure Key Vault, see: +This template creates an Azure Key Vault and a secret stored inside the key vault. If you are new to Azure Key Vault, see: - [Azure Key Vault service](https://azure.microsoft.com/services/key-vault/) - [Azure Key Vault documentation](https://docs.microsoft.com/azure/key-vault/) diff --git a/101-key-vault-create/azuredeploy.json b/101-key-vault-create/azuredeploy.json index b397be53cd18..0f3618e67630 100644 --- a/101-key-vault-create/azuredeploy.json +++ b/101-key-vault-create/azuredeploy.json @@ -27,6 +27,13 @@ "metadata": { "description": "The object ID of the Azure AD user for the key vault. Get it by using Get-AzureRmADUser or Get-AzureRmADServicePrincipal cmdlets." } + }, + "secretName": { + "type": "string", + "defaultValue": "vmAdminPassword" + }, + "secretValue": { + "type": "securestring" } }, "variables": { @@ -104,6 +111,23 @@ } } } + }, + { + "type": "Microsoft.KeyVault/vaults/secrets", + "name": "[concat(parameters('name'), '/', parameters('secretName'))]", + "apiVersion": "2016-10-01", + "location": "[parameters('location')]", + "scale": null, + "dependsOn": [ + "[resourceId('Microsoft.KeyVault/vaults', parameters('name'))]" + ], + "properties": { + "contentType": "securestring", + "value": "[parameters('secretValue')]", + "attributes": { + "enabled": true + } + } } ] } \ No newline at end of file diff --git a/101-key-vault-create/metadata.json b/101-key-vault-create/metadata.json index 22387d4e2379..77ae31e8b3ba 100644 --- a/101-key-vault-create/metadata.json +++ b/101-key-vault-create/metadata.json @@ -1,8 +1,8 @@ { "$schema": "https://aka.ms/azure-quickstart-templates-metadata-schema#", "type": "QuickStart", - "itemDisplayName": "Create an Azure Key Vault", - "description": "This template creates an Azure Key Vault.", + "itemDisplayName": "Create an Azure Key Vault and a secret", + "description": "This template creates an Azure Key Vault and a secret.", "summary": "This template creates a Key Vault and assigns permissions to the supplied objectId (principal).", "githubUsername": "seanbamsft", "dateUpdated": "2019-01-24" From 99f804996b2c250b8d214dbe5b5360fa0849ac48 Mon Sep 17 00:00:00 2001 From: StartAutomating Date: Thu, 31 Jan 2019 20:26:37 -0800 Subject: [PATCH 15/66] Initial Commit of PowerShell AzureRM Template Validation (Test-AzureRMTemplate and associated files) --- test/template-tests/Test-AzureRMTemplate | 2 ++ test/template-tests/Test-AzureRMTemplate.cmd | 1 + test/template-tests/Test-AzureRMTemplate.ps1 | Bin 0 -> 41506 bytes ...teUIDefinition-Must-Have-Parameters.test.ps1 | Bin 0 -> 690 bytes ...reateUIDefintion-Should-Have-Schema.test.ps1 | Bin 0 -> 2378 bytes ...r-Must-Be-Microsoft.Compute.MultiVM.test.ps1 | Bin 0 -> 734 bytes .../Location-Should-Be-In-Outputs.test.ps1 | Bin 0 -> 716 bytes ...t-Be-Present-In-Template-Parameters.test.ps1 | Bin 0 -> 1416 bytes ...lt-Must-Exist-In-CreateUIDefinition.test.ps1 | Bin 0 -> 2004 bytes .../Textboxes-Are-Well-Formed.test.ps1 | Bin 0 -> 2538 bytes .../Location-Should-Not-Be-Hardcoded.test.ps1 | Bin 0 -> 2094 bytes ...dIdentityExtension-must-not-be-used.test.ps1 | Bin 0 -> 486 bytes .../Min-And-Max-Value-Are-Numbers.test.ps1 | Bin 0 -> 2608 bytes .../Parameters-Must-Be-Referenced.test.ps1 | Bin 0 -> 808 bytes .../Parameters-Property-Must-Exist.test.ps1 | Bin 0 -> 432 bytes .../Resources-Should-Have-Location.test.ps1 | Bin 0 -> 824 bytes ...ring-Parameters-Cannot-Have-Default.test.ps1 | Bin 0 -> 846 bytes ...tual-Machines-Should-Not-Be-Preview.test.ps1 | Bin 0 -> 1514 bytes 18 files changed, 3 insertions(+) create mode 100644 test/template-tests/Test-AzureRMTemplate create mode 100644 test/template-tests/Test-AzureRMTemplate.cmd create mode 100644 test/template-tests/Test-AzureRMTemplate.ps1 create mode 100644 test/template-tests/testcases/CreateUIDefinition/CreateUIDefinition-Must-Have-Parameters.test.ps1 create mode 100644 test/template-tests/testcases/CreateUIDefinition/CreateUIDefintion-Should-Have-Schema.test.ps1 create mode 100644 test/template-tests/testcases/CreateUIDefinition/Handler-Must-Be-Microsoft.Compute.MultiVM.test.ps1 create mode 100644 test/template-tests/testcases/CreateUIDefinition/Location-Should-Be-In-Outputs.test.ps1 create mode 100644 test/template-tests/testcases/CreateUIDefinition/Outputs-Must-Be-Present-In-Template-Parameters.test.ps1 create mode 100644 test/template-tests/testcases/CreateUIDefinition/Parameters-Without-Default-Must-Exist-In-CreateUIDefinition.test.ps1 create mode 100644 test/template-tests/testcases/CreateUIDefinition/Textboxes-Are-Well-Formed.test.ps1 create mode 100644 test/template-tests/testcases/deploymentTemplate/Location-Should-Not-Be-Hardcoded.test.ps1 create mode 100644 test/template-tests/testcases/deploymentTemplate/ManagedIdentityExtension-must-not-be-used.test.ps1 create mode 100644 test/template-tests/testcases/deploymentTemplate/Min-And-Max-Value-Are-Numbers.test.ps1 create mode 100644 test/template-tests/testcases/deploymentTemplate/Parameters-Must-Be-Referenced.test.ps1 create mode 100644 test/template-tests/testcases/deploymentTemplate/Parameters-Property-Must-Exist.test.ps1 create mode 100644 test/template-tests/testcases/deploymentTemplate/Resources-Should-Have-Location.test.ps1 create mode 100644 test/template-tests/testcases/deploymentTemplate/Secure-String-Parameters-Cannot-Have-Default.test.ps1 create mode 100644 test/template-tests/testcases/deploymentTemplate/Virtual-Machines-Should-Not-Be-Preview.test.ps1 diff --git a/test/template-tests/Test-AzureRMTemplate b/test/template-tests/Test-AzureRMTemplate new file mode 100644 index 000000000000..c56fd5318175 --- /dev/null +++ b/test/template-tests/Test-AzureRMTemplate @@ -0,0 +1,2 @@ +#!/bin/sh +powershell -noprofile -nologo -command ". .\Test-AzureRMTemplate.ps1; Import-Module Pester; Test-AzureRMTemplate $@ ; if (\$error.Count) { exit 1}" diff --git a/test/template-tests/Test-AzureRMTemplate.cmd b/test/template-tests/Test-AzureRMTemplate.cmd new file mode 100644 index 000000000000..4c6a91d739c3 --- /dev/null +++ b/test/template-tests/Test-AzureRMTemplate.cmd @@ -0,0 +1 @@ +powershell.exe -noprofile -nologo -command ". .\Test-AzureRMTemplate.ps1; Import-Module Pester; Test-AzureRMTemplate %*; if ($error.Count) { exit 1}" diff --git a/test/template-tests/Test-AzureRMTemplate.ps1 b/test/template-tests/Test-AzureRMTemplate.ps1 new file mode 100644 index 0000000000000000000000000000000000000000..984b361eac6becaf83b7fa67dc2c880355c763e7 GIT binary patch literal 41506 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 BB&+}c literal 0 HcmV?d00001 diff --git a/test/template-tests/testcases/CreateUIDefinition/CreateUIDefinition-Must-Have-Parameters.test.ps1 b/test/template-tests/testcases/CreateUIDefinition/CreateUIDefinition-Must-Have-Parameters.test.ps1 new file mode 100644 index 0000000000000000000000000000000000000000..5166d2883018173a1a0db992e3a268cf7dcc2f6a GIT binary patch literal 690 zcmchU&1wQc5QOU-@Er#6prGOlcrqS5h=NEC!NaPPWCeF+cSR)R)suWZ%lbn+Bm`ub znVz2Rs_O2q&z&M=?5&!r=|Rt$o;+TKJikqi@g-Vw7E19P)mH;M)1HVnIjM5Rcw(%C z-=11poDgT4XsHdcD`HB2Lj&@C!1S7Hq(@#aAS4$^mwBeI6)??;iFIh}5TAnTQ1n;C zuFmyW)#h+Gy$2qLWvkE|T2mdc>%U@g=*x-ThTD3R=#_WGzQt)?W7yGy489{gR^`VX n>g_U{D9mrg`Lp^b6xnP&y&htl&g|cvxZV3}Ep=F`Rd(YW#$k2h literal 0 HcmV?d00001 diff --git a/test/template-tests/testcases/CreateUIDefinition/CreateUIDefintion-Should-Have-Schema.test.ps1 b/test/template-tests/testcases/CreateUIDefinition/CreateUIDefintion-Should-Have-Schema.test.ps1 new file mode 100644 index 0000000000000000000000000000000000000000..b03e49467166c97d99fff3d0808a9954c86bfa58 GIT binary patch literal 2378 zcmdUxOK;Oa6ou~^iT^O7m7GY88(3CCEI>#s5QvCwstVG?Z9^L;vYnz(`qzQ)%+$#^ zeW-+Hfh@=N%ze+f=jQjXsr9Yk9$U+v+7mmlkBgPeD$Cey*?ZP<8}eJ(gq69yv~AuC zn<24-&csR^u`=QW1O^@!>e-(zA)@ZjvydvUz!s@N^?@tyZ)5AxxNu0(q5 zpQ=o5Cw%w0zv8isJUW|t>r)~q@HNMW^1IqVrm^3ISX8@=XF`S**ObWiY?mvROnqf? zqCfFf%FwDT<@*QcuQN=^XM$8yujISS-gE93_)?ykT~LjTTJAomk}24m**X43wvUGt z6qO!hTmN)cHBud!_pzw6$@$euDVM^>Dzv(lS_ly_VzhsXhN2v@cSLrw`v28)hqyzZ z*Z5U;wASvc7(?o-WJAclpyCCm5V&X4{oC}m+N)dC@DuTjL4+hjMdv)5=y#q0W}xjX zs`|iVQJ53wNLw8vUJ9%jSY+z)xkPY{U*|n8D&j#zhV&#%sTv#)4{Z!nVK6Q*=?vTvE?gdnz{F|q08|JDI#aNTY553q;XZskPM@uM7Tc`HI894!KgYuq9{SoG`*R7i%kkeq T6ManOW0tzDgYK_E-T!|8IJkx< literal 0 HcmV?d00001 diff --git a/test/template-tests/testcases/CreateUIDefinition/Handler-Must-Be-Microsoft.Compute.MultiVM.test.ps1 b/test/template-tests/testcases/CreateUIDefinition/Handler-Must-Be-Microsoft.Compute.MultiVM.test.ps1 new file mode 100644 index 0000000000000000000000000000000000000000..2df517acabc3381f02014e82dcaf4b11be954647 GIT binary patch literal 734 zcmbu6%}N775QOV2_zpt|BmrG~0Z)4IAPW9m#Dj^mI+E-zv%83hudaUGYKVF;L6+I+ z>8Yu%>VA7|bfe5#Xsm5*=}M=|OjM`H?O4a;D&6w$RFiqqzJ|nEJ%}CN)M}N;B%+Gj zJxz4IWIWS}rg{K71M`s|>VWsrIioIgq(e?64AlzL>O0dnaZZa8*nqZO@HMOfMVm4f zy8m=Gr*?)t=-Dd-BKtZJ8U9D&!CL$QWi9B1@79${cbvah3Tm9U@wy!y9eCZBU;h5@ zD$t`DDk3UI%rbE@Pc5s&VS%q2y$#c}i5Fmc&54sP$&dc*%Q^0h{inwg-b{X-xmd?~ RG}$Dl&bGPIuO0^P;yW|ceQf{$ literal 0 HcmV?d00001 diff --git a/test/template-tests/testcases/CreateUIDefinition/Location-Should-Be-In-Outputs.test.ps1 b/test/template-tests/testcases/CreateUIDefinition/Location-Should-Be-In-Outputs.test.ps1 new file mode 100644 index 0000000000000000000000000000000000000000..4c7a63460c39d27a3728edacd1ea54c36a316aa9 GIT binary patch literal 716 zcmcJNK}*9x5QX1a@IQo5XaY6#4|u8n-xtW=QM>smeHt!gR;^b{(Ul1Yhj zc87{JYY``U&_b`&E~#nqJ&ovhhUxUETivi)fsl8Qx_zEsY?wYusSV(EMSTHk0Hbpe z6FO^pH#U|^^hRcBoEjxDxbJpmK;*wlFYqq3BMxbiFTJREqR literal 0 HcmV?d00001 diff --git a/test/template-tests/testcases/CreateUIDefinition/Outputs-Must-Be-Present-In-Template-Parameters.test.ps1 b/test/template-tests/testcases/CreateUIDefinition/Outputs-Must-Be-Present-In-Template-Parameters.test.ps1 new file mode 100644 index 0000000000000000000000000000000000000000..5dc908127ba9b98bc596ddf27fd3d65433cf2c86 GIT binary patch literal 1416 zcmb`HPfy!G5XIlQ65nAJB0;1O!3W?}IOG7WM5`W955?I)Q2eLa1R7QO>a@SHvx%LW zDoAMM^?G*p&6_tn{_|4khh{vfj&-09y4B~6#cM9l?y;`0Wg0Qhm19}zTwT^PE%4}b zCRfk|%Y;?N?x}kEzCpavC*A20-vpn^-qlCW`x4XZtA@JZYYakGL#m(amw4~V@@x;5 zUtpE0&~(kT&d9j*HmvMxLIw`SPRJrBSBFk-&2vDsSe00VpaFOb5Q}mS#C7^z#&)c1 z%=Lhxxt>{f_KND@8}Lrcw^cCH{Tj*h-j9iclf^AiY6goX(M^k0LzyuiRlO5-fhW#$c~-g)xh`#?AyC#mO7USoZ7T%#=b`H6i>&^H3oI12a3CvQ`9=vx#=4{ z9rgG6iT4r61!GEfNqK{+4lyN+`2w~H>uk;7XkAy=sBDaS2x8#OHeaiHj&)q#3PZCj zY)-L1fjXr>9q$pt^Egf~ne86kmAnG=h?TF@Ge&{Y&LROhBd(pX{%?A%_>QAZv3h6x zueV;id+mz<+YOP!H`K5{lcy$^tnGHpVA$ck?Wf(UZ!0;%&(v^aTXnS8FAxKm@y;50 R{U6cJz3Pg{tLlzw{tKz`>I47) literal 0 HcmV?d00001 diff --git a/test/template-tests/testcases/CreateUIDefinition/Parameters-Without-Default-Must-Exist-In-CreateUIDefinition.test.ps1 b/test/template-tests/testcases/CreateUIDefinition/Parameters-Without-Default-Must-Exist-In-CreateUIDefinition.test.ps1 new file mode 100644 index 0000000000000000000000000000000000000000..dcb14fcaf7d3453908b769a3d85a03243477e6f3 GIT binary patch literal 2004 zcmd6o%Z}4P5Jm4AiGOH8Bqq|N|9}+_DGMG_fLS0GnZ%O>@-TKX5TW^X;8Z(p$BAPy zhy}8owCi!J>Q;64ub-)g%6J#L&_g}YN4+g2iPlQcUg#CFrN;cOwL-GhQ*~Hp+F;Su zr_y(zH@enmq$Bi&yrXw~FO+H?5R#hBW$=x$oBf{=DcSkHS6|Qhy3vfBW<;5h)3SzX zXx$R`Cgg1XBTeO~r$a8W?pUP@cn)1#w!XnLmq~M?RF#_~Lz0qd7II9m=o0-$$jh;^ zrzw-yOSG2K8+pzjDWA(RTeIVXEbh3^%4lEDR%&DNVI*k>hd1l2rbnLqy zVTQ%2Zg?VY1A9(Au)bpXL<3eM^08?cV3CEMP0$p~I>^T#fNqP5eKclKt*Po4ZDYf5Ezkn+-An;`n~@x}x*8Qwv`G?tX};kLUifEc4yY_j(!Tcmeb0 i%~p>)!S0I*Rjq3`&EMS@P4gD#?*6k`Osbu8hWi`JK1MwN literal 0 HcmV?d00001 diff --git a/test/template-tests/testcases/CreateUIDefinition/Textboxes-Are-Well-Formed.test.ps1 b/test/template-tests/testcases/CreateUIDefinition/Textboxes-Are-Well-Formed.test.ps1 new file mode 100644 index 0000000000000000000000000000000000000000..a4dab3c2046350738f245b90dfda63e6d25d17fa GIT binary patch literal 2538 zcmd6p-EPxB5QXO&iFdFn3sQ+%yZ|@+Nn8{v@plnbRhu|qlsF|$Q6k8z1K-)rrfafk z+zJU~*;((-&dxb=W}II?FYVlB+!O2BeYVx(!5ABbh_5WOU_DV&@T$t51gE~=6f zmdt5Qvop?I+G}=Ac#9GNvPV0f>i|*8Cg1lxhXMaa1(pf zzRYnw2i**-%vRiDG583-!B^}d!*k_W?ekRDm7`DOQ7h6z`^4B@mdf~k%L_bBVY-X$ z5X&nRHHMi}G_i}BfJ!l;8f%5Jzc{`k&3;B zb30?#F70Ywwc7C9r-(S>g4`)b*BweTag|qiRQ>%OWcza!Tlg#n%v#A^w;1p2d;6Ka zTkjpgk?+_8`wSaB_YH_OoVm^*WvY{=BHY$^&|}=a+Lht!rX~aGJ?HL>Id9v(g0?{{-J-%S9T&hbQY&i2Zr%1O^6q}x|6MW}WH8)(o^JT7*w<9`eDZh&z?~c9zQArmT z|GSy^*Nntbw%G}h-Q1;auZm*bHLCUh75|Uq*i~?Ydc@fO%$NUi-xPfp9;H2hsbj3{ EH-kxcbpQYW literal 0 HcmV?d00001 diff --git a/test/template-tests/testcases/deploymentTemplate/Location-Should-Not-Be-Hardcoded.test.ps1 b/test/template-tests/testcases/deploymentTemplate/Location-Should-Not-Be-Hardcoded.test.ps1 new file mode 100644 index 0000000000000000000000000000000000000000..d1eb8f8706a831fb82e26c3fc49b5dd257ba548f GIT binary patch literal 2094 zcmb`H-EPxB5QXO&iFa6`N_DElq7T4L3*|@rNd)zx>P4EG#^5+1PD&B*>cDp6v~g)O&pzH^&k`D%}BhyBbJ zcyzflvBFX;DZ8B0ht{#vRm8$QQ|uSmcC62xu}v-Wc!~eM!l�{}aXjEl|9%Gy4d# zAxMOwm5$sLip=U4PPAAH`UA~yCx>F&R zMe(Mq=qYPqF*YHZc-F{vIWPNNcDKNKQ?19|(-HR1yvbVf18Z- z$y2cr*gppSl*}Xi_t8{&uUr*t8E?s5MuefOYN^8};+s0Pj#peZS&Gr?X7n<9Y9Bxr z(Yv}wTmBxg^_HZUzx&5{Cd41mfea=t*=7Ff#81vypnoUcXDMRAZiw}%t6@PU5#4QK zKjoGpR9NaAJfim*kzV67_B=hlpFQ6go8EK%PRt8hYFU~J_HCov$6(ToNXYwyz4SW6 z>w&$jF&kPs5J0gY`kWg%{#wr**9bH-cp73ATj$g(h4j&l_}OGIY;aiMBi1s!%6NBS zGo}jhS=II2Bi1X6TV7FY&l(jdR^P1`)G)VoeM&h^g-VS-oNw(aP1bv~&71DQM{1v( zy8rT0soT85pSo$%(l_{R2P4w~zZ&I)lCK|V hTcDn@OMmO+s@C#qJN@?=k$Z{HNUv1a^_M(H{RNM3RY?E< literal 0 HcmV?d00001 diff --git a/test/template-tests/testcases/deploymentTemplate/Min-And-Max-Value-Are-Numbers.test.ps1 b/test/template-tests/testcases/deploymentTemplate/Min-And-Max-Value-Are-Numbers.test.ps1 new file mode 100644 index 0000000000000000000000000000000000000000..7329c29bd497fe294a440817bf8f00ccdf01e860 GIT binary patch literal 2608 zcmdT_(MlUZ6g|&E|6!1YBv6Gi%~F+!>bRn|>KP_VxDdt7M;J{=_QI8Dhcj%{e1naJ-wb zxYX=zt&1WRBQthTnU)1Ja?@2k_0hAHSl~1JADi|)vQPO3j*sI{SS7CIut%(#I!=l1 z=mlw@_1cUOkWR^1>tC?Od%mlWiZynrrTR}@mE(x`6V6cel#7_S6&Lw0W+YXG*R!ml zjd`Th8+lSa#|Prh>A+i4yKgG0&s|pf+F0k%Vfz{PdBDBlI(yX4S#S-HOw$|(rl^!Y z;Yfu`;}P!;xi9S@c3xnzBxXS$)coIeaL5VI>_LOz))XOCsT)(#cx2i5dfah;=6Jbq zTaItm`nQg6bJ?!ro7Mk6#|P&&pRx18$aD9BlnMJFJ(t3%r2Wv;up2v$`n?cG*89Pq zaB^IM8{%hV;cpei{Qat^M^&t}eZ9^bv~H=;|I5!_IZyX@$@3_j#STBo%HJ|N6`y+E r#kKN>`%1H)cix5Gn$K9-r)k~RaFf>UHTip5dpB-JYhUZNv|i#jKM#ZE literal 0 HcmV?d00001 diff --git a/test/template-tests/testcases/deploymentTemplate/Parameters-Must-Be-Referenced.test.ps1 b/test/template-tests/testcases/deploymentTemplate/Parameters-Must-Be-Referenced.test.ps1 new file mode 100644 index 0000000000000000000000000000000000000000..2685df70225057eba447c4fbaff32e2a05f1d509 GIT binary patch literal 808 zcma))O-sW-5Qg8g;D1;`zy@saEO-$-c&LgWcxZ)c-Dt%mC5fPje_efMOKNL^NXYK& z?Ck9G?#$QcLbs~;a}BhuEsb@y@_04!><%=-SLmLxQHkeG2a2&Py%4d>nNqdpc;;9I zyL(D>v&wj(Q{Cx_*cmZPf2>Q^xfXg3dHqI=u_WPq7H;&!%=9P+P0X2=x@C0ST(J9h z*0kqjE%Vmg@V!-=`IEKi39G1wuqC}lkJZP+bA)Z`sz5gi+G=t>U^%i}L0n;H z{5BW7yr=rEhk76He@G+ZrWjzq28cfXE@qWOjCT z&R+g%9n|m?N;KC@&)SZRQ!7U`(Gy&$ciyckm`-agz>Ur*9_Xp$mBZwqlIo*Uy^M}K zZS<-W+BY;kztEolLbX24*G)7bOKSZAAVi6U|ZhOJAE^`$2oWE9i4rr MJBe-XFO{%|e~ki4TL1t6 literal 0 HcmV?d00001 diff --git a/test/template-tests/testcases/deploymentTemplate/Resources-Should-Have-Location.test.ps1 b/test/template-tests/testcases/deploymentTemplate/Resources-Should-Have-Location.test.ps1 new file mode 100644 index 0000000000000000000000000000000000000000..8b5460f75d8761684a83838c2a0bcc893998f395 GIT binary patch literal 824 zcmZ{i-Acni5QWdR;5#fO&_+z~1-$gG{-A;vTEVudMw+Ii6%_H+)o*r9B|oKfvpais z&Y3gw^S#!SD*lB=I@E#gb+wCR+A8CAq;p~`%~`i9iG1i(5&KGSAdY!cYNMP;&Thr+ ziDFH58E(68)|gSmua**9J_bsDolyZrOl-K V<8D_mXmr0;{?&+vQ&?>>e*qMae|-P| literal 0 HcmV?d00001 diff --git a/test/template-tests/testcases/deploymentTemplate/Secure-String-Parameters-Cannot-Have-Default.test.ps1 b/test/template-tests/testcases/deploymentTemplate/Secure-String-Parameters-Cannot-Have-Default.test.ps1 new file mode 100644 index 0000000000000000000000000000000000000000..6b06218030f22c3ba38cb32a9c249bb40aed5921 GIT binary patch literal 846 zcmZ{i+e!ja6o&unpm*4Wkb-V{f$j?GLJO3-h#<4kCOqXKkm%K`Z>?#YgCpXeHS75O zYtPU3TzxJ0PgK{jj`X10ttZn;8PU4h_@;W{Txo`9qjS};7h03iq-Lh2ay&WKl<1in zdfayG>PF9cBX>Yf;jgL3`$Th%y>C{^F_wnc4}D@r&OomU(A20&)QK@Lc}mo%4tI?e zl}qLXefq3`WxrfQ&gw}K?hSo1GFqJPJWo+?+SY6&!?w*B&xnX+727kqee%d&Gv@WF z9#eUTHTJ#kb0xle?{7+5y2M`ij%-rf=P&6o!U{U6xKHCaq^(2cgi4#8qa^Si)Wwt3 zb$8S?J#Jq{pla>P1G;DA1a7OZ52vsmWtD+Q(ix!)dMe#OQktH-IT?8s1XQ`1&-kAn^sTca9t4$l83<7o@in6{6j*-^PyGlVHueSKc?c;ZOH|{ptS*!N! zF89Oge1_iyP7xp8GIpJm-19`Ah_^KnwyGkqwq3p1-m1>^4ozq5Hj6vP_ST-eN*ldH z(xuMYzxN6I&gnAuvYlD=I&5E+cz=7BOL{wSn<45CL9BRO3%ATKH~3w3>#FER8oiIJ zY}_fif5OuJ@rt<}j;X(*?uq?BPR!^AS7Yskzn+`(t- Date: Fri, 1 Feb 2019 13:46:43 -0800 Subject: [PATCH 16/66] Fixing Encodings --- test/template-tests/Test-AzureRMTemplate.ps1 | Bin 41506 -> 41514 bytes ...UIDefinition-Must-Have-Parameters.test.ps1 | Bin 690 -> 694 bytes ...ateUIDefintion-Should-Have-Schema.test.ps1 | Bin 2378 -> 2382 bytes ...Must-Be-Microsoft.Compute.MultiVM.test.ps1 | Bin 734 -> 738 bytes .../Location-Should-Be-In-Outputs.test.ps1 | Bin 716 -> 720 bytes ...Be-Present-In-Template-Parameters.test.ps1 | Bin 1416 -> 1420 bytes ...-Must-Exist-In-CreateUIDefinition.test.ps1 | Bin 2004 -> 2008 bytes .../Textboxes-Are-Well-Formed.test.ps1 | Bin 2538 -> 2542 bytes .../Location-Should-Not-Be-Hardcoded.test.ps1 | Bin 2094 -> 2098 bytes ...dentityExtension-must-not-be-used.test.ps1 | Bin 486 -> 490 bytes .../Min-And-Max-Value-Are-Numbers.test.ps1 | Bin 2608 -> 2612 bytes .../Parameters-Must-Be-Referenced.test.ps1 | Bin 808 -> 812 bytes .../Parameters-Property-Must-Exist.test.ps1 | Bin 432 -> 436 bytes .../Resources-Should-Have-Location.test.ps1 | Bin 824 -> 828 bytes ...ng-Parameters-Cannot-Have-Default.test.ps1 | Bin 846 -> 850 bytes ...al-Machines-Should-Not-Be-Preview.test.ps1 | Bin 1514 -> 1518 bytes 16 files changed, 0 insertions(+), 0 deletions(-) diff --git a/test/template-tests/Test-AzureRMTemplate.ps1 b/test/template-tests/Test-AzureRMTemplate.ps1 index 984b361eac6becaf83b7fa67dc2c880355c763e7..3e8ae39b3b26d0cee85970eac64148b9ad899f41 100644 GIT binary patch delta 18 XcmZ2#O#lD@ diff --git a/test/template-tests/testcases/CreateUIDefinition/CreateUIDefinition-Must-Have-Parameters.test.ps1 b/test/template-tests/testcases/CreateUIDefinition/CreateUIDefinition-Must-Have-Parameters.test.ps1 index 5166d2883018173a1a0db992e3a268cf7dcc2f6a..57a6dfdb2b2e3e558314d4a1c89bf1eb97e0724f 100644 GIT binary patch delta 12 TcmdnQx{YF delta 7 OcmdnSx`}neCMEz3BLdd| diff --git a/test/template-tests/testcases/CreateUIDefinition/CreateUIDefintion-Should-Have-Schema.test.ps1 b/test/template-tests/testcases/CreateUIDefinition/CreateUIDefintion-Should-Have-Schema.test.ps1 index b03e49467166c97d99fff3d0808a9954c86bfa58..56aa905dbd024df30dcac7fa002abce5ce89ff44 100644 GIT binary patch delta 12 TcmX>lbWUi47bgoZ0~Z4T8xR89 delta 7 OcmX>nbV_K07bgG=`~tuL diff --git a/test/template-tests/testcases/CreateUIDefinition/Handler-Must-Be-Microsoft.Compute.MultiVM.test.ps1 b/test/template-tests/testcases/CreateUIDefinition/Handler-Must-Be-Microsoft.Compute.MultiVM.test.ps1 index 2df517acabc3381f02014e82dcaf4b11be954647..7ab282ecd09fc852c564c7566a9aa57380f6d2b1 100644 GIT binary patch delta 12 Tcmcb|`iOPIJth`j1}+8wAEpC# delta 7 OcmaFFdXII(JthDSivwE# diff --git a/test/template-tests/testcases/CreateUIDefinition/Location-Should-Be-In-Outputs.test.ps1 b/test/template-tests/testcases/CreateUIDefinition/Location-Should-Be-In-Outputs.test.ps1 index 4c7a63460c39d27a3728edacd1ea54c36a316aa9..8ca1c71904ca58f7d782107f80fc06bef544301f 100644 GIT binary patch delta 12 TcmX@ZdVzJr873B91}+8w9h?I| delta 7 Ocmcb>dWLnw872S?j{_wD diff --git a/test/template-tests/testcases/CreateUIDefinition/Outputs-Must-Be-Present-In-Template-Parameters.test.ps1 b/test/template-tests/testcases/CreateUIDefinition/Outputs-Must-Be-Present-In-Template-Parameters.test.ps1 index 5dc908127ba9b98bc596ddf27fd3d65433cf2c86..7a68baf4f68832e3e6c12655a8683c912b839668 100644 GIT binary patch delta 12 TcmeC+?&03h!OFtRz{LOn7IFfE delta 7 OcmeC-?%>|g!3qEh76NDh diff --git a/test/template-tests/testcases/CreateUIDefinition/Parameters-Without-Default-Must-Exist-In-CreateUIDefinition.test.ps1 b/test/template-tests/testcases/CreateUIDefinition/Parameters-Without-Default-Must-Exist-In-CreateUIDefinition.test.ps1 index dcb14fcaf7d3453908b769a3d85a03243477e6f3..2fca8dd54aeaefb3ed12e9d5a45844ca6b263e69 100644 GIT binary patch delta 12 Tcmcb@e}jL+6?PV01}+8wA8G?} delta 7 Ocmcb?e}#X;6?Om)XaiON diff --git a/test/template-tests/testcases/CreateUIDefinition/Textboxes-Are-Well-Formed.test.ps1 b/test/template-tests/testcases/CreateUIDefinition/Textboxes-Are-Well-Formed.test.ps1 index a4dab3c2046350738f245b90dfda63e6d25d17fa..13478246afaa9568d005402b45646aa7a47c99e1 100644 GIT binary patch delta 12 TcmaDQ{7!hoD^3<(1}+8wB18kd delta 7 OcmaDS{7QJkD^36p#si`N diff --git a/test/template-tests/testcases/deploymentTemplate/Location-Should-Not-Be-Hardcoded.test.ps1 b/test/template-tests/testcases/deploymentTemplate/Location-Should-Not-Be-Hardcoded.test.ps1 index d1eb8f8706a831fb82e26c3fc49b5dd257ba548f..2ce429913c73ebca5c80e692ac1790f9cce04d25 100644 GIT binary patch delta 12 TcmZ1{ut{Kp9tR6A0~Z4T7q$X| delta 7 Ocmdlauufou9tQvmUjkA2R?9wgRpI diff --git a/test/template-tests/testcases/deploymentTemplate/Virtual-Machines-Should-Not-Be-Preview.test.ps1 b/test/template-tests/testcases/deploymentTemplate/Virtual-Machines-Should-Not-Be-Preview.test.ps1 index 629783ca4286f04cf102ba45af196f7ff82ffe7a..27c9aaeafed214d4c1cacececbbe102008f7d3bd 100644 GIT binary patch delta 12 TcmaFG{f>LXD^?a>1}+8wA&dj5 delta 7 OcmaFI{fc|TD^>sxas!S4 From 7fd5fa0e34ec003c3f223b4b3b1fa20ae1682312 Mon Sep 17 00:00:00 2001 From: StartAutomating Date: Fri, 1 Feb 2019 13:48:51 -0800 Subject: [PATCH 17/66] Fixing Encodings (switching files to ASCII) --- ...UIDefinition-Must-Have-Parameters.test.ps1 | Bin 694 -> 348 bytes ...ateUIDefintion-Should-Have-Schema.test.ps1 | Bin 2382 -> 1192 bytes ...Must-Be-Microsoft.Compute.MultiVM.test.ps1 | Bin 738 -> 370 bytes .../Location-Should-Be-In-Outputs.test.ps1 | Bin 720 -> 361 bytes ...Be-Present-In-Template-Parameters.test.ps1 | Bin 1420 -> 711 bytes ...-Must-Exist-In-CreateUIDefinition.test.ps1 | Bin 2008 -> 1005 bytes .../Textboxes-Are-Well-Formed.test.ps1 | Bin 2542 -> 1272 bytes .../Location-Should-Not-Be-Hardcoded.test.ps1 | Bin 2098 -> 1050 bytes ...dentityExtension-must-not-be-used.test.ps1 | Bin 490 -> 246 bytes .../Min-And-Max-Value-Are-Numbers.test.ps1 | Bin 2612 -> 1307 bytes .../Parameters-Must-Be-Referenced.test.ps1 | Bin 812 -> 407 bytes .../Parameters-Property-Must-Exist.test.ps1 | Bin 436 -> 219 bytes .../Resources-Should-Have-Location.test.ps1 | Bin 828 -> 415 bytes ...ng-Parameters-Cannot-Have-Default.test.ps1 | Bin 850 -> 426 bytes ...al-Machines-Should-Not-Be-Preview.test.ps1 | Bin 1518 -> 760 bytes 15 files changed, 0 insertions(+), 0 deletions(-) diff --git a/test/template-tests/testcases/CreateUIDefinition/CreateUIDefinition-Must-Have-Parameters.test.ps1 b/test/template-tests/testcases/CreateUIDefinition/CreateUIDefinition-Must-Have-Parameters.test.ps1 index 57a6dfdb2b2e3e558314d4a1c89bf1eb97e0724f..3e527feb20d22c9684d596da713aeb0b3c4bf40e 100644 GIT binary patch literal 348 zcmb7`wyY?(1I=gKu_wygIEypARgA5YJ~2VY($Fq@3vY|5D{}4$YkE6 zHf*X$t99N96y#`T?9PbeCJTj6ILMtRA!oB;yy=XK`Syr~v^pFy8o}jsj3wE->9Nx) z)=DcXAxf+h_-ah+C)USs(F)p;1G_T>pV>ejD)OG}9t^xLp=MVjOA}~y{hOO^ji=&; XUoi5|p?Fv|wkx6ux{9!K?TBcSlc`XGC&5bj z?Wm#I8F8YK=2{cGAm-?g)Fa;qOs}a1dg8SLA-zDl%rkwBfN54jtV3Ii_zYBsqI(hB zs_H*gTfpJ;9(WvcQVM`Bk_zv(`l^_35 nZ=2b~VSWqFpVdF3$Y$&5bsyVw=6~+Q?cQH&sljquRX4r?o=5jR5WO4xABMyr8`kos$HLM>OQDC*(51PA&??^XT8Sl@k-TA>=D%06<$k4E zHizmYr1^OB-kV;KP$*iHSOE`d0{*y`%sreuEe+CwlGaMS z1p!|(J0?O;rblx7lQeley6Ke5pwtMgb*{Ist7>}WN@%e~h1zlPZ6M^eQSr}KOMb>* zl|A83;(hfLBtIWICodJhwML&Fo+^+Et*{_8NL?EuPb)+e0PAT!+nS-* z^cLw2jRXgNAy$K2i93Y4LqSO1qtQf{6Gm7a<5VbZ-$@6oivD5neX{Nwc!22^jGS3V zq2ia{o*GHk`BifZ$Ot{=@c*-5$^I1zr61ucLcE4@>sv4RlEqe!bN4lN-aqBEfl$5= xt>A24iRWdVxe2@QCm%;>HYewYj1z;3B3NuAn+C~m7c^v4wEHiC{z5S8{{!)FgjfIo literal 2382 zcmdUxOK;Oa6ou~^iT^O7m7GY88(3CCEI>#s5QvCwstVG?Z9^L;vYnz(`qzQ)%+$#^ zeW-+Hfh@=N%ze+f=jQjXsr9Yk9$U+v+7mmlkBgPeD$Cey*?ZP<8}eJ(gq69yv~AuC zn<24-&csR^u`=QW1O^@!>e-(zA)@ZjvydvUz!s@N^?@tyZ)5AxxNu0(q5 zpQ=o5Cw%w0zv8isJUW|t>r)~q@HNMW^1IqVrm^3ISX8@=XF`S**ObWiY?mvROnqf? zqCfFf%FwDT<@*QcuQN=^XM$8yujISS-gE93_)?ykT~LjTTJAomk}24m**X43wvUGt z6qO!hTmN)cHBud!_pzw6$@$euDVM^>Dzv(lS_ly_VzhsXhN2v@cSLrw`v28)hqyzZ z*Z5U;wASvc7(?o-WJAclpyCCm5V&X4{oC}m+N)dC@DuTjL4+hjMdv)5=y#q0W}xjX zs`|iVQJ53wNLw8vUJ9%jSY+z)xkPY{U*|n8D&j#zhV&#%sTv#)4{Z!nVK6Q*=?vTvE?gdnz{F|q08|JDI#aNTY553q;XZskPM@uM7Tc`HI894!KgYuq9{SoG`*R7i%kkeq T6ManOW0tzDgYK_E-2Z<7QM!gc diff --git a/test/template-tests/testcases/CreateUIDefinition/Handler-Must-Be-Microsoft.Compute.MultiVM.test.ps1 b/test/template-tests/testcases/CreateUIDefinition/Handler-Must-Be-Microsoft.Compute.MultiVM.test.ps1 index 7ab282ecd09fc852c564c7566a9aa57380f6d2b1..5856e9d454a03b0547c1f2fed536e93749ac34e7 100644 GIT binary patch literal 370 zcmaiuv1-FW42JiEdj}B=u^~2nflTSr!Nia>OX+ZNvoKLNJsiuI6l9n#KIb|7^iAs-)iX$m;SUzO0Q*pE2zhkXqPF8|W@%iZy8w#JL z>&}|Y8f&P5G!LwBw^+0z?1+-V$r>0(Tj39w{eBD-!BdPB4sbhyPPjwSVP?(wi}x=I x@;V^QOR9wYN&d!MZ#uh zXWzbgZ|3c_(ybzEqoEFUpli*#j8`Mi?NAePh3@z_D#<+QRDI&87Q_*6O4SNv0#U*3 ziAK8V80VU5p$D)_FdzB8&Uo(=r`M&(F)#zJ%4GXkW%m zt50WZYDd_eo>K)!WM2a!!v9Fz+lk+ytOmVFyLF||J?HP0oT|iIrMe9r?WMXezx@5* zm7_;XRCrVjm}TH(o@!Q(!wg>~dMl=B6VJf3S`!CdkstiomkZn(`%jNKypjAabFq%K SXtGHz65IYtzk2ApF1`aP?tO#+ diff --git a/test/template-tests/testcases/CreateUIDefinition/Location-Should-Be-In-Outputs.test.ps1 b/test/template-tests/testcases/CreateUIDefinition/Location-Should-Be-In-Outputs.test.ps1 index 8ca1c71904ca58f7d782107f80fc06bef544301f..81efb466141d368c87b416ded54a30c9e9cf07ed 100644 GIT binary patch literal 361 zcmb7<&kDjY494$;zC#!TTX4e{@T3<(aiE@LhpL%YY&+Tv5%Jw!{ez--FsF~?OTJ%f z<&_bfEsH3S(2I$(8%55a`YHJayM+syw6p!5ETeHYUF~sAtxg9X72#qu#7f(n=|1C3 za>kjiKxEbt{50mSp}L`vAKY5S5D90_pe@>YcZ6j8=z|VmbO_pRq4LhaV=>|E5~J>6 nNhS6ot=P@Et-ZG=W-t0atZXs8~=}(uHlOn$rBxB#4NwuKnf~LJaiBg@nx9 zxpVKCbI#1qccB+;`BO!@)Pn_cWs48K%>d#=2#-0wHT5wfj83*f4#RP#eJQiuxSX07idB z9MW0STi94?s12EgaoQ`1!Tq!|10w%bdV_bacj8c!PJIBclAY9M?@6Xt)+_5tiGH6L z8unMCs;w+UQS?u$LbN`@DY2XPD!q@6xz8Kux)9lI_8E`6agP6|J@@X_xajY6Zk!G= H>bkcB9{zZ? diff --git a/test/template-tests/testcases/CreateUIDefinition/Outputs-Must-Be-Present-In-Template-Parameters.test.ps1 b/test/template-tests/testcases/CreateUIDefinition/Outputs-Must-Be-Present-In-Template-Parameters.test.ps1 index 7a68baf4f68832e3e6c12655a8683c912b839668..7cd49cb8ddc43a7de63d31d8fd72c0e21555b7bf 100644 GIT binary patch literal 711 zcma))!A`?442JKO`VQ8pv`*S8cz~UN!w$eCKpYTUa*uoJJr$iuxEy^Fjm$!x>PX`Mn|4YG~vcLc!lm-G<*Wi@8*IK)LuLz zFt+rjnklHN!U|R!uzuBOw~pq6yb_%oAWAZ#jmQ4gHe&nw5XR56hT9tm|BfLN9#{*` jE}4m8)UR*Q3l*V*7&LxpCvmgV{}BUvh$6B=9DO2R_Alr) literal 1420 zcmb`H%}(P$5QOWD#5;`GNPxsf@Bo~E0|$O2KpfB>7H0xM@ei4VB|^OVvR~Vo*aou- z5*pbv?&+znuAcVW-$K7N;Yqcnb*yWP@2w4NEd2Xk~`%ad7E3mwT zRjNYc1=A)YgrmRjZuGq7&uesYgNy&4$E6%XqJV& zQ|wQmj_FUwJYaYp$LTq5yGOSruRuLw*jlC&UsQ-@L(B@H5F4z}q zXS_Q*Yin-!dKd;z_x^x{W;o|Et=bo7+9-{N1lkdNg#ozLB)N6+ zVbTgPAL+AZGFM&JBQL81EyJ8wCGA5UmcPc@Xq{K&?KT)~HA0N>> zAytxutPpl^0m+-t+9A-U*)ebnRNxl4L6C}om!>hz^3)%Vsl}w8$P=+ dYRyiQLA>B*g;al#Up3)SYwQ?{BVXL~Z~8 literal 2008 zcmd6o%Z}4P5Jm4AiGOH8Bqq|N|9}+_DGMG_fLS0GnZ%O>@-TKX5TW^X;8Z(p$BAPy zhy}8owCi!J>Q;64ub-)g%6J#L&_g}YN4+g2iPlQcUg#CFrN;cOwL-GhQ*~Hp+F;Su zr_y(zH@enmq$Bi&yrXw~FO+H?5R#hBW$=x$oBf{=DcSkHS6|Qhy3vfBW<;5h)3SzX zXx$R`Cgg1XBTeO~r$a8W?pUP@cn)1#w!XnLmq~M?RF#_~Lz0qd7II9m=o0-$$jh;^ zrzw-yOSG2K8+pzjDWA(RTeIVXEbh3^%4lEDR%&DNVI*k>hd1l2rbnLqy zVTQ%2Zg?VY1A9(Au)bpXL<3eM^08?cV3CEMP0$p~I>^T#fNqP5eKclKt*Po4ZDYf5Ezkn+-An;`n~@x}x*8Qwv`G?tX};kLUifEc4yY_j(!Tcmeb0 j%~p>)!S0I*Rjq3`&EMS@P4gD#?*6k`Osbu8hHLL{d|m8oB9npyIW!P3Xw!3d-9hBudU2fqO~tTKBQML$_+V)iSP`JZo>xl5H7uBg#^g8g_(7% z&3X$ng)H*Sch~v~opB zbxo#lqV0mV=l{Wo%v044R00T%g~83{eZEnazp0Gx!mm$oGU2?Pg(#do9;v$rtSp`i z5<_wT3F1Fmf$cc?Vdc6T1ol`S5cU^Qo%pdapP(0Zy zrpj!LxJQXo>>*3{F+%Tb>^ALG zNh>6fWoNxRJ3HshnQ?yoytH$ha!;&h5AA{V?PN7m+RRE;dv?rRZ9|?jYnWNsGs_uI z?Fx%0>}jmEikXU0&FWLzx6_r!xAw*^>l;= z1#?={?36PX_L^N2-gaX|C;!PtZr@fXdwe%B>#TvpBvf5Q!K#9Zj4U0%TtiG5+{7NW zFLPYaKsUuIvukd#7<`1^;4Ai!;kk0G_IWDn%F!qCs1@m?zdONiI^BDSirkFPtKTvb3+n^B7H3WKQ{OxkuO(yh~LR zo;7c(F6mat=j^x}jxOh^SktId2;z*z71xK|UHI*)ZaS1^;wrE3sQUXm$hPMyw(waDn6;9-ZZY22_qH>8 zzur57Bj2$H_8B&M?i&zmICGsr%2X#!MYyiu6uNjG>?6MOgyS+=@T@}T$YgEhsEB+tJv8&(~^@y?mnJ@q4zAgG)c$D`1rHi4 diff --git a/test/template-tests/testcases/deploymentTemplate/Location-Should-Not-Be-Hardcoded.test.ps1 b/test/template-tests/testcases/deploymentTemplate/Location-Should-Not-Be-Hardcoded.test.ps1 index 2ce429913c73ebca5c80e692ac1790f9cce04d25..4e15b8638d6959cc6d3f76e24d4d999fb805c83f 100644 GIT binary patch literal 1050 zcma))!A{&T5QguO@(v>uDGAzG@Bn)$EiH()NKM57?ZG4iF(kHYPqv`acgIfFW-E44 z9VxQxnSbX0JenIm6lrpO={HDdimzO@oRoQ5W@JWOTq-L_D7ic;S1!_@tOj|Vx zGi{W1;Q}o)IH)xixej)1zFqZ7P^U(UFsv^goNl%B3~2&xZ5pZ7)CN=^QBw!UNB+() z&&B<+UNzh^jKbTdW?lB$5)0uzUED&kBfoO51aHq-i?@92Y0di)p^^yswLz;!)8J>L zMqQLqeU-zk5)7V-9>2LMfC_&>K5!w!4ZC-g^Ai5dwy%sJtUei|3>;i+yg@Vo!)OVl zBDg{5xM>^JV#@&P4q?+E%pF>XyKjBm{x;bG%(c#12*p?=$-aaFP}SVrA%ey=**dXZ zNDHd!-OSF;oH=uLe*K)<&}RIPtz&oXjvd+CD@$r~OF8Y>D{O_G@}1iR%U63~JM3q+ zz@x{ViItXN$=DT~-nXtDuOgQ2nPES}wqpbCjBRSU$4mY9B|bg(|DP!KZ-C;Bo!Cc^ zjX)v{UH>-GuKPWr+9_-VDh|#_du74Cb1v_~E}YZ39l+iM9{TnI?sTH8+vQ8hsyh{8 zSrl)&ik`8SmS7X2iD&KDF6Xh|vAZSK>uNppo}P1m0V_>qlvkD4d)m&DSWuN=^|#5$ zfIJl&f&F99Psx0a|2~?E_u{Hp%Xmxfaw3deRZAT<5ntD-b-d!T$x?z|H>1bwnSB6R zhu+ma+Vb~_t+yn-{M|pnGbR3z4&*R#!7le#Cw>af0{uJkK1&e`b|b7$T@4E=>CoLK z_G4}-LWQN?!2^1q6X`WRW6#s)``Po2vFSb6?neF!Gah?Klf*h{Z7 zyzbe{8ndCL0|68ZqR+We;IH+>ah-!^22UfbV(XN8rH}!-5kH#@h7Ar&e8gIgSB!TX zHWR84pH*GYJz~AGq~#SQ_N-BXVh!ASMh$aY*Qb=zRH)SW!}->((qz3y+q~&Md}Q{? z+1s@}*wr-IUR`@WQ?~DabLutKS9M=1P+v6{wANoyn|gZqMb+H28olk*F8y6;8U_2} vnG1GHEYi*pRQmo&Z{2@V$-6bJCiW0aiM@9&l>c^msZY{4)8ZQEb^QGsMeb*N diff --git a/test/template-tests/testcases/deploymentTemplate/ManagedIdentityExtension-must-not-be-used.test.ps1 b/test/template-tests/testcases/deploymentTemplate/ManagedIdentityExtension-must-not-be-used.test.ps1 index f0486896048403adef051d075246a421142b7965..3d6d4f4cafda94cf54889eff48405b43e3ab058b 100644 GIT binary patch literal 246 zcmYk0!3x4K42JK8zC)0~HqhY24^14VpyJDg&2`T6<2kO3K8 zq1B07KQ@{0NXs@vD>nGex;!Q@3R~Z&ly&5W8wz!F7p+RI>;;NU{#sZ$ zl=BsGhaP(}){qw~k0g+f>1JNSQ!7ZbXDhU-nFGTjy)fa>%skXz0o)h`d=NMhjFHR& XK2l>~w!YHOsrDGFU1GI*X*KN|vZhmd literal 490 zcmZvY!D<3Q5Jc-7@E;lxR7fO0kfR3=f(Jtm!Gp8rT0soT85pSo$%(l_{R2P4w~zZ&I)lCK|V iTcDn@OMmO+s@C#qJN@?=k$Z{HNUv1a^_M(H_3jts>s4R? diff --git a/test/template-tests/testcases/deploymentTemplate/Min-And-Max-Value-Are-Numbers.test.ps1 b/test/template-tests/testcases/deploymentTemplate/Min-And-Max-Value-Are-Numbers.test.ps1 index 790f7756ba5f4f4955c0983558a1fb54bf3d1b24..377fd4c4cd3bc6c437f6af515529872eb79580fa 100644 GIT binary patch literal 1307 zcmcIjO>4t247~^PA4D-UhQ;g;^f*Qj?FuW~p%mt|>gJKyneC32(f>ZXj??sOD;x90 zjv_rhJxLYUyv)*MGV%|!sIvi=b8eMh_lVU?yc#JZtWdIdO{d=R{_gn=XV$&R7|W{Q z7K0^CXqqgPMm~Fmj8qX3gal&uTv_weQ20y}aEA<>Uk`{}7Dcr1)xJe6+Q6(bYRiRH zT2-j6K*NN~lywJu^}vfIc4>p}a~#B%wHM^VNM&Inq@C^s_@GDaF!LL&m4*({(BD8hh8;W7Y0CT!OLhlvYn3TDxr-J%_@E6gaJ(hfX@ntj4}LeBmib{Sn=Y^W^j zOAGm!>ld^^eAs2!0c`*agHhlJOB@3)>oKKPWSWGJO}Gw(`$l*nFA=`>`lIj>Y-%5_Y#{g%mipThb3w&knC3Ac{!wJ8qm}6pfi$;#P3~c_$5DVs9;s%av zGR_IC14l>XlA~g^xoX}qvnGzi55sbN(=TJkzTTdFmF#oEpIF5?LoE5dIcJO!$GaJe zOU>Tax+qdHGG_;sX<0BMH(k|JA3a-%B|fwNiD};>`;>p+_&olURpMF>?}$}X#~INb zy&w&=UYijD(ibw;`WLM6f$!?0VvQYYss2+}> zV;(8>MxIp9u}|Cu9e8JI_f19hxx-55jdczkwx4mI2izO3vq$ZmCD-uKG|h2fic0Ad zj#Rid9`Wvw`_dj_=LIJB#4PB8n*ZAl4mshOJ!uf!nj)ksbz>?TkK8xDo_E}@IbJT@ zmgAeX{;lKNT(;}@X7&Hi@xi&xXY9N%^4fhMWx_s4&!uoGX+JbI?8c6xelNt4^?vXt zoE%r+miQT2_*+FWf4?f~Q57p~U$659ty?Pe|NCdJoTvM{3CiZ4Cy s;#&FBeWls2JMTho&1bCa%d~E5xJm2wn*2Sjy&JcqwXgN3wDyYs1Wyfv{Qv*} diff --git a/test/template-tests/testcases/deploymentTemplate/Parameters-Must-Be-Referenced.test.ps1 b/test/template-tests/testcases/deploymentTemplate/Parameters-Must-Be-Referenced.test.ps1 index 8a2eb356ded90642917b74d655443994cab4c6ad..8a75c3fe92702aaf6fca7e0edbe9d02a7ffb895a 100644 GIT binary patch literal 407 zcmZY5!Ait15CG77ApbCwf-TtKS=fu@a zyvdB$q^C-X%{m>Bk*ZePL9?T;RmpV3%e4!JjkBw(dY2NP9$w$E=XfqVocxDo%r{ch zQjCsJ_is>@{w#vA@F!Kxk3sq1PN4GSJQ5oWHGE3}G0YgDbCnK185-+&(i|%ki?OXX z7yDvYR^{A=x{vMDr|WH9%wR%a$S^jyM2?_oF$8@;D4s3hh=jJs0cQFd{-Xu#^Y0Rt lB3pL@%+-TxkAc+cOwI!y=UJS<%=-SLmLxQHkeG2a2&Py%4d>nNqdpc;;9I zyL(D>v&wj(Q{Cx_*cmZPf2>Q^xfXg3dHqI=u_WPq7H;&!%=9P+P0X2=x@C0ST(J9h z*0kqjE%Vmg@V!-=`IEKi39G1wuqC}lkJZP+bA)Z`sz5gi+G=t>U^%i}L0n;H z{5BW7yr=rEhk76He@G+ZrWVxnA diff --git a/test/template-tests/testcases/deploymentTemplate/Parameters-Property-Must-Exist.test.ps1 b/test/template-tests/testcases/deploymentTemplate/Parameters-Property-Must-Exist.test.ps1 index 0f42202ec9c04134b854bbd0fffbde616ab5f818..b1c113da4c11841bfcc26cfca7e693a2209efb42 100644 GIT binary patch literal 219 zcmZ9GO$q`r42AcF-XRPF(}E6OV2&UT=uTWzjaaciq#1M&?`}K(EX*Q2lJ}A?8Zu5v zvF(dMMp8@TkA?${UClJ$tPjbu4Zd6GT`{g#`wJd8>w1GOUJc`WB88Sh3VQ-I_krPW z-NqEAWE&|&B(|7Z%ji@Szt2;nH9Vw%TzsZ*gX#yC;FBA{4T%BoHh1f@5h0(MNGd6w IP$;B$0lQ{Mi~s-t literal 436 zcmaKo-D<)>5QWdR;5&pMm_QAE0Ux0#=w0cBZC4s;e#l1JQ2Oe%-%dy*AhK+Ba^}pL zGjsW?bx^}ClxVJ*p0ynjr&f+^q9?FY?|fTTAf47)5H~u*c%Y_|R}PXBm1G~4>Sa{i zX`@%2;J(4>@rCyM7pnDXx^BV=UQ(+MQLdvRe5}x}P>AS$uR253!@TwkNCQ&aM8T(n zk(uYP+#Y%Dj diff --git a/test/template-tests/testcases/deploymentTemplate/Resources-Should-Have-Location.test.ps1 b/test/template-tests/testcases/deploymentTemplate/Resources-Should-Have-Location.test.ps1 index c521c4927412f59548a359e0857c8c3064f9d3e8..e25edd6f6688efb326fe44643432dc4504175622 100644 GIT binary patch literal 415 zcmY*V+e*YR5PdK7ABGZWD>nE8ee})Cq66i!?;xPtj@Ee zCp7&VREjY8nR*24K=Bz;r(USxE6+f}9#J{t^Oo&IiWnXBmrO%r+Fs3E;_ZOZq12fZ$9BLwXGx$o_E20_E99HKw z?a!HZ?rq?3`t&@Gm3_GujD0Mr#&FKO+E8crcAX`nswURqiqim%{khxt7;K716^iV2 zf*W=Idj412zVDRaNr~TuR~+0M>QN88a;hWd32KI@N(HdGu9P)D(}K|=LPrqasgWb+StY&PYZfrLyeC9GL2S;WA#p7g)Xtaw4QW- W-0dm`jn}W0e>I|E7e?z$`+orv>3@^} diff --git a/test/template-tests/testcases/deploymentTemplate/Secure-String-Parameters-Cannot-Have-Default.test.ps1 b/test/template-tests/testcases/deploymentTemplate/Secure-String-Parameters-Cannot-Have-Default.test.ps1 index 6166851b8399f2db72f3aaa6a746abacb9c92e6a..791e51c2c593684bb0e2bd508adb4fd1fb570146 100644 GIT binary patch literal 426 zcmY+A!D_=W42JK4yn`r#CeWC@KyMpthjfL6?Jx$@8YT5e;!IWwW$fK&*ISm#J_uX> z{{Q!gjC~qMFMHpR5T^wWHHzW$HW8j^vo}_YHpBKNd-a3m)K}1asIN$>a1gaKqV63;-3Hf?SI8|%_`pT1K>Us)x5N4YNMwn% literal 850 zcmZ{i+e!ja6o&unpm*4Wkb-V{f$j?GLJO3-h#<4kCOqXKkm%K`Z>?#YgCjC~mh1Ta zYtPU3TzxHgCaUXLM|#lh){|+ajA&hLd{ez}t~A55(Yb2a3$4j$QZv(1Ii4JAO7u(( zJ#IU8b)#p!kvkx#@YmGi|3q_*y>C{^F_wnc4}D@r&OomU(A20&)QK@Lc}mo%4tI?e zl}qLXefq3`WxrfQ&gw}K?hSo1GFqJPyiZYY+SY6&!?w*B&xnX+727kqee%d&Gv@WF z9#eUTHTJ#kb0xle?{7+5y2M`ij%-rf=P&6o!U{U6xKHCaq^(2cgi4#8qa^S@sEa45 z>+Yy)dfdK@K-Jon2XxQK3EWm+A5LLC$|?hqq%%Sp^i;Zmq%^&Ebzb|tLrjq!6eLj{ nCyBcHBZ<0z=YQ9>u^zF7Z);Wh0;_M!zRSe)<;2BletUia17VAs diff --git a/test/template-tests/testcases/deploymentTemplate/Virtual-Machines-Should-Not-Be-Preview.test.ps1 b/test/template-tests/testcases/deploymentTemplate/Virtual-Machines-Should-Not-Be-Preview.test.ps1 index 27c9aaeafed214d4c1cacececbbe102008f7d3bd..62674dfdad03b1a759715f41af6d61b168b69d59 100644 GIT binary patch literal 760 zcmb`Ev2KGf5I}b%{^1lM0ac-2kg-FCv{9O-L)F10N8%RS=zOG#s{VUT3?U>#m%@OJ z@6PYt)q;dd!r*n$E|8IuxzHQIh7Qw+sloKEJ$-t7|G z4w8t_nuZDlsUhM~WZs|I6u!d%+#^d!VkHYQ)|8wVM%4}D-ChzmqEfD;)MyJ)p+&aw zE&LrEL#7QEMzfIG!U-r}c4VtVjVFK>qK%chL67v~Kao^oi%Tq#P&=LJS*0;vO{SC; z=GL{$rS#ilKK1#7Zc7Ij)kiolBpI`NB114)`%XaD3g}x1(a`Gr!3{2jov@${9Pb4- zF0^BxK(-RJMfL+5M8MxN+rWCB&!x3eZ}VB}eQL$PeSr*FB|j13o2(|>OZNo@Se literal 1518 zcmd6nPjAye6vXF@#CKR#mYP=7e1aZ1^blH=QVxhi2l`>PMUD( zp|TwBzTJH@JM&)t{#k0Il6R(oUh9=U>uM8;S}C$R(2&?%-}qf=LFAXtl`$^0X2*%X zY|ehrrM~Jr(J||FJkt&HnUXB8e$oYoc&yo3zN4f<#mcTixvmqVR)Y5-d(x~u z_GTH#zWW`!j8pL1qdDB{&iNirhtyjpUFWZ?_ufv|I67O&CazSqgZZkyvA&3=^YvGRh#Rk8tZe11KNTc^* zm5n Date: Fri, 1 Feb 2019 14:02:27 -0800 Subject: [PATCH 18/66] Adding .gitattributes --- test/template-tests/.gitattributes | Bin 0 -> 26 bytes test/template-tests/Test-AzureRMTemplate.ps1 | Bin 41514 -> 20758 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 test/template-tests/.gitattributes diff --git a/test/template-tests/.gitattributes b/test/template-tests/.gitattributes new file mode 100644 index 0000000000000000000000000000000000000000..d2778fcb876d4f1ca59d26d8881572f74369fbe9 GIT binary patch literal 26 fcmezWPm4j1p@5;7!H_|LA%!86Aq@z58Mqh#Uj79- literal 0 HcmV?d00001 diff --git a/test/template-tests/Test-AzureRMTemplate.ps1 b/test/template-tests/Test-AzureRMTemplate.ps1 index 3e8ae39b3b26d0cee85970eac64148b9ad899f41..c065fb5fdd012f75fa5981b5ec3d172fcaa83d9f 100644 GIT binary patch literal 20758 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 UyH)Sp&^Z)<= literal 41514 zcmeI5TXP)8b;sv9RrwBE!j=Kb1{^tWO61bTgiKkK7!isd5EhFf35p^J&;TTwk@?k= zoL?XOae8`sdS(`2;&P=}(qLzMy3hUE)BE55b=3XTopg`8i|%=MYJaV|gYIc}Zl8C% zPrCoKZ_n)WH{IQI|7G{8JMJFYw@zGX4IqZnSDC5&pcnkAqe)mKcwd$+sNm(s;~mq zf44b~?d}u10zd16F>9QrnO~+WpRWhedAC>4;VYZj*8~z#V2Z-4?&k{3o6wB4bDFJ; zzHsEks0tTW_Sa7~;(HqhjZeEH`~SJ!fo8|{w?luC?gn**X^s`oFOYy116`@u%= zf7aQ(qVxR>o|Vn_$e#8Y!RqXiTi|fp?mxbq#kHW1&C0$5LTL8b{xOD67Y3Kp5$K_k zQ}DHYf_}T*3&Z%ddu{)Bt|Fh0jNZp-jt`T(0KxnAJ@S!rYu~8AEcfgQ$8pETIF{(I za|pad0iY2bhP*$rwORL8TD88Sj}YZoU95;M!VTegopr$UFNt0;{}5j8Flrp$uZ@yF z+9>Q;4(o8P(`;nSw{N^THaS8Xmf-xvD2aV!T_p33t^U~lI?7NfnA3C;#N;x$9 zm%KvCc5F^b;16j9mmhKBseSL#D-KJ;v^u&cJOleXCc{`+;DsZ(>}l2S?Ma?x4P=q+{XOF={@^6z{%48iZpFXt?j)Pf%uwCESWROD z)wsrBwZIR!>+>#y28-nIKvl`P;9wQM=eFYAtzK$JNaOUH$X4i9$jl#&PUqb;C$1wu zHSL1Sk4+ALO4^F#Oyf{;4LhrdVXOOn&sQHBPA_e4B>kfMG)Wb3Am2NelJ+Rs+>2z7 z`<~=}dP)}Lqi)-*2@-W?G<-AAt!9FoFa!6yml_5Fpr(w(tXsejY4Ne3q12ZlM^BeN&H9MKiOT6xfro;BTtR8_iW57 z`%EN8?DeV9Q9F68^ijR-S6l2nnhQS^fbq= z&2nzkabA=*ae6k*3dgWXuWkMJl4Zt@ytsr4n+Q+fw{s}Bz328sF7cXE*SFPg>vwCk z`q@^^X%+lkMla?m>6P>EQ?n%`)1UmXpL3(kx}Q+d^=Vd?~6rw(0y$B^>)PXw5(w6Yx`BEx`huZy>0~d z|5nItG_ zrN?^m6i4M>&YJdt*YJ}&)`qV{@%BFzc-6JtkYqax39(%H_IpF z*o%s5i#^_SUnbA&6)$3O=km%Tsk`>=9lP^$F=8)$gLJ*Lf9}iai-ac)f4`Tgi05I| zIuyb$pW!_Dn2#-gtwZ@&n++Zv7!)g`g{s5g;c~``@D85_kB;mL#L6+qJn_DGFRE-2 zQ+pgQDwS9Aak6W;s@!+g2_8v=WT0GQ$hG!rpC<|1wF(Xy6LrozwlbL(ag%2rt|4$t zl$@57ad;&&P_>jWC|l#9XtV^{_bvVqyn89v{~+P?jbZ0hLw1R?ozsdLMPcdOaE_xy zDUbKuN_e(OtgAc+ENYmnO|zu6$o_%BfE0>7m*Fou)Y#ZN>?Jltr zuz9{qHOqSrKiG<{N4rT%pW8U95T1hvJhCGFcuBO^wFXm(RoL_#pW2g}b=&j^EVeK4 z-%i+|38!WyzylqET6qnCN)r}oyq+1=we2cDVtptC?aDR8AtGPr&0N@O_D*RABPf$wfc*P8 zxg3}sn2qUI#-vH~Qq>{bF%GjDdDN<+!)Pr2m7WoD!6;e7n5FM2g_ZoExUOrBI{MBl zl2G)kD;Uwxu!cD;_Oemv6V~7R|K6G3?*1dgiNC2reqggnmXWgE%5x8|Mj-L^F}uAn zZLCBSGPJyd*TT)m=DoYXx3yYSKE_tvHI5@2K~-7Av1r6AByPJs3X~LRji~)nr;2)% zy3X||r-g@PLihl+*Kb-Da4*BEPwn|t9<99DI`Szy=I`dpP~%%PduzDUn<1K*ssIX3D3{ADRw85+ znIg8V(-Dv771f}5NW9x=dfw+Y3Qd(?2(RvX;q@AN5%1Yb^y-LT>55QodCx3U3u|Gr zR1>}(taQ^lFkIo?NPk<#YEWz{T`fM8P#hTd`tjspW_{$r9vIhKcE0TB)gY+bh}uY` z{UGHR_-gMG^Ox^f!<#E2u0^1#Thl>i#|Uv6^+d8yWSG8N9{D2CbdIGRc(=&CJZGaO zKvmLr>bax?`55&5c-uAAb2{I}#QJpD$pz8mh`rHAw38~V$7k%N$afE(cfONJ8l~%& z?Q0S@$LgH`&SSo) zMl7iSYPGfHWPOSF(C$b-`*fWHz2@C9DDN8Okvno)jCjLsg>HB2F z+uNBQd(Q+OxV<2|r{;yOu}6ga_Y)_Wi_VJI&FJ&>Ik#uKK;d2gZe2&WZTBWCg?-B9 znqKuBdWsjKWgZpxF_)%eC8IY5KbEX>^O9Xcxw%Z|vNbmv6#a6l%%Ml!18cUhjmU~3 z#<04p?$<{5wv}!{(fY1dS%|*5S6xN(fG+Q)&)2fH)a5ptmSIlt`Zdzb!J zst^8Rbei|CMU!%d8h`fEUVhm^!7yjmwk)*2ZOt$0uC1<7c0K0G_pdJHERPWI{X+>@ zb-%N{g}<_T$g2D2%fDLCZK7@Sp_y8_~STebbNfqHa1K=S7}I1nqm8JR&2C ztF2M`(L9FBSDcpf+U%l2$n(EheDO5>=bn!Jq4oU%G4g>$!5^BPdTN!L9g_`YKVVbd zfd!Nm#7o`cAyX-uSr^ytWME&o&zCS)cU}2Kk?_@Sa;|3GF(t=ZP}{ zXR1c5Iv+}LqGo*`8sy|6xy8SUwX|lPDz|OLoGR>?YI9KY>Dsnj8l~&w6ep1#Qa|?h zt@Pd4bzC>gCxTnPLxlID#J4YPP54KSpia^{+jCYM=e0w@EdK+CHsiZyde_)*?g>QE zkQR?=>7Y_|`Xo^hEjzr-Jjf}Zr`*LY1Z%%;+5oMgYpkUl`fHPoi(W(|?nF+T>$#qj zM&>#c(aXy6b@yE@3ni#@4e01JpQhb~)A%E0IfO$hE`edm*ns!8qJamhTw zA4@-FuaFINOMJ-rx7<2vWnDw7v5{1uz~?Y!M)YjrjmQV-d*8K(CCf)I$+UxVWWH!E z``lDJfUnHG%<>5vcJ#rACAcA22Z)cyTk5@M(N?#m_X3m5vEyrIJU)S{?ExxLs<-ZSs#?`0m-tGr&D zl7064h|UPRp4uIKtzTY4`((F5{`2oP!L=_h!}-haH(7%$mYR_7vhPQvIsAE~i=~2M zE6c1lSu-L<#lUe#vH2$R>RHW7+_T9%iV^5}5q)Vsc@Fv3P3HDJP?A}yp#Fvmo*&P( zWKLP) zdZiU6(|#8b1W|+U72Jfrf*bDB!JU!Mv?Rg=QQoeAbUPl33Iu5~>NjdCBu9SN$yIg+x1K;na}4Zi^hpdh_-( zl<+T$!sm@fN8jbYmYmcf^t-j^`t?cq!l-uaBpZOAzy{N6X74heRh^W-+@v}=T(9lV zYMG?gm%olW*uKe;PIk~r(uNu>N}jQE91j<7n?_V5k2Gf<%}XvE`dY&6JK(9Iv+Cw~ zZ;eL&wqQ_3el+mOdoy#ZroyYd3di?M|9xe48{Icb`d<3;?mMFcn!98BkRIB9V7qJF zA`+SN)V9q>_tL54evFDQ)`7a9`^hD|8N*>15BB*4+#w}+eaCon{*{nu#_M2Hw+iJ- z<>zHjT_>j1%6~huTjRTW=_h9Yykigd=?k!9H%`>>-Mgw1Ux#m^3!ZdnFCx2IvJ*M> zA-mT7??~^z7>zcmUyB0eb(w6IPs>8ZP6jNIG;Q2kZJV{i?rdtU{%`D6OK$sEQvr+J z?411(yV7%udlND(YF}rr&7@%2Q_AV*z$v+kT^G5B{notGvlQKG7w&Q|F%^^e9@K3+ ztEpUTUNy~Wvjo@Bp*C#Sm;Ipb&=#_s_PwFEzUzftHrU zYm0e}Q;}v^=Z_4Emi?YXZLRB)m9N*Y_KvNUkGkG^#E$-M+SpneF=w55x>$<~LX(2h zo=eV?Ls7JSor8mBh&nU5$Z$v2lDTRa=RN-Kj0^0J{*$dlwtbQ+>-`fHms^(>ChRkR zXk9GTUhyj0rMz@^BV7u5>^Z#J*GR0xE&}xm=Jxpo`#g!#=yneu2@k77HH^%6bGniN z>K)f%4n|HHGK3XFp5tUUJ+X9$#pbok#+-4E;v?Jj!=Ii~Yt3ejzz zM0lMZCYq)vIYCYx655SWR8ErcGc~Ek`E~ILC9{b1uK>3YWYa;kx$O|hH~bhEaSXBx+)ZcbL`r}we{VWQQGw@ zKYx`|-;p~>p(Itmg%DbYM^JCk@A{c_zMGr8J!Z+zJMr@jnHN6>J)aqET9AhJPD^CD zf96@zF-}*V(oNC#yX0GeZ`V2+`OZ4J7sux`ecy(akmNT5&SoD$(souesRB&g?)}gb0Ci9f7+nbOvNmI_Hmh?oN&>9so zhV*#%LD+^5rK4S=d3YVkAyG0A>TD^01KamWJvM5Q9j|Ox1vGX4bZlH|OWPdHoxk6w zy?X^;tkdXt|7zY&86*emJN>&XAKMO{`*wD@Z2di>N%>ZIi(it0@oVepDcK2`Dd$H{ zf;Mm&yLe{42B|@#xK5p6poj`vhe>|v0m8T8O4I-sS%O65Y2hM!)_bS4PzB72inYgP1CkaUN*Op!aG(X^8hC8EO;nvrPP-WDJOf^JkUBf!-4VHsE&%qLH$jsTzd}P z#4oa&%+D3^Y=x?Zp8$f-MEA)zj?)PPp|i+j?)9+r?j!43wJv6QGVq(&H21OKUV~UN z2jm_z%YuwUF}_h6gW!1`@OV0 zhjClcrbJE=>><|FSH~vm1iTl?PR2^$B+uKzL$eDXqT!O#ff1)x*3aMEwY`PV`zTqd zvVXW|bw2O=*DDZ$qP(`K>)L~D$Ypd6tjJbQK~674dK95}jpMm_Fs}>rR|qYTWJML= zNs1AOaoiug8Sy_Qo^?A}jsot3p)xgOIVN4oj7^%W@Gv#G-%ad$X2E@jhnBk zP=8!T-(|7&)Xw!X3!g(xIDE%=tSYCh<9MB=pBqzAj(k(`Y92S&y`m&cS6Nzl2V#I} z&6(&jxiaM`shOXjwzKJR8{V#*2oGIzO3&f>1a%syd(HFZ z>-1*E=G}iqVQwA2F$f}l<4uqI_MeZ5UucMXEg#?RjXOOZU=jUz}@NhI^i5$3%3xvW+`|Rl{yUkb&RoS!(Uou9%?F6zY|)g z!X?OVmxKO0os)31;!LVB9Gqnrb3f|)XWud!)8xJKpU>BzZ% zYpWGc@7?i8WcUWHJcslH-#8ovhv7&4+k7t=BWhfg)!Mcm7`QmM`o924+~_-h>QIfJ z+O6mMaL!q28SMKhD`fXyoPexo;*W+?>(?3sJ3Vp7#^1H4umhzI)pu9cDg`&ci|e}9 zxV9IIc;_PZ79J+8UMC$zTk00J?X7AO#@>lxu2xDC)>9euQL-E8>#HP>{>#SR@%1WQ z)Nqa(tqSoBtm6e7UXhtOiNEO*cgoesi8~LtaU!t>U^-v(mZV zi^rut&^zF(=XmLaZ9bbf+VZtj57Ub?zw5WevKv~r6E*M>%V zrrS1Q&dfo>I=>~Q>w+V-UzQIjH?bU>(YVG-!91V7eeDh!=P+@0JsAY~Jtt==ckvhu zPE1=Jb!RrGb*$Tm8H!VZ%OUP(X@WPnG{;I!(|3OUetlz&y=5Pb7;(Up{~sx^&G9D z>o6XZ|A${YMvdY552sc=`O)yDXT&IvONbMEXCHb)?^b&g6o(CaO?B;9n-7i1Du)Li z)$kKG9~;DqnCtzQ+}0zNc?6ZO8vEuV3Vav4QHkf-5l3~2{nzX{zHgBjbqb;ionlRF zp|gNm6c8oA<;-ff&Xe+-9q(z*nMd<&+3FqxvUg_49i*Ty6;W&Z!JzP3rzGJh&A>0A zG0IPq@}1v0v(EP+*MCPtFqPNg8<&dQ=k06Pd@;|^^4{DjdLdV`Jgzl&j2_S@G78S| zd4EyeKpI%rFX1_My`7>B@{Tz5U<}6ESfH)l4{s~@+?u0@u@=$P63G-6pIY@?egUUN0tpe>0Mo2&=K{fz9GE z;aptx#1c&P%o04o56Cu?JyAUD^qAyn?^(v$A#$O|;%9x3AFU&$yZ>0u+|5j{ClmsQo zb^A8kt8(gO`52-&*7cdTA%pTBn}&a^})t?zUO<_)oT?6hSwTSVQ1&($?AsJ=F_Ush2K9ff5A6w zX~f2nwYvZJy#&t;Q!vas%wd6kyt*qj%s#d&r;QF|}P~ zbHodI2Xo)PSLJ=*xJ9P7Zf#Je=kW1_W)1lW!1I~~Z&kQk!b7}>8gh3xqZF1Idcs=$-M z*7s`&#&))kMDpKQy-UvPvQ4^=&q!cT?{=T!9A-+d@2ol;jE zJ8?BMWBR?C=+n5>s=+s(!Zn>gN--kYIhBc)*84fLjz99`r%Nlg3~LcIntsDLU?&Rk z6FI%JGuKXuAJg>FTDszad5=q3AF>kr)ZH2e@3l^7kunmGgmc*06&4Yc$6&~WauTN= zxo}%&1nHFCYg|ZHNloP!^ilW?Ro)Msmsc#^7w_@}-P}STSHuN)y8M&_j{xNLTXHSz zHnWZOr)ulXy$5c3cLf|vd+5G0tb=ys!gaU0&x{8|Sp33**9f2wu`>|?_Z3a)eKG91 zKfP-@>MML{SD(+{7K!;~n*#=q=iR=-2gf)YsF zv*h?s;q9=$GKf8r7PpTQz2eNC{MVJ0&m(Ovb8d_J?{T8DQ~~f_8&vzO{M%A6)Y9`0IZF Dz62!N From 3c2e9c7d4fa11c0ac678d94f98495e911a43ad07 Mon Sep 17 00:00:00 2001 From: StartAutomating Date: Fri, 1 Feb 2019 15:39:31 -0800 Subject: [PATCH 19/66] Updating GitAttributes to try to fix diffing --- test/template-tests/.gitattributes | Bin 26 -> 106 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/test/template-tests/.gitattributes b/test/template-tests/.gitattributes index d2778fcb876d4f1ca59d26d8881572f74369fbe9..b906930e24c6b257393bf3c9b8bb713b695dd839 100644 GIT binary patch literal 106 zcmXZT!3sb?6ouh`t-Qmm6=h>LE18v*cmgJg&`>-*&cfz)`oHe`BxLLy$4^($V51IR!P9zP)_GQqrh6Vj@0^b`tFX literal 26 fcmezWPm4j1p@5;7!H_|LA%!86Aq@z58Mqh#Uj79- From 59e3ee4fc7240997a9d09c0c5318a2422dae4a5b Mon Sep 17 00:00:00 2001 From: StartAutomating Date: Fri, 1 Feb 2019 15:43:20 -0800 Subject: [PATCH 20/66] Re-encoding as UTF-8 --- test/template-tests/Test-AzureRMTemplate.ps1 | 3 ++- .../CreateUIDefinition-Must-Have-Parameters.test.ps1 | 3 ++- .../CreateUIDefintion-Should-Have-Schema.test.ps1 | 3 ++- .../Handler-Must-Be-Microsoft.Compute.MultiVM.test.ps1 | 3 ++- .../CreateUIDefinition/Location-Should-Be-In-Outputs.test.ps1 | 3 ++- .../Outputs-Must-Be-Present-In-Template-Parameters.test.ps1 | 3 ++- ...s-Without-Default-Must-Exist-In-CreateUIDefinition.test.ps1 | 3 ++- .../CreateUIDefinition/Textboxes-Are-Well-Formed.test.ps1 | 3 ++- .../Location-Should-Not-Be-Hardcoded.test.ps1 | 3 ++- .../ManagedIdentityExtension-must-not-be-used.test.ps1 | 3 ++- .../deploymentTemplate/Min-And-Max-Value-Are-Numbers.test.ps1 | 3 ++- .../deploymentTemplate/Parameters-Must-Be-Referenced.test.ps1 | 3 ++- .../deploymentTemplate/Parameters-Property-Must-Exist.test.ps1 | 3 ++- .../deploymentTemplate/Resources-Should-Have-Location.test.ps1 | 3 ++- .../Secure-String-Parameters-Cannot-Have-Default.test.ps1 | 3 ++- .../Virtual-Machines-Should-Not-Be-Preview.test.ps1 | 3 ++- 16 files changed, 32 insertions(+), 16 deletions(-) diff --git a/test/template-tests/Test-AzureRMTemplate.ps1 b/test/template-tests/Test-AzureRMTemplate.ps1 index c065fb5fdd01..6cd344caed32 100644 --- a/test/template-tests/Test-AzureRMTemplate.ps1 +++ b/test/template-tests/Test-AzureRMTemplate.ps1 @@ -1,4 +1,4 @@ -function Test-AzureRMTemplate +function Test-AzureRMTemplate { <# .Synopsis @@ -461,3 +461,4 @@ Each test script has access to a set of well-known variables: } + diff --git a/test/template-tests/testcases/CreateUIDefinition/CreateUIDefinition-Must-Have-Parameters.test.ps1 b/test/template-tests/testcases/CreateUIDefinition/CreateUIDefinition-Must-Have-Parameters.test.ps1 index 3e527feb20d2..eacde3d1c5b7 100644 --- a/test/template-tests/testcases/CreateUIDefinition/CreateUIDefinition-Must-Have-Parameters.test.ps1 +++ b/test/template-tests/testcases/CreateUIDefinition/CreateUIDefinition-Must-Have-Parameters.test.ps1 @@ -1,4 +1,4 @@ -param( +param( [Parameter(Mandatory=$true,Position=0)] [PSObject] $CreateUIDefinitionObject @@ -12,3 +12,4 @@ if (-not $CreateUIDefinitionObject.parameters.basics) { Write-Error "CreateUIDefinition is missing .parameters.basics" } + diff --git a/test/template-tests/testcases/CreateUIDefinition/CreateUIDefintion-Should-Have-Schema.test.ps1 b/test/template-tests/testcases/CreateUIDefinition/CreateUIDefintion-Should-Have-Schema.test.ps1 index 531d5d46ebab..7823a905f7ba 100644 --- a/test/template-tests/testcases/CreateUIDefinition/CreateUIDefintion-Should-Have-Schema.test.ps1 +++ b/test/template-tests/testcases/CreateUIDefinition/CreateUIDefintion-Should-Have-Schema.test.ps1 @@ -1,4 +1,4 @@ -param( +param( [Parameter(Mandatory=$true,Position=0)] [PSObject] $CreateUIDefinitionObject @@ -29,3 +29,4 @@ if ($CreateUIDefinitionObject.version -ne $schemaVersion) { throw "CreateUIDefinition version ($($CreateUIDefinitionObject.version)) is different from schema version ($schemaVersion)" } + diff --git a/test/template-tests/testcases/CreateUIDefinition/Handler-Must-Be-Microsoft.Compute.MultiVM.test.ps1 b/test/template-tests/testcases/CreateUIDefinition/Handler-Must-Be-Microsoft.Compute.MultiVM.test.ps1 index 5856e9d454a0..262b3094a60a 100644 --- a/test/template-tests/testcases/CreateUIDefinition/Handler-Must-Be-Microsoft.Compute.MultiVM.test.ps1 +++ b/test/template-tests/testcases/CreateUIDefinition/Handler-Must-Be-Microsoft.Compute.MultiVM.test.ps1 @@ -1,4 +1,4 @@ -param( +param( [Parameter(Mandatory=$true,Position=0)] [PSObject] $CreateUIDefinitionObject @@ -13,3 +13,4 @@ if ($CreateUIDefinitionObject.handler -cne 'Microsoft.Compute.MultiVm') { } + diff --git a/test/template-tests/testcases/CreateUIDefinition/Location-Should-Be-In-Outputs.test.ps1 b/test/template-tests/testcases/CreateUIDefinition/Location-Should-Be-In-Outputs.test.ps1 index 81efb466141d..654f02508e75 100644 --- a/test/template-tests/testcases/CreateUIDefinition/Location-Should-Be-In-Outputs.test.ps1 +++ b/test/template-tests/testcases/CreateUIDefinition/Location-Should-Be-In-Outputs.test.ps1 @@ -1,4 +1,4 @@ -param( +param( [Parameter(Mandatory=$true,Position=0)] [PSObject] $CreateUIDefinitionObject @@ -14,3 +14,4 @@ if ("$($CreateUIDefinitionObject.outputs.location)".Trim() -ne '[location()]') { } + diff --git a/test/template-tests/testcases/CreateUIDefinition/Outputs-Must-Be-Present-In-Template-Parameters.test.ps1 b/test/template-tests/testcases/CreateUIDefinition/Outputs-Must-Be-Present-In-Template-Parameters.test.ps1 index 7cd49cb8ddc4..e93085f0563e 100644 --- a/test/template-tests/testcases/CreateUIDefinition/Outputs-Must-Be-Present-In-Template-Parameters.test.ps1 +++ b/test/template-tests/testcases/CreateUIDefinition/Outputs-Must-Be-Present-In-Template-Parameters.test.ps1 @@ -1,4 +1,4 @@ -param( +param( [Parameter(Mandatory=$true,Position=0)] [PSObject] $CreateUIDefinitionObject, @@ -26,3 +26,4 @@ foreach ($output in $parameterInfo.outputs.psobject.properties) { } + diff --git a/test/template-tests/testcases/CreateUIDefinition/Parameters-Without-Default-Must-Exist-In-CreateUIDefinition.test.ps1 b/test/template-tests/testcases/CreateUIDefinition/Parameters-Without-Default-Must-Exist-In-CreateUIDefinition.test.ps1 index ae5266cace43..f5b7ba8ea4e2 100644 --- a/test/template-tests/testcases/CreateUIDefinition/Parameters-Without-Default-Must-Exist-In-CreateUIDefinition.test.ps1 +++ b/test/template-tests/testcases/CreateUIDefinition/Parameters-Without-Default-Must-Exist-In-CreateUIDefinition.test.ps1 @@ -1,4 +1,4 @@ -param( +param( [Parameter(Mandatory=$true)] [PSObject] $TemplateObject, @@ -25,3 +25,4 @@ foreach ($parameter in $TemplateObject.parameters.psobject.properties) { } + diff --git a/test/template-tests/testcases/CreateUIDefinition/Textboxes-Are-Well-Formed.test.ps1 b/test/template-tests/testcases/CreateUIDefinition/Textboxes-Are-Well-Formed.test.ps1 index 6b35b38c065b..3482aa4bd5e7 100644 --- a/test/template-tests/testcases/CreateUIDefinition/Textboxes-Are-Well-Formed.test.ps1 +++ b/test/template-tests/testcases/CreateUIDefinition/Textboxes-Are-Well-Formed.test.ps1 @@ -1,4 +1,4 @@ -param( +param( [Parameter(Mandatory=$true,Position=0)] [PSObject] $CreateUIDefinitionObject @@ -40,3 +40,4 @@ foreach ($textbox in $allTextBoxes) { } } + diff --git a/test/template-tests/testcases/deploymentTemplate/Location-Should-Not-Be-Hardcoded.test.ps1 b/test/template-tests/testcases/deploymentTemplate/Location-Should-Not-Be-Hardcoded.test.ps1 index 4e15b8638d69..2ebd5c03e114 100644 --- a/test/template-tests/testcases/deploymentTemplate/Location-Should-Not-Be-Hardcoded.test.ps1 +++ b/test/template-tests/testcases/deploymentTemplate/Location-Should-Not-Be-Hardcoded.test.ps1 @@ -1,4 +1,4 @@ -param( +param( [Parameter(Mandatory=$true,Position=0)] [string]$TemplateText, @@ -29,3 +29,4 @@ if ($TemplateWithoutParameters -like '*resourceGroup().location*') { + diff --git a/test/template-tests/testcases/deploymentTemplate/ManagedIdentityExtension-must-not-be-used.test.ps1 b/test/template-tests/testcases/deploymentTemplate/ManagedIdentityExtension-must-not-be-used.test.ps1 index 3d6d4f4cafda..b8432063fcc9 100644 --- a/test/template-tests/testcases/deploymentTemplate/ManagedIdentityExtension-must-not-be-used.test.ps1 +++ b/test/template-tests/testcases/deploymentTemplate/ManagedIdentityExtension-must-not-be-used.test.ps1 @@ -1,4 +1,4 @@ -param( +param( [Parameter(Mandatory=$true,Position=0)] [string] $TemplateText @@ -8,3 +8,4 @@ if ($templateText -match 'managedidentityextension') { } + diff --git a/test/template-tests/testcases/deploymentTemplate/Min-And-Max-Value-Are-Numbers.test.ps1 b/test/template-tests/testcases/deploymentTemplate/Min-And-Max-Value-Are-Numbers.test.ps1 index 377fd4c4cd3b..8aaa5d36fbff 100644 --- a/test/template-tests/testcases/deploymentTemplate/Min-And-Max-Value-Are-Numbers.test.ps1 +++ b/test/template-tests/testcases/deploymentTemplate/Min-And-Max-Value-Are-Numbers.test.ps1 @@ -1,4 +1,4 @@ -param( +param( [Parameter(Mandatory=$true,Position=0)] [PSObject] $TemplateObject @@ -33,3 +33,4 @@ foreach ($parameter in $templateObject.parameters) { } } + diff --git a/test/template-tests/testcases/deploymentTemplate/Parameters-Must-Be-Referenced.test.ps1 b/test/template-tests/testcases/deploymentTemplate/Parameters-Must-Be-Referenced.test.ps1 index 8a75c3fe9270..2c264ee3795b 100644 --- a/test/template-tests/testcases/deploymentTemplate/Parameters-Must-Be-Referenced.test.ps1 +++ b/test/template-tests/testcases/deploymentTemplate/Parameters-Must-Be-Referenced.test.ps1 @@ -1,4 +1,4 @@ -param( +param( [Parameter(Mandatory=$true,Position=0)] [PSObject] $TemplateObject @@ -12,3 +12,4 @@ foreach ($parameter in $TemplateObject.parameters.psobject.properties) { + diff --git a/test/template-tests/testcases/deploymentTemplate/Parameters-Property-Must-Exist.test.ps1 b/test/template-tests/testcases/deploymentTemplate/Parameters-Property-Must-Exist.test.ps1 index b1c113da4c11..77ba4899f668 100644 --- a/test/template-tests/testcases/deploymentTemplate/Parameters-Property-Must-Exist.test.ps1 +++ b/test/template-tests/testcases/deploymentTemplate/Parameters-Property-Must-Exist.test.ps1 @@ -1,4 +1,4 @@ -param( +param( [Parameter(Mandatory=$true,Position=0)] [PSObject] $TemplateObject @@ -9,3 +9,4 @@ if (-not $TemplateObject.psobject.properties.item('parameters')) { } + diff --git a/test/template-tests/testcases/deploymentTemplate/Resources-Should-Have-Location.test.ps1 b/test/template-tests/testcases/deploymentTemplate/Resources-Should-Have-Location.test.ps1 index e25edd6f6688..6660641cd090 100644 --- a/test/template-tests/testcases/deploymentTemplate/Resources-Should-Have-Location.test.ps1 +++ b/test/template-tests/testcases/deploymentTemplate/Resources-Should-Have-Location.test.ps1 @@ -1,4 +1,4 @@ -param( +param( [Parameter(Mandatory=$true,Position=0)] [PSObject] $TemplateObject @@ -14,3 +14,4 @@ foreach ($resource in $templateObject.resources) { + diff --git a/test/template-tests/testcases/deploymentTemplate/Secure-String-Parameters-Cannot-Have-Default.test.ps1 b/test/template-tests/testcases/deploymentTemplate/Secure-String-Parameters-Cannot-Have-Default.test.ps1 index 791e51c2c593..06fd8c992837 100644 --- a/test/template-tests/testcases/deploymentTemplate/Secure-String-Parameters-Cannot-Have-Default.test.ps1 +++ b/test/template-tests/testcases/deploymentTemplate/Secure-String-Parameters-Cannot-Have-Default.test.ps1 @@ -1,4 +1,4 @@ -param( +param( [Parameter(Mandatory=$true,Position=0)] [PSObject] $TemplateObject @@ -12,3 +12,4 @@ foreach ($parameter in $templateObject.parameters) { + diff --git a/test/template-tests/testcases/deploymentTemplate/Virtual-Machines-Should-Not-Be-Preview.test.ps1 b/test/template-tests/testcases/deploymentTemplate/Virtual-Machines-Should-Not-Be-Preview.test.ps1 index 62674dfdad03..ef49db0e4742 100644 --- a/test/template-tests/testcases/deploymentTemplate/Virtual-Machines-Should-Not-Be-Preview.test.ps1 +++ b/test/template-tests/testcases/deploymentTemplate/Virtual-Machines-Should-Not-Be-Preview.test.ps1 @@ -1,4 +1,4 @@ -param( +param( [Parameter(Mandatory=$true)] [PSObject] $TemplateObject @@ -18,3 +18,4 @@ foreach ($resource in $templateObject.resources) { } + From cbca1b987643f682958ea9c6bf6e326bcf3e6c8b Mon Sep 17 00:00:00 2001 From: Yuanheng Yang Date: Sat, 2 Feb 2019 10:22:59 +0800 Subject: [PATCH 21/66] Change the scripts format Replace Tab with space --- sccm-technicalpreview/scripts/InstallADDS.ps1 | 2 +- sccm-technicalpreview/scripts/InstallADK.ps1 | 24 +- sccm-technicalpreview/scripts/InstallDP.ps1 | 14 +- .../scripts/InstallFeature.ps1 | 4 +- sccm-technicalpreview/scripts/InstallMP.ps1 | 24 +- sccm-technicalpreview/scripts/InstallSCCM.ps1 | 26 +- sccm-technicalpreview/scripts/JoinDomain.ps1 | 6 +- .../scripts/OpenFirewallPort.ps1 | 55 ++- .../scripts/SetAutoLogOn.ps1 | 28 +- sccm-technicalpreview/scripts/UpgradeSCCM.ps1 | 214 +++++------ sccm-technicalpreview/scripts/WorkFlow-DC.ps1 | 73 ++-- .../scripts/WorkFlow-DPMP.ps1 | 121 +++--- .../scripts/WorkFlow-Other.ps1 | 123 +++--- .../scripts/WorkFlow-PS1.ps1 | 291 ++++++++------- sccm-technicalpreview/scripts/main.ps1 | 352 +++++++++--------- 15 files changed, 694 insertions(+), 663 deletions(-) diff --git a/sccm-technicalpreview/scripts/InstallADDS.ps1 b/sccm-technicalpreview/scripts/InstallADDS.ps1 index e3b53695bd9f..6086bbd78a55 100644 --- a/sccm-technicalpreview/scripts/InstallADDS.ps1 +++ b/sccm-technicalpreview/scripts/InstallADDS.ps1 @@ -67,6 +67,6 @@ else "[$(Get-Date -format HH:mm:ss)] AD have already installed" | Out-File -Append $logpath if(TestADDSForeastInstall -DomainFullName $DomainFullName -eq "Success") { - $result = InstallADDSForest -DomainFullName $DomainFullName + $result = InstallADDSForest -DomainFullName $DomainFullName } } \ No newline at end of file diff --git a/sccm-technicalpreview/scripts/InstallADK.ps1 b/sccm-technicalpreview/scripts/InstallADK.ps1 index 489aa26a340f..b78f809fb99b 100644 --- a/sccm-technicalpreview/scripts/InstallADK.ps1 +++ b/sccm-technicalpreview/scripts/InstallADK.ps1 @@ -18,15 +18,15 @@ $arg4 = "/q" try { - "[$(Get-Date -format HH:mm:ss)] Installing ADK..." | Out-File -Append $logpath - & $cmd $arg1 $arg2 $arg3 $arg4 | out-null - "[$(Get-Date -format HH:mm:ss)] ADK Installed Successfully!" | Out-File -Append $logpath + "[$(Get-Date -format HH:mm:ss)] Installing ADK..." | Out-File -Append $logpath + & $cmd $arg1 $arg2 $arg3 $arg4 | out-null + "[$(Get-Date -format HH:mm:ss)] ADK Installed Successfully!" | Out-File -Append $logpath } catch { - "[$(Get-Date -format HH:mm:ss)] Failed to install ADK with below error:" | Out-File -Append $logpath - $ErrorMessage = $_.Exception.Message - $ErrorMessage | Out-File -Append $logpath + "[$(Get-Date -format HH:mm:ss)] Failed to install ADK with below error:" | Out-File -Append $logpath + $ErrorMessage = $_.Exception.Message + $ErrorMessage | Out-File -Append $logpath } #ADK add-on (17763) @@ -41,13 +41,13 @@ $arg3 = "/q" try { - "[$(Get-Date -format HH:mm:ss)] Installing add-on for ADK..." | Out-File -Append $logpath - & $cmd $arg1 $arg2 $arg3 | out-null - "[$(Get-Date -format HH:mm:ss)] Add-on for ADK Installed Successfully!" | Out-File -Append $logpath + "[$(Get-Date -format HH:mm:ss)] Installing add-on for ADK..." | Out-File -Append $logpath + & $cmd $arg1 $arg2 $arg3 | out-null + "[$(Get-Date -format HH:mm:ss)] Add-on for ADK Installed Successfully!" | Out-File -Append $logpath } catch { - "[$(Get-Date -format HH:mm:ss)] Failed to install Add-on for ADK with below error:" | Out-File -Append $logpath - $ErrorMessage = $_.Exception.Message - $ErrorMessage | Out-File -Append $logpath + "[$(Get-Date -format HH:mm:ss)] Failed to install Add-on for ADK with below error:" | Out-File -Append $logpath + $ErrorMessage = $_.Exception.Message + $ErrorMessage | Out-File -Append $logpath } \ No newline at end of file diff --git a/sccm-technicalpreview/scripts/InstallDP.ps1 b/sccm-technicalpreview/scripts/InstallDP.ps1 index 078ea23d7247..1298335daf6c 100644 --- a/sccm-technicalpreview/scripts/InstallDP.ps1 +++ b/sccm-technicalpreview/scripts/InstallDP.ps1 @@ -7,19 +7,19 @@ if(!(Test-Path $ProvisionToolPath)) } $logpath = $ProvisionToolPath+"\InstallDPLog.txt" $SiteCode = $PSSiteCode # Site code - + $ProviderMachineName = $env:COMPUTERNAME+"."+$DomainFullName # SMS Provider machine name # Customizations $initParams = @{} if($ENV:SMS_ADMIN_UI_PATH -eq $null) { - $ENV:SMS_ADMIN_UI_PATH = "C:\Program Files (x86)\Microsoft Configuration Manager\AdminConsole\bin\i386" + $ENV:SMS_ADMIN_UI_PATH = "C:\Program Files (x86)\Microsoft Configuration Manager\AdminConsole\bin\i386" } # Import the ConfigurationManager.psd1 module if((Get-Module ConfigurationManager) -eq $null) { - Import-Module "$($ENV:SMS_ADMIN_UI_PATH)\..\ConfigurationManager.psd1" @initParams + Import-Module "$($ENV:SMS_ADMIN_UI_PATH)\..\ConfigurationManager.psd1" @initParams } # Connect to the site's drive if it is not already present @@ -28,9 +28,9 @@ if((Get-Module ConfigurationManager) -eq $null) { New-PSDrive -Name $SiteCode -PSProvider CMSite -Root $ProviderMachineName @initParams while((Get-PSDrive -Name $SiteCode -PSProvider CMSite -ErrorAction SilentlyContinue) -eq $null) { - "[$(Get-Date -format HH:mm:ss)] Failed ,retry in 10s. Please wait." | Out-File -Append $logpath - Start-Sleep -Seconds 10 - New-PSDrive -Name $SiteCode -PSProvider CMSite -Root $ProviderMachineName @initParams + "[$(Get-Date -format HH:mm:ss)] Failed ,retry in 10s. Please wait." | Out-File -Append $logpath + Start-Sleep -Seconds 10 + New-PSDrive -Name $SiteCode -PSProvider CMSite -Root $ProviderMachineName @initParams } # Set the current location to be the site code. @@ -39,7 +39,7 @@ Set-Location "$($SiteCode):\" @initParams $DPServerFullName = $DPServerName + "." + $DomainFullName if($(Get-CMSiteSystemServer -SiteSystemServerName $DPServerFullName) -eq $null) { - New-CMSiteSystemServer -Servername $DPServerFullName -Sitecode $SiteCode + New-CMSiteSystemServer -Servername $DPServerFullName -Sitecode $SiteCode } $Date = [DateTime]::Now.AddYears(10) diff --git a/sccm-technicalpreview/scripts/InstallFeature.ps1 b/sccm-technicalpreview/scripts/InstallFeature.ps1 index d7c07ad8ebfc..6b1bdbb9b2a3 100644 --- a/sccm-technicalpreview/scripts/InstallFeature.ps1 +++ b/sccm-technicalpreview/scripts/InstallFeature.ps1 @@ -76,11 +76,11 @@ if($rolelist -contains "Management point") } if($rolelist -contains "Reporting services point") { - #installed .net 4.5 or later + #installed .net 4.5 or later } if($rolelist -contains "Service connection point") { - #installed .net 4.5 or later + #installed .net 4.5 or later } if($rolelist -contains "Software update point") { diff --git a/sccm-technicalpreview/scripts/InstallMP.ps1 b/sccm-technicalpreview/scripts/InstallMP.ps1 index 4042e1c9d3c5..3ea6e2c18363 100644 --- a/sccm-technicalpreview/scripts/InstallMP.ps1 +++ b/sccm-technicalpreview/scripts/InstallMP.ps1 @@ -9,19 +9,19 @@ if(!(Test-Path $ProvisionToolPath)) } $logpath = $ProvisionToolPath+"\InstallMPLog.txt" $SiteCode = $PSSiteCode # Site code - + $ProviderMachineName = $env:COMPUTERNAME+"."+$DomainFullName # SMS Provider machine name # Customizations $initParams = @{} if($ENV:SMS_ADMIN_UI_PATH -eq $null) { - $ENV:SMS_ADMIN_UI_PATH = "C:\Program Files (x86)\Microsoft Configuration Manager\AdminConsole\bin\i386" + $ENV:SMS_ADMIN_UI_PATH = "C:\Program Files (x86)\Microsoft Configuration Manager\AdminConsole\bin\i386" } # Import the ConfigurationManager.psd1 module if((Get-Module ConfigurationManager) -eq $null) { - Import-Module "$($ENV:SMS_ADMIN_UI_PATH)\..\ConfigurationManager.psd1" @initParams + Import-Module "$($ENV:SMS_ADMIN_UI_PATH)\..\ConfigurationManager.psd1" @initParams } # Connect to the site's drive if it is not already present @@ -30,9 +30,9 @@ if((Get-Module ConfigurationManager) -eq $null) { New-PSDrive -Name $SiteCode -PSProvider CMSite -Root $ProviderMachineName @initParams while((Get-PSDrive -Name $SiteCode -PSProvider CMSite -ErrorAction SilentlyContinue) -eq $null) { - "[$(Get-Date -format HH:mm:ss)] Failed ,retry in 10s. Please wait." | Out-File -Append $logpath - Start-Sleep -Seconds 10 - New-PSDrive -Name $SiteCode -PSProvider CMSite -Root $ProviderMachineName @initParams + "[$(Get-Date -format HH:mm:ss)] Failed ,retry in 10s. Please wait." | Out-File -Append $logpath + Start-Sleep -Seconds 10 + New-PSDrive -Name $SiteCode -PSProvider CMSite -Root $ProviderMachineName @initParams } # Set the current location to be the site code. @@ -42,7 +42,7 @@ $MPServerFullName = $MPServerName + "." + $DomainFullName if($(Get-CMSiteSystemServer -SiteSystemServerName $MPServerFullName) -eq $null) { - New-CMSiteSystemServer -Servername $MPServerFullName -Sitecode $SiteCode + New-CMSiteSystemServer -Servername $MPServerFullName -Sitecode $SiteCode } $DomainName = $DomainFullName.split('.')[0] $DName = $DomainName + "\" + $DomainAdminName @@ -50,16 +50,16 @@ $DName = $DomainName + "\" + $DomainAdminName $pwd = $Password | ConvertTo-SecureString -AsPlainText -Force while($(Get-CMAccount -UserName $DName) -eq $null) { - "[$(Get-Date -format HH:mm:ss)] New CM Account $DomainAdminName." | Out-File -Append $logpath - New-CMAccount -UserName $DName -Password $pwd - Start-Sleep -Seconds 10 + "[$(Get-Date -format HH:mm:ss)] New CM Account $DomainAdminName." | Out-File -Append $logpath + New-CMAccount -UserName $DName -Password $pwd + Start-Sleep -Seconds 10 } $SQLServerFqdnName = "$SQLServerName.$env:userdnsdomain" if($SQLInstanceName -eq "MSSQLSERVER") { - Add-CMManagementPoint -SiteSystemServerName $MPServerFullName -SiteCode $SiteCode -ClientConnectionType InternetAndIntranet -AllowDevice -GenerateAlert -SQLServerFqdnName $SQLServerFqdnName -DatabaseName $DBName -UserName $DName + Add-CMManagementPoint -SiteSystemServerName $MPServerFullName -SiteCode $SiteCode -ClientConnectionType InternetAndIntranet -AllowDevice -GenerateAlert -SQLServerFqdnName $SQLServerFqdnName -DatabaseName $DBName -UserName $DName } else { - Add-CMManagementPoint -SiteSystemServerName $MPServerFullName -SiteCode $SiteCode -ClientConnectionType InternetAndIntranet -AllowDevice -GenerateAlert -SQLServerFqdnName $SQLServerFqdnName -SQLServerInstanceName $SQLInstanceName -DatabaseName $DBName -UserName $DName + Add-CMManagementPoint -SiteSystemServerName $MPServerFullName -SiteCode $SiteCode -ClientConnectionType InternetAndIntranet -AllowDevice -GenerateAlert -SQLServerFqdnName $SQLServerFqdnName -SQLServerInstanceName $SQLInstanceName -DatabaseName $DBName -UserName $DName } \ No newline at end of file diff --git a/sccm-technicalpreview/scripts/InstallSCCM.ps1 b/sccm-technicalpreview/scripts/InstallSCCM.ps1 index 1280d969fd44..23bb4ba16b73 100644 --- a/sccm-technicalpreview/scripts/InstallSCCM.ps1 +++ b/sccm-technicalpreview/scripts/InstallSCCM.ps1 @@ -20,16 +20,16 @@ $AzcopyPath = "C:\Program Files (x86)\Microsoft SDKs\Azure\AzCopy" if(!(Test-Path $AzcopyPath)) { - $path = "$ProvisionToolPath\azcopy.msi" - if(!(Test-Path $path)) - { - #Download azcopy - $url = "http://aka.ms/downloadazcopy" - Invoke-WebRequest -Uri $url -OutFile $path - } - - #Install azcopy - Start-Process msiexec.exe -Wait -ArgumentList "/I $path /quiet" + $path = "$ProvisionToolPath\azcopy.msi" + if(!(Test-Path $path)) + { + #Download azcopy + $url = "http://aka.ms/downloadazcopy" + Invoke-WebRequest -Uri $url -OutFile $path + } + + #Install azcopy + Start-Process msiexec.exe -Wait -ArgumentList "/I $path /quiet" } $cmpath = "c:\"+$CM+".exe" @@ -113,12 +113,12 @@ SysCenterId= if($SQLInstanceName.ToUpper() -eq "MSSQLSERVER") { - $cmini = $cmini.Replace('%SQLInstance%',"") + $cmini = $cmini.Replace('%SQLInstance%',"") } else { - $tinstance = $SQLInstanceName.ToUpper() + "\" - $cmini = $cmini.Replace('%SQLInstance%',$tinstance) + $tinstance = $SQLInstanceName.ToUpper() + "\" + $cmini = $cmini.Replace('%SQLInstance%',$tinstance) } $CMInstallationFile = "c:\" + $CM + "\SMSSETUP\BIN\X64\Setup.exe" $cmini > $CMINIPath diff --git a/sccm-technicalpreview/scripts/JoinDomain.ps1 b/sccm-technicalpreview/scripts/JoinDomain.ps1 index 7004d84e2f4d..8a3d6d3bc018 100644 --- a/sccm-technicalpreview/scripts/JoinDomain.ps1 +++ b/sccm-technicalpreview/scripts/JoinDomain.ps1 @@ -13,8 +13,8 @@ if($DCIPaddress -eq "") } else { - "[$(Get-Date -format HH:mm:ss)] Set DNS to $DCIPaddress" | Out-File -Append $logpath - Set-DnsClientServerAddress -InterfaceIndex $dnsset.InterfaceIndex -ServerAddresses $DCIPaddress + "[$(Get-Date -format HH:mm:ss)] Set DNS to $DCIPaddress" | Out-File -Append $logpath + Set-DnsClientServerAddress -InterfaceIndex $dnsset.InterfaceIndex -ServerAddresses $DCIPaddress } $DomainName = $DomainFullName.split('.')[0] $DName = $DomainName + "\" + $DomainAdminName @@ -27,7 +27,7 @@ $credential = New-Object System.Management.Automation.PSCredential($DName,$pwd) try { Add-Computer -DomainName $DomainFullName -Credential $credential - "[$(Get-Date -format HH:mm:ss)] Finished!" | Out-File -Append $logpath + "[$(Get-Date -format HH:mm:ss)] Finished!" | Out-File -Append $logpath } catch { diff --git a/sccm-technicalpreview/scripts/OpenFirewallPort.ps1 b/sccm-technicalpreview/scripts/OpenFirewallPort.ps1 index 7bea3fc7633a..222d33a71b6d 100644 --- a/sccm-technicalpreview/scripts/OpenFirewallPort.ps1 +++ b/sccm-technicalpreview/scripts/OpenFirewallPort.ps1 @@ -8,8 +8,8 @@ $logpath = $ProvisionToolPath+"\OpenFirewallPortLog.txt" if($rolelist -contains "DC") { #HTTP(S) Requests - New-NetFirewallRule -DisplayName 'HTTP(S) Outbound' -Profile Any -Direction Outbound -Action Allow -Protocol TCP -LocalPort @(80,443) -Group "For DC" - New-NetFirewallRule -DisplayName 'HTTP(S) Inbound' -Profile Any -Direction Inbound -Action Allow -Protocol TCP -LocalPort @(80,443) -Group "For DC" + New-NetFirewallRule -DisplayName 'HTTP(S) Outbound' -Profile Any -Direction Outbound -Action Allow -Protocol TCP -LocalPort @(80,443) -Group "For DC" + New-NetFirewallRule -DisplayName 'HTTP(S) Inbound' -Profile Any -Direction Inbound -Action Allow -Protocol TCP -LocalPort @(80,443) -Group "For DC" #PS-->DC(in) New-NetFirewallRule -DisplayName 'LDAP Inbound' -Profile Any -Direction Inbound -Action Allow -Protocol TCP -LocalPort 389 -Group "For DC" @@ -23,19 +23,19 @@ if($rolelist -contains "DC") New-NetFirewallRule -DisplayName 'RPC Inbound' -Profile Any -Direction Inbound -Action Allow -Protocol TCP -LocalPort 1024-65535 -Group "For DC" #THAgent - Enable-NetFirewallRule -DisplayGroup "Windows Management Instrumentation (WMI)" -Direction Inbound - Enable-NetFirewallRule -DisplayGroup "File and Printer Sharing" + Enable-NetFirewallRule -DisplayGroup "Windows Management Instrumentation (WMI)" -Direction Inbound + Enable-NetFirewallRule -DisplayGroup "File and Printer Sharing" } if($rolelist -contains "Site Server") { New-NetFirewallRule -DisplayName 'HTTP(S) Outbound' -Profile Any -Direction Outbound -Action Allow -Protocol TCP -LocalPort @(80,443) -Group "For SCCM" - New-NetFirewallRule -DisplayName 'HTTP(S) Inbound' -Profile Any -Direction Inbound -Action Allow -Protocol TCP -LocalPort @(80,443) -Group "For SCCM" + New-NetFirewallRule -DisplayName 'HTTP(S) Inbound' -Profile Any -Direction Inbound -Action Allow -Protocol TCP -LocalPort @(80,443) -Group "For SCCM" #site server<->site server New-NetFirewallRule -DisplayName 'SMB Inbound' -Profile Any -Direction Inbound -Action Allow -Protocol TCP -LocalPort 445 -Group "For SCCM" New-NetFirewallRule -DisplayName 'SMB Outbound' -Profile Any -Direction Outbound -Action Allow -Protocol TCP -LocalPort 445 -Group "For SCCM" - New-NetFirewallRule -DisplayName 'PPTP Inbound' -Profile Any -Direction Inbound -Action Allow -Protocol TCP -LocalPort 1723 -Group "For SCCM" + New-NetFirewallRule -DisplayName 'PPTP Inbound' -Profile Any -Direction Inbound -Action Allow -Protocol TCP -LocalPort 1723 -Group "For SCCM" New-NetFirewallRule -DisplayName 'PPTP Outbound' -Profile Any -Direction Outbound -Action Allow -Protocol TCP -LocalPort 1723 -Group "For SCCM" #priary site server(out) ->DC @@ -66,12 +66,12 @@ if($rolelist -contains "Software Update Point") New-NetFirewallRule -DisplayName 'SMB SUPInbound' -Profile Any -Direction Inbound -Action Allow -Protocol TCP -LocalPort 445 -Group "For SCCM SUP" New-NetFirewallRule -DisplayName 'SMB SUP Outbound' -Profile Any -Direction Outbound -Action Allow -Protocol TCP -LocalPort 445 -Group "For SCCM SUP" New-NetFirewallRule -DisplayName 'HTTP(S) SUP Outbound' -Profile Any -Direction Outbound -Action Allow -Protocol TCP -LocalPort @(8530,8531) -Group "For SCCM SUP" - New-NetFirewallRule -DisplayName 'HTTP(S) SUP Inbound' -Profile Any -Direction Inbound -Action Allow -Protocol TCP -LocalPort @(8530,8531) -Group "For SCCM SUP" + New-NetFirewallRule -DisplayName 'HTTP(S) SUP Inbound' -Profile Any -Direction Inbound -Action Allow -Protocol TCP -LocalPort @(8530,8531) -Group "For SCCM SUP" #SUP->Internet New-NetFirewallRule -DisplayName 'HTTP Outbound' -Profile Any -Direction Outbound -Action Allow -Protocol TCP -LocalPort 80 -Group "For SCCM SUP" New-NetFirewallRule -DisplayName 'HTTP(S) Outbound' -Profile Any -Direction Outbound -Action Allow -Protocol TCP -LocalPort @(80,443) -Group "For SCCM SUP" - New-NetFirewallRule -DisplayName 'HTTP(S) Inbound' -Profile Any -Direction Inbound -Action Allow -Protocol TCP -LocalPort @(80,443) -Group "For SCCM SUP" + New-NetFirewallRule -DisplayName 'HTTP(S) Inbound' -Profile Any -Direction Inbound -Action Allow -Protocol TCP -LocalPort @(80,443) -Group "For SCCM SUP" } if($rolelist -ccontains "State Migration Point") { @@ -131,18 +131,17 @@ if($rolelist -contains "Fallback Status Point") } if($rolelist -contains "Reporting Services Point") { - New-NetFirewallRule -DisplayName 'SQL over TCP Inbound' -Profile Any -Direction Inbound -Action Allow -Protocol TCP -LocalPort 1433 -Group "For SCCM RSP" - New-NetFirewallRule -DisplayName 'SQL over TCP Outbound' -Profile Any -Direction Outbound -Action Allow -Protocol TCP -LocalPort 1433 -Group "For SCCM RSP" - New-NetFirewallRule -DisplayName 'HTTP(S) Inbound' -Profile Any -Direction Inbound -Action Allow -Protocol TCP -LocalPort @(80,443) -Group "For SCCM RSP" - New-NetFirewallRule -DisplayName 'SMB Inbound' -Profile Any -Direction Inbound -Action Allow -Protocol TCP -LocalPort 445 -Group "For SCCM RSP" - New-NetFirewallRule -DisplayName 'RPC Endpoint Mapper Inbound' -Profile Any -Direction Inbound -Action Allow -Protocol TCP -LocalPort 135 -Group "For SCCM RSP" - New-NetFirewallRule -DisplayName 'RPC Endpoint Mapper UDP Inbound' -Profile Any -Direction Inbound -Action Allow -Protocol UDP -LocalPort 135 -Group "For SCCM RSP" - #dynamic port - New-NetFirewallRule -DisplayName 'RPC Inbound' -Profile Any -Direction Inbound -Action Allow -Protocol TCP -LocalPort 1024-65535 -Group "For SCCM RSP" + New-NetFirewallRule -DisplayName 'SQL over TCP Inbound' -Profile Any -Direction Inbound -Action Allow -Protocol TCP -LocalPort 1433 -Group "For SCCM RSP" + New-NetFirewallRule -DisplayName 'SQL over TCP Outbound' -Profile Any -Direction Outbound -Action Allow -Protocol TCP -LocalPort 1433 -Group "For SCCM RSP" + New-NetFirewallRule -DisplayName 'HTTP(S) Inbound' -Profile Any -Direction Inbound -Action Allow -Protocol TCP -LocalPort @(80,443) -Group "For SCCM RSP" + New-NetFirewallRule -DisplayName 'SMB Inbound' -Profile Any -Direction Inbound -Action Allow -Protocol TCP -LocalPort 445 -Group "For SCCM RSP" + New-NetFirewallRule -DisplayName 'RPC Endpoint Mapper Inbound' -Profile Any -Direction Inbound -Action Allow -Protocol TCP -LocalPort 135 -Group "For SCCM RSP" + New-NetFirewallRule -DisplayName 'RPC Endpoint Mapper UDP Inbound' -Profile Any -Direction Inbound -Action Allow -Protocol UDP -LocalPort 135 -Group "For SCCM RSP" + #dynamic port + New-NetFirewallRule -DisplayName 'RPC Inbound' -Profile Any -Direction Inbound -Action Allow -Protocol TCP -LocalPort 1024-65535 -Group "For SCCM RSP" } if($rolelist -contains "Distribution Point") { - New-NetFirewallRule -DisplayName 'HTTP(S) Inbound' -Profile Any -Direction Inbound -Action Allow -Protocol TCP -LocalPort @(80,443) -Group "For SCCM DP" New-NetFirewallRule -DisplayName 'SMB DP Inbound' -Profile Any -Direction Inbound -Action Allow -Protocol TCP -LocalPort 445 -Group "For SCCM DP" New-NetFirewallRule -DisplayName 'Multicast Protocol Inbound' -Profile Any -Direction Inbound -Action Allow -Protocol TCP -LocalPort 63000-64000 -Group "For SCCM DP" @@ -185,9 +184,9 @@ if($rolelist -contains "Server Locator Point") if($rolelist -contains "SQL Server") { New-NetFirewallRule -DisplayName 'SQL over TCP Inbound' -Profile Any -Direction Inbound -Action Allow -Protocol TCP -LocalPort 1433 -Group "For SQL Server" - New-NetFirewallRule -DisplayName 'WMI' -Program "%systemroot%\system32\svchost.exe" -Service "winmgmt" -Profile Any -Direction Inbound -Action Allow -Protocol TCP -LocalPort any -Group "For SQL Server WMI" - New-NetFirewallRule -DisplayName 'DCOM' -Program "%systemroot%\system32\svchost.exe" -Service "rpcss" -Profile Any -Direction Inbound -Action Allow -Protocol TCP -LocalPort 135 -Group "For SQL Server DCOM" - New-NetFirewallRule -DisplayName 'SMB Provider Inbound' -Profile Any -Direction Inbound -Action Allow -Protocol TCP -LocalPort 445 -Group "For SQL Server" + New-NetFirewallRule -DisplayName 'WMI' -Program "%systemroot%\system32\svchost.exe" -Service "winmgmt" -Profile Any -Direction Inbound -Action Allow -Protocol TCP -LocalPort any -Group "For SQL Server WMI" + New-NetFirewallRule -DisplayName 'DCOM' -Program "%systemroot%\system32\svchost.exe" -Service "rpcss" -Profile Any -Direction Inbound -Action Allow -Protocol TCP -LocalPort 135 -Group "For SQL Server DCOM" + New-NetFirewallRule -DisplayName 'SMB Provider Inbound' -Profile Any -Direction Inbound -Action Allow -Protocol TCP -LocalPort 445 -Group "For SQL Server" } if($rolelist -contains "Provider") { @@ -208,12 +207,12 @@ if($rolelist -contains "Asset Intelligence Synchronization Point") } if($rolelist -contains "CM Console") { - New-NetFirewallRule -DisplayName 'RPC Outbound' -Profile Any -Direction Outbound -Action Allow -Protocol TCP -LocalPort 135 -Group "For SCCM Console" - #cm console->client - New-NetFirewallRule -DisplayName 'Remote Control(control) Outbound' -Profile Any -Direction Outbound -Action Allow -Protocol TCP -LocalPort 2701 -Group "For SCCM Console" - New-NetFirewallRule -DisplayName 'Remote Control(control) Outbound' -Profile Any -Direction Outbound -Action Allow -Protocol UDP -LocalPort 2701 -Group "For SCCM Console" - New-NetFirewallRule -DisplayName 'Remote Control(data) Outbound' -Profile Any -Direction Outbound -Action Allow -Protocol TCP -LocalPort 2702 -Group "For SCCM Console" - New-NetFirewallRule -DisplayName 'Remote Control(data) Outbound' -Profile Any -Direction Outbound -Action Allow -Protocol UDP -LocalPort 2702 -Group "For SCCM Console" - New-NetFirewallRule -DisplayName 'Remote Control(RPC Endpoint Mapper) Outbound' -Profile Any -Direction Outbound -Action Allow -Protocol TCP -LocalPort 135 -Group "For SCCM Console" - New-NetFirewallRule -DisplayName 'Remote Assistance(RDP AND RTC) Outbound' -Profile Any -Direction Outbound -Action Allow -Protocol TCP -LocalPort 3389 -Group "For SCCM Console" + New-NetFirewallRule -DisplayName 'RPC Outbound' -Profile Any -Direction Outbound -Action Allow -Protocol TCP -LocalPort 135 -Group "For SCCM Console" + #cm console->client + New-NetFirewallRule -DisplayName 'Remote Control(control) Outbound' -Profile Any -Direction Outbound -Action Allow -Protocol TCP -LocalPort 2701 -Group "For SCCM Console" + New-NetFirewallRule -DisplayName 'Remote Control(control) Outbound' -Profile Any -Direction Outbound -Action Allow -Protocol UDP -LocalPort 2701 -Group "For SCCM Console" + New-NetFirewallRule -DisplayName 'Remote Control(data) Outbound' -Profile Any -Direction Outbound -Action Allow -Protocol TCP -LocalPort 2702 -Group "For SCCM Console" + New-NetFirewallRule -DisplayName 'Remote Control(data) Outbound' -Profile Any -Direction Outbound -Action Allow -Protocol UDP -LocalPort 2702 -Group "For SCCM Console" + New-NetFirewallRule -DisplayName 'Remote Control(RPC Endpoint Mapper) Outbound' -Profile Any -Direction Outbound -Action Allow -Protocol TCP -LocalPort 135 -Group "For SCCM Console" + New-NetFirewallRule -DisplayName 'Remote Assistance(RDP AND RTC) Outbound' -Profile Any -Direction Outbound -Action Allow -Protocol TCP -LocalPort 3389 -Group "For SCCM Console" } \ No newline at end of file diff --git a/sccm-technicalpreview/scripts/SetAutoLogOn.ps1 b/sccm-technicalpreview/scripts/SetAutoLogOn.ps1 index e8a11ab6b394..94ed5b807b30 100644 --- a/sccm-technicalpreview/scripts/SetAutoLogOn.ps1 +++ b/sccm-technicalpreview/scripts/SetAutoLogOn.ps1 @@ -10,7 +10,7 @@ $isdomain = $false $NetBIOSName = "" if($DomainFullName) { - $isdomain = $true + $isdomain = $true $NetBIOSName = $DomainFullName.split('.')[0] $Username = $NetBIOSName + '\' + $Username } @@ -19,35 +19,35 @@ $RegPath = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" "[$(Get-Date -format HH:mm:ss)] Start setting auto logon for $Username." | Out-File -Append $logpath while((Get-ItemProperty $RegPath).AutoAdminLogon -ne 1) { - "[$(Get-Date -format HH:mm:ss)] Setting AutoAdminLogon to 1." | Out-File -Append $logpath - Set-ItemProperty $RegPath "AutoAdminLogon" -Value "1" -type String + "[$(Get-Date -format HH:mm:ss)] Setting AutoAdminLogon to 1." | Out-File -Append $logpath + Set-ItemProperty $RegPath "AutoAdminLogon" -Value "1" -type String } while((Get-ItemProperty $RegPath).DefaultUsername -ne $Username) { - "[$(Get-Date -format HH:mm:ss)] Setting DefaultUsername to $Username." | Out-File -Append $logpath - Set-ItemProperty $RegPath "DefaultUsername" -Value "$Username" -type String + "[$(Get-Date -format HH:mm:ss)] Setting DefaultUsername to $Username." | Out-File -Append $logpath + Set-ItemProperty $RegPath "DefaultUsername" -Value "$Username" -type String } while((Get-ItemProperty $RegPath).DefaultPassword -ne $password) { - "[$(Get-Date -format HH:mm:ss)] Setting Password..." | Out-File -Append $logpath - Set-ItemProperty $RegPath "DefaultPassword" -Value "$password" -type String + "[$(Get-Date -format HH:mm:ss)] Setting Password..." | Out-File -Append $logpath + Set-ItemProperty $RegPath "DefaultPassword" -Value "$password" -type String } while((Get-ItemProperty $RegPath).AutoLogonCount -ne 1) { - "[$(Get-Date -format HH:mm:ss)] Setting Logon count to 1." | Out-File -Append $logpath - Set-ItemProperty $RegPath "AutoLogonCount" -Value 1 -type DWord + "[$(Get-Date -format HH:mm:ss)] Setting Logon count to 1." | Out-File -Append $logpath + Set-ItemProperty $RegPath "AutoLogonCount" -Value 1 -type DWord } if($isdomain) { - while((Get-ItemProperty $RegPath).DefaultDomainName -ne $NetBIOSName) - { - "[$(Get-Date -format HH:mm:ss)] Setting DefaultDomainName to $NetBIOSName." | Out-File -Append $logpath - Set-ItemProperty $RegPath "DefaultDomainName" -Value $NetBIOSName -type String - } + while((Get-ItemProperty $RegPath).DefaultDomainName -ne $NetBIOSName) + { + "[$(Get-Date -format HH:mm:ss)] Setting DefaultDomainName to $NetBIOSName." | Out-File -Append $logpath + Set-ItemProperty $RegPath "DefaultDomainName" -Value $NetBIOSName -type String + } } "[$(Get-Date -format HH:mm:ss)] Finished." | Out-File -Append $logpath \ No newline at end of file diff --git a/sccm-technicalpreview/scripts/UpgradeSCCM.ps1 b/sccm-technicalpreview/scripts/UpgradeSCCM.ps1 index da3c63412d59..672446d91177 100644 --- a/sccm-technicalpreview/scripts/UpgradeSCCM.ps1 +++ b/sccm-technicalpreview/scripts/UpgradeSCCM.ps1 @@ -7,19 +7,19 @@ if(!(Test-Path $ProvisionToolPath)) } $logpath = $ProvisionToolPath+"\UpgradeCMlog.txt" $SiteCode = Get-ItemPropertyValue -Path 'HKLM:\SOFTWARE\Microsoft\SMS\Identification' -Name 'Site Code' - + $ProviderMachineName = $env:COMPUTERNAME+"."+$DomainFullName # SMS Provider machine name # Customizations $initParams = @{} if($ENV:SMS_ADMIN_UI_PATH -eq $null) { - $ENV:SMS_ADMIN_UI_PATH = "C:\Program Files (x86)\Microsoft Configuration Manager\AdminConsole\bin\i386" + $ENV:SMS_ADMIN_UI_PATH = "C:\Program Files (x86)\Microsoft Configuration Manager\AdminConsole\bin\i386" } # Import the ConfigurationManager.psd1 module if((Get-Module ConfigurationManager) -eq $null) { - Import-Module "$($ENV:SMS_ADMIN_UI_PATH)\..\ConfigurationManager.psd1" @initParams + Import-Module "$($ENV:SMS_ADMIN_UI_PATH)\..\ConfigurationManager.psd1" @initParams } # Connect to the site's drive if it is not already present @@ -28,9 +28,9 @@ New-PSDrive -Name $SiteCode -PSProvider CMSite -Root $ProviderMachineName @initP while((Get-PSDrive -Name $SiteCode -PSProvider CMSite -ErrorAction SilentlyContinue) -eq $null) { - "[$(Get-Date -format HH:mm:ss)] Retry in 10s to set PS Drive. Please wait." | Out-File -Append $logpath - Start-Sleep -Seconds 10 - New-PSDrive -Name $SiteCode -PSProvider CMSite -Root $ProviderMachineName @initParams + "[$(Get-Date -format HH:mm:ss)] Retry in 10s to set PS Drive. Please wait." | Out-File -Append $logpath + Start-Sleep -Seconds 10 + New-PSDrive -Name $SiteCode -PSProvider CMSite -Root $ProviderMachineName @initParams } # Set the current location to be the site code. @@ -158,114 +158,114 @@ while($updatepack -ne "") if($retrytimes -eq 3) { $upgradingfailed = $true - break; + break } $updatepack = Get-CMSiteUpdate -Fast -Name $updatepack.Name - while($updatepack.State -eq 327682 -or $updatepack.State -eq 262145 -or $updatepack.State -eq 327679) - { - #package not downloaded - if($updatepack.State -eq 327682) - { - Invoke-CMSiteUpdateDownload -Name $updatepack.Name -Force -WarningAction SilentlyContinue - Start-Sleep 120 - $updatepack = Get-CMSiteUpdate -Name $updatepack.Name -Fast - $downloadstarttime = get-date - while($updatepack.State -eq 327682) - { - "[$(Get-Date -format HH:mm:ss)] Waiting SCCM Upgrade package start to download, sleep 2 min..." | Out-File -Append $logpath - Start-Sleep 120 - $updatepack = Get-CMSiteUpdate -Name $updatepack.Name -Fast - $downloadspan = New-TimeSpan -Start $downloadstarttime -End (Get-Date) - if($downloadspan.Hours -ge 1) - { - Restart-Service -DisplayName "SMS_Executive" - Start-Sleep 120 - $downloadstarttime = get-date - } - } - } - #waiting package downloaded - $downloadstarttime = get-date - while($updatepack.State -eq 262145) - { - "[$(Get-Date -format HH:mm:ss)] Waiting SCCM Upgrade package download, sleep 2 min..." | Out-File -Append $logpath - Start-Sleep 120 - $updatepack = Get-CMSiteUpdate -Name $updatepack.Name -Fast - $downloadspan = New-TimeSpan -Start $downloadstarttime -End (Get-Date) - if($downloadspan.Hours -ge 1) - { - Restart-Service -DisplayName "SMS_Executive" - Start-Sleep 120 - $downloadstarttime = get-date - } - } + while($updatepack.State -eq 327682 -or $updatepack.State -eq 262145 -or $updatepack.State -eq 327679) + { + #package not downloaded + if($updatepack.State -eq 327682) + { + Invoke-CMSiteUpdateDownload -Name $updatepack.Name -Force -WarningAction SilentlyContinue + Start-Sleep 120 + $updatepack = Get-CMSiteUpdate -Name $updatepack.Name -Fast + $downloadstarttime = get-date + while($updatepack.State -eq 327682) + { + "[$(Get-Date -format HH:mm:ss)] Waiting SCCM Upgrade package start to download, sleep 2 min..." | Out-File -Append $logpath + Start-Sleep 120 + $updatepack = Get-CMSiteUpdate -Name $updatepack.Name -Fast + $downloadspan = New-TimeSpan -Start $downloadstarttime -End (Get-Date) + if($downloadspan.Hours -ge 1) + { + Restart-Service -DisplayName "SMS_Executive" + Start-Sleep 120 + $downloadstarttime = get-date + } + } + } + #waiting package downloaded + $downloadstarttime = get-date + while($updatepack.State -eq 262145) + { + "[$(Get-Date -format HH:mm:ss)] Waiting SCCM Upgrade package download, sleep 2 min..." | Out-File -Append $logpath + Start-Sleep 120 + $updatepack = Get-CMSiteUpdate -Name $updatepack.Name -Fast + $downloadspan = New-TimeSpan -Start $downloadstarttime -End (Get-Date) + if($downloadspan.Hours -ge 1) + { + Restart-Service -DisplayName "SMS_Executive" + Start-Sleep 120 + $downloadstarttime = get-date + } + } - #downloading failed - if($updatepack.State -eq 327679) - { - $retrytimes++; - Start-Sleep 300 - continue; - } - } - #trigger prerequisites check after the package downloaded - Invoke-CMSiteUpdatePrerequisiteCheck -Name $updatepack.Name - while($updatepack.State -ne 196607 -and $updatepack.State -ne 131074 -and $updatepack.State -ne 131075) - { - ("[$(Get-Date -format HH:mm:ss)] Waiting checking prerequisites complete, current pack " + $updatepack.Name + " state is " + ($state.($updatepack.State)) + ", sleep 2 min...") | Out-File -Append $logpath - Start-Sleep 120 - $updatepack = Get-CMSiteUpdate -Fast -Name $updatepack.Name - } - if($updatepack.State -eq 196607) - { - $retrytimes++; - Start-Sleep 300 - continue; - } - #trigger setup after the prerequisites check - Install-CMSiteUpdate -Name $updatepack.Name -SkipPrerequisiteCheck -Force - while($updatepack.State -ne 196607 -and $updatepack.State -ne 262143 -and $updatepack.State -ne 196612) - { - ("[$(Get-Date -format HH:mm:ss)] Waiting SCCM Upgrade Complete, current pack " + $updatepack.Name + " state is " + ($state.($updatepack.State)) + ", sleep 2 min...") | Out-File -Append $logpath - Start-Sleep 120 - $updatepack = Get-CMSiteUpdate -Fast -Name $updatepack.Name - } - if($updatepack.State -eq 196612) - { - ("[$(Get-Date -format HH:mm:ss)] SCCM Upgrade Complete, current pack " + $updatepack.Name + " state is " + ($state.($updatepack.State)) ) | Out-File -Append $logpath - #we need waiting the copying files finished if there is only one site - $toplevelsite = Get-CMSite |where {$_.ReportingSiteCode -eq ""} - if((Get-CMSite).count -eq 1) - { - $path= Get-ItemPropertyValue -Path 'HKLM:\SOFTWARE\Microsoft\SMS\Setup' -Name 'Installation Directory' + #downloading failed + if($updatepack.State -eq 327679) + { + $retrytimes++ + Start-Sleep 300 + continue + } + } + #trigger prerequisites check after the package downloaded + Invoke-CMSiteUpdatePrerequisiteCheck -Name $updatepack.Name + while($updatepack.State -ne 196607 -and $updatepack.State -ne 131074 -and $updatepack.State -ne 131075) + { + ("[$(Get-Date -format HH:mm:ss)] Waiting checking prerequisites complete, current pack " + $updatepack.Name + " state is " + ($state.($updatepack.State)) + ", sleep 2 min...") | Out-File -Append $logpath + Start-Sleep 120 + $updatepack = Get-CMSiteUpdate -Fast -Name $updatepack.Name + } + if($updatepack.State -eq 196607) + { + $retrytimes++ + Start-Sleep 300 + continue + } + #trigger setup after the prerequisites check + Install-CMSiteUpdate -Name $updatepack.Name -SkipPrerequisiteCheck -Force + while($updatepack.State -ne 196607 -and $updatepack.State -ne 262143 -and $updatepack.State -ne 196612) + { + ("[$(Get-Date -format HH:mm:ss)] Waiting SCCM Upgrade Complete, current pack " + $updatepack.Name + " state is " + ($state.($updatepack.State)) + ", sleep 2 min...") | Out-File -Append $logpath + Start-Sleep 120 + $updatepack = Get-CMSiteUpdate -Fast -Name $updatepack.Name + } + if($updatepack.State -eq 196612) + { + ("[$(Get-Date -format HH:mm:ss)] SCCM Upgrade Complete, current pack " + $updatepack.Name + " state is " + ($state.($updatepack.State)) ) | Out-File -Append $logpath + #we need waiting the copying files finished if there is only one site + $toplevelsite = Get-CMSite |where {$_.ReportingSiteCode -eq ""} + if((Get-CMSite).count -eq 1) + { + $path= Get-ItemPropertyValue -Path 'HKLM:\SOFTWARE\Microsoft\SMS\Setup' -Name 'Installation Directory' - $fileversion=(Get-Item ($path+'\cd.latest\SMSSETUP\BIN\X64\setup.exe')).VersionInfo.FileVersion.split('.')[2] - while($fileversion -ne $toplevelsite.BuildNumber) - { - Start-Sleep 120 - $fileversion=(Get-Item ($path+'\cd.latest\SMSSETUP\BIN\X64\setup.exe')).VersionInfo.FileVersion.split('.')[2] - } - #Wait for copying files finished - Start-Sleep 600 - } - #Get if there are any other updates need to be installed - $updatepack = getupdate - } - if($updatepack.State -eq 196607 -or $updatepack.State -eq 262143 ) - { - if($retrytimes -le 3) - { - $upgradingfailed = $true - Start-Sleep 300 - continue; - } - $retrytimes = $retrytimes + 1; - } + $fileversion=(Get-Item ($path+'\cd.latest\SMSSETUP\BIN\X64\setup.exe')).VersionInfo.FileVersion.split('.')[2] + while($fileversion -ne $toplevelsite.BuildNumber) + { + Start-Sleep 120 + $fileversion=(Get-Item ($path+'\cd.latest\SMSSETUP\BIN\X64\setup.exe')).VersionInfo.FileVersion.split('.')[2] + } + #Wait for copying files finished + Start-Sleep 600 + } + #Get if there are any other updates need to be installed + $updatepack = getupdate + } + if($updatepack.State -eq 196607 -or $updatepack.State -eq 262143 ) + { + if($retrytimes -le 3) + { + $upgradingfailed = $true + Start-Sleep 300 + continue + } + $retrytimes = $retrytimes + 1 + } } if($upgradingfailed -eq $true) { - ("[$(Get-Date -format HH:mm:ss)] Upgrade " + $updatepack.Name + " failed") | Out-File -Append $logpath - throw + ("[$(Get-Date -format HH:mm:ss)] Upgrade " + $updatepack.Name + " failed") | Out-File -Append $logpath + throw } \ No newline at end of file diff --git a/sccm-technicalpreview/scripts/WorkFlow-DC.ps1 b/sccm-technicalpreview/scripts/WorkFlow-DC.ps1 index 4faf3236dda5..05ae934ee803 100644 --- a/sccm-technicalpreview/scripts/WorkFlow-DC.ps1 +++ b/sccm-technicalpreview/scripts/WorkFlow-DC.ps1 @@ -24,71 +24,74 @@ $AzcopyPath = "C:\Program Files (x86)\Microsoft SDKs\Azure\AzCopy" if(!(Test-Path $AzcopyPath)) { - $path = "$ProvisionToolPath\azcopy.msi" - if(!(Test-Path $path)) - { - #Download azcopy - $url = "http://aka.ms/downloadazcopy" - Invoke-WebRequest -Uri $url -OutFile $path - } + $path = "$ProvisionToolPath\azcopy.msi" + if(!(Test-Path $path)) + { + #Download azcopy + $url = "http://aka.ms/downloadazcopy" + Invoke-WebRequest -Uri $url -OutFile $path + } - #Install azcopy - Start-Process msiexec.exe -Wait -ArgumentList "/I $path /quiet" + #Install azcopy + Start-Process msiexec.exe -Wait -ArgumentList "/I $path /quiet" } $sourceDirctory = (split-path -parent $MyInvocation.MyCommand.Definition) + "\*" $destDirctory = "$ProvisionToolPath\" Copy-item -Force -Recurse $sourceDirctory -Destination $destDirctory -$ConfigurationFile = Join-Path -Path $ProvisionToolPath -ChildPath "$Role.json"; +$ConfigurationFile = Join-Path -Path $ProvisionToolPath -ChildPath "$Role.json" -if (Test-Path -Path $ConfigurationFile) { - $Configuration = Get-Content -Path $ConfigurationFile | ConvertFrom-Json; -} else { +if (Test-Path -Path $ConfigurationFile) +{ + $Configuration = Get-Content -Path $ConfigurationFile | ConvertFrom-Json +} +else +{ [hashtable]$Actions = @{ - Name = $env:COMPUTERNAME - InstallADDS = @{ + Name = $env:COMPUTERNAME + InstallADDS = @{ Status = 'NotStart' StartTime = '' EndTime = '' } - SetAutoLogOn = @{ + SetAutoLogOn = @{ Status = 'NotStart' StartTime = '' EndTime = '' } - TurnOnFirewallPort= @{ + TurnOnFirewallPort = @{ Status = 'NotStart' StartTime = '' EndTime = '' } - InstallRolesAndFeatures= @{ + InstallRolesAndFeatures = @{ Status = 'NotStart' StartTime = '' EndTime = '' } - WaitForPS= @{ + WaitForPS = @{ Status = 'NotStart' StartTime = '' EndTime = '' } - DelegateControl= @{ + DelegateControl = @{ Status = 'NotStart' StartTime = '' EndTime = '' } - ExendADSchema= @{ + ExendADSchema = @{ Status = 'NotStart' StartTime = '' EndTime = '' } - CleanUp= @{ + CleanUp = @{ Status = 'NotStart' StartTime = '' EndTime = '' } - }; - $Configuration = New-Object -TypeName psobject -Property $Actions; + } + $Configuration = New-Object -TypeName psobject -Property $Actions } $Configuration | Add-Member -MemberType ScriptMethod -Name SetRebootConfig -Value { @@ -101,24 +104,24 @@ $Configuration | Add-Member -MemberType ScriptMethod -Name SetRebootConfig -Valu $Command | Out-File -FilePath $BatchFilePath -Encoding ascii -Append $RunOnceRegKey = 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce' - $KeyValueName = 'Workflow Reboot'; + $KeyValueName = 'Workflow Reboot' $KeyType = [Microsoft.Win32.RegistryValueKind]::String $null = [Microsoft.Win32.Registry]::SetValue($RunOnceRegKey,$KeyValueName,$BatchFile,$KeyType) $this | ConvertTo-Json | Out-File -FilePath $ConfigurationFile -Force $configfile = $ConfigurationFile - $uploadurl = $tempurl + "/$Role.json" - AZCopy -source $configfile -dest $uploadurl -upload $true + $uploadurl = $tempurl + "/$Role.json" + AZCopy -source $configfile -dest $uploadurl -upload $true return 0 } catch { return 1 - }; + } } $Mainscript = $ProvisionToolPath + "\main.ps1" -. $Mainscript; +. $Mainscript if ($Configuration.InstallADDS.Status -eq 'NotStart') { $Configuration.InstallADDS.Status = 'Running' @@ -153,7 +156,7 @@ if ($Configuration.InstallADDS.Status -eq 'Completed') { $Result = $Configuration.SetRebootConfig() if ($Result -eq 0) { shutdown -r -t 10 - exit 0 + exit 0 } } else @@ -188,7 +191,7 @@ if ($Configuration.InstallADDS.Status -eq 'Completed') { $Configuration.InstallRolesAndFeatures.Status = 'Completed' $Configuration.InstallRolesAndFeatures.EndTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" } - else + else { $Configuration.InstallRolesAndFeatures.Status = 'Error' $Configuration.InstallRolesAndFeatures.EndTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" @@ -217,7 +220,7 @@ if ($Configuration.InstallADDS.Status -eq 'Completed') { $Configuration.DelegateControl.Status = 'Running' $Configuration.DelegateControl.StartTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" UploadConfigFile - [string[]]$AddPermissionRoleList = "PS1","DP_MP" + [string[]]$AddPermissionRoleList = "PS1","DP_MP" $Result = Delegate-Control $DomainFullName $AddPermissionRoleList if ($Result[-1] -eq 0) { $Configuration.DelegateControl.Status = 'Completed' @@ -231,7 +234,7 @@ if ($Configuration.InstallADDS.Status -eq 'Completed') { UploadConfigFile } - if ($Configuration.ExendADSchema.Status -eq 'NotStart') { + if ($Configuration.ExendADSchema.Status -eq 'NotStart') { $Configuration.ExendADSchema.Status = 'Running' $Configuration.ExendADSchema.StartTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" UploadConfigFile @@ -248,7 +251,7 @@ if ($Configuration.InstallADDS.Status -eq 'Completed') { UploadConfigFile } - if ($Configuration.CleanUp.Status -eq 'NotStart') { + if ($Configuration.CleanUp.Status -eq 'NotStart') { $Configuration.CleanUp.Status = 'Running' $Configuration.CleanUp.StartTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" UploadConfigFile @@ -257,7 +260,7 @@ if ($Configuration.InstallADDS.Status -eq 'Completed') { $Configuration.CleanUp.Status = 'Completed' $Configuration.CleanUp.EndTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" } - UploadConfigFile + UploadConfigFile } } diff --git a/sccm-technicalpreview/scripts/WorkFlow-DPMP.ps1 b/sccm-technicalpreview/scripts/WorkFlow-DPMP.ps1 index 710261d27d14..18e90a6f694f 100644 --- a/sccm-technicalpreview/scripts/WorkFlow-DPMP.ps1 +++ b/sccm-technicalpreview/scripts/WorkFlow-DPMP.ps1 @@ -25,71 +25,74 @@ $AzcopyPath = "C:\Program Files (x86)\Microsoft SDKs\Azure\AzCopy" if(!(Test-Path $AzcopyPath)) { - $path = "$ProvisionToolPath\azcopy.msi" - if(!(Test-Path $path)) - { - #Download azcopy - $url = "http://aka.ms/downloadazcopy" - Invoke-WebRequest -Uri $url -OutFile $path - } - - #Install azcopy - Start-Process msiexec.exe -Wait -ArgumentList "/I $path /quiet" + $path = "$ProvisionToolPath\azcopy.msi" + if(!(Test-Path $path)) + { + #Download azcopy + $url = "http://aka.ms/downloadazcopy" + Invoke-WebRequest -Uri $url -OutFile $path + } + + #Install azcopy + Start-Process msiexec.exe -Wait -ArgumentList "/I $path /quiet" } $sourceDirctory = (split-path -parent $MyInvocation.MyCommand.Definition) + "\*" $destDirctory = "$ProvisionToolPath\" Copy-item -Force -Recurse $sourceDirctory -Destination $destDirctory -$ConfigurationFile = Join-Path -Path $ProvisionToolPath -ChildPath "$Role.json"; +$ConfigurationFile = Join-Path -Path $ProvisionToolPath -ChildPath "$Role.json" -if (Test-Path -Path $ConfigurationFile) { - $Configuration = Get-Content -Path $ConfigurationFile | ConvertFrom-Json; -} else { +if (Test-Path -Path $ConfigurationFile) +{ + $Configuration = Get-Content -Path $ConfigurationFile | ConvertFrom-Json +} +else +{ [hashtable]$Actions = @{ - Name = $env:COMPUTERNAME - WaitForDC = @{ + Name = $env:COMPUTERNAME + WaitForDC = @{ Status = 'NotStart' StartTime = '' EndTime = '' } - JoinDomain = @{ + JoinDomain = @{ Status = 'NotStart' StartTime = '' EndTime = '' } - SetAutoLogOn = @{ + SetAutoLogOn = @{ Status = 'NotStart' StartTime = '' EndTime = '' } - TurnOnFirewallPort= @{ + TurnOnFirewallPort = @{ Status = 'NotStart' StartTime = '' EndTime = '' } - InstallRolesAndFeatures= @{ + InstallRolesAndFeatures = @{ Status = 'NotStart' StartTime = '' EndTime = '' } - WaitForPS= @{ + WaitForPS = @{ Status = 'NotStart' StartTime = '' EndTime = '' } - AddPermission= @{ + AddPermission = @{ Status = 'NotStart' StartTime = '' EndTime = '' } - CleanUp= @{ + CleanUp = @{ Status = 'NotStart' StartTime = '' EndTime = '' } - }; - $Configuration = New-Object -TypeName psobject -Property $Actions; + } + $Configuration = New-Object -TypeName psobject -Property $Actions } $Configuration | Add-Member -MemberType ScriptMethod -Name SetRebootConfig -Value { @@ -102,24 +105,24 @@ $Configuration | Add-Member -MemberType ScriptMethod -Name SetRebootConfig -Valu $Command | Out-File -FilePath $BatchFilePath -Encoding ascii -Append $RunOnceRegKey = 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce' - $KeyValueName = 'Workflow Reboot'; - $KeyType = [Microsoft.Win32.RegistryValueKind]::String; + $KeyValueName = 'Workflow Reboot' + $KeyType = [Microsoft.Win32.RegistryValueKind]::String $null = [Microsoft.Win32.Registry]::SetValue($RunOnceRegKey,$KeyValueName,$BatchFile,$KeyType) $this | ConvertTo-Json | Out-File -FilePath $ConfigurationFile -Force $configfile = $ConfigurationFile - $uploadurl = $tempurl + "/$Role.json" - AZCopy -source $configfile -dest $uploadurl -upload $true + $uploadurl = $tempurl + "/$Role.json" + AZCopy -source $configfile -dest $uploadurl -upload $true return 0 } catch { return 1 - }; + } } $Mainscript = $ProvisionToolPath + "\main.ps1" -. $Mainscript; +. $Mainscript if ($Configuration.WaitForDC.Status -eq 'NotStart') { $Configuration.WaitForDC.Status = 'Running' @@ -172,7 +175,7 @@ if($Configuration.WaitForDC.Status -eq 'Completed') $Result = $Configuration.SetRebootConfig() if ($Result -eq 0) { shutdown -r -t 10 - exit 0 + exit 0 } } else @@ -186,17 +189,17 @@ if($Configuration.WaitForDC.Status -eq 'Completed') Enable-RDP - if ($Configuration.TurnOnFirewallPort.Status -eq 'NotStart') { - $Configuration.TurnOnFirewallPort.Status = 'Running' - $Configuration.TurnOnFirewallPort.StartTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" - UploadConfigFile - $Result = TurnOn-FirewallPort $rolelist - if ($Result[-1] -eq 0) { - $Configuration.TurnOnFirewallPort.Status = 'Completed' - $Configuration.TurnOnFirewallPort.EndTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" - } - UploadConfigFile - } + if ($Configuration.TurnOnFirewallPort.Status -eq 'NotStart') { + $Configuration.TurnOnFirewallPort.Status = 'Running' + $Configuration.TurnOnFirewallPort.StartTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" + UploadConfigFile + $Result = TurnOn-FirewallPort $rolelist + if ($Result[-1] -eq 0) { + $Configuration.TurnOnFirewallPort.Status = 'Completed' + $Configuration.TurnOnFirewallPort.EndTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" + } + UploadConfigFile + } if ($Configuration.InstallRolesAndFeatures.Status -eq 'NotStart') { $Configuration.InstallRolesAndFeatures.Status = 'Running' @@ -219,10 +222,10 @@ if($Configuration.WaitForDC.Status -eq 'Completed') $Configuration.WaitForPS.Status = 'Completed' $Configuration.WaitForPS.EndTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" } - UploadConfigFile + UploadConfigFile } - if ($Configuration.AddPermission.Status -eq 'NotStart') { + if ($Configuration.AddPermission.Status -eq 'NotStart') { $Configuration.AddPermission.Status = 'Running' $Configuration.AddPermission.StartTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" UploadConfigFile @@ -231,20 +234,20 @@ if($Configuration.WaitForDC.Status -eq 'Completed') $Configuration.AddPermission.Status = 'Completed' $Configuration.AddPermission.EndTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" } - UploadConfigFile - } - - if ($Configuration.CleanUp.Status -eq 'NotStart') { - $Configuration.CleanUp.Status = 'Running' - $Configuration.CleanUp.StartTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" - UploadConfigFile - $Result = Clean-Up - if ($Result[-1] -eq 0) { - $Configuration.CleanUp.Status = 'Completed' - $Configuration.CleanUp.EndTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" - } - UploadConfigFile - } + UploadConfigFile + } + + if ($Configuration.CleanUp.Status -eq 'NotStart') { + $Configuration.CleanUp.Status = 'Running' + $Configuration.CleanUp.StartTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" + UploadConfigFile + $Result = Clean-Up + if ($Result[-1] -eq 0) { + $Configuration.CleanUp.Status = 'Completed' + $Configuration.CleanUp.EndTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" + } + UploadConfigFile + } } } diff --git a/sccm-technicalpreview/scripts/WorkFlow-Other.ps1 b/sccm-technicalpreview/scripts/WorkFlow-Other.ps1 index de23f2bcc295..5d70b237ad3d 100644 --- a/sccm-technicalpreview/scripts/WorkFlow-Other.ps1 +++ b/sccm-technicalpreview/scripts/WorkFlow-Other.ps1 @@ -24,71 +24,74 @@ $AzcopyPath = "C:\Program Files (x86)\Microsoft SDKs\Azure\AzCopy" if(!(Test-Path $AzcopyPath)) { - $path = "$ProvisionToolPath\azcopy.msi" - if(!(Test-Path $path)) - { - #Download azcopy - $url = "http://aka.ms/downloadazcopy" - Invoke-WebRequest -Uri $url -OutFile $path - } - - #Install azcopy - Start-Process msiexec.exe -Wait -ArgumentList "/I $path /quiet" + $path = "$ProvisionToolPath\azcopy.msi" + if(!(Test-Path $path)) + { + #Download azcopy + $url = "http://aka.ms/downloadazcopy" + Invoke-WebRequest -Uri $url -OutFile $path + } + + #Install azcopy + Start-Process msiexec.exe -Wait -ArgumentList "/I $path /quiet" } $sourceDirctory = (split-path -parent $MyInvocation.MyCommand.Definition) + "\*" $destDirctory = "$ProvisionToolPath\" Copy-item -Force -Recurse $sourceDirctory -Destination $destDirctory -$ConfigurationFile = Join-Path -Path $ProvisionToolPath -ChildPath "$Role.json"; +$ConfigurationFile = Join-Path -Path $ProvisionToolPath -ChildPath "$Role.json" -if (Test-Path -Path $ConfigurationFile) { - $Configuration = Get-Content -Path $ConfigurationFile | ConvertFrom-Json; -} else { +if (Test-Path -Path $ConfigurationFile) +{ + $Configuration = Get-Content -Path $ConfigurationFile | ConvertFrom-Json +} +else +{ [hashtable]$Actions = @{ - Name = $env:COMPUTERNAME - WaitForDC = @{ + Name = $env:COMPUTERNAME + WaitForDC = @{ Status = 'NotStart' StartTime = '' EndTime = '' } - JoinDomain = @{ + JoinDomain = @{ Status = 'NotStart' StartTime = '' EndTime = '' } - SetAutoLogOn = @{ + SetAutoLogOn = @{ Status = 'NotStart' StartTime = '' EndTime = '' } - TurnOnFirewallPort= @{ + TurnOnFirewallPort = @{ Status = 'NotStart' StartTime = '' EndTime = '' } - InstallRolesAndFeatures= @{ + InstallRolesAndFeatures = @{ Status = 'NotStart' StartTime = '' EndTime = '' } - WaitForPS= @{ + WaitForPS = @{ Status = 'NotStart' StartTime = '' EndTime = '' } - AddPermission= @{ + AddPermission = @{ Status = 'NotStart' StartTime = '' EndTime = '' } - CleanUp= @{ + CleanUp = @{ Status = 'NotStart' StartTime = '' EndTime = '' } - }; - $Configuration = New-Object -TypeName psobject -Property $Actions; + } + $Configuration = New-Object -TypeName psobject -Property $Actions } $Configuration | Add-Member -MemberType ScriptMethod -Name SetRebootConfig -Value { @@ -101,24 +104,24 @@ $Configuration | Add-Member -MemberType ScriptMethod -Name SetRebootConfig -Valu $Command | Out-File -FilePath $BatchFilePath -Encoding ascii -Append $RunOnceRegKey = 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce' - $KeyValueName = 'Workflow Reboot'; - $KeyType = [Microsoft.Win32.RegistryValueKind]::String; + $KeyValueName = 'Workflow Reboot' + $KeyType = [Microsoft.Win32.RegistryValueKind]::String $null = [Microsoft.Win32.Registry]::SetValue($RunOnceRegKey,$KeyValueName,$BatchFile,$KeyType) $this | ConvertTo-Json | Out-File -FilePath $ConfigurationFile -Force $configfile = $ConfigurationFile - $uploadurl = $tempurl + "/$Role.json" - AZCopy -source $configfile -dest $uploadurl -upload $true + $uploadurl = $tempurl + "/$Role.json" + AZCopy -source $configfile -dest $uploadurl -upload $true return 0 } catch { return 1 - }; + } } $Mainscript = $ProvisionToolPath + "\main.ps1" -. $Mainscript; +. $Mainscript if ($Configuration.WaitForDC.Status -eq 'NotStart') { $Configuration.WaitForDC.Status = 'Running' @@ -171,7 +174,7 @@ if($Configuration.WaitForDC.Status -eq 'Completed') $Result = $Configuration.SetRebootConfig() if ($Result -eq 0) { shutdown -r -t 10 - exit 0 + exit 0 } } else @@ -185,17 +188,17 @@ if($Configuration.WaitForDC.Status -eq 'Completed') Enable-RDP - if ($Configuration.TurnOnFirewallPort.Status -eq 'NotStart') { - $Configuration.TurnOnFirewallPort.Status = 'Running' - $Configuration.TurnOnFirewallPort.StartTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" - UploadConfigFile - $Result = TurnOn-FirewallPort - if ($Result[-1] -eq 0) { - $Configuration.TurnOnFirewallPort.Status = 'Completed' - $Configuration.TurnOnFirewallPort.EndTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" - } - UploadConfigFile - } + if ($Configuration.TurnOnFirewallPort.Status -eq 'NotStart') { + $Configuration.TurnOnFirewallPort.Status = 'Running' + $Configuration.TurnOnFirewallPort.StartTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" + UploadConfigFile + $Result = TurnOn-FirewallPort + if ($Result[-1] -eq 0) { + $Configuration.TurnOnFirewallPort.Status = 'Completed' + $Configuration.TurnOnFirewallPort.EndTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" + } + UploadConfigFile + } if ($Configuration.InstallRolesAndFeatures.Status -eq 'NotStart') { $Configuration.InstallRolesAndFeatures.Status = 'Running' @@ -209,7 +212,7 @@ if($Configuration.WaitForDC.Status -eq 'Completed') UploadConfigFile } - if ($Configuration.WaitForPS.Status -eq 'NotStart') { + if ($Configuration.WaitForPS.Status -eq 'NotStart') { $Configuration.WaitForPS.Status = 'Running' $Configuration.WaitForPS.StartTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" UploadConfigFile @@ -218,10 +221,10 @@ if($Configuration.WaitForDC.Status -eq 'Completed') $Configuration.WaitForPS.Status = 'Completed' $Configuration.WaitForPS.EndTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" } - UploadConfigFile + UploadConfigFile } - if ($Configuration.AddPermission.Status -eq 'NotStart') { + if ($Configuration.AddPermission.Status -eq 'NotStart') { $Configuration.AddPermission.Status = 'Running' $Configuration.AddPermission.StartTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" UploadConfigFile @@ -230,20 +233,20 @@ if($Configuration.WaitForDC.Status -eq 'Completed') $Configuration.AddPermission.Status = 'Completed' $Configuration.AddPermission.EndTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" } - UploadConfigFile - } - - if ($Configuration.CleanUp.Status -eq 'NotStart') { - $Configuration.CleanUp.Status = 'Running' - $Configuration.CleanUp.StartTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" - UploadConfigFile - $Result = Clean-Up - if ($Result[-1] -eq 0) { - $Configuration.CleanUp.Status = 'Completed' - $Configuration.CleanUp.EndTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" - } - UploadConfigFile - } + UploadConfigFile + } + + if ($Configuration.CleanUp.Status -eq 'NotStart') { + $Configuration.CleanUp.Status = 'Running' + $Configuration.CleanUp.StartTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" + UploadConfigFile + $Result = Clean-Up + if ($Result[-1] -eq 0) { + $Configuration.CleanUp.Status = 'Completed' + $Configuration.CleanUp.EndTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" + } + UploadConfigFile + } } } diff --git a/sccm-technicalpreview/scripts/WorkFlow-PS1.ps1 b/sccm-technicalpreview/scripts/WorkFlow-PS1.ps1 index cdd2a5316152..4743d718f2b2 100644 --- a/sccm-technicalpreview/scripts/WorkFlow-PS1.ps1 +++ b/sccm-technicalpreview/scripts/WorkFlow-PS1.ps1 @@ -25,33 +25,36 @@ $AzcopyPath = "C:\Program Files (x86)\Microsoft SDKs\Azure\AzCopy" if(!(Test-Path $AzcopyPath)) { - $path = "$ProvisionToolPath\azcopy.msi" - if(!(Test-Path $path)) - { - #Download azcopy - $url = "http://aka.ms/downloadazcopy" - Invoke-WebRequest -Uri $url -OutFile $path - } - - #Install azcopy - Start-Process msiexec.exe -Wait -ArgumentList "/I $path /quiet" + $path = "$ProvisionToolPath\azcopy.msi" + if(!(Test-Path $path)) + { + #Download azcopy + $url = "http://aka.ms/downloadazcopy" + Invoke-WebRequest -Uri $url -OutFile $path + } + + #Install azcopy + Start-Process msiexec.exe -Wait -ArgumentList "/I $path /quiet" } $sourceDirctory = (split-path -parent $MyInvocation.MyCommand.Definition) + "\*" $destDirctory = "$ProvisionToolPath\" Copy-item -Force -Recurse $sourceDirctory -Destination $destDirctory -$ConfigurationFile = Join-Path -Path $ProvisionToolPath -ChildPath "$Role.json"; +$ConfigurationFile = Join-Path -Path $ProvisionToolPath -ChildPath "$Role.json" -if (Test-Path -Path $ConfigurationFile) { - $Configuration = Get-Content -Path $ConfigurationFile | ConvertFrom-Json; -} else { +if (Test-Path -Path $ConfigurationFile) +{ + $Configuration = Get-Content -Path $ConfigurationFile | ConvertFrom-Json +} +else +{ [hashtable]$Actions = @{ - Name = $env:COMPUTERNAME - SQLInstanceName = "" - SQLDataFilePath = "" - SQLLogFilePath = "" - AddBuiltinPermission = @{ + Name = $env:COMPUTERNAME + SQLInstanceName = "" + SQLDataFilePath = "" + SQLLogFilePath = "" + AddBuiltinPermission = @{ Status = 'NotStart' StartTime = '' EndTime = '' @@ -61,80 +64,80 @@ if (Test-Path -Path $ConfigurationFile) { StartTime = '' EndTime = '' } - JoinDomain = @{ + JoinDomain = @{ Status = 'NotStart' StartTime = '' EndTime = '' } - SetAutoLogOn = @{ + SetAutoLogOn = @{ Status = 'NotStart' StartTime = '' EndTime = '' } - TurnOnFirewallPort= @{ + TurnOnFirewallPort = @{ Status = 'NotStart' StartTime = '' EndTime = '' } - InstallRolesAndFeatures= @{ + InstallRolesAndFeatures = @{ Status = 'NotStart' StartTime = '' EndTime = '' } - InstallADK= @{ + InstallADK = @{ Status = 'NotStart' StartTime = '' EndTime = '' } - ChangeSQLServicesAccount= @{ + ChangeSQLServicesAccount = @{ Status = 'NotStart' StartTime = '' EndTime = '' } - InstallSCCM= @{ + InstallSCCM = @{ Status = 'NotStart' StartTime = '' EndTime = '' } - UpgradeSCCM= @{ + UpgradeSCCM = @{ Status = 'NotStart' StartTime = '' EndTime = '' } - WaitForSiteServer= @{ + WaitForSiteServer = @{ Status = 'NotStart' StartTime = '' EndTime = '' } - InstallDP= @{ + InstallDP = @{ Status = 'NotStart' StartTime = '' EndTime = '' } - InstallMP= @{ + InstallMP = @{ Status = 'NotStart' StartTime = '' EndTime = '' } - CleanUp= @{ + CleanUp = @{ Status = 'NotStart' StartTime = '' EndTime = '' } - }; - $Configuration = New-Object -TypeName psobject -Property $Actions; + } + $Configuration = New-Object -TypeName psobject -Property $Actions } $Configuration | Add-Member -MemberType ScriptMethod -Name SetRebootConfig -Value { try - { + { $Invocation = (Get-Variable MyInvocation -Scope 1).Value $Path = $Invocation.MyCommand.Path - $BatchFilePath = Join-Path -Path $ProvisionToolPath -ChildPath "Resume_$($env:COMPUTERNAME).ps1" - $Command = "" - if($this.AddBuiltinPermission.Status -eq "Running") - { - $command = @' + $BatchFilePath = Join-Path -Path $ProvisionToolPath -ChildPath "Resume_$($env:COMPUTERNAME).ps1" + $Command = "" + if($this.AddBuiltinPermission.Status -eq "Running") + { + $command = @' Start-Sleep -Second 240 sqlcmd -Q "if not exists(select * from sys.server_principals where name='BUILTIN\administrators') CREATE LOGIN [BUILTIN\administrators] FROM WINDOWS;EXEC master..sp_addsrvrolemember @loginame = N'BUILTIN\administrators', @rolename = N'sysadmin'" $retrycount = 0 @@ -154,50 +157,50 @@ while($sqlpermission -eq $null) } } '@ - } - $Command | Out-File -FilePath $BatchFilePath -Encoding ascii - $Command = ". $Path $DCIPAddress $DomainFullName $DomainAdminName $Password $tempurl `"$sakey`"" - $Command | Out-File -FilePath $BatchFilePath -Encoding ascii -Append + } + $Command | Out-File -FilePath $BatchFilePath -Encoding ascii + $Command = ". $Path $DCIPAddress $DomainFullName $DomainAdminName $Password $tempurl `"$sakey`"" + $Command | Out-File -FilePath $BatchFilePath -Encoding ascii -Append $BatchFile = "cmd /k powershell -ExecutionPolicy Unrestricted -file " + $BatchFilePath $RunOnceRegKey = 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce' - $KeyValueName = 'Workflow Reboot'; - $KeyType = [Microsoft.Win32.RegistryValueKind]::String; + $KeyValueName = 'Workflow Reboot' + $KeyType = [Microsoft.Win32.RegistryValueKind]::String $null = [Microsoft.Win32.Registry]::SetValue($RunOnceRegKey,$KeyValueName,$BatchFile,$KeyType) $this | ConvertTo-Json | Out-File -FilePath $ConfigurationFile -Force $configfile = $ConfigurationFile - $uploadurl = $tempurl + "/$Role.json" - AZCopy -source $configfile -dest $uploadurl -upload $true + $uploadurl = $tempurl + "/$Role.json" + AZCopy -source $configfile -dest $uploadurl -upload $true return 0 } catch - { + { return 1 } } $Mainscript = $ProvisionToolPath + "\main.ps1" -. $Mainscript; +. $Mainscript if ($Configuration.AddBuiltinPermission.Status -eq 'NotStart') { $Configuration.AddBuiltinPermission.Status = 'Running' $Configuration.AddBuiltinPermission.StartTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" - Get-SQLInformation + Get-SQLInformation $Result = $Configuration.SetRebootConfig() if ($Result -eq 0) { - $Result = Set-AutoLogOn "" $DomainAdminName $Password + $Result = Set-AutoLogOn "" $DomainAdminName $Password shutdown -r -t 10 - exit 0 + exit 0 } } if ($Configuration.AddBuiltinPermission.Status -eq 'Running') { $Configuration.AddBuiltinPermission.Status = 'Completed' $Configuration.AddBuiltinPermission.EndTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" - UploadConfigFile + UploadConfigFile } if ($Configuration.WaitForDC.Status -eq 'NotStart') { @@ -251,7 +254,7 @@ if($Configuration.WaitForDC.Status -eq 'Completed') $Result = $Configuration.SetRebootConfig() if ($Result -eq 0) { shutdown -r -t 0 - exit 0 + exit 0 } } else @@ -265,17 +268,17 @@ if($Configuration.WaitForDC.Status -eq 'Completed') Enable-RDP - if ($Configuration.TurnOnFirewallPort.Status -eq 'NotStart') { - $Configuration.TurnOnFirewallPort.Status = 'Running' - $Configuration.TurnOnFirewallPort.StartTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" - UploadConfigFile - $Result = TurnOn-FirewallPort $RoleList - if ($Result[-1] -eq 0) { - $Configuration.TurnOnFirewallPort.Status = 'Completed' - $Configuration.TurnOnFirewallPort.EndTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" - } - UploadConfigFile - } + if ($Configuration.TurnOnFirewallPort.Status -eq 'NotStart') { + $Configuration.TurnOnFirewallPort.Status = 'Running' + $Configuration.TurnOnFirewallPort.StartTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" + UploadConfigFile + $Result = TurnOn-FirewallPort $RoleList + if ($Result[-1] -eq 0) { + $Configuration.TurnOnFirewallPort.Status = 'Completed' + $Configuration.TurnOnFirewallPort.EndTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" + } + UploadConfigFile + } if ($Configuration.InstallRolesAndFeatures.Status -eq 'NotStart') { $Configuration.InstallRolesAndFeatures.Status = 'Running' @@ -285,12 +288,12 @@ if($Configuration.WaitForDC.Status -eq 'Completed') if ($Result[-1] -eq 0) { $Configuration.InstallRolesAndFeatures.Status = 'Completed' $Configuration.InstallRolesAndFeatures.EndTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" - $Result = $Configuration.SetRebootConfig() - $Result = Set-AutoLogOn $DomainFullName $DomainAdminName $Password - if ($Result -eq 0) { - shutdown -r -t 10 - exit 0 - } + $Result = $Configuration.SetRebootConfig() + $Result = Set-AutoLogOn $DomainFullName $DomainAdminName $Password + if ($Result -eq 0) { + shutdown -r -t 10 + exit 0 + } } } @@ -305,10 +308,10 @@ if($Configuration.WaitForDC.Status -eq 'Completed') $Configuration.InstallADK.Status = 'Completed' $Configuration.InstallADK.EndTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" } - UploadConfigFile + UploadConfigFile } - - if ($Configuration.ChangeSQLServicesAccount.Status -eq 'NotStart') { + + if ($Configuration.ChangeSQLServicesAccount.Status -eq 'NotStart') { $Configuration.ChangeSQLServicesAccount.Status = 'Running' $Configuration.ChangeSQLServicesAccount.StartTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" UploadConfigFile @@ -317,11 +320,11 @@ if($Configuration.WaitForDC.Status -eq 'Completed') $Configuration.ChangeSQLServicesAccount.Status = 'Completed' $Configuration.ChangeSQLServicesAccount.EndTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" } - UploadConfigFile + UploadConfigFile } ##Install CM - if ($Configuration.InstallSCCM.Status -eq 'NotStart') { + if ($Configuration.InstallSCCM.Status -eq 'NotStart') { $Configuration.InstallSCCM.Status = 'Running' $Configuration.InstallSCCM.StartTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" UploadConfigFile @@ -330,69 +333,89 @@ if($Configuration.WaitForDC.Status -eq 'Completed') $Configuration.InstallSCCM.Status = 'Completed' $Configuration.InstallSCCM.EndTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" - $Result = $Configuration.SetRebootConfig() - $Result = Set-AutoLogOn $DomainFullName $DomainAdminName $Password + $Result = $Configuration.SetRebootConfig() + $Result = Set-AutoLogOn $DomainFullName $DomainAdminName $Password if ($Result -eq 0) { shutdown -r -t 120 } } - UploadConfigFile - exit 0 + else + { + $Configuration.InstallSCCM.Status = 'Error' + $Configuration.InstallSCCM.EndTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" + } + UploadConfigFile + exit 0 } - if($Configuration.InstallSCCM.Status -eq 'Completed') - { - if ($Configuration.UpgradeSCCM.Status -eq 'NotStart') - { - $Configuration.UpgradeSCCM.Status = 'Running' - $Configuration.UpgradeSCCM.StartTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" - UploadConfigFile - $Result = Upgrade-SCCM $DomainFullName - if ($Result[-1] -eq 0) { - $Configuration.UpgradeSCCM.Status = 'Completed' - $Configuration.UpgradeSCCM.EndTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" - } - UploadConfigFile - } - - if ($Configuration.WaitForSiteServer.Status -eq 'NotStart') { - $Configuration.WaitForSiteServer.Status = 'Running' - $Configuration.WaitForSiteServer.StartTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" - UploadConfigFile - $Result = WaitFor-SiteServer "DP_MP" - if ($Result[-1] -eq 0) { - $Configuration.WaitForSiteServer.Status = 'Completed' - $Configuration.WaitForSiteServer.EndTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" - } - UploadConfigFile - } - - if ($Configuration.InstallDP.Status -eq 'NotStart') { - $Configuration.InstallDP.Status = 'Running' - $Configuration.InstallDP.StartTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" - UploadConfigFile - $Result = Install-DP $DomainFullName - if ($Result[-1] -eq 0) { - $Configuration.InstallDP.Status = 'Completed' - $Configuration.InstallDP.EndTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" - } - UploadConfigFile - } - - if ($Configuration.InstallMP.Status -eq 'NotStart') { - $Configuration.InstallMP.Status = 'Running' - $Configuration.InstallMP.StartTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" - UploadConfigFile - $Result = Install-MP $DomainFullName $Role $DomainAdminName $Password - if ($Result[-1] -eq 0) { - $Configuration.InstallMP.Status = 'Completed' - $Configuration.InstallMP.EndTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" - } - UploadConfigFile - } - } - - if ($Configuration.CleanUp.Status -eq 'NotStart') { + if($Configuration.InstallSCCM.Status -eq 'Completed') + { + if ($Configuration.UpgradeSCCM.Status -eq 'NotStart') + { + $Configuration.UpgradeSCCM.Status = 'Running' + $Configuration.UpgradeSCCM.StartTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" + UploadConfigFile + $Result = Upgrade-SCCM $DomainFullName + if ($Result[-1] -eq 0) { + $Configuration.UpgradeSCCM.Status = 'Completed' + $Configuration.UpgradeSCCM.EndTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" + } + else + { + $Configuration.UpgradeSCCM.Status = 'Error' + $Configuration.UpgradeSCCM.EndTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" + } + UploadConfigFile + } + + if ($Configuration.WaitForSiteServer.Status -eq 'NotStart') { + $Configuration.WaitForSiteServer.Status = 'Running' + $Configuration.WaitForSiteServer.StartTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" + UploadConfigFile + $Result = WaitFor-SiteServer "DP_MP" + if ($Result[-1] -eq 0) { + $Configuration.WaitForSiteServer.Status = 'Completed' + $Configuration.WaitForSiteServer.EndTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" + } + UploadConfigFile + } + + if ($Configuration.InstallDP.Status -eq 'NotStart') { + $Configuration.InstallDP.Status = 'Running' + $Configuration.InstallDP.StartTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" + UploadConfigFile + $Result = Install-DP $DomainFullName + if ($Result[-1] -eq 0) { + $Configuration.InstallDP.Status = 'Completed' + $Configuration.InstallDP.EndTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" + } + else + { + $Configuration.InstallDP.Status = 'Error' + $Configuration.InstallDP.EndTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" + } + UploadConfigFile + } + + if ($Configuration.InstallMP.Status -eq 'NotStart') { + $Configuration.InstallMP.Status = 'Running' + $Configuration.InstallMP.StartTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" + UploadConfigFile + $Result = Install-MP $DomainFullName $Role $DomainAdminName $Password + if ($Result[-1] -eq 0) { + $Configuration.InstallMP.Status = 'Completed' + $Configuration.InstallMP.EndTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" + } + else + { + $Configuration.InstallMP.Status = 'Error' + $Configuration.InstallMP.EndTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" + } + UploadConfigFile + } + } + + if ($Configuration.CleanUp.Status -eq 'NotStart') { $Configuration.CleanUp.Status = 'Running' $Configuration.CleanUp.StartTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" UploadConfigFile @@ -401,7 +424,7 @@ if($Configuration.WaitForDC.Status -eq 'Completed') $Configuration.CleanUp.Status = 'Completed' $Configuration.CleanUp.EndTime = Get-Date -format "yyyy-MM-dd HH:mm:ss" } - UploadConfigFile + UploadConfigFile } } } diff --git a/sccm-technicalpreview/scripts/main.ps1 b/sccm-technicalpreview/scripts/main.ps1 index 93ccda1e9e2d..ebdf33a8e458 100644 --- a/sccm-technicalpreview/scripts/main.ps1 +++ b/sccm-technicalpreview/scripts/main.ps1 @@ -16,28 +16,28 @@ function Install-ADDS($DomainFullName,$Password) function Add-BuiltinPermission { - $logpath = $ProvisionToolPath+"\AddBuiltinPermission.txt" - try - { - Start-Sleep -Seconds 240 - "[$(Get-Date -format HH:mm:ss)] Adding Built Permission ..." | Out-File -Append $logpath - sqlcmd -Q "if not exists(select * from sys.server_principals where name='BUILTIN\administrators') CREATE LOGIN [BUILTIN\administrators] FROM WINDOWS;EXEC master..sp_addsrvrolemember @loginame = N'BUILTIN\administrators', @rolename = N'sysadmin'" | Out-Null - - $returncode = sqlcmd -Q "if not exists(select * from sys.server_principals where name='BUILTIN\administrators') PRINT 1" - while($returncode -eq 1 -or $returncode -eq $null) - { - "[$(Get-Date -format HH:mm:ss)] Failed , will try again ..." | Out-File -Append $logpath - Start-Sleep -Seconds 60 - sqlcmd -Q "if not exists(select * from sys.server_principals where name='BUILTIN\administrators') CREATE LOGIN [BUILTIN\administrators] FROM WINDOWS;EXEC master..sp_addsrvrolemember @loginame = N'BUILTIN\administrators', @rolename = N'sysadmin'" | Out-Null - $returncode = sqlcmd -Q "if not exists(select * from sys.server_principals where name='BUILTIN\administrators') PRINT 1" - } - } - catch - { - $_.Exception | Out-File -Append $logpath - Return 1 - } - Return 0 + $logpath = $ProvisionToolPath+"\AddBuiltinPermission.txt" + try + { + Start-Sleep -Seconds 240 + "[$(Get-Date -format HH:mm:ss)] Adding Built Permission ..." | Out-File -Append $logpath + sqlcmd -Q "if not exists(select * from sys.server_principals where name='BUILTIN\administrators') CREATE LOGIN [BUILTIN\administrators] FROM WINDOWS;EXEC master..sp_addsrvrolemember @loginame = N'BUILTIN\administrators', @rolename = N'sysadmin'" | Out-Null + + $returncode = sqlcmd -Q "if not exists(select * from sys.server_principals where name='BUILTIN\administrators') PRINT 1" + while($returncode -eq 1 -or $returncode -eq $null) + { + "[$(Get-Date -format HH:mm:ss)] Failed , will try again ..." | Out-File -Append $logpath + Start-Sleep -Seconds 60 + sqlcmd -Q "if not exists(select * from sys.server_principals where name='BUILTIN\administrators') CREATE LOGIN [BUILTIN\administrators] FROM WINDOWS;EXEC master..sp_addsrvrolemember @loginame = N'BUILTIN\administrators', @rolename = N'sysadmin'" | Out-Null + $returncode = sqlcmd -Q "if not exists(select * from sys.server_principals where name='BUILTIN\administrators') PRINT 1" + } + } + catch + { + $_.Exception | Out-File -Append $logpath + Return 1 + } + Return 0 } function Set-AutoLogOn($DomainFullName,$Username,$Password) @@ -127,7 +127,7 @@ function WaitFor-DC $waitfordclog = $ProvisionToolPath +"\WaitForDCLog.txt" $dcconfigpath = $ProvisionToolPath + "\DC.json" $source = $tempurl + "/DC.json" - AZCopy $source $dcconfigpath $false + AZCopy $source $dcconfigpath $false while(!(Test-Path $dcconfigpath)) { "[$(Get-Date -format HH:mm:ss)] Waiting for DC config file..." | Out-File -Append $waitfordclog @@ -152,7 +152,7 @@ function WaitFor-PS $waitforpslog = $ProvisionToolPath +"\WaitForPSLog.txt" $psconfigpath = $ProvisionToolPath + "\PS1.json" $source = $tempurl + "/PS1.json" - AZCopy $source $psconfigpath $false + AZCopy $source $psconfigpath $false while(!(Test-Path $psconfigpath)) { "[$(Get-Date -format HH:mm:ss)] Waiting for PS config file..." | Out-File -Append $waitforpslog @@ -177,7 +177,7 @@ function WaitFor-SiteServer($SiteServerRole) $waitforsiteserverlog = $ProvisionToolPath +"\WaitForSiteServerLog.txt" $siteserverconfigpath = $ProvisionToolPath + "\$SiteServerRole.json" $source = $tempurl + "/$SiteServerRole.json" - AZCopy $source $siteserverconfigpath $false + AZCopy $source $siteserverconfigpath $false while(!(Test-Path $siteserverconfigpath)) { "[$(Get-Date -format HH:mm:ss)] Waiting for Site Server config file..." | Out-File -Append $waitforsiteserverlog @@ -202,7 +202,7 @@ function WaitFor-SQL $waitforsqllog = $ProvisionToolPath +"\waitforsqllog.txt" $sqlconfigpath = $ProvisionToolPath + "\SQL.json" $source = $tempurl + "/SQL.json" - AZCopy $source $sqlconfigpath $false + AZCopy $source $sqlconfigpath $false while(!(Test-Path $sqlconfigpath)) { "[$(Get-Date -format HH:mm:ss)] Waiting for SQL config file..." | Out-File -Append $waitforsqllog @@ -227,9 +227,9 @@ function UploadConfigFile { $Configuration | ConvertTo-Json | Out-File -FilePath $ConfigurationFile -Force; $configfile = $ConfigurationFile - $uploadurl = $tempurl + "/$Role.json" + $uploadurl = $tempurl + "/$Role.json" - AZCopy $configfile $uploadurl $true + AZCopy $configfile $uploadurl $true } function Enable-RDP @@ -265,48 +265,48 @@ function TurnOn-FirewallPort([string[]]$Role) function Delegate-Control($DomainFullName,[string[]]$RoleList) { - $logpath = $ProvisionToolPath+"\DelegateControlLog.txt" - $RoleList | %{ - "[$(Get-Date -format HH:mm:ss)] Add permission for $_ ..." | Out-File -Append $logpath - $psconfigpath = $ProvisionToolPath + "\$_.json" - $source = $tempurl + "/$_.json" - AZCopy $source $psconfigpath $false - $psconfig = gc $psconfigpath | ConvertFrom-Json - - $currentmachine = $psconfig.Name - - try - { - $root = ConfigContainer - $DomainName = $DomainFullName.split('.')[0] - #Delegate Control - $cmd = "dsacls.exe" - $arg1 = "CN=System Management,CN=System,$root" - $arg2 = "/G" - $arg3 = ""+$DomainName+"\"+$currentmachine+"`$:GA;;" - $arg4 = "/I:T" - - & $cmd $arg1 $arg2 $arg3 $arg4 - "[$(Get-Date -format HH:mm:ss)] Finished." | Out-File -Append $logpath - } - catch - { - return 1 - } - } + $logpath = $ProvisionToolPath+"\DelegateControlLog.txt" + $RoleList | %{ + "[$(Get-Date -format HH:mm:ss)] Add permission for $_ ..." | Out-File -Append $logpath + $psconfigpath = $ProvisionToolPath + "\$_.json" + $source = $tempurl + "/$_.json" + AZCopy $source $psconfigpath $false + $psconfig = gc $psconfigpath | ConvertFrom-Json + + $currentmachine = $psconfig.Name + + try + { + $root = ConfigContainer + $DomainName = $DomainFullName.split('.')[0] + #Delegate Control + $cmd = "dsacls.exe" + $arg1 = "CN=System Management,CN=System,$root" + $arg2 = "/G" + $arg3 = ""+$DomainName+"\"+$currentmachine+"`$:GA;;" + $arg4 = "/I:T" + + & $cmd $arg1 $arg2 $arg3 $arg4 + "[$(Get-Date -format HH:mm:ss)] Finished." | Out-File -Append $logpath + } + catch + { + return 1 + } + } - Return 0 + Return 0 } function Extend-ADSchema { - $url = "https://cmsetoolstorage.blob.core.windows.net/work/tools/extadsch.exe" + $url = "https://cmsetoolstorage.blob.core.windows.net/work/tools/extadsch.exe" $path = "C:\extadsch.exe" Invoke-WebRequest -Uri $url -OutFile $path & 'C:\extadsch.exe' | out-null - return 0 + return 0 } function Install-ADK @@ -343,15 +343,15 @@ function Install-SCCM($DomainFullName,$Username,$Password,$SQLRole,$CM) { $path = "$ProvisionToolPath\InstallSCCM.ps1" - #GetSQLInfo - $configpath = $ProvisionToolPath + "\$SQLRole.json" + #GetSQLInfo + $configpath = $ProvisionToolPath + "\$SQLRole.json" $source = $tempurl + "/$SQLRole.json" - AZCopy $source $configpath $false + AZCopy $source $configpath $false $config = gc $configpath | ConvertFrom-Json - $SQLVMName = $config.Name - $SQLInstanceName = $config.SQLInstanceName - $SQLDataFilePath = $config.SQLDataFilePath - $SQLLogFilePath = $config.SQLLogFilePath + $SQLVMName = $config.Name + $SQLInstanceName = $config.SQLInstanceName + $SQLDataFilePath = $config.SQLDataFilePath + $SQLLogFilePath = $config.SQLLogFilePath try { @@ -381,97 +381,97 @@ function Upgrade-SCCM($DomainFullName) function Update-SQLServicesAccount($DomainFullName,$Username,$Password) { - if($DomainFullName) - { - $NetBIOSName = $DomainFullName.split('.')[0] - $Username = $NetBIOSName + '\' + $Username - } - $DomainPassword = $Password - $DomainUserName = $Username - - $SQLInstanceName = $Configuration.SQLInstanceName - $logpath = $ProvisionToolPath + "\UpdateSQLServicesAccount.log" - #Get SQL Server Services account - $query = "Name = '"+ $SQLInstanceName.ToUpper() +"'" - $services = Get-WmiObject win32_service -Filter $query - if($services -ne $null) - { - "[$(Get-Date -format HH:mm:ss)] Verify if SQL Server services account need to be changed" | Out-File -Append $logpath - if($services.StartName -ne $DomainUserName) - { - "[$(Get-Date -format HH:mm:ss)] SQL Server services account need to be changed" | Out-File -Append $logpath - #change services account - if($services.State -eq 'Running') - { - #Check if SQLSERVERAGENT is running - $sqlserveragentflag = 0 - $sqlserveragentservices = Get-WmiObject win32_service -Filter "Name = 'SQLSERVERAGENT'" - if($sqlserveragentservices -ne $null) - { - if($sqlserveragentservices.State -eq 'Running') - { - "[$(Get-Date -format HH:mm:ss)] SQLSERVERAGENT need to be stopped first" | Out-File -Append $logpath - $Result = $sqlserveragentservices.StopService() - "[$(Get-Date -format HH:mm:ss)] Stopping SQLSERVERAGENT.." | Out-File -Append $logpath - if ($Result.ReturnValue -eq '0') - { - $sqlserveragentflag = 1 - "[$(Get-Date -format HH:mm:ss)] Stopped" | Out-File -Append $logpath - } - } - } - $Result = $services.StopService() - "[$(Get-Date -format HH:mm:ss)] Stopping SQL Server services.." | Out-File -Append $logpath - if ($Result.ReturnValue -eq '0') - { - "[$(Get-Date -format HH:mm:ss)] Stopped" | Out-File -Append $logpath - } - - "[$(Get-Date -format HH:mm:ss)] Changing the services account..." | Out-File -Append $logpath - - $Result = $services.change($null,$null,$null,$null,$null,$null,$DomainUserName,$Password,$null,$null,$null) - if ($Result.ReturnValue -eq '0') - { - "[$(Get-Date -format HH:mm:ss)] Successfully Change the services account" | Out-File -Append $logpath - if($sqlserveragentflag -eq 1) - { - "[$(Get-Date -format HH:mm:ss)] Starting SQLSERVERAGENT.." | Out-File -Append $logpath - $Result = $sqlserveragentservices.StartService() - if($Result.ReturnValue -eq '0') - { - "[$(Get-Date -format HH:mm:ss)] Started" | Out-File -Append $logpath - } - } - $Result = $services.StartService() - "[$(Get-Date -format HH:mm:ss)] Starting SQL Server services.." | Out-File -Append $logpath - while($Result.ReturnValue -ne '0') - { - $returncode = $Result.ReturnValue - "[$(Get-Date -format HH:mm:ss)] Return $returncode , will try again" | Out-File -Append $logpath - Start-Sleep -Seconds 10 - $Result = $services.StartService() - } - "[$(Get-Date -format HH:mm:ss)] Started" | Out-File -Append $logpath - } - } - } - else - { - "[$(Get-Date -format HH:mm:ss)] No need to be changed" | Out-File -Append $logpath - } - } - Return 0 + if($DomainFullName) + { + $NetBIOSName = $DomainFullName.split('.')[0] + $Username = $NetBIOSName + '\' + $Username + } + $DomainPassword = $Password + $DomainUserName = $Username + + $SQLInstanceName = $Configuration.SQLInstanceName + $logpath = $ProvisionToolPath + "\UpdateSQLServicesAccount.log" + #Get SQL Server Services account + $query = "Name = '"+ $SQLInstanceName.ToUpper() +"'" + $services = Get-WmiObject win32_service -Filter $query + if($services -ne $null) + { + "[$(Get-Date -format HH:mm:ss)] Verify if SQL Server services account need to be changed" | Out-File -Append $logpath + if($services.StartName -ne $DomainUserName) + { + "[$(Get-Date -format HH:mm:ss)] SQL Server services account need to be changed" | Out-File -Append $logpath + #change services account + if($services.State -eq 'Running') + { + #Check if SQLSERVERAGENT is running + $sqlserveragentflag = 0 + $sqlserveragentservices = Get-WmiObject win32_service -Filter "Name = 'SQLSERVERAGENT'" + if($sqlserveragentservices -ne $null) + { + if($sqlserveragentservices.State -eq 'Running') + { + "[$(Get-Date -format HH:mm:ss)] SQLSERVERAGENT need to be stopped first" | Out-File -Append $logpath + $Result = $sqlserveragentservices.StopService() + "[$(Get-Date -format HH:mm:ss)] Stopping SQLSERVERAGENT.." | Out-File -Append $logpath + if ($Result.ReturnValue -eq '0') + { + $sqlserveragentflag = 1 + "[$(Get-Date -format HH:mm:ss)] Stopped" | Out-File -Append $logpath + } + } + } + $Result = $services.StopService() + "[$(Get-Date -format HH:mm:ss)] Stopping SQL Server services.." | Out-File -Append $logpath + if ($Result.ReturnValue -eq '0') + { + "[$(Get-Date -format HH:mm:ss)] Stopped" | Out-File -Append $logpath + } + + "[$(Get-Date -format HH:mm:ss)] Changing the services account..." | Out-File -Append $logpath + + $Result = $services.change($null,$null,$null,$null,$null,$null,$DomainUserName,$Password,$null,$null,$null) + if ($Result.ReturnValue -eq '0') + { + "[$(Get-Date -format HH:mm:ss)] Successfully Change the services account" | Out-File -Append $logpath + if($sqlserveragentflag -eq 1) + { + "[$(Get-Date -format HH:mm:ss)] Starting SQLSERVERAGENT.." | Out-File -Append $logpath + $Result = $sqlserveragentservices.StartService() + if($Result.ReturnValue -eq '0') + { + "[$(Get-Date -format HH:mm:ss)] Started" | Out-File -Append $logpath + } + } + $Result = $services.StartService() + "[$(Get-Date -format HH:mm:ss)] Starting SQL Server services.." | Out-File -Append $logpath + while($Result.ReturnValue -ne '0') + { + $returncode = $Result.ReturnValue + "[$(Get-Date -format HH:mm:ss)] Return $returncode , will try again" | Out-File -Append $logpath + Start-Sleep -Seconds 10 + $Result = $services.StartService() + } + "[$(Get-Date -format HH:mm:ss)] Started" | Out-File -Append $logpath + } + } + } + else + { + "[$(Get-Date -format HH:mm:ss)] No need to be changed" | Out-File -Append $logpath + } + } + Return 0 } function Install-DP($DomainFullName) { $path = "$ProvisionToolPath\InstallDP.ps1" - $configpath = $ProvisionToolPath + "\DP_MP.json" + $configpath = $ProvisionToolPath + "\DP_MP.json" $source = $tempurl + "/DP_MP.json" - AZCopy $source $configpath $false + AZCopy $source $configpath $false $config = gc $configpath | ConvertFrom-Json - $currentmachine = $config.Name + $currentmachine = $config.Name try { @@ -486,8 +486,8 @@ function Install-DP($DomainFullName) function Clean-Up { - $BatchFilePath = Join-Path -Path $ProvisionToolPath -ChildPath "Resume_$($env:COMPUTERNAME).ps1" - Remove-Item $BatchFilePath + $BatchFilePath = Join-Path -Path $ProvisionToolPath -ChildPath "Resume_$($env:COMPUTERNAME).ps1" + Remove-Item $BatchFilePath return 0 } @@ -495,21 +495,21 @@ function Clean-Up function Install-MP($DomainFullName,$SQLRole,$DomainAdminName,$Password) { $path = "$ProvisionToolPath\InstallMP.ps1" - $configpath = $ProvisionToolPath + "\DP_MP.json" + $configpath = $ProvisionToolPath + "\DP_MP.json" $source = $tempurl + "/DP_MP.json" - AZCopy $source $configpath $false + AZCopy $source $configpath $false $config = gc $configpath | ConvertFrom-Json - $currentmachine = $config.Name + $currentmachine = $config.Name - #GetSQLInfo - $configpath = $ProvisionToolPath + "\$SQLRole.json" + #GetSQLInfo + $configpath = $ProvisionToolPath + "\$SQLRole.json" $source = $tempurl + "/$SQLRole.json" - AZCopy $source $configpath $false + AZCopy $source $configpath $false $config = gc $configpath | ConvertFrom-Json - $SQLVMName = $config.Name - $SQLInstanceName = $config.SQLInstanceName - $SQLDataFilePath = $config.SQLDataFilePath - $SQLLogFilePath = $config.SQLLogFilePath + $SQLVMName = $config.Name + $SQLInstanceName = $config.SQLInstanceName + $SQLDataFilePath = $config.SQLDataFilePath + $SQLLogFilePath = $config.SQLLogFilePath try { @@ -546,17 +546,17 @@ function ConfigContainer function Add-Permission($DomainFullName) { - $logpath = $ProvisionToolPath+"\AddPermissionLog.txt" - $DomainName = $DomainFullName.split('.')[0] - $psconfigpath = $ProvisionToolPath + "\PS1.json" + $logpath = $ProvisionToolPath+"\AddPermissionLog.txt" + $DomainName = $DomainFullName.split('.')[0] + $psconfigpath = $ProvisionToolPath + "\PS1.json" $source = $tempurl + "/PS1.json" - AZCopy $source $psconfigpath $false + AZCopy $source $psconfigpath $false $psconfig = gc $psconfigpath | ConvertFrom-Json - $currentmachine = $psconfig.Name - $psname = $currentmachine +"$" + $currentmachine = $psconfig.Name + $psname = $currentmachine +"$" - $GroupObj = [ADSI]"WinNT://$env:COMPUTERNAME/Administrators" + $GroupObj = [ADSI]"WinNT://$env:COMPUTERNAME/Administrators" if($GroupObj.IsMember("WinNT://$DomainName/$psname") -eq $false) { "[$(Get-Date -format HH:mm:ss)] add $psname to administrators group" | Out-File -Append $logpath @@ -567,17 +567,17 @@ function Add-Permission($DomainFullName) "[$(Get-Date -format HH:mm:ss)] $psname is already in administrators group" | Out-File -Append $logpath } - return 0 + return 0 } function Get-SQLInformation { - $inst = (get-itemproperty 'HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server').InstalledInstances[0] - $p = (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\SQL').$inst + $inst = (get-itemproperty 'HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server').InstalledInstances[0] + $p = (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\SQL').$inst - $sqlinfo = Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\$p\$inst" + $sqlinfo = Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\$p\$inst" - $Configuration.SQLInstanceName = $inst - $Configuration.SQLDataFilePath = $sqlinfo.DefaultData - $Configuration.SQLLogFilePath = $sqlinfo.DefaultLog + $Configuration.SQLInstanceName = $inst + $Configuration.SQLDataFilePath = $sqlinfo.DefaultData + $Configuration.SQLLogFilePath = $sqlinfo.DefaultLog } \ No newline at end of file From fcc442ad19bb71c148894e7d65aca5c9dedd81eb Mon Sep 17 00:00:00 2001 From: Marlon Singleton Date: Thu, 7 Feb 2019 20:34:01 +0300 Subject: [PATCH 22/66] Changed "Send_message." to "Send_message" Fixed issue #5781 --- 201-alert-to-queue-with-logic-app/azuredeploy.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/201-alert-to-queue-with-logic-app/azuredeploy.json b/201-alert-to-queue-with-logic-app/azuredeploy.json index c8e0851c37cb..51d5e8ac1903 100644 --- a/201-alert-to-queue-with-logic-app/azuredeploy.json +++ b/201-alert-to-queue-with-logic-app/azuredeploy.json @@ -81,7 +81,7 @@ } }, "actions": { - "Send_message.": { + "Send_message": { "type": "ApiConnection", "inputs": { "body": { From 2f1a56d571de25df6e13a15ca82e5d3cde098bfa Mon Sep 17 00:00:00 2001 From: Suraj MB Date: Fri, 8 Feb 2019 19:31:59 +0530 Subject: [PATCH 23/66] Updated with SAS URL generation instructions Due to users facing issues with Blob or Storage account level SAS URL, added instructions to generate container level SAS URL. --- application-gateway-logviewer-goaccess/README.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/application-gateway-logviewer-goaccess/README.md b/application-gateway-logviewer-goaccess/README.md index 54d93bed038a..4c89e9c3c92e 100644 --- a/application-gateway-logviewer-goaccess/README.md +++ b/application-gateway-logviewer-goaccess/README.md @@ -19,7 +19,11 @@ By default, GoAccess installed by this template will parse and display traffic s
  1. Only the ApplicationGatewayAccessLog will be used by GoAccess
  2. You want to make sure you are sending and storing your ApplicationGatewayAccessLog to a storage account (select the “Archive to a storage account” check box if using the Portal to enable Application Gateway logging).
  3. -
  4. In your storage account settings, ensure you have Shared Access Signature key configured. The expiry date time needs to be set to a date much further out in the future (eg: 1 year out from now). Also, only the Read and List permissions are needed for GoAccess. Make sure to generate the connection string as well. The Blob service SAS URL connection string is what you need to input to the ARM template.
  5. +
  6. In your storage account container, ensure you have Shared Access Signature key configured. The expiry date time needs to be set to a date much further out in the future (eg: 1 year out from now). Also, only the Read and List permissions are needed for GoAccess. Make sure to generate the connection string as well. The Blob Container Service SAS URL connection string is what you need to input to the ARM template. +

    You can generate Service-level SAS URL for the Blob Container "insights-logs-applicationgatewayaccesslog" using Azure Storage Explorer for your operating system. Storage Explorer is available for Windows, MacOS and Linux.

    + For example, the blob container SAS URL looks like this - https://appgwlogstrgacc.blob.core.windows.net/insights-logs-applicationgatewayaccesslog?st=2019-02-08T12%3A55%3A14Z&se=2020-02-09T12%3A55%3A00Z&sp=rl&sv=2018-03-28&sr=c&sig=jcfAjefo3TitH7kl9YC15COaSdfgMmPFnO8QTI6oY9c%3D

    + Alternatively, you can generate the Service-level SAS using REST API. Read more about it here. +

@@ -33,7 +37,7 @@ The template will require a set of parameters input from you as the user:
  • adminUsername: Username you want to use for the VM the template creates
  • adminPassword: Password you want to use to log in to the VM
  • dnsNameForPublicIP: The DNS name (prefix) you want to use for the VM to map against its public IP
  • -
  • appGwAccessLogsBlobSasUri: The SAS URL connection string (see 2(c) in the Pre-requisites list above) for the storage account blog where your Application Gateway Access Logs are stored
  • +
  • appGwAccessLogsBlobSasUri: The SAS URL connection string (see 2(iii) in the Pre-requisites list above) for the storage account blog where your Application Gateway Access Logs are stored
  • FilterRegexForAppGwAccessLogs: A regex to use to filter the Application Gateway Access Logs to a specific subset. For example, if you have multiple application gateways publishing logs to the same storage account blob, and you only want GoAccess to surface traffic stats for say one of the Application Gateways, you can provide a regex for this field to filter to just that instance.
  • Region: The Azure region where you would like the VM to be created
  • @@ -55,6 +59,8 @@ Please note following aspects related to this template: By default, the GoAccess dashboard and associated data are unsecured. Since the web server is Apache HTTP Webserver, you can secure access by following the Apache Auth documentation. +Also, since it is a Virtual Machine, you can use Network Security Groups to allow/deny IP addresses to restrict access, but make sure that outbound internet connectivity is allowed to reach the storage account. +

    Getting Help

    For any issues with running this template, please file an issue in GitHub under Azure/azure-quickstart-templates repository: https://github.com/Azure/azure-quickstart-templates/issues From 7fb8defb1421356f6dec3dff1dc1f714f344f8a3 Mon Sep 17 00:00:00 2001 From: Jonathan Gao Date: Fri, 8 Feb 2019 13:17:25 -0500 Subject: [PATCH 24/66] rename the key vault name parameter --- 101-key-vault-create/azuredeploy.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/101-key-vault-create/azuredeploy.json b/101-key-vault-create/azuredeploy.json index 0f3618e67630..7a24079522d5 100644 --- a/101-key-vault-create/azuredeploy.json +++ b/101-key-vault-create/azuredeploy.json @@ -2,7 +2,7 @@ "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { - "name": { + "keyVaultName": { "type": "string", "metadata": { "description": "Name of the key vault." @@ -45,7 +45,7 @@ "resources": [ { "type": "Microsoft.KeyVault/vaults", - "name": "[parameters('name')]", + "name": "[parameters('keyVaultName')]", "apiVersion": "2016-10-01", "location": "[parameters('location')]", "properties": { @@ -114,12 +114,12 @@ }, { "type": "Microsoft.KeyVault/vaults/secrets", - "name": "[concat(parameters('name'), '/', parameters('secretName'))]", + "name": "[concat(parameters('keyVaultName'), '/', parameters('secretName'))]", "apiVersion": "2016-10-01", "location": "[parameters('location')]", "scale": null, "dependsOn": [ - "[resourceId('Microsoft.KeyVault/vaults', parameters('name'))]" + "[resourceId('Microsoft.KeyVault/vaults', parameters('keyVaultName'))]" ], "properties": { "contentType": "securestring", From 7caeb495b4e63a272e0d4972707071136864cc63 Mon Sep 17 00:00:00 2001 From: StartAutomating Date: Fri, 8 Feb 2019 22:49:44 -0800 Subject: [PATCH 25/66] Incorporating Pull Request Feedback --- test/template-tests/Test-AzureRMTemplate.ps1 | 17 ++++++++++----- ...zureRMTemplate => Test-AzureRMTemplate.sh} | 0 ...-Must-Exist-In-CreateUIDefinition.test.ps1 | 12 +++-------- .../Textboxes-Are-Well-Formed.test.ps1 | 7 ++++--- .../Location-Should-Not-Be-Hardcoded.test.ps1 | 21 +++++++------------ ...dentityExtension-must-not-be-used.test.ps1 | 10 ++++----- .../Parameters-Property-Must-Exist.test.ps1 | 5 +---- .../Resources-Should-Have-Location.test.ps1 | 2 +- ...ng-Parameters-Cannot-Have-Default.test.ps1 | 6 ++++-- ...al-Machines-Should-Not-Be-Preview.test.ps1 | 6 +++++- 10 files changed, 43 insertions(+), 43 deletions(-) rename test/template-tests/{Test-AzureRMTemplate => Test-AzureRMTemplate.sh} (100%) diff --git a/test/template-tests/Test-AzureRMTemplate.ps1 b/test/template-tests/Test-AzureRMTemplate.ps1 index 6cd344caed32..f78ac9651b93 100644 --- a/test/template-tests/Test-AzureRMTemplate.ps1 +++ b/test/template-tests/Test-AzureRMTemplate.ps1 @@ -246,6 +246,7 @@ Each test script has access to a set of well-known variables: if (-not $matchingGroups) { continue } if ($fileInfo.Schema -like '*deploymentTemplate*') { + $isMainTemplate = 'mainTemplate.json', 'azureDeploy.json' -contains $fileInfo.Name $templateFileName = $fileInfo.Name $TemplateObject = $fileInfo.Object $TemplateText = $fileInfo.Text @@ -287,8 +288,9 @@ Each test script has access to a set of well-known variables: process { # If no template was passed, if ($PSCmdlet.ParameterSetName -eq 'NearbyTemplate') { - # attempt to find one in the current directory and it's subdirectories. + # attempt to find one in the current directory and it's subdirectories $possibleJsonFiles = @(Get-ChildItem -Filter *.json -Recurse | + Sort-Object Name -Descending | # (sort by name descending so that MainTemplate.json comes first). Where-Object { 'azureDeploy.json', 'mainTemplate.json' -contains $_.Name }) @@ -369,7 +371,7 @@ Each test script has access to a set of well-known variables: #*$TemplateFileName (the name of the azure template file) $templateFileName = $TemplatePath | Split-Path -Leaf #*$IsMainTemplate (if the TemplateFileName is named mainTemplate.json) - $isMainTemplate = $templateFileName -eq 'mainTemplate.json' + $isMainTemplate = 'mainTemplate.json', 'azureDeploy.json' -contains $templateFileName $templateFile = Get-Item -LiteralPath $resolvedTemplatePath $templateFolder = $templateFile.Directory #*$FolderName (the name of the root folder containing the template) @@ -386,10 +388,11 @@ Each test script has access to a set of well-known variables: #*$CreateUIDefinitionObject (the createuidefinition text, converted from json) $createUIDefinitionObject = $createUIDefintionText | ConvertFrom-Json #*$HasCreateUIDefinition (indicates if a CreateUIDefinition.json file exists) - $HasCreateUIDefinition = $false + $HasCreateUIDefinition = $true } else { $HasCreateUIDefinition = $false } + #*$FolderFiles (a list of objects of each file in the directory) $FolderFiles = @@ -416,10 +419,14 @@ Each test script has access to a set of well-known variables: $fileObject }) - + if ($isMainTemplate) { + $MainTemplatePath = "$TemplateFullPath" + $MainTemplateText = [IO.File]::ReadAllText($MainTemplatePath) + $MainTemplateObject = $MainTemplateText | ConvertFrom-Json + } # If we've found a CreateUIDefinition, we'll want to process it first. - if ($createUIDefintionText) { + if ($HasCreateUIDefinition) { # Loop over the folder files and get every file that isn't createUIDefinition $otherFolderFiles = @(foreach ($_ in $FolderFiles) { if ($_.Name -ne 'CreateUIDefinition.json') { diff --git a/test/template-tests/Test-AzureRMTemplate b/test/template-tests/Test-AzureRMTemplate.sh similarity index 100% rename from test/template-tests/Test-AzureRMTemplate rename to test/template-tests/Test-AzureRMTemplate.sh diff --git a/test/template-tests/testcases/CreateUIDefinition/Parameters-Without-Default-Must-Exist-In-CreateUIDefinition.test.ps1 b/test/template-tests/testcases/CreateUIDefinition/Parameters-Without-Default-Must-Exist-In-CreateUIDefinition.test.ps1 index f5b7ba8ea4e2..a6af1672565c 100644 --- a/test/template-tests/testcases/CreateUIDefinition/Parameters-Without-Default-Must-Exist-In-CreateUIDefinition.test.ps1 +++ b/test/template-tests/testcases/CreateUIDefinition/Parameters-Without-Default-Must-Exist-In-CreateUIDefinition.test.ps1 @@ -3,6 +3,7 @@ [PSObject] $TemplateObject, +[Parameter(Mandatory=$true)] [PSObject] $CreateUIDefinitionObject ) @@ -12,17 +13,10 @@ foreach ($parameter in $TemplateObject.parameters.psobject.properties) { $parameterInfo = $parameter.Value $defaultValue = $parameterInfo.defaultValue if ($parameter.type -eq 'SecureString') { continue } # Skipping SecureStrings, as they are not allowed a default value - if (-not $defaultValue) { - if (-not $CreateUIDefinitionObject) { - Write-Error "$parameterName does not have a default value, and no CreateUIDefinition exists" - continue - } + if (-not $defaultValue) { if (-not $CreateUIDefinitionObject.outputs.$parameterName) { Write-Error "$parameterName does not have a default value, and is not defined in CreateUIDefinition.outuputs" -ErrorId Parameter.Without.Default.Missing.From.CreateUIDefinition -TargetObject $TemplateObject.parameters continue } } -} - - - +} \ No newline at end of file diff --git a/test/template-tests/testcases/CreateUIDefinition/Textboxes-Are-Well-Formed.test.ps1 b/test/template-tests/testcases/CreateUIDefinition/Textboxes-Are-Well-Formed.test.ps1 index 3482aa4bd5e7..8702f10cf369 100644 --- a/test/template-tests/testcases/CreateUIDefinition/Textboxes-Are-Well-Formed.test.ps1 +++ b/test/template-tests/testcases/CreateUIDefinition/Textboxes-Are-Well-Formed.test.ps1 @@ -4,7 +4,8 @@ $CreateUIDefinitionObject ) -$findTextBoxes = { + +function findTextBoxes { param([Parameter(ValueFromPipelineByPropertyName=$true,Position=0)][PSObject]$value) process { if (-not $value) { return } @@ -20,13 +21,13 @@ $findTextBoxes = { & $findTextBoxes -value { $_ } } else { $value.psobject.properties | - & $findTextBoxes + findTextBoxes } } } -$allTextBoxes = & $findTextBoxes $CreateUIDefinitionObject +$allTextBoxes = findTextBoxes $CreateUIDefinitionObject foreach ($textbox in $allTextBoxes) { if (-not $textbox.constraints) { Write-Error "Textbox $($textbox.Name) is missing constraints" diff --git a/test/template-tests/testcases/deploymentTemplate/Location-Should-Not-Be-Hardcoded.test.ps1 b/test/template-tests/testcases/deploymentTemplate/Location-Should-Not-Be-Hardcoded.test.ps1 index 2ebd5c03e114..21080b6bfc15 100644 --- a/test/template-tests/testcases/deploymentTemplate/Location-Should-Not-Be-Hardcoded.test.ps1 +++ b/test/template-tests/testcases/deploymentTemplate/Location-Should-Not-Be-Hardcoded.test.ps1 @@ -3,7 +3,10 @@ [string]$TemplateText, [Parameter(Mandatory=$true,Position=1)] -[string]$TemplateObject +[string]$TemplateObject, + +[Parameter(Mandatory=$true,Position=1)] +[switch]$IsMainTemplate ) $TemplateObjectCopy = $templateText | ConvertFrom-Json $TemplateObjectCopy.psobject.properties.remove('parameters') @@ -13,20 +16,12 @@ $TemplateWithoutParameters = $TemplateObjectCopy | $locationParameter = $templateObject.parameters.location -if ($locationParameter -and $locationParameter.defaultvalue -ne '[resourceGroup().location]' -and $TemplateFileName -eq 'mainTemplate.json') { +if ($locationParameter -and + $locationParameter.defaultvalue -ne '[resourceGroup().location]' -and + $IsMainTemplate) { Write-Error "Location parameter must not be hardcoded. The default value should be [resourceGroup().location]." -ErrorId Location.Parameter.Hardcoded -TargetObject $parameter } if ($TemplateWithoutParameters -like '*resourceGroup().location*') { Write-Error "$TemplateFileName must use the location parameter, not resourceGroup().location (except when used as a default value)" -ErrorId Location.Parameter.Should.Be.Used -TargetObject $parameter -} - - - - - - - - - - +} \ No newline at end of file diff --git a/test/template-tests/testcases/deploymentTemplate/ManagedIdentityExtension-must-not-be-used.test.ps1 b/test/template-tests/testcases/deploymentTemplate/ManagedIdentityExtension-must-not-be-used.test.ps1 index b8432063fcc9..9fde8d5ed682 100644 --- a/test/template-tests/testcases/deploymentTemplate/ManagedIdentityExtension-must-not-be-used.test.ps1 +++ b/test/template-tests/testcases/deploymentTemplate/ManagedIdentityExtension-must-not-be-used.test.ps1 @@ -1,11 +1,11 @@ param( [Parameter(Mandatory=$true,Position=0)] [string] -$TemplateText +$TemplateObject ) -if ($templateText -match 'managedidentityextension') { - Write-Error "Managed Identity Extension must not be used" -ErrorId ManagedIdentityExtension.Was.Used -} - +$resourcesJson = $TemplateObject.resources | ConvertTo-Json -Depth 10 +if ($resourcesJson -match 'ManagedIdentityExtension') { + Write-Error "Managed Identity Extension must not be used" -ErrorId ManagedIdentityExtension.Was.Used +} \ No newline at end of file diff --git a/test/template-tests/testcases/deploymentTemplate/Parameters-Property-Must-Exist.test.ps1 b/test/template-tests/testcases/deploymentTemplate/Parameters-Property-Must-Exist.test.ps1 index 77ba4899f668..889dcac308c1 100644 --- a/test/template-tests/testcases/deploymentTemplate/Parameters-Property-Must-Exist.test.ps1 +++ b/test/template-tests/testcases/deploymentTemplate/Parameters-Property-Must-Exist.test.ps1 @@ -6,7 +6,4 @@ $TemplateObject if (-not $TemplateObject.psobject.properties.item('parameters')) { throw "Parameters property must exist in the template" -} - - - +} \ No newline at end of file diff --git a/test/template-tests/testcases/deploymentTemplate/Resources-Should-Have-Location.test.ps1 b/test/template-tests/testcases/deploymentTemplate/Resources-Should-Have-Location.test.ps1 index 6660641cd090..ccc5b70ca04e 100644 --- a/test/template-tests/testcases/deploymentTemplate/Resources-Should-Have-Location.test.ps1 +++ b/test/template-tests/testcases/deploymentTemplate/Resources-Should-Have-Location.test.ps1 @@ -7,7 +7,7 @@ foreach ($resource in $templateObject.resources) { if ($resource.Location) { $location = "$($resource.location)".Trim() if ($location -notmatch '^\[.*\]$' -and $location -ne 'global') { - Write-Error "Resource $($resource.Name) Location must be an expression or 'global'" + Write-Error "Resource $($resource.Name) Location must be an expression or 'global'" -TargetObject $resource } } } diff --git a/test/template-tests/testcases/deploymentTemplate/Secure-String-Parameters-Cannot-Have-Default.test.ps1 b/test/template-tests/testcases/deploymentTemplate/Secure-String-Parameters-Cannot-Have-Default.test.ps1 index 06fd8c992837..0171ff43ec5f 100644 --- a/test/template-tests/testcases/deploymentTemplate/Secure-String-Parameters-Cannot-Have-Default.test.ps1 +++ b/test/template-tests/testcases/deploymentTemplate/Secure-String-Parameters-Cannot-Have-Default.test.ps1 @@ -3,9 +3,11 @@ [PSObject] $TemplateObject ) -foreach ($parameter in $templateObject.parameters) { +foreach ($parameterProp in $templateObject.parameters.psobject.properties) { + $parameter = $parameterProp.Value + $name = $parameterProp.Name if ($parameter.Type -eq 'securestring' -and $parameter.defaultValue) { - Write-Error -Message "Parameter $($parameter.Name) is a SecureString, and must not have a default value." ` + Write-Error -Message "Parameter $name is a SecureString, and must not have a default value." ` -ErrorId SecureString.Must.Not.Have.Default -TargetObject $parameter } } diff --git a/test/template-tests/testcases/deploymentTemplate/Virtual-Machines-Should-Not-Be-Preview.test.ps1 b/test/template-tests/testcases/deploymentTemplate/Virtual-Machines-Should-Not-Be-Preview.test.ps1 index ef49db0e4742..ad0f5563a5a6 100644 --- a/test/template-tests/testcases/deploymentTemplate/Virtual-Machines-Should-Not-Be-Preview.test.ps1 +++ b/test/template-tests/testcases/deploymentTemplate/Virtual-Machines-Should-Not-Be-Preview.test.ps1 @@ -4,7 +4,11 @@ $TemplateObject ) foreach ($resource in $templateObject.resources) { - if ('microsoft.compute/virtualmachinescalesets', 'microsoft.compute/virtualmachines' -notcontains $resource.ResourceType) { + # This is a PowerShell trick to simplify multiple -ors + # -notcontains checks that a list (on the left side) doesn't contain a value (on the right side) + # So this test will ignore resources that aren't /virtualmachines or /virtualmachineassets + if ('microsoft.compute/virtualmachinescalesets', + 'microsoft.compute/virtualmachines' -notcontains $resource.ResourceType) { continue } $imageReference = $resource.virtualmachineprofile.storageprofile.imagereference From a84f0ddc04f6cee0eb90a62558b03c0f56c8ca46 Mon Sep 17 00:00:00 2001 From: StartAutomating Date: Fri, 8 Feb 2019 22:53:38 -0800 Subject: [PATCH 26/66] Making Schema Test Case-Sensitive --- .../CreateUIDefintion-Should-Have-Schema.test.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/template-tests/testcases/CreateUIDefinition/CreateUIDefintion-Should-Have-Schema.test.ps1 b/test/template-tests/testcases/CreateUIDefinition/CreateUIDefintion-Should-Have-Schema.test.ps1 index 7823a905f7ba..39f1af371ee6 100644 --- a/test/template-tests/testcases/CreateUIDefinition/CreateUIDefintion-Should-Have-Schema.test.ps1 +++ b/test/template-tests/testcases/CreateUIDefinition/CreateUIDefintion-Should-Have-Schema.test.ps1 @@ -8,7 +8,7 @@ if (-not $CreateUIDefinitionObject.'$Schema') { throw "CreateUIDefinition is missing a `$schema property" } -if (-not $CreateUIDefinitionObject.'$schema' -ne 'https://schema.management.azure.com/schemas/0.1.2-preview/CreateUIDefinition.MultiVm.json#') { +if (-not $CreateUIDefinitionObject.'$schema' -cne 'https://schema.management.azure.com/schemas/0.1.2-preview/CreateUIDefinition.MultiVm.json#') { throw "CreateUIDefintion has an incorrect schema. Schema should be https://schema.management.azure.com/schemas/0.1.2-preview/CreateUIDefinition.MultiVm.json#, and is '$($CreateUIDefinitionObject.'$schema')'" } From 4ef05a166a2dcc880050e9d8b259b808f824a985 Mon Sep 17 00:00:00 2001 From: StartAutomating Date: Fri, 8 Feb 2019 23:04:31 -0800 Subject: [PATCH 27/66] Changing behavior when multiple templates are found --- test/template-tests/Test-AzureRMTemplate.ps1 | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/template-tests/Test-AzureRMTemplate.ps1 b/test/template-tests/Test-AzureRMTemplate.ps1 index f78ac9651b93..f80b465864b2 100644 --- a/test/template-tests/Test-AzureRMTemplate.ps1 +++ b/test/template-tests/Test-AzureRMTemplate.ps1 @@ -64,7 +64,7 @@ Each test script has access to a set of well-known variables: [Collections.IDictionary] $TestCase = [Ordered]@{}, - # A set of test groups. + # A set of test groups. Test groups will be automatically populated by the directory names in /testcases. [Parameter(ValueFromPipelineByPropertyName=$true)] [ValidateScript({ foreach ($k in $_.Keys) { @@ -298,7 +298,8 @@ Each test script has access to a set of well-known variables: # If more than one template was found, warn which one we'll be testing. if ($possibleJsonFiles.Count -gt 1) { - Write-Warning "More than one potential template file found, using $($possibleJsonFiles[0].Fullname)" + Write-Error "More than one potential template file found beneath '$pwd'. Please have only azureDeploy.json or mainTemplate.json, not both." + return } From 7384cb33d0198c2ceafc47cb80d801753b9e169c Mon Sep 17 00:00:00 2001 From: StartAutomating Date: Fri, 8 Feb 2019 23:07:08 -0800 Subject: [PATCH 28/66] Removing SecureString Type skip and clarifying PowerShell -not behavior --- ...s-Without-Default-Must-Exist-In-CreateUIDefinition.test.ps1 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/template-tests/testcases/CreateUIDefinition/Parameters-Without-Default-Must-Exist-In-CreateUIDefinition.test.ps1 b/test/template-tests/testcases/CreateUIDefinition/Parameters-Without-Default-Must-Exist-In-CreateUIDefinition.test.ps1 index a6af1672565c..3eb2ec011ba4 100644 --- a/test/template-tests/testcases/CreateUIDefinition/Parameters-Without-Default-Must-Exist-In-CreateUIDefinition.test.ps1 +++ b/test/template-tests/testcases/CreateUIDefinition/Parameters-Without-Default-Must-Exist-In-CreateUIDefinition.test.ps1 @@ -12,8 +12,7 @@ foreach ($parameter in $TemplateObject.parameters.psobject.properties) { $parameterName = $parameter.Name $parameterInfo = $parameter.Value $defaultValue = $parameterInfo.defaultValue - if ($parameter.type -eq 'SecureString') { continue } # Skipping SecureStrings, as they are not allowed a default value - if (-not $defaultValue) { + if (-not $defaultValue) { # PowerShell -not will cover both null and blank strings if (-not $CreateUIDefinitionObject.outputs.$parameterName) { Write-Error "$parameterName does not have a default value, and is not defined in CreateUIDefinition.outuputs" -ErrorId Parameter.Without.Default.Missing.From.CreateUIDefinition -TargetObject $TemplateObject.parameters continue From d08f39b843d22b06dce703c623fd35eceb4beca8 Mon Sep 17 00:00:00 2001 From: StartAutomating Date: Fri, 8 Feb 2019 23:14:07 -0800 Subject: [PATCH 29/66] Adding note to clarify blank values are allowed --- .../Secure-String-Parameters-Cannot-Have-Default.test.ps1 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/template-tests/testcases/deploymentTemplate/Secure-String-Parameters-Cannot-Have-Default.test.ps1 b/test/template-tests/testcases/deploymentTemplate/Secure-String-Parameters-Cannot-Have-Default.test.ps1 index 0171ff43ec5f..8c001de0eced 100644 --- a/test/template-tests/testcases/deploymentTemplate/Secure-String-Parameters-Cannot-Have-Default.test.ps1 +++ b/test/template-tests/testcases/deploymentTemplate/Secure-String-Parameters-Cannot-Have-Default.test.ps1 @@ -6,7 +6,9 @@ $TemplateObject foreach ($parameterProp in $templateObject.parameters.psobject.properties) { $parameter = $parameterProp.Value $name = $parameterProp.Name - if ($parameter.Type -eq 'securestring' -and $parameter.defaultValue) { + if ($parameter.Type -eq 'securestring' -and + $parameter.defaultValue) # This will only return true when defaultvalue is not null or blank. + { Write-Error -Message "Parameter $name is a SecureString, and must not have a default value." ` -ErrorId SecureString.Must.Not.Have.Default -TargetObject $parameter } From 47520d46c680752d5de250aa1d4784406825c26a Mon Sep 17 00:00:00 2001 From: Marlon Singleton Date: Sun, 10 Feb 2019 12:57:51 +0300 Subject: [PATCH 30/66] fixed parameter names --- .../azuredeploy.parameters.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/201-alert-to-queue-with-logic-app/azuredeploy.parameters.json b/201-alert-to-queue-with-logic-app/azuredeploy.parameters.json index ec47bed3eccc..043daf4be70a 100644 --- a/201-alert-to-queue-with-logic-app/azuredeploy.parameters.json +++ b/201-alert-to-queue-with-logic-app/azuredeploy.parameters.json @@ -5,14 +5,14 @@ "logicAppName": { "value":"AlertToQueue" }, - "servicebusconnectionString": { + "serviceBusConnectionString": { "value":"GEN-PASSWORD" }, - "servicebusConnectionName": { + "serviceBusConnectionName": { "value":"AlertQueue" }, - "servicebusQueueName": { + "serviceBusQueueName": { "value":"myQueue" } } -} \ No newline at end of file +} From 4fb9c417e98529ece625e8c313da3e084377776a Mon Sep 17 00:00:00 2001 From: Suraj MB Date: Mon, 11 Feb 2019 12:04:03 +0530 Subject: [PATCH 31/66] Added screenshot for Storage Explorer SAS generation Added screenshot for Storage Explorer SAS generation --- application-gateway-logviewer-goaccess/README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/application-gateway-logviewer-goaccess/README.md b/application-gateway-logviewer-goaccess/README.md index 4c89e9c3c92e..b53fd0bdbd18 100644 --- a/application-gateway-logviewer-goaccess/README.md +++ b/application-gateway-logviewer-goaccess/README.md @@ -21,8 +21,9 @@ By default, GoAccess installed by this template will parse and display traffic s
  • You want to make sure you are sending and storing your ApplicationGatewayAccessLog to a storage account (select the “Archive to a storage account” check box if using the Portal to enable Application Gateway logging).
  • In your storage account container, ensure you have Shared Access Signature key configured. The expiry date time needs to be set to a date much further out in the future (eg: 1 year out from now). Also, only the Read and List permissions are needed for GoAccess. Make sure to generate the connection string as well. The Blob Container Service SAS URL connection string is what you need to input to the ARM template.

    You can generate Service-level SAS URL for the Blob Container "insights-logs-applicationgatewayaccesslog" using Azure Storage Explorer for your operating system. Storage Explorer is available for Windows, MacOS and Linux.

    - For example, the blob container SAS URL looks like this - https://appgwlogstrgacc.blob.core.windows.net/insights-logs-applicationgatewayaccesslog?st=2019-02-08T12%3A55%3A14Z&se=2020-02-09T12%3A55%3A00Z&sp=rl&sv=2018-03-28&sr=c&sig=jcfAjefo3TitH7kl9YC15COaSdfgMmPFnO8QTI6oY9c%3D

    - Alternatively, you can generate the Service-level SAS using REST API. Read more about it here. + For example, the blob container SAS URL looks like this - https://appgwlogstrgacc.blob.core.windows.net/insights-logs-applicationgatewayaccesslog?st=2019-02-08T12%3A55%3A14Z&se=2020-02-09T12%3A55%3A00Z&sp=rl&sv=2018-03-28&sr=c&sig=jcfAjefo3TitH7kl9YC15COaSdfgMmPFnO8QTI6oY9c%3D

    + +

    Alternatively, you can generate the Service-level SAS using REST API. Read more about it here.

  • From 3f3babde593f000c4d3d8537108131148585007d Mon Sep 17 00:00:00 2001 From: Suraj MB Date: Mon, 11 Feb 2019 12:11:39 +0530 Subject: [PATCH 32/66] Updated SAS URL example Updated SAS URL example --- application-gateway-logviewer-goaccess/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application-gateway-logviewer-goaccess/README.md b/application-gateway-logviewer-goaccess/README.md index b53fd0bdbd18..a8ff88968121 100644 --- a/application-gateway-logviewer-goaccess/README.md +++ b/application-gateway-logviewer-goaccess/README.md @@ -21,7 +21,7 @@ By default, GoAccess installed by this template will parse and display traffic s
  • You want to make sure you are sending and storing your ApplicationGatewayAccessLog to a storage account (select the “Archive to a storage account” check box if using the Portal to enable Application Gateway logging).
  • In your storage account container, ensure you have Shared Access Signature key configured. The expiry date time needs to be set to a date much further out in the future (eg: 1 year out from now). Also, only the Read and List permissions are needed for GoAccess. Make sure to generate the connection string as well. The Blob Container Service SAS URL connection string is what you need to input to the ARM template.

    You can generate Service-level SAS URL for the Blob Container "insights-logs-applicationgatewayaccesslog" using Azure Storage Explorer for your operating system. Storage Explorer is available for Windows, MacOS and Linux.

    - For example, the blob container SAS URL looks like this - https://appgwlogstrgacc.blob.core.windows.net/insights-logs-applicationgatewayaccesslog?st=2019-02-08T12%3A55%3A14Z&se=2020-02-09T12%3A55%3A00Z&sp=rl&sv=2018-03-28&sr=c&sig=jcfAjefo3TitH7kl9YC15COaSdfgMmPFnO8QTI6oY9c%3D

    + For example, the blob container SAS URL should look like this -

    https://[your-blob-url]/insights-logs-applicationgatewayaccesslog?st=2019-02-08T12%3A55%3A14Z&se=2020-02-09T12%3A55%3A00Z&sp=rl&sv=2018-03-28&sr=c&sig=jcfAjefo3TitH7kl9YC15COaSdfgMmPFnO8QTI6oY9c%3D




    Alternatively, you can generate the Service-level SAS using REST API. Read more about it here.
  • From 66d6d15cd088a6db93940209891be3db7f92df26 Mon Sep 17 00:00:00 2001 From: Jonathan Gao Date: Mon, 11 Feb 2019 15:44:01 -0500 Subject: [PATCH 33/66] add parameter meta --- 101-key-vault-create/azuredeploy.json | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/101-key-vault-create/azuredeploy.json b/101-key-vault-create/azuredeploy.json index 7a24079522d5..4b15baf0c053 100644 --- a/101-key-vault-create/azuredeploy.json +++ b/101-key-vault-create/azuredeploy.json @@ -30,10 +30,16 @@ }, "secretName": { "type": "string", - "defaultValue": "vmAdminPassword" + "defaultValue": "vmAdminPassword", + "metadata": { + "description": "Name of the secret that you want to create." + } }, "secretValue": { - "type": "securestring" + "type": "securestring", + "metadata": { + "description": "Value of the secret that you want to create." + } } }, "variables": { From c71a067636acc846e5c77653cec8b7f4863e3feb Mon Sep 17 00:00:00 2001 From: victorar Date: Tue, 12 Feb 2019 16:29:28 +0100 Subject: [PATCH 34/66] Adding HostHeader Adding HostHeader property --- 201-front-door-rate-limiting/azuredeploy.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/201-front-door-rate-limiting/azuredeploy.json b/201-front-door-rate-limiting/azuredeploy.json index 4e8940921dbb..e6e0a7447aba 100644 --- a/201-front-door-rate-limiting/azuredeploy.json +++ b/201-front-door-rate-limiting/azuredeploy.json @@ -90,7 +90,8 @@ } ], "acceptedProtocols": [ - "Http" + "Http", + "Https" ], "patternsToMatch": [ "/*" @@ -129,6 +130,7 @@ "backends": [ { "address": "[parameters('backendAddress')]", + "backendHostHeader": "[parameters('backendAddress')]", "httpPort": 80, "httpsPort": 443, "weight": 50, From 8257af5baf547f2cd003342248ddb0dd0f29b68c Mon Sep 17 00:00:00 2001 From: d6p <43806862+d6p@users.noreply.github.com> Date: Wed, 13 Feb 2019 16:53:36 +0100 Subject: [PATCH 35/66] update .travis.yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f13c227212ff..d7ec5b0ca471 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ before_script: - npm install -g grunt-cli - npm install -g mocha node_js: - - "0.12" + - "node" sudo: false cache: directories: From 0c686329c80d82b1b9a1484f61e477e399cbec36 Mon Sep 17 00:00:00 2001 From: d6p <43806862+d6p@users.noreply.github.com> Date: Wed, 13 Feb 2019 17:48:58 +0100 Subject: [PATCH 36/66] remove nested deployment --- .../nestedtemplates/cluster.json | 123 ++++++++---------- 1 file changed, 54 insertions(+), 69 deletions(-) diff --git a/safekit-cluster-farm/nestedtemplates/cluster.json b/safekit-cluster-farm/nestedtemplates/cluster.json index 78f4ca8a5abe..f800d65849fc 100644 --- a/safekit-cluster-farm/nestedtemplates/cluster.json +++ b/safekit-cluster-farm/nestedtemplates/cluster.json @@ -66,7 +66,6 @@ "metadata": { "description": "Public VM IP dns label prefix" } - }, "Loadbalancer": { "type": "string", @@ -230,80 +229,66 @@ } }, { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2018-05-01", - "name": "optionalLB", + "condition": "[and(not(empty(parameters('VIPDnsLabel'))),not(equals(parameters('Loadbalancer'),'none')))]", + "type": "Microsoft.Network/loadBalancers", + "apiVersion": "2018-08-01", + "name": "[variables('lbName')]", + "location": "[parameters('location')]", "dependsOn": [ "optionalVip" ], + "sku": { + "name": "Standard" + }, "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [ - { - "condition": "[and(not(empty(parameters('VIPDnsLabel'))),not(equals(parameters('Loadbalancer'),'none')))]", - "type": "Microsoft.Network/loadBalancers", - "apiVersion": "2018-08-01", - "name": "[variables('lbName')]", - "location": "[parameters('location')]", - "sku": { - "name": "Standard" + "frontendIPConfigurations": [ + { + "name": "[variables('frontEndIPConfigName')]", + "properties": { + "publicIPAddress": { + "id": "[resourceId('Microsoft.Network/publicIPAddresses',concat('pip',parameters('VIPDnsLabel')))]" + } + } + } + ], + "backendAddressPools": [ + { + "name": "[variables('lbPoolName')]" + } + ], + "loadBalancingRules": [ + { + "name": "LBRule", + "properties": { + "frontendIPConfiguration": { + "id": "[resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations',variables('lbName'),variables('frontEndIPConfigName'))]" + }, + "backendAddressPool": { + "id": "[resourceId('Microsoft.Network/loadBalancers/backendAddressPools',variables('lbName'),variables('lbPoolName'))]" }, - "properties": { - "frontendIPConfigurations": [ - { - "name": "[variables('frontEndIPConfigName')]", - "properties": { - "publicIPAddress": { - "id": "[resourceId('Microsoft.Network/publicIPAddresses',concat('pip',parameters('VIPDnsLabel')))]" - } - } - } - ], - "backendAddressPools": [ - { - "name": "[variables('lbPoolName')]" - } - ], - "loadBalancingRules": [ - { - "name": "LBRule", - "properties": { - "frontendIPConfiguration": { - "id": "[resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations',variables('lbName'),variables('frontEndIPConfigName'))]" - }, - "backendAddressPool": { - "id": "[resourceId('Microsoft.Network/loadBalancers/backendAddressPools',variables('lbName'),variables('lbPoolName'))]" - }, - "protocol": "tcp", - "frontendPort": 9453, - "backendPort": 9453, - "enableFloatingIP": false, - "idleTimeoutInMinutes": 5, - "probe": { - "id": "[resourceId('Microsoft.Network/loadBalancers/probes',variables('lbName'),variables('lbProbeName'))]" - } - } - } - ], - "probes": [ - { - "name": "[variables('lbProbeName')]", - "properties": { - "protocol": "http", - "port": 9010, - "requestPath": "[concat('/var/modules/',parameters('moduleName'),'/ready.txt')]", - "intervalInSeconds": 5, - "numberOfProbes": 2 - } - } - ] + "protocol": "tcp", + "frontendPort": 9453, + "backendPort": 9453, + "enableFloatingIP": false, + "idleTimeoutInMinutes": 5, + "probe": { + "id": "[resourceId('Microsoft.Network/loadBalancers/probes',variables('lbName'),variables('lbProbeName'))]" } } - ] - } + } + ], + "probes": [ + { + "name": "[variables('lbProbeName')]", + "properties": { + "protocol": "http", + "port": 9010, + "requestPath": "[concat('/var/modules/',parameters('moduleName'),'/ready.txt')]", + "intervalInSeconds": 5, + "numberOfProbes": 2 + } + } + ] } }, { @@ -401,7 +386,7 @@ "count": "[length(variables('vms'))]" }, "dependsOn": [ - "optionalLB", + "[variables('lbName')]", "[resourceId('Microsoft.Network/publicIPAddresses/',concat('pip',variables('vms')[copyIndex()]))]", "[resourceId('Microsoft.Network/networkSecurityGroups/',variables('NSGName'))]", "[variables('virtualNetworkName')]" From ad12d555d1e456f8be6059d0270a2df0988e0773 Mon Sep 17 00:00:00 2001 From: Aaron Ullom Date: Wed, 13 Feb 2019 13:08:01 -0600 Subject: [PATCH 37/66] Fixes issue #5808 - failure to create alert actions for oms-cloudfoundry-solution --- oms-cloudfoundry-solution/azuredeploy.json | 9 +++++++++ .../azuredeploy.parameters.json | 3 +++ oms-cloudfoundry-solution/nested/omsAlerts.json | 12 +++++++++++- 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/oms-cloudfoundry-solution/azuredeploy.json b/oms-cloudfoundry-solution/azuredeploy.json index 481b5c1c5964..8447cfb0054c 100644 --- a/oms-cloudfoundry-solution/azuredeploy.json +++ b/oms-cloudfoundry-solution/azuredeploy.json @@ -72,6 +72,12 @@ "description": "Select your provider of system metrics" } }, + "actionGroupName": { + "type": "string", + "metadata": { + "description": "The name of the action group for alert actions" + } + }, "_artifactsLocation": { "type": "string", "defaultValue": "https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/oms-cloudfoundry-solution", @@ -187,6 +193,9 @@ "parameters": { "omsWorkspaceName": { "value": "[parameters('omsWorkspaceName')]" + }, + "actionGroupName": { + "value": "[parameters('actionGroupName')]" } } } diff --git a/oms-cloudfoundry-solution/azuredeploy.parameters.json b/oms-cloudfoundry-solution/azuredeploy.parameters.json index a711d9846142..5b8608ca07b5 100644 --- a/oms-cloudfoundry-solution/azuredeploy.parameters.json +++ b/oms-cloudfoundry-solution/azuredeploy.parameters.json @@ -13,6 +13,9 @@ }, "systemMetricsProvider": { "value": "None" + }, + "actionGroupName": { + "value": "" } } } \ No newline at end of file diff --git a/oms-cloudfoundry-solution/nested/omsAlerts.json b/oms-cloudfoundry-solution/nested/omsAlerts.json index 2de1f09d8e0c..e3f4df459c34 100644 --- a/oms-cloudfoundry-solution/nested/omsAlerts.json +++ b/oms-cloudfoundry-solution/nested/omsAlerts.json @@ -7,6 +7,12 @@ "metadata": { "description": "Input the name of your OMS Workspace" } + }, + "actionGroupName": { + "type": "string", + "metadata": { + "description": "The name of the action group for alert actions" + } } }, "variables": { @@ -1776,8 +1782,12 @@ }, "Throttling": { "DurationInMinutes": "[variables('alerts')[copyIndex()].alert.throttleMinutes]" + }, + "AzNsNotification": { + "GroupIds": ["[concat(resourceGroup().id, '/providers/microsoft.insights/actiongroups/', parameters('actionGroupIds'))]"], + "CustomEmailSubject": "[concat('[', toUpper(variables('alerts')[copyIndex()].alert.severity), '] ', variables('alerts')[copyIndex()].alert.displayName)]" } } - } + } ] } \ No newline at end of file From 6d6366b1974b6f44e936a2166b32f8e26130dc72 Mon Sep 17 00:00:00 2001 From: Aaron Ullom Date: Wed, 13 Feb 2019 13:34:30 -0600 Subject: [PATCH 38/66] Fix actionGroupName parameter name --- oms-cloudfoundry-solution/nested/omsAlerts.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oms-cloudfoundry-solution/nested/omsAlerts.json b/oms-cloudfoundry-solution/nested/omsAlerts.json index e3f4df459c34..2e2247bb4f82 100644 --- a/oms-cloudfoundry-solution/nested/omsAlerts.json +++ b/oms-cloudfoundry-solution/nested/omsAlerts.json @@ -1784,7 +1784,7 @@ "DurationInMinutes": "[variables('alerts')[copyIndex()].alert.throttleMinutes]" }, "AzNsNotification": { - "GroupIds": ["[concat(resourceGroup().id, '/providers/microsoft.insights/actiongroups/', parameters('actionGroupIds'))]"], + "GroupIds": ["[concat(resourceGroup().id, '/providers/microsoft.insights/actiongroups/', parameters('actionGroupName'))]"], "CustomEmailSubject": "[concat('[', toUpper(variables('alerts')[copyIndex()].alert.severity), '] ', variables('alerts')[copyIndex()].alert.displayName)]" } } From a8658337ac5b18c1f8b2854e245a3e699bf07845 Mon Sep 17 00:00:00 2001 From: Aaron Ullom Date: Wed, 13 Feb 2019 13:48:42 -0600 Subject: [PATCH 39/66] Fix case on json property --- oms-cloudfoundry-solution/nested/omsAlerts.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oms-cloudfoundry-solution/nested/omsAlerts.json b/oms-cloudfoundry-solution/nested/omsAlerts.json index 2e2247bb4f82..08d72050f634 100644 --- a/oms-cloudfoundry-solution/nested/omsAlerts.json +++ b/oms-cloudfoundry-solution/nested/omsAlerts.json @@ -1773,7 +1773,7 @@ "properties": { "etag": "*", "Type": "Alert", - "name": "[variables('alerts')[copyIndex()].alert.displayName]", + "Name": "[variables('alerts')[copyIndex()].alert.displayName]", "Description": "[variables('alerts')[copyIndex()].alert.description]", "Severity": "[toLower(variables('alerts')[copyIndex()].alert.severity)]", "Threshold": { From 4cacf6cffa5256bdeef100accd922919f6392a26 Mon Sep 17 00:00:00 2001 From: Aaron Ullom Date: Wed, 13 Feb 2019 14:55:50 -0600 Subject: [PATCH 40/66] Changed default actionGroupName to None --- oms-cloudfoundry-solution/azuredeploy.parameters.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oms-cloudfoundry-solution/azuredeploy.parameters.json b/oms-cloudfoundry-solution/azuredeploy.parameters.json index 5b8608ca07b5..96443674ef6a 100644 --- a/oms-cloudfoundry-solution/azuredeploy.parameters.json +++ b/oms-cloudfoundry-solution/azuredeploy.parameters.json @@ -15,7 +15,7 @@ "value": "None" }, "actionGroupName": { - "value": "" + "value": "None" } } } \ No newline at end of file From 53ffbe081ced64fdf74cc16361d7fbe22f8de325 Mon Sep 17 00:00:00 2001 From: Jonathan Gao Date: Thu, 14 Feb 2019 12:26:59 -0500 Subject: [PATCH 41/66] update the azureRM to az in the cmdlet names --- 101-key-vault-create/azuredeploy.json | 4 ++-- 101-key-vault-create/metadata.json | 2 +- 201-key-vault-secret-create/azuredeploy.json | 4 ++-- 201-key-vault-secret-create/metadata.json | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/101-key-vault-create/azuredeploy.json b/101-key-vault-create/azuredeploy.json index 4b15baf0c053..643e278f125f 100644 --- a/101-key-vault-create/azuredeploy.json +++ b/101-key-vault-create/azuredeploy.json @@ -19,13 +19,13 @@ "type": "string", "defaultValue": "[subscription().tenantId]", "metadata": { - "description": "Tenant Id of the Azure subscription used for authenticating requests to the key vault. Get it by using Get-AzureRmSubscription cmdlet." + "description": "Tenant Id of the Azure subscription used for authenticating requests to the key vault. Get it by using Get-AzSubscription cmdlet." } }, "objectId": { "type": "string", "metadata": { - "description": "The object ID of the Azure AD user for the key vault. Get it by using Get-AzureRmADUser or Get-AzureRmADServicePrincipal cmdlets." + "description": "The object ID of the Azure AD user for the key vault. Get it by using Get-AzADUser or Get-AzADServicePrincipal cmdlets." } }, "secretName": { diff --git a/101-key-vault-create/metadata.json b/101-key-vault-create/metadata.json index 77ae31e8b3ba..9fec7bee3275 100644 --- a/101-key-vault-create/metadata.json +++ b/101-key-vault-create/metadata.json @@ -5,7 +5,7 @@ "description": "This template creates an Azure Key Vault and a secret.", "summary": "This template creates a Key Vault and assigns permissions to the supplied objectId (principal).", "githubUsername": "seanbamsft", - "dateUpdated": "2019-01-24" + "dateUpdated": "2019-02-14" } diff --git a/201-key-vault-secret-create/azuredeploy.json b/201-key-vault-secret-create/azuredeploy.json index d45e42fdfc2d..f0e143318b29 100644 --- a/201-key-vault-secret-create/azuredeploy.json +++ b/201-key-vault-secret-create/azuredeploy.json @@ -19,13 +19,13 @@ "type": "string", "defaultValue": "[subscription().tenantId]", "metadata": { - "description": "Tenant Id of the Azure subscription used for authenticating requests to the key vault. Get it by using Get-AzureRmSubscription cmdlet." + "description": "Tenant Id of the Azure subscription used for authenticating requests to the key vault. Get it by using Get-AzSubscription cmdlet." } }, "objectId": { "type": "string", "metadata": { - "description": "The object ID of the Azure AD user for the key vault. Get it by using Get-AzureRmADUser or Get-AzureRmADServicePrincipal cmdlets." + "description": "The object ID of the Azure AD user for the key vault. Get it by using Get-AzADUser -UserPrincipalName or Get-AzADServicePrincipal cmdlets." } }, "secretsObject": { diff --git a/201-key-vault-secret-create/metadata.json b/201-key-vault-secret-create/metadata.json index 6eeac196eeb3..c7996874b2dd 100644 --- a/201-key-vault-secret-create/metadata.json +++ b/201-key-vault-secret-create/metadata.json @@ -5,7 +5,7 @@ "description": "This template creates a Key Vault and a list of secrets within the key vault as passed along with the parameters", "summary": "Creates a Key Vault with a list of secrets", "githubUsername": "rahulpnath", - "dateUpdated": "2019-01-24" + "dateUpdated": "2019-02-14" } From 3a0b4797860a492f1daaa7fe5d81f5327a22dc8a Mon Sep 17 00:00:00 2001 From: Jonathan Gao Date: Fri, 15 Feb 2019 12:06:10 -0500 Subject: [PATCH 42/66] incorporate Brian's comments --- 101-key-vault-create/azuredeploy.json | 143 ++++++++++-------- .../azuredeploy.parameters.json | 7 +- 201-key-vault-secret-create/azuredeploy.json | 115 +++++++------- .../azuredeploy.parameters.json | 7 +- 4 files changed, 143 insertions(+), 129 deletions(-) diff --git a/101-key-vault-create/azuredeploy.json b/101-key-vault-create/azuredeploy.json index 643e278f125f..5ead34421361 100644 --- a/101-key-vault-create/azuredeploy.json +++ b/101-key-vault-create/azuredeploy.json @@ -5,115 +5,133 @@ "keyVaultName": { "type": "string", "metadata": { - "description": "Name of the key vault." + "description": "Specifies the name of the key vault." } }, "location": { "type": "string", "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Location for the key vault." + "description": "Specifies the Azure location where the key vault should be created." + } + }, + "enabledForDeployment": { + "type": "bool", + "defaultValue": false, + "allowedValues": [ + true, + false + ], + "metadata": { + "description": "Specifies whether Azure Virtual Machines are permitted to retrieve certificates stored as secrets from the key vault." + } + }, + "enabledForDiskEncryption": { + "type": "bool", + "defaultValue": false, + "allowedValues": [ + true, + false + ], + "metadata": { + "description": "Specifies whether Azure Disk Encryption is permitted to retrieve secrets from the vault and unwrap keys." + } + }, + "enabledForTemplateDeployment": { + "type": "bool", + "defaultValue": false, + "allowedValues": [ + true, + false + ], + "metadata": { + "description": "Specifies whether Azure Resource Manager is permitted to retrieve secrets from the key vault." } }, "tenantId": { "type": "string", "defaultValue": "[subscription().tenantId]", "metadata": { - "description": "Tenant Id of the Azure subscription used for authenticating requests to the key vault. Get it by using Get-AzSubscription cmdlet." + "description": "Specifies the Azure Active Directory tenant ID that should be used for authenticating requests to the key vault. Get it by using Get-AzSubscription cmdlet." } }, "objectId": { "type": "string", "metadata": { - "description": "The object ID of the Azure AD user for the key vault. Get it by using Get-AzADUser or Get-AzADServicePrincipal cmdlets." + "description": "Specifies the object ID of a user, service principal or security group in the Azure Active Directory tenant for the vault. The object ID must be unique for the list of access policies. Get it by using Get-AzADUser or Get-AzADServicePrincipal cmdlets." + } + }, + "keysPermissions": { + "type": "array", + "defaultValue": [ + "list" + ], + "metadata": { + "description": "Specifies the permissions to keys in the vault. Valid values are: all, encrypt, decrypt, wrapKey, unwrapKey, sign, verify, get, list, create, update, import, delete, backup, restore, recover, and purge." + } + }, + "secretsPermissions": { + "type": "array", + "defaultValue": [ + "list" + ], + "metadata": { + "description": "Specifies the permissions to secrets in the vault. Valid values are: all, get, list, set, delete, backup, restore, recover, and purge." + } + }, + "skuName": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Standard", + "Premium" + ], + "metadata": { + "description": "Specifies whether the key vault is a standard vault or a premium vault." } }, "secretName": { "type": "string", - "defaultValue": "vmAdminPassword", "metadata": { - "description": "Name of the secret that you want to create." + "description": "Specifies the name of the secret that you want to create." } }, "secretValue": { "type": "securestring", "metadata": { - "description": "Value of the secret that you want to create." + "description": "Specifies the value of the secret that you want to create." } } }, - "variables": { - "enabledForDeployment": false, - "enabledForDiskEncryption": false, - "enabledForTemplateDeployment": false, - "sku": "Standard" - }, "resources": [ { "type": "Microsoft.KeyVault/vaults", "name": "[parameters('keyVaultName')]", - "apiVersion": "2016-10-01", + "apiVersion": "2018-02-14", "location": "[parameters('location')]", "properties": { - "enabledForDeployment": "[variables('enabledForDeployment')]", - "enabledForDiskEncryption": "[variables('enabledForDiskEncryption')]", - "enabledForTemplateDeployment": "[variables('enabledForTemplateDeployment')]", + "enabledForDeployment": "[parameters('enabledForDeployment')]", + "enabledForDiskEncryption": "[parameters('enabledForDiskEncryption')]", + "enabledForTemplateDeployment": "[parameters('enabledForTemplateDeployment')]", "tenantId": "[parameters('tenantId')]", "accessPolicies": [ { "objectId": "[parameters('objectId')]", "tenantId": "[parameters('tenantId')]", "permissions": { - "keys": [ - "Get", - "List", - "Update", - "Create", - "Import", - "Delete", - "Recover", - "Backup", - "Restore" - ], - "secrets": [ - "Get", - "List", - "Set", - "Delete", - "Recover", - "Backup", - "Restore" - ], - "certificates": [ - "Get", - "List", - "Update", - "Create", - "Import", - "Delete", - "Recover", - "Backup", - "Restore", - "ManageContacts", - "ManageIssuers", - "GetIssuers", - "ListIssuers", - "SetIssuers", - "DeleteIssuers" - ] + "keys": "[parameters('keysPermissions')]", + "secrets": "[parameters('secretsPermissions')]" } } ], "sku": { - "name": "[variables('sku')]", + "name": "[parameters('skuName')]", "family": "A" }, "networkAcls": { "value": { "defaultAction": "Allow", - "bypass": "AzureServices", - "virtualNetworkRules": [], - "ipRules": [] + "bypass": "AzureServices" } } } @@ -121,18 +139,13 @@ { "type": "Microsoft.KeyVault/vaults/secrets", "name": "[concat(parameters('keyVaultName'), '/', parameters('secretName'))]", - "apiVersion": "2016-10-01", + "apiVersion": "2018-02-14", "location": "[parameters('location')]", - "scale": null, "dependsOn": [ "[resourceId('Microsoft.KeyVault/vaults', parameters('keyVaultName'))]" ], "properties": { - "contentType": "securestring", - "value": "[parameters('secretValue')]", - "attributes": { - "enabled": true - } + "value": "[parameters('secretValue')]" } } ] diff --git a/101-key-vault-create/azuredeploy.parameters.json b/101-key-vault-create/azuredeploy.parameters.json index 04ba8be9f817..61209ca862f1 100644 --- a/101-key-vault-create/azuredeploy.parameters.json +++ b/101-key-vault-create/azuredeploy.parameters.json @@ -3,13 +3,10 @@ "contentVersion": "1.0.0.0", "parameters": { "keyVaultName": { - "value": "GEN-KEYVAULT-NAME" - }, - "tenantId": { - "value": "GEN-GUID" + "value": "GEN-UNIQUE" }, "objectId": { - "value": "GEN-GUID" + "value": "GEN-AZURE_OBJECT_ID" } } } \ No newline at end of file diff --git a/201-key-vault-secret-create/azuredeploy.json b/201-key-vault-secret-create/azuredeploy.json index f0e143318b29..36fa6779a813 100644 --- a/201-key-vault-secret-create/azuredeploy.json +++ b/201-key-vault-secret-create/azuredeploy.json @@ -2,7 +2,7 @@ "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { - "name": { + "keyVaultName": { "type": "string", "metadata": { "description": "Name of the key vault." @@ -15,6 +15,27 @@ "description": "Location of the key vault." } }, + "enabledForDeployment": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Specifies if the vault is enabled for VM or Service Fabric deployment" + } + }, + "enabledForTemplateDeployment": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Specifies if the vault is enabled for ARM template deployment" + } + }, + "enabledForDiskEncryption": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Specifies if the vault is enabled for volume encryption" + } + }, "tenantId": { "type": "string", "defaultValue": "[subscription().tenantId]", @@ -28,6 +49,35 @@ "description": "The object ID of the Azure AD user for the key vault. Get it by using Get-AzADUser -UserPrincipalName or Get-AzADServicePrincipal cmdlets." } }, + "keysPermissions": { + "type": "array", + "defaultValue": [ + "list" + ], + "metadata": { + "description": "Specifies the permissions to keys in the vault. Valid values are: all, encrypt, decrypt, wrapKey, unwrapKey, sign, verify, get, list, create, update, import, delete, backup, restore, recover, and purge." + } + }, + "secretsPermissions": { + "type": "array", + "defaultValue": [ + "list" + ], + "metadata": { + "description": "Specifies the permissions to secrets in the vault. Valid values are: all, get, list, set, delete, backup, restore, recover, and purge." + } + }, + "skuName": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Standard", + "Premium" + ], + "metadata": { + "description": "Specifies whether the key vault is a standard vault or a premium vault." + } + }, "secretsObject": { "type": "secureObject", "defaultValue": "{}", @@ -36,91 +86,48 @@ } } }, - "variables": { - "enabledForDeployment": false, - "enabledForTemplateDeployment": false, - "enabledForDiskEncryption": false, - "sku": "Standard" - }, "resources": [ { "type": "Microsoft.KeyVault/vaults", - "name": "[parameters('name')]", + "name": "[parameters('keyVaultName')]", "location": "[parameters('location')]", "apiVersion": "2018-02-14", "tags": { "displayName": "KeyVault" }, "properties": { - "enabledForDeployment": "[variables('enabledForDeployment')]", - "enabledForTemplateDeployment": "[variables('enabledForTemplateDeployment')]", - "enabledForDiskEncryption": "[variables('enabledForDiskEncryption')]", + "enabledForDeployment": "[parameters('enabledForDeployment')]", + "enabledForTemplateDeployment": "[parameters('enabledForTemplateDeployment')]", + "enabledForDiskEncryption": "[parameters('enabledForDiskEncryption')]", "tenantId": "[parameters('tenantId')]", "accessPolicies": [ { "objectId": "[parameters('objectId')]", "tenantId": "[parameters('tenantId')]", "permissions": { - "keys": [ - "Get", - "List", - "Update", - "Create", - "Import", - "Delete", - "Recover", - "Backup", - "Restore" - ], - "secrets": [ - "Get", - "List", - "Set", - "Delete", - "Recover", - "Backup", - "Restore" - ], - "certificates": [ - "Get", - "List", - "Update", - "Create", - "Import", - "Delete", - "Recover", - "Backup", - "Restore", - "ManageContacts", - "ManageIssuers", - "GetIssuers", - "ListIssuers", - "SetIssuers", - "DeleteIssuers" - ] + "keys": "[parameters('keysPermissions')]", + "secrets": "[parameters('secretsPermissions')]" } } ], "sku": { - "name": "[variables('sku')]", + "name": "[parameters('skuName')]", "family": "A" }, "networkAcls": { "value": { "defaultAction": "Allow", - "bypass": "AzureServices", - "virtualNetworkRules": [], - "ipRules": [] + "bypass": "AzureServices" } } } }, { "type": "Microsoft.KeyVault/vaults/secrets", - "name": "[concat(parameters('name'), '/', parameters('secretsObject').secrets[copyIndex()].secretName)]", + "name": "[concat(parameters('keyVaultName'), '/', parameters('secretsObject').secrets[copyIndex()].secretName)]", "apiVersion": "2018-02-14", "dependsOn": [ - "[concat('Microsoft.KeyVault/vaults/', parameters('name'))]" + "[concat('Microsoft.KeyVault/vaults/', parameters('keyVaultName'))]" ], "properties": { "value": "[parameters('secretsObject').secrets[copyIndex()].secretValue]" diff --git a/201-key-vault-secret-create/azuredeploy.parameters.json b/201-key-vault-secret-create/azuredeploy.parameters.json index 21b42c7a9052..c5ed17eb26f8 100644 --- a/201-key-vault-secret-create/azuredeploy.parameters.json +++ b/201-key-vault-secret-create/azuredeploy.parameters.json @@ -3,13 +3,10 @@ "contentVersion": "1.0.0.0", "parameters": { "name": { - "value": "GEN-KEYVAULT-NAME" - }, - "tenantId": { - "value": "GEN-GUID" + "value": "GEN-UNIQUE" }, "objectId": { - "value": "GEN-GUID" + "value": "GEN-AZURE_OBJECT_ID" }, "secretsObject": { "value": { From 380954d08a3c145a07b3f890ec658913e3fbff57 Mon Sep 17 00:00:00 2001 From: Jonathan Gao Date: Fri, 15 Feb 2019 13:31:16 -0500 Subject: [PATCH 43/66] incorporate Brian's feedback --- 201-key-vault-secret-create/azuredeploy.json | 32 ++++++++++++++------ 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/201-key-vault-secret-create/azuredeploy.json b/201-key-vault-secret-create/azuredeploy.json index 36fa6779a813..b937448f1df9 100644 --- a/201-key-vault-secret-create/azuredeploy.json +++ b/201-key-vault-secret-create/azuredeploy.json @@ -5,48 +5,60 @@ "keyVaultName": { "type": "string", "metadata": { - "description": "Name of the key vault." + "description": "Specifies the name of the key vault." } }, "location": { "type": "string", "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Location of the key vault." + "description": "Specifies the Azure location where the key vault should be created." } }, "enabledForDeployment": { "type": "bool", "defaultValue": false, + "allowedValues": [ + true, + false + ], "metadata": { - "description": "Specifies if the vault is enabled for VM or Service Fabric deployment" + "description": "Specifies whether Azure Virtual Machines are permitted to retrieve certificates stored as secrets from the key vault." } }, - "enabledForTemplateDeployment": { + "enabledForDiskEncryption": { "type": "bool", "defaultValue": false, + "allowedValues": [ + true, + false + ], "metadata": { - "description": "Specifies if the vault is enabled for ARM template deployment" + "description": "Specifies whether Azure Disk Encryption is permitted to retrieve secrets from the vault and unwrap keys." } }, - "enabledForDiskEncryption": { + "enabledForTemplateDeployment": { "type": "bool", "defaultValue": false, + "allowedValues": [ + true, + false + ], "metadata": { - "description": "Specifies if the vault is enabled for volume encryption" + "description": "Specifies whether Azure Resource Manager is permitted to retrieve secrets from the key vault." } }, "tenantId": { "type": "string", "defaultValue": "[subscription().tenantId]", "metadata": { - "description": "Tenant Id of the Azure subscription used for authenticating requests to the key vault. Get it by using Get-AzSubscription cmdlet." + "description": "Specifies the Azure Active Directory tenant ID that should be used for authenticating requests to the key vault. Get it by using Get-AzSubscription cmdlet." } }, "objectId": { "type": "string", "metadata": { - "description": "The object ID of the Azure AD user for the key vault. Get it by using Get-AzADUser -UserPrincipalName or Get-AzADServicePrincipal cmdlets." + "description": "Specifies the object ID of a user, service principal or security group in the Azure Active Directory tenant for the vault. The object ID must be unique for the list of access policies. Get it by using Get-AzADUser or Get-AzADServicePrincipal cmdlets." } }, "keysPermissions": { @@ -82,7 +94,7 @@ "type": "secureObject", "defaultValue": "{}", "metadata": { - "description": "all secrets {\"secretName\":\"\",\"secretValue\":\"\"} wrapped in a secure object." + "description": "Specifies all secrets {\"secretName\":\"\",\"secretValue\":\"\"} wrapped in a secure object." } } }, From 7337487b0a770d7cee5357fb90763d386682d099 Mon Sep 17 00:00:00 2001 From: Marlon Singleton Date: Sat, 16 Feb 2019 22:57:01 +0300 Subject: [PATCH 44/66] updated: ubuntuOSVersion changed ubuntuOSVersion from 17.10 to 18.04-LTS. Deployment fails with 17.10. Successfully tested deployment with 18.04-LTS. --- 101-ubuntu-mate-desktop-vscode/azuredeploy.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/101-ubuntu-mate-desktop-vscode/azuredeploy.json b/101-ubuntu-mate-desktop-vscode/azuredeploy.json index 99ae2fac6c79..3331fd01d78d 100644 --- a/101-ubuntu-mate-desktop-vscode/azuredeploy.json +++ b/101-ubuntu-mate-desktop-vscode/azuredeploy.json @@ -55,7 +55,7 @@ "vmStorageAccountContainerName": "vhds", "imagePublisher": "Canonical", "imageOffer": "UbuntuServer", - "ubuntuOSVersion": "17.10", + "ubuntuOSVersion": "18.04-LTS", "OSDiskName": "OSDisk", "vmName": "vm", "nicName": "vmNic", From 630afdfb2111d7c86d9fbfac23f94ec2a9db7592 Mon Sep 17 00:00:00 2001 From: Jonathan Gao Date: Sat, 16 Feb 2019 20:52:23 -0500 Subject: [PATCH 45/66] move 'copy' before 'properties' --- 201-key-vault-secret-create/azuredeploy.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/201-key-vault-secret-create/azuredeploy.json b/201-key-vault-secret-create/azuredeploy.json index b937448f1df9..796361a8c947 100644 --- a/201-key-vault-secret-create/azuredeploy.json +++ b/201-key-vault-secret-create/azuredeploy.json @@ -141,12 +141,12 @@ "dependsOn": [ "[concat('Microsoft.KeyVault/vaults/', parameters('keyVaultName'))]" ], - "properties": { - "value": "[parameters('secretsObject').secrets[copyIndex()].secretValue]" - }, "copy": { "name": "secretsCopy", "count": "[length(parameters('secretsObject').secrets)]" + }, + "properties": { + "value": "[parameters('secretsObject').secrets[copyIndex()].secretValue]" } } ] From 9cf498399aa0ff0bb2f22ee8a23d51d2a0d9f2e6 Mon Sep 17 00:00:00 2001 From: Nerya Cohen Date: Sun, 17 Feb 2019 09:54:42 +0200 Subject: [PATCH 46/66] remove params which have a default value --- .../azuredeploy.parameters.json | 9 --------- 1 file changed, 9 deletions(-) diff --git a/201-storage-advanced-threat-protection-create/azuredeploy.parameters.json b/201-storage-advanced-threat-protection-create/azuredeploy.parameters.json index b198b97158b9..d95b533b058e 100644 --- a/201-storage-advanced-threat-protection-create/azuredeploy.parameters.json +++ b/201-storage-advanced-threat-protection-create/azuredeploy.parameters.json @@ -4,15 +4,6 @@ "parameters": { "storageAccountName": { "value": "GEN-UNIQUE" - }, - "storageAccountKind": { - "value": "StorageV2" - }, - "storageAccountReplication": { - "value": "Standard_LRS" - }, - "advancedThreatProtectionEnabled": { - "value": true } } } \ No newline at end of file From 16b57db94c50c069a98812530df14c2166cadebe Mon Sep 17 00:00:00 2001 From: Nerya Cohen Date: Sun, 17 Feb 2019 09:56:31 +0200 Subject: [PATCH 47/66] fix for tomerlmsft comments --- .../azuredeploy.json | 4 ++-- 201-storage-advanced-threat-protection-create/metadata.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/201-storage-advanced-threat-protection-create/azuredeploy.json b/201-storage-advanced-threat-protection-create/azuredeploy.json index ec202d831e4c..11349d5e2562 100644 --- a/201-storage-advanced-threat-protection-create/azuredeploy.json +++ b/201-storage-advanced-threat-protection-create/azuredeploy.json @@ -23,7 +23,7 @@ "Storage" ], "metadata": { - "description": "Storage Account type, for more info see 'https://docs.microsoft.com/en-us/azure/storage/common/storage-account-overview'." + "description": "Storage account type, for more info see 'https://docs.microsoft.com/en-us/azure/storage/common/storage-account-overview'." } }, "storageAccountReplication": { @@ -36,7 +36,7 @@ "Premium_LRS" ], "metadata": { - "description": "Storage Account replication, for more info see 'https://docs.microsoft.com/en-us/azure/storage/common/storage-redundancy'." + "description": "Storage account replication, for more info see 'https://docs.microsoft.com/en-us/azure/storage/common/storage-redundancy'." } }, "advancedThreatProtectionEnabled": { diff --git a/201-storage-advanced-threat-protection-create/metadata.json b/201-storage-advanced-threat-protection-create/metadata.json index 3448c17a5f15..da1fe081cc8f 100644 --- a/201-storage-advanced-threat-protection-create/metadata.json +++ b/201-storage-advanced-threat-protection-create/metadata.json @@ -1,9 +1,9 @@ { "$schema": "https://aka.ms/azure-quickstart-templates-metadata-schema#", "type": "QuickStart", - "itemDisplayName": "Storage account with Advanced Threat Protection", + "itemDisplayName": "Storage account with Advanced Threat Protection.", "description": "This template allows you to deploy an Azure Storage account with Advanced Threat Protection enabled.", "summary": "Deploy an Azure Storage account with Advanced Threat Protection enabled.", "githubUsername": "neryaco", - "dateUpdated": "2019-01-22" + "dateUpdated": "2019-02-17" } \ No newline at end of file From 1230dc581775a4442d9ee09477bdf224c12173c7 Mon Sep 17 00:00:00 2001 From: Nerya Cohen Date: Sun, 17 Feb 2019 09:57:41 +0200 Subject: [PATCH 48/66] add defaultValue for storageAccountName --- 201-storage-advanced-threat-protection-create/azuredeploy.json | 1 + 1 file changed, 1 insertion(+) diff --git a/201-storage-advanced-threat-protection-create/azuredeploy.json b/201-storage-advanced-threat-protection-create/azuredeploy.json index 11349d5e2562..91ad96327d22 100644 --- a/201-storage-advanced-threat-protection-create/azuredeploy.json +++ b/201-storage-advanced-threat-protection-create/azuredeploy.json @@ -4,6 +4,7 @@ "parameters": { "storageAccountName": { "type": "string", + "defaultValue": "[concat('atpstorage', uniqueString(resourceGroup().id))]", "metadata": { "description": "The name must be unique across all existing storage account names in Azure. It must be 3 to 24 characters long, and can contain only lowercase letters and numbers." } From 56c06a78ddd1433f5db31162c1074917ddb59d02 Mon Sep 17 00:00:00 2001 From: Nerya Cohen Date: Sun, 17 Feb 2019 10:08:06 +0200 Subject: [PATCH 49/66] change storageAccountLocation to location --- .../azuredeploy.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/201-storage-advanced-threat-protection-create/azuredeploy.json b/201-storage-advanced-threat-protection-create/azuredeploy.json index 91ad96327d22..7659945baf08 100644 --- a/201-storage-advanced-threat-protection-create/azuredeploy.json +++ b/201-storage-advanced-threat-protection-create/azuredeploy.json @@ -9,7 +9,7 @@ "description": "The name must be unique across all existing storage account names in Azure. It must be 3 to 24 characters long, and can contain only lowercase letters and numbers." } }, - "storageAccountLocation": { + "location": { "type": "string", "defaultValue": "[resourceGroup().location]", "metadata": { @@ -52,7 +52,7 @@ { "type": "Microsoft.Storage/storageAccounts", "name": "[parameters('storageAccountName')]", - "location": "[parameters('storageAccountLocation')]", + "location": "[parameters('location')]", "apiVersion": "2018-07-01", "sku": { "name": "[parameters('storageAccountReplication')]" From 2555de1bdc72b7bc599c35f14850d2bfa77a28b8 Mon Sep 17 00:00:00 2001 From: Nerya Cohen Date: Sun, 17 Feb 2019 10:09:41 +0200 Subject: [PATCH 50/66] replace concat() with resourceId() --- 201-storage-advanced-threat-protection-create/azuredeploy.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/201-storage-advanced-threat-protection-create/azuredeploy.json b/201-storage-advanced-threat-protection-create/azuredeploy.json index 7659945baf08..a73490a8a591 100644 --- a/201-storage-advanced-threat-protection-create/azuredeploy.json +++ b/201-storage-advanced-threat-protection-create/azuredeploy.json @@ -66,7 +66,7 @@ "name": "Microsoft.Security/current", "apiVersion": "2017-08-01-preview", "dependsOn": [ - "[concat('Microsoft.Storage/storageAccounts/', parameters('storageAccountName'))]" + "[resourceId('Microsoft.Storage/storageAccounts/', parameters('storageAccountName'))]" ], "properties": { "isEnabled": true From 7de4de039a7888d66de45e0680a9862a4b51556e Mon Sep 17 00:00:00 2001 From: Nerya Cohen Date: Sun, 17 Feb 2019 10:17:19 +0200 Subject: [PATCH 51/66] Update .travis.yml --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index f13c227212ff..5c62be27cd68 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,8 +5,8 @@ before_script: - npm install -g grunt-cli - npm install -g mocha node_js: - - "0.12" + - "node" sudo: false cache: directories: - - node_modules + - node_modules \ No newline at end of file From fa41100d3ba9228a5beb94eb387bdf3695467f36 Mon Sep 17 00:00:00 2001 From: StartAutomating Date: Mon, 18 Feb 2019 17:44:59 -0800 Subject: [PATCH 52/66] - Adding ReadMe - Adding Module - Updating wrappers to use module - Adding Expand-AzureRMTemplate, which expands the template contents - Enabling documentation in JSON, by overriding ConvertFrom-Json with a version that handles comments --- test/README.md | 1 - test/template-tests/.gitattributes | Bin 106 -> 0 bytes test/template-tests/AzRMTester.psd1 | 5 + test/template-tests/AzRMTester.psm1 | 6 + test/template-tests/ConvertFrom-JSON.ps1 | 61 ++++++ .../template-tests/Expand-AzureRMTemplate.ps1 | 182 ++++++++++++++++++ test/template-tests/Test-AzureRMTemplate.cmd | 2 +- test/template-tests/Test-AzureRMTemplate.ps1 | 125 ++---------- test/template-tests/Test-AzureRMTemplate.sh | 2 +- test/template-tests/readme.md | 58 ++++++ .../Min-And-Max-Value-Are-Numbers.test.ps1 | 4 +- .../Resources-Should-Have-Location.test.ps1 | 20 +- ...ng-Parameters-Cannot-Have-Default.test.ps1 | 2 +- 13 files changed, 338 insertions(+), 130 deletions(-) delete mode 100644 test/README.md delete mode 100644 test/template-tests/.gitattributes create mode 100644 test/template-tests/AzRMTester.psd1 create mode 100644 test/template-tests/AzRMTester.psm1 create mode 100644 test/template-tests/ConvertFrom-JSON.ps1 create mode 100644 test/template-tests/Expand-AzureRMTemplate.ps1 create mode 100644 test/template-tests/readme.md diff --git a/test/README.md b/test/README.md deleted file mode 100644 index 8b137891791f..000000000000 --- a/test/README.md +++ /dev/null @@ -1 +0,0 @@ - diff --git a/test/template-tests/.gitattributes b/test/template-tests/.gitattributes deleted file mode 100644 index b906930e24c6b257393bf3c9b8bb713b695dd839..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 106 zcmXZT!3sb?6ouh`t-Qmm6=h>LE18v*cmgJg&`>-*&cfz)`oHe`BxLLy$4^($V51IR!P9zP)_GQqrh6Vj@0^b`tFX diff --git a/test/template-tests/AzRMTester.psd1 b/test/template-tests/AzRMTester.psd1 new file mode 100644 index 000000000000..cdafb19677f9 --- /dev/null +++ b/test/template-tests/AzRMTester.psd1 @@ -0,0 +1,5 @@ +@{ + ModuleVersion = 0.1 + ModuleToProcess = 'AzRMTester.psm1' + Description = 'Validation tools for Azure Resource Manager Templates' +} \ No newline at end of file diff --git a/test/template-tests/AzRMTester.psm1 b/test/template-tests/AzRMTester.psm1 new file mode 100644 index 000000000000..c56ec4c0681c --- /dev/null +++ b/test/template-tests/AzRMTester.psm1 @@ -0,0 +1,6 @@ +. $psScriptRoot\ConvertFrom-Json.ps1 # Overwriting ConvertFrom-JSON to allow for comments within JSON + +. $PSScriptRoot\Expand-AzureRMTemplate.ps1 +. $PSScriptRoot\Test-AzureRMTemplate.ps1 + + diff --git a/test/template-tests/ConvertFrom-JSON.ps1 b/test/template-tests/ConvertFrom-JSON.ps1 new file mode 100644 index 000000000000..c0f4215a1dc9 --- /dev/null +++ b/test/template-tests/ConvertFrom-JSON.ps1 @@ -0,0 +1,61 @@ +function ConvertFrom-Json +{ +[CmdletBinding(HelpUri='https://go.microsoft.com/fwlink/?LinkID=217031', RemotingCapability='None')] +param( + [Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)] + [AllowEmptyString()] + [string] + ${InputObject}) + +begin +{ + try { + $outBuffer = $null + if ($PSBoundParameters.TryGetValue('OutBuffer', [ref]$outBuffer)) + { + $PSBoundParameters['OutBuffer'] = 1 + } + $wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Microsoft.PowerShell.Utility\ConvertFrom-Json', [System.Management.Automation.CommandTypes]::Cmdlet) + $scriptCmd = {& $wrappedCmd @PSBoundParameters } + $steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin) + $steppablePipeline.Begin($PSCmdlet) + } catch { + throw + } +} + +process +{ + try { + $options = 'Multiline,IgnoreCase,IgnorePatternWhitespace' + + $in = + [Regex]::Replace( + [Regex]::Replace($_, '/\*(?[^(/*/)]+)\*/', '', $options), + '(?.{0,})$', '', $options + ) + + $steppablePipeline.Process( + $in + ) + } catch { + throw + } +} + +end +{ + try { + $steppablePipeline.End() + } catch { + throw + } +} +<# + +.ForwardHelpTargetName Microsoft.PowerShell.Utility\ConvertFrom-Json +.ForwardHelpCategory Cmdlet + +#> + +} \ No newline at end of file diff --git a/test/template-tests/Expand-AzureRMTemplate.ps1 b/test/template-tests/Expand-AzureRMTemplate.ps1 new file mode 100644 index 000000000000..3893d5bbe728 --- /dev/null +++ b/test/template-tests/Expand-AzureRMTemplate.ps1 @@ -0,0 +1,182 @@ +function Expand-AzureRMTemplate +{ + <# + .Synopsis + Expands the contents of an Azure Resource Manager template. + .Description + Expands an Azure Resource Manager template and related files into a set of well-known parameters + + #> + param( + # The path to an Azure resource manager template + [Parameter(Mandatory=$true,Position=0,ValueFromPipelineByPropertyName=$true,ParameterSetName='SpecificTemplate')] + [Alias('Fullname','Path')] + [string] + $TemplatePath + ) + + begin { + function Expand-Resource ( + [Parameter(Mandatory=$true,Position=0,ValueFromPipelineByPropertyName=$true)] + [Alias('Resources')] + [PSObject[]] + $Resource, + + [PSObject[]] + $Parent + ) { + process { + foreach ($r in $Resource) { + $r | + Add-Member NoteProperty ParentResources $parent -Force -PassThru + + if ($r.resources) { + $r | Expand-Resource -Parent (@($r) + @(if ($parent) { $parent })) + } + } + } + } + } + + process { + # Now let's try to resolve the template path. + $resolvedTemplatePath = + # If the template path doesn't appear to be a path to a json file, + if ($TemplatePath -notlike '*.json') { + # see if it looks like a file + if (($templatePath | Split-Path -Leaf) -like '*.*') { + $TemplatePath = $TemplatePath | Split-Path # if it does, reassign template path to it's directory. + } + # Then, go looking beneath that template path + $preferredJsonFile = $TemplatePath | + Get-ChildItem -Filter *.json | + # for a file named azureDeploy.json or mainTemplate.json + Where-Object { 'azureDeploy.json', 'mainTemplate.json' -contains $_.Name } | + Select-Object -First 1 -ExpandProperty Fullname + # If no file was found, write an error and return. + if (-not $preferredJsonFile) { + Write-Error "No azureDeploy.json or mainTemplate.json found beneath $TemplatePath" + return + } + $preferredJsonFile + } else { + $ExecutionContext.SessionState.Path.GetResolvedPSPathFromPSPath($templatePath) + } + + # If we couldn't find a template file, return (an error should have already been written). + if (-not $resolvedTemplatePath) { return } + + + # Next, we want to pre-populate a number of well-known variables. + # These variables will be available to every test case. They are: + $WellKnownVariables = 'TemplateFullPath','TemplateText','TemplateObject', + 'CreateUIDefinitionFullPath','createUIDefintionText','CreateUIDefinitionObject', + 'FolderName', 'HasCreateUIDefinition', 'IsMainTemplate','FolderFiles', + 'MainTemplatePath', 'MainTemplateObject', 'MainTemplateText' + foreach ($_ in $WellKnownVariables) { + $ExecutionContext.SessionState.PSVariable.Set($_, $null) + } + + #*$templateFullPath (the full path to the .json file) + $TemplateFullPath = "$resolvedTemplatePath" + #*$TemplateFileName (the name of the azure template file) + $templateFileName = $TemplatePath | Split-Path -Leaf + #*$IsMainTemplate (if the TemplateFileName is named mainTemplate.json) + $isMainTemplate = 'mainTemplate.json', 'azureDeploy.json' -contains $templateFileName + $templateFile = Get-Item -LiteralPath $resolvedTemplatePath + $templateFolder = $templateFile.Directory + #*$FolderName (the name of the root folder containing the template) + $TemplateName = $templateFolder.Name + #*$TemplateText (the text contents of the template file) + $TemplateText = [IO.File]::ReadAllText($resolvedTemplatePath) + #*$TemplateObject (the template text, converted from JSON) + $TemplateObject = $TemplateText | ConvertFrom-Json + #*$CreateUIDefinitionFullPath (the path to CreateUIDefinition.json) + $createUiDefinitionFullPath = Join-Path -childPath 'createUiDefinition.json' -Path $templateFolder + if (Test-Path $createUiDefinitionFullPath) { + #*$CreateUIDefinitionText (the text contents of CreateUIDefinition.json) + $createUIDefintionText = [IO.File]::ReadAllText($createUiDefinitionFullPath) + #*$CreateUIDefinitionObject (the createuidefinition text, converted from json) + $createUIDefinitionObject = $createUIDefintionText | ConvertFrom-Json + #*$HasCreateUIDefinition (indicates if a CreateUIDefinition.json file exists) + $HasCreateUIDefinition = $true + } else { + $HasCreateUIDefinition = $false + $createUiDefinitionFullPath = $null + } + + + #*$FolderFiles (a list of objects of each file in the directory) + $FolderFiles = + @(Get-ChildItem -Path $templateFolder.FullName -Recurse | + Where-Object { -not $_.PSIsContainer } | + ForEach-Object { + + # All FolderFile objects will have the following properties: + $fileInfo = $_ + $fileObject = [Ordered]@{ + Name = $fileInfo.Name #*Name (the name of the file) + Extension = $fileInfo.Extension #*Extension (the file extension) + Bytes = [IO.File]::ReadAllBytes($fileInfo.FullName)#*Bytes (the file content as a byte array) + Text = [IO.File]::ReadAllText($fileInfo.FullName)#*Text (the file content as text) + FullPath = $fileInfo.Fullname#*FullPath (the full path to the file) + } + if ($fileInfo.Extension -eq '.json') { + # If the file is JSON, two additional properties may be present: + #*Object (the file's text, converted from JSON) + $fileObject.Object = $fileObject.Text | ConvertFrom-Json + #*Schema (the value of the $schema property of the JSON object, if present) + $fileObject.schema = $fileObject.Object.'$schema' + } + $fileObject + }) + + if ($isMainTemplate) { # If the file was a main template, + # we set a few more variables: + #*MainTemplatePath (the path to the main template file) + $MainTemplatePath = "$TemplateFullPath" + #*MainTemplateText (the text of the main template file) + $MainTemplateText = [IO.File]::ReadAllText($MainTemplatePath) + #*MainTemplateObject (the main template, converted from JSON) + $MainTemplateObject = $MainTemplateText | ConvertFrom-Json + #*MainTemplateResources (the resources and child resources in the main template) + $MainTemplateResources = Expand-Resource -Resource $MainTemplateObject.resources + #*MainTemplateParameters (a hashtable of parameters in the main template) + $MainTemplateParameters = [Ordered]@{} + foreach ($prop in $MainTemplateObject.parameters.psobject.properties) { + $MainTemplateParameters[$prop.Name] = $prop.Value + } + #*MainTemplateVariables (a hashtable of variables in the main template) + $MainTemplateVariables = [Ordered]@{} + foreach ($prop in $MainTemplateObject.variables.psobject.properties) { + $MainTemplateVariables[$prop.Name] = $prop.Value + } + #*MainTemplateOutputs (a hashtable of outputs in the main template) + $MainTemplateOutputs = [Ordered]@{} + foreach ($prop in $MainTemplateObject.outputs.psobject.properties) { + $MainTemplateOutputs[$prop.Name] = $prop.Value + } + } + + # If we've found a CreateUIDefinition, we'll want to process it first. + if ($HasCreateUIDefinition) { + # Loop over the folder files and get every file that isn't createUIDefinition + $otherFolderFiles = @(foreach ($_ in $FolderFiles) { + if ($_.Name -ne 'CreateUIDefinition.json') { + $_ + } else { + $createUIDefFile = $_ + } + }) + # Then recreate the list with createUIDefinition that the front. + $FolderFiles = @(@($createUIDefFile) + @($otherFolderFiles) -ne $null) + } + + + $out = [Ordered]@{} + foreach ($v in $WellKnownVariables) { + $out[$v] = $ExecutionContext.SessionState.PSVariable.Get($v).Value + } + $out + } +} \ No newline at end of file diff --git a/test/template-tests/Test-AzureRMTemplate.cmd b/test/template-tests/Test-AzureRMTemplate.cmd index 4c6a91d739c3..c2e5e65e3f1c 100644 --- a/test/template-tests/Test-AzureRMTemplate.cmd +++ b/test/template-tests/Test-AzureRMTemplate.cmd @@ -1 +1 @@ -powershell.exe -noprofile -nologo -command ". .\Test-AzureRMTemplate.ps1; Import-Module Pester; Test-AzureRMTemplate %*; if ($error.Count) { exit 1}" +powershell.exe -noprofile -nologo -command "Import-Module Pester, '%~dp0AzRMTester.psd1'; Test-AzureRMTemplate %*; if ($error.Count) { exit 1}" diff --git a/test/template-tests/Test-AzureRMTemplate.ps1 b/test/template-tests/Test-AzureRMTemplate.ps1 index f80b465864b2..20b41c587764 100644 --- a/test/template-tests/Test-AzureRMTemplate.ps1 +++ b/test/template-tests/Test-AzureRMTemplate.ps1 @@ -23,6 +23,12 @@ Each test script has access to a set of well-known variables: * CreateUIDefinitionText (the text of createUIDefintion.json) * CreateUIDefinitionObject ( the createUIDefintion object) * HasCreateUIDefintion (a boolean indicating if the directory includes createUIDefintion.json) +* MainTemplateText (the text of the main template file) +* MainTemplateObject (the main template file, converted from JSON) +* MainTemplateResources (the resources and child resources of the main template) +* MainTemplateParameters (a hashtable containing the parameters found in the main template) +* MainTemplateVariables (a hashtable containing the variables found in the main template) +* MainTemplateOutputs (a hashtable containing the outputs found in the main template) #> [CmdletBinding(DefaultParameterSetName='NearbyTemplate')] @@ -330,115 +336,13 @@ Each test script has access to a set of well-known variables: } } - # Now let's try to resolve the template path. - $resolvedTemplatePath = - # If the template path doesn't appear to be a path to a json file, - if ($TemplatePath -notlike '*.json') { - # see if it looks like a file - if (($templatePath | Split-Path -Leaf) -like '*.*') { - $TemplatePath = $TemplatePath | Split-Path # if it does, reassign template path to it's directory. - } - # Then, go looking beneath that template path - $preferredJsonFile = $TemplatePath | - Get-ChildItem -Filter *.json | - # for a file named azureDeploy.json or mainTemplate.json - Where-Object { 'azureDeploy.json', 'mainTemplate.json' -contains $_.Name } | - Select-Object -First 1 -ExpandProperty Fullname - # If no file was found, write an error and return. - if (-not $preferredJsonFile) { - Write-Error "No azureDeploy.json or mainTemplate.json found beneath $TemplatePath" - return - } - $preferredJsonFile - } else { - $ExecutionContext.SessionState.Path.GetResolvedPSPathFromPSPath($templatePath) - } - - # If we couldn't find a template file, return (an error should have already been written). - if (-not $resolvedTemplatePath) { return } - - - # Next, we want to pre-populate a number of well-known variables. - # These variables will be available to every test case. They are: - $WellKnownVariables = 'TemplateFullPath','TemplateText','TemplateObject', - 'CreateUIDefinitionFullPath','createUIDefintionText','CreateUIDefinitionObject', - 'FolderName', 'HasCreateUIDefinition', 'IsMainTemplate' - foreach ($_ in $WellKnownVariables) { - $ExecutionContext.SessionState.PSVariable.Set($_, $null) - } - - #*$templateFullPath (the full path to the .json file) - $TemplateFullPath = "$resolvedTemplatePath" - #*$TemplateFileName (the name of the azure template file) - $templateFileName = $TemplatePath | Split-Path -Leaf - #*$IsMainTemplate (if the TemplateFileName is named mainTemplate.json) - $isMainTemplate = 'mainTemplate.json', 'azureDeploy.json' -contains $templateFileName - $templateFile = Get-Item -LiteralPath $resolvedTemplatePath - $templateFolder = $templateFile.Directory - #*$FolderName (the name of the root folder containing the template) - $TemplateName = $templateFolder.Name - #*$TemplateText (the text contents of the template file) - $TemplateText = [IO.File]::ReadAllText($resolvedTemplatePath) - #*$TemplateObject (the template text, converted from JSON) - $TemplateObject = $TemplateText | ConvertFrom-Json - #*$CreateUIDefinitionFullPath (the path to CreateUIDefinition.json) - $createUiDefinitionFullPath = Join-Path -childPath 'createUiDefinition.json' -Path $templateFolder - if (Test-Path $createUiDefinitionFullPath) { - #*$CreateUIDefinitionText (the text contents of CreateUIDefinition.json) - $createUIDefintionText = [IO.File]::ReadAllText($createUiDefinitionFullPath) - #*$CreateUIDefinitionObject (the createuidefinition text, converted from json) - $createUIDefinitionObject = $createUIDefintionText | ConvertFrom-Json - #*$HasCreateUIDefinition (indicates if a CreateUIDefinition.json file exists) - $HasCreateUIDefinition = $true - } else { - $HasCreateUIDefinition = $false - } - - - #*$FolderFiles (a list of objects of each file in the directory) - $FolderFiles = - @(Get-ChildItem -Path $templateFolder.FullName -Recurse | - Where-Object { -not $_.PSIsContainer } | - ForEach-Object { - - # All FolderFile objects will have the following properties: - $fileInfo = $_ - $fileObject = [Ordered]@{ - Name = $fileInfo.Name #*Name (the name of the file) - Extension = $fileInfo.Extension #*Extension (the file extension) - Bytes = [IO.File]::ReadAllBytes($fileInfo.FullName)#*Bytes (the file content as a byte array) - Text = [IO.File]::ReadAllText($fileInfo.FullName)#*Text (the file content as text) - FullPath = $fileInfo.Fullname#*FullPath (the full path to the file) - } - if ($fileInfo.Extension -eq '.json') { - # If the file is JSON, two additional properties may be present: - #*Object (the file's text, converted from JSON) - $fileObject.Object = $fileObject.Text | ConvertFrom-Json - #*Schema (the value of the $schema property of the JSON object, if present) - $fileObject.schema = $fileObject.Object.'$schema' - } - $fileObject - }) + $expandedTemplate =Expand-AzureRMTemplate -TemplatePath $templatePath + if (-not $expandedTemplate) { return } + $wellKnownVariables = $expandedTemplate.Keys - if ($isMainTemplate) { - $MainTemplatePath = "$TemplateFullPath" - $MainTemplateText = [IO.File]::ReadAllText($MainTemplatePath) - $MainTemplateObject = $MainTemplateText | ConvertFrom-Json - } - - # If we've found a CreateUIDefinition, we'll want to process it first. - if ($HasCreateUIDefinition) { - # Loop over the folder files and get every file that isn't createUIDefinition - $otherFolderFiles = @(foreach ($_ in $FolderFiles) { - if ($_.Name -ne 'CreateUIDefinition.json') { - $_ - } else { - $createUIDefFile = $_ - } - }) - # Then recreate the list with createUIDefinition that the front. - $FolderFiles = @(@($createUIDefFile) + @($otherFolderFiles) -ne $null) - } + foreach ($kv in $expandedTemplate.GetEnumerator()) { + $ExecutionContext.SessionState.PSVariable.Set($kv.Key, $kv.Value) + } # If a file list was provided, if ($PSBoundParameters.File) { @@ -466,7 +370,4 @@ Each test script has access to a set of well-known variables: describe "Validating Azure Template $TemplateName" ${function:Test-FileList} } } -} - - - +} \ No newline at end of file diff --git a/test/template-tests/Test-AzureRMTemplate.sh b/test/template-tests/Test-AzureRMTemplate.sh index c56fd5318175..2a103995d359 100644 --- a/test/template-tests/Test-AzureRMTemplate.sh +++ b/test/template-tests/Test-AzureRMTemplate.sh @@ -1,2 +1,2 @@ #!/bin/sh -powershell -noprofile -nologo -command ". .\Test-AzureRMTemplate.ps1; Import-Module Pester; Test-AzureRMTemplate $@ ; if (\$error.Count) { exit 1}" +powershell -noprofile -nologo -command "Import-Module Pester, '$(dirname $(readlink -f $0))/AzRMTester.psd1'; Test-AzureRMTemplate $@ ; if (\$error.Count) { exit 1}" \ No newline at end of file diff --git a/test/template-tests/readme.md b/test/template-tests/readme.md new file mode 100644 index 000000000000..ae90127c50e4 --- /dev/null +++ b/test/template-tests/readme.md @@ -0,0 +1,58 @@ +### Running Tests + +Test can be run directly in PowerShell, or run from the command line using a wrapper script. + +You can run the full suite of tests by using Test-AzureRMTemplate.cmd (on Windows) or Test-AzureRMTemplate.sh (on Linux), and passing in the path to a template. + +This will run the full suite of applicable tests on your template. To run a specific group of tests, use: + + + Test-AzureRMTemplate -TemplatePath $thePathToYourTemplate -Test deploymentTemplate + # This will run deployment template tests on all appropriate files + + Test-AzureRMTemplate -TemplatePath $thePathToYourTemplate -Test "Resources Should Have Location" + # This will run the specific test, 'Resources Should have Location', on all appropriate files + + Test-AzureRMTemplate -TemplatePath $thePathToYourTemplate -Test "Resources Should Have Location" -File MyNestedTemplate.json + # This will run the specific test, 'Resources Should have Location', but only on MyNestedTemplate.json + + +#### Running Tests on Linux + +Before you run the tests on Linux, you'll need to [install PowerShell Core](https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell-core-on-linux?view=powershell-6). + +#### Running Tests in PowerShell + +To run the tests in PowerShell, you'll need to import the module. + + Import-Module .\AzRMTester.psd1 # assuming you're in the same directory as .\AzRMTester.psd1 + +You can then test a particular path by using: + + Test-AzureRMTemplate -TemplatePath /yourTemplatePath/ + +### Running Tests from the Command Line + +You can use a BASH file or Command Script to run on the command line. To do so, simply call Test-AzureRMTemplate.sh (or .cmd). This will pass the arguments down to the PowerShell script. To get help, pass a -? + + +### Inspecting Test Results + +By default, tests are run in Pester, which displays output in a colorized format, but does not return individual failures to the pipeline. +To inspect the results, use the -NoPester flag and assign the results to a variable +(you must be running in PowerShell): + + $TestResults = Test-AzureRMTemplate -TemplatePath /yourTemplatePath/ -NoPester + +To see failures, use Where-Object to filter the results + + $TestFailures = $TestResults | Where-Object { -not $_.Passed } + +Many test failures will return a TargetObject, for instance, the exact parameter within a template that had an issue. To extract out target objects from an error, use: + + $FailureTargetObjects = $TestFailures | + Select-Object -ExpandProperty Errors | + Select-Object -ExpandProperty TargetObject + + +Please note that not all test cases will return a target object. If no target object is returned, the target should be clear from the error message. \ No newline at end of file diff --git a/test/template-tests/testcases/deploymentTemplate/Min-And-Max-Value-Are-Numbers.test.ps1 b/test/template-tests/testcases/deploymentTemplate/Min-And-Max-Value-Are-Numbers.test.ps1 index 8aaa5d36fbff..0e2d02888c88 100644 --- a/test/template-tests/testcases/deploymentTemplate/Min-And-Max-Value-Are-Numbers.test.ps1 +++ b/test/template-tests/testcases/deploymentTemplate/Min-And-Max-Value-Are-Numbers.test.ps1 @@ -31,6 +31,4 @@ foreach ($parameter in $templateObject.parameters) { if ($max -ne $null -and $min -eq $null){ Write-Error "$($Parameter.Name) missing min value" -ErrorId Parameter.Missing.Min -TargetObject $parameter } -} - - +} \ No newline at end of file diff --git a/test/template-tests/testcases/deploymentTemplate/Resources-Should-Have-Location.test.ps1 b/test/template-tests/testcases/deploymentTemplate/Resources-Should-Have-Location.test.ps1 index ccc5b70ca04e..8d02308ebd9d 100644 --- a/test/template-tests/testcases/deploymentTemplate/Resources-Should-Have-Location.test.ps1 +++ b/test/template-tests/testcases/deploymentTemplate/Resources-Should-Have-Location.test.ps1 @@ -1,17 +1,15 @@ param( [Parameter(Mandatory=$true,Position=0)] [PSObject] -$TemplateObject +$MainTemplateResources ) -foreach ($resource in $templateObject.resources) { - if ($resource.Location) { - $location = "$($resource.location)".Trim() - if ($location -notmatch '^\[.*\]$' -and $location -ne 'global') { - Write-Error "Resource $($resource.Name) Location must be an expression or 'global'" -TargetObject $resource +foreach ($mtr in $MainTemplateResources) { + foreach ($resource in @(@($mtr) + $mtr.ParentResources)) { + if ($resource.Location) { + $location = "$($resource.location)".Trim() + if ($location -notmatch '^\[.*\]$' -and $location -ne 'global') { + Write-Error "Resource $($resource.Name) Location must be an expression or 'global'" -TargetObject $resource + } } } -} - - - - +} \ No newline at end of file diff --git a/test/template-tests/testcases/deploymentTemplate/Secure-String-Parameters-Cannot-Have-Default.test.ps1 b/test/template-tests/testcases/deploymentTemplate/Secure-String-Parameters-Cannot-Have-Default.test.ps1 index 8c001de0eced..f98361b2469b 100644 --- a/test/template-tests/testcases/deploymentTemplate/Secure-String-Parameters-Cannot-Have-Default.test.ps1 +++ b/test/template-tests/testcases/deploymentTemplate/Secure-String-Parameters-Cannot-Have-Default.test.ps1 @@ -7,7 +7,7 @@ foreach ($parameterProp in $templateObject.parameters.psobject.properties) { $parameter = $parameterProp.Value $name = $parameterProp.Name if ($parameter.Type -eq 'securestring' -and - $parameter.defaultValue) # This will only return true when defaultvalue is not null or blank. + $parameter.defaultValue) # Will return true when defaultvalue is not null or blank (blank values are OK). { Write-Error -Message "Parameter $name is a SecureString, and must not have a default value." ` -ErrorId SecureString.Must.Not.Have.Default -TargetObject $parameter From 2e78eb595acb809aff5e4547caf57ac46f0c28c5 Mon Sep 17 00:00:00 2001 From: Brian Moore Date: Mon, 18 Feb 2019 18:12:48 -0800 Subject: [PATCH 53/66] added missing params --- 101-key-vault-create/azuredeploy.parameters.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/101-key-vault-create/azuredeploy.parameters.json b/101-key-vault-create/azuredeploy.parameters.json index 61209ca862f1..825ac62fd47c 100644 --- a/101-key-vault-create/azuredeploy.parameters.json +++ b/101-key-vault-create/azuredeploy.parameters.json @@ -7,6 +7,12 @@ }, "objectId": { "value": "GEN-AZURE_OBJECT_ID" + }, + "secretName": { + "value": "GEN-UNIQUE" + }, + "secretValue": { + "value": "GEN-UNIQUE" } } -} \ No newline at end of file +} From ecb414c0b3cb252c3dafeba5e7823c6b8a3b3064 Mon Sep 17 00:00:00 2001 From: Brian Moore Date: Mon, 18 Feb 2019 18:19:55 -0800 Subject: [PATCH 54/66] fix param --- 101-key-vault-create/azuredeploy.parameters.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/101-key-vault-create/azuredeploy.parameters.json b/101-key-vault-create/azuredeploy.parameters.json index 825ac62fd47c..6bd65b0155f1 100644 --- a/101-key-vault-create/azuredeploy.parameters.json +++ b/101-key-vault-create/azuredeploy.parameters.json @@ -6,7 +6,7 @@ "value": "GEN-UNIQUE" }, "objectId": { - "value": "GEN-AZURE_OBJECT_ID" + "value": "GEN-AZURE_CLIENT_ID" }, "secretName": { "value": "GEN-UNIQUE" From 79b5e3f3603e1ba9182a593c58bae059a25c46c2 Mon Sep 17 00:00:00 2001 From: Brian Moore Date: Mon, 18 Feb 2019 18:20:18 -0800 Subject: [PATCH 55/66] fix param --- 201-key-vault-secret-create/azuredeploy.parameters.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/201-key-vault-secret-create/azuredeploy.parameters.json b/201-key-vault-secret-create/azuredeploy.parameters.json index c5ed17eb26f8..d181ca3b6d95 100644 --- a/201-key-vault-secret-create/azuredeploy.parameters.json +++ b/201-key-vault-secret-create/azuredeploy.parameters.json @@ -6,7 +6,7 @@ "value": "GEN-UNIQUE" }, "objectId": { - "value": "GEN-AZURE_OBJECT_ID" + "value": "GEN-AZURE_CLIENT_ID" }, "secretsObject": { "value": { @@ -23,4 +23,4 @@ } } } -} \ No newline at end of file +} From 0bf27968ec6b09ebf35cd1630fec3205f4912f76 Mon Sep 17 00:00:00 2001 From: StartAutomating Date: Mon, 18 Feb 2019 18:24:13 -0800 Subject: [PATCH 56/66] Renaming readme.md to README.md --- test/template-tests/{readme.md => README.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test/template-tests/{readme.md => README.md} (100%) diff --git a/test/template-tests/readme.md b/test/template-tests/README.md similarity index 100% rename from test/template-tests/readme.md rename to test/template-tests/README.md From 42f1ec7728860df80ac0efe6605c5ab963a22391 Mon Sep 17 00:00:00 2001 From: Brian Moore Date: Mon, 18 Feb 2019 18:25:31 -0800 Subject: [PATCH 57/66] fix param --- 101-key-vault-create/azuredeploy.parameters.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/101-key-vault-create/azuredeploy.parameters.json b/101-key-vault-create/azuredeploy.parameters.json index 6bd65b0155f1..711c11a0e262 100644 --- a/101-key-vault-create/azuredeploy.parameters.json +++ b/101-key-vault-create/azuredeploy.parameters.json @@ -6,7 +6,7 @@ "value": "GEN-UNIQUE" }, "objectId": { - "value": "GEN-AZURE_CLIENT_ID" + "value": "GEN-AZUREAD-OBJECTID" }, "secretName": { "value": "GEN-UNIQUE" From 338480ce6eaec3da88f91d5a729f58d86e72866c Mon Sep 17 00:00:00 2001 From: Brian Moore Date: Mon, 18 Feb 2019 18:25:54 -0800 Subject: [PATCH 58/66] fix param --- 201-key-vault-secret-create/azuredeploy.parameters.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/201-key-vault-secret-create/azuredeploy.parameters.json b/201-key-vault-secret-create/azuredeploy.parameters.json index d181ca3b6d95..45477c8a4450 100644 --- a/201-key-vault-secret-create/azuredeploy.parameters.json +++ b/201-key-vault-secret-create/azuredeploy.parameters.json @@ -6,7 +6,7 @@ "value": "GEN-UNIQUE" }, "objectId": { - "value": "GEN-AZURE_CLIENT_ID" + "value": "GEN-AZUREAD-OBJECTID" }, "secretsObject": { "value": { From bfcfc471cb6ea4684f6b6d34ce21539be0b23fe8 Mon Sep 17 00:00:00 2001 From: StartAutomating Date: Mon, 18 Feb 2019 19:03:18 -0800 Subject: [PATCH 59/66] Expanding Location Test to Cover bad uses of Location in other Parameters --- .../Location-Should-Not-Be-Hardcoded.test.ps1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/template-tests/testcases/deploymentTemplate/Location-Should-Not-Be-Hardcoded.test.ps1 b/test/template-tests/testcases/deploymentTemplate/Location-Should-Not-Be-Hardcoded.test.ps1 index 21080b6bfc15..a73c0ed67378 100644 --- a/test/template-tests/testcases/deploymentTemplate/Location-Should-Not-Be-Hardcoded.test.ps1 +++ b/test/template-tests/testcases/deploymentTemplate/Location-Should-Not-Be-Hardcoded.test.ps1 @@ -9,8 +9,8 @@ [switch]$IsMainTemplate ) $TemplateObjectCopy = $templateText | ConvertFrom-Json -$TemplateObjectCopy.psobject.properties.remove('parameters') -$TemplateWithoutParameters = $TemplateObjectCopy | +$TemplateObjectCopy.parameters.psobject.properties.remove('location') +$TemplateWithoutLocationParameter = $TemplateObjectCopy | ConvertTo-Json -Depth 10 @@ -22,6 +22,6 @@ if ($locationParameter -and Write-Error "Location parameter must not be hardcoded. The default value should be [resourceGroup().location]." -ErrorId Location.Parameter.Hardcoded -TargetObject $parameter } -if ($TemplateWithoutParameters -like '*resourceGroup().location*') { +if ($TemplateWithoutLocationParameter -like '*resourceGroup().location*') { Write-Error "$TemplateFileName must use the location parameter, not resourceGroup().location (except when used as a default value)" -ErrorId Location.Parameter.Should.Be.Used -TargetObject $parameter } \ No newline at end of file From 441a89461807200d802c4492f2e07902c335f557 Mon Sep 17 00:00:00 2001 From: Nerya Cohen Date: Tue, 19 Feb 2019 10:00:30 +0200 Subject: [PATCH 60/66] fix readme links --- 201-storage-advanced-threat-protection-create/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/201-storage-advanced-threat-protection-create/README.md b/201-storage-advanced-threat-protection-create/README.md index a5703597362d..d67b55873bb1 100644 --- a/201-storage-advanced-threat-protection-create/README.md +++ b/201-storage-advanced-threat-protection-create/README.md @@ -1,9 +1,9 @@ # Deploy an Azure Storage Account with Advanced Threat Protection enabled - + - + From bf7f2af01c921716e04e0a9afb74cc57089fc012 Mon Sep 17 00:00:00 2001 From: Yuanheng Yang Date: Thu, 21 Feb 2019 10:16:59 +0800 Subject: [PATCH 61/66] Update SCCM TP build download link Update SCCM TP build download link --- sccm-technicalpreview/scripts/InstallSCCM.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sccm-technicalpreview/scripts/InstallSCCM.ps1 b/sccm-technicalpreview/scripts/InstallSCCM.ps1 index 23bb4ba16b73..cceda5db2309 100644 --- a/sccm-technicalpreview/scripts/InstallSCCM.ps1 +++ b/sccm-technicalpreview/scripts/InstallSCCM.ps1 @@ -40,7 +40,7 @@ if(Test-Path $cmpath) } "[$(Get-Date -format HH:mm:ss)] Copying SCCM installation source..." | Out-File -Append $logpath -$cmurl = "http://download.microsoft.com/download/D/8/E/D8E795CE-44D7-40B7-9067-D3D1313865E5/SC_Configmgr_SCEP_TechPreview1810.exe" +$cmurl = "https://go.microsoft.com/fwlink/?linkid=2077212&clcid=0x409" Invoke-WebRequest -Uri $cmurl -OutFile $cmpath if(Test-Path $cmsourcepath) From 86a5d7a7093cb49398c2cfe6de070b66a4f95462 Mon Sep 17 00:00:00 2001 From: Yuanheng Yang Date: Thu, 21 Feb 2019 10:26:50 +0800 Subject: [PATCH 62/66] Change CM TP build download link Change CM TP build download link --- sccm-technicalpreview/scripts/InstallSCCM.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sccm-technicalpreview/scripts/InstallSCCM.ps1 b/sccm-technicalpreview/scripts/InstallSCCM.ps1 index cceda5db2309..82a7cfa6bbc8 100644 --- a/sccm-technicalpreview/scripts/InstallSCCM.ps1 +++ b/sccm-technicalpreview/scripts/InstallSCCM.ps1 @@ -40,7 +40,7 @@ if(Test-Path $cmpath) } "[$(Get-Date -format HH:mm:ss)] Copying SCCM installation source..." | Out-File -Append $logpath -$cmurl = "https://go.microsoft.com/fwlink/?linkid=2077212&clcid=0x409" +$cmurl = "https://download.microsoft.com/download/D/8/E/D8E795CE-44D7-40B7-9067-D3D1313865E5/SC_Configmgr_SCEP_TechPreview1902.exe" Invoke-WebRequest -Uri $cmurl -OutFile $cmpath if(Test-Path $cmsourcepath) From 88ff4aa96ebb8346ec5b306e8ee8918989e843c7 Mon Sep 17 00:00:00 2001 From: Yizhong Wu Date: Thu, 21 Feb 2019 12:53:32 +0800 Subject: [PATCH 63/66] Revert "Change CM TP build download link" This reverts commit 86a5d7a7093cb49398c2cfe6de070b66a4f95462. --- sccm-technicalpreview/scripts/InstallSCCM.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sccm-technicalpreview/scripts/InstallSCCM.ps1 b/sccm-technicalpreview/scripts/InstallSCCM.ps1 index 82a7cfa6bbc8..cceda5db2309 100644 --- a/sccm-technicalpreview/scripts/InstallSCCM.ps1 +++ b/sccm-technicalpreview/scripts/InstallSCCM.ps1 @@ -40,7 +40,7 @@ if(Test-Path $cmpath) } "[$(Get-Date -format HH:mm:ss)] Copying SCCM installation source..." | Out-File -Append $logpath -$cmurl = "https://download.microsoft.com/download/D/8/E/D8E795CE-44D7-40B7-9067-D3D1313865E5/SC_Configmgr_SCEP_TechPreview1902.exe" +$cmurl = "https://go.microsoft.com/fwlink/?linkid=2077212&clcid=0x409" Invoke-WebRequest -Uri $cmurl -OutFile $cmpath if(Test-Path $cmsourcepath) From 6ed25632bf01e659609f4d60977ba561bc00c9ce Mon Sep 17 00:00:00 2001 From: Marlon Singleton Date: Thu, 21 Feb 2019 19:23:14 +0300 Subject: [PATCH 64/66] removed: failing special placeholder --- 101-batchaccount-with-storage/azuredeploy.parameters.json | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/101-batchaccount-with-storage/azuredeploy.parameters.json b/101-batchaccount-with-storage/azuredeploy.parameters.json index cedcacd179df..55c1a478b8b0 100644 --- a/101-batchaccount-with-storage/azuredeploy.parameters.json +++ b/101-batchaccount-with-storage/azuredeploy.parameters.json @@ -1,9 +1,5 @@ { "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", - "parameters": { - "batchAccountName": { - "value": "GEN-UNIQUE-12" - } - } + "parameters": { } } From d326f02de0f06d66807c5c57ef12a32caeb45e8f Mon Sep 17 00:00:00 2001 From: Marlon Singleton Date: Thu, 21 Feb 2019 19:36:10 +0300 Subject: [PATCH 65/66] updated: batch account to uniquestring --- 101-batchaccount-with-storage/azuredeploy.json | 1 + 1 file changed, 1 insertion(+) diff --git a/101-batchaccount-with-storage/azuredeploy.json b/101-batchaccount-with-storage/azuredeploy.json index 53ddad3bd05d..43700749d9f6 100644 --- a/101-batchaccount-with-storage/azuredeploy.json +++ b/101-batchaccount-with-storage/azuredeploy.json @@ -4,6 +4,7 @@ "parameters": { "batchAccountName": { "type": "string", + "defaultValue": "[concat(toLower(uniqueString(resourceGroup().id)), 'batch')]" "metadata": { "description": "Batch Account Name" } From 35c5621fdf8790c433cbc3748c6bdcae63656e67 Mon Sep 17 00:00:00 2001 From: Marlon Singleton Date: Thu, 21 Feb 2019 19:37:15 +0300 Subject: [PATCH 66/66] replaced: missing comma --- 101-batchaccount-with-storage/azuredeploy.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/101-batchaccount-with-storage/azuredeploy.json b/101-batchaccount-with-storage/azuredeploy.json index 43700749d9f6..841260979c89 100644 --- a/101-batchaccount-with-storage/azuredeploy.json +++ b/101-batchaccount-with-storage/azuredeploy.json @@ -4,7 +4,7 @@ "parameters": { "batchAccountName": { "type": "string", - "defaultValue": "[concat(toLower(uniqueString(resourceGroup().id)), 'batch')]" + "defaultValue": "[concat(toLower(uniqueString(resourceGroup().id)), 'batch')]", "metadata": { "description": "Batch Account Name" }