Monday, January 25, 2016

Find Process Identifier (PID) for Application Pool

Developers and system administrators must know to find out the correct PID associated with application pool if multiple web sites are running different app pools on the same server. PID is more important when Administrator troubleshoots an issue/worker process or developers debug the code by attaching the correct W3WP process with visual studio.

There are four common methods available to find out the Process Identifier for application pool.
1. Using IIS user interface
2. Using Command prompt
3. Using Task manager
4. Using Process Viewer


Method 1: Using IIS User Interface


1. Open IIS
2. Select Server from Connection Tree
3. Select Features Tab
4. Double click on Worker Process available under IIS section
5. Find the application pool name and Process identifiers in tabular view


Method 2: Using Command Prompt

iisapp.vbs script needs to be used to retrieve the correct PID from IIS6 and Windows 2003 server. Find the details in below snapshot.

C:\Windows\System32>script iisapp.vbs

Command “appcmd” need to be used on IIS7 or above and Windows 2008 server or above to retrieve the correct PID details from server. The “appcmd” command had to be executed by passing additional parameters “list” and “wps”. Find the details in below snapshot.


Go to c:\Windows\system32\inetsrv>appcmd list wps

Method 3: Using Command Prompt
1. Open Task Manager
2. Go to Process Tab
3. Go to View menu and client on Select columns
4. Add PID(Process Identifier) and Command line
5. Click OK
6. Find the PID and application pool details in the updated view




Thursday, January 14, 2016

Activate Web (subsite) scoped feature in all existing sites and subsites using PowerShell


We ware asked to enable a new rule that site/sub site cannot be deleted if any document declared as record. Of course I have added  new web deleting event receiver and used a web scoped feature to register the event on web.

But we have more than 100000 sub sites in our SharePoint farm. And enabling web scoped feature for all existing sites became a risk and performance hit.

I had created two scripts to resolve this issue. 1. PS script to collect all site collection from a web application and store it in a XML file. 2. PS script will read the XML file and process the site collection one by one as we got a provision to pass number site to be processed at one time. It reduced the performance hit and trace issue if any feature failed to activate

PowerShell script to Fetch All Site Collection:

# This script to generate XML file which contains all site collections in web application

# .\1_GetsiteCollections.ps1 -url "http://kmsnet:5500/" 



param
(
[string]$url   # Web application URL

)

If ((Get-PSSnapIn -Name Microsoft.SharePoint.PowerShell -ErrorAction Stop) -eq $null )  
{ Add-PSSnapIn -Name Microsoft.SharePoint.PowerShell } 

#Start-Transcript
if($url)
{

[string]$filepath = $(get-location).Path;
# XML file generation code 
$ErrorActionPreference = "SilentlyContinue"
#$ErrorActionPreference = "Stop"

# Create a new XML File with config root node
[System.XML.XMLDocument]$oXMLDocument=New-Object System.XML.XMLDocument

# New Node
[System.XML.XMLElement]$oXMLRoot=$oXMLDocument.CreateElement("SiteCollection")
# Append as child to an existing node
$oXMLDocument.appendChild($oXMLRoot)
    $site = get-spsite $url
    $WebApp = $site.webapplication 
    $Count =0;
    try
    {
   foreach ($spsite in $WebApp.sites) 
   {
            [System.XML.XMLElement]$oXMLSystem=$oXMLRoot.appendChild($oXMLDocument.CreateElement("site"))
            $Count +=1;
       $oXMLSystem.SetAttribute("Count",$($Count))
       $oXMLSystem.SetAttribute("URL",$($spsite.Url))
            $oXMLSystem.SetAttribute("GUID",$($spsite.ID))
            $oXMLSystem.SetAttribute("Status","New")
                        
        }
        
        $xmlPath=$filepath + "\SiteCollXML";
        New-Item -force -ItemType directory -Path $xmlPath;
        $Filename = $filepath + "\SiteCollXML\SiteURL.xml"
        $oXMLDocument.Save($Filename )
        Write-host " Site collection file is generated : " $Filename
        
    }
     catch
    {
       # $Error; 
        $ErrorMessage = $_.Exception.Message
        write-host $ErrorMessage 


        $FailedItem = $_.Exception.ItemName
        write-host $FailedItem 
        
    }

}
else
{
Write-host "Please provide the Web Application Url...!!!" -foregroundcolor "Yellow"
}

PowerShell Script to process each site collection.

# .\2_EnableWebScopedFeature.ps1 -count 5 -Enable Y -FeatureId "12f73b57-1db8-4272-9d95-d8c1cc9f3d41"

param
(
    
    [int]$count =$(throw "Count is mandatory, please provide a value."), # No. of site collections to be processed
    [string]$Enable =$(throw "Pass y/Y to Activate the feature else pass n/N to deactivate the deature"),
    [string]$FeatureId =$(throw "Pass feature Id")
    
 )



Start-Transcript

If ((Get-PSSnapIn -Name Microsoft.SharePoint.PowerShell -ErrorAction Stop) -eq $null )  
{ Add-PSSnapIn -Name Microsoft.SharePoint.PowerShell } 

write-host "Successfully added SharePoint PowerShell snapins"

#$ErrorActionPreference = "Stop"
$ErrorActionPreference = "SilentlyContinue"
$curDir=$(get-location).Path;
$LogTime = Get-Date -Format yyyy-MM-dd_h-mm  
$LogFile = $curDir + "\Logs1-$LogTime.txt"  
$DocIDFile = $curDir + "\Log2-$LogTime.txt"  
write-host "Log file Location : " $LogFile


$filePath = $curDir + "\SiteCollXML\SiteURL.xml"

#write-host "source XMl file Path is $filePath "
write-host " Doc Id file " $DocIDFile 


$SiteCollectionsXML = [xml](gc $filePath)
try
{
    write-host "$count number of site collection requested to process";
    $currentcount = 0
    $DocIDcount = 0

$SiteCollectionsXML = [xml](gc $filePath)
$newItems=$SiteCollectionsXML.SiteCollection.site | where { $_.Status -eq "New"} 
    $node="";
    foreach ($sColl in $newItems)
  {
      if ([int]$currentcount -lt $count)
            {
        write-host "Start: Site Collection ";
        
        try
        {
        $currentcount = $currentcount + 1
         $node = $SiteCollectionsXML.SiteCollection.site | where {$_.GUID -eq $sColl.GUID}   
        $node.Status = "New"
        $objsite = Get-SPSite $sColl.URL;
        if($Enable -eq "Y" -and $Enable -eq "y")
        {
        $objsite | Get-SPWeb -limit all | ForEach-Object {Enable-SPFeature -Identity $FeatureId -Url $_.Url -Confirm:$false -ErrorAction:SilentlyContinue -Force}
        $node.Status = "Feature Activated"
        }
        
        if($Enable -eq "N" -and $Enable -eq "n")
        {
        $objsite | Get-SPWeb -limit all | ForEach-Object {Disable-SPFeature -Identity $FeatureId -Url $_.Url -Force -Confirm:$false -ErrorAction:SilentlyContinue}
        $node.Status = "Feature Dectivated"
        }
        
        $objsite.Dispose();
        
              
        
         
        }
        catch
        {
        $ex = $_.Exception 
        $node.Status = "Failed to Activate: $ex.Message" 
        Write-Error "Error on $siteURL details: $ex.Message" 
continue 
        
        }
        finally
        {
        $objsite.Dispose();
        $SiteCollectionsXML.Save($filePath);
        }
        
          }
    }
        $SiteCollectionsXML.Save($filePath)
}
catch
{
       
    $ErrorMessage = $_.Exception.Message
    write-host $ErrorMessage 

    $FailedItem = $_.Exception.ItemName
    write-host $FailedItem 
       
    $node = $SiteCollectionsXML.SiteCollection.site | where {$_.GUID -eq $Guid}
    $node.Status = "Error"

    Add-Content -path $LogFile -value ("`n" + "Site URL : " + ($SiteCollectionUrl)  + ' Site GUID : ' + ($Guid) + ' Error: ' + ($ErrorMessage) )

    $SiteCollections.Save($filePath)

}

Stop-Transcript

XML Output

<SiteCollection>
  <site Count="1" URL="http://kmsnet:5500" GUID="870c5dbb-c1b8-417a-89b3-c428369b7e45" Status="Feature Activated" />
  <site Count="2" URL="http://kmsnet:5500/SC1/" GUID="888b3fd3-48a1-41c5-b1c9-bd5b9102b29f" Status="Feature Activated" />
  <site Count="3" URL="http://kmsnet:5500/SC2" GUID="9f6f0d3b-1e02-42e0-8fbd-070b298576dc" Status="Feature Activated" />

</SiteCollection>