Framework/Helpers/ResourceHelper.ps1
using namespace Microsoft.Azure.Storage.Blob using namespace Microsoft.Azure.Commands.Management.Storage.Models using namespace Microsoft.WindowsAzure.Commands.Common.Storage.ResourceModel Set-StrictMode -Version Latest class ResourceGroupHelper: EventBase { [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 = [ResourceGroupHelper]::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; } } } static [PSObject] GetResourceGroupTags([string]$RGName) { $azskResourceGroup = Get-AzResourceGroup -Name $RGName -ErrorAction SilentlyContinue; $tags = @{} if(($azskResourceGroup | Measure-Object).Count -gt 0) { $tags = $azskResourceGroup.Tags; if($null -eq $tags) { $tags = @{} } } return $tags } static [string] GetResourceGroupTag([string]$RGName, [string] $tagName) { $azskResourceGroup = Get-AzResourceGroup -Name $RGName -ErrorAction SilentlyContinue; $tags = @{} if(($azskResourceGroup | Measure-Object).Count -gt 0) { $tags = $azskResourceGroup.Tags; if(($tags | Measure-Object).Count -gt 0) { return $tags[$tagName]; } } return ""; } static [bool] NewAzSKResourceGroup([string]$ResourceGroup, [string]$Location, [string] $Version) { try { [Hashtable] $RGTags = @{}; if ([string]::IsNullOrWhiteSpace($Version)) { $version= [Constants]::AzSKCurrentModuleVersion } $RGTags += @{ "AzSKVersion" = $Version; "CreationTime" = $(get-date).ToUniversalTime().ToString("yyyyMMdd_HHmmss"); } $newRG = New-AzResourceGroup -Name $ResourceGroup -Location $Location ` -Tag $RGTags ` -ErrorAction Stop return $true } catch { #return as false in the case of exception. Caller of this function is taking care if the value is false return $false } } static [void] CreateNewResourceGroupIfNotExists([string]$ResourceGroup, [string]$Location, [string] $Version) { if((Get-AzResourceGroup -Name $ResourceGroup -ErrorAction SilentlyContinue | Measure-Object).Count -eq 0) { [ResourceGroupHelper]::NewAzSKResourceGroup($ResourceGroup,$Location,$Version) } } static [void] SetResourceGroupTags([string]$RGName, [PSObject]$TagsHashTable, [bool] $Remove) { [ResourceGroupHelper]::SetResourceGroupTags($RGName, $TagsHashTable, $Remove, $true) } static [void] SetResourceGroupTags([string]$RGName, [PSObject]$TagsHashTable, [bool] $Remove, [bool] $update) { $azskResourceGroup = Get-AzResourceGroup -Name $RGName -ErrorAction SilentlyContinue; if(($azskResourceGroup | Measure-Object).Count -gt 0) { $tags = $azskResourceGroup.Tags; if($null -eq $tags) { $tags = @{} } if(($TagsHashTable | Measure-Object).Count -gt 0) { $TagsHashTable.Keys | ForEach-Object { $key = $_; if($null -ne $tags -and $tags.ContainsKey($key)) { if($update) { $tags[$key] = $TagsHashTable[$key]; } if($Remove) { $tags.Remove($key); } } elseif(-not $Remove) { $tags.Add($key, $TagsHashTable[$key]) } } } try { Set-AzResourceGroup -Name $RGName -Tag $tags -ErrorAction Stop } catch { #Skipping tag exception. Exception can be raised due to privilege issues. #[EventBase]::PublishGenericCustomMessage(" `r`nError occured while adding tag(s) on resource group [$RGName]. $($_.Exception)", [MessageType]::Warning); } } } static [bool] IsLatestVersionConfiguredOnSub([String] $ConfigVersion,[string] $TagName,[string] $FeatureName) { $IsLatestVersionPresent = [ResourceGroupHelper]::IsLatestVersionConfiguredOnSub($ConfigVersion,$TagName) if($IsLatestVersionPresent){ #<TODO Framework: Use Publish Custom Message and use only one function for latest configurations versions> Write-Host "$FeatureName configuration in your subscription is already up to date. If you would like to reconfigure, please rerun the command with '-Force' parameter." -ForegroundColor Cyan } return $IsLatestVersionPresent } static [bool] IsLatestVersionConfiguredOnSub([String] $ConfigVersion,[string] $TagName) { $IsLatestVersionPresent = $false $tagsOnSub = [ResourceGroupHelper]::GetResourceGroupTags([ConfigurationManager]::GetAzSKConfigData().AzSKRGName) if($tagsOnSub) { $SubConfigVersion= $tagsOnSub.GetEnumerator() | Where-Object {$_.Name -eq $TagName -and $_.Value -eq $ConfigVersion} if(($SubConfigVersion | Measure-Object).Count -gt 0) { $IsLatestVersionPresent = $true } } return $IsLatestVersionPresent } } class ResourceHelper: EventBase{ static [void] SetResourceTags([string] $ResourceId, [PSObject] $TagsHashTable, [bool] $Remove, [bool] $update) { $azskResource = Get-AzResource -ResourceId $ResourceId -ErrorAction SilentlyContinue; if(($azskResource | Measure-Object).Count -gt 0) { $tags = $azskResource.Tags; if($null -eq $tags) { $tags = @{} } if(($TagsHashTable | Measure-Object).Count -gt 0) { $TagsHashTable.Keys | ForEach-Object { $key = $_; if($null -ne $tags -and $tags.ContainsKey($key)) { if($update) { $tags[$key] = $TagsHashTable[$key]; } if($Remove) { $tags.Remove($key); } } elseif(-not $Remove) { $tags.Add($key, $TagsHashTable[$key]) } } } try { Set-AzResource -ResourceId $ResourceId -Tag $tags -Force -ErrorAction Stop } catch { [EventBase]::PublishGenericCustomMessage(" `r`nError occured while adding tag(s) on resource [$ResourceId]. $($_.Exception)", [MessageType]::Warning); } } } static [bool] IsvNetExpressRouteConnected($resourceName, $resourceGroupName) { $result = $false; $gateways = @(); $gateways += Get-AzVirtualNetworkGateway -ResourceGroupName $resourceGroupName | Where-Object { $_.GatewayType -eq "ExpressRoute" } if($gateways.Count -ne 0) { $vNet = Get-AzVirtualNetwork -Name $resourceName -ResourceGroupName $resourceGroupName if($vnet) { $subnetIds = @(); $vnet | ForEach-Object { if($_.Subnets) { $subnetIds += $_.Subnets | Select-Object -Property Id | Select-Object -ExpandProperty Id } }; if($subnetIds.Count -ne 0) { $gateways | ForEach-Object { $result = $result -or (($_.IpConfigurations | Where-Object { $subnetIds -contains $_.Subnet.Id } | Measure-Object).Count -ne 0); }; } } } return $result; } static [void] RegisterResourceProviderIfNotRegistered([string] $provideNamespace) { if([string]::IsNullOrWhiteSpace($provideNamespace)) { throw [System.ArgumentException] "The argument '$provideNamespace' is null or empty"; } # Check if provider is registered or not if(-not [ResourceHelper]::IsProviderRegistered($provideNamespace)) { [EventBase]::PublishGenericCustomMessage(" `r`nThe resource provider: [$provideNamespace] is not registered on the subscription. `r`nRegistering resource provider, this can take up to a minute...", [MessageType]::Warning); Register-AzResourceProvider -ProviderNamespace $provideNamespace $retryCount = 10; while($retryCount -ne 0 -and (-not [ResourceHelper]::IsProviderRegistered($provideNamespace))) { $timeout = 10 Start-Sleep -Seconds $timeout $retryCount--; #[EventBase]::PublishGenericCustomMessage("Checking resource provider status every $timeout seconds..."); } if(-not [ResourceHelper]::IsProviderRegistered($provideNamespace)) { throw ([SuppressedException]::new(("Resource provider: [$provideNamespace] registration failed. `r`nTry registering the resource provider from Azure Portal --> your Subscription --> Resource Providers --> $provideNamespace --> Register"), [SuppressedExceptionType]::Generic)) } else { [EventBase]::PublishGenericCustomMessage("Resource provider: [$provideNamespace] registration successful.`r`n ", [MessageType]::Update); } } } hidden static [bool] IsProviderRegistered([string] $provideNamespace) { return ((Get-AzResourceProvider -ProviderNamespace $provideNamespace | Where-Object { $_.RegistrationState -ne "Registered" } | Measure-Object).Count -eq 0); } } class StorageHelper: ResourceGroupHelper { hidden [PSStorageAccount] $StorageAccount = $null; [string] $StorageAccountName; [string] $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, [string] $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 } static [void] UploadStorageBlobContent([string] $fileName, [string] $blobName, [string] $containerName, [object] $stgCtx) { Set-AzStorageBlobContent -Blob $blobName -Container $containerName -File $fileName -Context $stgCtx -Force | Out-Null } static [object] GetStorageBlobContent([string] $folderName, [string] $fileName, [string] $blobName, [string] $containerName, [object] $stgCtx) { $fileName = Join-Path $folderName.TrimEnd([IO.Path]::DirectorySeparatorChar) $fileName return [StorageHelper]::GetStorageBlobContent($fileName, $blobName, $containerName, $stgCtx) } static [object] GetStorageBlobContent([string] $fileName, [string] $blobName, [string] $containerName, [object] $stgCtx) { $result = Get-AzStorageBlobContent -Blob $blobName -Container $containerName -Destination $fileName -Context $stgCtx -Force return $result } [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 = [StorageHelper]::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) { [StorageHelper]::UploadStorageBlobContent($_.FullName, $blobName , $containerName ,$this.StorageAccount.Context) #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) { [StorageHelper]::UploadStorageBlobContent($_.FullName, $blobName, $containerName, $this.StorageAccount.Context) #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) { [StorageHelper]::GetStorageBlobContent($destinationPath, $blobName , $containerName ,$this.StorageAccount.Context) #Get-AzStorageBlobContent -Blob $blobName -Container $containerName -Context $this.StorageAccount.Context -Destination $destinationPath -Force -ErrorAction Stop } else { [StorageHelper]::GetStorageBlobContent($destinationPath, $blobName , $containerName ,$this.StorageAccount.Context) #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 = Join-Path $([Constants]::AzSKTempFolderPath) "ContainerContent" [Helpers]::CreateFolderIfNotExist($copyDestinationPath,$true) } else { $copyDestinationPath= $destinationPath } while($loopValue -gt 0) { $loopValue = $loopValue - 1; try { if($overwrite) { [StorageHelper]::GetStorageBlobContent($copyDestinationPath, $blobName , $containerName ,$this.StorageAccount.Context) #$blobDetails= Get-AzStorageBlobContent -Blob $blobName -Container $containerName -Context $this.StorageAccount.Context -Destination $copyDestinationPath -Force -ErrorAction Stop } else { [StorageHelper]::GetStorageBlobContent($copyDestinationPath, $blobName , $containerName ,$this.StorageAccount.Context) #$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 = Join-Path $([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 $blobList+= [StorageHelper]::GetStorageBlobContent($copyDestinationPath, $blobName.Split("/")[-1], $blobName , $containerName ,$this.StorageAccount.Context) } $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 } static [PSObject] NewAzskCompliantStorage([string]$StorageName, [string]$StorageKind,[string]$ResourceGroup,[string]$Location) { $storageSku = [Constants]::NewStorageSku $storageObject = $null try { #register resource providers [ResourceHelper]::RegisterResourceProviderIfNotRegistered("Microsoft.Storage"); [ResourceHelper]::RegisterResourceProviderIfNotRegistered("microsoft.insights"); #create storage $status = Get-AzStorageAccountNameAvailability -Name $StorageName if($null -ne $status -and $status.NameAvailable -eq $true) { $newStorage = New-AzStorageAccount -ResourceGroupName $ResourceGroup ` -Name $StorageName ` -Type $storageSku ` -Location $Location ` -Kind $StorageKind ` -AccessTier Cool ` -EnableHttpsTrafficOnly $true ` -ErrorAction Stop $retryAccount = 0 do { $storageObject = Get-AzStorageAccount -ResourceGroupName $ResourceGroup -Name $StorageName -ErrorAction SilentlyContinue Start-Sleep -seconds 2 $retryAccount++ }while (!$storageObject -and $retryAccount -ne 6) if ($storageObject) { #set diagnostics on $currentContext = $storageObject.Context Set-AzStorageServiceLoggingProperty -ServiceType Blob -LoggingOperations All -Context $currentContext -RetentionDays 365 -PassThru -ErrorAction Stop Set-AzStorageServiceMetricsProperty -MetricsType Hour -ServiceType Blob -Context $currentContext -MetricsLevel ServiceAndApi -RetentionDays 365 -PassThru -ErrorAction Stop } } else { throw ([SuppressedException]::new(("The specified name for the storage account is not available. Please rerun this command to try a different name."), [SuppressedExceptionType]::Generic)); } } catch { [EventBase]::PublishGenericException($_); $storageObject = $null #clean-up storage if error occurs if ((Get-AzResource -ResourceGroupName $ResourceGroup -Name $StorageName|Measure-Object).Count -gt 0) { # caused deletion of storage on any exception. # Remove-AzureRmStorageAccount -ResourceGroupName $ResourceGroup -Name $StorageName -Force -ErrorAction SilentlyContinue } } return $storageObject } static [PSObject] NewAzskCompliantStorage([string]$StorageName, [string]$ResourceGroup, [string]$Location) { return [StorageHelper]::NewAzskCompliantStorage($StorageName,[Constants]::NewStorageKind,[string]$ResourceGroup,[string]$Location) } static [string] CreateStorageAccountSharedKey([string] $StringToSign,[string] $AccountName,[string] $AccessKey) { $KeyBytes = [System.Convert]::FromBase64String($AccessKey) $HMAC = New-Object System.Security.Cryptography.HMACSHA256 $HMAC.Key = $KeyBytes $UnsignedBytes = [System.Text.Encoding]::UTF8.GetBytes($StringToSign) $KeyHash = $HMAC.ComputeHash($UnsignedBytes) $SignedString = [System.Convert]::ToBase64String($KeyHash) $sharedKey = $AccountName+":"+$SignedString return $sharedKey } } 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(); [ResourceHelper]::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)) } } } } |