The New-PSDrive is slower than your grandmother, at scale.
I wrote this function to use the vCenter Datastore Browser instead, which is vastly faster to find content on Datastores.
Remember, ALWAYS use Get-View if it has the data you need vs. the other Get-vObject cmdlets, as it is much faster. if it is in .ExtensionData, for the object Get-View is your best choice for performance on a large scale. for a small number of objects the performance difference is going to be negligible.
Function global:Browse-DataStore{
<#
.SYNOPSIS
Enumerates Folders and Files on a DataStore
.DESCRIPTION
Enumerates Folders and Files on a DataStore
.PARAMETER Datastore
Datastore Name, View or Object
.PARAMETER Server
vCenter Name, Service Instance, or Object
.EXAMPLE
Browse-DataStore -Datastore "DatastoreName" -Server "vCenterName" -Folder "FolderName"
This retrieves the directory structure and writes to screen as an object
.EXAMPLE
Browse-DataStore -Datastore (Get-Datastore "DatastoreName" -Server "vCenterName") -Folder "FolderName"
.EXAMPLE
Browse-DataStore -Datastore (Get-View ViewType Datastore -Filter @{"name"="DatastoreName"} -Server "vCenterName")
.NOTES
This function to circumvent the need for New-PSdrive to read the files on a Datastore
$vCenter = "vCenterName"
$DataStore = Get-Datastore "DataStoreName" -Server $vCenter
$FolderName = "FolderName"
New-PSDrive -Location $DataStore -Name TargetDS -PSProvider VimDatastore -Root "\" | Out-Null
Get-ChildItem "TargetDS:/$FolderName" -Include * -Recurse | Select Name,@{n="Size";e={$_.Length}},LastWriteTime,DatastoreFullPath
Remove-PSDrive -Name TargetDS
.COMPONENT
PowerShell
PowerCLI
.LINK
#No online help available.
#To see the information on Function Options, type: "get-help about_Comment_Based_Help".
#>
[CmdletBinding()]
[OutputType([Object])]
Param (
[parameter(Mandatory, ValueFromPipeline=$True, HelpMessage="Datastore(s) to Browse.")][Object]$Datastore,
[parameter(Mandatory=$False, ValueFromPipeline=$True, HelpMessage="Folder on Datastore(s) to Browse.")][String]$Folder,
[Parameter(Mandatory=$False, ValueFromPipeline=$True, HelpMessage="vCenter(s) to query.")][Object]$Server = $(IF($Global:DefaultVIServers.Name){$Global:DefaultVIServers}ElseIf($Global:DefaultVIServer.Name){$Global:DefaultVIServer}Else{$NULL}),
[ValidateNotNull()]
[System.Management.Automation.PSCredential]
[System.Management.Automation.Credential()]
$Credential = [System.Management.Automation.PSCredential]::Empty
)
Begin{
Function Connect-VC{
IF(((!($Global:DefaultVIServer | ?{$_.Name -eq $Server}).IsConnected)) -OR ((!($Global:DefaultVIServers | ?{$_.Name -eq $Server}).IsConnected))){
IF(!($Credential)){$Credential = Get-Credential -UserName $Env:UserName -Message "Enter Password to connect to `r`n vCenter [$Server]"}
$vCenter = ""; $vCenter = Connect-VIServer -Server $Server -Credential $Credential
}Else{
IF((!($Global:DefaultVIServer | ?{$_.Name -eq $Server}).IsConnected)){$vCenter = ""; $vCenter = ($Global:DefaultVIServer | ?{$_.Name -eq $Server})}
IF((!($Global:DefaultVIServers | ?{$_.Name -eq $Server}).IsConnected)){$vCenter = ""; $vCenter = ($Global:DefaultVIServers | ?{$_.Name -eq $Server})}
}
}
IF($Server){
IF($(($Server).GetType().Name) -eq "string"){
#Is String
Connect-VC
}ElseIF($(($Server).GetType().Name) -eq "VIServerImpl"){
#Is Connect-VIServer Object
$AnyvCenterConnected = $False
Foreach($Item in $Server){IF($Item.IsConnected -eq $True){$AnyvCenterConnected = $True}}
IF($AnyvCenterConnected -eq $False){Write-Host -Fore Yellow "No vCenter Connected, quitting..."; Break}
$vCenter = $Server
}ElseIF($(($Server).GetType().Name) -eq "ServiceInstance"){
#Is Get-View ServiceInstance Object
$vCenter = $(($Server).Client.ServiceUrl.Split("/")[2])
Connect-VC
}ElseIF($(($Server).GetType().Name) -eq "Object[]"){
#Is a Collection
$AnyvCenterConnected = $False
Foreach($Item in $Server){IF($Item.IsConnected -eq $True){$AnyvCenterConnected = $True}}
IF($AnyvCenterConnected -eq $False){Write-Host -Fore Yellow "No vCenter Connected, quitting..."; Break}
$vCenter = $Server
}
}
}
Process{
IF($Datastore){
Foreach($DS in $Datastore){
IF($(($DS).GetType().Name) -eq "string"){
#Is String
$DSView = (Get-View -ViewType DataStore -Server $vCenter -Filter @{"name"="$($DS)"})
$DSBrowser = Get-View -ID $(($DSView).Browser) -Server $vCenter
}ElseIF((($DS).GetType().Name) -eq "VmfsDatastoreImpl"){
#Is Get-Datastore Object
$DSView = $DS.ExtensionData
$DSBrowser = Get-View -ID $(($DSView).Browser) -Server $($DS.Uid.Split("@",2).Split(":",2)[1])
}ElseIF($(($DS).GetType().Name) -eq "Datastore"){
#Is Get-View Datastore Object
$DSView = $DS
$DSBrowser = Get-View -ID $($DS.Browser) -Server $($DS.Client.ServiceUrl.Split("/")[2])
}
IF($DSBrowser){
$FileQueryFlags = New-Object VMware.Vim.FileQueryFlags
$FileQueryFlags.FileSize = $true
$FileQueryFlags.FileType = $true
$FileQueryFlags.Modification = $true
$FolderFileInfo = New-Object VMware.Vim.FolderFileInfo
$FolderFileQuery = New-Object VMware.Vim.FolderFileQuery
$DatastoreBrowserSearchSpec = New-Object VMware.Vim.HostDatastoreBrowserSearchSpec
$DatastoreBrowserSearchSpec.details = $FileQueryFlags
$DatastoreBrowserSearchSpec.sortFoldersFirst = $true
#$RootPath = "[" + $DSView.Summary.Name + "]"
$RootPath = "[" + $DSView.Name + "]"
If($Folder){$RootPath = $RootPath + " " + $Folder}
$SearchResult = $DSBrowser.SearchDatastoreSubFolders($RootPath, $DatastoreBrowserSearchSpec)
$Report = @()
Foreach ($FolderObject in $SearchResult){
Foreach ($Item in $FolderObject.File){
$File = "" | Select Name, Size, Modified, FullPath
$File.Name = $Item.Path
$File.Size = $Item.Filesize
$File.Modified = $Item.Modification
$File.FullPath = $FolderObject.FolderPath + $File.Name
$Report += $File
}
}
$Report = $Report | Sort Name
Return $Report
}
}
}Else{Write-Host -Fore Yellow "No Datastore(s) provided, quitting..."; Break}
}
End{}
}