Framework/Helpers/ResourceHelper.ps1
using namespace Microsoft.WindowsAzure.Storage.Blob using namespace Microsoft.Azure.Commands.Management.Storage.Models using namespace Microsoft.Azure.Management.Storage.Models using namespace Microsoft.WindowsAzure.Commands.Common.Storage.ResourceModel Set-StrictMode -Version Latest class ResourceGroupHelper: AzSKRoot { [string] $ResourceGroupName; [string] $ResourceGroupLocation = "EastUS2"; [PSObject] $ResourceGroup; ResourceGroupHelper([string] $subscriptionId, [string] $resourceGroupName): Base($subscriptionId) { $this.CreateInstance($resourceGroupName, "EastUS2"); } ResourceGroupHelper([string] $subscriptionId, [string] $resourceGroupName, [string] $resourceGroupLocation): Base($subscriptionId) { $this.CreateInstance($resourceGroupName, $resourceGroupLocation); } hidden [void] CreateInstance([string] $resourceGroupName, [string] $resourceGroupLocation) { if([string]::IsNullOrWhiteSpace($resourceGroupName)) { throw [System.ArgumentException] ("The argument 'resourceGroupName' is null or empty"); } $this.ResourceGroupName = $resourceGroupName; if(-not [string]::IsNullOrWhiteSpace($resourceGroupLocation)) { $this.ResourceGroupLocation = $resourceGroupLocation; } } [void] CreateResourceGroupIfNotExists() { if(-not $this.ResourceGroup) { $rg = Get-AzResourceGroup -Name $this.ResourceGroupName -ErrorAction ignore #$rg = Get-AzResourceGroup | Where-Object { $_.ResourceGroupName -eq $this.ResourceGroupName } | Select-Object -First 1 if(-not $rg) { $this.PublishCustomMessage("Creating resource group [$($this.ResourceGroupName)]..."); $result = [Helpers]::NewAzSKResourceGroup($this.ResourceGroupName, $this.ResourceGroupLocation, ""); if($result) { $this.ResourceGroup = $result; $this.PublishCustomMessage("Successfully created resource group [$($this.ResourceGroupName)]", [MessageType]::Update); } else { throw ([SuppressedException]::new("Error occured while creating resource group [$($this.ResourceGroupName)]", [SuppressedExceptionType]::Generic)) } } else { $this.ResourceGroup = $rg; } } } } class StorageHelper: ResourceGroupHelper { hidden [PSStorageAccount] $StorageAccount = $null; [string] $StorageAccountName; [Kind] $StorageKind; [string] $AccessKey; [int] $HaveWritePermissions = 0; [int] $retryCount = 3; [int] $sleepIntervalInSecs = 10; static [StorageHelper] $AzSKStorageHelperInstance = $null hidden [string] $ResourceType = "Microsoft.Storage/storageAccounts"; StorageHelper([string] $subscriptionId, [string] $resourceGroupName, [string] $resourceGroupLocation, [string] $storageAccountName): Base($subscriptionId, $resourceGroupName, $resourceGroupLocation) { if([string]::IsNullOrWhiteSpace($storageAccountName)) { throw [System.ArgumentException] ("The argument 'storageAccountName' is null or empty"); } $this.StorageAccountName = $storageAccountName; $this.StorageKind = [Constants]::NewStorageKind; } StorageHelper([string] $subscriptionId, [string] $resourceGroupName, [string] $resourceGroupLocation, [string] $storageAccountName, [Kind] $storageKind): Base($subscriptionId, $resourceGroupName, $resourceGroupLocation) { if([string]::IsNullOrWhiteSpace($storageAccountName)) { throw [System.ArgumentException] ("The argument 'storageAccountName' is null or empty"); } $this.StorageAccountName = $storageAccountName; $this.StorageKind = $storageKind } [void] UpdateCurrentInstance([StorageHelper] $AzSKStorageHelperInstance) { $this.AccessKey = $AzSKStorageHelperInstance.AccessKey $this.HaveWritePermissions = $AzSKStorageHelperInstance.HaveWritePermissions } [void] CreateStorageIfNotExists() { if(-not $this.StorageAccount) { $isAzSKStorage = $false; $this.CreateResourceGroupIfNotExists(); if($this.ResourceGroupName -eq [ConfigurationManager]::GetAzSKConfigData().AzSKRGName -and $this.StorageAccountName -like "$([Constants]::StorageAccountPreName)*") { if($null -ne [StorageHelper]::AzSKStorageHelperInstance) { $this.UpdateCurrentInstance([StorageHelper]::AzSKStorageHelperInstance); return; } else { $isAzSKStorage = $true } } $existingResources = Get-AzResource -ResourceGroupName $this.ResourceGroupName -ResourceType $this.ResourceType # Assuming 1 storage account is needed on Resource group if(($existingResources | Measure-Object).Count -gt 1) { throw ([SuppressedException]::new(("Multiple storage accounts found in resource group: [$($this.ResourceGroupName)]. This is not expected. Please contact support team."), [SuppressedExceptionType]::InvalidOperation)) } elseif(($existingResources | Measure-Object).Count -eq 0) { $this.PublishCustomMessage("Creating a storage account: ["+ $this.StorageAccountName +"]..."); $newStorage = [Helpers]::NewAzskCompliantStorage($this.StorageAccountName, $this.StorageKind, $this.ResourceGroupName, $this.ResourceGroupLocation); if($newStorage) { $this.PublishCustomMessage("Successfully created storage account [$($this.StorageAccountName)]", [MessageType]::Update); } else { throw ([SuppressedException]::new("Failed to create storage account [$($this.StorageAccountName)]", [SuppressedExceptionType]::Generic)) } } elseif(($existingResources | Measure-Object).Count -eq 1) { $this.StorageAccountName = $existingResources.Name; } # Fetch the Storage account context $this.StorageAccount = Get-AzStorageAccount -ResourceGroupName $this.ResourceGroupName -Name $this.StorageAccountName -ErrorAction Ignore if(-not ($this.StorageAccount -and $this.StorageAccount.Context)) { $this.StorageAccount = $null; throw ([SuppressedException]::new("Unable to fetch the storage account [$($this.StorageAccountName)]", [SuppressedExceptionType]::InvalidOperation)) } #fetch access key $keys = Get-AzStorageAccountKey -ResourceGroupName $this.ResourceGroupName -Name $this.StorageAccountName -ErrorAction SilentlyContinue if($keys) { $this.AccessKey = $keys[0].Value; } #precompute storage access permissions for the current scan account $this.ComputePermissions(); if($isAzSKStorage) { [StorageHelper]::AzSKStorageHelperInstance = $this } } } [AzureStorageContainer] CreateStorageContainerIfNotExists([string] $containerName) { return $this.CreateStorageContainerIfNotExists($containerName, [BlobContainerPublicAccessType]::Off); } [AzureStorageContainer] CreateStorageContainerIfNotExists([string] $containerName, [BlobContainerPublicAccessType] $accessType) { if([string]::IsNullOrWhiteSpace($containerName)) { throw [System.ArgumentException] ("The argument 'containerName' is null or empty"); } $this.CreateStorageIfNotExists(); $container = Get-AzStorageContainer -Context $this.StorageAccount.Context -Name $containerName -ErrorAction Ignore if(($container| Measure-Object).Count -eq 0) { $this.PublishCustomMessage("Creating storage container [$containerName]..."); $container = New-AzStorageContainer -Context $this.StorageAccount.Context -Name $containerName -Permission $accessType if($container) { $this.PublishCustomMessage("Successfully created storage container [$containerName]", [MessageType]::Update); } } if(($container| Measure-Object).Count -eq 0) { throw ([SuppressedException]::new("Unable to fetch/create the container [$containerName] under storage account [$($this.StorageAccountName)]", [SuppressedExceptionType]::InvalidOperation)) } return $container; } [AzureStorageTable] CreateTableIfNotExists([string] $tableName) { if([string]::IsNullOrWhiteSpace($tableName)) { throw [System.ArgumentException] ("The argument 'tableName' is null or empty"); } $this.CreateStorageIfNotExists(); $table = Get-AzStorageTable -Context $this.StorageAccount.Context -Name $tableName -ErrorAction Ignore if(($table| Measure-Object).Count -eq 0) { $this.PublishCustomMessage("Creating table [$tableName]..."); $table = New-AzStorageTable -Name $tableName -Context $this.StorageAccount.Context if($table) { $this.PublishCustomMessage("Successfully created table: [$tableName] in storage: [$($this.StorageAccountName)]", [MessageType]::Update); } } if(($table| Measure-Object).Count -eq 0) { throw ([SuppressedException]::new("Unable to fetch/create the table [$tableName] under storage account [$($this.StorageAccountName)]", [SuppressedExceptionType]::InvalidOperation)) } return $table; } hidden [void] ComputePermissions() { if($null -eq $this.StorageAccount) { #No storage account => no permissions at all $this.HaveWritePermissions = 0 return; } $this.HaveWritePermissions = 0 #this is local constant with dummy container name to check for storage permissions $writeTestContainerName = "wt" + $(get-date).ToUniversalTime().ToString("yyyyMMddHHmmss"); #see if user can create the test container in the storage account. If yes then user have both RW permissions. try { New-AzStorageContainer -Context $this.StorageAccount.Context -Name $writeTestContainerName -ErrorAction Stop $this.HaveWritePermissions = 1 Remove-AzStorageContainer -Name $writeTestContainerName -Context $this.StorageAccount.Context -ErrorAction SilentlyContinue -Force } catch { $this.HaveWritePermissions = 0 } } [AzureStorageContainer] UploadFilesToBlob([string] $containerName, [string] $blobPath, [System.IO.FileInfo[]] $filesToUpload, [bool] $overwrite) { return $this.UploadFilesToBlob([string] $containerName, [BlobContainerPublicAccessType]::Off, $blobPath, $filesToUpload, $overwrite); } [AzureStorageContainer] UploadFilesToBlob([string] $containerName, [string] $blobPath, [System.IO.FileInfo[]] $filesToUpload) { return $this.UploadFilesToBlob([string] $containerName, [BlobContainerPublicAccessType]::Off, $blobPath, $filesToUpload); } [AzureStorageContainer] UploadFilesToBlob([string] $containerName, [BlobContainerPublicAccessType] $accessType, [string] $blobPath, [System.IO.FileInfo[]] $filesToUpload) { return $this.UploadFilesToBlob([string] $containerName, $accessType, $blobPath, $filesToUpload, $true); } [AzureStorageContainer] UploadFilesToBlob([string] $containerName, [BlobContainerPublicAccessType] $accessType, [string] $blobPath, [System.IO.FileInfo[]] $filesToUpload, [bool] $overwrite) { $result = $null; if($filesToUpload -and $filesToUpload.Count -ne 0) { $result = $this.CreateStorageContainerIfNotExists($containerName, $accessType); $this.PublishCustomMessage("Uploading [$($filesToUpload.Count)] file(s) to container [$containerName]..."); $filesToUpload | ForEach-Object { $blobName = $_.Name; if(-not [string]::IsNullOrWhiteSpace($blobPath)) { $blobName = $blobPath + "/" + $blobName; } if($_.Extension.ToLower() -ne '.zip') { [Helpers]::RemoveUtf8BOM($_); } $loopValue = $this.retryCount; $sleepValue = $this.sleepIntervalInSecs; while($loopValue -gt 0) { $loopValue = $loopValue - 1; try { if($overwrite) { Set-AzStorageBlobContent -Blob $blobName -Container $containerName -File $_.FullName -Context $this.StorageAccount.Context -Force | Out-Null } else { $currentBlob = Get-AzStorageBlob -Blob $blobName -Container $containerName -Context $this.StorageAccount.Context -ErrorAction Ignore if(-not $currentBlob) { Set-AzStorageBlobContent -Blob $blobName -Container $containerName -File $_.FullName -Context $this.StorageAccount.Context | Out-Null } } $loopValue = 0; } catch { #sleep for incremental 10 seconds before next retry; Start-Sleep -Seconds $sleepValue; $sleepValue = $sleepValue + 10; } } }; $this.PublishCustomMessage("All files have been uploaded to container [$containerName]"); } else { throw [System.ArgumentException] ("The argument 'filesToUpload' is null or empty"); } return $result; } [void] DownloadFilesFromBlob([string] $containerName, [string] $blobName, [string] $destinationPath, [bool] $overwrite) { $loopValue = $this.retryCount; $sleepValue = $this.sleepIntervalInSecs; while($loopValue -gt 0) { $loopValue = $loopValue - 1; try { if($overwrite) { Get-AzStorageBlobContent -Blob $blobName -Container $containerName -Context $this.StorageAccount.Context -Destination $destinationPath -Force -ErrorAction Stop } else { Get-AzStorageBlobContent -Blob $blobName -Container $containerName -Context $this.StorageAccount.Context -Destination $destinationPath -ErrorAction Stop } $loopValue = 0; } catch { #sleep for incremental 10 seconds before next retry; Start-Sleep -Seconds $sleepValue; $sleepValue = $sleepValue + 10; } } } [psobject] DownloadFilesFromBlob([string] $containerName, [string] $blobName, [string] $destinationPath, [bool] $overwrite,[bool] $WithoutVirtualDirectory) { $loopValue = $this.retryCount; $sleepValue = $this.sleepIntervalInSecs; $blobDetails =$null if($WithoutVirtualDirectory) { $copyDestinationPath = [Constants]::AzSKTempFolderPath + "ContainerContent\" [Helpers]::CreateFolderIfNotExist($copyDestinationPath,$true) } else { $copyDestinationPath= $destinationPath } while($loopValue -gt 0) { $loopValue = $loopValue - 1; try { if($overwrite) { $blobDetails= Get-AzStorageBlobContent -Blob $blobName -Container $containerName -Context $this.StorageAccount.Context -Destination $copyDestinationPath -Force -ErrorAction Stop } else { $blobDetails= Get-AzStorageBlobContent -Blob $blobName -Container $containerName -Context $this.StorageAccount.Context -Destination $copyDestinationPath -ErrorAction Stop } $loopValue = 0; } catch { #sleep for incremental 10 seconds before next retry; Start-Sleep -Seconds $sleepValue; $sleepValue = $sleepValue + 10; } } if($WithoutVirtualDirectory) { Get-ChildItem -Path $copyDestinationPath -Recurse -File | Copy-Item -Destination $destinationPath -Force } return $blobDetails } [string] GenerateSASToken([string] $containerName) { $this.CreateStorageContainerIfNotExists($containerName); $sasToken = New-AzStorageContainerSASToken -Name $containerName -Context $this.StorageAccount.Context -ExpiryTime (Get-Date).AddMonths(6) -Permission rl -Protocol HttpsOnly -StartTime (Get-Date).AddDays(-1) if([string]::IsNullOrWhiteSpace($sasToken)) { throw ([SuppressedException]::new("Unable to create SAS token for storage account [$($this.StorageAccountName)]", [SuppressedExceptionType]::InvalidOperation)) } return $sasToken; } [string] GenerateTableSASToken([string] $tableName) { $this.CreateTableIfNotExists($tableName); $sasToken = New-AzStorageTableSASToken -Context $this.StorageAccount.Context -Name $tableName -Permission rau -Protocol HttpsOnly -StartTime (Get-Date).AddDays(-1) -ExpiryTime (Get-Date).AddHours(6) if([string]::IsNullOrWhiteSpace($sasToken)) { throw ([SuppressedException]::new("Unable to create SAS token for table [$tableName] in storage account [$($this.StorageAccountName)]", [SuppressedExceptionType]::InvalidOperation)) } return $sasToken; } [void] GetStorageAccountInstance() { # Fetch the Storage account context $this.StorageAccount = Get-AzStorageAccount -ResourceGroupName $this.ResourceGroupName -Name $this.StorageAccountName -ErrorAction Ignore if(-not ($this.StorageAccount -and $this.StorageAccount.Context)) { $this.StorageAccount = $null; throw ([SuppressedException]::new("Unable to fetch the storage account [$($this.StorageAccountName)] under resource group [$($this.ResourceGroupName)]", [SuppressedExceptionType]::InvalidOperation)) } } #Function to download files from container with or without virtual directory [PSObject] DownloadFilesFromContainer([string] $containerName, [string] $folderName, [string] $destinationPath, [bool] $overwrite, [bool] $WithoutVirtualDirectory) { $loopValue = $this.retryCount; $sleepValue = $this.sleepIntervalInSecs; $blobList = @() [Helpers]::CreateFolderIfNotExist($destinationPath,$false) if($WithoutVirtualDirectory) { $copyDestinationPath = [Constants]::AzSKTempFolderPath + "ContainerContent\" [Helpers]::CreateFolderIfNotExist($copyDestinationPath,$true) } else { $copyDestinationPath= $destinationPath } while($loopValue -gt 0) { $loopValue = $loopValue - 1; try { $blobs = Get-AzStorageBlob -Container $containerName -Context $($this.StorageAccount.Context) | Where-Object {$_.Name -like "*$folderName*"} foreach ($blob in $blobs) { $blobName = $blob.Name if($overwrite) { $blobList+= Get-AzStorageBlobContent -Blob $blobName -Container $containerName -Context $this.StorageAccount.Context -Destination $copyDestinationPath -Force -ErrorAction Stop } else{ $blobList+= Get-AzStorageBlobContent -Blob $blobName -Container $containerName -Context $this.StorageAccount.Context -Destination $copyDestinationPath -ErrorAction Stop } } $loopValue = 0; } catch { #sleep for incremental 10 seconds before next retry; Start-Sleep -Seconds $sleepValue; $sleepValue = $sleepValue + 10; } } if($WithoutVirtualDirectory) { Get-ChildItem -Path $copyDestinationPath -Recurse -File | Copy-Item -Destination $destinationPath -Force } return $blobList } } class AppInsightHelper: ResourceGroupHelper { [PSObject] $AppInsightInstance = $null; [string] $AppInsightName; [string] $AppInsightLocation; hidden [string] $ResourceType = "Microsoft.Insights/components"; AppInsightHelper([string] $subscriptionId, [string] $resourceGroupName,[string] $resourceGroupLocation, [string] $appInsightsLocation, [string] $appInsightName): Base($subscriptionId, $resourceGroupName, $resourceGroupLocation) { if([string]::IsNullOrWhiteSpace($appInsightName)) { throw [System.ArgumentException] ("The argument 'appInsightName' is null or empty"); } $this.AppInsightName = $appInsightName; $this.AppInsightLocation = $appInsightsLocation; } [void] CreateAppInsightIfNotExists() { if(-not $this.AppInsightInstance) { $this.CreateResourceGroupIfNotExists(); [Helpers]::RegisterResourceProviderIfNotRegistered("microsoft.insights"); $existingResources = Get-AzResource -ResourceGroupName $this.ResourceGroupName -ResourceType $this.ResourceType # Assuming 1 storage account is needed on Resource group if(($existingResources | Measure-Object).Count -gt 1) { throw ([SuppressedException]::new(("Multiple application insight resources found in resource group: [$($this.ResourceGroupName)]. This is not expected. Please contact support team."), [SuppressedExceptionType]::InvalidOperation)) } elseif(($existingResources | Measure-Object).Count -eq 0) { $this.PublishCustomMessage("Creating an application insight resource ["+ $this.AppInsightName +"]..."); $newResource = New-AzResource -ResourceName $this.AppInsightName -ResourceGroupName $this.ResourceGroupName -ResourceType $this.ResourceType ` -Location $this.AppInsightLocation -PropertyObject @{"Application_Type"="web"} -Force if($newResource) { $this.PublishCustomMessage("Successfully created application insight resource [$($this.AppInsightName)]", [MessageType]::Update); } else { throw ([SuppressedException]::new("Failed to create application insight resource [$($this.AppInsightName)]", [SuppressedExceptionType]::Generic)) } } elseif(($existingResources | Measure-Object).Count -eq 1) { $this.AppInsightName = $existingResources.Name; } # Fetch the application insight $this.AppInsightInstance = Get-AzResource -Name $this.AppInsightName -ResourceGroupName $this.ResourceGroupName -ResourceType $this.ResourceType -ExpandProperties if(-not ($this.AppInsightInstance -and $this.AppInsightInstance.Properties)) { $this.AppInsightInstance = $null; throw ([SuppressedException]::new("Unable to fetch application insight resource [$($this.AppInsightName)]", [SuppressedExceptionType]::InvalidOperation)) } } } } |