VMware Cloud Community
umms
Enthusiast
Enthusiast
Jump to solution

Export/Import Folder Structure

Hi,

So I found this command:

Get-folder -type VM | Foreach {($_ | Get-FolderPath).Path | Out-file C:\scripts\logs\Folders.txt -Append}

When run I get the following error:

Get-FolderPath : The term 'Get-FolderPath' 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:38

+ Get-folder -type VM | Foreach {($_ | Get-FolderPath).Path | Out-file  ...

+                                      ~~~~~~~~~~~~~~

    + CategoryInfo          : ObjectNotFound: (Get-FolderPath:String) [], CommandNotFoundException

    + FullyQualifiedErrorId : CommandNotFoundException

Anyone have any suggestions on this one? Also looking for a good Import script.

Thanks.

Reply
0 Kudos
1 Solution

Accepted Solutions
LucD
Leadership
Leadership
Jump to solution

I normally use the following 2 scripts.

To export

function Get-FolderPath{

    <#

    .SYNOPSIS

        Returns the folderpath for a folder

    .DESCRIPTION

        The function will return the complete folderpath for

        a given folder, optionally with the "hidden" folders

        included. The function also indicats if it is a "blue"

        or "yellow" folder.

    .NOTES

        Authors:    Luc Dekens

    .PARAMETER Folder

        On or more folders

    .PARAMETER ShowHidden

        Switch to specify if "hidden" folders should be included

        in the returned path. The default is $false.

    .EXAMPLE

        PS> Get-FolderPath -Folder (Get-Folder -Name "MyFolder")

    .EXAMPLE

        PS> Get-Folder | Get-FolderPath -ShowHidden:$true

    #>

 

        param(

        [parameter(valuefrompipeline = $true,

        position = 0,

        HelpMessage = "Enter a folder")]

        [VMware.VimAutomation.ViCore.Impl.V1.Inventory.FolderImpl[]]$Folder,

        [switch]$ShowHidden = $false

        )

 

        begin{

            $excludedNames = "Datacenters","vm","host"

        }

 

        process{

            $Folder | %{

                $fld = $_.Extensiondata

                $fldType = "yellow"

                if($fld.ChildType -contains "VirtualMachine"){

                    $fldType = "blue"

                }

                $path = $fld.Name

                while($fld.Parent){

                    $fld = Get-View $fld.Parent

                    if((!$ShowHidden -and $excludedNames -notcontains $fld.Name) -or $ShowHidden){

                        $path = $fld.Name + "\" + $path

                    }

                }

                $row = "" | Select Name,Path,Type

                $row.Name = $_.Name

                $row.Path = $path

                $row.Type = $fldType

                $row

            }

        }

    }

    ## Export all folders

    $report = @()

    $report = Get-folder -type VM | where{$_.Name -ne 'vm'} | Get-Folderpath

    $report | Export-Csv '.\folders.csv' -NoTypeInformation -UseCulture

To import

Import-Csv -Path '.\folders.csv' -UseCulture |

Sort-Object -Property {(Select-String -InputObject $_.Path -Pattern '/+' -AllMatches).Matches.Count} | %{

    $dcName,$rest = $_.Path.Split('\')

    $location = Get-Datacenter -Name $dcName | Get-Folder -Name 'vm'

    if($rest.count -gt 1){

        $rest[0..($rest.Count -2)] | %{

            $location = Get-Inventory -Name $_ -Location $location -NoRecursion

        }

        $newFolder = $rest[-1]

    }

    else{

        $newFolder = $rest

    }

    New-Folder -Name $newFolder -Location $location

}


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

View solution in original post

Reply
0 Kudos
17 Replies
Nawals
Expert
Expert
Jump to solution

Export all VMs list with Folder structure.

-----------------------------------------------------------------------------

New-VIProperty -Name 'BlueFolderPath' -ObjectType 'VirtualMachine' -Value {
    param($vm)

    function Get-ParentName{
        param($object)

        if($object.Folder){
            $blue = Get-ParentName $object.Folder
            $name = $object.Folder.Name
        }
        elseif($object.Parent -and $object.Parent.GetType().Name -like "Folder*"){
            $blue = Get-ParentName $object.Parent
            $name = $object.Parent.Name
        }
        elseif($object.ParentFolder){
            $blue = Get-ParentName $object.ParentFolder
            $name = $object.ParentFolder.Name
        }
        if("vm","Datacenters" -notcontains $name){
            $blue + "/" + $name
        }
        else{
            $blue
        }
    }

    (Get-ParentName $vm).Remove(0,1)
} -Force | Out-Null

$dcName = "vLAB_DC"

Get-VM -Location (Get-Datacenter -Name $dcName | Get-Cluster "vLAB_Cluster") |
Select Name, VMHost, BlueFolderPath |
Export-Csv "C:\vcenter-migration\vLAB-VMs-Folder.csv" -NoTypeInformation -UseCulture
-----------------------------------------------------------------------------

Import Folder structure and Move VMs to its original folder.


Below script will create folder structure and move VMs to its own folder as it was in old vCenter.

----------------------------------------------------------------------------------------------------------------------------------------------------------  #Import Folders and Move VMs to its folder

$vmsonha5 = Get-Cluster vLAB_Cluster | Get-VM  |sort name
$csv3 = "C:\vCenter-Migration\vLAB_VMs_Folder.csv"

$newDatacenter = "RnDDataCenter5.x"
$newFolder = "vCenter-Folders"

$startFolder = New-Folder -Name $newFolder -Location (Get-Folder -Name vm -Location (Get-Datacenter -Name $newDatacenter))
$startfolder = Get-Folder "vCenter-Folders"

$testing2 = Import-Csv $csv3 -UseCulture

$testing2 | %{
    $location = $startFolder
    $_.BlueFolderPath.TrimStart('/').Split('/') | %{
        $tgtFolder = Get-Folder -Name $_ -Location $location -ErrorAction SilentlyContinue
        if(!$tgtFolder){
            $location = New-Folder -Name $_ -Location $location
        }
        else{
            $location = $tgtFolder
        }
    }
   
#     Write-Host $location
    $hm = $_.Name2
$wups = $vmsonha5 | where {$_.name -eq $hm}

#Write-Host $hm
Move-VM -VM $wups -Destination $location -Confirm:$false -RunAsync
    }

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


If your inventory is huge and if this script takes time to complete, I would suggest splitting VM csv file and running this same script in multiple sessions for each csv

This will help you to complete the task with less time.


E.g. in my activity each signal migration was taking 8 seconds to migrate each VM, then I divided exported csv and saved with 5 different names. Created 5 different copies of above script and executed in different in PowerCLI sessions, this helped me to reduce the migration time.

NKS Please Mark Helpful/correct if my answer resolve your query.
Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

Get-FolderPath is not a PowerCLI cmdlet, but a function I wrote.

See Get The Folderpath

On your import question, how did you do the export or what is in the file with the import information?


You can use my New-VIProperties (which the previous replier copied without a reference it seems) I defined in Export / Import selective Folder structure


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
umms
Enthusiast
Enthusiast
Jump to solution

Ok, I went on that page. I copied the script and ran it.

So how would I get the script I originally put in this post to work so I can get a file that outputs the Folder structure?

Oh and for import I would just use the same format as the export script.

Reply
0 Kudos
umms
Enthusiast
Enthusiast
Jump to solution

Ok, I got this script to work to export to CSV:

Import-Module VMware.VimAutomation.Core

If ($globale:DefaultVIServers) {

Disconnect-VIServer -Server $global:DefaultVIServers -Force

}

$sourceVI = Read-Host "Please enter name or IP address of the source Server"

$datacenter = Read-Host "Datacenter name in source vCenter"

$creds = get-credential

connect-viserver -server $sourceVI -Credential $creds

filter Get-FolderPath {

    $_ | Get-View | % {

        $row = "" | select Name, Path

        $row.Name = $_.Name

       $current = Get-View $_.Parent

        $path = $_.Name

        do {

            $parent = $current

            if($parent.Name -ne "vm"){$path = $parent.Name + "\" + $path}

            $current = Get-View $current.Parent

        } while ($current.Parent -ne $null)

        $row.Path = $path

        $row

    }

}

## Export all folders

$report = @()

$report = get-datacenter $datacenter -Server $sourceVI| Get-folder vm | get-folder | Get-Folderpath

        ##Replace the top level with vm

        foreach ($line in $report) {

        $line.Path = ($line.Path).Replace($datacenter + "\","vm\")

        }

$report | Export-Csv "d:\temp\scripts\03-$($datacenter)-Folders-with-FolderPath.csv" -NoTypeInformation

Disconnect-VIServer "*" -Confirm:$False

Now I found a similar script to import the folder structure and it does it by DataCenter. I am wondering can you do it by DataCenter and then Subfolder. For example I want to import the structure to

DC=Test

Subfolder=Test

and now all folders and subfolders that were exported.

Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

I normally use the following 2 scripts.

To export

function Get-FolderPath{

    <#

    .SYNOPSIS

        Returns the folderpath for a folder

    .DESCRIPTION

        The function will return the complete folderpath for

        a given folder, optionally with the "hidden" folders

        included. The function also indicats if it is a "blue"

        or "yellow" folder.

    .NOTES

        Authors:    Luc Dekens

    .PARAMETER Folder

        On or more folders

    .PARAMETER ShowHidden

        Switch to specify if "hidden" folders should be included

        in the returned path. The default is $false.

    .EXAMPLE

        PS> Get-FolderPath -Folder (Get-Folder -Name "MyFolder")

    .EXAMPLE

        PS> Get-Folder | Get-FolderPath -ShowHidden:$true

    #>

 

        param(

        [parameter(valuefrompipeline = $true,

        position = 0,

        HelpMessage = "Enter a folder")]

        [VMware.VimAutomation.ViCore.Impl.V1.Inventory.FolderImpl[]]$Folder,

        [switch]$ShowHidden = $false

        )

 

        begin{

            $excludedNames = "Datacenters","vm","host"

        }

 

        process{

            $Folder | %{

                $fld = $_.Extensiondata

                $fldType = "yellow"

                if($fld.ChildType -contains "VirtualMachine"){

                    $fldType = "blue"

                }

                $path = $fld.Name

                while($fld.Parent){

                    $fld = Get-View $fld.Parent

                    if((!$ShowHidden -and $excludedNames -notcontains $fld.Name) -or $ShowHidden){

                        $path = $fld.Name + "\" + $path

                    }

                }

                $row = "" | Select Name,Path,Type

                $row.Name = $_.Name

                $row.Path = $path

                $row.Type = $fldType

                $row

            }

        }

    }

    ## Export all folders

    $report = @()

    $report = Get-folder -type VM | where{$_.Name -ne 'vm'} | Get-Folderpath

    $report | Export-Csv '.\folders.csv' -NoTypeInformation -UseCulture

To import

Import-Csv -Path '.\folders.csv' -UseCulture |

Sort-Object -Property {(Select-String -InputObject $_.Path -Pattern '/+' -AllMatches).Matches.Count} | %{

    $dcName,$rest = $_.Path.Split('\')

    $location = Get-Datacenter -Name $dcName | Get-Folder -Name 'vm'

    if($rest.count -gt 1){

        $rest[0..($rest.Count -2)] | %{

            $location = Get-Inventory -Name $_ -Location $location -NoRecursion

        }

        $newFolder = $rest[-1]

    }

    else{

        $newFolder = $rest

    }

    New-Folder -Name $newFolder -Location $location

}


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
the1960
Contributor
Contributor
Jump to solution

Hi LucD,

I have different scripts in use from you. Now I would use your Folder-Script (export/import). It works. During the import, however, the folders are only created up to the 3rd level.

Br Tobias

Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

I did notice that the Pattern expression in the above reply is incorrect.
I assume this is an HTML issue when the posts were migrated from the Jive platform to the Khoros platform.

That line should say (note the Pattern expression with back-slash back-slash plus-sign)

Sort-Object -Property { (Select-String -InputObject $_.Path -Pattern '\\+' -AllMatches).Matches.Count } | ForEach-Object {


Does that produce the correct folder structure on import?
I just tested with 4 levels deep, and it seems to work for me.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
the1960
Contributor
Contributor
Jump to solution

It's perfect your support.

Works fine.

Thanks so much.

Reply
0 Kudos
mldeller
Enthusiast
Enthusiast
Jump to solution

Great stuff as always @LucD 

I was wondering if your export/import script can be set to exclude any empty folders from the export part?

Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

You can add an extra condition to the Where-clause

$report = Get-folder -type VM | where{$_.Name -ne 'vm' -and $_.ExtensionData.childEntity.Count -ne 0} | Get-Folderpath


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

mldeller
Enthusiast
Enthusiast
Jump to solution

Perfect, thanks!

Reply
0 Kudos
slavonac
Enthusiast
Enthusiast
Jump to solution

Just ignore my last comment this is exactly what I needed i just had to replace datacenter on destination datacenter and then works like a charm

 

 

Reply
0 Kudos
stealthdave
Contributor
Contributor
Jump to solution

@LucD 

Hi LucD,

Thanks for the great script.

An issue I have seen when coming to import is that it sometimes tries to recreate the sub folder before the folder above is created, and fails. It's not really an issue as I just ran the script over and over until it had no more folders to create.

I tried sorting the folders.csv file by the path column, but this didn't seem to help.

Cheers

Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

Did you include the Sort-Object with the Select-String I mentioned in another reply?
That should sort the Folders based on the depth of the folderpath


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
mandeeeps468
Contributor
Contributor
Jump to solution

Export is working fine however nothing coming up in import.  Getting below error during import PS.

I used Sort-Object with the Select-String as well. (From your pervious reply)

New-Folder : 10/23/2023 1:08:39 PM New-Folder The name 'vCLS' already exists.
At line:26 char:5
+ New-Folder -Name $newFolder -Location $location
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [New-Folder], DuplicateName
+ FullyQualifiedErrorId : Client20_InventoryServiceImpl_NewFolder_ViError,
VMware.VimAutomation.ViCore.Cmdlets.Commands.NewFolder

New-Folder : Cannot convert 'System.Object[]' to the type
'VMware.VimAutomation.ViCore.Types.V1.Inventory.VIContainer' required by
parameter 'Location'. Specified method is not supported.
At line:26 char:43


+ New-Folder -Name $newFolder -Location $location
+ ~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [New-Folder], ParameterBind
ingException
+ FullyQualifiedErrorId : CannotConvertArgument,VMware.VimAutomation.ViCor
e.Cmdlets.Commands.NewFolder

===============================

 CSV data from Export PS  - Attached



Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

You didn't exclude the 'vCLS' folder.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
mandeeeps468
Contributor
Contributor
Jump to solution

Updated script and excluded 'vCLS' = where{$_.Name -ne 'vm'-and $_.Name -ne 'vCLS'}

Now, Import is working fine as well.

Thank you so much. Your input has been truly beneficial .

Reply
0 Kudos