Cloud/Azure.ps1
# This funtion for using existing az contex if avalable else get new context from azure by browser autontication function Connect-AzureAccount { param ( [Parameter(Mandatory = $true)] [string]$TenantId, [Parameter(Mandatory = $true)] [string]$SubscriptionId, [switch]$Force ) try { $currentContext = Get-AzContext if ($Force) { Write-GsLog "Forcefully. Initiating login..." Action $out = Connect-AzAccount -Tenant $TenantId -Subscription $SubscriptionId -ErrorAction Stop Write-GsLog "Connected to Azure with tenant $TenantId and subscription $SubscriptionId." Info } elseif ( (-not $currentContext) -or $currentContext.Tenant.Id -ne $TenantId ) { Write-GsLog "No Azure context found. Initiating login..." Action $out = Connect-AzAccount -Tenant $TenantId -Subscription $SubscriptionId -ErrorAction Stop Write-GsLog "Connected to Azure with tenant $TenantId and subscription $SubscriptionId." Info } elseif ($currentContext.Tenant.Id -eq $TenantId -and $currentContext.Subscription.Id -ne $SubscriptionId) { Write-GsLog "Authenticated with correct tenant ($($currentContext.Tenant.Name)), but using a different subscription ($($currentContext.Subscription.Name))." Debug Write-GsLog "Switching Azure subscription to $SubscriptionId..." Action Set-AzContext -SubscriptionId $SubscriptionId -ErrorAction Stop $out = Get-AzContext Write-GsLog "Azure subscription context switched to $SubscriptionId." Info } else { Write-GsLog "Azure context already matches the specified tenant and subscription. Reusing current session." Info } return $out } catch { Write-GsLog "Failed to connect or set Azure context: $($_.Exception.Message)" Error exit 1 } } # this function will get vms list and their disk function Get-AzureVmAndDisk { param ( [Parameter(Mandatory = $true)] [string[]]$VmNames ) if (-not $VmNames -or $VmNames.Count -eq 0) { Write-GsLog "No VM names provided." Error return } Write-GsLog "Getting VM and disk list from Azure..." Info try { $vmList = Get-AzVM $diskList = Get-AzDisk Write-GsLog "Filtering VMs and their associated disks..." Debug $selectedVms = $vmList | Where-Object { $_.Name -in $VmNames } if (-not $selectedVms -or $selectedVms.Count -eq 0) { Write-GsLog "Unable to find any VMs matching the provided names: $($VmNames -join ', ')." Error return } $selectedVmIds = $selectedVms.Id $associatedDisks = $diskList | Where-Object { $_.ManagedBy -in $selectedVmIds } Write-GsLog "Found $($selectedVms.Count) VM(s) and $($associatedDisks.Count) associated disk(s)." Info return [PSCustomObject]@{ VMs = $selectedVms Disks = $associatedDisks } } catch { Write-GsLog "Failed to get VM or disk information: $($_.Exception.Message)" Error return } } # This function will help to get the vm information along with it's disk and Nic information function Get-AzureVmFullInfo { param ( [string[]]$VmName, [string]$ResourceGroupName ) try { Write-GsLog "Fetching Azure VM details..." Info # Retrieve all VMs or filter by resource group $allVms = if ($ResourceGroupName) { Get-AzVM -ResourceGroupName $ResourceGroupName } else { Get-AzVM } # Filter by VM name if specified $filteredVms = if ($VmName) { $allVms | Where-Object { $_.Name -in $VmName } } else { $allVms } if (-not $filteredVms -or $filteredVms.Count -eq 0) { Write-GsLog "No matching VMs found." Warning return } $vmDetailsList = foreach ($vm in $filteredVms) { $vmStatus = Get-AzVM -ResourceGroupName $vm.ResourceGroupName -Name $vm.Name -Status # Get disk info $osDiskName = $vm.StorageProfile.OSDisk.Name $dataDiskNames = $vm.StorageProfile.DataDisks.Name $allDiskNames = @($osDiskName) + $dataDiskNames $disks = $allDiskNames | ForEach-Object { Get-AzDisk -ResourceGroupName $vm.ResourceGroupName -DiskName $_ } # Get NICs $nicIds = $vm.NetworkProfile.NetworkInterfaces.Id $nics = $nicIds | ForEach-Object { Get-AzNetworkInterface -ResourceId $_ } # Build NIC and IP details $nicDetails = foreach ($nic in $nics) { $ipConfigs = $nic.IpConfigurations | ForEach-Object { [PSCustomObject]@{ PrivateIpAddress = $_.PrivateIpAddress PublicIpAddress = if ($_.PublicIpAddress) { (Get-AzPublicIpAddress -ResourceGroupName $vm.ResourceGroupName -Name ($_.PublicIpAddress.Id.Split('/')[-1])).IpAddress } else { $null } Subnet = $_.Subnet.Id.Split('/')[-1] Vnet = $_.Subnet.Id.Split('/')[-3] } } [PSCustomObject]@{ NicName = $nic.Name IpConfigs = $ipConfigs Nsg = if ($nic.NetworkSecurityGroup) { (Get-AzNetworkSecurityGroup -ResourceGroupName $vm.ResourceGroupName -Name ($nic.NetworkSecurityGroup.Id.Split('/')[-1])).Name } else { $null } } } # Return full VM info [PSCustomObject]@{ Name = $vm.Name ResourceGroup = $vm.ResourceGroupName Location = $vm.Location VmSize = $vm.HardwareProfile.VmSize OSType = $vm.StorageProfile.OSDisk.OsType ComputerName = $vm.OsProfile.ComputerName ProvisionState = $vmStatus.ProvisioningState PowerState = ($vmStatus.Statuses | Where-Object { $_.Code -like 'PowerState/*' }).DisplayStatus Disks = $disks Nics = $nicDetails } } return $vmDetailsList } catch { Write-GsLog "Failed to retrieve VM details: $($_.Exception.Message)" Error return } } # This function will create snapshot from disk function ConvertTo-AzureDiskToSnapshot { param ( [Parameter(Mandatory = $true)] [Object[]]$Disk, [string]$Location = 'CentralIndia' ) $OutputSnapshots = @() foreach ($currentDisk in $Disk) { $snapshotName = "snapshot_$($currentDisk.Name)_$(Get-Date -Format 'yyyy_MM_dd')_vhd" $resourceGroup = $currentDisk.ResourceGroupName try { # Check for existing snapshot $existingSnapshot = Get-AzSnapshot -SnapshotName $snapshotName -ResourceGroupName $resourceGroup -ErrorAction SilentlyContinue # Create snapshot config $snapshotConfig = New-AzSnapshotConfig -SourceUri $currentDisk.Id -Location $Location -CreateOption Copy if (-not $existingSnapshot) { Write-GsLog "Creating snapshot for disk '$($currentDisk.Name)' as '$snapshotName'" Action $newSnapshot = New-AzSnapshot -Snapshot $snapshotConfig -SnapshotName $snapshotName -ResourceGroupName $resourceGroup } else { Write-GsLog "Snapshot '$snapshotName' already exists. Updating it instead." Warning $newSnapshot = Update-AzSnapshot -Snapshot $existingSnapshot -SnapshotName $snapshotName -ResourceGroupName $resourceGroup -Verbose } $OutputSnapshots += $newSnapshot } catch { Write-GsLog "Failed to create or update snapshot for disk '$($currentDisk.Name)': $($_.Exception.Message)" Error } } return $OutputSnapshots } # This func will remove the snapshot which are provided function Remove-AzureSnapshot { param ( [Parameter(Mandatory = $true)] [object[]]$Snapshot ) foreach ($snap in $Snapshot) { try { $snapName = $snap.Name $resourceGroup = $snap.ResourceGroupName Write-GsLog "Revoking access for snapshot '$snapName'" Info Revoke-AzSnapshotAccess -SnapshotName $snapName -ResourceGroupName $resourceGroup Write-GsLog "Deleting snapshot '$snapName' in resource group '$resourceGroup'" Action Remove-AzSnapshot -SnapshotName $snapName -ResourceGroupName $resourceGroup -Force Write-GsLog "Successfully deleted snapshot '$snapName'" Success } catch { Write-GsLog "Failed to delete snapshot '$($snap.Name)': $($_.Exception.Message)" Error } } } # To enable public assess of the snapshot function Enable-AzureSnapshotPublicAccess { param ( [Parameter(Mandatory = $true)] [string]$SnapshotName, [Parameter(Mandatory = $true)] [string]$ResourceGroupName ) try { Write-GsLog "Checking current network access setting for snapshot '$SnapshotName'" Info $snapshot = Get-AzSnapshot -SnapshotName $SnapshotName -ResourceGroupName $ResourceGroupName if ($snapshot.PublicNetworkAccess -eq 'Enabled') { Write-GsLog "Public network access is already enabled for snapshot '$SnapshotName'" Success return } Write-GsLog "Enabling public network access for snapshot '$SnapshotName'" Action $uri = "/subscriptions/$($snapshot.Id.Split('/')[2])/resourceGroups/$ResourceGroupName/providers/Microsoft.Compute/snapshots/$SnapshotName?api-version=2022-03-02" $payload = @{ properties = @{ publicNetworkAccess = 'Enabled' } } | ConvertTo-Json -Depth 5 Invoke-AzRestMethod -Method PATCH -Path $uri -Payload $payload Write-GsLog "Public access successfully enabled for snapshot '$SnapshotName'" Success } catch { Write-GsLog "Failed to enable public access: $($_.Exception.Message)" Error } } # This function will help to send the snapshot to any storage account (even when inter Tenant) function Send-AzureSnapshotsToStorage { param ( [Parameter(Mandatory = $true)] [object[]]$Snapshot, [Parameter(Mandatory = $true)] [string]$StorageAccountName, [Parameter(Mandatory = $true)] [string]$StorageAccountKey, [Parameter(Mandatory = $true)] [string]$ContainerName, [int]$TimeOutSec = 86400, [switch]$WaitForComplete ) try { Write-GsLog "Creating storage context for '$StorageAccountName'" Info $context = New-AzStorageContext -StorageAccountName $StorageAccountName -StorageAccountKey $StorageAccountKey } catch { Write-GsLog "Failed to create storage context: $($_.Exception.Message)" Error return } $blobNames = @() foreach ($snap in $Snapshot) { try { $snapName = $snap.Name $resourceGroup = $snap.ResourceGroupName if ($snapshot.PublicNetworkAccess -ne 'Enabled') { Write-GsLog "Public network access is not enabled for snapshot '$($snapName)'" Warning Write-GsLog "Enabling public network access for snapshot '$( $snapName)'" Action Enable-AzureSnapshotPublicAccess -SnapshotName $snapName -ResourceGroupName $resourceGroup } Write-GsLog "Generating SAS URL for snapshot '$snapName'" Debug $sas = Grant-AzSnapshotAccess -ResourceGroupName $resourceGroup -SnapshotName $snapName -DurationInSecond $TimeOutSec -Access Read Write-GsLog "Starting blob copy for snapshot '$snapName' to container '$ContainerName'" Action $copyResult = Start-AzStorageBlobCopy -AbsoluteUri $sas.AccessSAS -DestContainer $ContainerName -DestContext $context -DestBlob $snapName $blobNames += $snapName } catch { Write-GsLog "Failed to start copy for snapshot '$($snap.Name)': $($_.Exception.Message)" Error } } if ($WaitForComplete) { Write-GsLog "Monitoring snapshot copy progress..." Info $inProgress = $true while ($inProgress) { $inProgress = $false foreach ($blobName in $blobNames) { $copyState = Get-AzStorageBlobCopyState -Blob $blobName -Container $ContainerName -Context $context if ($copyState.Status -ne "Success") { $inProgress = $true $percent = if ($copyState.TotalBytes -gt 0) { [math]::Round(100 * $copyState.BytesCopied / $copyState.TotalBytes, 2) } else { 0 } Write-GsLog "Snapshot '$blobName' copy status: $($copyState.Status) - $percent% completed" Debug } else { Write-GsLog "Snapshot '$blobName' copy completed successfully" Success } Write-GsLog "`n`n`n" Debug } if ($inProgress) { Start-Sleep -Seconds 10 } } } Write-GsLog "Fetching blob references from container '$ContainerName'" Info $blobs = @() foreach ($blobName in $blobNames) { try { $blob = Get-AzStorageBlob -Blob $blobName -Container $ContainerName -Context $context if ($blob) { $blobs += $blob.ICloudBlob } } catch { Write-GsLog "Failed to retrieve blob '$blobName': $($_.Exception.Message)" Warning } } return $blobs } function Invoke-AzureVmDiskToStorageAsSnapshotBlob { [CmdletBinding()] param ( [Parameter(Mandatory = $false)] [string]$TenantId = (Read-Host "Provide the source VM tenant ID"), [Parameter(Mandatory = $false)] [string]$SubscriptionId = (Read-Host "Provide the source VM subscription ID"), [Parameter(Mandatory = $false)] [string[]]$VmName = ((Read-Host "Provide source VM names (comma-separated)").Split(',') | ForEach-Object { $_.Trim() }), [Parameter(Mandatory = $false)] [string]$StorageAccountName = (Read-Host "Provide the destination Storage Account name"), [Parameter(Mandatory = $false)] [string]$ContainerName = (Read-Host "Provide the destination Container name"), [Parameter(Mandatory = $false)] [string]$StorageAccountKey = (Read-Host "Provide the destination Storage Account key") ) try { Write-GsLog "Authenticating to Azure with Tenant: $TenantId and Subscription: $SubscriptionId" Action Connect-GsAzureAccount -TenantId $TenantId -SubscriptionId $SubscriptionId -Force } catch { Write-GsLog "Failed to authenticate to Azure: $($_.Exception.Message)" Error return } try { Write-GsLog "Fetching VM information for: $($VmName -join ', ')" Info $vmInfo = Get-GsAzureVmFullInfo -VmName $VmName if (-not $vmInfo -or -not $vmInfo.Disks) { Write-GsLog "No disks found for the specified VMs." Error return } } catch { Write-GsLog "Error fetching VM information: $($_.Exception.Message)" Error return } try { Write-GsLog "Creating snapshots from attached disks..." Info $snapshots = ConvertTo-GsAzureDiskToSnapshot -Disk $vmInfo.Disks if (-not $snapshots -or $snapshots.Count -eq 0) { Write-GsLog "No snapshots were created." Error return } } catch { Write-GsLog "Error creating snapshots: $($_.Exception.Message)" Error return } try { Write-GsLog "Starting snapshot copy to storage account '$StorageAccountName' in container '$ContainerName'" Info $blobs = Send-GsAzureSnapshotsToStorage -Snapshot $snapshots -StorageAccountName $StorageAccountName -ContainerName $ContainerName -StorageAccountKey $StorageAccountKey -WaitForComplete Write-GsLog "Snapshots successfully transferred. Total blobs: $($blobs.Count)" Success } catch { Write-GsLog "Snapshot copy failed: $($_.Exception.Message)" Error } try { Write-GsLog "Starting deletion of temporary snapshots..." Warning foreach ($snap in $snapshots) { Write-GsLog "Deleting snapshot '$($snap.Name)' in resource group '$($snap.ResourceGroupName)'" Action } Remove-GsAzureSnapshot -Snapshot $snapshots Write-GsLog "All snapshots successfully deleted." Success } catch { Write-GsLog "Snapshot deletion failed: $($_.Exception.Message)" Error } return $blobs } Export-ModuleMember -Function '*' |