{"id":739,"date":"2022-01-31T13:59:32","date_gmt":"2022-01-31T13:59:32","guid":{"rendered":"http:\/\/192.168.8.14\/?p=739"},"modified":"2022-01-31T14:05:48","modified_gmt":"2022-01-31T14:05:48","slug":"orphan-file-removal-for-the-paranoid","status":"publish","type":"post","link":"https:\/\/www.jasonstreet.com\/?p=739","title":{"rendered":"Orphan file removal for the paranoid"},"content":{"rendered":"\n<p>here is a script i put together to loop through the RVTools result and mount all the suspect VMDKs<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: powershell; title: ; notranslate\" title=\"\">\n$vCenterURL = &quot;vmware server&quot;\n$ScriptFolder = &quot;path to the script, output of the RVTools output CSV folder in here&quot;\n$RVToolsFolder = &#039;&#039; # name of the RVTools folder. leave black and the script will use the most recent.\n$MountDisks = &quot;no&quot; # mount the disk to a test VM to confirm its safe to delete (ie not attached to anything)\n$autoDeleteDisks = &quot;no&quot;\n\n$TempVMName = &quot;jase-orphVM&quot;\n\nif ($RVToolsFolder -eq &#039;&#039;)\n{\n    $bob = Get-ChildItem $ScriptFolder | where{$_.name -match &quot;RVTools&quot;} | select -last 1\n    $RVToolsFolder = $bob.name\n}\n\nconnect-viserver $vCenterURL\n\n# import the RVtools file and filter only the zombie vmdks\n$RVToolsRaw = import-csv ($ScriptFolder + $RVToolsFolder + &quot;\\RVTools_tabvHealth.csv&quot;)\n$RVOrphenDisks = $RVToolsRaw | where {$_.message -eq &quot;Possibly a Zombie vmdk file! Please check.&quot;} | sort name\n\n\n# \n$OrphDisks = @()\n$CurrentDS = &quot;none&quot;\n$x = 0\ndo {\n    # \n    $tmpOrphDisk = &#039;&#039; | select Datastore,fullpath,path,date,sizeGB,Safe,removed\n\n    $tmpOrphDisk.Datastore = (((($RVOrphenDisks&#x5B;$x].name).split(&quot;]&quot;))&#x5B;0]).replace(&quot;&#x5B;&quot;,&quot;&quot;)).trim()\n    $tmpOrphDisk.path = ((($RVOrphenDisks&#x5B;$x].name).split(&quot;]&quot;))&#x5B;1]).trim()\n    $tmpOrphDisk.fullpath = $RVOrphenDisks&#x5B;$x].name\n\n\n    # if this file is not in the &quot;current datastore&quot; scan this datastore, get all vmdks and make it the current datastore.\n    # basically im expecting the RVTools list to be alphabetical so I dont have to rescan the same datastore more then once.\n    if ($CurrentDS -ne $tmpOrphDisk.Datastore)\n    {\n        $DS = get-datastore $tmpOrphDisk.Datastore\n\n        # scan the datastore and get all the vmdk details (path, mod date and size)\n        $DatastoreView = Get-View $DS.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.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 + $tmpOrphDisk.Datastore + \u201c]\u201d) # Do the search \n        $DSscan = $DatastoreBrowser.SearchDatastoreSubFolders($RootPath, $SearchSpecification)\n\n        # loop through the list of vmdks and make it in in to searchable array\n        $DSDiskList = @()\n        foreach ($DFolder in $DSscan)\n        {\n            foreach ($Dfile in $DFolder.file)\n            {\n                if ($Dfile.path -like &quot;*-flat.vmdk&quot;)\n                {\n                    $tmpDSDiskList = &#039;&#039; | select path, date, size\n                    $tmpDSDiskList.path = ($DFolder.Folderpath + ($Dfile.path).replace(&quot;-flat.vmdk&quot;,&quot;.vmdk&quot;))\n                    $tmpDSDiskList.date = $Dfile.Modification\n                    $tmpDSDiskList.size = $Dfile.FileSize\n                    $DSDiskList += $tmpDSDiskList\n                }\n            }\n        }\n\n        $CurrentDS = $tmpOrphDisk.Datastore\n    }\n    # \n\n    # populate report array with vmdk info\n    $diskResult = $DSDiskList | where{$_.path -eq $RVOrphenDisks&#x5B;$x].name}\n    $tmpOrphDisk.date = $diskResult.date\n    $tmpOrphDisk.SizeGB = $diskResult.size \/ 1gb\n\n    if ($MountDisks -eq &quot;yes&quot;)\n    {\n        # check the existance of the tmp test vm, create if need to\n        if (!(get-vm $tempVMname))\n        {\n            # create new VM and remove its disk and NIC\n            $TargetHost = get-vmhost -Datastore $tmpOrphDisk.Datastore | where {$_.connectionState -eq &quot;Connected&quot;} | select -First 1\n            New-VM -Name $tempVMname -Datastore $tmpOrphDisk.Datastore -vmhost $TargetHost \n            get-vm $tempVMname | Get-NetworkAdapter | Remove-NetworkAdapter -confirm:$false\n            get-vm $tempVMname | Get-HardDisk | Remove-HardDisk -DeletePermanently -confirm:$false\n        }\n\n        # check the existance of the tmp test vm\n        if (get-vm $tempVMname)\n        {\n            # get the first host that can access that datastore this orphan is on, move hte tmp VM to it\n            $TargetHost = get-vmhost -Datastore $tmpOrphDisk.Datastore | where {$_.connectionState -eq &quot;Connected&quot;} | select -First 1\n            get-vm $tempVMname | move-vm -destination $TargetHost\n\n            # mount the orphen vmdk to the tmp VM\n            write-host (&quot;  mounting &quot; + $tmpOrphDisk.fullpath) -ForegroundColor Yellow\n            get-vm $tempVMname | New-HardDisk -DiskPath $tmpOrphDisk.fullpath\n            if ($?)\n            {\n                $tmpOrphDisk.Safe = &quot;yes&quot;\n\n                if ($autoDeleteDisks -eq &quot;yes&quot;)\n                {\n                    write-host (&quot;  removing &quot; + $tmpOrphDisk.fullpath) -ForegroundColor Yellow\n                    get-vm $tempVMname | Get-HardDisk | Remove-HardDisk -DeletePermanently -confirm:$false -WhatIf\n                    if ($?)\n                    {\n                        write-host (&quot;    removed &quot; + $tmpOrphDisk.fullpath) -ForegroundColor Yellow\n                        $tmpOrphDisk.removed = &quot;yes&quot;\n                    }else{\n                        write-host (&quot;    remove failed &quot; + $tmpOrphDisk.fullpath) -ForegroundColor red\n                        $tmpOrphDisk.removed = &quot;no&quot;\n                    }\n                }else{\n                    # not allowed to delete disks\n                    $tmpOrphDisk.removed = &quot;disabled&quot;\n\n                    # detaching the disk from the tmpTest VM with out deleting the VMDK\n                    write-host (&quot;  detaching &quot; + $tmpOrphDisk.fullpath) -ForegroundColor Yellow\n                    get-vm $tempVMname | Get-HardDisk | Remove-HardDisk -confirm:$false\n                }\n            }else{\n                # failed to mount vmdk\n                write-host (&quot;  mounting failed &quot; + $tmpOrphDisk.fullpath) -ForegroundColor red\n                $tmpOrphDisk.Safe = &quot;no&quot;\n            }\n\n        }else{\n            # tmpTest VM not found, cant continue.\n            $tmpOrphDisk.removed = &quot;no&quot;\n            $tmpOrphDisk.Safe = &quot;unknown&quot;\n        }\n    }\n\n\n\n    $OrphDisks += $tmpOrphDisk\n    $x ++\n} until($x -ge $RVOrphenDisks.count)\n\n# remove the tmptest VM\nget-vm $tempVMname | Get-HardDisk | Remove-HardDisk -confirm:$false \nget-vm $tempVMname | remove-vm -Confirm:$false\n\n$OrphDisks | Out-GridView \n$OrphDisks | export-csv &quot;Orphan_report.csv&quot; -NoTypeInformation\n<\/pre><\/div>\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>here is a script i put together to loop through the RVTools result and mount all the suspect VMDKs<\/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,132,43],"tags":[12,13,20,6],"class_list":["post-739","post","type-post","status-publish","format-standard","hentry","category-powercli","category-powershell","category-reporting","category-vmware","tag-powercli","tag-powershell","tag-vcenter","tag-vmware"],"_links":{"self":[{"href":"https:\/\/www.jasonstreet.com\/index.php?rest_route=\/wp\/v2\/posts\/739","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=739"}],"version-history":[{"count":5,"href":"https:\/\/www.jasonstreet.com\/index.php?rest_route=\/wp\/v2\/posts\/739\/revisions"}],"predecessor-version":[{"id":746,"href":"https:\/\/www.jasonstreet.com\/index.php?rest_route=\/wp\/v2\/posts\/739\/revisions\/746"}],"wp:attachment":[{"href":"https:\/\/www.jasonstreet.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=739"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.jasonstreet.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=739"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.jasonstreet.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=739"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}