VMware Cloud Community
virtualtech_wor
Enthusiast
Enthusiast
Jump to solution

Orphaned VMDK Script - calculate total orphaned space

Hi,

This is the script I'm currently using. (I'm not copying here the complete version that includes like parameters, logging etc)

I'm using $orphanSize += $fileResult.FileSize to find the total orphaned space ($totalorphanedspace) on specific vCenter. However, the total that I'm getting using $totalorphanedspace is not matching the total value that I'm getting by manually calculating (from the generated report). can you please help.

foreach ($vCenter in $vCenters) {

$Report= @()

$arrUsedDisks = Get-View -ViewType VirtualMachine | % {$_.Layout} | % {$_.Disk} | % {$_.DiskFile}

    Get-View -ViewType Datastore -Property Name,Browser,Host | %{

    $ds = $_

    $dsBrowser = Get-View $ds.browser

    $rootPath = "[" + $ds.Name + "]"

    $searchSpec = New-Object VMware.Vim.HostDatastoreBrowserSearchSpec -property @{

        matchPattern="*.vmdk"

        details= New-Object VMware.Vim.FileQueryFlags -property @{

            filesize=$true

            modification=$true

        }

    }

    $searchResult = $dsBrowser.SearchDatastoreSubFolders($rootPath, $searchSpec)

    foreach ($folder in $searchResult) {

    foreach ($fileResult in $folder.File) {

         #if ($fileResult.Path -notmatch "-ctk.vmdk|-delta.vmdk|-00000[0-10].vmdk|-rdmp.vmdk|-rdm.vmdk"-and ($fileResult.Modification -lt $DaysOld)) {

                   if ($fileResult.Path -match "-flat.vmdk"-and ($fileResult.Modification -lt $DaysOld)) {

         if (-not ($arrUsedDisks -contains ($folder.FolderPath + $fileResult.Path))){

         $row = "" | Select DataStore, Path, ProbablyOrphanedFile, SizeGB, LastModifiedOn, Host

         $row.DataStore = $ds.Name

         $row.Path = $folder.FolderPath

         $row.ProbablyOrphanedFile = $fileResult.Path

         $row.SizeGB = [math]::Round($fileResult.FileSize/1GB,1)

         $row.LastModifiedOn = $fileResult.Modification

         $row.Host = (Get-View $ds.Host[0].Key).Name

         $orphanSize += $fileResult.FileSize                               

         $report += $row

  }

  }

  }

  }

  }

}

$ovmdkscount = $report.Count

$totalorphanedspace = ([Math]::Round($orphanSize/1GB,1))

$report | ConvertTo-Html –title "$vCenter - Orphaned VMDK Report" –body "<H2>$vCenter - Orphaned VMDK Report</H2>" -head $Header | Out-File $BasePath\$Date\$vCenter-OrphanedVMDKs-$Date.htm

$text = "$vCenter has got $ovmdkscount Orphaned VMDKs - Total Orphaned Space that could be reclaimed is $totalorphanedspace GB"

$text | Out-File $BasePath\$Date\ReportedvCentersStatus.txt -Append -Force

0 Kudos
1 Solution

Accepted Solutions
FMON
Enthusiast
Enthusiast
Jump to solution

Here is what I was saying about the $orphanSize = 0

foreach ($vCenter in $vCenters) {

  $orphanSize = 0   #   <<< since you want to tally orphan size per vcenter, for each vcenter you need to set it back to zero

 

  $Report= @()

  $arrUsedDisks = Get-View -ViewType VirtualMachine | % {$_.Layout} | % {$_.Disk} | % {$_.DiskFile}

  Get-View -ViewType Datastore -Property Name,Browser,Host | %{

  $ds = $_

    $dsBrowser = Get-View $ds.browser

    $rootPath = "[" + $ds.Name + "]"

    $searchSpec = New-Object VMware.Vim.HostDatastoreBrowserSearchSpec -property @{matchPattern="*.vmdk";details=New-Object VMware.Vim.FileQueryFlags -property @{filesize=$true;modification=$true} }

    $searchResult = $dsBrowser.SearchDatastoreSubFolders($rootPath, $searchSpec)

    foreach ($folder in $searchResult) {

      foreach ($fileResult in $folder.File) {

        if ($fileResult.Path -match "-flat.vmdk"-and ($fileResult.Modification -lt $DaysOld)) {

          if (-not ($arrUsedDisks -contains ($folder.FolderPath + $fileResult.Path))){

            $orphanSize += $fileResult.FileSize

            $row = "" | Select DataStore, Path, ProbablyOrphanedFile, SizeGB, LastModifiedOn, Host

            $row.DataStore = $ds.Name

            $row.Path = $folder.FolderPath

            $row.ProbablyOrphanedFile = $fileResult.Path

            $row.SizeGB = [math]::Round($fileResult.FileSize/1GB,1)

            $row.LastModifiedOn = $fileResult.Modification

            $row.Host = (Get-View $ds.Host[0].Key).Name

            $report += $row

          }

        }

      }

    }

  }

  #also the following 5 lines were originally not part of your foreach vcenter loop

  $ovmdkscount = $report.Count

  $totalorphanedspace = ([Math]::Round($orphanSize/1GB,1))

  $report | ConvertTo-Html –title "$vCenter - Orphaned VMDK Report" –body "<H2>$vCenter - Orphaned VMDK Report</H2>" -head $Header | Out-File $BasePath\$Date\$vCenter-OrphanedVMDKs-$Date.htm

  $text = "$vCenter has got $ovmdkscount Orphaned VMDKs - Total Orphaned Space that could be reclaimed is $totalorphanedspace GB"

  $text | Out-File $BasePath\$Date\ReportedvCentersStatus.txt -Append -Force

}

Not sure if that will solve your problem or not but that was a problem.

Alternatively you could add this to each of your rows:

$row.SizeBytes = $fileResult.FileSize

and then calculate the total size at the end:

$otherTotalOrphanedSpace = $report | Measure-Object -sum -property SizeBytes | select -expand Sum | foreach { [Math]::Round($_ / 1GB, 1) }

View solution in original post

0 Kudos
8 Replies
FMON
Enthusiast
Enthusiast
Jump to solution

$orphanSize = 0


Does not exist anywhere in the code you pasted.  So as-is it would just keep on growing.


Have you considered keeping a size-bytes in the report, and then using measure-object -sum to calculate total?

0 Kudos
virtualtech_wor
Enthusiast
Enthusiast
Jump to solution

Sorry, I didn't understand.

Do you mind modifying the code as per your comments and copy the code here back please?

Thanks.

0 Kudos
FMON
Enthusiast
Enthusiast
Jump to solution

Here is what I was saying about the $orphanSize = 0

foreach ($vCenter in $vCenters) {

  $orphanSize = 0   #   <<< since you want to tally orphan size per vcenter, for each vcenter you need to set it back to zero

 

  $Report= @()

  $arrUsedDisks = Get-View -ViewType VirtualMachine | % {$_.Layout} | % {$_.Disk} | % {$_.DiskFile}

  Get-View -ViewType Datastore -Property Name,Browser,Host | %{

  $ds = $_

    $dsBrowser = Get-View $ds.browser

    $rootPath = "[" + $ds.Name + "]"

    $searchSpec = New-Object VMware.Vim.HostDatastoreBrowserSearchSpec -property @{matchPattern="*.vmdk";details=New-Object VMware.Vim.FileQueryFlags -property @{filesize=$true;modification=$true} }

    $searchResult = $dsBrowser.SearchDatastoreSubFolders($rootPath, $searchSpec)

    foreach ($folder in $searchResult) {

      foreach ($fileResult in $folder.File) {

        if ($fileResult.Path -match "-flat.vmdk"-and ($fileResult.Modification -lt $DaysOld)) {

          if (-not ($arrUsedDisks -contains ($folder.FolderPath + $fileResult.Path))){

            $orphanSize += $fileResult.FileSize

            $row = "" | Select DataStore, Path, ProbablyOrphanedFile, SizeGB, LastModifiedOn, Host

            $row.DataStore = $ds.Name

            $row.Path = $folder.FolderPath

            $row.ProbablyOrphanedFile = $fileResult.Path

            $row.SizeGB = [math]::Round($fileResult.FileSize/1GB,1)

            $row.LastModifiedOn = $fileResult.Modification

            $row.Host = (Get-View $ds.Host[0].Key).Name

            $report += $row

          }

        }

      }

    }

  }

  #also the following 5 lines were originally not part of your foreach vcenter loop

  $ovmdkscount = $report.Count

  $totalorphanedspace = ([Math]::Round($orphanSize/1GB,1))

  $report | ConvertTo-Html –title "$vCenter - Orphaned VMDK Report" –body "<H2>$vCenter - Orphaned VMDK Report</H2>" -head $Header | Out-File $BasePath\$Date\$vCenter-OrphanedVMDKs-$Date.htm

  $text = "$vCenter has got $ovmdkscount Orphaned VMDKs - Total Orphaned Space that could be reclaimed is $totalorphanedspace GB"

  $text | Out-File $BasePath\$Date\ReportedvCentersStatus.txt -Append -Force

}

Not sure if that will solve your problem or not but that was a problem.

Alternatively you could add this to each of your rows:

$row.SizeBytes = $fileResult.FileSize

and then calculate the total size at the end:

$otherTotalOrphanedSpace = $report | Measure-Object -sum -property SizeBytes | select -expand Sum | foreach { [Math]::Round($_ / 1GB, 1) }

0 Kudos
virtualtech_wor
Enthusiast
Enthusiast
Jump to solution

Thank you for the detailed response.

For now, if I want to try option 2:

Instead of adding this $row.SizeBytes = $fileResult.FileSize to the code, can I do by utilizing the existing $row.SizeGB = [math]::Round($fileResult.FileSize/1GB,1),

as I want the report to show each vmdk size in GB and adding one more column with $row.SizeBytes  for each vmdk would not be beneficial in my case.

Or is there a way, I can use $row.SizeBytes = $fileResult.FileSize, but not show this value on report and just use for measuring the size as you mentioned.


$otherTotalOrphanedSpace = $report | Measure-Object -sum -property SizeGB | select -expand Sum

0 Kudos
FMON
Enthusiast
Enthusiast
Jump to solution

You can exclude the $row.SizeBytes from your html by using select-object as shown below in red:

$report | select * -exclude SizeBytes | ConvertTo-Html –title "$vCenter - Orphaned VMDK Report" –body "<H2>$vCenter - Orphaned VMDK Report</H2>" -head $Header | Out-File $BasePath\$Date\$vCenter-OrphanedVMDKs-$Date.htm

Keep in mind, comparing this value to the sum of the converted GB values may result in a rounding difference.

0 Kudos
virtualtech_wor
Enthusiast
Enthusiast
Jump to solution

Thank you.

In case if any specific Datastore is inaccessible on some vCenter, how do we catch the exception and skip that Datastore. I'm seeing this error:

Exception calling "SearchDatastoreSubFolders" with "2" argument(s): "Datastore 'xxxxxxxxxx' is not accessible. "

At E:\Scripts\OrphanedVMDKs\OrphanedVMDKs.ps1:82 char:5

+     $searchResult = $dsBrowser.SearchDatastoreSubFolders($rootPath, $searchSpec)

+     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException

    + FullyQualifiedErrorId : VimException

0 Kudos
FMON
Enthusiast
Enthusiast
Jump to solution

if you just want to keep it from bleeding on your screen when it hits a ds it can't access then replacing the line with this should do it:

$searchResult = try{$dsBrowser.SearchDatastoreSubFolders($rootPath, $searchSpec)}catch{}

Good luck!

0 Kudos
virtualtech_wor
Enthusiast
Enthusiast
Jump to solution

Thanks.

To log the inaccessible Datastore name and specific exception (error) details. Can I do something like this instead:

$searchResult = try {

                             $dsBrowser.SearchDatastoreSubFolders($rootPath, $searchSpec)

                                }

                      catch {  

                      $Error = $Error[0].Exception.Message

                      Log-Write "On $vCenter - Datastore $ds.Name is not accessible. Error: $Error - Skipping the Datastore."

                      }

0 Kudos