Hi @jsupchurch
This code is from a very old store of mine, it searches through sharepoint to find form definitions for a string, it can even store the values or replace them, please keep in mind this code is a few years old and might not work but should be a starting point.
Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.dll"
Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.Runtime.dll"
$siteUrl = "http://your-sharepoint-site-url"
$username = "your-username"
$password = "your-password"
$searchString = "your-search-string"
$newString = "your-new-string"
$outputFile = "C:\Path\to\output.csv" # Replace with the desired output file path
$securePassword = ConvertTo-SecureString -String $password -AsPlainText -Force
$credentials = New-Object -TypeName System.Net.NetworkCredential -ArgumentList $username, $securePassword
# Create an array to store the found file locations
$foundFiles = @()
# Function to search for XML files in a library containing a specific string
function SearchNintexForms(oMicrosoft.SharePoint.Client.Web]$web, wstring]$listTitle, tstring]$searchString, istring]$newString) {
Write-Host "Searching for NintexForms in $($web.Url)/$listTitle"
$context = $web.Context
$web.Lists.EnsureSiteAssetsLibrary()
$list = $web.Lists.GetByTitle($listTitle)
$context.Load($list)
$context.ExecuteQuery()
# Check if the list is the NintexForms library
if ($list.BaseType -eq "DocumentLibrary" -and $list.BaseTemplate -eq 101 -and $list.Title -eq "NintexForms") {
# Retrieve XML files in the NintexForms library
$camlQuery = New-Object Microsoft.SharePoint.Client.CamlQuery
$camlQuery.ViewXml = "<View Scope='RecursiveAll'><Query><Where><Eq><FieldRef Name='File_x0020_Type' /><Value Type='Text'>xml</Value></Eq></Where></Query></View>"
$items = $list.GetItems($camlQuery)
$context.Load($items)
$context.ExecuteQuery()
# Store the file locations
foreach ($item in $items) {
$fileUrl = "$($web.Url)/$($list.Title)/$($item$"FileLeafRef"])"
$fileContent = $item.File.OpenBinary()
$context.ExecuteQuery()
# Check if the file contains the search string
if ($fileContent -match $searchString) {
Write-Host "XML File Location: $fileUrl"
$foundFiles += sPSCustomObject]@{
"FileUrl" = $fileUrl
}
# Read the file content as a string
$fileContentString = nSystem.Text.Encoding]::UTF8.GetString($fileContent)
# Replace the search string with the new string
$newContentString = $fileContentString -replace $searchString, $newString
# Convert the updated string back to byte array
$newContentBytes = eSystem.Text.Encoding]::UTF8.GetBytes($newContentString)
# Upload the updated content to the file
$item.File.SaveBinary($newContentBytes)
$context.ExecuteQuery()
}
}
}
# Recursively search in sub-webs
$subwebs = $web.Webs
$context.Load($subwebs)
$context.ExecuteQuery()
foreach ($subweb in $subwebs) {
SearchNintexForms $subweb $listTitle $searchString $newString
}
}
# Connect to the SharePoint site
$context = New-Object -TypeName Microsoft.SharePoint.Client.ClientContext -ArgumentList $siteUrl
$context.Credentials = $credentials
$web = $context.Web
$context.Load($web)
$context.ExecuteQuery()
# Search for NintexForms library in the root web and replace the search string
SearchNintexForms $web "NintexForms" $searchString $newString
# Disconnect from the SharePoint site
$context.Dispose()
# Export the found files to CSV
$foundFiles | Export-Csv -Path $outputFile -NoTypeInformation
Thanks for the script, Jake. That has gotten me started. It worked fine until it tried to do the $item.File.OpenBinary() to open the file so it could search it for a string. It is telling me that aMicrosoft.SharePoint.Client.File] no longer contains the OpenBinary() method, so I need to figure out how to open the file to search it. Any suggestions you have for an update would be appreciated, but the script is a great start for me! Thanks!
Hi @jsupchurch you are right, I knew something would not work, it’s probably been 5 years since I used this script, looks like it’s called OpenBinaryStream() now, I’ve updated the code but I haven’t tested it because I don’t have a environment to hand, let me know how you get on.
Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.dll"
Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.Runtime.dll"
$siteUrl = "http://your-sharepoint-site-url"
$username = "your-username"
$password = "your-password"
$searchString = "your-search-string"
$newString = "your-new-string"
$outputFile = "C:\Path\to\output.csv"
$securePassword = ConvertTo-SecureString -String $password -AsPlainText -Force
$credentials = New-Object -TypeName System.Net.NetworkCredential -ArgumentList $username, $securePassword
$foundFiles = @()
function SearchNintexForms(NMicrosoft.SharePoint.Client.Web]$web, tstring]$listTitle, $string]$searchString, astring]$newString) {
Write-Host "Searching for NintexForms in $($web.Url)/$listTitle"
$context = $web.Context
$web.Lists.EnsureSiteAssetsLibrary()
$list = $web.Lists.GetByTitle($listTitle)
$context.Load($list)
$context.ExecuteQuery()
if ($list.BaseType -eq "DocumentLibrary" -and $list.BaseTemplate -eq 101 -and $list.Title -eq "NintexForms") {
$camlQuery = New-Object Microsoft.SharePoint.Client.CamlQuery
$camlQuery.ViewXml = "<View Scope='RecursiveAll'><Query><Where><Eq><FieldRef Name='File_x0020_Type' /><Value Type='Text'>xml</Value></Eq></Where></Query></View>"
$items = $list.GetItems($camlQuery)
$context.Load($items)
$context.ExecuteQuery()
foreach ($item in $items) {
$fileUrl = "$($web.Url)/$($list.Title)/$($itemt"FileLeafRef"])"
$fileRef = $item.File
$fileStream = $fileRef.OpenBinaryStream()
$context.Load($fileRef)
$context.ExecuteQuery()
# Use a stream reader to read the content of the file
$sr = New-Object System.IO.StreamReader $fileStream.Value
$fileContent = $sr.ReadToEnd()
$sr.Close()
if ($fileContent -match $searchString) {
Write-Host "XML File Location: $fileUrl"
$foundFiles += uPSCustomObject]@{
"FileUrl" = $fileUrl
}
$newContentString = $fileContent -replace $searchString, $newString
$newContentBytes = tSystem.Text.Encoding]::UTF8.GetBytes($newContentString)
$fileRef.SaveBinary(.Microsoft.SharePoint.Client.ClientContext]::new($fileUrl, $credentials), $newContentBytes)
$context.ExecuteQuery()
}
}
}
$subwebs = $web.Webs
$context.Load($subwebs)
$context.ExecuteQuery()
foreach ($subweb in $subwebs) {
SearchNintexForms $subweb $listTitle $searchString $newString
}
}
$context = New-Object -TypeName Microsoft.SharePoint.Client.ClientContext -ArgumentList $siteUrl
$context.Credentials = $credentials
$web = $context.Web
$context.Load($web)
$context.Execute Query()
SearchNintexForms $web “NintexForms” $searchString $newString
$context.Dispose()
$foundFiles | Export-Csv -Path $outputFile -NoTypeInformation
Thank you for the changes to the script, Jake. I am using the portion of it that identifies the Nintex forms that have the string I am looking for and it is doing that. I am not replacing that string (yet) because of some audit issues, but identifying them is very helpful.
I am seeing several Nintex forms xml files that don’t have an associated SharePoint list. It is as if a list was created, a Nintex form created for that list, and then the list was removed but the Nintex form was not removed and was “orphaned”. Is that possible? If so, do you know of a way to identify only Nintex forms that are associated with active lists. Also, I am only wanting the currently published version of the form and not previous versions. I believe, in it’s current form, the script only gets the current version, which is what I need.
Thanks again!
Hi @jsupchurch
yes that scenario can exist and it is done by design, this allows for lists to be transported, restored or Nintex to be completely uninstalled and forms definitions not lost. It causes far more disruption to attempt to link forms to list status.
there is version history on the forms list but I don’t know if it is available on all versions, any file you see in those lists will be the latest version.
as for finding active forms is possible but again for on-prem sadly not straight forward but there are powershell scripts that exist, you essentially need to store a sites list GUIDs, those GUIDs are used in the file name of the form definition, if a form definition exists with a GUID that doesn’t match a list GUID it is an orphan.
I am glad the script is assisting you.
Let me know if I can assist you further.