Hi... that is a great point. When I get back to doing regular updates, I'll be sure to add in the title the topic of each of the regular updates. Hope to be back in the next month or so! I've been working on another project in the meantime. Cheers! Matt
One step closer to automation. I loaded the API Example and Save a Form to the filesystem and also published a form to a list on another site collection. Worked as expected.
I'm still trying to think of a way to do this in PowerShell. One thing I didn't like was having to set manual credentials--should be some way to let an Admin User just perform the action.
Also in the companion project to the Console App are all of the Rest Calls and Nintex Form WorkArea--this should be helpful to try from Powershell.
One difference I noticed between the Workflows and Forms is that there is NO asmx file for the forms. With the workflows we could access /_vti_bin/NintexWorkflows/Workflow.asmx--may this architecture is geared more to the Rest Client.
Stephan, thanks for your feedback and insight. I can imagine that you can re-purpose the sample to create either a console app that takes credential parameters, or a windows form that provides a small GUI to take those values. I hope to get a chance to research how to implement the same task in PowerShell. A lot of users are using PowerShell for their admin tasks... Cheers! Matt
Thanks for the great article. I have repurposed the example. I created a Global Feature by creating an empty SharePoint Project.Then I added the classes from your library. Then created a Farm Feature with auto-activate and deployed.
Then I started playing with PowerShell to reproduce what was in the console app.
This is one of the PowerShell published the form to a new site collection:
<#
.Synopsis
Gets the NintexForm from a List and copies to a File for a given Web
.EXAMPLE
Copy-NintexFormXMLtoDestionList "http://hcmsspd08/sites/Testocrs" OCRs OCRsForm.xml
#>
function Copy-NintexFormXMLtoDestionList
{
]OutputType(Oint])]
Param
(
Parameter(Mandatory=$true,
ValueFromPipelineByPropertyName=$true,
Position=0)]
ostring] $WebURL ,
,Parameter(Mandatory=$true,
ValueFromPipelineByPropertyName=$true,
Position=1)]
pstring] $DestinationListName,
iParameter(Mandatory=$true,
ValueFromPipelineByPropertyName=$true,
Position=2)]
ustring] $XMLName,
tParameter(
ValueFromPipelineByPropertyName=$true,
Position=3)]
lSystem.Management.Automation.CredentialAttribute()] $Credentials
)
Begin
{
if (-not (Get-PSSnapin Microsoft.SharePoint.Powershell -ErrorAction SilentlyContinue))
{
Add-PSSnapin Microsoft.SharePoint.Powershell
}
Add-Type -AssemblyName "NintexFormClient, Version=1.0.0.0, Culture=neutral, PublicKeyToken=acf93b5929daca89"
Set-Location $PSScriptRoot
.GetListGuidfromListName.ps1
$FileRootPath=".Forms$XMLName"
$FullFileName=Resolve-Path $FileRootPath
$destinationListGuid=Get-ListGuidfromListName $WebUrl $DestinationListName
if ($Credentials -ne $null)
{
$ClientCredentials=$Credentials
}
else
{
$ClientCredentials=Get-Credential
}
$NintexFormsClientVersion=eNintexFormsClient.Version]::SharePoint2013
$destinationContentTypeId=""
}
Process
{
$destinationCtx = new-object NintexFormsClient.NfClientContext($WebURL, $ClientCredentials, $NintexFormsClientVersion);
$formXML= >system.io.file]::ReadAllText($FullFileName, pSystem.Text.Encoding]::Unicode)
$result=$destinationCtx.PublishForm($destinationListGuid,$destinationContentTypeId,$formXML)
write-host -f green ("Successfully Published version: {0}" -f $result.Version)
}
End
{
}
}
#Runs the script
cls
$Credentials=Get-Credential
Copy-NintexFormXMLtoDestionList "http://hcmsspd08/sites/Testocrs" OCRs OCRsForm.xml $Credentials
My project was named "NintexFormClient"
Cheers--thanks for great examples!
Sorry can't help the machine I'm using it one is over http. I would make sure you can get to the web using your https address.
It may be your credentials (you should have a user account in the domain with admin rights for the site). However this sounds like it may actually be an issue with the REST client configuration interacting with your environment, or conversely the web.config for the service. I was able to use it over HTTPS with a user account with admin rights on the target site and belonging to the domain, however about two weeks ago I ran into an issue trying to hit the publish endpoint. The other ones work for me still. I have a question out to an internal team on the publish endpoint already and when I talk to them will mention this as well. It may be a little while before I get the info I need.
Alas no. My environment is HTTP, and yeah the HTTP is likely the issue over the client binding. I am curious myself how to get it to work with HTTPS, but will need to do some research (and ask people who know a lot more than I do...) to find out. The fix would likely be in the NintexFormsClient (NFClientContext.cs) where the transport bindings are established.
The https binding may be a problem I encountered when I tried to publish a form on our production machines. The credentials would never work.
function Nintex-PublishForm(
[Microsoft.SharePoint.SPWeb] $Web,
[string] $DestinationListName,
[string] $FileName
[System.Management.Automation.CredentialAttribute()] $Credentials
)
{
$formDigest = Get-FormDigest -Web $Web
$addressUrl = [Microsoft.SharePoint.Utilities.SPUtility]::ConcatUrls($Web.Url, "_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 $FileName
# Create the data we want to send
$list = Get-SPListByInternalName -Web $Web -InternalName $DestinationListName
$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);
}
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
}
catch [Exception] {
}
}
finally {
if($response) { $response.Dispose() }
}
return $true
}
function Get-FormDigest(
[Microsoft.SharePoint.SPWeb] $Web
)
{
[System.Reflection.Assembly]::LoadWithPartialName("System.IO") >> $null
$formDigestRequest = [Microsoft.SharePoint.Utilities.SPUtility]::ConcatUrls($Web.Site.RootWeb.Url, "_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 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-SPListByInternalName($Web, $InternalName)
{
$list = $Web.Lists | Where { $_.RootFolder.Name.ToLowerInvariant() -eq $InternalName.ToLowerInvariant()}
return $list
}
function checkFileExists([string]$path)
{
$found = $false
if (($path -ne $null) -and ($path.Length -gt 0))
{
if (Test-Path -LiteralPath $path)
{
$found = $true
}
}
return $found
}
<#
.Synopsis
Copies a NintexForm and Publishes it to a new List based on the $SiteUrl and TargetListName
.EXAMPLE
$gSiteUrl="http://hcmssp08/sites/Testocrs"
Publish-NintexFormtoNewList $gSiteUrl ".OCRsExportsFormsOCRsForm.xml" "OCRs"
#>
function Publish-NintexFormtoNewList
{
[CmdletBinding()]
[OutputType([int])]
Param
(
[Parameter(Mandatory=$true,
ValueFromPipelineByPropertyName=$true,
Position=0)]
[string] $WebUrl,
[Parameter(Mandatory=$true,
ValueFromPipelineByPropertyName=$true,
Position=1)]
[string] $FormFileName,
[Parameter(Mandatory=$true,
ValueFromPipelineByPropertyName=$true,
Position=2)]
[string] $TargetListName
)
Begin
{
Set-Location $PSScriptRoot
}
Process
{
try
{
$FullFormFileNamewithPath=Resolve-Path $FormFileName
$Credentials=Get-Credential
$web=Get-SPWeb $WebUrl
Nintex-PublishForm $web OCRs $FullFormFileNamewithPath $Credentials
LogInfo("Loaded Lastest Form: {0}" -f $FormFileName)
}
catch
{
LogError("Publish of OCR Form Failed--Please Import and Publish the OCR Form Manually after the script completes")
Write-Error -f yellow ("Publish of OCR Form Failed--Please Import and Publish the OCR Form Manually after the script completes")
}
finally
{
if ($web){
$web.Dispose()
}
}
}
End
{
}
}
It worked fine on my dev machine that uses http. Failed on production machines that use https
Hi Biju, I understand that you need to get this to work. I developed the sample to show how to interact with the end point, but my environment is just HTTP. Having the sample work with HTTPs would make it a lot more useful, and so thanks for pointing out this issue. I don't know off the top of my head how to resolve this -- it may be something relativity simple in terms of setting the transport bindings, or it could be kind of tricky. I'm going to have to get access to a HTTPS environment, do some research. and double-check possible solutions. I have some questions out to experienced devs in house, but haven't heard back. I wish I could provide you an answer right away, but realistically it is going to take me some to get an answer. In the meantime someone in the community may have resolved this issue, and if not, I'll get back to you. It may take me a week or more, however, given what I have on my plate.
Stephan, thanks again for your contribution to the thread! I was creating the sample to interact with the end point using HTTP, and I didn't consider other use cases, even obvious ones like using HTTPS. I think getting the sample to work with HTTPS would be good, but I'll have to figure out the whats what of making that work...
Matt,
I found this code--How do I make it https?
public static Binding GetDefaultBinding()
{
// Create and configure a new WebMessageEncodingBindingElement binding element.
var webMessageEncodingBindingElement = new WebMessageEncodingBindingElement { MessageVersion = MessageVersion.None };
webMessageEncodingBindingElement.ReaderQuotas.MaxStringContentLength = 2147483647;
// Create and configure a new HttpTransportBindingElement binding element.
var transport = new HttpTransportBindingElement
{
MaxBufferPoolSize = 524288,
MaxBufferSize = 65536000,
MaxReceivedMessageSize = 65536000,
ManualAddressing = true,
AuthenticationScheme = AuthenticationSchemes.Ntlm
};
// Create a new custom binding based on the new binding elements.
var binding = new CustomBinding(webMessageEncodingBindingElement, transport)
{
CloseTimeout = new TimeSpan(2, 0, 0),
OpenTimeout = new TimeSpan(2, 0, 0),
SendTimeout = new TimeSpan(2, 0, 0)
};
return binding;
}
Sorry, I just realized that you have some work to do. Ignore my question further down the thread.
Thanks for your development. It was a start.
Ganesh, This is great! Thanks for your note.
Thanks Matt, that is a really useful example. We would have had a real problem if we hadn't found a way to automate this.
But now our client wants to move the entire application in the cloud, so I my new task is to find a way to deploy forms into multiple lists in SharePoint Online.
I am assuming your rest-based service can't be deployed to SP Online. Are there any options for automating deployments in the cloud?
Hi Andrew,
Oh great! Thanks.
For the online version of the product we have a small API (API for the Nintex Forms for Office 0365) that allows for crud operations on a list: get, publish, import, save, and delete. There also an endpoint for toggling the assigned use tag (development/production).
You can find API reference topics here:
http://bit.ly/2jeBKZN
Note, the main trick with using the 0365 API is that you will need your tenant URL (yourtenant.sharepoint.com) but also API root URL, which is at the nintexO365.com domain, i.e., yourtenant. nintexO365.com. So the endpoint would look like: https://yourtenant.nintexO365.com/api/v1/forms/<https://yourtenant.nintexO365.com/api/v1/forms/%7blistid%7d>.
You will also a need to request a key from Nintex and include that in your header.
You can find the steps in the attached reference, but please let me know if you run into difficulties.
Thanks for asking.
Cheers,
Matt
Matt Briggs | Nintex<http://www.nintex.com/> Workflow for Everyone | Programmer Writer, User Assistance | matt.briggs@nintex.com | 1 (425) 3289 0469 | 1 (253) 237 2474
<https://twitter.com/nintex> <https://www.facebook.com/Nintex> <http://www.linkedin.com/company/nintex> <http://www.youtube.com/nintex>
hi Matt,
Have you got a chance to look at the PublishFormXML endpoint issue that I was reporting before?
Based on a test on the PublishFormXML end point using the form XML returned by the GetFormXML end point, you will get the issue the same the form was not published to a list.
I think the question here is simple, what is documented for the PublishFormXML endpoint is not working, I have been trying all I could with different format of the Form XML, including format as we exported the Form XML from the Form Designer, format that is returned by the GetFormXML, etc… Can you check with the development team what is the actual format to supplier for the PublishFormXML end point? No point wasting time trying it without knowing what is actual Form XML to be supplied.
KK
Hi KK:
I thought I'd messaged you back, sorry! I am not having trouble publishing the form using the sample for On Prem 2013 and the code sample in the SDK. The SDK comes with a Nintex Forms Client that handles some of the complexity of working with the On Prem REST point. You can find the sample here: http://help.nintex.com/en-US/sdks/sdk2013/#FormSDK/Topics/SDK_NF_API_OPS_NintexFormsPublishExample.htm
I have generated exceptions when the account I"m using doesn't have the right permissions.
When I try to execute the function "GetFormFromFileAndPublishToList" with a Nintex forms xml template I always receive the server response
"System.Net.WebException: The remote server returned an error: (413) Request Entity Too Large. at System.Net.HttpWebRequest.GetResponse() at System.ServiceModel.Channels.HttpChannelFactory`1.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)".
Up to now I do not know how to change this behaviour. Entries in web.config like
<system.serviceModel> <bindings> <webHttpBinding> <binding maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" transferMode="Streamed"> </binding> </webHttpBinding> </bindings></system.serviceModel>
did not work.,
Does anybody know how to solve this problem?
Kind regards
Andy
Hi ,
Is there any way we can publish Nintex forms to a content type and not to a specific list?
Thanks,
Ram
Dear Stphan,
Your PowerShell Script was really helpful and I was able to use it in On-Prem with HTTP. My requirement was Create a Sub Site from Template, Publish All Forms from the template site (by default it is not getting published), Publish Workflows. Used your script as a base and it worked like a charm.
Thank you very much.
I have explained my script here in case if anyone need it.
How to Publish Nintex Forms through PowerShell - Get-SPNote
Cheers
Thanks for your kind comments.
Have you solved this issue, i'm facing it right now with Nintex Responsive Form 2016