Estimados,
Alguien conoce algún scripts de como encontrar archivos huerfanos, zombies, carpetas sin uso, osea limpiar mis datastore de todos los archivos sin uso.
Nota: estoy utilizando rvtools, pero solo me muestra los .vmkd
Sorry for replying in English.
You might want to have a look at my Orphaned Files And Folders – Spring Cleaning post
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Hola como ejecuto el script, se debe modificar?
Se ejecuta con powercli?
Me debo conectar al vcenter por powercli?
Yes, the script is a PowerShell function, just copy it to a .ps1 file.
And yes, the function requires PowerCLI to be installed.
In the .ps1 file, after the function, add a Connect-VIServer.
Then on the next line call the Remove-OrpahedData function, you have to provide a datastore as a parameter.
Then call it all by typing the name of the .ps1 file at the PSprompt.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
La linea de conexión la agrego aquí, lo otro donde ingreso los datastore en que linea?:
Connect-VIServer -Server 10.1x.x.xx -Protocol https -User xx\xx -Password xxxx$
function Remove-OrphanedData {
<#
.SYNOPSIS Remove orphaned folders and VMDK files
.DESCRIPTION The function searches orphaned folders and VMDK files
on one or more datastores and reports its findings.
Optionally the function removes the orphaned folders and VMDK files
.NOTES Author: Luc Dekens
.PARAMETER Datastore
One or more datastores.
The default is to investigate all shared VMFS datastores
.PARAMETER Delete
A switch that indicates if you want to remove the folders
and VMDK files
.EXAMPLE
PS> Remove-OrphanedData -Datastore ds1
.EXAMPLE
PS> Get-Datastore ds* | Remove-OrphanedData
.EXAMPLE
PS> Remove-OrphanedData -Datastore $ds -Delete
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[parameter(Mandatory=$true,ValueFromPipeline=$true)]
[PSObject[]]$Datastore,
[switch]$Delete
)
begin{
$fldList = @{}
$hdList = @{}
$fileMgr = Get-View FileManager
}
process{
foreach($ds in $Datastore){
if($ds.GetType().Name -eq "String"){
$ds = Get-Datastore -Name $ds
}
if($ds.Type -eq "VMFS" -and $ds.ExtensionData.Summary.MultipleHostAccess){
Get-VM -Datastore $ds | %{
$_.Extensiondata.LayoutEx.File | where{"diskDescriptor","diskExtent" -contains $_.Type} | %{
$fldList[$_.Name.Split('/')[0]] = $_.Name
$hdList[$_.Name] = $_.Name
}
}
Get-Template | where {$_.DatastoreIdList -contains $ds.Id} | %{
$_.Extensiondata.LayoutEx.File | where{"diskDescriptor","diskExtent" -contains $_.Type} | %{
$fldList[$_.Name.Split('/')[0]] = $_.Name
$hdList[$_.Name] = $_.Name
}
}
$dc = $ds.Datacenter.Extensiondata
$flags = New-Object VMware.Vim.FileQueryFlags
$flags.FileSize = $true
$flags.FileType = $true
$disk = New-Object VMware.Vim.VmDiskFileQuery
$disk.details = New-Object VMware.Vim.VmDiskFileQueryFlags
$disk.details.capacityKb = $true
$disk.details.diskExtents = $true
$disk.details.diskType = $true
$disk.details.thin = $true
$searchSpec = New-Object VMware.Vim.HostDatastoreBrowserSearchSpec
$searchSpec.details = $flags
$searchSpec.Query += $disk
$searchSpec.sortFoldersFirst = $true
$dsBrowser = Get-View $ds.ExtensionData.browser
$rootPath = "[" + $ds.Name + "]"
$searchResult = $dsBrowser.SearchDatastoreSubFolders($rootPath, $searchSpec)
foreach($folder in $searchResult){
if($fldList.ContainsKey($folder.FolderPath.TrimEnd('/'))){
foreach ($file in $folder.File){
if(!$hdList.ContainsKey($folder.FolderPath + $file.Path)){
New-Object PSObject -Property @{
Folder = $folder.FolderPath
Name = $file.Path
Size = $file.FileSize
CapacityKB = $file.CapacityKb
Thin = $file.Thin
Extents = [string]::Join(',',($file.DiskExtents))
}
if($Delete){
If ($PSCmdlet.ShouldProcess(($folder.FolderPath + " " + $file.Path),"Remove VMDK")){
$dsBrowser.DeleteFile($folder.FolderPath + $file.Path)
}
}
}
}
}
elseif($folder.File | where {"cos.vmdk","esxconsole.vmdk" -notcontains $_.Path}){
$folder.File | %{
New-Object PSObject -Property @{
Folder = $folder.FolderPath
Name = $_.Path
Size = $_.FileSize
CapacityKB = $_.CapacityKB
Thin = $_.Thin
Extents = [String]::Join(',',($_.DiskExtents))
}
}
if($Delete){
if($folder.FolderPath -eq $rootPath){
$folder.File | %{
If ($PSCmdlet.ShouldProcess(($folder.FolderPath + " " + $_.Path),"Remove VMDK")){
$dsBrowser.DeleteFile($folder.FolderPath + $_.Path)
}
}
}
else{
If ($PSCmdlet.ShouldProcess($folder.FolderPath,"Remove Folder")){
$fileMgr.DeleteDatastoreFile($folder.FolderPath,$dc.MoRef)
}
}
}
}
}
}
}
}
}
At the end of the file where you copied all this, you have to call the function.
For example with a line like
Remove-OrphanedData -Datastore MyDS
Add a line like this at the end of the file.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Así debe quedar, lo marque en rojo?
Connect-VIServer -Server 10.1x.x.xx -Protocol https -User xx\xx -Password xxxx$
function Remove-OrphanedData {
<#
.SYNOPSIS Remove orphaned folders and VMDK files
.DESCRIPTION The function searches orphaned folders and VMDK files
on one or more datastores and reports its findings.
Optionally the function removes the orphaned folders and VMDK files
.NOTES Author: Luc Dekens
.PARAMETER Datastore
One or more datastores.
The default is to investigate all shared VMFS datastores
.PARAMETER Delete
A switch that indicates if you want to remove the folders
and VMDK files
.EXAMPLE
PS> Remove-OrphanedData -Datastore Datastore-1
.EXAMPLE
PS> Get-Datastore ds* | Remove-OrphanedData
.EXAMPLE
PS> Remove-OrphanedData -Datastore $ds -Delete
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[parameter(Mandatory=$true,ValueFromPipeline=$true)]
[PSObject[]]$Datastore,
[switch]$Delete
)
begin{
$fldList = @{}
$hdList = @{}
$fileMgr = Get-View FileManager
}
process{
foreach($ds in $Datastore){
if($ds.GetType().Name -eq "String"){
$ds = Get-Datastore -Name $ds
}
if($ds.Type -eq "VMFS" -and $ds.ExtensionData.Summary.MultipleHostAccess){
Get-VM -Datastore $ds | %{
$_.Extensiondata.LayoutEx.File | where{"diskDescriptor","diskExtent" -contains $_.Type} | %{
$fldList[$_.Name.Split('/')[0]] = $_.Name
$hdList[$_.Name] = $_.Name
}
}
Get-Template | where {$_.DatastoreIdList -contains $ds.Id} | %{
$_.Extensiondata.LayoutEx.File | where{"diskDescriptor","diskExtent" -contains $_.Type} | %{
$fldList[$_.Name.Split('/')[0]] = $_.Name
$hdList[$_.Name] = $_.Name
}
}
$dc = $ds.Datacenter.Extensiondata
$flags = New-Object VMware.Vim.FileQueryFlags
$flags.FileSize = $true
$flags.FileType = $true
$disk = New-Object VMware.Vim.VmDiskFileQuery
$disk.details = New-Object VMware.Vim.VmDiskFileQueryFlags
$disk.details.capacityKb = $true
$disk.details.diskExtents = $true
$disk.details.diskType = $true
$disk.details.thin = $true
$searchSpec = New-Object VMware.Vim.HostDatastoreBrowserSearchSpec
$searchSpec.details = $flags
$searchSpec.Query += $disk
$searchSpec.sortFoldersFirst = $true
$dsBrowser = Get-View $ds.ExtensionData.browser
$rootPath = "[" + $ds.Name + "]"
$searchResult = $dsBrowser.SearchDatastoreSubFolders($rootPath, $searchSpec)
foreach($folder in $searchResult){
if($fldList.ContainsKey($folder.FolderPath.TrimEnd('/'))){
foreach ($file in $folder.File){
if(!$hdList.ContainsKey($folder.FolderPath + $file.Path)){
New-Object PSObject -Property @{
Folder = $folder.FolderPath
Name = $file.Path
Size = $file.FileSize
CapacityKB = $file.CapacityKb
Thin = $file.Thin
Extents = [string]::Join(',',($file.DiskExtents))
}
if($Delete){
If ($PSCmdlet.ShouldProcess(($folder.FolderPath + " " + $file.Path),"Remove VMDK")){
$dsBrowser.DeleteFile($folder.FolderPath + $file.Path)
}
}
}
}
}
elseif($folder.File | where {"cos.vmdk","esxconsole.vmdk" -notcontains $_.Path}){
$folder.File | %{
New-Object PSObject -Property @{
Folder = $folder.FolderPath
Name = $_.Path
Size = $_.FileSize
CapacityKB = $_.CapacityKB
Thin = $_.Thin
Extents = [String]::Join(',',($_.DiskExtents))
}
}
if($Delete){
if($folder.FolderPath -eq $rootPath){
$folder.File | %{
If ($PSCmdlet.ShouldProcess(($folder.FolderPath + " " + $_.Path),"Remove VMDK")){
$dsBrowser.DeleteFile($folder.FolderPath + $_.Path)
}
}
}
else{
If ($PSCmdlet.ShouldProcess($folder.FolderPath,"Remove Folder")){
$fileMgr.DeleteDatastoreFile($folder.FolderPath,$dc.MoRef)
}
}
Remove-OrphanedData -Datastore Datastore-1
}
}
}
}
}
}
No, the call to the function should go behind the function definition, meaning after the last brace of the function.
Just make it the last line in the .ps1 file
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Algo así?
Connect-VIServer -Server 10.1x.x.xx -Protocol https -User xx\xx -Password xxxx$
function Remove-OrphanedData {
<#
.SYNOPSIS Remove orphaned folders and VMDK files
.DESCRIPTION The function searches orphaned folders and VMDK files
on one or more datastores and reports its findings.
Optionally the function removes the orphaned folders and VMDK files
.NOTES Author: Luc Dekens
.PARAMETER Datastore
One or more datastores.
The default is to investigate all shared VMFS datastores
.PARAMETER Delete
A switch that indicates if you want to remove the folders
and VMDK files
.EXAMPLE
PS> Remove-OrphanedData -Datastore Datastore-1
.EXAMPLE
PS> Get-Datastore ds* | Remove-OrphanedData
.EXAMPLE
PS> Remove-OrphanedData -Datastore $ds -Delete
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[parameter(Mandatory=$true,ValueFromPipeline=$true)]
[PSObject[]]$Datastore,
[switch]$Delete
)
begin{
$fldList = @{}
$hdList = @{}
$fileMgr = Get-View FileManager
}
process{
foreach($ds in $Datastore){
if($ds.GetType().Name -eq "String"){
$ds = Get-Datastore -Name $ds
}
if($ds.Type -eq "VMFS" -and $ds.ExtensionData.Summary.MultipleHostAccess){
Get-VM -Datastore $ds | %{
$_.Extensiondata.LayoutEx.File | where{"diskDescriptor","diskExtent" -contains $_.Type} | %{
$fldList[$_.Name.Split('/')[0]] = $_.Name
$hdList[$_.Name] = $_.Name
}
}
Get-Template | where {$_.DatastoreIdList -contains $ds.Id} | %{
$_.Extensiondata.LayoutEx.File | where{"diskDescriptor","diskExtent" -contains $_.Type} | %{
$fldList[$_.Name.Split('/')[0]] = $_.Name
$hdList[$_.Name] = $_.Name
}
}
$dc = $ds.Datacenter.Extensiondata
$flags = New-Object VMware.Vim.FileQueryFlags
$flags.FileSize = $true
$flags.FileType = $true
$disk = New-Object VMware.Vim.VmDiskFileQuery
$disk.details = New-Object VMware.Vim.VmDiskFileQueryFlags
$disk.details.capacityKb = $true
$disk.details.diskExtents = $true
$disk.details.diskType = $true
$disk.details.thin = $true
$searchSpec = New-Object VMware.Vim.HostDatastoreBrowserSearchSpec
$searchSpec.details = $flags
$searchSpec.Query += $disk
$searchSpec.sortFoldersFirst = $true
$dsBrowser = Get-View $ds.ExtensionData.browser
$rootPath = "[" + $ds.Name + "]"
$searchResult = $dsBrowser.SearchDatastoreSubFolders($rootPath, $searchSpec)
foreach($folder in $searchResult){
if($fldList.ContainsKey($folder.FolderPath.TrimEnd('/'))){
foreach ($file in $folder.File){
if(!$hdList.ContainsKey($folder.FolderPath + $file.Path)){
New-Object PSObject -Property @{
Folder = $folder.FolderPath
Name = $file.Path
Size = $file.FileSize
CapacityKB = $file.CapacityKb
Thin = $file.Thin
Extents = [string]::Join(',',($file.DiskExtents))
}
if($Delete){
If ($PSCmdlet.ShouldProcess(($folder.FolderPath + " " + $file.Path),"Remove VMDK")){
$dsBrowser.DeleteFile($folder.FolderPath + $file.Path)
}
}
}
}
}
elseif($folder.File | where {"cos.vmdk","esxconsole.vmdk" -notcontains $_.Path}){
$folder.File | %{
New-Object PSObject -Property @{
Folder = $folder.FolderPath
Name = $_.Path
Size = $_.FileSize
CapacityKB = $_.CapacityKB
Thin = $_.Thin
Extents = [String]::Join(',',($_.DiskExtents))
}
}
if($Delete){
if($folder.FolderPath -eq $rootPath){
$folder.File | %{
If ($PSCmdlet.ShouldProcess(($folder.FolderPath + " " + $_.Path),"Remove VMDK")){
$dsBrowser.DeleteFile($folder.FolderPath + $_.Path)
}
}
}
else{
If ($PSCmdlet.ShouldProcess($folder.FolderPath,"Remove Folder")){
$fileMgr.DeleteDatastoreFile($folder.FolderPath,$dc.MoRef)
}
}
Remove-OrphanedData -Datastore Datastore-1
}
}
}
}
}
}
}
}
}
Remove-OrphanedData -Datastore Datastore-1
Yes
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Una duda este scripts borra los huérfanos o solo me lista los posibles huérfanos para ser borrados?
Mi idea es solamente que me genere una lista de los posibles huérfanos, ideal seria a un txt o excel.
El scritps borra automáticamente los huerfanos?
No, you have to use the Delete switch with the $true value.
By default, nothing is erased.
See also the Sample Usage in my blog post I mentioned earlier.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Para exportar a un CSV, se usa así?
Connect-VIServer -Server 10.1x.x.xx -Protocol https -User xx\xx -Password xxxx$
function Remove-OrphanedData {
<#
.SYNOPSIS Remove orphaned folders and VMDK files
.DESCRIPTION The function searches orphaned folders and VMDK files
on one or more datastores and reports its findings.
Optionally the function removes the orphaned folders and VMDK files
.NOTES Author: Luc Dekens
.PARAMETER Datastore
One or more datastores.
The default is to investigate all shared VMFS datastores
.PARAMETER Delete
A switch that indicates if you want to remove the folders
and VMDK files
.EXAMPLE
PS> Remove-OrphanedData -Datastore ds1
.EXAMPLE
PS> Get-Datastore ds* | Remove-OrphanedData
.EXAMPLE
PS> Remove-OrphanedData -Datastore $ds -Delete
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[parameter(Mandatory=$true,ValueFromPipeline=$true)]
[PSObject[]]$Datastore,
[switch]$Delete
)
begin{
$fldList = @{}
$hdList = @{}
$fileMgr = Get-View FileManager
}
process{
foreach($ds in $Datastore){
if($ds.GetType().Name -eq "String"){
$ds = Get-Datastore -Name $ds
}
if($ds.Type -eq "VMFS" -and $ds.ExtensionData.Summary.MultipleHostAccess){
Get-VM -Datastore $ds | %{
$_.Extensiondata.LayoutEx.File | where{"diskDescriptor","diskExtent" -contains $_.Type} | %{
$fldList[$_.Name.Split('/')[0]] = $_.Name
$hdList[$_.Name] = $_.Name
}
}
Get-Template | where {$_.DatastoreIdList -contains $ds.Id} | %{
$_.Extensiondata.LayoutEx.File | where{"diskDescriptor","diskExtent" -contains $_.Type} | %{
$fldList[$_.Name.Split('/')[0]] = $_.Name
$hdList[$_.Name] = $_.Name
}
}
$dc = $ds.Datacenter.Extensiondata
$flags = New-Object VMware.Vim.FileQueryFlags
$flags.FileSize = $true
$flags.FileType = $true
$disk = New-Object VMware.Vim.VmDiskFileQuery
$disk.details = New-Object VMware.Vim.VmDiskFileQueryFlags
$disk.details.capacityKb = $true
$disk.details.diskExtents = $true
$disk.details.diskType = $true
$disk.details.thin = $true
$searchSpec = New-Object VMware.Vim.HostDatastoreBrowserSearchSpec
$searchSpec.details = $flags
$searchSpec.Query += $disk
$searchSpec.sortFoldersFirst = $true
$dsBrowser = Get-View $ds.ExtensionData.browser
$rootPath = "[" + $ds.Name + "]"
$searchResult = $dsBrowser.SearchDatastoreSubFolders($rootPath, $searchSpec)
foreach($folder in $searchResult){
if($fldList.ContainsKey($folder.FolderPath.TrimEnd('/'))){
foreach ($file in $folder.File){
if(!$hdList.ContainsKey($folder.FolderPath + $file.Path)){
New-Object PSObject -Property @{
Folder = $folder.FolderPath
Name = $file.Path
Size = $file.FileSize
CapacityKB = $file.CapacityKb
Thin = $file.Thin
Extents = [string]::Join(',',($file.DiskExtents))
}
if($Delete){
If ($PSCmdlet.ShouldProcess(($folder.FolderPath + " " + $file.Path),"Remove VMDK")){
$dsBrowser.DeleteFile($folder.FolderPath + $file.Path)
}
}
}
}
}
elseif($folder.File | where {"cos.vmdk","esxconsole.vmdk" -notcontains $_.Path}){
$folder.File | %{
New-Object PSObject -Property @{
Folder = $folder.FolderPath
Name = $_.Path
Size = $_.FileSize
CapacityKB = $_.CapacityKB
Thin = $_.Thin
Extents = [String]::Join(',',($_.DiskExtents))
}
}
if($Delete){
if($folder.FolderPath -eq $rootPath){
$folder.File | %{
If ($PSCmdlet.ShouldProcess(($folder.FolderPath + " " + $_.Path),"Remove VMDK")){
$dsBrowser.DeleteFile($folder.FolderPath + $_.Path)
}
}
}
else{
If ($PSCmdlet.ShouldProcess($folder.FolderPath,"Remove Folder")){
$fileMgr.DeleteDatastoreFile($folder.FolderPath,$dc.MoRef)
}
}
}
}
}
}
}
}
}
Remove-OrphanedData -Datastore-1 | Export-Csv report.csv -NoTypeInformation -UseCulture
Yes
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Excelente, me funciono.
Existe alguna forma de averiguar, otros tipos de archivos que no sean .vmdk o carpetas que no estén en uso?
Esto me arrojo:
PowerCLI C:\> Remove-OrphanedData -Datastore_IBM_1 | Export-Csv report.csv -NoTypeInformation -UseCulture
Remove-OrphanedData : No se encuentra ningún parámetro que coincida con el nombre del parámetro 'Datastore_IBM_1'.
En línea: 1 Carácter: 21
+ Remove-OrphanedData -Datastore_IBM_1 | Export-Csv report.csv -NoTypeI ...
+ ~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Remove-OrphanedData], ParameterBindingException
+ FullyQualifiedErrorId : NamedParameterNotFound,Remove-OrphanedData
In theory yes, but I don't have a script for that I'm afraid.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
You have to provide the Datastore parameter with the name of the datastore.
If your datastore is named Datastore_IBM_1, you would call the function like this
Remove-OrphanedData -Datastore Datastore_IBM_1
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
gracias, funciono.