Public/Item/Resolve-GDriveFolderIdByPath.ps1
|
<# .SYNOPSIS Resolves a hierarchical folder path into a Google Drive folder ID .DESCRIPTION Traverses a folder path element-by-element by querying the Google Drive API recursively. The function can either fail when a subfolder is missing or dynamically build out the directory structure on the fly. .PARAMETER Path The structural string path of the target folder (e.g., "Test/ABC/123" or "Test\ABC\123"). .PARAMETER AccessToken Access Token for request .PARAMETER ParentId An optional Google Drive Folder ID or Shared Drive ID to start the search from. Providing this optimizes performance by bypassing the global root-level search. .PARAMETER CreateIfNotExisting If specified, the function will dynamically create any missing folders along the path rather than throwing an error. .EXAMPLE $FolderId = Resolve-GDriveFolderIdByPath -Path "SharedDrive/Test/ABC" -AccessToken $MyToken Resolves the ID for the folder "ABC" starting from the global root. .EXAMPLE $FolderId = Resolve-GDriveFolderIdByPath -Path "Test\ABC\123" -AccessToken $MyToken -ParentId "0B-zZ...xyz" -CreateIfNotExisting Starts searching inside the folder defined by ParentId. If "ABC" or "123" do not exist, they are created automatically. .OUTPUTS System.String. Returns the alpha-numeric Google Drive ID of the target folder, or $null if the operation fails. .NOTES - This function issues one API call per path depth level. #> function Resolve-GDriveFolderIdByPath { [CmdletBinding(SupportsShouldProcess=$true)] param ( [Parameter(Mandatory = $true)] [string]$Path, [Parameter(Mandatory = $true)] [string]$AccessToken, [string]$ParentId, [switch]$CreateIfNotExisting ) # Split the path across both / and \ and strip empty elements via the .Where() method $Elements = ($Path -split '[/\\]').Where({ $_ }) if ($Elements.Count -eq 0) { Write-Error "The provided path is empty or invalid." return $null } $CurrentId = $ParentId # Variable for recursive should process $IsSimulatedPath = $false foreach ($Element in $Elements) { if (-not $isSimulatedPath) { # Escape single quotes in folder names to prevent Google Drive API query syntax errors $EscapedName = $Element.Replace("'", "\'") if ([string]::IsNullOrWhiteSpace($CurrentId)) { # Step 1: Search globally for the root folder or Shared Drive top-level directory $Query = "name = '{0}' and mimeType = 'application/vnd.google-apps.folder' and trashed = false" -f $EscapedName } else { # Step 2: Target sub-folders strictly within the verified parent ID $Query = "name = '{0}' and '{1}' in parents and mimeType = 'application/vnd.google-apps.folder' and trashed = false" -f $EscapedName, $CurrentId } Write-Verbose "Querying for '$Element' using: $Query" # -AllDriveItems forces the API to look inside Shared Drives $SearchResult = Find-GDriveItem -AccessToken $AccessToken -Query $Query -AllDriveItems } # Validate if the API returned a valid file list object containing files if ($isSimulatedPath -or $null -eq $SearchResult -or $null -eq $SearchResult.files -or $SearchResult.files.Count -eq 0) { if ($CreateIfNotExisting) { Write-Verbose "Creating folder for '$Element' (Parent: '$CurrentId')" # Build parameter splatting table dynamically $FolderParams = @{ Name = $Element AccessToken = $AccessToken } # Only append ParentID parameter if it actually exists if (-not [string]::IsNullOrWhiteSpace($CurrentId)) { $FolderParams['ParentID'] = $CurrentId } if($PSCmdlet.ShouldProcess("Create new folder '$Element' under '$CurrentId'", $Element, "New-GDriveFolder")) { # Create the folder $NewFolder = New-GDriveFolder @FolderParams # Verify the folder was actually created successfully if ($null -eq $NewFolder -or [string]::IsNullOrWhiteSpace($NewFolder.id)) { Write-Error "Failed to create folder '$Element' under parent '$CurrentId'." return $null } $CurrentId = $NewFolder.id } else { $CurrentId = "DummyIdForElement-" + $Element $IsSimulatedPath = $true } } else { Write-Error "Failed to resolve path: Folder '$Element' was not found." return $null } } else { # If duplicate folder names exist at the same level, default to the first one returned if ($SearchResult.files.Count -gt 1) { Write-Warning "Multiple folders named '$Element' were found at this level. Proceeding with the first match." } # Update parent context to the current folder's ID for the next iteration $CurrentId = $SearchResult.files[0].id } } # Return the final destination ID return $CurrentId } |