Thursday, July 16, 2015

Powershell script to create xml from SharePoint List items and columns

This script will generate an xml file from the list - MyListName.
Additional method is given to remove required fields from the XML nodes
Additional method is given to Rename required fields/nodes in the XML
This powershell script generate a blank template XML from the list fields/columns which need to be added in the xml for each item in the list
The powershell is reading content like - listname, fieldToRemove, fieldsToRename, siteurl etc from The config xml, which can be modified later for future use
The config xml and the powershell script should be in same folder
The script is logging the error in the error log file

The output XML will be like: - For each item a new node "<Contract>"is added

<?xml version="1.0"?>
<Contracts>
 <Contract>
   <Field1>Field1Content</Field1>
   <Field2>Field2Content</Field1>
  </Contract>
   <Contract>
   <Field1>Field1Content</Field1>
   <Field2>Field2Content</Field1>
  </Contract>
 </Contracts>


Following is the code:

1. The Config XML:

<settings>
<FieldsToNotAdd>Submitted;field1;field2</FieldsToNotAdd>
<ModifyNames>ActualColName1,ColNameToDisplay1;ActualColName2,ColNameToDisplay2</ModifyNames>
<NodeNamesToIgnore>ows_Author;ows_AuthorId;vti_title;ows_Editor</NodeNamesToIgnore>
<OutputXmlFilePath>OutputXMLFile.xml</OutputXmlFilePath>
<WebURL>http://internet.sharepointsite.com/teams/nibha</WebURL>
<ListName>MyListName</ListName>

</settings>

2. Powershell Script:

#This script will generate an xml file from the list - MyListName.
#Additional method is given to remove required fields from the XML nodes
#Additional method is given to Rename required fields/nodes in the XML
# This powershell script generate a blank template XML from the list fields/columns which need to be added in the xml for each item in the list
# The powershell is reading content like - listname, fieldtoremove, fieldstorename, siteurl etc from the config xml, which can be modified later for future use
# the config xml and the powershell script should be in same folder
# The script is logging the error in the error log file

cls

if((Get-PSSnapin | Where {$_.Name -eq "Microsoft.SharePoint.PowerShell"}) -eq $null) {
Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue;
}

#Load Config XML
$configXml = New-Object xml
$configXml.Load("XMLConfig.xml")
# Script variables

$DatePostFix = Get-Date -format "MM-dd-yyyy_hh-mm-ss"
$LogFileName = "GenerateXMLErrorLog_" + $DatePostFix + ".csv"
$outputXmlFilePath= $configXml.SelectSingleNode("settings/OutputXmlFilePath").InnerText;
$webURL = $configXml.SelectSingleNode("settings/WebURL").InnerText;
$listName = $configXml.SelectSingleNode("settings/ListName").InnerText
$outputXmlTemplate= "MyTemplateXML.xml";

# Method to Create the XML Template, this template is created by all the list fields.
# This template is being used for creating the complete XML with the list data
function CreateTemplateXML()
{
    try {
    $spWeb = Get-SPWeb $webURL;
    $spList = $spWeb.Lists[$listName];
    $spItems = $spList.GetItems()[0];
    [System.Xml.XmlTextWriter]$xml = New-Object 'System.Xml.XmlTextWriter' $outputXmlTemplate, ([Text.Encoding]::UTF16);
    $xml.Formatting = "indented";
    $xml.Indentation = 4;
    $xml.WriteStartDocument();
    $xml.WriteStartElement('Contracts');

    $spItems | ForEach-Object {
        $xml.WriteStartElement('Contract');
        $litem = $_
        $_.Fields | ForEach {
              $displayName = $_.InternalName
            $xml.WriteElementString($displayName, '');
        }
        $xml.WriteEndElement();
    }

    $xml.WriteEndElement();
    $xml.Flush();
    $xml.Close();
    $spWeb.Dispose();
    }
    Catch [exception]
    {
         # Logging the exception in log file
         " Exception in My XML Template creation method (CreateTemplateXML() ) = {0}" -f $_.Exception.Message |Add-Content $LogFileName
         $xml.Flush();
         $xml.Close();
         $spWeb.Dispose();
     }
}

# Method to Remove the required elements
function RemoveNodes()
{
     try {
        $remove_parent_path = '/Contracts/Contract'
        $remove_nodes = $xml.SelectNodes($remove_parent_path)
        foreach ($field in $fieldsToNotAdd.Split(";"))
        {
                $remove_nodes | % {
                    $remove_child_node = $_.SelectSingleNode($field)
                    if ($remove_child_node -ne $null) {
                        $_.RemoveChild($remove_child_node) | Out-Null
                    }
                }
        }
    }
    Catch [exception]
    {
         # Logging the exception in log file
         " Exception in My XML Template method (RemoveNodes() ) = {0}" -f $_.Exception.Message |Add-Content $LogFileName
     }
}

#Method to Rename the required nodes
function RenameNodes()
{
    try {
        foreach ($nodeNames in $modifyNames.Split(";"))
        {
            $oldNodeName = $nodeNames.Split(",")[0]
            $newNodeName = $nodeNames.Split(",")[1]
            (Get-Content $outputXmlFilePath) |
                Foreach-Object {$_ -replace , $oldNodeName,$newNodeName} |
                Set-Content $outputXmlFilePath
        }
    }
    Catch [exception]
    {
         # Logging the exception in log file
         " Exception in My XML Template method (RenameNodes() ) = {0}" -f $_.Exception.Message |Add-Content $LogFileName
     }
}

#Call the method to create the XML Template
CreateTemplateXML

# load XML template into XML object
$xml = New-Object xml
$xml.Load($outputXmlTemplate)

# Get Fields names - fields to not add, fields to modify the names
$fieldsToNotAdd = $configXml.SelectSingleNode("settings/FieldsToNotAdd").InnerText
$modifyNames = $configXml.SelectSingleNode("settings/ModifyNames").InnerText

# Call method to remove the fields not to add in the xml
  RemoveNodes

try {
    # grab template Contract

    $newContract = (@($xml.Contracts.Contract)[0]).Clone()
    # Create the complete XML START
    # Use  XML template to add Contracts to xml
    $spWeb = Get-SPWeb $webURL;
    $spList = $spWeb.Lists[$listName];
    $spItems = $spList.GetItems();

    $spItems | ForEach-Object {
           $newContract = $newContract.clone()
        $litem = $_
        $_.Fields | ForEach {
              $displayName = $_.InternalName
            $lvalue = $litem[$displayName]
        if ($newContract.$displayName -ne $null -and $litem[$displayName] -ne $null) { $newContract.$displayName =  $litem[$displayName].toString() }
        }
           $xml.Contracts.AppendChild($newContract) > $null
    }

    # remove Contracts with undefined ID (remove template)

    $xml.Contracts.Contract |

    Where-Object { $_.ID -eq "" } |
    ForEach-Object  { [void]$xml.Contracts.RemoveChild($_) }

    # save xml to file
    $xml.Save($outputXmlFilePath)
    # Create the complete XML END
    # Call the method to Rename Nodes

    RenameNodes

  }
  Catch [exception]
  {
         # Logging the exception in log file
         "Exception in DCV Contracts XML Creation - {0}" -f $_.Exception.Message |Add-Content $LogFileName
  }

    # Dispose the spweb object
    $spWeb.Dispose();