{"id":628,"date":"2021-03-12T00:07:45","date_gmt":"2021-03-12T00:07:45","guid":{"rendered":"http:\/\/192.168.8.14\/?p=628"},"modified":"2021-03-12T00:07:45","modified_gmt":"2021-03-12T00:07:45","slug":"very-fast-orphan-finder","status":"publish","type":"post","link":"https:\/\/www.jasonstreet.com\/?p=628","title":{"rendered":"Very fast orphan finder"},"content":{"rendered":"\n<p>Some thing every VMWare admin will end up doing at some point is orpahen file hunting. That fun task of hunting down unused VM disks hopefully before your datastore is out of space.<\/p>\n\n\n\n<p>Working for a cloud provider, wasted space is always a problem and RVTools has been my tool of choice for years. RVTools does not give me file size or last modification time. Two very important bits of information in the &#8220;can I delete this?&#8221; decision. But RVTools is quick, very quick (and free). <\/p>\n\n\n\n<p>Here is a handy bit of Powershell that is not quite as quick as RVTools but is not that much slower, and will give me Last modified date and the file size.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: powershell; title: ; notranslate\" title=\"\">\n$vCenterServer = &quot;myvCenterServer.domain&quot;\nconnect-viserver $vCenterServer\n\n\n\n$OrphanedFiles = @()\n$OrphanedDisks = @()\n$AllKnownPaths = @()\n$AllFoundPaths = @()\n$DataStores = get-datastore \nforeach ($DataStore in $DataStores)\n{\n    $DiskKnownPaths = @()\n    $DiskFoundPaths = @()\n    &quot;Scanning $DataStore&quot;\n\n    # get paths of VMs known in vCenter\n    $VMsinDS = get-vm -Datastore $Datastore\n    foreach ($VM in $VMsinDS)\n    {\n        $AllKnownPaths += $vm.ExtensionData.Layoutex.file.name \n        $DiskKnownPaths += $vm.ExtensionData.Layoutex.file.name\n    }\n\n    # get paths of templates known in vCenter\n    $TemplatessinDS = get-template -Datastore $Datastore\n    foreach ($Template in $TemplatessinDS)\n    {\n        $AllKnownPaths += $Template.ExtensionData.Layoutex.file.name \n        $DiskKnownPaths += $Template.ExtensionData.Layoutex.file.name\n    }\n\n\n\n    # Search the Datastore for files\n    # this is some code I found by LucD\n    # \n    $DatastoreView = Get-View $Datastore.id # Create new search specification for SearchDatastoreSubFolders method \n    $SearchSpecification = New-Object VMware.Vim.HostDatastoreBrowserSearchSpec # Create the file query flags to return Size, type and last modified \n    $fileQueryFlags = New-Object VMware.Vim.FileQueryFlags \n    $fileQueryFlags.FileSize = $true \n    #$fileQueryFlags.FileType = $true \n    $fileQueryFlags.Modification = $true # Set the flags on the search specification \n    $SearchSpecification.Details = $fileQueryFlags # Set the browser \n    $DatastoreBrowser = Get-View $DataStoreView.browser # Set root path to search from \n    $RootPath = (\u201c&#x5B;\u201d + $Datastore.Name + \u201c]\u201d) # Do the search \n    $SearchResults = $DatastoreBrowser.SearchDatastoreSubFolders($RootPath, $SearchSpecification)\n\n    # format the list of fond files in to a more useable array\n    foreach ($SearchResult in $SearchResults)\n    {\n        $DSName = ((($SearchResult.folderpath).split(&#039;] &#039;))&#x5B;0]).replace(&#039;&#x5B;&#039;,&#039;&#039;)\n        $FilePath = (($SearchResult.folderpath).replace((&#039;&#x5B;&#039; +$DSName + &#039;]&#039;),&#039;&#039;)).trim()\n\n\n        foreach ($File in $SearchResult.file)\n        {\n            $tmpFoundFile = &#039;&#039; | select DS,Path,Name,FullName,ModDate,FileSize\n            $tmpFoundFile.DS = $DSName\n            $tmpFoundFile.Path = $FilePath\n            $tmpFoundFile.Name = $File.Path\n            $tmpFoundFile.FullName = $SearchResult.folderpath + $File.Path\n            $tmpFoundFile.ModDate = $File.Modification\n            $tmpFoundFile.FileSize = $File.FileSize\n            $AllFoundPaths += $tmpFoundFile\n            $DiskFoundPaths += $tmpFoundFile\n        }\n    }\n\n    # get the files that exist but are not known to vCenter\n\n    # loop the list of found files on the datastore and compere with the known files\n    foreach ($DiskFoundPath in $DiskFoundPaths)\n    {\n        $Foundit = $false\n        \n        if ($DiskKnownPaths -contains $DiskFoundPath.fullname){$Foundit = $true} # if this matches then the file is known to vCenter\n        if ($DiskKnownPaths -contains (($DiskFoundPath.fullname).replace(&quot;-flat.vmdk&quot;,&quot;.vmdk&quot;))){$Foundit = $true} # if the file Im looking at is -flat.vdk rename it to .vmdk (otherwise all -flat.vmdks would be orphaned)       \n\n        \n        if ($DiskFoundPath.path -match &quot;contentlib-&quot;){$Foundit = $true} # ignore anything with in a content library\n        if ($DiskFoundPath.path -match &quot;.dvsData&quot;){$Foundit = $true} # ignore anything with .dvsData\n        if ($DiskFoundPath.name -match &quot;.vmx~&quot;){$Foundit = $true} # ignore anything ending in .vmx~\n        if ($DiskFoundPath.Path -eq &quot;&quot;){$Foundit = $true} # ignore anything in the root (cant tell the difference between a file and a directory)\n\n        # if we have not matched the found file to a known file then its most likely orphaned\n        if ($Foundit -eq $false)\n        {\n            # Add the foundfile object to the output array\n            $OrphanedFiles += $DiskFoundPath\n\n            # if the found file is a -flat.vmdk, rename it to .vmdk (so I can find it) and save to its own disk output array\n            if ($DiskFoundPath.name -match &quot;-flat.vmdk&quot;)\n            {\n                $VMDKOnly = $DiskFoundPath\n                $VMDKOnly.name = $VMDKOnly.name.replace(&quot;-flat.vmdk&quot;,&quot;.vmdk&quot;)\n                $VMDKOnly.FullName = $VMDKOnly.FullName.replace(&quot;-flat.vmdk&quot;,&quot;.vmdk&quot;)\n                $VMDKOnly.FileSize = &#x5B;long]$VMDKOnly.FileSize \/ 1Mb\n                $OrphanedDisks += $VMDKOnly\n            }\n        }\n    }\n\n}\n\n# $AllKnownPaths # an array of every known file \n# $AllFoundPaths # an array of every fine in the datastores\n$OrphanedFiles | export-csv &quot;orphs.csv&quot; -NoTypeInformation\n$OrphanedDisks | export-csv &quot;orph-disks.csv&quot; -NoTypeInformation\n\n<\/pre><\/div>\n\n\n<p>You will how have 2 CSV files.<\/p>\n\n\n\n<p>Orphs.cav will list every file on your datastore that is not part of a VM or template.<\/p>\n\n\n\n<p>Orph-disks.csv will list only the VMDKs <\/p>\n\n\n\n<p>Note: when scanning the datastore at the file level the result can not distinguish between a file and a directory. So in the full report there will be odd results more then once directory level deep.<\/p>\n\n\n\n<p>The is a lot of system stuff saved on DataStores. Cluster HA, Host scratch etc. all this will show up in the full report. <\/p>\n\n\n\n<p>Disks are what you are looking for, Use the disk report.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Some thing every VMWare admin will end up doing at some point is orpahen file hunting. That fun task of hunting down unused VM disks hopefully before your datastore is out of space. Working for a cloud provider, wasted space is always a problem and RVTools has been my tool of choice for years. RVTools&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[5,4,43],"tags":[123,122,120,10,124,121],"class_list":["post-628","post","type-post","status-publish","format-standard","hentry","category-powercli","category-powershell","category-vmware","tag-datastore","tag-fast","tag-orphen","tag-report","tag-usage","tag-zombie"],"_links":{"self":[{"href":"https:\/\/www.jasonstreet.com\/index.php?rest_route=\/wp\/v2\/posts\/628","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.jasonstreet.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.jasonstreet.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.jasonstreet.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.jasonstreet.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=628"}],"version-history":[{"count":3,"href":"https:\/\/www.jasonstreet.com\/index.php?rest_route=\/wp\/v2\/posts\/628\/revisions"}],"predecessor-version":[{"id":631,"href":"https:\/\/www.jasonstreet.com\/index.php?rest_route=\/wp\/v2\/posts\/628\/revisions\/631"}],"wp:attachment":[{"href":"https:\/\/www.jasonstreet.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=628"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.jasonstreet.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=628"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.jasonstreet.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=628"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}