Skip to content

Instantly share code, notes, and snippets.

@omiossec
Created June 18, 2020 05:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save omiossec/5c579305fe7dc069a321bcc063b6108a to your computer and use it in GitHub Desktop.
Save omiossec/5c579305fe7dc069a321bcc063b6108a to your computer and use it in GitHub Desktop.
trigger:
- master
resources:
- repo: self
variables:
resourceGroupName: 'demo-whatif'
templateFolder: "arm"
templateFile: "demo-arm.json"
templateParameterFile: "demo-arm.params.json"
organisationName: "AZ-OMDEMO"
projectName: "what-if"
pool:
vmImage: 'ubuntu-latest'
steps:
- task: PowerShell@2
displayName: 'Update Az Resources Module'
inputs:
targetType: 'inline'
script: |
Install-Module Az.Resources -RequiredVersion 1.12.1-preview -AllowPrerelease -Force -Scope CurrentUser
#- task: PowerShell@2
# displayName: 'Import Az Resources Module'
# inputs:
# targetType: 'inline'
## script: |
# Import-Module Az.Resources -RequiredVersion 1.12.1
- task: AzurePowerShell@5
displayName: 'Get Az Resources What-if Result'
env:
PATSECRET: $(patSecret)
inputs:
azureSubscription: AzureDemo
scriptType: filePath
scriptPath: $(Build.SourcesDirectory)/testwhatif.ps1
azurePowerShellVersion: 'LatestVersion'
- task: CopyFiles@2
inputs:
contents: 'arm/**'
targetFolder: $(Build.ArtifactStagingDirectory)
- task: PublishBuildArtifacts@1
inputs:
pathToPublish: $(Build.ArtifactStagingDirectory)
artifactName: ArmFiles
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"nsgName": {
"type": "string",
"defaultValue": "DefaultNSG"
},
"vnetName": {
"type": "string",
"defaultValue": "firstVnet"
},
"vnetPrefix": {
"type": "string",
"defaultValue": "192.168.10.0/24"
},
"subnetName": {
"type": "string",
"defaultValue": "firstSubnet"
},
"subnetPrefix": {
"type": "string",
"defaultValue": "192.168.10.0/25"
}
},
"variables": {},
"resources": [
{
"name": "[parameters('nsgName')]",
"type": "Microsoft.Network/networkSecurityGroups",
"apiVersion": "2019-11-01",
"location": "[resourceGroup().location]",
"properties": {
"securityRules": [
]
}
},
{
"name": "[parameters('vnetName')]",
"type": "Microsoft.Network/virtualNetworks",
"apiVersion": "2019-11-01",
"location": "[resourceGroup().location]",
"dependsOn": [
"[resourceId('Microsoft.Network/networkSecurityGroups', parameters('nsgName'))]"
],
"properties": {
"addressSpace": {
"addressPrefixes": [
"[parameters('vnetPrefix')]"
]
},
"subnets": [
{
"name": "[parameters('subnetName')]",
"properties": {
"addressPrefix": "[parameters('subnetPrefix')]",
"networkSecurityGroup": {
"ID": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('nsgName'))]"
}
}
}
]
}
}
],
"outputs": {}
}
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"nsgName": {
"value": "nsg1"
},
"vnetName": {
"value": "first2-Vnet"
},
"vnetPrefix": {
"value": "10.0.0.0/8"
},
"subnetName": {
"value": "first-subnet"
},
"subnetPrefix": {
"value": "10.0.8.0/24"
}
}
}
$ErrorView = 'NormalView'
$SourceFolder = [Environment]::GetEnvironmentVariable('BUILD_SOURCESDIRECTORY')
$TargetResourceGroupName=[Environment]::GetEnvironmentVariable('RESOURCEGROUPNAME')
$ArmTemplateFolder=[Environment]::GetEnvironmentVariable('TEMPLATEFOLDER')
$ArmTemplateFile=[Environment]::GetEnvironmentVariable('TEMPLATEFILE')
$ArmTemplateParametersFile=[Environment]::GetEnvironmentVariable('TEMPLATEPARAMETERFILE')
$AzureDevOpsOrganisation = [Environment]::GetEnvironmentVariable('ORGANISATIONNAME')
$AzureDevOpsProjedtName = [Environment]::GetEnvironmentVariable('PROJECTNAME')
$PipelineBuildID = [Environment]::GetEnvironmentVariable('BUILD_BUILDID')
$AzureDevOpsPAT = [Environment]::GetEnvironmentVariable('PATSECRET')
$ArmTemplateFilePath = Join-Path -Path $ArmTemplateFolder -ChildPath $ArmTemplateFile
$ArmTemplateParametersFilePath = Join-Path -Path $ArmTemplateFolder -ChildPath $ArmTemplateParametersFile
$TaskText = ""
$UriPost = "https://dev.azure.com/$($AzureDevOpsOrganisation)/$($AzureDevOpsProjedtName)/_apis/wit/workitems/`$task?api-version=5.1" 
if (!(test-path -Path $ArmTemplateFolder -ErrorAction SilentlyContinue)) {
Throw "Template folder doesn't exist"
Exit 1
}
if (!(test-path -Path $ArmTemplateFilePath -ErrorAction SilentlyContinue)) {
Throw "Template file doesn't exist"
Exit 1
}
if (!(test-path -Path $ArmTemplateParametersFilePath -ErrorAction SilentlyContinue)) {
Throw "Template parameter file doesn't exist"
Exit 1
}
$whatifResultObject = Get-AzResourceGroupDeploymentWhatIfResult -TemplateFile $ArmTemplateFilePath -TemplateParameterFile $ArmTemplateParametersFilePath -ResourceGroupName $TargetResourceGroupName -ResultFormat FullResourcePayloads
foreach ($change in $whatifResultObject.Changes) {
switch ($change.ChangeType) {
"NoChange" {
$TextColor = "Green"
$Text = "Resource all ready deployed in the same was as the template"
}
"Modify" {
$TextColor = "Magenta"
$Text = "Resource will be Updated by the template"
}
"Create" {
$TextColor = "Cyan"
$Text = "Resource does not exist in the resource group and will be deployed"
}
"Ignore" {
$TextColor = "Green"
$Text = "Resource exist in Azure but not in the template, no change"
}
"Delete" {
$TextColor = "Red"
$Text = "Resource exist in Azure but not in the template, Resource will be deleted"
}
}
write-host "$($change.ChangeType) $($change.RelativeResourceId)" -ForegroundColor $TextColor
write-host $Text -ForegroundColor $TextColor
write-host " `r`n"
if (($change.ChangeType -eq "Modify") -OR ($change.ChangeType -eq "Delete")) {
$TaskText += $text
$TaskText += "`r`n"
$TaskText += "$($change.ChangeType) $($change.RelativeResourceId)"
$TaskText += "`r`n"
}
}
# create an issue
if (($whatifResultObject.Changes.ChangeType -contains "Modify") -OR ($whatifResultObject.Changes.ChangeType -contains "Delete")) {
$taskSubject = "ARM Template need a review in Build $($PipelineBuildID)"
$Payload = @(
@{
"op" = "add"
"path" = "/fields/System.Title"
"from" = $null
"value" = $taskSubject
}
@{
"op" = "add"
"path" = "/fields/System.Description"
"from" = $null
"value" = $TaskText
}
)
$JsonPayLoad = $Payload | ConvertTo-Json -Depth 3
$AzureDevOpsAuthenicationHeader = @{
"Authorization" = ('Basic {0}' -f [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($AzureDevOpsPAT)")))
}
Invoke-RestMethod -Uri $UriPost -Method PATCH -Headers $AzureDevOpsAuthenicationHeader  -Body $JsonPayLoad -ContentType "application/json-patch+json"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment