Create a folder tree from a template

blogCreateFolderFromTemplate

In the past few weeks, many of you asked this question: “how to create a folder in Vault by copying the folder tree from another template folder?”. In this post, I’m showing you how to do this with Vault Data Standard.

There are basically 2 steps to do. The first is to enhance the standard folder dialog by adding a combobox where you can select a template folder. The second is to copy the complete folder tree from the template folder to the new generated target folder.

Let’s start with the dialog. You have to add an additional row to your dialog,  a label and a combobox. This is how it looks on my side

<Label Content="Template" Grid.Column="0" Grid.Row="4" />
<ComboBox ItemsSource="{Binding PsList[GetListOfVaultProjects]}" SelectedValue="{Binding Prop[Template].Value}" Grid.Column="1" Grid.Row="4" />

As you can see, I bind the ItemsSource of the combobox to a PowerShell function called GetListOfVaultProjects, and the SelectedValue to a Vault property called Template. This means that we have to create a Vault property named Template and map such property to the Folder categories. We also have to create the PowerShell function with the name GetListOfVaultProjects. For this purpose, I just created a new PowerShell file and placed it into the addinVault folder of Data Standard. This is how my function looks like

function GetListOfVaultProjects()
{
     $dsDiag.Trace(">> GetListOfVaultProjects")
     $designsFolder = $vault.DocumentService.GetFolderByPath("$/Designs")
     $subFolders = $vault.DocumentService.GetFoldersByParentId($designsFolder.Id,$false)
     $projectFolders = $subFolders | Where-Object { $_.Cat.CatName -eq "Project" }
     $listOfProjects = $projectFolders | ForEach-Object { $_.FullName }
     $dsDiag.Trace("<< GetListOfVaultProjects")
     return @($listOfProjects)
}

As you can see, the function looks to all Folders underneath $/Designs and picks only those that are of category “Folder”. If you like to have your template somewhere else, then just adjust the folder, and in case, also the category. You may wonder why the return value is embedded in a @(…) in the last line. The reason is that in case you only have one template, PowerShell reduces the array (list of values) down to one single value. But we need a list of values, worst case either an empty list or a list with at least one element. As in PowerShell an array is create with @(), by embedding the variable into @(), we ensure that in case there is only one or no values, an array is still returned.

Anyway, the next step is to enhance the PowerShell script that creates the Folder (addinVault/Menus/CreateFolder.ps1). In this script, we will recursively recreate the same folder structure as defined in the selected template folder. As we don’t know how deep or articulated the folder structure might be, we create a little recursive function that goes into the tree and recreates step by step the folder tree for the target folder. This is the function

function recursivelyCreateFolders($targetFolder, $sourceFolder)
{
     $sourceSubFolders = $vault.DocumentService.GetFoldersByParentId($sourceFolder.Id,$false)
     foreach ($folder in $sourceSubFolders) {
          $newTargetSubFolder = $vault.DocumentServiceExtensions.AddFolderWithCategory($folder.Name, $targetFolder.Id, $folder.IsLibrary, $folder.Cat.CatId)
          recursivelyCreateFolders -targetFolder $newTargetSubFolder -sourceFolder $folder
     }
}

We basically pass the source and the target folder and let the function go into the child folder of the source and recreate them at the target. For each folder found in the source, the function calls them with the according child source and target folder. So, the function will go down the tree itself. It’s important that this function is written at the top of the script file, as script files are read from top to bottom. So, when we later call the function, the function must already be known.

Now we can call the function right after the new folder has been created, like this:

if($result)
{
      #new folder can be found in $dialog.CurrentFolder
      $folder = $vault.DocumentService.GetFolderById($folderId)
      $path=$folder.FullName+"/"+$dialog.CurrentFolder.Name

#create template folder tree
      $newFolder = $vault.DocumentService.GetFolderByPath($path)
      $template = $dialog.ViewModel.Prop["Template"].Value
      if($template -ne "")
      {
           $templateFolder = $vault.DocumentService.GetFolderByPath($template)
           recursivelyCreateFolders -sourceFolder $templateFolder -targetFolder $newFolder
      }
...
..
...

And this is how it looks once it’s finished

createFolderFromTemplate

As you can see, when you now create a new folder, you can pick from a list of templates and no matter how the structure in the selected template looks like, the new folder will have the same children.

Of course this sample can be extended, for instance by applying some properties of the new folder to the child folders. Or by copying also some files from the source to the target. Or by renaming the child folder with a prefix from the originator folder. Or… you get the idea. In this sample, the template folders are within Vault, but they can also come from an external source, such as your ERP or similar. So, the possibilities are endless. The logic remains almost the same. Yes, there is a bit of code to write, that is obvious as somewhere we must teach Vault to do what we like, but I’m still delighted by the shortness of the code.

I hope you enjoyed this sample and comments are welcome as always!

This entry was posted in Data Standard, PowerShell, Vault API and tagged , , , . Bookmark the permalink.

19 Responses to Create a folder tree from a template

  1. Andreas says:

    Danke Marco kann man gut gebrauchen !!!

  2. Razvan says:

    What if I already know the subfolder structure, but it is just different by folder category? Let’s say Category1 has 3 subfolders 1,2 & 3 and Category2 has 3 subfolders 4,5 & 6. Can you point me to the right direction? Thank you.

    • Marco Mirandola says:

      We had a similar question on the Autodesk forum (http://forums.autodesk.com/t5/vault-customization/datastandard-folder-structure/m-p/5343867#M2675) and gave a simple answer there. Then we came up with the idea to create this post. However, in order to solve your requirement, you can write the logic directly in the CreateFolder.ps1 as mentioned in the forum post. Now, in order to keep your logic a bit more flexible, it would be possible to save the sub-folder structure in a configuration file such as a XML and just read out the logic dynamically. So you could just enter the different structures for the different categories in the XML and let the few PowerShell script lines do the rest. I may create a small example for demonstrating the possibilities.

      • Razvan says:

        I managed to find the Autodesk forum post and solve it by first comparing the category with $categ=$dialog.CurrentFolder.Cat.CatName. Your solution is more pro and I will try to figure it out. Good application by the way the VAPI TRACE. Thank you

  3. Gerd Assmann says:

    Bei mir kommt leider das Sub 2 Verzeichnis nicht mit :-(

    • Marco Mirandola says:

      Hallo Gerd, konntest du das Problem mittlerweile lösen? Falls nicht, dann melde dich direkt über unserem Support.

  4. Max says:

    I am probably missing something, but a little help would be nice :).
    We are running the Vault 2015 R2 and customizing the CAD data standard is no problem. But i can’t get this to show up in the menu. I use the 08_FolderCustomObject as basis. Is there a setting inside Vault which i need to change?

    • Marco Mirandola says:

      Hi Max, I’m not sure I understand the question. Will you contact me directly or send your request to our support? There are no special settings on the Vault side. If you use the FolderCustomObject sample, then of course you need a Custom Object called Company in order to get this running. But i’m not sure if this is your problem, so probably email works better here?

  5. Marcel.Decressin@mum-os.de says:

    Super Beispiel.
    Ich würde gern eine Excel-liste als Vorlage angeben. In der Liste stehen Ordnernnamen, Eigenschaften, Kategorien usw.
    Sollte doch ohne Probleme möglich sein, oder? Haben Sie dazu ein kurzes Beispiel?
    Danke

    • Marco Mirandola says:

      Yes, PowerShell offers an Import-CSV command-let, which allows to import a CSV file. This way you could fill up the selection list with fixed values and create according subfolders based on the entries of you CSV.
      As an alternative, i would also think about XML. An XML file is more structured then a CSV. So, you could have the list of available template folders and within each template the according subfolders, which could be also a folder tree with several sub-levels.
      I don’t have a running sample to share, however, you may find sample on how to bind a listbox to an XAML file in the training videos that has been created two years ago. I will see if we can make a variation of this post with the XML as a sample.

  6. Marcel.Decressin@mum-os.de says:

    CSV wäre perfekt. Ich habe bereits eine Formatierte .csv Datei ;). Mit dieser möchte ich Ordner mit Unterordnern und entsprechenden Eigenschaften über DataStandard erstellen.

    Danke

  7. Pingback: New folder with subfolders | coolorange

  8. Paul You says:

    Hi, Marco.

    I created templates under Designs folder and they are displayed properly.
    However, when I create folder, title and Description are not saved
    Moreover, I have below problem as well
    $template = $dialog.ViewModel.Prop[“Template”].Value
    is empty all the time

    I’m not sure where I made a mistake. I hope you can support me.

    Kind regards

    Paul

    • Marco Mirandola says:

      Hi Paul, have you created a user defined property called Template and assigned it to the Folder entity and according categories? This samples expects that a UDP called Template exists. In such property, the selected template is saved and later in the menu script the value is used.

  9. So, I have successfully been able to get this to start working, however, it only copies the first folder in the structure. What might I be missing? There are 8 sub-folders that I am trying to copy but it stops after copying the first sub folder.

  10. Simon Bevin says:

    Hi Marco,

    Followed this post to create the folders within vault 2017. I have created the category template but i only seem to receive the source folder none of the Sub folders or the sub-Sub folders.

    have you any ideas how this would differ or if it does differ within 2017?

    Thank you

  11. Jonathan Spies says:

    Hi togehter,
    I just followed this post. Now I started to work with DataStandard and I wanted to integrate this function in my Test Vault.
    But I don´t get it where I have to copy the first part, to edit the “New standard folder” dialog.
    Hope somebody can help me with this…
    Iam working with Vault 2017…

    Thank you

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s