Sharepoint Web Config Modification Using PowerShell


Below is an example of how to add a web configuration modification in SharePoint Using PowerShell.  The script has a pience of function to add the Location configuration for timeout as well as a function that allows you to delete the modication done by the user.  Rew points to consider when you want to write that code.

Owner: Every configuration is tagged with the owner and can be retreived using the propertly.  Be careful in making different web config entries as if you set a single Owner all the configuration can get cleaned up.

$configMod.Name = “add[@name=""location""]” : Define the Name of entry you did in value.
$configMod.Path = “/configuration” : Define the place you want to add the entry.  You can extended it with /Configuration/SharePoint/SafeControls/
$configMod.Value = “<location path=’_vti_bin/sitedata.asmx’></location> : Actual Full String.  use Double (Double Quotes “”) to cover string and make sure you are using the right double quotes “” by pasting the script in notepad or PowerShell ISE.

Write-Host "===============================================" -ForegroundColor Yellow
Write-Host "Adding Timout Value to SharePoint Web.Config" -ForegroundColor Yellow
Write-Host "===============================================" -ForegroundColor Yellow

Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue

function RemoveMyEntries($webapp, $Owner)
{
   $oldMods = @();
   $webapp.WebConfigModifications | where-object { $_.Owner -eq $Owner } | foreach-object { $oldMods = $oldMods + $_}
   Write-Host $oldMods.Count "Items Found"
   $oldMods | foreach-object { $webapp.WebConfigModifications.Remove($_) }
   
   #$webapp.Update()
   #$webapp.Parent.ApplyWebConfigModifications()
}

$Owner = "Jerry"
$WebApp = Get-SPWebApplication http://portal.hp.com

Write-Host $WebApp
#Write-Host "Removing All Entries Made by $Owner"
RemoveMyEntries $WebApp $Owner 
sleep -Seconds 10
#Write-Host "Removed All Entries Made by $Owner"

Write-Host "Creating New Entry"
$configMod = New-Object Microsoft.SharePoint.Administration.SPWebConfigModification
$configMod.Name = "add[@name=""location""]"
$configMod.Path = “/configuration”
$configMod.Value = "<location path='_vti_bin/sitedata.asmx'><system.web><httpRuntime executionTimeout='3600'/></system.web></location>"
$configMod.Sequence = 0
$configMod.Type = 0 #for enum value of SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode
$configMod.Owner = $Owner
$WebApp.WebConfigModifications.Add($configMod)
$WebApp.Update()
$WebApp.Parent.ApplyWebConfigModifications()
Write-Host "Web Application Entry has been added. Wait for a couple of minutes and then test it out" -ForegroundColor Green

Creating extended Search topology in Sharepoint 2013


If you are creating a Search service application in SharePoint 2013 and want to create an extedned search topology, the only choice you have is “PowerShell”.  Althought the process looks bit complex but if you spent few minutes in the PowerShell script below it will become very simply.

Below script uses a 9 server Search Toplogy where we have the following configuration

  • 3 Query Processing Components
  • 3 Index Partitions and their Replicas
  • 2 Admin Components
  • 2 Crawl Components
  • 2 Analytic Components
  • 2 Content Processing Components

You can see that we have redundant search components.  with this topology we were planning to cover 30 content sources with over 40 Million items in in the index.

First on the root define the Servers and mention their role.  I used an Excel sheet first then moved them in Powershell

Note: If you are extending an existing which already has index.  it is good to RESET Index.  Additonally you can pause the Search Service Applicaton and then resume it after new topology.

$hostA = Get-SPEnterpriseSearchServiceInstance -Identity “SERVER135" #Query Processing -  Index 0
$hostB = Get-SPEnterpriseSearchServiceInstance -Identity "SERVER136" #Query Processing -  Index 1
$hostC = Get-SPEnterpriseSearchServiceInstance -Identity "SERVER137" #Query Processing -  Index 2

$hostD = Get-SPEnterpriseSearchServiceInstance -Identity “SERVER138" #Analytics Processing - Index 2 (Replica)
$hostE = Get-SPEnterpriseSearchServiceInstance -Identity “SERVER139” #Analytics Processing - Index 1 (Replica)
$hostF = Get-SPEnterpriseSearchServiceInstance -Identity “SERVER140" #Index 0 (Replica)

$hostG = Get-SPEnterpriseSearchServiceInstance -Identity “SERVER141" #Content Processing - Crawl Component
$hostH = Get-SPEnterpriseSearchServiceInstance -Identity “SERVER142" #Content Processing - Crawl Component

Next Step is to Start the Enterprise Search Service Instance on these servers

Start-SPEnterpriseSearchServiceInstance -Identity $hostA
Start-SPEnterpriseSearchServiceInstance -Identity $hostB
Start-SPEnterpriseSearchServiceInstance -Identity $hostC
Start-SPEnterpriseSearchServiceInstance -Identity $hostD
Start-SPEnterpriseSearchServiceInstance -Identity $hostE
Start-SPEnterpriseSearchServiceInstance -Identity $hostF
Start-SPEnterpriseSearchServiceInstance -Identity $hostG
Start-SPEnterpriseSearchServiceInstance -Identity $hostH

Now wait for all services to be provisioned.  You can check the status using the script below

//Wait until status of “OnLine” by issuing the following commands:

Get-SPEnterpriseSearchServiceInstance -Identity $hostA | Select Server, Status
Get-SPEnterpriseSearchServiceInstance -Identity $hostB | Select Server, Status
Get-SPEnterpriseSearchServiceInstance -Identity $hostC | Select Server, Status
Get-SPEnterpriseSearchServiceInstance -Identity $hostD | Select Server, Status
Get-SPEnterpriseSearchServiceInstance -Identity $hostE | Select Server, Status
Get-SPEnterpriseSearchServiceInstance -Identity $hostF | Select Server, Status
Get-SPEnterpriseSearchServiceInstance -Identity $hostG | Select Server, Status
Get-SPEnterpriseSearchServiceInstance -Identity $hostH | Select Server, Status

Now Next Step is to Get the Search Service Application and Create a new Search Topology.  To reuse existing topology you can clone it.

$ssa = Get-SPEnterpriseSearchServiceApplication
$newTopology  = New-SPEnterpriseSearchTopology -SearchApplication $ssa

Next Step would be to Create the Components.  Below i am creating by the hosts for easier managment.

Host A

New-SPEnterpriseSearchQueryProcessingComponent -SearchTopology $newTopology -SearchServiceInstance $hostA
New-SPEnterpriseSearchIndexComponent -SearchTopology $newTopology -SearchServiceInstance $hostA -IndexPartition 0

Host B

New-SPEnterpriseSearchQueryProcessingComponent -SearchTopology $newTopology -SearchServiceInstance $hostB
New-SPEnterpriseSearchIndexComponent -SearchTopology $newTopology -SearchServiceInstance $hostB -IndexPartition 1

Host C

New-SPEnterpriseSearchQueryProcessingComponent -SearchTopology $newTopology -SearchServiceInstance $hostC
New-SPEnterpriseSearchIndexComponent -SearchTopology $newTopology -SearchServiceInstance $hostC -IndexPartition 2

Host D

New-SPEnterpriseSearchAnalyticsProcessingComponent -SearchTopology $newTopology -SearchServiceInstance $hostD
New-SPEnterpriseSearchIndexComponent -SearchTopology $newTopology -SearchServiceInstance $hostD -IndexPartition 2

Host E

New-SPEnterpriseSearchAnalyticsProcessingComponent -SearchTopology $newTopology -SearchServiceInstance $hostE
New-SPEnterpriseSearchIndexComponent -SearchTopology $newTopology -SearchServiceInstance $hostE -IndexPartition 1

Host F

New-SPEnterpriseSearchIndexComponent -SearchTopology $newTopology -SearchServiceInstance $hostF -IndexPartition 0
New-SPEnterpriseSearchAdminComponent -SearchTopology $newTopology -SearchServiceInstance $hostF

Host G

New-SPEnterpriseSearchCrawlComponent -SearchTopology $newTopology -SearchServiceInstance $hostG
New-SPEnterpriseSearchContentProcessingComponent -SearchTopology $newTopology -SearchServiceInstance $hostG

Host H

New-SPEnterpriseSearchCrawlComponent -SearchTopology $newTopology -SearchServiceInstance $hostH
New-SPEnterpriseSearchContentProcessingComponent -SearchTopology $newTopology -SearchServiceInstance $hostH

Now Set the topology as Active Topolgy

Set-SPEnterpriseSearchTopology -Identity $newTopology
iisreset 
Get-SPEnterpriseSearchTopology -SearchApplication $ssa

Remove the Old Toplogy

#Removing Old Topology Get-SPEnterpriseSearchTopology -SearchApplication $ssa #Note the ID of the old toplogy $OldTopology = Get-SPEnterpriseSearchTopology -SearchApplication $ssa -Identity 64e1b2ba-bfc6-44d4-9ebe-9f9b5952bdd0 #To Verify $OldTopology Remove-SPEnterpriseSearchTopology -Identity $OldTopology.Id -SearchApplication $ssa

#You are all Set now Open Central Administration –> Manage Service Applications –> Search #Service Application –> Review the components and all should show
#Green check mark. Refresh the browse if they take time to get green

Exporting SharePoint document using powershell


Few months back I found this PowerShell script and extended it to support a site collection.

$ver = $host | select version 
if($Ver.version.major -gt 1) {$Host.Runspace.ThreadOptions = "ReuseThread"} 
if(!(Get-PSSnapin Microsoft.SharePoint.PowerShell -ea 0)) 
{ 
Add-PSSnapin Microsoft.SharePoint.PowerShell  -ErrorAction SilentlyContinue
} 


$Directory = "c:\ExportFiles\" 
 
## 
#Define Functions 
## 
 
Function TrimDirectory ($Directory) 
{ 
    if($Directory.EndsWith("\")) 
    { 
        Set-Variable -Name Directory -Value ($Directory.Substring(0, ($Directory.Length -1))) -Scope Script 
    } 
} 
 
Function EnsureDirectory ($Directory) 
{ 
    if(!(Test-Path $Directory)) 
    { 
        TrimDirectory $Directory 
                 
        New-Item -Path $Directory -ItemType Directory 
    } 
} 
 
Function ExportFiles ($SPList, $GalleryName) 
{ 
    EnsureDirectory ($Directory + "\" + $GalleryName) 
    Write-Host $SPlist.rootfolder.files.count
    foreach ($file in $SPlist.rootfolder.files) 
    { 
         
        $DestinationFile = ($Directory + "\$GalleryName\" + $file.name) 
        $FileBinary = $file.OpenBinary() 
        $FileStream = New-Object System.IO.FileStream($DestinationFile), Create 
        $Writer = New-Object System.IO.BinaryWriter($FileStream) 
        $Writer.write($FileBinary) 
        $Writer.close() 
    } 
     
    foreach($Folder in $SPList.Folders) 
    { 
         
        if($ParentFolderURL) 
        { 
            Remove-Variable ParentFolderURL 
        } 
     
        $i = 0 
     
        $folderURL = $Folder.url.split("/") 
     
        while($I -lt ($FolderURL.count -1)) 
        { 
            $ParentFolderURL = "$ParentFolderURL/" + $FolderURL[$I] 
            $I++ 
        } 
         
        $DownloadDirectory = ($Directory + "\$GalleryName\" + $Folder.url.substring($SPList.RootFolder.Url.Length)) -replace "/", "\" 
         
        EnsureDirectory $DownloadDirectory 
         
        foreach ($File in $Folder.Folder.Files) 
        { 
            $DestinationFile = ($Directory + "\$GalleryName\" + $Folder.url.Substring($SPList.Rootfolder.URL.Length) + "\" + $file.name) -replace "/", "\" 
             
            $FileBinary = $file.OpenBinary() 
 
            $FileStream = New-Object System.IO.FileStream($DestinationFile), Create 
 
            $Writer = New-Object System.IO.BinaryWriter($FileStream) 
 
            $Writer.write($FileBinary) 
 
            $Writer.close() 
        } 
         
         
    } 
} 
 
 
## 
#Start Script 
## 
 
 
TrimDirectory $Directory 
EnsureDirectory $Directory 

Start-SPAssignment -Global

$SiteURL = "http://intranet.hp.com"
$Site = Get-SPSite $SiteURL

foreach($Web in $Site.AllWebs)
{

    foreach($List in $Web.Lists)
    {
        if(!$List.Hidden)
        {
            $Title = $List.Title
            Write-Host $Title
            $ListFolder = New-Item -Path ($Directory + "\$Title") -ItemType Directory -ErrorAction SilentlyContinue
            ExportFiles $List $Title.ToString()
        }
    }
}

Stop-SPAssignment -Global

#New-Item -Path ($Directory + "\Documents") -ItemType Directory 
#$Documents = $Site.RootWeb.Lists | ? {$_.title -eq "Documents"} 
#ExportFiles $Documents "Documents" 

Powershell – current folder and file


While working with PowerShell some times if is required to access resources like XML and csv files from local folder where the PS1 file is placed.  PowerShell 3.0 has made it easy for us.  Use the script below to get current folder, file and execution path

$thisfolderIncludingFileName = Split-Path -parent $MyInvocation.MyCommand.Definition
$currentScriptName = $MyInvocation.MyCommand.Name

$currentExecutionPath = $thisfolderIncludingFileName.Replace($currentScriptName, "");

Write-Host "Current Folder with FileName : $thisfolder"
Write-Host "Current File Name : $currentScriptName"
Write-Host "Current Exeuction Path $currentExecutionPath"

image

Note: I have find out that you must save your script file before you can test these calls and you can not get this path when you press F8 to execute any script line by line.

collecting and merging uls logs


During Troubleshooting and specially working with Microsoft Support team we have to collect logs from all servers in the farm and send it to them.  The issue is that these logs will have more information than what we have with out issue.  So there is the best option.

  1. Create a File
  2. Enable Verbose Ex or Verbose Logging
  3. Reproduce the issue
  4. Disable Verbose Ex or Verbose Logging
  5. Merge the Log Files

Luckily the script below will do that. 

Note: The output file will grow very large in case the issue has multiple steps for repduction + VerboseEx logging produce lot of extra information.  Change the verbose if you are not looking for EX.

save the below script as Ps1 and you are ready.

#Title: ULS Collector
#Description: This script will collect the ULS logs by way of merging them from every server.

#Add SharePoint Snapin
Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue

#Set file location
$path = Read-Host "Please enter the full path for the log file along with the file name";

#Increase logging to verbose
Write-Host "Increasing ULS logging to VerboseEx...";
Set-SPLogLevel -TraceSeverity VerboseEx -EventSeverity Verbose;

#Prompting to start and setting the start time
Read-Host "Hit enter to start, then reproduce the issue"
$starttime = Get-Date -Format "MM/dd/yyyy HH:mm:ss"
Write-Host "The start time for the log file is $starttime";

#Prompting to stop and setting the end time
Read-Host "Hit enter to end"
$endtime = Get-Date -Format "MM/dd/yyyy HH:mm:ss"
Write-Host "The ending time for the log file is $endtime";

#Setting the log level back to normal
Clear-SPLogLevel

#Merging the logs to the specified path using the start and end times
Merge-SPLogFile -Path $path -Overwrite -StartTime $starttime -EndTime $endtime;
Write-Host "Logs have been collected. Resetting the log level back to normal."

New-SPLogFile

copy Service pack and cu files in multiple server


To copy large files to SharePoint servers can be pain ful e.g. if  you are on monthly patch mode or have large farms.  below script can automated that.

# robocopy.exe source destination /mirror
$Servers = @("ServerA", "ServerB", "ServerC")
foreach($Server in $Servers)
{
    $Location = "\\$Server\e$\Binaries\SP2013SP1"
    Write-Host $Location
    Robocopy.exe E:\Binaries\SP2013SP1\ $Location /MIR 

}

##### OR ######

$Servers = Get-SPServer | ? { $_.Role -eq "Application" -or $_.Role -eq "WebFrontEnd"}
foreach($Server in $Servers)
{
    $Location = "\\$Server\e$\Binaries\SP2013SP1"
    Write-Host $Location
    Robocopy.exe E:\Binaries\SP2013SP1\ $Location /MIR 

}

Spdiagnosticssession, merge-sploG AND ulSVIEWER


If you facing an issue in SharePoint environment and you are trying to get the ULS logs you can use the below method to get the log efficiently.  Althought the process can be done from UI but it takes more effort.

# Use the Start-SPDiagnosticsSession cmdlet to report diagnostic information to the usage database. # After a diagnostic session starts, all Windows PowerShell for SharePoint cmdlets in Windows PowerShell scripts # will use the same correlation to report diagnostic information.

$correlationId = [guid]::NewGuid() Start-SPDiagnosticsSession -CorrelationId $correlationId -Dashboard:$true -TraceLevel Verbose

Now you can reproduce your scanario or error so that the logs are generated.  Now you can close the Diagnostic sessions.

#Run the below Line Stop the Diagnostic Session
Stop-SPDiagnosticsSession
Get-Content e:\data\SharePoint\Logs\*.log | select-string $correlationId | clip
Get-Content e:\data\SharePoint\Logs\*.log | select-string $correlationId | Diag.txt 

#Get-Content *.log | select-string $correlationId
Get-Content e:\data\SharePoint\Logs\*.log | select-string $correlationId 

You can also use Merge-SPlogFile to collect the logs into a single file.

Merge-SPLogFile -Correlation $correlationId -Path "E:\Data\MergedLogs\MergeedLog.log" -Overwrite

Now you can open ULS Viewer directly for this file.

image

.\ulsviewer.exe -filename E:\Data\MergedLogs\MergeedLog.log

image