Framework/Core/PolicySetup/PolicySetup.ps1
using namespace System.Management.Automation using namespace Microsoft.Azure.Commands.Management.Storage.Models using namespace Microsoft.WindowsAzure.Storage.Blob using namespace Microsoft.WindowsAzure.Commands.Common.Storage.ResourceModel Set-StrictMode -Version Latest class PolicySetup: CommandBase { [StorageHelper] $StorageAccountInstance; [AppInsightHelper] $AppInsightInstance; [string] $OrgName; [string] $DepartmentName; [string] $OrgFullName; hidden [string] $PolicyUrl; hidden [string] $InstallerUrl; hidden [string] $InstallerFileName; hidden [string] $Version = "2.1711.0"; hidden [string] $ConfigContainerName = "policies"; hidden [string] $InstallerContainerName = "installer"; hidden [string] $FolderPath; hidden [string] $ConfigFolderPath; hidden [string] $InstallerFolderPath; hidden [string] $RunbookFolderPath; hidden [string] $InstallerFile; hidden [string] $IWRCommand; #PolicySetup([string] $subscriptionId, [InvocationInfo] $invocationContext, [string] $orgName, [string] $resourceGroupLocation): # Base($subscriptionId, $invocationContext) #{ # $this.CreateInstance($subscriptionId, $orgName, "", $resourceGroupLocation); #} PolicySetup([string] $subscriptionId, [InvocationInfo] $invocationContext, [string] $orgName, [string] $departmentName, [string] $resourceGroupLocation, [string] $localPolicyFolderPath): Base($subscriptionId, $invocationContext) { $this.CreateInstance($subscriptionId, $orgName, $departmentName, $resourceGroupLocation, $localPolicyFolderPath); } [void] CreateInstance([string] $subscriptionId, [string] $orgName, [string] $departmentName, [string] $resourceGroupLocation, [string] $localPolicyFolderPath) { if([string]::IsNullOrWhiteSpace($orgName)) { throw ([SuppressedException]::new(("The argument 'orgName' is null or empty"), [SuppressedExceptionType]::NullArgument)) } $this.OrgName = $orgName; $this.DepartmentName = $departmentName; $this.OrgFullName = $orgName; if(-not [string]::IsNullOrWhiteSpace($departmentName)) { $this.OrgFullName = $this.OrgFullName + "-" + $departmentName; } $prefix = [Constants]::AzSdkModuleName + "-" + $this.OrgFullName; $candidateStorageAccountName = $prefix.Replace("-", "").ToLower() + "sa"; [int] $availableLength = 24 - ([Constants]::AzSdkModuleName.Length + 2) $storageRegEx = [regex]"^[a-z0-9]{3,24}$" if(-not $storageRegEx.IsMatch($candidateStorageAccountName)) { throw ([SuppressedException]::new("Only alphanumeric characters are supported in OrgName and DeptName params. Total length (OrgName + DeptName) should be less than $availableLength characters ", [SuppressedExceptionType]::InvalidArgument)) } $this.FolderPath = [System.Environment]::GetFolderPath("Desktop") + "\" + $prefix + "-Policy\"; if(-not [string]::IsNullOrWhiteSpace($localPolicyFolderPath)) { try { if (-not $localPolicyFolderPath.EndsWith("\")) { $localPolicyFolderPath += "\"; } $localPolicyFolderPath += $prefix + "-Policy\"; if (-not (Test-Path $localPolicyFolderPath)) { mkdir -Path $localPolicyFolderPath -ErrorAction Stop | Out-Null } Copy-Item ($PSScriptRoot + "\README.txt") ($localPolicyFolderPath + "README.txt") -Force #Out-File -InputObject "AzSDK folder check" -Force -FilePath $testFilePath -Encoding utf8 #Remove-Item -Path $testFilePath -Force $this.FolderPath = $localPolicyFolderPath; } catch { throw ([SuppressedException]::new("Not able to access/modify the folder [$localPolicyFolderPath].`r`n$($_.ToString())", [SuppressedExceptionType]::InvalidOperation)) } } $this.StorageAccountInstance = [StorageHelper]::new($subscriptionId, $prefix + "-RG" , $resourceGroupLocation, $prefix.Replace("-", "").ToLower() + "sa"); $this.AppInsightInstance = [AppInsightHelper]::new($subscriptionId, $prefix + "-RG" , $resourceGroupLocation, $prefix + "-AppInsight"); $this.ConfigFolderPath = $this.FolderPath + "Config\"; $this.InstallerFolderPath = $this.FolderPath + "Installer\"; $this.RunbookFolderPath = $this.FolderPath + "CA-Runbook\"; $this.InstallerFileName = [Constants]::AzSdkModuleName + "-EasyInstaller.ps1"; $this.InstallerFile = $this.InstallerFolderPath + $this.InstallerFileName; # setup base version $azsdkConfig = [ConfigurationManager]::GetAzSdkConfigData(); if([Helpers]::CheckMember($azsdkConfig, "ConfigSchemaBaseVersion") -and (-not [string]::IsNullOrWhiteSpace($azsdkConfig.ConfigSchemaBaseVersion))) { $this.Version = $azsdkConfig.ConfigSchemaBaseVersion; } } [void] ModifyConfigs() { # Modify config files and save to temp location $metadataFileNames = @(); if(-not [string]::IsNullOrWhiteSpace($this.InstallerUrl)) { $this.IWRCommand = "iwr '$($this.InstallerUrl)' -UseBasicParsing | iex"; } if((Get-ChildItem $this.ConfigFolderPath -Recurse -Force | Where-Object { $_.Name -eq "AzSdk.json" } | Measure-Object).Count -eq 0) { $azsdkOverride = [ConfigOverride]::new("AzSdk.json"); $azsdkOverride.UpdatePropertyValue("PolicyMessage", "Running $([Constants]::AzSdkModuleName) cmdlet using $($this.OrgFullName) policy..."); if(-not [string]::IsNullOrWhiteSpace($this.IWRCommand)) { $azsdkOverride.UpdatePropertyValue("InstallationCommand", $this.IWRCommand); } if($this.AppInsightInstance -and $this.AppInsightInstance.AppInsightInstance -and $this.AppInsightInstance.AppInsightInstance.Properties) { $azsdkOverride.UpdatePropertyValue("ControlTelemetryKey", $this.AppInsightInstance.AppInsightInstance.Properties.InstrumentationKey); $azsdkOverride.UpdatePropertyValue("EnableControlTelemetry", "true"); } $azsdkOverride.WriteToFolder($this.ConfigFolderPath); } # Dynamically get list of files available in folder $metadataFileNames += Get-ChildItem $this.ConfigFolderPath -Recurse -Force | Where-Object { $_.mode -match "-a---" -and $_.Name -ne "ServerConfigMetadata.json" } | Select-Object -Property Name | Select-Object -ExpandProperty Name | Select-Object @{ Label="Name"; Expression={ $_ } }; $metadataOverride = [ConfigOverride]::new("ServerConfigMetadata.json"); $metadataOverride.UpdatePropertyValue("OnlinePolicyList", $metadataFileNames); $metadataOverride.WriteToFolder($this.ConfigFolderPath); } [void] ModifyInstaller() { if(-not [string]::IsNullOrWhiteSpace($this.PolicyUrl)) { # write SAS token url to installer file $folderName = [System.IO.Path]::GetDirectoryName($this.InstallerFile); # Check for environment specific installer file $fileName = $PSScriptRoot + "\" + [Constants]::AzSdkModuleName +"-EasyInstaller.ps1"; if(-not (Test-Path -Path $fileName)) { $fileName = $PSScriptRoot + "\EasyInstaller.ps1"; } $fileContent = Get-Content -Path $fileName; $fileContent = $fileContent.Replace("#PolicyUrl#", $this.PolicyUrl); $fileContent = $fileContent.Replace("#ModuleName#", [Constants]::AzSdkModuleName); $fileContent = $fileContent.Replace("#OrgName#", $this.OrgFullName); if (-not (Test-Path $folderName)) { mkdir -Path $folderName -ErrorAction Stop | Out-Null } if (-not $folderName.EndsWith("\")) { $folderName += "\"; } Out-File -InputObject $fileContent -Force -FilePath $this.InstallerFile -Encoding utf8 #Set-Content -Value $fileContent -Path $this.InstallerFile -Force } else { throw ([SuppressedException]::new("Not able to create installer file.", [SuppressedExceptionType]::Generic)) } } [void] CopyRunbook() { # Quick fix: Temporary code added to make the policies run for non-CSE tenants. Suggested by Byna. try { if (-not (Test-Path $this.RunbookFolderPath)) { mkdir -Path $this.RunbookFolderPath -ErrorAction Stop | Out-Null } if((Get-ChildItem $this.RunbookFolderPath -Force | Where-Object { $_.Name -eq "RunbookScanAgent.ps1" } | Measure-Object).Count -eq 0) { $caFilePath = (Get-Item -Path $PSScriptRoot).Parent.Parent.FullName + "\Configurations\ContinuousAssurance\RunbookScanAgent.ps1" Copy-Item ($caFilePath) ($this.RunbookFolderPath + "RunbookScanAgent.ps1") } $allCAFiles = @(); $allCAFiles += Get-ChildItem $this.RunbookFolderPath -Force | Where-Object { $_.mode -match "-a---" } if($allCAFiles.Count -ne 0) { $this.StorageAccountInstance.UploadFilesToBlob($this.ConfigContainerName, "0.0.0", $allCAFiles); } } catch { $this.CommandError($_); } } [MessageData[]] InstallPolicy() { $this.AppInsightInstance.CreateAppInsightIfNotExists(); $container = $this.StorageAccountInstance.CreateStorageContainerIfNotExists($this.InstallerContainerName, [BlobContainerPublicAccessType]::Blob); if($container -and $container.CloudBlobContainer) { $this.InstallerUrl = $container.CloudBlobContainer.Uri.AbsoluteUri + "/" + $this.InstallerFileName; } $this.ModifyConfigs(); $allFiles = @(); $allFiles += Get-ChildItem $this.ConfigFolderPath -Recurse -Force | Where-Object { $_.mode -match "-a---" } #| Select-Object -Property FullName | Select-Object -ExpandProperty FullName; if($allFiles.Count -ne 0) { $this.StorageAccountInstance.UploadFilesToBlob($this.ConfigContainerName, $this.Version, $allFiles); } else { #throw ([SuppressedException]::new("No files found under folder [$($this.ConfigFolderPath)]", [SuppressedExceptionType]::InvalidOperation)) } $container = $this.StorageAccountInstance.CreateStorageContainerIfNotExists($this.ConfigContainerName); if($container -and $container.CloudBlobContainer) { $this.PolicyUrl = $container.CloudBlobContainer.Uri.AbsoluteUri + "/```$(```$Version)/```$(```$FileName)" + $this.StorageAccountInstance.GenerateSASToken($this.ConfigContainerName); } $this.ModifyInstaller(); $this.StorageAccountInstance.UploadFilesToBlob($this.InstallerContainerName, "", (Get-ChildItem -Path $this.InstallerFile)); $this.CopyRunbook(); $this.PublishCustomMessage(" `r`nThe setup has been completed and policies have been copied to [$($this.FolderPath)].`r`nRun the command below to install Organization specific version.`r`n$($this.IWRCommand)", [MessageType]::Update); $this.PublishCustomMessage(" `r`nNote: This is a basic setup and uses a public access blob for storing your org's installer. Once you have richer org policies, consider using a location/end-point protected by your tenant authentication.", [MessageType]::Warning); # Removing cleanup step #$this.CleanupTempFolders(); return @(); } [void] CleanupTempFolders() { Remove-Item -Path $this.ConfigFolderPath -Force -Recurse -ErrorAction Ignore Remove-Item -Path $this.InstallerFolderPath -Force -Recurse -ErrorAction Ignore } } |