1

This is the first PowerShell-script I ever wrote.

I want to keep digging into the folder 10 times. Is there a better way to do this than my way to keep repeating?

Here is the script:

# Connect
Connect-PnPOnline -Url https://site.sharepoint.com/sites/atp/tt -Interactive

# Get parentSource folder
$parentSource="SourceLibrary/SourceFolder"
# Get parentTarget folder
$parentTarget="TargetLibrary3/TargetFolder"


$parentSourceFolders = Get-PnPFolderItem $parentSource

# start loop to folders/files in the parentSource folder
# if childFolder already in parentTarget folder

Foreach ($folder in $parentSourceFolders) {
    $TargetFolder = $parentTarget + "/" + $folder.Name
    Copy-PnPFile -SourceUrl $parentSource/$($folder.Name) -TargetUrl $TargetFolder -Force -OverwriteIfAlreadyExists
    Write-Host "COPY:" $parentSource/$($folder.Name)
    Write-Host "PASTE:" $TargetFolder
    
    if(Get-PnPFolderInFolder -FolderSiteRelativeUrl $parentSource/$($folder.Name)){
    # start another loop to folders/files in the childFolder
    $childFolder1stSubfolders = Get-PnPFolderInFolder -FolderSiteRelativeUrl $parentSource/$($folder.Name)
        Foreach ($sub1folder in $childFolder1stSubfolders) {
        Copy-PnPFile -SourceUrl $parentSource/$($folder.Name)/$($sub1folder.Name) -TargetUrl $TargetFolder/$($sub1folder.Name) -Force -OverwriteIfAlreadyExists
        Write-Host "COPY:" $parentSource/$($folder.Name)/$($sub1folder.Name)
        Write-Host "PASTE:" $TargetFolder/$($sub1folder.Name)

            if(Get-PnPFolderInFolder -FolderSiteRelativeUrl $parentSource/$($folder.Name)/$($sub1folder.Name)){
            $childFolder2ndSubfolders = Get-PnPFolderInFolder -FolderSiteRelativeUrl $parentSource/$($folder.Name)/$($sub1folder.Name)
                Foreach ($sub2folder in $childFolder2ndSubfolders) {
                Copy-PnPFile -SourceUrl $parentSource/$($folder.Name)/$($sub1folder.Name)/$($sub2folder.Name) -TargetUrl $TargetFolder/$($sub1folder.Name)/$($sub2folder.Name) -Force -OverwriteIfAlreadyExists
                Write-Host "COPY:" $parentSource/$($folder.Name)/$($sub1folder.Name)/$($sub2folder.Name)
                Write-Host "PASTE:" $TargetFolder/$($sub1folder.Name)/$($sub2folder.Name)
                }
            }
        }
    }
}
2
  • What's the main goal here? Copy all the contents from on library folder to another library but only ten levels deep in the source library? Commented May 27, 2024 at 7:26
  • Yes, as well as overwrite the existing folders because manual 'copy to' does not accept replacing folders if they exist. Thanks! Commented May 28, 2024 at 5:52

2 Answers 2

0

Got caught up with some other things. This script should do what you want.

Please note that if you set the path at $SouceLibrary to an existing nested folder, the depth will then be included in the $maxLevel total as I count slashes (/) for each folders path.

I'm sure that there's plenty of stuff that could be improved but I can't put any more time into it. :)

# Connect to SPO
Connect-PnPOnline -Url "https://site.sharepoint.com/sites/atp/tt" -Interactive

# Source library/folder
$sourceFolder = "SourceLibrary/One Folder"
# Destination library/folder
$destinationFolder = "DestinationLibrary/My existing folder"

# Count the current depth in the source folder path (-1 to exclude the library/rootfolder)
$sourceFolderDepth = ($sourceFolder -split "/").Count -1

# Limit how deep to traverse in the source library folder structure
$maxLevel = 5

# If $sourceFolder is the rootfolder (the actual library), filter out the default folder
$filteredItems = @("Forms", "Document", "AllItems.aspx", "Combine.aspx", "DispForm.aspx", "EditForm.aspx", "repair.aspx", "template.dotx", "Thumbnails.aspx", "Upload.aspx")

# Get all folders recursively 
$folders = Get-PnPFolderItem -FolderSiteRelativeUrl $sourceFolder -ItemType Folder -Recursive | Where-Object { $_.Name -notin $filteredItems}

# Loop through all the folders
foreach($folder in $folders) {

    # Count the number of folders in the current item path to determine how deep down in the folder hierarchy we are
    $folderPathCount = $(($folder.ServerRelativeUrl -split "$sourceFolder")[1] -replace "/$($folder.Name)", '').Split("/").Count + $sourceFolderDepth

    # Check if the current folder path is less than or equal to the maxlevel set
    if($folderPathCount -le $maxLevel) {

        # Build the source path
        $sourcePath = $($folder.ServerRelativeUrl -split $sourceFolder)[1]

        # Build the destination path
        $destinationPath = $destinationFolder + $($sourcePath.Substring(0, $sourcePath.LastIndexOf('/')))

        # Check if the current folder already exist before trying to create it
        $currentFolder = Get-PnPFolder -Url $($destinationPath + "/" + $folder.Name) -ErrorAction SilentlyContinue

        if($null -eq $currentFolder) {     
            # Create the folder as it does not exist
            Add-PnPFolder -Folder $destinationPath -Name $folder.Name | Out-Null
        }

        # Get all files in the current folder
        $files = Get-PnPFolderItem -FolderSiteRelativeUrl $($sourceFolder + $sourcePath) -ItemType File | Where-Object { $_.Name -notin $filteredItems}

        # Loop through all the files in the current folder
        foreach($file in $files) {

            # Check if the file already exist before trying to copy it
            if(-not(Get-PnPFolderItem -FolderSiteRelativeUrl $($destinationPath + "/" + $folder.Name) -ItemName $file.Name)) {

                # Copy the file if it does not already exist - use force to skip confirmation
                Copy-PnPFile -SourceUrl $file.ServerRelativeUrl -TargetUrl $($destinationFolder + $sourcePath) -Force
            }
        }
    }
     # We've reached the maxlevel, stop the loop
    else {
        break;
    }
}
0

You should make it as a function and use recursion. It would seem cleaner.

function Overwrite-MyFolders {
    yourcode

   Overwrite-MyFolders -ParentSourceFolders $parentSourceFolders
}

A nice simple example + explanation can be found here

Function Get-Ps1File {
    Param ($Path= '.\')
 
    Get-ChildItem -Path $Path | ForEach-Object {
        If ($_.Name -like "*.ps1") {
            $_.Name
        } ElseIf ($_.PSIsContainer) {
            Get-Ps1File -Path $_.FullName
        } # End If-ElseIf.
    } # End ForEach-Object.
} # End Function: Get-Ps1File.

If you want the function to roll EXACTLY 10 times you can put a condition checking, e.g. for the path length or the number of "/".

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.