SharePoint Modern Site – Using Multiple Languages and Translate Page Programmatically using CSOM C# and PNP Core Context

Sathish Nadarajan
 
Solution Architect
November 22, 2021
 
Rate this article
 
Views
1358

I was trying to translate the pages created in one Site Collection to other languages and there is a simplest way of doing this using the PNP Core Context.  This is not available in the PNP Framework Context I hope.  (again, this is my opinion as I couldn’t find a way).

Basically, we need to enable the languages and even this can be done through programmatically while provisioning the sites.  But in my case, I have the site already.  Hence, I was about to do this manually through the site settings itself.

Go to the Site Settings and Language settings.  Select the Additional Languages and Click on Save.

 

Let me create a new page.

Created a page

Click on the Translation of the page.

On Click of the button, a new page will get created inside the es folder.

 

 

 

When we wanted to do this for a migrated site, which may have few thousands of pages, doing this is impossible and the migration tools will also not be able to do this.  In that case, writing a small utility to create the translation pages is very useful and effective.

As part of the earlier article, create the context.

Then, the below code will do the translation.

using (var scope = host.Services.CreateScope())

            {

                var pnpContextFactory = scope.ServiceProvider.GetRequiredService<IPnPContextFactory>();

                using (var context = await pnpContextFactory.CreateAsync("DemoSite"))

                {

                    var page = (await context.Web.GetPagesAsync("DemoPage")).FirstOrDefault();

                    await page.TranslatePagesAsync();

                }

            }

The above piece will do the same which we did manually earlier.  Hope this is simple and a good use case.

 

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
 

CSOM – Get the Pages modified after a time stamp by C# CSOM – SharePoint Online

Sathish Nadarajan
 
Solution Architect
October 7, 2021
 
Rate this article
 
Views
1305

In one of the requirements, got to retrieve the files which are modified after a specific time stamp. As part of that, created a CAML Query and thought of sharing with the community with the usecase.

One thing, just wanted to highlight is, the below code uses pnpFramework to get the context. As the earlier PNPCoreOnline is deprecated. Please search for pnpframework on the Nuget Manager.

public static void GetPagesByTimeStamp()
        {
            System.IO.File.AppendAllText(logFilePath, "Started.." + Environment.NewLine + Environment.NewLine);

            string siteUrl = ConfigurationManager.AppSettings["siteUrl"];
            string userName = ConfigurationManager.AppSettings["userName"];
            string password = ConfigurationManager.AppSettings["password"];
            string timestamp = ConfigurationManager.AppSettings["timestamp"];

            try
            {
                using (var ctx = new PnPClientContext(siteUrl))
                {
                    ctx.Credentials = new SharePointOnlineCredentials(userName, password.ToSecureString());
                    //Get the web from the current context
                    Web web = ctx.Web;
                    ctx.Load(web);
                    ctx.Load(web.Lists);
                    ctx.ExecuteQueryRetry();

                    //Get the Pages Library
                    var pages = ctx.Web.Lists.GetByTitle("Site Pages");
                    ctx.Load(pages);

                    //
                    
                    string datetime = Convert.ToDateTime(timestamp).ToString("yyyy-MM-ddTHH:mm:ssZ");
                    //Get all Items inside the Pages Library
                    CamlQuery camlQuery = new CamlQuery();
                    camlQuery.ViewXml = @"<View Scope='Recursive'>
                                             <Query>
                                                <Where>
                                                    <Gt>
                                                        <FieldRef Name='Modified'/>
                                                        <Value IncludeTimeValue='TRUE' Type='DateTime'>" + datetime + "</Value>" + 
                                                    @"</Gt>
                                                </Where>
                                                <OrderBy>
                                                    <FieldRef Name='Modified' Ascending = 'true' />
                                                </OrderBy>
                                            </Query>
                                         </View>";
                    ListItemCollection listItems = pages.GetItems(camlQuery);
                    ctx.Load(listItems);
                    ctx.ExecuteQuery();

                    List<Page> lstPages = new List<Page>();

                    foreach (var listItem in listItems)
                    {
                        System.Console.WriteLine(listItem["Title"]);
                        Page p = new Page();
                        p.Id = Convert.ToInt32(listItem["ID"]);
                        p.Name = Convert.ToString(listItem["Title"]);

                        lstPages.Add(p);


                    }



                    TextWriter txtWriter = new StreamWriter(ConfigurationManager.AppSettings["LogFilePath"] + "Pages.csv");

                    using (CsvWriter writer = new CsvWriter(txtWriter, new CsvHelper.Configuration.CsvConfiguration(System.Globalization.CultureInfo.InvariantCulture)))
                    {
                        writer.WriteRecords(lstPages);

                        writer.Flush();

                    }




                }
            }
            catch (Exception ex)
            {
                System.Console.WriteLine("Exception occurred : " + ex.Message);
                System.Console.ReadLine();
            }
        }

The above code is self explanatory and doesn’t require much explanation I guess.


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
 

CSOM – PowerShell Script – Import Nintex Workflows in SharePoint

Sathish Nadarajan
 
Solution Architect
February 10, 2021
 
Rate this article
 
Views
1004

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

01.ImprotNintexForms

function Import-NintexWorkflow {
<# .SYNOPSIS Imports a Nintex workflow .nwf file to a list. .DESCRIPTION Imports a Nintex workflow .nwf file to a list. #>
[CmdletBinding()]
param(
[string]$WebUrl = $(throw "Required parameter -WebUrl missing"),
[string]$listName = $(throw "Required parameter -ListName missing"),
[string[]]$workflowNames = $(throw "Required parameter -workflowNames missing"),
[string]$WorkflowFolderPath = $(throw "Required parameter -WorkflowFolderPath missing"),
[bool]$OverwriteExistingVersion = $false
)
begin {
if(!(Get-PnPConnection)) {
throw "There is no PnPConnection"
}
Write-Host "---- Importing Nintex workflow to '$($listName)' ----" -ForegroundColor Yellow
}
process {
$List = Get-PnPList -Identity $listName
$ListID = $List.Id.ToString()
$ListName = $List.Title
$webServiceUrl = "$WebUrl/_vti_bin/NintexWorkflow/Workflow.asmx"
$webServiceProxy = New-WebServiceProxy -Uri $webServiceUrl -UseDefaultCredential
$webServiceProxy.URL = $webServiceUrl

for ($i=0;$i -lt $workflowNames.Length; $i++) {
$WorkflowName = $workflowNames[$i] + "_6"
$WorkflowFilePath = $WorkflowFolderPath + "" + $workflowNames[$i] + ".nwf"

$nwfContent = Get-Content "$WorkflowFilePath"
$utf8 = New-Object System.Text.UTF8Encoding
[byte[]] $byteData = $utf8.GetBytes($nwfContent.ToString())
$hasWorkflowPublished = $webServiceProxy.WorkflowExists($WorkflowName,$ListID,"List")
Write-Host "Workflow exists status: '$hasWorkflowPublished'" -ForegroundColor Cyan
if($hasWorkflowPublished -eq "NameUsedInOtherList" -or $hasWorkflowPublished -eq "NameUsedInThisList") {
#May be delete it
Write-Host "Workflow already exists '$hasWorkflowPublished', if status is 'NameUsedInOtherList' no changes can be made. Please delete it." -ForegroundColor Cyan
}
if($hasWorkflowPublished -eq "NameNotUsed" -or ($hasWorkflowPublished -eq "NameUsedInThisList" -and $OverwriteExistingVersion -eq $true)){
$IsPublished = $webServiceProxy.PublishFromNWF($byteData, $ListName, $WorkflowName, $true)
if($IsPublished) {
Write-Host "Nintex Workflow '$WorkflowName' successfully published to list '$ListName'" -ForegroundColor Green
} else {
Write-Host "Nintex Workflow '$WorkflowName' could not be published to list '$ListName'" -ForegroundColor Yellow
}
}
}
}
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://andytest-sp:555/sites/newsite/'
$sourceListname = "AssetRegisterV2"

$outputFolderPath = ".Logs-$LogTime"

$targetWebUrl = 'http://andytest-sp:555/sites/newsite/'
$targetListname = "AssetRegister_Test"
$workflowNames = @('Send Notification When Child is Promoted as Parent','Send Notification When Asset is deleted')

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

Import-Module ".4.ImportNintexWorkflows.ps1"

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

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

Import-NintexWorkflow $targetWebUrl $targetListname $workflowNames $outputFolderPath $true
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
 

CSOM – PowerShell Script – Export Nintex Workflows in SharePoint

Sathish Nadarajan
 
Solution Architect
February 9, 2021
 
Rate this article
 
Views
1778

During the time of deployment, we may in a need to export and import the workflows from our DEV environment to the higher environment. In this article, let us see how to Export Nintex Workflows in SharePoint using CSOM PowerShell Script.

The code is self-explanatory.

01.ExportNintexForms

 

function Export-NintexWorkflow {
<# .SYNOPSIS Export a Nintex workflow .nwf file to a local directory .DESCRIPTION Export a Nintex workflow .nwf file to a local directory #>
[CmdletBinding()]
param(
[string]$WebUrl = $(throw "Required parameter -WebUrl missing"),
[string]$listName = $(throw "Required parameter -ListName missing"),
[string[]]$workflowNames = $(throw "Required parameter -WorkflowNames missing"),
[string]$FilePath = $(throw "Required parameter -FilePath missing")
)
begin {
if(!(Get-PnPConnection)) {
throw "There is no PnPConnection"
}
Write-Host "---- Exporting Nintex workflow for '$($List.Title)' ----" -ForegroundColor Yellow
}
process {
$List = Get-PnPList -Identity $listName
$timeStampString = [DateTime]::Now.ToString("yyyyMMdd-HHmmss")
# Get XML New File path
$xmlFilePath = "$FilePath$($List.Title)-$timeStampString.nwf"

$webServiceUrl = "$WebUrl/_vti_bin/NintexWorkflow/Workflow.asmx"
$webServiceProxy = New-WebServiceProxy -Uri $webServiceUrl -UseDefaultCredential
$webServiceProxy.URL = $webServiceUrl
$ctx=Get-PnPContext

$ctx.load($List.WorkflowAssociations)
$ctx.ExecuteQuery()

#Get all workflows that are associated with the current list
foreach($listassociation in $List.WorkflowAssociations) {
if($workflowNames.Contains($listassociation.Name)){
$WorkflowName = $listassociation.Name
$workflowContent = $webServiceProxy.ExportWorkflow($WorkflowName, $List.Title, "list")
$xmlFilePath = "$FilePath$WorkflowName.nwf"
#Save XML File to Disk
$workflowContent | Out-File $xmlFilePath
Write-Host "Nintex workflow '$WorkflowName' exported successfully to '$xmlFilePath'" -ForegroundColor Green
}
}
}
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://SourceSiteURL/sites/newsite/'
$sourceListname = "AssetRegisterV2"

$outputFolderPath = ".Logs-$LogTime"

$targetWebUrl = 'http://TargetSiteURL/sites/newsite/'
$targetListname = "AssetRegister_Test"
$workflowNames = @('Send Notification When Child is Promoted as Parent','Send Notification When Asset is deleted')

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

Import-Module ".3.ExportNintexWorkflows.ps1"

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

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

Export-NintexWorkflow $sourceWebUrl $sourceListname $workflowNames $outputFolderPath

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
 

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

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

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
 

How to Rename the Site Collection URL in SharePoint 2019 using PowerShell

Sathish Nadarajan
 
Solution Architect
April 10, 2020
 
Rate this article
 
Views
4082

During the migration, we will be creating huge number of site collections. While creating those site collections, we should be cautious about the Site URL. Recently, I made a type error while creating the Site Collection and did the Migration. After sometime, I realized that the URL has a typo. At that time, the below commands will be useful to rename the URL. But again, one important thing to notice is, the referenced links needs to be updated. It will not be updated automatically.

A simple method to rename the Site Collection URL – Thought of sharing.

$site = Get-SPSite http://MyWebApp/sites/gws1/
$site.Rename("http:// MyWebApp /sites/gws2/")

There are some important things to be noted when using this. The default links will be link corrected automatically. But, if we have few custom links based on the old URL, then they will not be renamed automatically. There are potential chances of link breaks. So, we need to be very careful while using this feature.

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
 

How to Update Nintex Workflow with No New Instances in SharePoint 2013 Using CSOM PowerShell Script

Sathish Nadarajan
 
Solution Architect
December 17, 2019
 
Rate this article
 
Views
933

After a long time, faced with a different scenario. The site collection has various lists and there are a lot of Nintex workflows associated to those lists. I was about to populate data for those lists using a backend mechanism, but don’t want those workflows to be triggered. Provided the Scenario, I don’t want to delete and attach the workflows again. Rather, there is an option called “No New instances” in the workflow properties. But, since we had many lists, can’t do this manually. Hence, came up with a script. Thought of sharing with the community.
When we do manually, we will go to the workflow settings of the list and click on the “Remove, Block or Restore a workflow”

Once, we click that, the next screen would be as below where we can toggle between the properties.

The below script will toggle this property.

Clear-Host

# Connects and Creates Context
Connect-PnPOnline https://SiteCollectionURL -CurrentCredentials

[System.Collections.ArrayList]$listsToUpdateWorkflowStatus = Get-PnPList | Where-Object {$_.Title.StartsWith('Our Lists Prefix') }

$ctx=Get-PnPContext

foreach ($list in $listsToUpdateWorkflowStatus)
{
     
        $ctx.load($list.WorkflowAssociations)
        $ctx.ExecuteQuery()
        $list.WorkflowAssociations
        $workflowAssociation = $list.WorkflowAssociations[0]
        # $workflowAssociation.DeleteObject()
        $workflowAssociation.Enabled = $false
        $workflowAssociation.Update()
        $list.Update()
        
        $ctx.ExecuteQuery()
     
}

Happy Coding,
Sathish Nadarajan.

Category : CSOM, PowerShell, SharePoint

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
 

SharePoint Office 365 – Global Navigation & Current Navigation Provisioning using PNP Template and C#

Sathish Nadarajan
 
Solution Architect
May 23, 2019
 
Rate this article
 
Views
1949

In this article, let us provision the Global Navigation & Current Navigation using PNP Provisioning Template by using C#.  The Provisioning Template is as below.

 <?xml version="1.0"?>
 <pnp:Provisioning xmlns:pnp="http://schemas.dev.office.com/PnP/2018/01/ProvisioningSchema">
   <pnp:Preferences Generator="OfficeDevPnP.Core, Version=4.0.30319, Culture=neutral, PublicKeyToken=5e633289e95c321a" />
   <pnp:Templates>
     <pnp:ProvisioningTemplate ID="SPPALS.ProvisioningTemplate.Navigation" Version="1" Scope="RootSite">
       <pnp:Navigation AddNewPagesToNavigation="false" CreateFriendlyUrlsForNewPages="false">
         <pnp:GlobalNavigation NavigationType="Structural">
           <pnp:StructuralNavigation RemoveExistingNodes="true">
             <pnp:NavigationNode Title="Node.1" Url="{sitecollection}/Pages/CORB.aspx" IsExternal="true" IsVisible="true" >
               <pnp:NavigationNode Title="Node.1.1" Url="{sitecollection}/Pages/Page2.aspx" IsExternal="true" IsVisible="true"/>
               <pnp:NavigationNode Title="Node.1.2" Url="https://sharepointpals.com" IsExternal="true" IsVisible="true"/>
             </pnp:NavigationNode>
           </pnp:StructuralNavigation>
         </pnp:GlobalNavigation>
         <pnp:CurrentNavigation NavigationType="Structural">
           <pnp:StructuralNavigation RemoveExistingNodes="true">
             <pnp:NavigationNode Title="Node.1" Url="{sitecollection}/Pages/CORB.aspx" IsExternal="true" IsVisible="true" >
               <pnp:NavigationNode Title="Node.1.1" Url="{sitecollection}/Pages/Page2.aspx" IsExternal="true" IsVisible="true"/>
               <pnp:NavigationNode Title="Node.1.2" Url="https://sharepointpals.com" IsExternal="true" IsVisible="true"/>
             </pnp:NavigationNode>
           </pnp:StructuralNavigation>
         </pnp:CurrentNavigation>
       </pnp:Navigation>
     </pnp:ProvisioningTemplate>
   </pnp:Templates>
 </pnp:Provisioning>
 

 

And the C# code is straight forward.  It is as below.

 

 static void Main(string[] args)
         {
             ProvisionTaxonomyPNP();
         }
 
         public static void ProvisionTaxonomyPNP()
         {
             OfficeDevPnP.Core.AuthenticationManager authMgr = new OfficeDevPnP.Core.AuthenticationManager();
 
             string siteUrl = "https://sppalsmvp.sharepoint.com/sites/TeamSite/";
             string userName = "sathish@sppals.com";
             string password = "*****";
 
             using (var clientContext = authMgr.GetSharePointOnlineAuthenticatedContextTenant(siteUrl, userName, password))
             {
                 Web web = clientContext.Web;
                 clientContext.Load(web);
                 clientContext.Load(web.Lists);
                 clientContext.ExecuteQuery();
 
                 var templateLocation = "D:\PRACTICE SOURCE CODE\SPPALS.Console\SPPALS.Console\ProvisioningTemplate";
                 var provisioningProvider = new XMLFileSystemTemplateProvider(templateLocation, string.Empty);
 
                 var organizationSiteProvisioningTemplate = provisioningProvider.GetTemplate("SPPals.ProvisioningTemplate.Navigation.xml");
                 organizationSiteProvisioningTemplate.Connector.Parameters[FileConnectorBase.CONNECTIONSTRING] = templateLocation;
                 clientContext.Web.ApplyProvisioningTemplate(organizationSiteProvisioningTemplate);
             }
         }
 
 

 

The terms will be provisioned as below.  We can see that on the AreaNavigationSettings.aspx

 

And on the Screen, the Nodes will be like,

 

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
 

SharePoint Office 365 – Terms Provisioning using PNP Template and C#

Sathish Nadarajan
 
Solution Architect
May 14, 2019
 
Rate this article
 
Views
1567

In this article, let us provision the TermSet and Terms using PNP Provisioning Template by using C#.  The Provisioning Template is as below.

 <?xml version="1.0"?>
 <pnp:Provisioning xmlns:pnp="http://schemas.dev.office.com/PnP/2018/01/ProvisioningSchema">
   <pnp:Preferences Generator="OfficeDevPnP.Core, Version=4.0.30319, Culture=neutral, PublicKeyToken=5e633289e95c321a" />
   <pnp:Templates>
     <pnp:ProvisioningTemplate ID="SPPALS.ProvisioningTemplate.TermGroups" Version="1" Scope="RootSite">
       <pnp:TermGroups>
         <pnp:TermGroup Name="{sitecollectiontermgroupname}">
           <pnp:TermSets>
             <pnp:TermSet Name="TermSet1" Language="1033">
               <pnp:Terms>
                 <pnp:Term Name="Term1"   IsAvailableForTagging="true" IsSourceTerm="false"></pnp:Term>
                 <pnp:Term Name="Term2"  IsAvailableForTagging="true" IsSourceTerm="false"></pnp:Term>
                 <pnp:Term Name="Term3"   IsAvailableForTagging="true" IsSourceTerm="false"></pnp:Term>
               </pnp:Terms>
             </pnp:TermSet>
           </pnp:TermSets>
         </pnp:TermGroup>
       </pnp:TermGroups>
     </pnp:ProvisioningTemplate>
   </pnp:Templates>
 </pnp:Provisioning>
 

And the C# code is straight forward.  It is as below.

 static void Main(string[] args)
         {
             ProvisionTaxonomyPNP();
         }
 
         public static void ProvisionTaxonomyPNP()
         {
             OfficeDevPnP.Core.AuthenticationManager authMgr = new OfficeDevPnP.Core.AuthenticationManager();
 
             string siteUrl = "https://sppalsmvp.sharepoint.com/sites/TeamSite/";
             string userName = "sathish@sppals.com";
             string password = "*****";
 
             using (var clientContext = authMgr.GetSharePointOnlineAuthenticatedContextTenant(siteUrl, userName, password))
             {
                 Web web = clientContext.Web;
                 clientContext.Load(web);
                 clientContext.Load(web.Lists);
                 clientContext.ExecuteQuery();
 
                 var templateLocation = "D:\PRACTICE SOURCE CODE\SPPALS.Console\SPPALS.Console\ProvisioningTemplate";
                 var provisioningProvider = new XMLFileSystemTemplateProvider(templateLocation, string.Empty);
 
                 var organizationSiteProvisioningTemplate = provisioningProvider.GetTemplate("SPPals.ProvisioningTemplate.TermGroups.xml");
                 organizationSiteProvisioningTemplate.Connector.Parameters[FileConnectorBase.CONNECTIONSTRING] = templateLocation;
                 clientContext.Web.ApplyProvisioningTemplate(organizationSiteProvisioningTemplate);
             }
         }
 

 

The terms will be provisioned as below.

 

 

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
 

How To Check Existence Of A Subsite And Provision Subsite In SharePoint Online Using CSOM – C# Programmatically

Ahamed Fazil Buhari
 
Senior Developer
March 25, 2019
 
Rate this article
 
Views
3071

Hi,

In the below article we will see how to provision Sub Sites in SharePoint Online. As a first step, we need to check whether the subsite is already exists or not. If it doesn’t exits then we will provision the site using CSOM (Console Application).

I have the Site URL and Client ID values in app.config file. Please refer this article if you are not familiar with Token based authentication

 

The below code with comments explains everything.

 using Microsoft.SharePoint.Client;
 using System;
 
 namespace SpPals.TemplateProvision
 {
     public static class SPpals
     {
         public static void ProvisionFunction()
         {
             string topRootSite = "https://fazildev.sharepoint.com/sites/sppals/";
             var siteUri = new Uri(topRootSite);
             var realm = TokenHelper.GetRealmFromTargetUrl(siteUri);
             // Client ID and Secrent Key will be taken from App.config file
             var accessToken = TokenHelper.GetAppOnlyAccessToken(TokenHelper.SharePointPrincipal,
             siteUri.Authority, realm).AccessToken;
             using (var ctx = TokenHelper.GetClientContextWithAccessToken(siteUri.ToString(), accessToken))
             {
                 string subSite = "test2";
                 ProvisionSubSite(subSite, ctx);
             }
         }
 
         static void ProvisionSubSite(string subSite, ClientContext ctx)
         {
             try
             {
                 // If the site is subsite of a subsite, then use OpenWeb as show below in comment
                 // ctx.Site.OpenWeb("top-subsite-url-name").WebExists(subSite);
                 // Check If Subsite existing
                 if (ctx.Site.RootWeb.WebExists(subSite))
                 {
                     Console.WriteLine("Already Exists");
                 }
                 else
                 {
                     WebCreationInformation webCreationInformation = new WebCreationInformation()
                     {
                         // I create TeamSite as subsite - you can find different type of sites here
                         //  https://www.jasjitchopra.com/sharepoint-2013-site-templates-codes-for-powershell/
                         WebTemplate = "STS#0",
                         Title = subSite,
                         Url = subSite,
                         Language = 1033,
                         UseSamePermissionsAsParentSite = true
                     };
                     Web newWeb = ctx.Web.Webs.Add(webCreationInformation);
                     ctx.Load(newWeb);
                     ctx.ExecuteQuery();
                 }
             }
             catch (Exception ex)
             {
                 Console.WriteLine("Something went wrong. " + ex.Message);
             }
         }
     }
 }
 

Please make sure the following reference from Nuget package are already added in your project and include TokenHelper.cs file into your project for authentication.

 

Happy Coding

Ahamed

Category : Office 365, SharePoint

Author Info

Ahamed Fazil Buhari
 
Senior Developer
 
Rate this article
 
Ahamed is a Senior Developer and he has very good experience in the field of Microsoft Technologies, especially SharePoint, Azure, M365, SPFx, .NET and client side scripting - JavaScript, TypeScript, ...read more
 

Leave a comment