PowerShell - Azure Delete Reserved disks over 90 days - azure

i am facing a mission in my work and she goes like this:
We have disks in our Azure account that they are attached to stopped and stopped(deallocated) vms. if am saying right they called Reserved disks.
The problem that we are still charged for this disks, i need your help with a PowerShell Script to look for this disks over xx days and than delete them.
my script for now looks like this.. please anyone that expert in PowerShell can help me here?
*** UPDATE - The mission i got have changed to list all the vms that are in status deallocated over xx days and than remove the disks that related to them.
# Get orphan managed disks
$managedDisks = Get-AzDisk
foreach ($md in $managedDisks) {
if (($md.ManagedBy -eq $null) -and ($md -notlike '*-ASRReplica')) {
$md | Remove-AzDisk -Force -verbose
}
}
Thank you all !!!

Per my understanding, you already get the way to filter all managed disks that have not been appended to a VM. And now, you want to know how to filter all managed disks that have not been used for 30 days.
For this requirement, we can query disk metrics: if a disk has been used in 30 days, there should be some metrics data(i,e read bytes and write bytes):
and if it has not been used, its metrics data in this period of time should be empty. So we can use PowerShell below to check:
#check disk read and write metrics log for each hour in past 30 days
$now = Get-Date -AsUtc
$m = Get-AzMetric `
-ResourceId '<managed disk resource ID>' `
-StartTime $now.AddDays(-30) `
-EndTime $now `
-TimeGrain 01:00:00 `
-MetricName 'Composite Disk Read Bytes/sec','Composite Disk Write Bytes/sec'
$readMetricsRecord = $m[0].Data
$writeMetricsRecord = $m[1].Data
if($readMetricsRecord.length -eq 0 -and $writeMetricsRecord.length -eq 0){
echo 'this disk has no usage record'
}else{
echo 'this disk has been used'
}

sharing with you the script guys , Get the vms in deallocated state over X days than , if they have a disk that is over X GB tag the vm and the disk .
$ids = New-Object System.Collections.ArrayList
$mergedTags = #{"Candidate"="Delete Me"}
$vms = (Get-AzVM -Status)
foreach ($vm in $vms ) {
$getStatuses = Get-AzVM -ResourceGroupName $vm.ResourceGroupName -Name $vm.Name -Status
$getTodaysDate = Get-Date
$ts = New-TimeSpan -Start (($getStatuses.Statuses).Time).DateTime -End $getTodaysDate
[bool]$flag = 0
if (($vm.PowerState -eq "VM deallocated") -AND ($ts.Days -gt 30)) {
$ids.Add($vm.Id)
foreach ($disk in $getStatuses.Disks.Name) {
$diskSize = Get-AzDisk -ResourceGroupName $vm.ResourceGroupName -Name $disk
if ($diskSize.DiskSizeGB -gt 50) {
$flag = 1
$ids.Add($diskSize.Id)
if ($flag = 1) {
Update-AzTag -ResourceId $vm.Id -Tag $mergedTags -Operation Merge
Update-AzTag -ResourceId $diskSize.Id -Tag $mergedTags -Operation Merge
}
}
}
}
}
}

Related

Azure Powershell Question for Virtual Machine

I am reviewing a script that is supposed to delete a vm along with all of the resources attributed to the vm
Write-Host -NoNewline -ForegroundColor Green "Please enter the VM name you would like to remove:"
$VMName = Read-Host
$vm = Get-AzVm -Name $VMName
if ($vm) {
$RGName=$vm.ResourceGroupName
Write-Host -ForegroundColor Cyan 'Resource Group Name is identified as-' $RGName
#boot diagnostics container auto generated in storage account. Auto delete this storageURI property
$diagSa = [regex]::match($vm.DiagnosticsProfile.bootDiagnostics.storageUri, '^http[s]?://(.+?)\.').groups[1].value
Write-Host -ForegroundColor Cyan 'Marking Disks for deletion...'
$tags = #{"VMName"=$VMName; "Delete Ready"="Yes"}
$osDiskName = $vm.StorageProfile.OSDisk.Name
$datadisks = $vm.StorageProfile.DataDisks
$ResourceID = (Get-Azdisk -Name $osDiskName).id
New-AzTag -ResourceId $ResourceID -Tag $tags | Out-Null
if ($vm.StorageProfile.DataDisks.Count -gt 0) {
foreach ($datadisks in $vm.StorageProfile.DataDisks){
$datadiskname=$datadisks.name
$ResourceID = (Get-Azdisk -Name $datadiskname).id
New-AzTag -ResourceId $ResourceID -Tag $tags | Out-Null
}
}
if ($vm.Name.Length -gt 9){
$i = 9
}
else
{
$i = $vm.Name.Length - 1
}
$azResourceParams = #{
'ResourceName' = $VMName
'ResourceType' = 'Microsoft.Compute/virtualMachines'
'ResourceGroupName' = $RGName
}
$vmResource = Get-AzResource #azResourceParams
$vmId = $vmResource.Properties.VmId
$diagContainerName = ('bootdiagnostics-{0}-{1}' -f $vm.Name.ToLower().Substring(0, $i), $vmId)
$diagSaRg = (Get-AzStorageAccount | where { $_.StorageAccountName -eq $diagSa }).ResourceGroupName
$saParams = #{
'ResourceGroupName' = $diagSaRg
'Name' = $diagSa
}
Write-Host -ForegroundColor Cyan 'Removing Boot Diagnostic disk..'
if ($diagSa){
Get-AzStorageAccount #saParams | Get-AzStorageContainer | where {$_.Name-eq $diagContainerName} | Remove-AzStorageContainer -Force
}
else {
Write-Host -ForegroundColor Green "No Boot Diagnostics Disk found attached to the VM!"
}
Write-Host -ForegroundColor Cyan 'Removing Virtual Machine-' $VMName 'in Resource Group-'$RGName '...'
$null = $vm | Remove-AzVM -Force
Write-Host -ForegroundColor Cyan 'Removing Network Interface Cards, Public IP Address(s) used by the VM...'
foreach($nicUri in $vm.NetworkProfile.NetworkInterfaces.Id) {
$nic = Get-AzNetworkInterface -ResourceGroupName $vm.ResourceGroupName -Name $nicUri.Split('/')[-1]
Remove-AzNetworkInterface -Name $nic.Name -ResourceGroupName $vm.ResourceGroupName -Force
foreach($ipConfig in $nic.IpConfigurations) {
if($ipConfig.PublicIpAddress -ne $null){
Remove-AzPublicIpAddress -ResourceGroupName $vm.ResourceGroupName -Name $ipConfig.PublicIpAddress.Id.Split('/')[-1] -Force
}
}
}
Write-Host -ForegroundColor Cyan 'Removing OS disk and Data Disk(s) used by the VM..'
Get-AzResource -tag $tags | where{$_.resourcegroupname -eq $RGName}| Remove-AzResource -force | Out-Null
Write-Host -ForegroundColor Green 'Azure Virtual Machine-' $VMName 'and all the resources associated with the VM were removed sucessfully...'
}
else{
Write-Host -ForegroundColor Red "The VM name entered doesn't exist in your connected Azure Tenant! Kindly check the name entered and restart the script with correct VM name..."
}
I had a question: what does this block of code exactly do:
$diagSa = [regex]::match($vm.DiagnosticsProfile.bootDiagnostics.storageUri, '^http[s]?://(.+?)\.').groups[1].value
I know it matches the storage uri, but how? And why is this needed? I am not sure what the .groups[1].value is referring to either
$diagSa =
[regex]::match($vm.DiagnosticsProfile.bootDiagnostics.storageUri,
'^http[s]?://(.+?).').groups[1].value
I know it matches the storage uri, but how?
You are using the [regex] type accelerator & match method () in the above expression.
The Match() method is a way to instruct PowerShell to attempt to match a string inside of another string. The Match() method has two parameters; the string you'd like to match on and the regular expression you'd like to test against.
Whenever a match is found and a regex group is used; (), the [regex] type accelerator has a Captures property. This Captures property then has a property called Groups. This is a collection that contains lots of attributes of what was matched. The second element in that collection contains the actual value that was matched.
what the .groups[1].value is referring to either
groups[1].values returns the storage account name where the boot diagnostics container resides.
And why is this needed?
When creating an Azure VM, you always have the option of creating a boot diagnostics container. This is useful to troubleshooting VM boot issues but doesn’t get removed when a VM is deleted. Let’s remedy that.
To remove the boot diagnostics container, you first need to figure out the name of the storage account the container resides on. To find that storage account, you’ll have to do some parsing of the storageUri property that’s exists in the DiagnosticsProfile object on the VM.
for more information about [regex]::match().group[1].value expression refer the below blog :
https://mcpmag.com/articles/2015/09/30/regex-groups-with-powershell.aspx

Best way to retrieve CPU utilization for all VMs in a Azure subscription

Trying to get the CPU utilization (and preferably network as well. I would love to get RAM too, but as i understand that requires having the guest module installed to get those metrics. so at this point i just need the metrics at the 'host' level).
Idea is to run this against all VMs in a subscription, to get VM name, VM resource group, CPU utilization over the last x days, network in over the last x days, and network out over the last x days.
The first thing I tried though, using the "Get-AzureRMMetric", starts giving errors.
I type "get-azurermmetric", and am prompted for a resource ID. I enter the resource ID of the VM, and the response i get is a long string of warnings, and exception types, that an invalid status code 'notfound' was returned.
Any ideas?
First, you need to determine which metrics are supported for vm, use the following code:
(Get-AzureRmMetricDefinition -ResourceId "vm resource id").name
Then you can see the supported metrics(Just ignore the warning message):
As per your question, I think you need "Percentage CPU" / "Network In" / "Network Out".
Then you can use the sample code below for your purpose(you can make some changes if it does not meet your need):
#get all vms in a resource group, but you can remove -ResourceGroupName "xxx" to get all the vms in a subscription
$vms = Get-AzureRmVM -ResourceGroupName "xxx"
#get the last 3 days data
#end date
$et=Get-Date
#start date
$st=$et.AddDays(-3)
#define an array to store the infomation like vm name / resource group / cpu usage / network in / networkout
$arr =#()
foreach($vm in $vms)
{
#define a string to store related infomation like vm name etc. then add the string to an array
$s = ""
#percentage cpu usage
$cpu = Get-AzureRmMetric -ResourceId $vm.Id -MetricName "Percentage CPU" -DetailedOutput -StartTime $st `
-EndTime $et -TimeGrain 12:00:00 -WarningAction SilentlyContinue
#network in
$in = Get-AzureRmMetric -ResourceId $vm.Id -MetricName "Network In" -DetailedOutput -StartTime $st `
-EndTime $et -TimeGrain 12:00:00 -WarningAction SilentlyContinue
#network out
$out = Get-AzureRmMetric -ResourceId $vm.Id -MetricName "Network Out" -DetailedOutput -StartTime $st `
-EndTime $et -TimeGrain 12:00:00 -WarningAction SilentlyContinue
# 3 days == 72hours == 12*6hours
$cpu_total=0.0
$networkIn_total = 0.0
$networkOut_total = 0.0
foreach($c in $cpu.Data.Average)
{
#this is a average value for 12 hours, so total = $c*12 (or should be $c*12*60*60)
$cpu_total += $c*12
}
foreach($i in $in.Data.total)
{
$networkIn_total += $i
}
foreach($t in $out.Data.total)
{
$networkOut_total += $t
}
# add all the related info to the string
$s = "VM Name: " + $vm.name + "; Resource Group: " + $vm.ResourceGroupName + "; CPU: " +$cpu_total +"; Network In: " + $networkIn_total + "; Network Out: " + $networkOut_total
# add the above string to an array
$arr += $s
}
#check the values in the array
$arr
The test result:
Space
Is that we can able to fetch maximum usage on CPU with date using same script,
i have used to did below changes like call Maximum ...no luck..i hope some condition need to do you have solution for that
foreach($c in $cpu.Data.Maximum)
{
#this is a average value for 12 hours, so total = $c*12 (or should be $c*12*60*60)
$cpu_total += $c*12
#($c|measure -maximum).maximum
}

Is it possible to use Azure Automation Runbook to delete another Runbook output (an Azure File share snapshot)?

I want to use the runbook to delete another runbook output (an Azure File Share snapshot).
Is it possible? If you know something, please write something at here
Runbook 1: Create an Azure File share snapshot
$context = New-AzureStorageContext -StorageAccountName -StorageAccountKey
$share = Get-AzureStorageShare -Context
$context -Name "sharefile"
$snapshot = $share.Snapshot()
Runbook 2: Delete the Azure runbook output. The problem with this is that it deletes all snapshots rather than just delete the one created by the first runbook.
$allsnapshots = Get-AzureStorageShare -Context $context | Where-Object { $_.Name -eq "sharefile" -and $_.IsSnapshot -eq $true }
foreach($snapshot in $allsnapshots){
if($snapshot.SnapshotTime -lt (get-date).Add·Hours()){
$snapshot.Delete()
}
}
The sample code is as below, I test it in runbook and works well(create a snapshot, and then delete it after 3 minutes), and the other snapshots have no effect.
code in my powershell runbook:
param(
[string]$username,
[string]$password,
[string]$filesharename
)
$context = New-AzureStorageContext -StorageAccountName $username -StorageAccountKey $password
$share = Get-AzureStorageShare -Context $context -Name $filesharename
$s = $share.snapshot()
#get the snapshot name, which is always a UTC time formated value
$s2= $s.SnapshotQualifiedStorageUri.PrimaryUri.ToString()
#the $snapshottime is actually equal to snapshot name
$snapshottime = $s2.Substring($s2.IndexOf('=')+1)
write-output "create a snapshot"
write-output $snapshottime
#wait 180 seconds, then delete the snapshot
start-sleep -s 180
write-output "delete the snapshot"
$snap = Get-AzureStorageShare -Context $context -SnapshotTime $snapshottime -Name $filesharename
$snap.Delete()
write-output "deleted successfully after 3 minutes"
after it's running, you can see the snapshot is created in azure portal:
After it completes, the specified snapshot is deleted(you may need to open a new webpage to see the change due to some cache issue)
the output in runbook:

How to delete managed disk snapshot every 10 minutes

I have the below script which I am using in order to delete snapshot older then 10 minutes and retain the snapshot that are not older then 10minutes, I have the below script but its not working as it suppose to, can anyone tell me whats being going wrong?
foreach($snapname in $snapshotnames)
{
Get-AzureRmSnapshot -ResourceGroupName $rg -SnapshotName $snapname |?{$_.Name -Like "*-Server1*"} | ?{($_.TimeCreated).ToString('yyyyMMdd') -lt ([datetime]::Now.AddMinutes(-10).tostring('yyyymmdd'))} | remove-azurermsnapshot -force
}
You should use [datetime]::UtcNow instead of [datetime]::Now and not use .tostring('yyyymmdd').
So your command should be:
foreach($snapname in $snapshotnames)
{
Get-AzureRmSnapshot -ResourceGroupName $rg -SnapshotName $snapname | ?{$_.Name -Like "*-Server1*"} | ?{($_.TimeCreated) -lt ([datetime]::UtcNow.AddMinutes(-10))} | remove-azurermsnapshot -force
}
My specific test command:
Get-AzureRmSnapshot -ResourceGroupName "<ResourceGroupName>" -SnapshotName "<SnapshotName>" | ?{($_.TimeCreated) -lt ([datetime]::UtcNow.AddMinutes(-10))} | remove-azurermsnapshot -force
Result screenshot:

Is there an Azure powershell cmdlet to get cores, cpu of an ARM VM in a subscription

I am trying to get the list of ARM VM's in a subscription using Get-AzureRmVM and their instance sizes using the HardwareProfile.VmSize object. Is there a way to get the #of Cpu, #of Cores etc. for each vm using a cmdlet ( like in classic using the Get-AzureRoleSize cmdlet) ?
Do you mean use command to get information like this?
PS C:\User> $size = (Get-AzureRmVM -ResourceGroupName ubuntu -Name vm1).HardwareProfile.VmSize
PS C:\Users> get-azurermvmsize -location eastus | ?{ $_.name -eq $size }
Name NumberOfCores MemoryInMB MaxDataDiskCount OSDiskSizeInMB ResourceDiskSizeInMB
---- ------------- ---------- ---------------- -------------- --------------------
Standard_DS1_v2 1 3584 2 1047552 7168
Here the complete solution if you want to get the Total Cores of multiple VMs:
# Calculating total Amount of Cores
Write-Output "Calculating the total Cores of VMs ..."
try {
$TotalCores = $null
$Location = "westeurope"
$Cores = $null
$TotalVMs = (Get-AzVM -Status | Where-Object { $_.ProvisioningState -eq "Succeeded" }) | Sort-Object -Property Name
foreach ($VM in $TotalVMs) {
Write-Output "Checking $($Vm.Name) ..."
$VMSize = (Get-AzVM -Name $VM.Name).HardwareProfile.VmSize
$Cores = (Get-AzVMSize -location $Location | Where-Object { $_.name -eq $VMSize }).NumberOfCores
$TotalCores += $Cores
}
Write-Output "Wow! Found '$TotalCores' Cores ..."
}
catch {
$ErrorMsg = "[ERROR] while calculating the total CPU Cores: $($_.Exception.Message)!"
Write-Error -Message $ErrorMsg
}

Resources