microsoft-365/SharePointSearchHelpers.psm1
|
function Search-DeletedItem { param( [Parameter(Mandatory = $true)] [string]$SiteURL, [Parameter(Mandatory = $false)] [string]$Keyword = "", [Parameter(Mandatory = $false)] [string]$OriginalLocation = "", [Parameter(Mandatory = $false)] [string]$DeletedBy = "", [Parameter(Mandatory = $false)] [int]$DaysBack = 93, [Parameter(Mandatory = $false)] [switch]$ExportToCSV, [Parameter(Mandatory = $false)] [switch]$IncludeSecondStage ) try { # Connect to SharePoint Write-Host "Connecting to $SiteURL..." -ForegroundColor Yellow connect-pnponline -Interactive -ClientId deccb19c-bfba-483c-84aa-ee7076b19053 -Url $SiteURL # Calculate date range $StartDate = (Get-Date).AddDays(-$DaysBack) # Search first stage recycle bin Write-Host "Searching first stage recycle bin..." -ForegroundColor Green $FirstStageItems = Get-PnPRecycleBinItem | Where-Object { # $_.ItemType -eq "Folder" -and $_.DeletedDate -ge $StartDate -and ($Keyword -eq "" -or $_.Title -like "*$Keyword*") -and ($OriginalLocation -eq "" -or $_.DirName -like "*$OriginalLocation*") -and ($DeletedBy -eq "" -or $_.DeletedByName -like "*$DeletedBy*") } $AllResults = @() if ($FirstStageItems) { $FirstStageItems | ForEach-Object { $AllResults += [PSCustomObject]@{ Title = $_.Title DeletedDate = $_.DeletedDate DeletedBy = $_.DeletedByName Location = $_.DirName Stage = "First Stage" Id = $_.Id Size = $_.Size } } } # Search second stage recycle bin if requested if ($IncludeSecondStage) { Write-Host "Searching second stage recycle bin..." -ForegroundColor Green $SecondStageItems = Get-PnPRecycleBinItem -SecondStage | Where-Object { # $_.ItemType -eq "Folder" -and $_.DeletedDate -ge $StartDate -and ($Keyword -eq "" -or $_.Title -like "*$Keyword*") -and ($OriginalLocation -eq "" -or $_.DirName -like "*$OriginalLocation*") -and ($DeletedBy -eq "" -or $_.DeletedByName -like "*$DeletedBy*") } if ($SecondStageItems) { $SecondStageItems | ForEach-Object { $AllResults += [PSCustomObject]@{ Title = $_.Title DeletedDate = $_.DeletedDate DeletedBy = $_.DeletedByName Location = $_.DirName Stage = "Second Stage" Id = $_.Id Size = $_.Size } } } } # Display results if ($AllResults.Count -gt 0) { Write-Host "Found $($AllResults.Count) matching folder(s):" -ForegroundColor Green # $AllResults | Sort-Object DeletedDate -Descending | Format-Table -AutoSize # Export to CSV if requested if ($ExportToCSV) { $FileName = "DeletedFolders_$(Get-Date -Format 'yyyyMMdd_HHmmss').csv" $AllResults | Export-Csv -Path $FileName -NoTypeInformation Write-Host "Results exported to $FileName" -ForegroundColor Green } } else { Write-Host "No matching folders found in the specified time range." -ForegroundColor Red } return $AllResults } catch { Write-Error "Error occurred: $($_.Exception.Message)" } finally { } } # Usage examples: # Search-DeletedFolder -SiteURL "https://yourtenant.sharepoint.com/sites/yoursite" # Search-DeletedFolder -SiteURL "https://yourtenant.sharepoint.com/sites/yoursite" -Keyword "ProjectFiles" # Search-DeletedFolder -SiteURL "https://yourtenant.sharepoint.com/sites/yoursite" -DaysBack 30 -ExportToCSV # Search-DeletedFolder -SiteURL "https://yourtenant.sharepoint.com/sites/yoursite" -IncludeSecondStage -ExportToCSV # Search-DeletedItem "https://jranck-my.sharepoint.com/personal/kzeien_jranck_com" -OriginalLocation "IDrive Migration Logs" | Restore-DeletedItem # Document Library Search Examples: # Search-DocumentLibrary -SiteURL "https://yourtenant.sharepoint.com/sites/yoursite" -LibraryName "Documents" -SearchString "Project" # Search-DocumentLibrary -SiteURL "https://yourtenant.sharepoint.com/sites/yoursite" -LibraryName "Documents" -SearchString "Budget" -ItemType "Files" -ExportToCSV # Quick restore function function Restore-DeletedItem { [CmdletBinding()] param( [Parameter(ValueFromPipelineByPropertyName = $true, Position = 0)] [string]$Id, [Parameter(ValueFromPipeline = $true)] [psobject]$InputObject ) process { try { # If an object was piped, normalize to a collection so we handle arrays or single objects if ($null -ne $InputObject) { $objs = if ($InputObject -is [System.Collections.IEnumerable] -and -not ($InputObject -is [string])) { $InputObject } else { @($InputObject) } foreach ($obj in $objs) { $itemId = $null if ($obj -is [string]) { $itemId = $obj } elseif ($obj.PSObject.Properties.Name -contains 'Id') { $itemId = $obj.Id } elseif ($obj.PSObject.Properties.Name -contains 'ID') { $itemId = $obj.ID } else { Write-Error "Piped object does not contain an 'Id' property: $($obj | Out-String)" continue } if (-not $itemId) { Write-Error "No Id found on piped object." continue } # THIS ASSUMES YOU ARE ALREADY CONNECTED Restore-PnPRecycleBinItem -Identity $itemId -Force Write-Host "Item $itemId restored successfully" -ForegroundColor Green } return } # If Id was bound by property name (or passed directly), handle it here if ($PSBoundParameters.ContainsKey('Id') -and $Id) { Restore-PnPRecycleBinItem -Identity $Id -Force Write-Host "Item $Id restored successfully" -ForegroundColor Green return } Write-Error "No Id provided to Restore-DeletedItem." } catch { Write-Error "Error restoring item: $($_.Exception.Message)" } } } # Advanced search function using SharePoint Search API function Search-DocumentLibrary { param( [Parameter(Mandatory = $true)] [string]$SiteURL, [Parameter(Mandatory = $true)] [string]$LibraryName, [Parameter(Mandatory = $true)] [string]$SearchString, [Parameter(Mandatory = $false)] [ValidateSet("All", "Files", "Folders")] [string]$ItemType = "All", [Parameter(Mandatory = $false)] [switch]$ExportToCSV ) try { Write-Host "Connecting to $SiteURL..." -ForegroundColor Yellow connect-pnponline -Interactive -ClientId deccb19c-bfba-483c-84aa-ee7076b19053 -Url $SiteURL # Build search query $Query = "path:$SiteURL/$LibraryName* AND filename:$SearchString" # Add content type filter if ($ItemType -eq "Files") { $Query += " AND IsDocument:true" } elseif ($ItemType -eq "Folders") { $Query += " AND contentclass:STS_ListItem_DocumentLibrary" } Write-Host "Executing search query: $Query" -ForegroundColor Yellow # Execute search $SearchResults = Submit-PnPSearchQuery -Query $Query -MaxResults 500 -TrimDuplicates:$false $Results = @() foreach ($Result in $SearchResults.ResultRows) { $Results += [PSCustomObject]@{ Title = $Result.Title Filename = $Result.Filename Path = $Result.Path.Replace("$SiteURL/", "") Size = $Result.Size LastModifiedTime = $Result.LastModifiedTime Author = $Result.Author FileType = $Result.FileType IsFolder = $Result.IsFolder ContentClass = $Result.ContentClass } } # Display results if ($Results.Count -gt 0) { Write-Host "Found $($Results.Count) matching item(s) via search:" -ForegroundColor Green # $Results | Sort-Object IsFolder, Title | Format-Table Title, FileType, LastModifiedTime, Author -AutoSize if ($ExportToCSV) { $FileName = "AdvancedLibrarySearch_$($LibraryName)_$($SearchString)_$(Get-Date -Format 'yyyyMMdd_HHmmss').csv" $Results | Export-Csv -Path $FileName -NoTypeInformation Write-Host "Results exported to $FileName" -ForegroundColor Green } } else { Write-Host "No matching items found via search." -ForegroundColor Red } return $Results } catch { Write-Error "Error occurred: $($_.Exception.Message)" } finally { } } |