Optimization of environmental costs in Azure. Disks. #01
Tags: azure, powershell, costs
Published: 2021-04-26 14:50:02

The greater the environment, the more likely some resources are abandoned and unused. You know, someone requested a virtual machine, app service, but it turned out that it is unnecessary. Or some project or PoC finished and test resources are not removed. Due to this, it is important to look at your resources and check if can be removed or resized for example.

If you have virtual machines in your Azure environment, it's always good to check some things related to disks. In this post, you can see how easy to check if some disks are not attached or if on some virtual machines disk space is unallocated.

Checking if some disks are orphaned you can do with the below Powershell command:
```ps1
$existingDisks = Get-AzDisk

Write-Output "`nUnattached disks:"
foreach ($disk in $existingDisks) {
    If ($disk.DiskState.Contains('Unattached')) {
        $disk.Name
    }
}

```

`Get-AzDisk` gets all disks in the current subscription. Each disk has the property **DiskState** which can tell you if the disk is attached to some virtual machine or not. The above script checks if the **DiskState** property has value *Unattached* which means that it isn't connected to any VM.

Another thing is that the disk can be connected to the virtual machine, but it isn't initialized on the OS level. How to check that? It's a more complex operation. You can't do that from the Azure perspective, you have to check disk statuses directly on the OS. But relax, you don't have to log into each virtual machine and check that manually. Let's use the **Run Command** interface. There are a few ways to [run custom scripts directly on virtual machine](https://docs.microsoft.com/en-us/azure/virtual-machines/windows/run-scripts-in-vm), each of them has its own pros and cons. **Run Command** will be the best option for us.

I prepared a small script which will be run through **Run Command** interface on the virtual machine. Here it is:
```ps1
$disksInfo = Get-Disk

foreach ($disk in $disksInfo) {
    If ($disk.PartitionStyle.Contains('RAW')) {
        Write-Output $true
    }
}
```

Important information is that the disk with the unallocated space has something called [**PartitionStyle** with value *RAW*](https://docs.microsoft.com/en-us/answers/questions/144362/how-to-get-unallocated-data-disk-details-from-os-l.html). The above script takes info about all physical disks in the machine and checks if any of those disks have **PartitionStyle** status equal *RAW*.

The process is: get info about all virtual machines in the subscription with the information if the virtual machine is running, run on each of them the custom script, aggregate info about the statuses of calling **Run Command** with the custom script, and show the list of virtual machines with unallocated spaces. The below scripts realize that process:
```ps1
# List of vms
$vms = Get-AzVm -Status
$vmsToCheck = @()

# List of VMs with unallocated disks
foreach ($vm in $vms) {
    If ($vm.PowerState.Contains('VM running') -and $vm.StorageProfile.DataDisks.Length -gt 0) {
        $vmsToCheck += $vm
    }
}

foreach ($vm in $vmsToCheck) {
    $scriptBlock = {
        $runOutput = Invoke-AzVMRunCommand -ResourceId $args[0].Id -CommandId 'RunPowerShellScript' -ScriptPath '.\Test-IfVmHasUnallocatedDisks.ps1'
        If ($runOutput.Value[0].Message.Contains('True')) {
            return $args[0].Name
        }
    }

    $jobName = "$($vm.Name)-DisksCheck"

    $job = Start-Job -ScriptBlock $scriptBlock -ArgumentList $vm -Name $jobName
    $jobs += $job
}

Write-Host -NoNewline "`nChecking unallocated disks"
while ((Get-Job -Name "*-DisksCheck" | Where-Object State -eq Running)) {
    Write-Host -NoNewline "."
    Start-Sleep -Seconds 2
}

Write-Output "`nVMs with unallocated disks:"
Get-Job | Receive-Job
```

Small hack in the script above - calling **Run Command** takes quite a long time, so I'm running checking for chosen machines in parallel and after that, I'm waiting for when all jobs will be done.

[Original post](https://wachulec.me/posts/optimization-of-environmental-costs-disks-vol-01/) you can always find on [my blog](https://wachulec.me/)!