Orphaned Files Revisited

In my Orphaned files and folders – Spring cleaning post from way back, I provided a script to find orphaned VMDKs. This week there was a post in the VMTN PowerCLI Community that had a request to find all orphaned files. Time for a revisit of my old post!

file-orphan

I took my old script, massaged it a bit and gave it a more contemporary look and feel.
Just for info, the SearchDatastoreSubFolders method is relatively slow. So scanning a couple of datastores for orphaned files might take a bit of time. Be patient 🙂

The Script

Annotations

Line 28-57: The script constructs the SearchDatastoreSubFolders parameter in the Begin block. This parameter will be the same for all datastores.

Line 56: To get maximum detail for the returned files, the script uses all available FileQuery variations

Line 62-64: Cheap OBN implementation

Line 67: The script only looks at shared VMFS datastores

Line 71: This hash table will be used to determine which file/folder is orphaned or not. First all the files the method fins are placed in the hash table. Then the files that belong to VMs and Templates are removed. Finally some system files are removed. What is left are orphaned files.

Line 76: Get all the files on the datastore with the SearchDatastoreSubFolders method

Line 77-87: Enter the files in the hash table

Line 83-85: Take care of the folder entries. If a file inside a folder is encountered, the script also removes the folder itself from the hash table

Line 90-96: Remove all files that belong to registered VMs from the hash table

Line 99-105: Remove all files that belong to registered Templates from the hash table

Line 108-111: Remove system files. For now these all files that are located in folders that start with a dot, or in a folder named vmkdump.

Line 114-128: If there are entries left in the hash table, collect more information and create an ordered object containing that information.

Sample Usage

The use of this function is rather straightforward, call the function with a datastorename or a datastore object.

or

The function also accepts the datastore objects via the pipeline. You can do

The objects that are returned by the function, depending on the type of file, contain information about the file. The following sample output shows how some properties are specific to certain file types.

orphan-1

If you want to create an orphaned files report for multiple datastores, it is handy to capture the results for each datastore in a separate worksheet in an Excel spreadsheet.

The following sample code uses Doug Finke‘s ImportExcel module to accomplish that.

The resulting spreadsheet has all the orphaned files, with a separate worksheet for each datastore that has orphaned files.

orphan-2

Enjoy!

92 Comments

    Marco Hofmann

    Hi! Really would like to use that script, but I only get zero results. Even with -Verbose.
    This should work against VSAN 7, should it?

      LucD

      The version of the script in the post does not work with VSAN datatsores.

      But on VMTN I got a similar question, and I posted an updated version of the script there.
      See https://communities.vmware.com/t5/VMware-PowerCLI-Discussions/get-orphaned-vmdk-information-from-vSAN/m-p/2814645/highlight/true#M98536

      Can you try that version and let me know if it returns correct results for you?

    Shibin

    Looking at this in 2023 on latest version of vCenter, ESXi and DS.

    I tried to use this script. Since we have restricted environment, I used the export CSV method mentioned in one of the comment section. Regardless of both options ( without export and with export ) I couldn’t get any results neither on screen nor on files.

    What I did, first, generated list of DS in a text file, then used that text file lines one by one to scan it ( as shown below ):

    Script reading each line and scanning, but not seeing any results. Is that due to any version changes ? But in my RV Tools report, there are plenty of zombie / orphaned files listed.

    (Get-Datastore).Name > C:\Temp\AP2_DSName.txt
    Write-Host “List of data store in AP2 vCenter has been created” -ForegroundColor Green
    $Reader = New-Object System.IO.StreamReader(“C:\Temp\AP2_DSName.txt”)
    while($Line = $Reader.ReadLine()) {
    # Validate the orphane / zombie files
    Get-Datastore -Name $Line | Get-VmwOrphan
    Write-Host “Searching for Zombie files has been completed on $Line” -ForegroundColor Magenta
    }
    $Reader.Close()

      LucD

      The script works, for me, with the latest vSphere and ESXi versions.
      Are your datastores VMFS datastores?

      You can also activate Verbose logging, which might give some clues what happens.
      Set the $verbosePreference variable to ‘Continue’ at the start of your code.

      $VerbosePreference = 'Continue'

        Shibin

        Yes, all are VMFS datastores.

        Enabled verbose mode and run. I could see many has returned orphaned files found. But the exported data has only one item, which is part of an existing VM, but moved to different datastore. No other information I could see. Below are the verbose command output.

        VERBOSE: 09/13/2023 14:41:13 Get-VmwOrphan Looking at AP2_HDS_NMA_TP0_ESX_0023
        VERBOSE: 13-Sep-23 2:41:14 PM Get-View Finished execution
        VERBOSE: 13-Sep-23 2:42:56 PM Get-VM Finished execution
        VERBOSE: 13-Sep-23 2:43:08 PM Get-Template Finished execution
        VERBOSE: 09/13/2023 14:43:08 Get-VmwOrphan No orphaned files found on AP2_HDS_NMA_TP0_ESX_0023.
        VERBOSE: 13-Sep-23 2:43:08 PM Get-Datastore Finished execution
        Searching for Zombie files has been completed on AP2_HDS_NMA_TP0_ESX_0023

        VERBOSE: 09/13/2023 14:43:11 Get-VmwOrphan Looking at AP2_HDS_NMA_TP0_ESX_0022
        VERBOSE: 13-Sep-23 2:43:11 PM Get-View Finished execution
        VERBOSE: 13-Sep-23 2:43:44 PM Get-VM Finished execution
        VERBOSE: 13-Sep-23 2:44:00 PM Get-Template Finished execution
        VERBOSE: 09/13/2023 14:44:00 Get-VmwOrphan Found orphaned files on AP2_HDS_NMA_TP0_ESX_0022!
        VERBOSE: 13-Sep-23 2:44:00 PM Get-Datastore Finished execution
        Searching for Zombie files has been completed on AP2_HDS_NMA_TP0_ESX_0022

          LucD

          Could you try capturing the output in a variable instead of showing it in the console?
          Something like this for example

          $report = @()

          (Get-Datastore).Name > C:\Temp\AP2_DSName.txt
          Write-Host “List of data store in AP2 vCenter has been created” -ForegroundColor Green
          $Reader = New-Object System.IO.StreamReader(“C:\Temp\AP2_DSName.txt”)
          while($Line = $Reader.ReadLine()) {
          # Validate the orphane / zombie files
          $report += Get-Datastore -Name $Line | Get-VmwOrphan
          Write-Host “Searching for Zombie files has been completed on $Line” -ForegroundColor Magenta
          }
          $Reader.Close()

          $report

            Shibin

            I followed Pablo’s method to capture it in CSV file

            Pablo
            DECEMBER 20, 2022 at 11:28″

            I will re-attempt as you mentioned, will let you know the results when it is ready.

              Shibin

              No luck with that option as well. Same result like previous.

              Shibin

              Ok. I found the problem.

              The function Get-VmwOrphan generate information, but it stores into $obj at line number 128. Hence it will not show any result on screen. That’s the reason the $report array has not showing any result. Since I have 200 Data store and looped to call, each time when function gets called, the $obj will be cleared and will not update my CSV file as well. So the result is, last DS with orphaned file shows. Rest of them will be overwritten.

              I used return $obj to dump it on screen, so when function called using Get-VmwOrphan -Datastore $DSName it showed on the screen.

              Since the $obj inside the function and clears everytime, I need to find a way to dump it into the the CSV file which calls from my PS script and append it.

                LucD

                The content of $obj is send to the console in line 128.
                Your observation is not correct I’m afraid.

                  Shibin

                  You are right. When I integrated Pablo’s method that went wrong. After removal of that and run the script with my original way, it worked and got results.

                  Thank you for the great script !!!

    mmccar

    Hey LucD

    Great script, thanks for sharing.

    I ran the script against our datastores but found some orphaned files remained (e.g. .hlog, .vmem, .vmsd, .vmxf, .xml). I couldn’t find file query objects for these file types to add, so i decided to capture all file types by commenting out $searchSpec.Query.

    However, this picks up some files belonging to live VMs on the datastore (e.g. .scoreboard, -ctk.vmdk, .vmx~, .vmx.lck), i am guessing as these are not returned by $_.ExtensionData.LayoutEx.File, hence are not removed from $fileTab. I could filter these with a Where-Object but of course that would also exclude orphans of the same type.

    Just wondering if you came across similar challenges and have any advice?

      LucD

      The current version of the script only looks at VMDK files I’m afraid.

      The $fileTab table is filled with all VMDK found on the datastore.
      Then the VMDK files that are used by VMs, Templates, and some system files are removed from that table.

      To handle all the files you encountered would require a serious rewrite of the script.
      Although the basic concept should be the same:

    1. Find all files
    2. Remove all files used by VMs and Templates

    Eric

    Hello, I can’t dot source the function, it returns a ton of errors, starting at line 20:

    At C:\scripts\orphaned.ps1:21 char:20
    +   [CmdletBinding()]
    + ~
    An expression was expected after ‘(‘.
    At C:\scripts\orphaned.ps1:23 char:35
    +     [parameter(Mandatory=$true,ValueFromPipeline=$true)]
    + ~
    Missing argument in parameter list.
    At C:\scripts\orphaned.ps1:23 char:61
    +     [parameter(Mandatory=$true,ValueFromPipeline=$true)]
    + ~
    Missing closing ‘)’ in expression.
    At C:\scripts\orphaned.ps1:1 char:23
    + function Get-VmwOrphan{
    + ~
    Missing closing ‘}’ in statement block or type definition.
    At C:\scripts\orphaned.ps1:25 char:5
    +   )
    + ~

      LucD

      Looks like something went wrong with your copy/paste by the looks of it.
      These strange characters (+ Â Â) at the beginning of each line seem to indicate that.

      Did you use the Copy option?
      Copy code

    Pablo

    Hi there,
    first and foremost, thank you su much for this script, it’s superb!! 🙂
    I have made some minimal changes on your script, to be able to generate a CSV output with the orphaned files:

    In line 61:
    $FileObjectArray = @()

    In lines 128 & 129:
    $FileObject = New-Object PSObject -Property $obj
    $FileObjectArray += $FileObject

    Finally, in line 136:
    If ($FileObjectArray) {$FileObjectArray | Export-csv -NoTypeInformation vMwareOrphanedFiles.csv -Force}

    Hope my amendments, helps someone .

    KR,
    Pablo

      LucD

      Nice one, thanks Pablo

    Rani

    Hi LucD,

    I added the below to the end of the function in the script

    Get-VmwOrphan -Datastore RegionA01-LOCAL-ESX01A

    $ds = Get-Datastore -Name nimblea-vvol01

    Get-VmwOrphan -Datastore $ds

    Get-Cluster -Name RegionA01-COMP01 | Get-Datastore | Get-VmwOrphan

    but none of your 3 sample usage returns anything, I created a dummy vm removed it from vc it does not return anything. what am i missing any help pls

      LucD

      Where did you add those lines?
      After the last curly brace (line 138)?

        Rani

        yep right after the line 138 end of the curly brace, I tried one sample at a time but none helped. I will try again on my lab machines and repost if no success

          Rani

          Hi LucD,

          Seems I had missed copying entirely, copied again created new scripts with 3 above samples and all of them give the similar output and I was able to spot the orphaned vm but I could not export to excel

          Export-Excel : The term ‘Export-Excel’ is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
          At C:\Users\Prince Joshua\Downloads\Orphan VMDK.ps1:144 char:17
          + $ds.Group | Export-Excel -Path $reportName -WorkSheetname $ds.Nam …
          + ~~~~~~~~~~~~
          + CategoryInfo : ObjectNotFound: (Export-Excel:String) [], CommandNotFoundException
          + FullyQualifiedErrorId : CommandNotFoundException

          Export-Excel : The term ‘Export-Excel’ is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
          At C:\Users\Prince Joshua\Downloads\Orphan VMDK.ps1:144 char:17
          + $ds.Group | Export-Excel -Path $reportName -WorkSheetname $ds.Nam …
          + ~~~~~~~~~~~~
          + CategoryInfo : ObjectNotFound: (Export-Excel:String) [], CommandNotFoundException
          + FullyQualifiedErrorId : CommandNotFoundException

          Realized lab machines dont have excel would that be a problem?

          Thanks help when u can

            LucD

            No, you don’t need to have Excel installed, but it looks like the ImportExcel module is not installed.

              Rani

              Perfect, worked on all 3 samples as you noted / directed thanks a lot for your help again and your scripts are very useful even this https://communities.vmware.com/t5/VMware-PowerCLI-Discussions/Script-to-export-Alarms-from-VCenter-to-analyze/m-p/2681811 🙂

    Ricardo Jose

    Regards,

    how to use on infraestructure with mixed datastore VMFS6 + VSan + NFS 3

    does it works with Vsan ??

    My Best Regards

      LucD

      Hi,
      Due to the internal format of the file structure on VSAN, the current script doesn’t work as-is.

      For NFS you will have to remove the test condition for VMFS at the beginning, but other than that it should work on NFS.

      Regards,
      Luc

    Joy

    How do I alter the function to print the name of the datastore / folder that threw an error?

    PS C:\WINDOWS\system32> Get-Datastore | Where-Object {$_.Name -notmatch “^st074no_templates_ds01$|^st0004no_templates_ds1-q1$|local”} | Get-VmwOrphan | Export-Csv c:\users\jm\downloads\vc007no-oct28-orphaned.csv -NoTypeInformation
    Exception calling “SearchDatastoreSubFolders” with “2” argument(s): “An error occurred while communicating with the
    remote host.”
    At line:77 char:9
    + $searchResult = $dsBrowser.SearchDatastoreSubFolders($rootPat …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : VimException

    I’ve got a much better understanding how all works and get random errors depending on vcenter I run it on. Now I want to drill down to see what datastore wasn’t happy.

      LucD

      In line 68 there is a Write-Verbose that shows which datastore is being looked at.
      Just call the function with the Verbose switch.

      Get-Datastore |
      Where-Object {$_.Name -notmatch "^st074no_templates_ds01$|^st0004no_templates_ds1-q1$|local"} |
      Get-VmwOrphan -Verbose

    Joy

    Get-VM : 10/26/2021 1:59:16 PM Get-VM Exception has been thrown by the target of an invocation.
    At C:\Users\jm\VMware_scripts\SpringCleaning\Orphaned files\SpringCleaning-LocateOrphaned.ps1:96 char:9
    + Get-VM -Datastore $ds | %{
    + ~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [Get-VM], VimException
    + FullyQualifiedErrorId : Core_BaseCmdlet_UnknownError,VMware.VimAutomation.ViCore.Cmdlets.Commands.GetVM

    Get-VM : 10/26/2021 2:00:22 PM Get-VM Exception has been thrown by the target of an invocation.
    At C:\Users\jm\VMware_scripts\SpringCleaning\Orphaned files\SpringCleaning-LocateOrphaned.ps1:96 char:9
    + Get-VM -Datastore $ds | %{
    + ~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [Get-VM], VimException
    + FullyQualifiedErrorId : Core_BaseCmdlet_UnknownError,VMware.VimAutomation.ViCore.Cmdlets.Commands.GetVM

    Exception calling “Add” with “2” argument(s): “Item has already been added. Key in dictionary: ‘[st251104_pre_ds19] previpwebw02-1.sjrb.ad/PREVIPWEBW02-1.SJRB.AD.vmdk’ Key being added: ‘[st251104_pre_ds19]
    previpwebw02-1.sjrb.ad/previpwebw02-1.sjrb.ad.vmdk'”
    At C:\Users\jm\VMware_scripts\SpringCleaning\Orphaned files\SpringCleaning-LocateOrphaned.ps1:86 char:13
    + $fileTab.Add($key,$file)
    + ~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : ArgumentException

    Exception calling “Add” with “2” argument(s): “Item has already been added. Key in dictionary: ‘[st251104_pre_ds19] .snapshot/SCV_Daily_10-26-2021_02.25.01.0574/previpwebw02-1.sjrb.ad/PREVIPWEBW02-1.SJRB.AD.vmdk’ Key being added:
    ‘[st251104_pre_ds19] .snapshot/SCV_Daily_10-26-2021_02.25.01.0574/previpwebw02-1.sjrb.ad/previpwebw02-1.sjrb.ad.vmdk'”
    At C:\Users\jm\VMware_scripts\SpringCleaning\Orphaned files\SpringCleaning-LocateOrphaned.ps1:86 char:13
    + $fileTab.Add($key,$file)
    + ~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : ArgumentException

    Exception calling “Add” with “2” argument(s): “Item has already been added. Key in dictionary: ‘[st251104_pre_ds19] .snapshot/SCV_Daily_10-17-2021_02.25.01.0088/previpwebw02-1.sjrb.ad/PREVIPWEBW02-1.SJRB.AD.vmdk’ Key being added:
    ‘[st251104_pre_ds19] .snapshot/SCV_Daily_10-17-2021_02.25.01.0088/previpwebw02-1.sjrb.ad/previpwebw02-1.sjrb.ad.vmdk'”
    At C:\Users\jm\VMware_scripts\SpringCleaning\Orphaned files\SpringCleaning-LocateOrphaned.ps1:86 char:13
    + $fileTab.Add($key,$file)
    + ~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : ArgumentException

    Hi Luc,

    I’m seeing a couple of issues, see above. The “Exception has been thrown….” message research I did indicated to uninstall and reinstall powercli. I have not done this yet. What is the impact, other than the message being thrown?

    Ultimately, I’d like to exclude ./snapshot/SCV* on all my datastores. This is a backup path.

    I’d also like to exclude the following datastores:
    st074no_templates_ds01
    st0004no_templates_ds1-q1
    *local*

      LucD

      Hi Joy,
      For the exceptions, I would indeed advise completely removing PowerCLI and reinstalling with Install-Module.
      The removal can be done by just deleting all the folders related to PowerCLI.
      You can find those folders by running

      Get-Module -Name VMware*

      These exceptions skip a number of VMs, meaning that the VMDK from those VMs will be listed as orphaned.

      To exclude specific datastores, you can use a Where-clause after the Get-Datastore cmdlet.
      The easiest way is to use a RegEx.

      Get-Datastore |
      Where-Object {$_.Name -notmatch "^st074no_templates_ds01$|^st0004no_templates_ds1-q1$|local"} |
      Get-VmwOrphan

      The function should exclude system folders (like ./snapshot/SCV*), see line 108.
      Should that not be the case, the RegEx in said line 108 can be adapted.

      I hope that helps,
      Luc

        Joy

        Hi Luc,

        Before I get into what didn’t work I’d like to ask for a modification so that column B was the datastore name and column C was the datastore folder and filename.

        Problems I encountered:
        1. Running VM files identified as orphaned.
        Folder Datastore Folder/File
        [st912cl_pre_ds05 aaa1dev.core.wifi.inet/aaa1dev.core.wifi.inet.nvram
        [st912cl_pre_ds05 aaa1dev.core.wifi.inet/aaa1dev.core.wifi.inet.vmdk
        [st912cl_pre_ds05 aaa1dev.core.wifi.inet/aaa1dev.core.wifi.inet.vmx
        [st912cl_pre_ds05 aaa1dev.core.wifi.inet/vmware.log
        [st912cl_pre_ds05 aaa1dev.core.wifi.inet/vmware-0.log
        [st912cl_pre_ds05 aaa1dev.core.wifi.inet/vmware-4.log
        [st912cl_pre_ds05 aaa1dev.core.wifi.inet/vmware-5.log
        [st912cl_pre_ds05 aaa1dev.core.wifi.inet/vmware-6.log
        [st912cl_pre_ds05 aaa1dev.core.wifi.inet/vmware-7.log
        [st912cl_pre_ds05 aaa1dev.core.wifi.inet/vmware-8.log

        2. VMs running off ISO files were identified. In hindsight, this is likely good as I can approach the user group asking why they are running VMs off ISOs vs the booted OS.

        I have not made the changes you suggested yet, nor have I uninstalled and reinstalled powercli. I am a wee bit perplexed at what you mean by this:

        Get-Datastore |
        Where-Object {$_.Name -notmatch “^st074no_templates_ds01$|^st0004no_templates_ds1-q1$|local”} |
        Get-VmwOrphan

        –> do you want me to just run that on the powercli command line or did you want me to make the change at a particular place in the script? I understand what we’re doing here, just not sure where I’m to put this.

        I’m not sure if you recall, I’m using NFS so removed “$ds.Type -eq “VMFS” -and ” from line 67. I’m mentioning this as a reminder of previous conversations. I know you’re a busy person.

        function Get-VmwOrphan{
        Get-VmwOrphan -Datastore DS1
        .EXAMPLE
        PS> Get-Datastore -Name DS* | Get-VmwOrphan
        #>

        [CmdletBinding()]
        param(
        [parameter(Mandatory=$true,ValueFromPipeline=$true)]
        [PSObject[]]$Datastore
        )

        Begin{
        $flags = New-Object VMware.Vim.FileQueryFlags
        $flags.FileOwner = $true
        $flags.FileSize = $true
        $flags.FileType = $true
        $flags.Modification = $true

        $qFloppy = New-Object VMware.Vim.FloppyImageFileQuery
        $qFolder = New-Object VMware.Vim.FolderFileQuery
        $qISO = New-Object VMware.Vim.IsoImageFileQuery
        $qConfig = New-Object VMware.Vim.VmConfigFileQuery
        $qConfig.Details = New-Object VMware.Vim.VmConfigFileQueryFlags
        $qConfig.Details.ConfigVersion = $true
        $qTemplate = New-Object VMware.Vim.TemplateConfigFileQuery
        $qTemplate.Details = New-Object VMware.Vim.VmConfigFileQueryFlags
        $qTemplate.Details.ConfigVersion = $true
        $qDisk = New-Object VMware.Vim.VmDiskFileQuery
        $qDisk.Details = New-Object VMware.Vim.VmDiskFileQueryFlags
        $qDisk.Details.CapacityKB = $true
        $qDisk.Details.DiskExtents = $true
        $qDisk.Details.DiskType = $true
        $qDisk.Details.HardwareVersion = $true
        $qDisk.Details.Thin = $true
        $qLog = New-Object VMware.Vim.VmLogFileQuery
        $qRAM = New-Object VMware.Vim.VmNvramFileQuery
        $qSnap = New-Object VMware.Vim.VmSnapshotFileQuery

        $searchSpec = New-Object VMware.Vim.HostDatastoreBrowserSearchSpec
        $searchSpec.details = $flags
        $searchSpec.Query = $qFloppy,$qFolder,$qISO,$qConfig,$qTemplate,$qDisk,$qLog,$qRAM,$qSnap
        $searchSpec.sortFoldersFirst = $true
        }

        Process{
        foreach($ds in $Datastore){
        if($ds.GetType().Name -eq “String”){
        $ds = Get-Datastore | where{$_.Name -notmatch “^st074no_templates_ds01$|^st004no_templates_ds1-q1$|local”}
        }

        # Only shared NFS datastore
        if($ds.ExtensionData.Summary.MultipleHostAccess -and $ds.State -eq ‘Available’){
        Write-Verbose -Message “$(Get-Date)t$((Get-PSCallStack)[0].Command)tLooking at $($ds.Name)”

        # Define file DB
        $fileTab = @{}

        # Get datastore files
        $dsBrowser = Get-View -Id $ds.ExtensionData.browser
        $rootPath = “[” + $ds.Name + “]”
        $searchResult = $dsBrowser.SearchDatastoreSubFolders($rootPath, $searchSpec) | Sort-Object -Property {$_.FolderPath.Length}
        foreach($folder in $searchResult){
        foreach ($file in $folder.File){
        $key = “$($folder.FolderPath)$(if($folder.FolderPath[-1] -eq ‘]’){‘ ‘})$($file.Path)”
        $fileTab.Add($key,$file)

        $folderKey = “$($folder.FolderPath.TrimEnd(‘/’))”
        if($fileTab.ContainsKey($folderKey)){
        $fileTab.Remove($folderKey)
        }
        }
        }

        # Get VM inventory
        Get-VM -Datastore $ds | %{
        $_.ExtensionData.LayoutEx.File | %{
        if($fileTab.ContainsKey($_.Name)){
        $fileTab.Remove($_.Name)
        }
        }
        }

        # Get Template inventory
        Get-Template | where {$_.DatastoreIdList -contains $ds.Id} | %{
        $_.ExtensionData.LayoutEx.File | %{
        if($fileTab.ContainsKey($_.Name)){
        $fileTab.Remove($_.Name)
        }
        }
        }

        # Remove system files & folders from list
        $systemFiles = $fileTab.Keys | where{$_ -match “] \.|vmkdump”}
        $systemFiles | %{
        $fileTab.Remove($_)
        }

        # Organise remaining files
        if($fileTab.Count){
        $fileTab.GetEnumerator() | %{
        $obj = [ordered]@{
        Name = $_.Value.Path
        Folder = $_.Name
        Size = $_.Value.FileSize
        CapacityKB = $_.Value.CapacityKb
        Modification = $_.Value.Modification
        Owner = $_.Value.Owner
        Thin = $_.Value.Thin
        Extents = $_.Value.DiskExtents -join ‘,’
        DiskType = $_.Value.DiskType
        HWVersion = $_.Value.HardwareVersion
        }
        New-Object PSObject -Property $obj
        }
        Write-Verbose -Message “$(Get-Date)t$((Get-PSCallStack)[0].Command)tFound orphaned files on $($ds.Name)!”
        }
        else{
        Write-Verbose -Message “$(Get-Date)t$((Get-PSCallStack)[0].Command)tNo orphaned files found on $($ds.Name).”
        }
        }
        }
        }
        }

        $reportName = ‘C:\Users\Jm\Downloads\orphan-report-vc007no-all-datacenters-no-local-no-templates.xlsx’

        foreach($ds in (Get-Datacenter | Get-Datastore | Get-VmwOrphan | Group-Object -Property {$_.Folder.Split(‘]’)[0].TrimStart(‘[‘)})){
        $ds.Group | Export-Excel -Path $reportName -WorkSheetname $ds.Name -AutoSize -AutoFilter -FreezeTopRow
        }

          LucD

          This is the code that calls the Get-VmwOrphan function for each datastore that passes the Where-clause.
          That Whereclause uses a RegEx to filter out the datastores you mentioned earlier.
          If you place the function Get-VmwOrphan in a .ps1 file, then add those lines to the end, they will call the function.


          Get-Datastore |
          Where-Object {$_.Name -notmatch “^st074no_templates_ds01$|^st0004no_templates_ds1-q1$|local”} |
          Get-VmwOrphan

          And yes, that is the correct change to use the function for NFS datastores.

        Joy

        Luc,

        Who knew that the newer versions of PowerCLI were integrated into PowerShell? That threw me. Just a wee panic. 🙂 I was on a really old one that was installed from a .msi file.

        All seems to be working just fine now. Amazing script. Thank you so much.

        Joy

          LucD

          You’re welcome 🙂

    Martin

    Hi Luc,

    Anyway to make it work with GUID names?

    I really don’t want to have to clean orphaned vmdk file by hand 🙁

    Thanks

      LucD

      What exactly do you mean by “GUID names”?

        Martin

        Hi Luc,

        I was replying to an older post of yours, looks like it didn’t attach to it.

        LucD
        SEPTEMBER 13, 2019 at 18:44
        The function does test for a VMFS datastore, but you should be able to leave that Where-clause out.
        With VSAN there is an issue, since the path the VM uses internally is not with the user-friendly datastorename, but with a king of GUID.
        The function will not work with that.

        Basically, because our volumes are named as UUID (I think thats the official name) I believe its why your script may not be working for my environment. I was looking to know if you know a way around removing orphaned/zombie vmdk files, eith with your script or another way.

    Chris

    Hey LucD,

    when running your Script and exporting to CSV (cmd called: Get-Cluster -Name clustername | Get-Datastore | Get-VmwOrphan | Export-Csv c:\orphans.csv) I get values out however I get an error thrown at the end:

    Exception calling “ContainsKey” with “1” argument(s): “Key cannot be null.
    Parameter name: key”
    At C:\Users\Administrator\Desktop\New.ps1:92 char:16
    + if($fileTab.ContainsKey($_.Name)){
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : ArgumentNullException

    any ideas on this? it’s relating to the following section:

    # Get VM inventory
    Get-VM -Datastore $ds | %{
    $_.ExtensionData.LayoutEx.File | %{
    if($fileTab.ContainsKey($_.Name)){
    $fileTab.Remove($_.Name)
    }
    }
    }

    Have had a look to see if we have a datastore within this cluster with no name but nothing I could see.

    Any thoughts on this would be useful as I am a bit stumped.

      LucD

      Hi Chris,
      Judging from that snippet I would suspect a VM without files.
      A kind of “ghost” VM.
      Do you know for which VM the error is produced?
      Luc

        Chris

        Hello LucD,

        Yes we actually have a VM that’s listed in inventory but the HDD’s currently been taken out of it.

        I would never have guessed at that from the output.. however my PS is somewhat lacking, so it’s probably obvious.

        Thank you

    Danny Z

    Hi LucD,

    I tried using the script but I keep getting the following message.
    Here is code to call the function:

    $cred = Get-Credential
    $vcNames = Get-Content “C:\Temp\p2298.txt”

    Connect-VIServer -Server $vcNames -Credential $cred

    Get-datastore -name DS* | Get-VmwOrphan

    Get-VmwOrphan : The term ‘Get-VmwOrphan’ is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was
    included, verify that the path is correct and try again.
    At line:1 char:47
    + Get-Cluster -Name MyCluster | Get-Datastore | Get-VmwOrphan
    + ~~~~~~~~~~~~~
    + CategoryInfo : ObjectNotFound: (Get-VmwOrphan:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

    Can you please help?

      LucD

      You will have to include the function.
      One way of doing that is to copy/paste the function to your .ps1 file.
      Then, from the same .ps1 file, you can call the function.

      function Get-VmwOrphan{
      ...
      }

      Get-VmwOrphan -Datastore MyDS1

    Michael Anselmi

    Hello LucD,

    I’ve been using your script for quite a while now. Thank you. I see that the version I have is an old one. Looked at your changelog but didn’t see if you ever added support for the new content libraries. Would you be interested in adding support?

    Kind regards,

    Michael.

      LucD

      Thanks Michael.

      I’ll have a look if that is possible

    Johnn Wong

    getting this message in PowerCLI
    WARNING: The ‘Accessible’ property of Datastore type is deprecated. Use the ‘State’ property instead.

      LucD

      Thanks for reporting that John.
      I updated the code to

      if($ds.Type -eq "VMFS" -and $ds.ExtensionData.Summary.MultipleHostAccess -and $ds.State -eq 'Available'){

    LB-ATL

    I think I must’ve had a stroke or something because I cannot, for the LIFE of me, get this to return ANY result.

    I tried the unregistered VM trick… nothing.
    I tried adding the code after the script that “calls the function”… nothing.

    I don’t know what I’m doing wrong.

    I copy/pasted the code into a PS1 file named “Get-VmwOrphan.ps1”

    From PowerCLI (latest)

    I connected to my vCenter…
    I then typed “Get-Datastore | Get_VmwOrphan”

    I got a prompt – no output.

    I tried using “.\Get-VmwOrphan.ps1”

    I got a prompt – no output.

    ARGH.

      LB-ATL

      Also, this is on a vSAN, so it doesn’t register as VMFS5 (If that matters)

      LucD

      If you stored the function in that .ps1 file, you will have to dot-source that file.
      That way the PS engine knows the function.

      . .\file.ps1

      Notice the blank between the 2 dots.
      The example assumes the .ps1 file is located in your current directory, but it could be anywhere.
      Just adapt the path.

      . C:\Scripts\file.ps1

        LucD

        The function does test for a VMFS datastore, but you should be able to leave that Where-clause out.
        With VSAN there is an issue, since the path the VM uses internally is not with the user-friendly datastorename, but with a king of GUID.
        The function will not work with that.

    Nathan C

    I have been using your script in a large environemnt, I have nearly 3000 volumes. I was tasked with finding orphans and this script came in very handy. I have discovered 2 issues. One I was able to fix, the other still eludes me. Both give the exact same error(almsost).

    The Errors…
    1. The Volume name being passed 2 times with a space in between….
    Exception calling “SearchDatastoreSubFolders” with “2” argument(s): “Invalid datastore path ‘[LOC-91253-BIZU-VMC000-Temp-DS01 LOC-91253-BIZU-VMC000-Temp-DS01]’.”
    At C:\VMWareScripts\LucD\UpdatedOrphansFunction\NewOrphans.ps1:68 char:1
    + $searchResult = $dsBrowser.SearchDatastoreSubFolders($rootPath, $searchSpec) | S …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : VimException

    2. The Volume being called only once no spaces, but a “-” sign inside the Volume name…
    Exception calling “SearchDatastoreSubFolders” with “2” argument(s): “Invalid datastore path ‘[97354_BIZU-CL01_DS03]’.”
    At C:\users\nathan_choate\GIT\HCLS-VM-Toolkit\NATHAN\LucD\UpdatedOrphansFunction\NewOrphans.ps1:68 char:1
    + $searchResult = $dsBrowser.SearchDatastoreSubFolders($rootPath, $searchSpec) | S …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : VimException

    ====
    On item #1, with the volume listed twice with a space in between, this ended up being from having multiple vcenters with cross shared volumes, I solved this in the code…
    Your line 74 >> $dsBrowser = Get-View -Id $ds.ExtensionData.browser
    Your line 75 >> $rootPath = “[” + $ds.Name + “]”
    My New Line added >> $dsBrowser = $dsBrowser[0] > $searchResult = $dsBrowser.SearchDatastoreSubFolders($rootPath, $searchSpec) | Sort-Object -Property {$_.FolderPath.Length}

    ====
    As for item #2 im still stumped, I figured its got to be the ‘minus’ sign in the volume name…..
    PowerCLI C:\VMWareScripts\LucD\UpdatedOrphansFunction\082819run> $rootpath
    [97354_BIZU-CL01_DS03]
    PowerCLI C:\VMWareScripts\LucD\UpdatedOrphansFunction\082819run> $rootPath = “[“”97354_BIZU-CL01_DS03″”]”
    PowerCLI C:\VMWareScripts\LucD\UpdatedOrphansFunction\082819run> $rootPath
    [“97354_BIZU-CL01_DS03”]
    PowerCLI C:\VMWareScripts\LucD\UpdatedOrphansFunction\082819run> $searchResult = $dsBrowser.SearchDatastoreSubFolders($rootPath, $searchSpec)
    Exception calling “SearchDatastoreSubFolders” with “2” argument(s): “Invalid datastore path ‘[“97354_BIZU-CL01_DS03″]’.”
    At line:1 char:1
    + $searchResult = $dsBrowser.SearchDatastoreSubFolders($rootPath, $searchSpec)
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : VimException

    I have tried to force quotes around the $rootpath variable, but I cant seem to get the method to accept a volume with a ‘dash’ inside it. I have a number of these, its a large environment with many people and so its hard to just ‘fix’ the names, I was hoping to get some fresh ideas on how to deal with this. Thanks.

      Otis Wheeler

      I don’t know if you got an answer but I had issues with the Exception calling “SearchDatastoreSubFolders” with “2” argument(s): “Invalid..
      You will need to specify the vcenter you are wanting to get the data from. this is easy with just a couple of edits.
      after the line
      if($ds.extensiondata.summary.MaintenanceMode -eq “normal”){
      add this line
      $Vcenter = [regex]::Split($ds.Uid,’.*@(.*):’)[1]
      and then edit the $dsBrowser line and add the -server
      $dsBrowser = Get-View -Id $ds.ExtensionData.browser -server $Vcenter

      now when you call the function you will have to do the same.
      $MyCluster = get-cluster somecluster
      $Vcenter = [regex]::Split($MyCluster.Uid,’.*@(.*):’)[1]
      $ClusterObj | Get-Datastore -server $Vcenter | Get-VmwOrphan

      the reason I have to do this is because I am connected to 8 vcenters when I run this function so it see’s multiple datastores with the same ID

        LucD

        Thanks for posting that fix.

        Travis

        You can also use $ds.GetClient().Config.Server to get the server of the datastore rather than trimming the UID.

    Thomas

    First off, thanks for this function – will edefinately come in handy.

    I do however experience a slight issue, in that I’m getting no output.

    PowerShel: 5.1.18362.145
    VMware PowerCLI 11.2.0 build 12483598

    When running the function:

    Get-VmwOrphan -datastore fast03
    VERBOSE: 6/12/2019 8:36:42 AM Get-Datastore Finished executio

    And that’s it. What am I missing?

    Running Get-Datastore -name “fast03” shows expected output, so I know I’m connected and using a valid datastore.

    Thanks

      LucD

      Hi Thomas,
      Could it be that there are no orphaned files on that datastore?
      As a test, can you create a dummy VM on that datastore and then unregister it.
      When you then call the function, the files of that dummy VM should be shown.

        Thomas

        Hi

        Still doesn’t show anything. Wouldn’t the script output “”No orphaned files found on $($ds.Name).” if nothing had been found? After hitting “Enter”, i only the above verbose output, and the command finished instantly.

        It’s like it never really initiates or starts to run.

          LucD

          Hi Thomas,
          Sorry to hear that.
          Could it be that this datastore does not pass the test in line 67 (VMFS and shared and accessible)?

            Thomas

            Hi

            You hit the nail! It’s not a VMFS datastore at all (NFS 3).

            Thanks for the assistance.

              LucD

              You can still use the same logic, just remove the test for the VMFS type and the shared storage.

    Prashant

    Thanks for the excellent script. The sample code with ImportExcel function is missing operators. Please modify the sample code with ImportExcel function as:
    ====
    $reportName = ‘C:\temp\VMW-orphan-report-MYCluster.xlsx’
    foreach($ds in (Get-Cluster -Name MYCluster | Get-Datastore | Get-VmwOrphan |
    Group-Object -Property {$_.Folder.Split(‘]’)[0].TrimStart(‘[‘)})){
    $ds.Group | Export-Excel -Path $reportName -WorkSheetname $ds.Name -AutoSize -AutoFilter -FreezeTopRow
    }
    ====

    The output is listing Templates as being orphaned and is also picking up VMware-*.log files from actual VMs that exist. A sample output is attached:

    Name Folder Size
    vmware.log [MY_VMDATASTORE_05] MY-VMW-123-02/vmware.log 308926
    UBUNTU-18.vmtx [MY_VMDATASTORE_05] UBUNTU-18/UBUNTU-18.vmtx 2686
    vmware-7.log [MY_VMDATASTORE_05] MY-VMW-123_restored/vmware-7.log 1161458
    vmware-1.log [MY_VMDATASTORE_05] VCSA01/vmware-1.log 267696
    vmware-6.log [MY_VMDATASTORE_05] MY-vm-1234_restored/vmware-6.log 724546
    windows-2012-r2.vmtx [MY_VMDATASTORE_05] windows-2012-r2/windows-2012-r2.vmtx 2542
    vmware-1.log [MY_VMDATASTORE_05] MY-Pilot-02/vmware-1.log 397817

      LucD

      Thanks for the feedback.

      I’m not sure what you mean with “missing operators”?
      That sample seems to work for me, and the code you included looks exactly as what I have, except for the Path of the file.

      The script indeed also lists templates, but only when they are orphaned. In other words not registered in the vCenter.

      The vmware.log files are not automatically removed when the logging cycles. So you could have for example 5 vmware.log type files attached to the VM, while there can be other vmware.log type files that are not connected to the VM anymore. In other words orphaned.

        Shaneb

        howdy

        the code from your block above is missing a } as the person above pointed out

        The sample above reads

        foreach($ds in (Get-Cluster -Name MyCluster | Get-Datastore | Get-VmwOrphan |
        Group-Object -Property {$_.Folder.Split(‘]’)[0].TrimStart(‘[‘))){

        it should read

        foreach($ds in (Get-Cluster -Name MyCluster | Get-Datastore | Get-VmwOrphan |
        Group-Object -Property {$_.Folder.Split(‘]’)[0].TrimStart(‘[‘)}))

        with a extra } after trimstart(‘{‘)

          LucD

          Thanks for noticing.
          I corrected the sample.

    Scott

    For some reason mine is listing Templates as being orphaned even though they aren’t. It is also picking up VMware-*.log files from actual VMs that exist. Does it not filter out Templates? Not sure on why the log files are showing up either.

      LucD

      Normally it checks if the files it finds belong to a registered VM. If they don’t, it reports the file as orphaned.
      Can you send me an example (you can use the Contact form)?

    Peter

    Hi Luc,

    I have placed your code – from 1st row to 138th – and then we pasted the following from 139th:
    $reportName = ‘C:\orphan-report.xlsx’

    foreach($ds in (Get-Cluster -Name LABMHM | Get-Datastore | Get-VmwOrphan |
    Group-Object -Property {$_.Folder.Split(‘]’)[0].TrimStart(‘[‘)})){
    $ds.Group | Export-Excel -Path $reportName -WorkSheetname $ds.Name -AutoSize -AutoFilter -FreezeTopRow

    The whole code(from st row to 144) was saved as Get-VmwOrphan.ps1
    There is an error message when it runs
    PS C:\> .\Get-VmwOrphan.ps1
    WARNING: The ‘Accessible’ property of Datastore type is deprecated. Use the ‘State’ property instead.
    Exception calling “Add” with “2” argument(s): “Az elemet korábban már felvették. Kulcs a szótárban: „[CX4_Medium] log” ; Felvétel alatt álló kulcs: „[CX4_Medium] Log”.”
    At C:\Get-VmwOrphan.ps1:80 char:13
    + $fileTab.Add($key,$file)
    + ~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : ArgumentException

    In english: Exception calling “Add” with “2” argument(s): “Item has already been added. Key in dictionary: „[CX4_Medium] log” ; Key being added: „[CX4_Medium] Log”.”

    PowerCLI Version
    —————-
    VMware PowerCLI 11.0.0 build 10380590
    —————
    Component Versions
    —————
    VMware Cis Core PowerCLI Component PowerCLI Component 11.0 build 10335701
    VMware VimAutomation VICore Commands PowerCLI Component PowerCLI Component 11.0 build 10336080

    Your assistant and cooperation is highly appreciacted in this matter!

    Sincerely,
    Peter

      LucD

      Hi Peter,
      Can you give it a try with

      $reportName = 'C:\orphan-report.xlsx'

      Get-Cluster -Name LABMHM | Get-Datastore -PipelineVariable ds |
      ForEach-Object -Process {
      Get-VmwOrphan -Datastore $_
      } |
      Group-Object -Property {$_.Folder.Split(']')[0].TrimStart('[')} |
      Select -ExpandProperty Group |
      Export-Excel -Path $reportName -WorkSheetname $ds.Name -AutoSize -AutoFilter -FreezeTopRow

      You can ignore the Warning.

    Mariano

    Hello, please help as I get the following error:

    PowerCLI C:\> Import-Module C:\Users\user\Desktop\Orphaned_VM_Script.ps1
    PowerCLI C:\> Remove-OrphanedData -Datastore wrp-archive
    Get-View : 15/02/2019 2:46:50 PM Get-View View with Id ‘FileManager-FileManager’ was not found on the server(s).
    At C:\Users\user\Desktop\Orphaned_VM_Script.ps1:30 char:12
    + $fileMgr = Get-View FileManager
    + ~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : ObjectNotFound: (:) [Get-View], VimException
    + FullyQualifiedErrorId : Core_GetView_WriteNotFoundError,VMware.VimAutomation.ViCore.Cmdlets.Commands.DotNetInter
    op.GetVIView

      LucD

      I’m not sure why you are trying to do an Import-Module of the .ps1 file?
      When you want use a function, store the code in a .ps1 file.
      At the end of that file, add the line that calls the function.
      Now from a PowerShell prompt, invoke the .ps1 file, by typing it’s path

    Rajug VCP

    Thank you LuCD,
    am lil confused. I just used the main script and ran in Powercli its nothing happning.
    do I need to copy the other lines also with main script?
    foreach($ds in (Get-Cluster -Name MyCluster | Get-Datastore | Get-VmwOrphan |
    Group-Object -Property {$_.Folder.Split(‘]’)[0].TrimStart(‘[‘))){
    $ds.Group | Export-Excel -Path $reportName -WorkSheetname $ds.Name -AutoSize -AutoFilter -FreezeTopRow
    }

      LucD

      Hi Rajug,
      Yes, the function in itself will not do anything.
      You will have to call the function.
      You can place that call in the same .ps1 file as the one you placed the function in.
      The code you included is such a call to the function.

    ANkoji

    Hi Lucd,

    Where I need to copy below lines in Script for output

    $reportName = ‘C:\orphan-report.xlsx’
    foreach($ds in (Get-Cluster -Name MyCluster | Get-Datastore | Get-VmwOrphan |
    Group-Object -Property {$_.Folder.Split(‘]’)[0].TrimStart(‘[‘))){
    $ds.Group | Export-Excel -Path $reportName -WorkSheetname $ds.Name -AutoSize -AutoFilter -FreezeTopRow
    }

      LucD

      The Get-VmwOrphan is a function.
      You can copy the complete function to a .ps1 file, and then place your lines of code at the bottom of your .ps1 file (outside the function).

    RegReg

    very good thank you

    Pete

    Great script, thanks! I used installed the ImportExcel module and tried your sample code and got an error. It looks like it’s missing a } at the end of line 4 before the final 2 closing parenthesis. Line 4 should be as follows. At least that’s how it worked for me.

    Group-Object -Property {$_.Folder.Split(‘]’)[0].TrimStart(‘[‘)})){

    Jon

    Can folders be excluded? When I modify for including NFS datastores, NetApp snapshots directory (.snapshot) becomes visible too and the scan sorts through all of that as well. Slows down the scan unnecessarily. Thoughts?

      LucD

      Hi Jon,
      The SearchDatastoreSubFolders method doesn’t have any options to exclude specific folders I’m afraid.
      The only option I can think of is to call the Get-VmwOrphan function and then filter the results with a Where-clause on the Folder property.
      Luc

    Dario

    Hi Luc,

    there seems to be a error when using this script with PowerCLI 6.5:
    C:\Program Files (x86)\VMware\Infrastructure\vSphere PowerCLI\Scripts\Initialize-PowerCliEnvironment.ps1
    WARNING: The ‘Accessible’ property of Datastore type is deprecated. Use the ‘State’ property instead.
    Exception calling “SearchDatastoreSubFolders” with “2” argument(s): “Invalid datastore path ‘[s-infra-00-001]’.”
    At D:\sw\Script\PowerShell\VMWare\Get-Orphaned-Files-2.1.ps1:68 char:1
    + $searchResult = $dsBrowser.SearchDatastoreSubFolders($rootPath, $searchSpec) | S …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : VimException

    And in your sample code at the bottom of the post there is a “}” missing on line 3.

    JD

    Hey LucD

    Just getting your script to run after hunting around

    I get the following error:
    PowerCLI C:\Program Files (x86)\VMware\Infrastructure\vSphere PowerCLI> Get-VmwO
    rphan -Datastore V-Cluster2-DISKa
    WARNING: The ‘Accessible’ property of Datastore type is deprecated. Use the
    ‘State’ property instead.
    Unable to find type [ordered]: make sure that the assembly containing this type
    is loaded.
    At C:\Users\jdesmarais\Documents\WindowsPowerShell\Modules\MyFunctions\MyFuncti
    ons.psm1:103 char:17
    + $obj = [ordered] <<<< @{
    + CategoryInfo : InvalidOperation: (ordered:String) [], RuntimeEx
    ception
    + FullyQualifiedErrorId : TypeNotFound

      JD

      I figured it out, I needed powershell 3 for windows 7.

    JerH

    Thanks for taking the time and effort to create these scripts. I’m really new to using PS scripts in VMware. I’m assuming somewhere along the way, I need to specify which vCenter to run this on? Can you help with the proper language for that? Also, I get an error with I try to run it with the export-excel function. Do I just paste that code into the end of your script? Maybe I need to download Doug Finkel’s code to make it work? Sorry for the annoying newb questions, but I’m not getting anywhere trying to figure it out on my own…

    Dennis Zimmer

    Great Script Luc! I would change line 67 to avoid an error for datastores that can’t be accessed.
    if($ds.Type -eq “VMFS” -and $ds.ExtensionData.Summary.MultipleHostAccess -and $ds.Accessible){

    That script will definitely makes its way into our OpBot repository!

      LucD

      Great suggestion Dennis.
      The code has been updated.

        Vladimir

        Hi LucD! In order to include NFS shared volumes, I would like to change line like 67 this

        if((($ds.Type -eq “VMFS”) -or ($ds.Type -eq “NFS”)) -and $ds.ExtensionData.Summary.MultipleHostAccess -and $ds.State -eq “Available”) {

        (already included ds.State instead deprecated ds.Accessible property)

    Dennis Zimmer

    Amazing script Luc, that will find its way into our OpBot function library. Small improvement, that the script runs through even if some datastores are not accessible:
    Line 61
    if($ds.Type -eq “VMFS” -and $ds.ExtensionData.Summary.MultipleHostAccess){

    I would change to
    if($ds.Type -eq “VMFS” -and $ds.ExtensionData.Summary.MultipleHostAccess -and $ds.Accessible){

    Todd Scalzott

    Thanks so much for this great script, Luc.

    Are you missing “$_.Group |” prior to “Export-Excel” in your sample utilizing the ImportExcel module?

    Thanks,
    Todd

      LucD

      Thanks Todd, your assumption is correct, well spotted.
      I updated the sample code.

    Stu Green

    Hi Luc,

    Thanks for this script 🙂

    I added this filter which I found to give the output in Byte\KB\MB\GB\TB\PB format

    https://mjolinor.wordpress.com/2012/04/18/powershell-byte-count-formatting-simplified/

    Cheers!

    Ritam9

    Hi Luc,
    Thanks again for your wonderful scripts. Is this has to be run from the Powershell only ? I am not able to run from powercli . Can you provide the script which can be run from the powercli. Also does it avoid snapshot files / ctk files ?

    PowerCLI D:\> powercliversion

    PowerCLI Version
    —————-
    VMware vSphere PowerCLI 5.1 Release 1 build 793510
    —————
    Snapin Versions
    —————
    VMWare AutoDeploy PowerCLI Component 5.1 build 768137
    VMWare ImageBuilder PowerCLI Component 5.1 build 768137
    VMware License PowerCLI Component 5.1 build 669840
    VMware vSphere PowerCLI Component 5.1 build 793489

      LucD

      Hi Ritam9,
      You have to download the function, under The Script, from the post, and store it in a .ps1 file.
      Now, at the end of the file, you will have to call the function. I have some examples of that in the Sample Usage.
      Once you have all that in the .ps1 file, save the file and from the PowerCLI prompt you can call the .ps1 file.
      Note that you will have to connect (Connect-VIServer) first to a vSphere Server (vCenter or ESXi node).
      I hope that helps.
      Luc

    Tony

    Thanks for another great script. Note, in your example section you have Get-VmwOrphaned -Datastore DS1, which should be updated to Get-VmwOrphan

      LucD

      Thanks Tony.
      And thanks for spotting that!

Leave a Reply

Your email address will not be published. Required fields are marked *

*
*

This site uses Akismet to reduce spam. Learn how your comment data is processed.