Matt
Matt

Reputation: 379

Recursively creating folder hierarchy with New-RsFolder in PowerShell

I am using the SSRS PowerShell cmdlets to move over all of our SSRS reports to a new server. Right now I'm trying to recreate the file hierarchy that already exists on the reporting server in our new one.

In order to do this, I am recursing through a local copy of the report folders that I created on my PC. Using the New-RsFolder function I am able to create the first level of folders, but the script starts to fail once it gets to any sort of sub directory.

Import-Module ReportingServicesTools
$ReportPath = 'C:\MyFiles\SSRS 2016 Upgrade\Reporting Server\' 
$Folders = Get-ChildItem $ReportPath -Recurse -Directory

foreach($Folder in $Folders){
    $SubFolderPath = ''
    $arrSubFolders = $Folder.FullName.Replace($ReportPath, '').Split('\')
    foreach($SubFolder in $arrSubFolders){
        $SubFolderPath += '/'
        try{
            New-RsFolder -ReportServerUri $ReportServerURI -FolderName $SubFolder -RsFolder $SubFolderPath
            Write-Host "Created folder $($SubFolderPath)/$($SubFolder)"
        }
        catch{
            Write-Host "Folder $($SubFolderPath)/$($SubFolder) exists"
        }
        $SubFolderPath += $SubFolder
    }
}

As soon as I get back around to accounting the script starts to catch that the folder exists already, as indicated here:

Created folder //Accounting
Created folder //Customer Service
Created folder //Dashlets
Created folder //Data Sources
Created folder //DataSets
Created folder //Forms
Created folder //Human Resources
Created folder //Information Technology
Created folder //Integrated
Created folder //Maintenance
Created folder //Management
Created folder //Old Reports
Created folder //Operations
Created folder //Owner Operator Settlements
Created folder //Report Parts
Created folder //Safety and Recruiting
Folder //Accounting exists
Folder /Accounting//PnG Proposal and Payment exists
Folder //Accounting exists
Folder /Accounting//PTI Logistics exists
Folder //Accounting exists
Folder /Accounting//Settlements exists
Folder //Accounting exists
Folder /Accounting//XRS exists
Folder //Accounting exists
Folder /Accounting//PTI Logistics exists
Folder /Accounting/PTI Logistics//PTI Logistics - Settlements exists
Folder //Accounting exists
Folder /Accounting//PTI Logistics exists
Folder /Accounting/PTI Logistics//PTI Logistics - Settlements exists
Folder /Accounting/PTI Logistics/PTI Logistics - Settlements//Drill-Through exists
Folder //Accounting exists
Folder /Accounting//Settlements exists
Folder /Accounting/Settlements//Drill-Through exists
Folder //Accounting exists
Folder /Accounting//Settlements exists
Folder /Accounting/Settlements//TMW Templates exists
Folder //Customer Service exists

Recursion was never my strong suit so if someone could shed some light on this I would appreciate it.

Upvotes: 3

Views: 2942

Answers (1)

mklement0
mklement0

Reputation: 438273

Get-ChildItem -Recurse enumerates the targeted directory tree with parent paths coming before their descendants.

Additionally, you can use the -Name switch in order to output the directories' path strings, relative to the target directory.

That means that you can focus on just creating each folder one by one, relying on its ancestral path to have preexisted (in the case of /) or to have been created in a previous iteration:

Import-Module ReportingServicesTools
$ReportPath = 'C:\MyFiles\SSRS 2016 Upgrade\Reporting Server' 

Get-ChildItem $ReportPath -Recurse -Directory -Name | ForEach-Object {
  # Split the relative input path into leaf (directory name)
  # and parent path, and convert the parent path to the target parent path
  # by prepending "/" and converting path-internal "\" instances to "/".
  $SubFolderParentPath = '/' + ((Split-Path -Parent $_) -replace '\\', '/')                            #'
  $SubFolderName = Split-Path -Leaf $_
  try{
    New-RsFolder -ReportServerUri $ReportServerURI -Path $SubFolderParentPath -FolderName $SubFolderName 
    Write-Host "Created folder ${SubFolderPath}/${SubFolder}"
  }
  catch {
      # Report the specific error that occurred, accessible via $_
      Write-Host "An error occurred for ${SubFolderPath}/${SubFolder}: $_"
  }
}

This approach is not only more efficient than yours, it also avoids the attempts to create ancestral paths multiple times.

Note:

  • -Path rather than -RsFolder is used, because the version of New-RsFolder available in the PowerShell Gallery as part of the ReportingServices module only supports -Path for specifying the target location (folder).

  • The catch block now reports the actual error ($_) that occurred, because the specific problem may something other than a preexisting folder.

  • Be sure to start the target path passed to -Path with /.

Upvotes: 3

Related Questions