Framework/Configurations/Migration/Migration.ps1

Set-StrictMode -Version Latest

class MigrationHelper 
{
    static [StorageHelper] $StorageAccountInstance;
    
    static [void] StartMigration([SubscriptionContext] $subscriptionContext, [PSObject] $InvocationContext, [string] $AzureADAppName)
    {
        [bool] $MigrateASC = $false;    
        [AIOrgTelemetryHelper]::CommonProperties= $subscriptionContext
        [PSObject] $MigrationOutput = @{}
        [bool] $ErrorOccurred = $false;
        try
        {
            [AIOrgTelemetryHelper]::PublishEvent("AzSK Migration Started",$null, $null)
            if(-not [MigrationHelper]::MigrationPrerequisiteCheck($subscriptionContext.SubscriptionId))
            {
                [AIOrgTelemetryHelper]::PublishEvent("AzSK Migration Prerequisite Failed",$null, $null)
                return
            }

            Write-Host ([Constants]::DoubleDashLine + "`r`nUpdating your current subscription with latest policies along with migration of existing resources...`r`n" + [Constants]::DoubleDashLine) -ForegroundColor Cyan;

            #region clear any existing locks
            try
            {
                Write-Host ("Checking if there are any resource locks on old RG...") -ForegroundColor Yellow;

                $azsdkRGScope = "/subscriptions/$($subscriptionContext.SubscriptionId)/resourceGroups/$([OldConstants]::AzSDKRGName)"
                $resourceLocks = @();
                $resourceLocks += Get-AzureRmResourceLock -Scope $azsdkRGScope -ErrorAction Stop
                if($resourceLocks.Count -gt 0)
                {
                    $resourceLocks | ForEach-Object {
                        Remove-AzureRmResourceLock -LockId $_.LockId -Force
                    }
                    Write-Host ("Successfully removed the locks on old resource group.") -ForegroundColor Green;
                }
                else
                {
                    Write-Host ("No locks found on old resource group.") -ForegroundColor Green;
                }
                $MigrationOutput.LockRemoval = "Success"
            }
            catch
            {
                Write-Host "An error occurred during removal of locks on old resource group: [$([OldConstants]::AzSDKRGName)]" -ForegroundColor Red
                [AIOrgTelemetryHelper]::PublishEvent("AzSK Migration Error",@{ "StageName"= "Resource Group Lock"; "ErrorRecord" = ($_ | Out-String); "MigrationStatus"= ($MigrationOutput | Out-String) }, $null)
                $MigrationOutput.LockRemoval = "Failed. Message[$_]"
                $ErrorOccurred = $true;
                throw;
            }
            #endregion

            #region capture the existing information
            $vars = $null
            $oldResourceGroupLocation = [ConfigurationManager]::GetAzSKConfigData().AzSKLocation;
            $scanIntervalInHours = 24;
            try
            {
                Write-Host ("Extracting current data from old resources...") -ForegroundColor Yellow;

                $oldRg = Get-AzureRmResourceGroup -Name $([OldConstants]::AzSDKRGName) -ErrorAction SilentlyContinue
                if($oldRg)
                {
                    $oldResourceGroupLocation = $oldRg.Location;
                }
                $vars = Get-AzureRmAutomationVariable -ResourceGroupName $([OldConstants]::AzSDKRGName) -AutomationAccountName $([OldConstants]::AutomationAccountName) -ErrorAction SilentlyContinue
                $migrateCA = $true;
                if(($vars | Measure-Object).Count -eq 0)
                {
                    $migrateCA = $false;
                }
                $newRGName = [ConfigurationManager]::GetAzSKConfigData().AzSKRGName;
                if($migrateCA)
                {
                    $schedule = Get-AzureRmAutomationSchedule -Name $([Constants]::ScheduleName) -ResourceGroupName $newRGName -AutomationAccountName $([Constants]::AutomationAccountName) -ErrorAction SilentlyContinue
                    if($null -ne $schedule -and $schedule.Frequency -eq 'Hour')
                    {
                        $scanIntervalInHours = $schedule.Interval
                    }

                    #extract CA scaling configuration data
                    $caSubs = @();
                    $storageAccounts = @();
                    $storageAccounts += Get-AzureRmStorageAccount -ResourceGroupName $([OldConstants]::AzSDKRGName) -ErrorAction SilentlyContinue;
                    if(($storageAccounts | Measure-Object).Count -gt 0)
                    {
                        $storageAccounts = $storageAccounts | Where-Object { $_.StorageAccountName -like "$([OldConstants]::StorageAccountPreName)*" } ;
                        [CAScanModel[]] $scanobjects = @();
                        $TargetSubscriptionIds = ""
                        if(($storageAccounts | Measure-Object).Count -eq 1)
                        {
                            $AzSKTemp = [Constants]::AzSKAppFolderPath + "\Migration\CAScalingConfig";                
                            if(-not (Test-Path "$AzSKTemp"))
                            {
                                mkdir -Path "$AzSKTemp" -ErrorAction Stop | Out-Null
                            }
                            else
                            {
                                Remove-Item -Path "$AzSKTemp\*" -Force -Recurse 
                            }
                            $keys = Get-AzureRmStorageAccountKey -ResourceGroupName $([OldConstants]::AzSDKRGName) -Name $storageAccounts[0].StorageAccountName
                            $currentContext = New-AzureStorageContext -StorageAccountName $storageAccounts[0].StorageAccountName -StorageAccountKey $keys[0].Value -Protocol Https
                            $CAScanDataBlobObject = Get-AzureStorageBlob -Container $([OldConstants]::CAMultiSubScanConfigContainerName) -Blob $([Constants]::CATargetSubsBlobName) -Context $currentContext -ErrorAction SilentlyContinue 
                            if($null -ne $CAScanDataBlobObject)
                            {                        
                                $CAScanDataBlobContentObject = Get-AzureStorageBlobContent -Container $([OldConstants]::CAMultiSubScanConfigContainerName) -Blob $([Constants]::CATargetSubsBlobName) -Context $currentContext -Destination $AzSKTemp -Force
                                $CAScanDataBlobContent = Get-ChildItem -Path "$AzSKTemp\$([Constants]::CATargetSubsBlobName)" -Force | Get-Content | ConvertFrom-Json

                                #create the active snapshot from the ca scan objects
                                if(($CAScanDataBlobContent | Measure-Object).Count -gt 0)
                                {

                                    $CAScanDataBlobContent | ForEach-Object {
                                        $CAScanDataInstance = $_;
                                        $scanobject = [CAScanModel]::new($CAScanDataInstance.SubscriptionId, $CAScanDataInstance.LoggingOption);
                                        $scanobjects += $scanobject;
                                        $caSubs += $CAScanDataInstance.SubscriptionId 
                                        $TargetSubscriptionIds = $TargetSubscriptionIds + "," + $CAScanDataInstance.SubscriptionId                             
                                    }
                                    $TargetSubscriptionIds = $TargetSubscriptionIds.SubString(1)
                                }
                            }
                        }
                    }

                }                
                Write-Host ("Successfully completed extracting current data from old resources.") -ForegroundColor Green;
                $MigrationOutput.CurrentDataExtraction = "Success"                
            }
            catch{
                Write-Host "An error while fetching the current data" -ForegroundColor Red
                [AIOrgTelemetryHelper]::PublishEvent("AzSK Migration Error",@{ "StageName"= "Capture Existing Metadata"; "ErrorRecord" = ($_ | Out-String); "MigrationStatus"= ($MigrationOutput | Out-String) }, $null)
                $MigrationOutput.CurrentDataExtraction = "Failed. Message[$_]"
                $ErrorOccurred = $true;
                throw;
            }
            #endregion

            #region attestation migration
            try
            {
                Write-Host ("Migrating the attestation data to new storage account...") -ForegroundColor Yellow;
                [MigrationHelper]::MigrateStorageToLatest($subscriptionContext.SubscriptionId, $oldResourceGroupLocation)
                Write-Host ("Successfully completed migrating the attestation data.") -ForegroundColor Green;
                $MigrationOutput.StorageDataMigration = "Success"
            }
            catch
            {
                Write-Host "An error occurred either during migration of attestation data to new storage account. See migration log for details." -ForegroundColor Red
                [AIOrgTelemetryHelper]::PublishEvent("AzSK Migration Error",@{ "StageName"= "Attestation Migration"; "ErrorRecord" = ($_ | Out-String); "MigrationStatus"= ($MigrationOutput | Out-String) }, $null)
                $MigrationOutput.StorageDataMigration = "Failed. Message[$_]"
                $ErrorOccurred = $true;
                #eat the exception and continue with other migration
            }
            #endregion

            #region alerts migration
            try
            {
                Write-Host ("Creating new alerts and cleaning up old ones...") -ForegroundColor Yellow;
                [MigrationHelper]::MigrateAlerts($subscriptionContext.SubscriptionId, $InvocationContext);
                Write-Host ("Successfully completed creating new alerts.") -ForegroundColor Green;
                $MigrationOutput.AlertsMigration = "Success"
            }
            catch
            {
                Write-Host "An error occurred either during creation of new alerts or removal of old ones. See migration log for details." -ForegroundColor Red
                [AIOrgTelemetryHelper]::PublishEvent("AzSK Migration Error",@{ "StageName"= "Alert Setup"; "ErrorRecord" = ($_ | Out-String) }, $null)
                $MigrationOutput.AlertsMigration = "Failed. Message[$_]"
                $ErrorOccurred = $true;
                #eat the exception and continue with other migration
            }
            #endregion

            #region arm policies migration
            try
            {
                Write-Host ("Creating new policies and cleaning up olde ones...") -ForegroundColor Yellow;
                [MigrationHelper]::MigrateARMPolicies($subscriptionContext.SubscriptionId, $subscriptionContext.Scope, $InvocationContext);
                Write-Host ("Successfully completed creating new ARM policies.") -ForegroundColor Green;
                $MigrationOutput.ARMPoliciesMigration = "Success"
            }
            catch
            {
                Write-Host "An error occurred either during creation of new policies or removal of old ones. See migration log for details." -ForegroundColor Red
                [AIOrgTelemetryHelper]::PublishEvent("AzSK Migration Error",@{ "StageName"= "ARM Policy Setup"; "ErrorRecord" = ($_ | Out-String); "MigrationStatus"= ($MigrationOutput | Out-String) }, $null)
                $MigrationOutput.ARMPoliciesMigration = "Failed. Message[$_]"
                $ErrorOccurred = $true;
                #eat the exception and continue with other migration
            }
            #endregion

            #region update security center policies
            if($MigrateASC)
            {
                try
                {
                    Write-Host ("Updating Security Center policies as per latest configuration...") -ForegroundColor Yellow;
                    [MigrationHelper]::UpdateASC($subscriptionContext.SubscriptionId)
                    Write-Host ("Successfully updated Security Center policies.") -ForegroundColor Green;
                    $MigrationOutput.ASCUpdate = "Success"
                }
                catch
                {
                    Write-Host "An error occurred during updation of Security Center policies as per latest configuration. See migration log for details." -ForegroundColor Red
                    [AIOrgTelemetryHelper]::PublishEvent("AzSK Migration Error",@{ "StageName"= "ASC Update"; "ErrorRecord" = ($_ | Out-String); "MigrationStatus"= ($MigrationOutput | Out-String) }, $null)
                    $MigrationOutput.ASCUpdate = "Failed. Message[$_]"
                    $ErrorOccurred = $true;
                    #eat the exception and continue with other migration
                }
            }
            #endregion

            #region CA migration
            try
            {
                if($migrateCA)
                {
                    Write-Host ("Installing CA using the latest module...") -ForegroundColor Yellow;
                    [MigrationHelper]::MigrateAutomationAccountToLatest($subscriptionContext.SubscriptionId, $InvocationContext, $vars, $AzureADAppName, $scanIntervalInHours)                    
                    Remove-AzureRmAutomationAccount -ResourceGroupName $([OldConstants]::AzSDKRGName) -Name $([OldConstants]::AutomationAccountName) -Force
                    [Helpers]::SetResourceGroupTags([OldConstants]::AzSDKRGName ,@{[OldConstants]::RunbookVersionTagName=""}, $true)
                    Write-Host ("Successfully completed re-configuring CA.") -ForegroundColor Green;
                }
                else
                {
                    $caresources = Find-AzureRmResource -ResourceNameEquals $([Constants]::AutomationAccountName)
                    if(($caresources | Measure-Object).Count -eq 0)
                    {                        
                        Write-Host ("The current subscription is not configured with CA.") -ForegroundColor Yellow;
                    }
                    else
                    {
                        Write-Host ("CA has been already migrated for this subscription.") -ForegroundColor Green;
                    }
                }
                $MigrationOutput.CAMigration = "Success"
            }
            catch
            {
                Write-Host "An error occurred during CA migration. See migration log for details." -ForegroundColor Red
                [AIOrgTelemetryHelper]::PublishEvent("AzSK Migration Error",@{ "StageName"= "CA Setup"; "ErrorRecord" = ($_ | Out-String); "MigrationStatus"= ($MigrationOutput | Out-String) }, $null)
                $MigrationOutput.CAMigration = "Failed. Message[$_]"
                $ErrorOccurred = $true;
                #eat the exception and continue with other migration
            }
            #endregion

            #region cleanup of old CA SPN

            $subscriptionScope = "/subscriptions/{0}" -f $subscriptionContext.SubscriptionId

            $azskspnformatstring = "AzSDK_CA_SPN";
            $azskRoleAssignments = Get-AzureRmRoleAssignment -Scope $subscriptionScope -RoleDefinitionName Reader | Where-Object { $_.DisplayName -like "$($azskspnformatstring)*" }

            $azskRoleAssignments | ForEach-Object{
                $roleAssignment = $_
                #If you want to remove the role assignment then uncomment the following code.
                #Remove-AzureRmRoleAssignment -ObjectId $roleAssignment.ObjectId -RoleDefinitionName "Reader"
                #Remove-AzureRmRoleAssignment -ObjectId $roleAssignment.ObjectId -RoleDefinitionName "Contributor"
            }

            #endregion

            #region to warn about other resources
            $resources = Find-AzureRmResource -ResourceGroupNameEquals $([OldConstants]::AzSDKRGName) | Where-Object { -not ($_.Name -like "$([OldConstants]::StorageAccountPreName)*")}
            #filterout our resources
            if(($resources | Measure-Object).Count -gt 0)
            {
                $resourceString = [Helpers]::ConvertToPson($resources);
                Write-Host "We found resources which are not owned by AzSK. You need to migrate them to appropriate resource groups." -ForegroundColor Yellow
                Write-Host $resourceString
                $MigrationOutput.ResourcesToBeMigrated = "Failed. $resourceString"
            }
            else
            {
                $MigrationOutput.ResourcesToBeMigrated = "Success"
            }
            #endregion

            #region complete migration
            $MigrationOutput.ErrorOccurred = $ErrorOccurred
            if($MigrationOutput.ErrorOccurred -eq $false)
            {
                [MigrationHelper]::CompleteMigration($subscriptionContext.SubscriptionId, $MigrationOutput)
                #endregion
                [AIOrgTelemetryHelper]::PublishEvent("AzSK Migration Completed",@{ "MigrationStatus"= ($MigrationOutput | Out-String) }, $null)    
                write-host ([Constants]::SingleDashLine + "`r`nMigration completed successfully`r`n"+[Constants]::SingleDashLine) -ForegroundColor Green
            }
            else
            {
                [MigrationHelper]::PersistMigrationOutput($subscriptionContext.SubscriptionId, $MigrationOutput)
                [AIOrgTelemetryHelper]::PublishEvent("AzSK Migration Not Completed",@{ "MigrationStatus"= ($MigrationOutput | Out-String) }, $null)    
                write-host ([Constants]::SingleDashLine + "`r`nAn error during migration, please retry again. If issue still continue please reach out to support team.`r`n"+[Constants]::SingleDashLine) -ForegroundColor Red
            }            
            
        }
        catch
        {
            $MigrationOutput.ErrorOccurred = $ErrorOccurred
            [AIOrgTelemetryHelper]::PublishEvent("AzSK Migration Error",@{ "StageName"= "Migration Block"; "ErrorRecord" = ($_ | Out-String); "MigrationStatus"= ($MigrationOutput | Out-String) }, $null)
            [MigrationHelper]::RollBackMigration($subscriptionContext.SubscriptionId, $MigrationOutput)
            throw "Error occurred during migration. $($_.Exception)"
        }
    }

    static [void] UpdateASC([string] $SubscriptionId)
    {
        $secCenter = [SecurityCenter]::new($SubscriptionId);
        if ($secCenter) 
        {
            #calling the ASC policy method with default params i.e. without ASC security poc email and phone number
            $secCenter.SetPolicies();
        } 
    }

    static [void] SetupAzSKResources([string] $subscriptionId, [string] $location)
    {        
        $RGName = [ConfigurationManager]::GetAzSKConfigData().AzSKRGName;
        $storageAccountName = ([Constants]::StorageAccountPreName + (Get-Date).ToUniversalTime().ToString("yyyyMMddHHmmss"))
        [MigrationHelper]::StorageAccountInstance = [StorageHelper]::new($subscriptionId, $RGName, $location, $storageAccountName);
        [MigrationHelper]::StorageAccountInstance.CreateStorageContainerIfNotExists([Constants]::AttestationDataContainerName)
        [MigrationHelper]::StorageAccountInstance.CreateStorageContainerIfNotExists([Constants]::CAScanOutputLogsContainerName)
        [MigrationHelper]::StorageAccountInstance.CreateStorageContainerIfNotExists([Constants]::CAScanProgressSnapshotsContainerName)        
    }
    static [void] RollBackMigration([string] $subscriptionId, [PSObject] $MigrationOutput)
    {
        try
        {
        #delete partially created resources
        [MigrationHelper]::PersistMigrationOutput($subscriptionId, $MigrationOutput);
        }
        catch
        {
            [AIOrgTelemetryHelper]::PublishEvent("AzSK Migration Error",@{ "StageName"= "Rollback"; "ErrorRecord" = ($_ | Out-String) }, $null)
        }
    }
    static [void] MigrateStorageToLatest($SubscriptionId, $oldResourceGroupLocation)
    {
        $OldRgName = [OldConstants]::AzSDKRGName
        $storageAccounts = @();
        $storageAccounts += Get-AzureRmStorageAccount -ResourceGroupName $OldRgName -ErrorAction SilentlyContinue;
        $storageAccounts = $storageAccounts | Where-Object { $_.StorageAccountName -like "$([OldConstants]::StorageAccountPreName)*" } ;
        if(($storageAccounts | Measure-Object).Count -ne 1)
        {
            return;
        }
        #region creating new resources
        try
        {
            Write-Host ("Creating new resources...") -ForegroundColor Yellow;            
            [MigrationHelper]::SetupAzSKResources($SubscriptionId, $oldResourceGroupLocation)
            Write-Host ("Successfully completed creating new resources.") -ForegroundColor Green;
        }
        catch{
            Write-Host "An error occurred during creation of new resources. See migration log for details." -ForegroundColor Red
            [AIOrgTelemetryHelper]::PublishEvent("AzSK Migration Error",@{ "StageName"= "Resource Setup"; "ErrorRecord" = ($_ | Out-String); "MigrationStatus"= "SetupResourcesFailed"}, $null)
            $ErrorOccurred = $true;
            throw;
        }
        #endregion


        #region Step1: Migrate Storage
        $context = $storageAccounts[0].Context;

        $newRGName = [ConfigurationManager]::GetAzSKConfigData().AzSKRGName;
        $newStorageAccounts = @();
        $newStorageAccounts  += Get-AzureRmStorageAccount -ResourceGroupName $newRGName -ErrorAction SilentlyContinue;
        $newStorageAccounts = $newStorageAccounts | Where-Object { $_.StorageAccountName -like "$([Constants]::StorageAccountPreName)*" } ;
        if(($newStorageAccounts | Measure-Object).Count -ne 1)
        {
            return;
        }
        $newContext = $newStorageAccounts[0].Context;

        #region Migrate Attestation Data
        $AzSKTemp = [Constants]::AzSKAppFolderPath + "\Migration\Attestation";                
        if(-not (Test-Path "$AzSKTemp"))
        {
            mkdir -Path "$AzSKTemp" -ErrorAction Stop | Out-Null
        }
        else
        {
            Remove-Item -Path "$AzSKTemp\*" -Force -Recurse 
        }

        $attestationBlobs = Get-AzureStorageBlob -Container $([OldConstants]::AttestationDataContainerName) -Context $context -ErrorAction SilentlyContinue
        if(($attestationBlobs | Measure-Object).Count -gt 0)
        {
            $attestationBlobs | ForEach-Object {
                $blob = $_;
                $filename = "$AzSKTemp\$($blob.Name)"
                Get-AzureStorageBlobContent -Blob $_.Name -Container $([OldConstants]::AttestationDataContainerName) -Destination $filename -Context $context -Force -ErrorAction SilentlyContinue
            }
        }

        #move the stuff to new storage account
        
        #region to check if there are existing blobs in the new attestation container
        $attestationBlobs = Get-AzureStorageBlob -Container $([Constants]::AttestationDataContainerName) -Context $newContext
        if(($attestationBlobs | Measure-Object).Count -gt 0)
        {
            Write-Host "Skipping migration of attestation data. Found attestation data in new container. Migrating again can corrupt your latest attestation data." -ForegroundColor Yellow
        }
        else
        {
            $controlStateArray = Get-ChildItem -Path "$AzSKTemp"                
            $controlStateArray | ForEach-Object {
                $state = $_;
                $loopValue = 3;
                while($loopValue -gt 0)
                {
                    $loopValue = $loopValue - 1;
                    try
                    {
                        Set-AzureStorageBlobContent -File $state.FullName -Container $([Constants]::AttestationDataContainerName) -BlobType Block -Context $newContext -Force -ErrorAction Stop
                        $loopValue = 0;
                    }
                    catch
                    {
                        #eat this exception and retry
                    }
                }
            }
        }
        #endregion

        #region Migrate Central Scanning Config Data
        $AzSKTemp = [Constants]::AzSKAppFolderPath + "\Migration\CentralScanConfig";                
        if(-not (Test-Path "$AzSKTemp"))
        {
            mkdir -Path "$AzSKTemp" -ErrorAction Stop | Out-Null
        }
        else
        {
            Remove-Item -Path "$AzSKTemp\*" -Force -Recurse 
        }

        $centalScanningConfiguration = Get-AzureStorageBlob -Container $([OldConstants]::CAMultiSubScanConfigContainerName) -Context $context -ErrorAction SilentlyContinue
        #if($null -eq $centalScanningConfiguration)
        #{
        # return;
        #}

        if(($centalScanningConfiguration | Measure-Object).Count -gt 0)
        {
            $centalScanningConfiguration | ForEach-Object {
                $blob = $_;
                $filename = "$AzSKTemp\$($blob.Name)"
                Get-AzureStorageBlobContent -Blob $_.Name -Container $([OldConstants]::CAMultiSubScanConfigContainerName) -Destination $filename -Context $context -Force -ErrorAction SilentlyContinue
            }
        }

        #move the stuff to new storage account

        $configDataFiles = Get-ChildItem -Path "$AzSKTemp"                
            $configDataFiles | ForEach-Object {
                $file = $_;
                $loopValue = 3;
                while($loopValue -gt 0)
                {
                    $loopValue = $loopValue - 1;
                    try
                    {
                        Set-AzureStorageBlobContent -File $file.FullName -Container $([Constants]::CAMultiSubScanConfigContainerName) -BlobType Block -Context $newContext -Force -ErrorAction Stop
                        $loopValue = 0;
                    }
                    catch
                    {
                        #eat this exception and retry
                    }
                }
            }


        #endregion

        #region add migration tag to old storage account
        $oldStorageResource = Get-AzureRmResource -ResourceId $storageAccounts[0].Id
        $resourceTags = $oldStorageResource.Tags
        if($null -eq $resourceTags)
        {
            $resourceTags = @{}
        }
        if($resourceTags.ContainsKey("Migration"))
        {
            $resourceTags["Migration"] = [DateTime]::UtcNow.ToString("yyyyMMdd_HHmmss");
        }
        else
        {
            $resourceTags.Add("Migration",[DateTime]::UtcNow.ToString("yyyyMMdd_HHmmss"));
        }
        Set-AzureRmResource -Tag  $resourceTags -ResourceId $storageAccounts[0].Id -Force
        #endregion
        #endregion
    }

    static [void] PersistMigrationOutput([string] $subscriptionId, [PSObject] $MigrationOutput)
    {
        if($null -ne $MigrationOutput)
        {
            $temp = ($env:temp + "\AzSKTemp\");
            $fileName =  "MigrationOutput_"+ (Get-Date).ToUniversalTime().ToString("yyyyMMddHHmmss")+ ".json"
            if(-not (Test-Path -Path $temp))
            {
                mkdir -Path $temp -Force
            }
            [Helpers]::ConvertToJsonCustom($MigrationOutput) | Out-File "$temp\$fileName" -Force;
            $oldStorageAccount = Find-AzureRmResource -ResourceNameContains $([OldConstants]::StorageAccountPreName) -ResourceGroupNameEquals $([OldConstants]::AzSDKRGName) -ResourceType 'Microsoft.Storage/storageAccounts'
            if($oldStorageAccount)
            {
                $storageHelper = [StorageHelper]::new($subscriptionId,[OldConstants]::AzSDKRGName,$oldStorageAccount.Location, $oldStorageAccount.Name);
                $fileInfos = @();
                $fileInfos += [System.IO.FileInfo]::new("$temp\$fileName");
                $storageHelper.UploadFilesToBlob("migration", "", $fileInfos, $true);
            }
            #Store logs to new storage
            try{
                $newStorageRGName = [ConfigurationManager]::GetAzSKConfigData().AzSKRGName
                $newStorageAccount = Find-AzureRmResource -ResourceNameContains $([Constants]::StorageAccountPreName) -ResourceGroupNameEquals $newStorageRGName -ResourceType 'Microsoft.Storage/storageAccounts'
                if($newStorageAccount)
                {
                    $storageHelper = [StorageHelper]::new($subscriptionId,$newStorageRGName,$newStorageAccount.Location, $newStorageAccount.Name);
                    $fileInfos = @();
                    $fileInfos += [System.IO.FileInfo]::new("$temp\$fileName");
                    $storageHelper.UploadFilesToBlob("migration", "", $fileInfos, $true);
                }
            }
            catch
            {
                #Kept blank to avoid issue with posting migration logs to new storage
            }
            

            #put a lock once the migration is started
            $azsdkRGScope = "/subscriptions/$subscriptionId/resourceGroups/$([OldConstants]::AzSDKRGName)"
            New-AzureRmResourceLock -LockName "AzSKMigrationLock" -LockLevel ReadOnly -Scope $azsdkRGScope -LockNotes "Migration lock by AzSK to avoid any future edits" -Force
        }
    }
    static [void] MigrateAutomationAccountToLatest([string] $subscriptionId, [PSObject] $invocationContext, [PSObject] $vars, [string] $AzureADAppName, [int] $scanIntervalInHours)
    {
        $azskRG = "*";
        $omsWSId = "";
        $omsWSKey = "";
        $altOMSWSId = "";
        $altOMSWSKey = "";
        $wUrl = "";
        $wHeaderName = "";
        $wHeaderValue = "";
        $disableAlertRunbook ="";
        $vars | ForEach-Object{
            if($_.Name -eq [Constants]::AppResourceGroupNames)
            {
                $azskRG = $_.Value
            }
            elseif($_.Name -eq [Constants]::OMSWorkspaceId)
            {
                $omsWSId = $_.Value
            }
            elseif($_.Name -eq [Constants]::OMSSharedKey)
            {
                $omsWSKey = $_.Value
            }
            elseif($_.Name -eq [Constants]::AltOMSWorkspaceId)
            {
                $altOMSWSId = $_.Value
            }
            elseif($_.Name -eq [Constants]::AltOMSSharedKey)
            {
                $altOMSWSKey = $_.Value
            }
            elseif($_.Name -eq [Constants]::WebhookUrl)
            {
                $wUrl = $_.Value
            }
            elseif($_.Name -eq [Constants]::WebhookAuthZHeaderName)
            {
                $wHeaderName = $_.Value
            }
            elseif($_.Name -eq [Constants]::WebhookAuthZHeaderValue)
            {
                $wHeaderValue = $_.Value
            }
            elseif($_.Name -eq [Constants]::DisableAlertRunbook)
            {
                $disableAlertRunbook = $_.Value
            }                        
        }            

        $ccAccount = [CCAutomation]::new($subscriptionId, $invocationContext,`
                [ConfigurationManager]::GetAzSKConfigData().AzSKLocation, $null, $null, $azskRG,`
                $AzureADAppName, $scanIntervalInHours);
        #set the OMS settings
        $ccAccount.SetOMSSettings($omsWSId, $omsWSKey, $altOMSWSId, $altOMSWSKey);

        #set the Webhook settings
        $ccAccount.SetWebhookSettings($wUrl, $wHeaderName, $wHeaderValue);
        $ccAccount.InstallAzSKContinuousAssurance();

        #region to install the disable alertrunbook variable
        $RGName = [ConfigurationManager]::GetAzSKConfigData().AzSKRGName;
        if(-not [string]::IsNullOrWhiteSpace($disableAlertRunbook))
        {
            New-AzureRmAutomationVariable -Name $([Constants]::DisableAlertRunbook) -Value $disableAlertRunbook -Encrypted $false -ResourceGroupName $RGName -AutomationAccountName $([Constants]::AutomationAccountName) -ErrorAction Ignore
        }            
        [MigrationHelper]::SetCASPNPermissions($ccAccount);

        #endregion

    }
    static [void] MigrateAlerts([string] $subscriptionId, [PSObject] $invocationContext)
    {
        $mandatoryTags = [string]::Join(",", [ConfigurationManager]::GetAzSKConfigData().SubscriptionMandatoryTags);
        $alert = [Alerts]::new($subscriptionId, $invocationContext, $mandatoryTags);
        if ($alert) 
        {
            #calling alert method with default params i.e. without security contanct email and phone number
            $smsReceivers = $null;
            $emailReceivers = $null;
            $webhookUri = "";
            $curActionGroupResource = $alert.GetAlertActionGroup([OldConstants]::AzSDKRGName, [OldConstants]::AlertActionGroupName);
            if($curActionGroupResource)
            {
                $curActionGroupResourceData= Get-AzureRmResource -ResourceId $curActionGroupResource.ResourceId
                $emailReceivers = $curActionGroupResourceData.properties.emailReceivers
            }
            $curCriticalActionGroupResource = $alert.GetAlertActionGroup([OldConstants]::AzSDKRGName, [OldConstants]::CriticalAlertActionGroupName);
            if($curCriticalActionGroupResource)
            {
                $curCriticalActionGroupResourceData= Get-AzureRmResource -ResourceId $curCriticalActionGroupResource.ResourceId
                $smsReceivers = $curCriticalActionGroupResourceData.properties.smsReceivers
            }
            if($null -ne $emailReceivers)
            {
                $alert.SetAlerts($emailReceivers,$smsReceivers,$null);
                Find-AzureRmResource -ResourceGroupNameEquals $([OldConstants]::AzSDKRGName) -ResourceType "Microsoft.Insights/activityLogAlerts" -ErrorAction SilentlyContinue | Remove-AzureRmResource -Force -ErrorAction SilentlyContinue
                Find-AzureRmResource -ResourceGroupName $([OldConstants]::AzSDKRGName) -ResourceType "Microsoft.Insights/actiongroups" -ErrorAction SilentlyContinue | Remove-AzureRmResource -Force -ErrorAction SilentlyContinue                
                [Helpers]::SetResourceGroupTags([OldConstants]::AzSDKRGName ,@{[OldConstants]::AzSDKAlertsVersionTagName=""}, $true)
            }            
        }
        else{
            #No current alerts found
        }    
    }

    static [void] MigrateARMPolicies([string] $subscriptionId,[string] $scope, [PSObject] $invocationContext)
    {
        $oldPoliciesCount = (Get-AzureRmPolicyAssignment | Where-Object { $_.Name -like 'AzSDK*'} | Measure-Object).Count
        if($oldPoliciesCount -gt 0)
        {
            $mandatoryTags = [string]::Join(",", [ConfigurationManager]::GetAzSKConfigData().SubscriptionMandatoryTags);
            $armPolicy = [ARMPolicy]::new($subscriptionId, $invocationContext, $mandatoryTags);
            if ($armPolicy) 
            {
                #region AzSK TBR migration
                Write-Host "Checking for the presence of old policies..." -ForegroundColor Yellow
                $armPolicy.RemoveARMPolicies("AzSDK", $scope)                

                #endregion

                $armPolicy.SetARMPolicies();
            }
        }
    }

    static [void] CompleteMigration([string] $subscriptionId, [PSObject] $MigrationOutput)
    {
        #apply tag
        $tagName = [Constants]::MigrationTagName
        $resourceGroupTags = [Helpers]::GetResourceGroupTags([OldConstants]::AzSDKRGName)
        if($null -eq $resourceGroupTags)
        {
            $resourceTags = @{}
        }
        if($resourceGroupTags.ContainsKey($tagName))
        {
            $resourceGroupTags[$tagName] = [DateTime]::UtcNow.ToString("yyyyMMdd_HHmmss");
        }
        else
        {
            $resourceGroupTags.Add($tagName,[DateTime]::UtcNow.ToString("yyyyMMdd_HHmmss"));
        }
        $RGName = [ConfigurationManager]::GetAzSKConfigData().AzSKRGName;
        [Helpers]::SetResourceGroupTags($RGName,$resourceGroupTags,$false,$false)

        #set the tag on the storage account
        $resources = @();
        $resources += Find-AzureRmResource -ResourceNameContains $([Constants]::StorageAccountPreName) -ResourceGroupNameEquals $RGName -ResourceType "Microsoft.Storage/storageAccounts"
        if(($resources | Measure-Object).Count -gt 0)
        {
            [MigrationHelper]::SetMigrationTag($resources[0].ResourceId);
        }

        #set tag on automation account
        $resources = @();
        $resources += Find-AzureRmResource -ResourceNameEquals $([Constants]::AutomationAccountName) -ResourceGroupNameEquals $RGName -ResourceType "Microsoft.Automation/automationAccounts"
        if(($resources | Measure-Object).Count -gt 0)
        {
            [MigrationHelper]::SetMigrationTag($resources[0].ResourceId);                        
        }

        [MigrationHelper]::PersistMigrationOutput($subscriptionId, $MigrationOutput);            
    }

    static [void] SetMigrationTag([string] $ResourceId)
    {
        $tagName = [Constants]::MigrationTagName;
        $tagValue = [DateTime]::UtcNow.ToString("yyyyMMdd_HHmmss");
        $resourceTags = @{};
        $resourceTags.Add($tagName,$tagValue);
        [Helpers]::SetResourceTags($ResourceId, $resourceTags, $false, $true);
    }


    static [void] SetCASPNPermissions([CCAutomation] $ccAutomation)
    {
        $runAsConnection = $ccAutomation.GetRunAsConnection();
        if($runAsConnection)
        {
            $existingAppId = $runAsConnection.FieldDefinitionValues.ApplicationId                
            $ADApp = Get-AzureRmADApplication -ApplicationId $existingAppId -ErrorAction SilentlyContinue                
            if($ADApp)
            {
                #check SP permissions
                $haveRGAccess = $ccAutomation.CheckServicePrincipalRGAccess($existingAppId, [OldConstants]::AzSDKRGName, "Owner")
                #assign SP $ccAutomation
                if(!$haveRGAccess)
                {
                    $ccAutomation.SetServicePrincipalRGAccess($existingAppId, [OldConstants]::AzSDKRGName, "Owner")
                }
            }
        }
    }

    static [bool] MigrationPrerequisiteCheck($SubscriptionId)
    {        
        $IsMigrationPossible = $true
        #1. Check if Old RG present
        $OldRGResource =  Get-AzureRmResourceGroup -Name $([OldConstants]::AzSDKRGName) -ErrorAction SilentlyContinue
        if($OldRGResource)
        {
            #2. Check Permission using delete lock on old RG
            try
            {
                $azsdkRGScope = "/subscriptions/$subscriptionId/resourceGroups/AzSDKRG"
                $lock =New-AzureRmResourceLock -LockName "AzSKMigrationDeleteLock" -LockLevel CanNotDelete -Scope $azsdkRGScope -LockNotes "Migration lock by AzSK to validate permission" -Force                 
                Remove-AzureRmResourceLock -LockId $lock.LockId -Force
            }
            catch
            {
                $IsMigrationPossible = $false
                Write-Host "Please validate you have Owner permission. Try re-running command after permission confirmation. If issue still continue please reach out to support team." -ForegroundColor Red
                return $IsMigrationPossible            
            }
            # 3. Check if migration completed
            $isMigrationCompleted = [UserSubscriptionDataHelper]::IsMigrationCompleted($SubscriptionId)
            if($isMigrationCompleted -ne "COMP")
            {
                $IsMigrationPossible = $true
            }
            else
            {
                Write-Host ("WARNING: Your subscription has already been migrated from `"AzSDK`" to `"AzSK`". If you'd like to update any other aspect of subscription security (policies, alerts, ASC, CA, etc.), you can rerun this command without the '-Migrate' switch.") -ForegroundColor Yellow;                
                $IsMigrationPossible= $false
            }
        }
        else
        {
            Write-Host ("WARNING: No AzSDK-based assets found in the subscription. Migration does not apply. You can use the AzSK module directly.") -ForegroundColor Yellow;
            $IsMigrationPossible = $false
        }        
        return $IsMigrationPossible
    }
}

[MigrationHelper]::StartMigration($SubscriptionContext, $InvocationContext, $AzureADAppName)