PowerShell SharePoint DataTable - sharepoint

I am trying to update a SharePoint list, because of its size and to make things faster I want to use a DataTable.
$webURL = "http://test/test"
$listName = "Test List"
$web = Get-SPWeb $webURL
$list = $web.Lists[$listName]
$items = $list.items.GetDataTable() | select LinkTitle, Failure_x0020_Step
foreach($item in $items)
{
if(($item.LinkTitle -eq "PC111"))
{
$item.Failure_x0020_Step = "Failure Test"
$item.Update()
}
else {}
}
I get this error when running the script:
Method invocation failed because [System.Data.DataRow] doesn't contain a method named 'Update'.
+ CategoryInfo : InvalidOperation: (Update:String) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound
I do have it working without the DataTable (changes below), but would prefer the DataTable.
$items = $list.items
if(($item["Computer"] -eq "PC111"))
$item["Failure Step"] = "Failure Test"

When you're calling Update(), that is trying to apply an Update to the DataTable, not the SharePoint list. They are separated. You'll need to retrieve the actual list item from SharePoint and update it.
I'm not sure why a DataTable makes things faster for you but if you want to keep it:
$webURL = "http://test/test"
$listName = "Test List"
$web = Get-SPWeb $webURL
$list = $web.Lists[$listName]
$items = $list.items.GetDataTable() | select LinkTitle, Failure_x0020_Step, ID
foreach($item in $items)
{
if(($item.LinkTitle -eq "PC111"))
{
$realItem = $list.GetItemById($item.ID)
$realItem['Failure_x0020_Step'] = "Failure Test"
$realItem.Update()
}
else {}
}

Related

Default OOBX EditForm disappeared for a SharePoint document library

Default OOBX EditForm disappeared for a SharePoint document library. We tried to create a new edit form in SharePoint designer but got an error that Could not save the List Changes to Server.
Then tried another approach, go to All files/Documentlibrary/Forms -- here got list view threshold error. We have more than 10 thousands items in the library, can't open up forms folder.
Please advise how to get the default edit form back.
You'll need to do it through PowerShell:
$webpartTemplate = #"
<WebPart xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/WebPart/v2">
<Assembly>Microsoft.SharePoint, Version=16.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c</Assembly>
<TypeName>Microsoft.SharePoint.WebPartPages.ListFormWebPart</TypeName>
<ListName xmlns="http://schemas.microsoft.com/WebPart/v2/ListForm">{{{LIST_ID}}}</ListName>
<ListId xmlns="http://schemas.microsoft.com/WebPart/v2/ListForm">{{LIST_ID}}</ListId>
<PageType xmlns="http://schemas.microsoft.com/WebPart/v2/ListForm">{{PAGE_TYPE}}</PageType>
<FormType xmlns="http://schemas.microsoft.com/WebPart/v2/ListForm">{{FORM_TYPE}}</FormType>
<ControlMode xmlns="http://schemas.microsoft.com/WebPart/v2/ListForm">{{CONTROL_MODE}}</ControlMode>
<ViewFlag xmlns="http://schemas.microsoft.com/WebPart/v2/ListForm">1048576</ViewFlag>
<ViewFlags xmlns="http://schemas.microsoft.com/WebPart/v2/ListForm">Default</ViewFlags>
<ListItemId xmlns="http://schemas.microsoft.com/WebPart/v2/ListForm">0</ListItemId>
</WebPart>
"#
Function Create-DefaultListForm
{
param(
[parameter(Mandatory=$true)]$List,
[parameter(Mandatory=$true)][string]$FormUrl,
[parameter(Mandatory=$true)][ValidateSet("Display", "Edit", "New")]$FormType
)
begin { }
process
{
$webpartXml = $webpartTemplate -replace "{{LIST_ID}}", $List.Id.ToString()
switch ($FormType)
{
"Display" {
$webpartXml = $webpartXml -replace "{{PAGE_TYPE}}", "PAGE_DISPLAYFORM"
$webpartXml = $webpartXml -replace "{{FORM_TYPE}}", "4"
$webpartXml = $webpartXml -replace "{{CONTROL_MODE}}", "Display"
break;
}
"Edit" {
$webpartXml = $webpartXml -replace "{{PAGE_TYPE}}", "PAGE_EDITFORM"
$webpartXml = $webpartXml -replace "{{FORM_TYPE}}", "6"
$webpartXml = $webpartXml -replace "{{CONTROL_MODE}}", "Edit"
break;
}
"New" {
$webpartXml = $webpartXml -replace "{{PAGE_TYPE}}", "PAGE_NEWFORM"
$webpartXml = $webpartXml -replace "{{FORM_TYPE}}", "8"
$webpartXml = $webpartXml -replace "{{CONTROL_MODE}}", "New"
break;
}
}
try
{
#Check if form page already exists
$listPages = Get-PnPProperty -ClientObject $List.RootFolder -Property Files
$formPage = $listPages | Where-Object { $_.ServerRelativeUrl.ToLower() -eq $FormUrl.ToLower() }
if ($null -eq $formPage) {
Write-Output " [Creating Form Page] $FormUrl"
#Create Form
Remove-PnPFile -ServerRelativeUrl $FormUrl -Force
$formPage = $List.RootFolder.Files.AddTemplateFile($FormUrl, [Microsoft.SharePoint.Client.TemplateFileType]::FormPage)
}
else {
#Form page exists, check if form is recognized by list (i.e. form page has a form webpart on it)
$listForms = Get-PnPProperty -ClientObject $List -Property Forms
if ($null -ne $listForms -and $listForms.Count -gt 0) {
$existingForm = $list.Forms | Where-Object { $_.ServerRelativeUrl.ToLower() -eq $FormUrl.ToLower() }
if ($null -ne $existingForm) {
Write-Warning " [Form Already Exists] $FormUrl"
return;
}
}
}
Write-Output " [Adding Form Webpart] $FormUrl"
#Get Webpart Manager for Form
$wpm = $formPage.GetLimitedWebPartManager([Microsoft.SharePoint.Client.WebParts.PersonalizationScope]::Shared)
#Import Webpart on page
$wp = $wpm.ImportWebPart($webpartXml)
#Add webpart to Form
$wpm.AddWebPart($wp.WebPart, "Main", 1) | Out-Null
#Execute changes
$List.Context.ExecuteQuery()
}
catch
{
Write-Error "Error creating form $FormType at $FormUrl. Error: $($_.Exception)"
}
}
end { }
}
Use the script something like this. If you only need to restore the EditForm, then you obviously you can skip the Upload, New, and DispForms below:
Connect-PnPOnline -Url $problemSiteUrl -UseWebLogin
$list = Get-PnPList $problemlistTitle
$listUrl = $list.RootFolder.ServerRelativeUrl
# Handle Document Library Types
if ($list.BaseType -eq [Microsoft.SharePoint.Client.BaseType]::DocumentLibrary) {
Write-Host " > Processing Library: $listUrl"
Create-DefaultListForm -List $list -FormUrl "$listUrl/Forms/Upload.aspx" -FormType New
Create-DefaultListForm -List $list -FormUrl "$listUrl/Forms/DispForm.aspx" -FormType Display
Create-DefaultListForm -List $list -FormUrl "$listUrl/Forms/EditForm.aspx" -FormType Edit
}
# Handle Generic List Types
else {
Write-Host " > Processing List: $listUrl"
Create-DefaultListForm -List $list -FormUrl "$listUrl/NewForm.aspx" -FormType New
Create-DefaultListForm -List $list -FormUrl "$listUrl/DispForm.aspx" -FormType Display
Create-DefaultListForm -List $list -FormUrl "$listUrl/EditForm.aspx" -FormType Edit
}
If you only need the Edit form, use the Create-DefaultListForm function like this:
Connect-PnPOnline -Url 'UrlOfProblemSite' -UseWebLogin
$list = Get-PnPList 'TitleOfTheProblemLibraryHere'
$listUrl = $list.RootFolder.ServerRelativeUrl
Create-DefaultListForm -List $list -FormUrl "$listUrl/Forms/EditForm.aspx" -FormType Edit

Change multiple files content type programatically using CSOM for SharePoint Online

I am attempting to change all the files in a library from one content type to another. This is in SharePoint Online so I'm using the CSOM. I am new to this so I'm stuck at where to go from what I have below.
I think my biggest issue is getting the values of the content types. That and I'm so used to SP On Premise I'm having trouble grasping this CSOM stuff. Much thanks to anyone that can help point me in the right direction!
#Load necessary module to connect to SPOService
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.Runtime") | Out-Null
#Login Information for script
$User = "user"
$Pass = "password"
$WebUrl = "SiteURL"
#Connect to SharePoint Online service
Write-Host "Logging into SharePoint online service." -ForegroundColor Green
$Context = New-Object Microsoft.SharePoint.Client.ClientContext($WebUrl)
$Context.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($User, (ConvertTo-SecureString $Pass -AsPlainText -Force))
#Get the Necessary List
Write-Host "Getting the required list." -ForegroundColor Green
$List = $Context.Web.Lists.GetByTitle("TestLibrary")
Write-Host "Getting the Content Types." -ForegroundColor Green
$oldCT = $list.ContentTypes("OldCTName")
$newCT = $list.ContentTypes("NewCTName")
$newCTID = $newCT.ID
$Query = [Microsoft.SharePoint.Client.CamlQuery]::CreateAllItemsQuery(1000);
$Items = $List.GetItems($Query);
$Context.Load($Items);
$Context.ExecuteQuery();
#Check if the values specified for the content types actually exist on the list
if (($oldCT -ne $null) -and ($newCT -ne $null))
{
#Go through each item in the list
#Edit existing list items
foreach($item in $Items)
{
#Check if the item content type currently equals the old content type specified
if ($_.ContentType.Name -eq $oldCT.Name)
{
#Check the check out status of the file
if ($_.File.CheckOutType -eq "None")
{
#Change the content type association for the item
$_.File.CheckOut()
write-host "Resetting content type for file" $_.Name "from" $oldCT.Name "to" $newCT.Name
$_["ContentTypeId"] = $newCTID
$_.Update()
$_.File.CheckIn("Content type changed to " + $newCT.Name, 1)
}
else
{
write-host "File" $_.Name "is checked out to" $_.File.CheckedOutByUser.ToString() "and cannot be modified"
}
}
else
{
write-host "File" $_.Name "is associated with the content type" $_.ContentType.Name "and shall not be modified"
}
}
}
else
{
write-host "One of the content types specified has not been attached to the list"$list.Title
}
$Context.ExecuteQuery();
}

migrate document with its meta data from one document library to a folder

I am beginner in sharepoint specially in powershell.
I am trying to move all the documents of a document library from one site to another site inside a folder. but I could just copy the files not metadata whcih come from contenttypes!
$PSSnapin = Add-PsSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue Out-Null
clear
$org = "http://'YYYYY'/sites/XXXX"
$dest = "http://'YYYYY'/sites/XXXX/Subsite"
$orgLibrary = (Get-SPWeb $org).Folders["newdoc1"]
$destLibrary = (Get-SPWeb $dest).Folders["newdoc2"].SubFolders["folder1"]
$destFiles = $destLibrary.Files
foreach ($file in $orgLibrary.Files)
{
$curFile = $file.OpenBinary()
$destURL = $destFiles.Folder.Url + "/" + $file.Name
$destFiles.Add($destURL, $curFile, $true)
}
This one here does just that. Except for modified and created dates, all other fields are brought over.
$web = Get-SPWeb "http://sharepointed.com/"
$list = $web.Lists["Shared Documents"]
$spQuery = New-Object Microsoft.SharePoint.SPQuery
$spQuery.ViewAttributes = "Scope='Recursive'";
$spQuery.RowLimit = 2000
$caml = '<Where><Lt><FieldRef Name="Created" /><Value IncludeTimeValue="TRUE" Type="DateTime">2014-01-01T04:06:45Z</Value></Lt></Where> '
$spQuery.Query = $caml
do
{
$listItems = $list.GetItems($spQuery)
$spQuery.ListItemCollectionPosition = $listItems.ListItemCollectionPosition
$listTotal = $listItems.Count
for ($x=$listTotal-1;$x -ge 0; $x--)
{
try
{
$listItems[$x].CopyTo("http://sharepoint/Docs/Documents/"+ $listItems[$x].name)
Write-Host("DELETED: " + $listItems[$x].name)
$listItems[$x].Recycle()
}
catch
{
Write-Host $_.Exception.ToString()
}
}
}
while ($spQuery.ListItemCollectionPosition -ne $null)
via Ian

Powershell to list all pages with their layout across the rootweb and all subwebs?

I need to be able to create a report of all existing pages and their page layout.
I have the following powershell script but even using Recursive its only returning me the ones from the root web.
filter Get-PublishingPages {
$pubweb = [Microsoft.SharePoint.Publishing.PublishingWeb]::GetPublishingWeb($_)
$query = new-object Microsoft.SharePoint.SPQuery
$query.ViewAttributes = "Scope='Recursive'"
$pubweb.GetPublishingPages($query)
}
$url="https://xxxxl.com"
get-spweb $url | Get-PublishingPages | select Uri, Title, #{Name='PageLayout';Expression={$_.Layout.ServerRelativeUrl}}
This worked for me.
filter Get-PublishingPages {
$pubweb = [Microsoft.SharePoint.Publishing.PublishingWeb]::GetPublishingWeb($_)
$query = new-object Microsoft.SharePoint.SPQuery
$query.ViewAttributes = "Scope='Recursive'"
$pubweb.GetPublishingPages($query)
}
$str = "http://yourdomain.com" // your URL
if($str -eq $null )
{
Write-Host “Enter a valid URL”
return
}
$site = Get-SPSite -Identity $str
if($site -eq $null)
{
Write-Host “Enter a valid URL”
return
}
$allweb = $site.Allwebs
foreach($web in $allweb )
{
$web | Get-PublishingPages | select Uri, Title, #{Name=’PageLayout’;Expression={$_.Layout.ServerRelativeUrl}}| Format-List
}
Bit of a shot in the dark here, but have you tried setting the scope to RecursiveAll instead of just Recursive? My understanding was that Recursive only hit all files in a folder while RecursiveAll gets all subfolders as well.
Reference: http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.spviewscope.aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-1

How to update SharePoint enterprise keywords with multiple values using powershell?

I'm trying to write a powershell script that looks at a user defined variable and updates the enterprise keywords for each item in a list that matches that value.
For instance, say you have a page in SP that has the managed metadata keywords: new, fresh, clean
I want a script that asks a user what keyword they want to swap out. So a user would specify a variable as: fresh and another variable as: fresher and it would update any item with the keyword fresh to fresher.
Here's what I 've used before but doesn't work now because there are mutliple values:
Add-PSSnapin Microsoft.SharePoint.PowerShell -EA SilentlyContinue
$webURL = <MY SP URL>
$listName = <MY LIST NAME>
$web = Get-SPWeb $webURL
$list = $web.Lists[$listName]
$listitems = $list.items
$session = Get-SPTaxonomySession -Site $web.Site
$termStore = $session.TermStores["Managed Metadata Service"]
$group = $termStore.Groups["Resources"]
$termset = $group.TermSets["Wiki Categories"]
$terms = $termSet.GetTerms(100)
$wiki1 = read-host "Enter the wiki category you want to update"
$wiki2 = read-host "Enter the replacement wiki category"
$term = $terms | ?{$_.name -eq $wiki2}
Foreach($item in $listitems)
{$wiki = $item["Wiki Categories"]
if($wiki.label -eq $term)
{
$spitem = [Microsoft.SharePoint.SPListItem]$item;
$taxfield = [Microsoft.SharePoint.Taxonomy.TaxonomyField]$spitem.Fields["Wiki Categories"]
$taxfield.SetFieldValue($spitem, $term)
$spitem.Update()
$spitem.File.Publish("True")
}
}
I'm pretty sure the issue is with this line:
$term = $terms | ?{$_.name -eq $wiki2}
And this line:
$taxfield.SetFieldValue($spitem, $term)
The problem is that you passing a TermCollection ($term) to SetFieldValue where you should pass in a TaxonomyFieldValueCollection.
You can convert them like this:
$taxfield = $spitem.Fields["Wiki Categories"]
$tfvc = new-object -typename Microsoft.SharePoint.Taxonomy.TaxonomyFieldValueCollection -argumentlist $taxfield;
foreach($t in $ term)
{
$tfv = new-object -typename Microsoft.SharePoint.Taxonomy.TaxonomyFieldValue -argumentlist $taxfield
$tfv.TermGuid = $t.Id
$tfv.Label = $t.Name
$tfvc.Add($tfv)
}
...
$taxfield.SetFieldValue($spitem, $tfvc)

Resources