CSOM – PowerShell Script – Export and Import Nintex Forms in SharePoint

Sathish Nadarajan
 
Solution Architect
February 8, 2021
 
Rate this article
 
Views
1907

In this article, let us see how to Export and Import Nintex Forms in SharePoint using CSOM PowerShell Script.
The code is self-explanatory.

01.ExportNintexForms.ps1

function Export-NintexForm {
<# .SYNOPSIS Exports a Nintex form XML to a local directory. .DESCRIPTION Exports a Nintex form XML to a local directory. #>
[CmdletBinding()]
[OutputType([string])]
param(
[string]$WebUrl = $(throw "Required parameter -WebUrl missing"),
[string]$ListName = $(throw "Required parameter -ListName missing"),
[string]$FilePath = $(throw "Required parameter -FilePath missing")
)
begin {
if(!(Get-PnPConnection)) {
throw "There is no PnPConnection"
}
Write-Host "---- Exporting Nintex form for '$ListName' ----" -ForegroundColor Yellow
}
process {
$xmlFilePath ="";
$list = Get-PnPList -Identity $ListName

$addressUrl = "$WebUrl/_vti_bin/NintexFormsServices/NfRestService.svc/GetFormXml"
$addressUri = New-Object System.Uri($addressUrl)

# Create the web request
[System.Net.HttpWebRequest] $request = [System.Net.WebRequest]::Create($addressUri)

# Add authentication to request
$request.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials

# Set type to POST
$request.Method = "POST";
$request.ContentType = "application/json; charset=utf-8";
$request.Accept = "application/json, text/javascript, */*; q=0.01"
$request.Headers.Add("X-Requested-With", "XMLHttpRequest")

# Create the data we want to send
$id = "{$($list.ID)}"
$contentTypeID = "{0x01000***********}" #Give the content Type ID
$data = "{`"contentTypeId`": `"$contentTypeID`", `"listId`": `"$id`" }"

# Create a byte array of the data we want to send
$utf8 = New-Object System.Text.UTF8Encoding
[byte[]] $byteData = $utf8.GetBytes($data.ToString())

# Set the content length in the request headers
$request.ContentLength = $byteData.Length;

# Write data
try {
$postStream = $request.GetRequestStream()
$postStream.Write($byteData, 0, $byteData.Length);
}
catch [Exception]{
Write-Host -f red $_.Exception.ToString()
}
finally {
if($postStream) { $postStream.Dispose() }
}

# Get response
try {
[System.Net.HttpWebResponse] $response = [System.Net.HttpWebResponse] $request.GetResponse()
# Get the response stream
[System.IO.StreamReader] $reader = New-Object System.IO.StreamReader($response.GetResponseStream())

try {
$strResult = $reader.ReadToEnd()
$xml = [System.Web.HttpUtility]:: HtmlDecode($strResult)

#Once Deserialized XML will get generated with below string tag, insted of going for XML manupulation I have removed the string tag from the xml
$xmlExcludedStringTag = $xml -replace "" , "";
$xmlExcludedStringTag = $xmlExcludedStringTag -replace "" , "";

$timeStampString = [DateTime]::Now.ToString("yyyyMMdd-HHmmss")
# Get XML New File path
$xmlFilePath = "$FilePath$($ListName)Form-$timeStampString.xml";

#Save XML File to Disk
#$xmlExcludedStringTag | Out-File $xmlFilePath
$enc = [system.Text.Encoding]::Unicode
$encodedData = $enc.GetBytes($xmlExcludedStringTag)
$encodedData | Set-Content $xmlFilePath -Encoding Byte
Write-Host "Nintex form exported successfully to '$xmlFilePath'" -ForegroundColor Green
return $xmlFilePath
}
catch [Exception] {
Write-Host -f red $_.Exception.ToString()
}
}
catch [Exception] {
Write-Host -f red $_.Exception.ToString()
}
finally {
if($response) { $response.Dispose() }
}
$xmlFilePath
}
end { }
}

02.ImportNintexForms.ps1

function Read-FileBytes($Filename)
{
try {
[system.io.stream] $stream = [system.io.File]::OpenRead($Filename)
try {
[byte[]] $filebytes = New-Object byte[] $stream.length
[void] $stream.Read($filebytes, 0, $stream.Length)

return $filebytes
}
finally {
$stream.Close()
}
}
catch {

return
}
return $true;
}

function Get-FormDigest($webUrl )
{
[System.Reflection.Assembly]::LoadWithPartialName("System.IO") >> $null

#$formDigestRequest = [Microsoft.SharePoint.Utilities.SPUtility]::ConcatUrls($webUrl, "_api/contextinfo")
$formDigestRequest = $webUrl + "/_api/contextinfo"
$formDigestUri = New-Object System.Uri($formDigestRequest)
$credCache = New-Object System.Net.CredentialCache
$credCache.Add($formDigestUri, "NTLM", [System.Net.CredentialCache]::DefaultNetworkCredentials)
$spRequest = [System.Net.HttpWebRequest] [System.Net.HttpWebRequest]::Create($formDigestRequest)
$spRequest.Credentials = $credCache
$spRequest.Method = "POST"
$spRequest.Accept = "application/json;odata=verbose"
$spRequest.ContentLength = 0

[System.Net.HttpWebResponse] $endpointResponse = [System.Net.HttpWebResponse] $spRequest.GetResponse()
[System.IO.Stream]$postStream = $endpointResponse.GetResponseStream()
[System.IO.StreamReader] $postReader = New-Object System.IO.StreamReader($postStream)
$results = $postReader.ReadToEnd()

$postReader.Close()
$postStream.Close()

#Get the FormDigest Value
$startTag = "FormDigestValue"
$endTag = "LibraryVersion"
$startTagIndex = $results.IndexOf($startTag) + 1
$endTagIndex = $results.IndexOf($endTag, $startTagIndex)
[string] $newFormDigest = $null
if (($startTagIndex -ge 0) -and ($endTagIndex -gt $startTagIndex))
{
$newFormDigest = $results.Substring($startTagIndex + $startTag.Length + 2, $endTagIndex - $startTagIndex - $startTag.Length - 5)
}

return $newFormDigest
}

function Nintex-GetJsonFormFromXml($FileName)
{

[System.Reflection.Assembly]::LoadWithPartialName("Nintex.Forms.SharePoint") >> $null
[System.Reflection.Assembly]::LoadWithPartialName("Nintex.Forms") >> $null

[byte[]] $fileBytes = Read-FileBytes -FileName $FileName
try
{
$form = [Nintex.Forms.FormsHelper]::XmlToObject([Nintex.Forms.NFUtilities]::ConvertByteArrayToString($fileBytes))
}
catch [Exception]
{
$form = [Nintex.Forms.FormsHelper]::XmlToObject([Nintex.Forms.NFUtilities]::ConvertByteArrayToString($fileBytes, [System.Text.Encoding]::UTF8))
}

$form.LiveSettings.Url = ""
$form.LiveSettings.ShortUrl = ""
$form.RefreshLayoutDisplayNames()
$form.Id = [guid]::NewGuid()

$json = [Nintex.Forms.FormsHelper]::ObjectToJson($form);
return $json;
}

function Import-NintexForm {
<# .SYNOPSIS Imports a Nintex form XML to a local directory. .DESCRIPTION Imports a Nintex form XML to a local directory. #>
[CmdletBinding()]
[OutputType([string])]
param(
[string]$webUrl = $(throw "Required parameter -WebUrl missing"),
[string]$listName = $(throw "Required parameter -ListName missing"),
[string]$filePath = $(throw "Required parameter -FilePath missing")
)
begin {
if(!(Get-PnPConnection)) {
throw "There is no PnPConnection"
}
Write-Host "---- Importing Nintex form for '$listName' ----" -ForegroundColor Yellow
}
process {
$list = Get-PnPList -Identity $listName

$formDigest = Get-FormDigest $webUrl
$addressUrl = $webUrl + "/_vti_bin/NintexFormsServices/NfRestService.svc/PublishForm"
$addressUri = New-Object System.Uri($addressUrl)

# Create the web request
[System.Net.HttpWebRequest] $request = [System.Net.WebRequest]::Create($addressUri)

# Add authentication to request
$request.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials

# Set type to POST
$request.Method = "POST";
$request.ContentType = "application/json; charset=utf-8";
$request.Accept = "application/json, text/javascript, */*; q=0.01"
$request.Headers.Add("X-RequestDigest", $formDigest);
$request.Headers.Add("X-Requested-With", "XMLHttpRequest")

$form = Nintex-GetJsonFormFromXml -FileName $filePath

# Create the data we want to send
$id = "{$($list.ID)}"
$data = "{`"contentTypeId`": `"`", `"listId`": `"$id`", `"form`": $form }"

# Create a byte array of the data we want to send
$utf8 = New-Object System.Text.UTF8Encoding
[byte[]] $byteData = $utf8.GetBytes($data.ToString())

# Set the content length in the request headers
$request.ContentLength = $byteData.Length;

# Write data
try {
$postStream = $request.GetRequestStream()
$postStream.Write($byteData, 0, $byteData.Length);
}
catch [Exception]{
write-host -f red $_.Exception.ToString()
}
finally {
if($postStream) { $postStream.Dispose() }
}

# Get response
try {
[System.Net.HttpWebResponse] $response = [System.Net.HttpWebResponse] $request.GetResponse()

# Get the response stream
[System.IO.StreamReader] $reader = New-Object System.IO.StreamReader($response.GetResponseStream())

try {
$strResult = $reader.ReadToEnd()
$jsonResult = ConvertFrom-Json $strResult
$jsonResult

$jsonResult.PublishFormResult.Url
$jsonResult.PublishFormResult.Version

}
catch [Exception] {
write-host -f red $_.Exception.ToString()
}
}
catch [Exception] {
write-host -f red $_.Exception.ToString()
}
finally {
if($response) { $response.Dispose() }
}
}
end{}
}

 

Run.ps1

#=========================================== Description Start ========================================= #
# Deploy from a List

# Author : Sathish Nadarajan
# Date : 03-Feb-2021
#=========================================== Description End====================================== #

# ============================================ PreRequisites Start ================================= #

#Get-Module -Name *pnp*
#Pre Req - SharePoint PnP PowerShell Version 2.25.1804.1

#=============================================PreRequisites End =============================== #

#============================================= Initial Setup Start =============================== #

cls

$Host.UI.RawUI.WindowTitle = "-- Deploy Assets --"

$StartDate = Get-Date
Write-Host -ForegroundColor White "------------------------------------"
Write-Host -ForegroundColor White "| Deploy Assets |"
Write-Host -ForegroundColor White "| Started on: $StartDate |"
Write-Host -ForegroundColor White "------------------------------------"

#Add-PSSnapin Microsoft.SharePoint.PowerShell

$LogTime = Get-Date -Format yyyy-MM-dd_hh-mm-ss

$scriptBase = split-path $SCRIPT:MyInvocation.MyCommand.Path -parent
Set-Location $scriptBase

# Create Log File Folder3
if(!(TEST-PATH ".Logs-$LogTime")){
NEW-ITEM ".Logs-$LogTime" -type Directory
}

# Assign the Log and Progress Files
$TranscriptFile = ".Logs-$LogTimeDeploy.Transcript.rtf"
try{
stop-transcript|out-null
}
catch [System.InvalidOperationException]{}
start-transcript $TranscriptFile

#============================================= Initial Setup End =============================== #

# ============================================ Setup Input Paths Start ================================= #

#connect to the SharePoint list
$sourceWebUrl = 'http://SiteCollectionURL/sites/newsite/'
$sourceListname = "MyList"

$outputFolderPath = ".Logs-$LogTime"

$targetWebUrl = 'http://TargetSiteCollectionURL/sites/newsite/'
$targetListname = "TargetMyList"

# ============================================ Setup Input Paths End ================================= #

Import-Module ".1.ExportNintexForms.ps1"
Import-Module ".2.ImportNintexForms.ps1"

Write-Host "Begin to Execute.." -ForeGroundColor Yellow
"Begin to Execute..." | Out-File -FilePath $TranscriptFile -Append

Connect-PnPOnline -Url $sourceWebUrl -CurrentCredentials -ErrorAction Inquire

$nintexFormXMLPath = Export-NintexForm $sourceWebUrl $sourceListname $outputFolderPath

Import-NintexForm $targetWebUrl $targetListname $nintexFormXMLPath

Disconnect-PnPOnline

Write-Host "Update Completed.. Press Enter to Exit" -ForeGroundColor Green

try{
stop-transcript|out-null
}
catch [System.InvalidOperationException]{}

Happy Coding
Sathish Nadarajan

Author Info

Sathish Nadarajan
 
Solution Architect
 
Rate this article
 
Sathish is a Microsoft MVP for SharePoint (Office Servers and Services) having 15+ years of experience in Microsoft Technologies. He holds a Masters Degree in Computer Aided Design and Business ...read more
 

Leave a comment