Solved

Search All Nintex Forms in a Site Collection or Web App

  • 30 May 2023
  • 5 replies
  • 70 views

Badge +3

I am using Nintex Forms 2019 on premises.  I have forms developed on several site collections / sites.  Many of these forms use the SQL Request control.  We recently migrated several databases to a different SQL server with a different server name and we are trying to change the connection strings in all of the SQL Request controls to point to the correct server.  We are getting SQL login failures, but it is difficult to know which forms are being loaded to generate those errors.

I know that a Nintex Form can be exported in XML format, so it is searchable.  Does anyone have a method (Powershell script, etc.) to search all Nintex forms in a site collection or in a web app for an occurrence of a string (like a SQL server name) and list the site name and list name where the form was found?

If I can find the forms that contain the old SQL server name in the connection string by searching the XML, I can fix them easily.

Thanks for any help anyone can provide.

icon

Best answer by Jake 7 June 2023, 14:04

View original

5 replies

Userlevel 5
Badge +13

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([Microsoft.SharePoint.Client.Web]$web, [string]$listTitle, [string]$searchString, [string]$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 += [PSCustomObject]@{
"FileUrl" = $fileUrl
}

# Read the file content as a string
$fileContentString = [System.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 = [System.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

 

Badge +3

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 [Microsoft.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!

Userlevel 5
Badge +13

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([Microsoft.SharePoint.Client.Web]$web, [string]$listTitle, [string]$searchString, [string]$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)/$($item["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 += [PSCustomObject]@{
"FileUrl" = $fileUrl
}

$newContentString = $fileContent -replace $searchString, $newString
$newContentBytes = [System.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

 

Badge +3

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!

Userlevel 5
Badge +13

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. 

Reply