SharePoint 2013 | Approve a list item | PowerShell

From here: https://sharepoint-learners.blogspot.com/2016/09/sharepoint-2013-approve-list-item.html

Work Statement: Approve all the list items
 
$site = new-object Microsoft.SharePoint.SPSite("http://site")
$web = $site.OpenWeb()
$list = $web.Lists["Posts"]
$items = $list.Items

foreach ($item in $items)
{
    $item["_ModerationStatus"] = 0
    $item.Update()
}



Work Statement: You want to approve a single list item

$site = new-object Microsoft.SharePoint.SPSite("http://site")
$web = $site.OpenWeb()
$list = $web.Lists["Posts"]
$items = $list.GetItemById(10)
$item["_ModerationStatus"] = 0

$item.Update()


The following are more ModertionStatus:

ValueDescription
0 The list item is approved.
1 The list item has been denied approval.
2 The list item is pending approval.
3 The list item is in the draft or checked out state.
4 The list item is scheduled for automatic approval at a future date.

Add Column to Default View Using PowerShell

Recently I had a request from a client to add a custom site collection column to all document libraries. This is pretty easy though the SharePoint UI of course, by creating a custom Site Column in the collection and adding it to the ‘Document’ content type.

However, in doing this the column is not added to the default view for any document libraries. This can be easily done using PowerShell using the script below. This adds the column to the default view in every document library throughout the entire site collection (referenced here).

$site = Get-SPSite “http://sharepoint.com”
$column = “Column”

$site | Get-SPWeb -limit all | ForEach-Object {

# Get all document libraries
$lists = $_.Lists | where  {$_.BaseType -eq “DocumentLibrary”}

# Loop libraries
for ($i = 0; $i -lt $lists.Count; $i++)
{

try
{

# Get current view
$view = $lists[$i].DefaultView

if($view)
{

# Delete if already exist
while($view.ViewFields.ToStringCollection().Contains($column))
{

$view.ViewFields.delete($column)
$view.Update()

}

# Add column
if(!$view.ViewFields.ToStringCollection().Contains($column))
{

$view.ViewFields.add($column)
$view.Update()

}

}

}
catch [Exception]
{

write-output (”  Error: ” + $_.Exception.ToString())

}

}

}

$site.Dispose()

You can also add views to a view by URL and view name for one specific view or list (a nice tip I found here). Here is another option by using GetViewFromUrl:

$spWeb = Get-SPWeb -Identity "http://mySharePoint"
$spView = $spWeb.GetViewFromUrl("/Lists/MyList/AllItems.aspx")
$spField = $spList.Fields["MyField"]
$spView.ViewFields.Add($spField)
$spView.Update()

You can also try to use SPList object as below:

$spList = Get-SPList -Url "http://mySharePoint/Lists/MyList"
$spView = $spList.Views["All Items"]
$spField = $spList.Fields["MyField"]
$spView.ViewFields.Add($spField)
$spView.Update()

Adding multiple columns to a view can also be done with PowerShell, and even create a new view and set it as the default view. This is really awesome if you want to leave the default ‘All Items’ view in tact, but create a new custom view and set it as default (found here):

Add-PSSnapin Microsoft.SharePoint.PowerShell -erroraction SilentlyContinue
$siteURL = "http://dev1share"
 $site = Get-SPSite($siteURL)
foreach($web in $site.AllWebs) {
$listCounter = $web.Lists.Count
 for($i=0;$i -le $listCounter;$i++) {
    $list = $web.Lists[$i]
     if($list.BaseType -eq "DocumentLibrary") {
     $newList = $web.Lists.item($list.ID);
  $viewfields = New-Object System.Collections.Specialized.StringCollection
   $viewfields.Add("DocIcon")
   $viewfields.Add("LinkFilename")
   $viewfields.Add("_UIVersionString")
   $viewfields.Add("Modified")
   $viewfields.Add("Created")
   $viewfields.Add("Editor")
   $viewfields.Add("FileSizeDisplay")
  [void]$newList.Views.Add("Detailed", $viewfields, "", 100, $true, $true)
   $newList.Update();
  $view=$newList.Views["Detailed"]
   $view.DefaultView = $true
   $view.Update()
 }
 }
$web.Dispose();
 }
 $site.Dispose();

 

SharePoint PowerShell Create View Based on Existing View

The following PowerShell script crawls the specified lists, copies the fields from the All Items views and creates a new view named "Created By Me" and sets it as default. Tested with SharePoint 2010 but should work with 2013 as well. Tested with list but not with Document Libraries.

I used this script as a base.

$ver = $host | select version

if ($ver.Version.Major -gt 1) {$host.Runspace.ThreadOptions = "ReuseThread"} 

if ((Get-PSSnapin "Microsoft.SharePoint.PowerShell" -ErrorAction SilentlyContinue) -eq $null) 

{

 Add-PSSnapin "Microsoft.SharePoint.PowerShell"

}

 

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint") 

 

$web = Get-SPWeb -Identity "http://portal/sites/Requests"

$lists=$web.Lists["User Request", "Hardware Request",  "Employee Request"]

$SourceView="All Items"

$NewViewName="Created By Me"

$NewViewDefault=$true

 

 

foreach($list in $lists) {

 

 $view = $list.Views[$SourceView]

 $Viewfields = $list.Views[$SourceView].ViewFields.ToStringCollection()

 $viewRowLimit="100"

 $viewPaged=$true

 $viewDefaultView=$NewViewDefault

 

# Setting the Query for the View

 $viewQuery = "<ORDERBY><FIELDREF name="" false="" ascending=""></FIELDREF></ORDERBY><WHERE><EQ><FIELDREF author="" name=""><VALUE type="" integer=""><USERID type="" integer=""></USERID></VALUE></FIELDREF></EQ></WHERE>"

 $viewName = $NewViewName

 

# Finally – Provisioning the View

 $myListView = $list.Views.Add($viewName, $viewFields, $viewQuery, 100, $True, $False, "HTML", $False)

 

# You need to Update the View for changes made to the view

# Updating the List is not enough

 $myListView.DefaultView = $True

 $myListView.Update()

 $list.Update()

}

$web.Dispose()

How to determine what version of PowerShell is installed

Use $PSVersionTable.PSVersion to determine the engine version. If the variable does not exist, it is safe to assume the engine is version 1.0.

Note that $Host.Version and (Get-Host).Version are not reliable - they reflect the version of the host only, not the engine. PowerGUI, PowerShellPLUS, etc. are all hosting applications, and they will set the host's version to reflect their product version, which is entirely correct.

PowerShell Backup from Local folder to FTP location

Here is a script that I wrote for backing up some very important files to an off-site ftp location. It backs up only files that are new OR have changed in the last 24 hours. That number of days could be a parameter based on when the backup last ran, however this is the base code that you can start using right away. Just add it to a Task Schedule that runs one a day.


# ==============================================================================================
#Set the Date/Time
# ==============================================================================================
$BackUpdateTime  = (Get-Date).Year.ToString()
$BackUpdateTime += (Get-Date).Month.ToString()
$BackUpdateTime += (Get-Date).Day.ToString()
$BackUpdateTime += (Get-Date).Hour.ToString()
$BackUpdateTime += (Get-Date).Minute.ToString()
$BackUpdateTime += (Get-Date).Second.ToString()
$today = (Get-Date -Format yyyy-MM-dd)

try {
 $ftp = "ftp://ftp.mysite.ca/"
 $user = "ftpuser"
 $pass = "ftppassword" 
 
 $webclient = New-Object System.Net.WebClient
 $webclient.Credentials = New-Object System.Net.NetworkCredential($user,$pass) 

 #we specify the directory where all files that we want to upload 
 $Dir="Y:\LocalDirectory\"
 $LogFile="I:\PowerShell\MyBackup_"+$today+".txt"
 Clear-Host
 #Write-Host $LogFile
 "From:"+$Dir+" (on server01) To:"+$ftp | Out-File $LogFile -Append
 "Start: "+(Get-Date) | Out-File $LogFile -Append

 $files = @(Get-ChildItem -Path  $Dir -Recurse | ?{ !$_.PSIsContainer } |Where-Object { $_.lastwritetime -gt (get-date).AddDays(-1)} | Select-Object -ExpandProperty FullName )
 foreach($item in $files)
 {
     if($item -ne $null)
  {
   $uri = New-Object System.Uri($ftp+$item.Substring(3))
   $webclient.UploadFile($uri, $item)
   #Write-Host (Get-Date)$item
   "$(Get-Date): "+$item | Out-File $LogFile -Append
  }
 }
 $webclient.Dispose()

 "End:"+(Get-Date) | Out-File $LogFile -Append
 
 $msg = new-object Net.Mail.MailMessage
 
 # Edit the From Address as per your environment. 
 $msg.From = "Backup (server01) <my.email@mysite.ca>"

 # Edit the mail address to which the Notification should be sent. 
 $msg.To.Add("my.email@mysite.ca")

 # Subject for the notification email. The + “$today” part will add the date in the subject. 
 $msg.Subject = "Backup was Successful for " + "$today"

 # Body or the notification email. The + “$today” part will add the date in the subject. 
 $msg.Body = "Backup was Successful for " + $today + "`r`n`r`n" 
 
 $att = new-object Net.Mail.Attachment($LogFile)
 $msg.Attachments.Add($att)
 
 # IP address of your SMTP server.
 $smtpServer = "smtp.mysite.ca" 
 $smtp = new-object Net.Mail.SmtpClient($smtpServer) 

 $smtp.Send($msg)
 $msg.Dispose()
}
Catch { 
 $ErrorMessage = $_.Exception.Message 

 # Configure the below parameters as per the above. 
 $msg = new-object Net.Mail.MailMessage
 $msg.From = "Backup (server01) <my.email@mysite.ca>" 
 $msg.To.Add("my.email@mysite.ca") 
 $msg.Subject = "Backup Job failed on " + "$today" 
 $msg.Body = "Job failed on " + "$today and the reason for failure was $ErrorMessage." 
 
 $att = new-object Net.Mail.Attachment($LogFile)
 $msg.Attachments.Add($att)
 
 $smtpServer = "smtp.mysite.ca" 
 $smtp = new-object Net.Mail.SmtpClient($smtpServer) 
 
 $smtp.Send($msg)
 $msg.Dispose()
}

File Locked After Sending via Email with Powershell

The files that you attach to an email become locked until the instance of Powershell you are running has exited completely. So if you run a script through Powershell ISE that attaches a file to an email, that file will remain locked until you exit Powershell ISE.

If the file is locked by Powershell, you will get an error/warning message similar to the following if you try to modify it in any way;

The process cannot access the file 'c:\filename.txt' because it is being used by another process

By using the following command, you can ensure that Powershell 'disposes' of the email message once it has been sent and does not continue to 'lock' any files you attach and send via email;

$mailmessage.dispose()

Note: this is assuming that $MailMessage = New-Object system.net.mail.mailmessage

PowerShell 2.0 Adding Columns to Document Libries in a Site Collection.

Adding Columns to a SharePoint List across an entire Site Collection should be done like this using PowerShell (with Power GUI):
 
Note that the use of the following works with all the defaults... 
$fieldDateTime = [Microsoft.SharePoint.SPFieldType]::DateTime
$list.Fields.Add("Compliance Date",$fieldDateTime,$false) 

However, you get MORE Control over Field Attributes using this method:
$fldXml = "<Field Type='DateTime' DisplayName='Report Sign Off Date' Format='DateOnly' Name='Report Sign Off Date'/>"     
$list.Fields.AddFieldAsXml($fldXml) 
 
Both methods are used in the code block below. 
if ((Get-PSSnapin | ? { $_.Name -eq "Microsoft.SharePoint.PowerShell" }) -eq $null) {
    Add-PSSnapin Microsoft.SharePoint.PowerShell
}
[Microsoft.SharePoint.SPSecurity]::RunWithElevatedPrivileges( 
{
 $site =  Get-SPSite -Identity "https://mysite.com/sites/thissite"
 Write-Host "Script Started"
 [array]$ListNames = "ListA", "ListB"
 $NumberofReportsinRecordFound = $false
 $ReportSignOffDateFound = $false
 $ComplianceDateFound = $false
 foreach($web in $site.AllWebs)
 {
  #Get number if Lists rather than using foreach as we will be modifying the List
  
  for($i=0; $i -lt $web.Lists.Count; $i++)
  {
   $list = $web.Lists[$i]
   if($list.BaseType -eq "DocumentLibrary" -and $list.BaseTemplate -notmatch "Catalog")
   {
    Write-Host $web.Title
    Write-Host $list
        
    $NumberofReportsinRecordFound = $false
    $ReportSignOffDateFound = $false
    $ComplianceDateFound = $false
      
    if($ListNames -contains $list.Title)
    {
     for($j=0; $j -lt $list.Fields.Count; $j++)
     {
      $field = $list.Fields[$j]
      if($field.Title -like "*do not use*")
      {
          Write-Host "do not use deleted!"
       $list.Fields.Delete($field)
       $list.Update() 
      }
      
      if($field.Title -like "Number of Reports in Record")
      {
       $NumberofReportsinRecordFound = $true
      }
      if($field.Title -like "Report Sign Off Date")
      {
       $ReportSignOffDateFound = $true
      }
      
      if($field.Title -like "Compliance Date")
      {
       $ComplianceDateFound = $true
      }
     }
        $fieldNumber = [Microsoft.SharePoint.SPFieldType]::Number

     if(!$NumberofReportsinRecordFound){
      $list.Fields.Add("Number of Reports in Record",$fieldNumber,$false)
      $fld = $list.Fields["Number of Reports in Record"]
     }
     
     if(!$ReportSignOffDateFound){
      $fldXml = "<Field Type='DateTime' DisplayName='Report Sign Off Date' Format='DateOnly' Name='Report Sign Off Date'/>"
      $list.Fields.AddFieldAsXml($fldXml)
     }
     
     if(!$ComplianceDateFound){
      $fldXml = "<Field Type='DateTime' DisplayName='Compliance Date' Format='DateOnly' Name='Compliance Date'/>"
      $list.Fields.AddFieldAsXml($fldXml)
     }
     $list.Description = "Inspection Reports"
     $list.Update()
    }
   }
  }
 }
 $web.Dispose()
 $site.Dispose()
 Write-Output "Script Ended"
}
)