Setting, Saving & Restoring Logging Level for SharePoint using PowerShell

Background Information:

We want to have a script that will automate the configuration of the SharePoint ULS log by configuring the diagnostic logging with PowerShell. Assume you have a problem in production, you may wish to change the logging level of all logging categories to verbose for a short period of time to allow you to capture as much information about the problem as possible. The downside of this approach however, is that increasing the amount of information captured obviously increases the disk space taken by the logs. It is therefore crucial for you to be able to easily bring the level of information captured down after the “monitoring” window is over. I am a strong believer that most of the time, setting your log levels to Error will be enough to give you a good indicator of where important issues are within your environments.

To achieve this, we will be creating a PowerShell script that will simply prompt the user to enter the name of a logging level, and will then go and set all logging categories in the SharePoint farm to that level. I believe this script is something every SharePoint admin should keep handy in their back pockets.

PowerShell Methods:

In order for us to be able to change the logging level of a SharePoint farm, PowerShell provides us with the Set-SPLogLevel. This PowerShell cmdlet accepts the –TraceSeverity parameter which specifies the logging level to set for the SharePoint farm. SharePoint also makes available the Clear-SPLogLevel PowerShell cmdlet to restore all logging categories to their default value (Information level). Using the Set-SPLogLevel cmdlet, the possible values for the trace severity level are:

  • None
  • ErrorCritical
  • Error
  • Warning
  • Information
  • Verbose

With this in mind, we can go ahead and create the following (extremely basic you’ll say) PowerShell script:

$level = Read-Host “Log Level (None, ErrorCritical, Error, Warning, Information, or Verbose)”

Set-SPLogLevel –Eventseverity $level

So these two lines of script will allow us to do just what we want, and will set the logging level for all the farm. But what if you had set special logging levels for specific categories? For example, your organization may have decided to set the User Profile Category to log all the “Verbose” information received, but left all other categories to “High”. How do you go about remembering these special configurations? Remember that the Clear-SPLogLevel simply puts all categories back to the “Information” level.

What we need is to add logic in our script so that it loops through all the current configuration, before changing it, saves it somewhere, and allow us to restore it later on. In order for us to be able to get a listing of what the current settings for the logging level, we need to make a call to the Get-SPLogLevel PowerShell cmdlet. Calling this cmdlet will return a full list of all logging categories along with their current logging level (see Figure below).

20140428-1.png

We will now be developing a new PowerShell function that will strictly be taking care of saving the information about the various logging categories and their associated logging level into a structured format that we could reuse later on to restore values to what they were. We will be saving the logging information in a text file under the C:\Temp\ folder. Make sure you modify this value to point to wherever you wish to have your file saved. The resulting text file will contain one line of text per logging category. Each line will start with the category’s area, the name of the category, the trace severity level, and the event severity level, all separated by a pipe character (|). The following PowerShell lines will declare such a function:

$newLine = “`r`n”

Function SaveCurrentLoggingSettings($path)

{             

                $content = “”

                $logSettings = Get-SPLogLevel

                foreach($setting in $logSettings)

                {

                                $content += $setting.Area.ToString() + “|” + $setting.Name.ToString() + “|” + $setting.TraceSev.ToString() + “|” + $setting.EventSev.ToString() + $newLine

                }

 

                if((Test-Path $path) -eq $false)

                {

                                New-Item $path -Type File -Force

                }

 

                $content | Out-File -FilePath $path

}

 

SaveCurrentLoggingSettings(“C:\temp\nik.txt”)

20140428-2.png

 

Now the second part is to write a function that will do the opposite, and read values out of that file and set the logging levels back to the values contained in it. The following PowerShell lines will read the content of the file, loop through each line one at a time, split them on the ‘|’ character, and then set their values back into your SharePoint Farm.

$newLine = “`r`n”

 

Function RestoreLoggingLevelsFromFile($path)

{

                $content = Get-Content $path

                $lines = $content.Split($newLine)

                foreach($line in $lines)

                {

                                if($line -ne “”)

                                {

                                                $segment = $line.Split(‘|’)

                                                Write-Host “Setting Levels on [“$segment[1]”] T=”$segment[2]”E=”$segment[3]

                                                Set-SPLogLevel -EventSeverity $segment[3] -TraceSeverity $segment[2] -Identity ($segment[0] + “:” + $segment[1])​

                                }

                }

}

RestoreLoggingLevelsFromFile(“C:\temp\nik.txt”)

20140428-3.png

Putting it All Together:

Now that we’ve managed to write a function to save the current logging configuration, and another to restore values from it, we can combine both and produce a single PowerShell script. For this tutorial, the script we will produce will do the following operations in sequence:

  1. Save the current Logging levels on disk at c:\Temp\nik.txt
  2. Set the logging level of all categories to “Error”
  3. Wait for the user to confirm a rollback
  4. Upon confirm rollback from user, will restore all values from file;

Here’s what the resulting script will look like:

$newLine = “`r`n”

 

Function RestoreLoggingLevelsFromFile($path)

{

                $content = Get-Content $path

                $lines = $content.Split($newLine)

                foreach($line in $lines)

                {

                                if($line -ne “”)

                                {

                                                $segment = $line.Split(‘|’)

                                                Write-Host “Setting Levels on [“$segment[1]”] T=”$segment[2]”E=”$segment[3]

                                                Set-SPLogLevel -EventSeverity $segment[3] -TraceSeverity $segment[2]

                                }

                }

}

Function SaveCurrentLoggingSettings($path)

{             

                $content = “”

                $logSettings = Get-SPLogLevel

                foreach($setting in $logSettings)

                {

                                $content += $setting.Area.ToString() + “|” + $setting.Name.ToString() + “|” + $setting.TraceSev.ToString() + “|” + $setting.EventSev.ToString() + $newLine

                }

 

                if((Test-Path $path) -eq $false)

                {

                                New-Item $path -Type File -Force

                }

 

                $content | Out-File -FilePath $path

}

 

SaveCurrentLoggingSettings(“C:\temp\nik.txt”)

Set-SPLogLevel –EventSeverity “Error”

Read-Host “Enter any key to restore configuration values”

RestoreLoggingLevelsFromFile(“C:\temp\nik.txt”)

20140428-4.png

Web Spider using PowerShell

Background Information:

I have a need to simulate traffic after hours on one of our SharePoint sites to investigate a performance issues where the w3wp.exe process crashes after a few hours of activity. I have decided to develop a PowerShell script to mimic a user access various pages on the site and clicking on any links they find. This PowerShell script should prompt the user for their credentials, for the URL of the start site they wish to crawl, for the maximum number of links the script should visit before aborting, and last but none the least, the maximum level of pages in the architecture the crawler should visit. The script should log pages that have been visited and ensure we don’t visit the same page more than once.

Script’s Logic:

My PowerShell script will start by making a request to the root site, based on the URL the user provided. Using the Invoke-WebRequest PowerShell cmdlet, I will retrieve the page’s HTML content and store it in a variable. Then, I will search through that content for anchor tags containing links (“<a> tags with the href property). Using a combination of string methods, I will retrieve the URL of every link on the main page, and will call a recursive method that will repeat the same “link-retrieval” process on each link retrieved for the main page.

The script will need to have a try/catch block to ensure no errors are thrown back to the user in the case where URLs retrieved from links are invalid (e.g. “#”, “javascript:”, etc). The script will also account for relative URLs, meaning that if a URL retrieved from a page’s content starts with ‘/’, the domain name of the parent page will be used to form an absolute link. Finally, my script will display some level of execution status out to the PowerShell console; for every link crawled, it will display a new line containing information about the total number of links visited so far, the hierarchical level of the link (compared to the parent site), and the URL being visited. Figures below show the execution of the script on my personal blog. For simplicity’s sake, I have hardcoded the value in the top section of my script.

 

20140429-1.png

20140429-2.png

Script’s Content:

As mentionned above, in my case, I have hardcoded the values of the parameters instead of prompting the user to enter them manually. The following script will crawl my blog (http://nikcharlebois.com) for a maximum total of 200 links, and won’t crawl pages that are more than 3 levels deeper that my blog’s home page. Enjoy!

$creds = Get-Credential
$url = “http://www.nikcharlebois.com”
$Script:maxLinks = 200
$Script:maxLevels = 3
$Script:numberLinks = 0
$Script:linksVisited = @()
Function CrawlLink($site, $level)
{
Try
{
$request = Invoke-WebRequest $site -Credential $creds
$content = $request.Content
$domain = ($site.Replace(“http://”,””).Replace(“https://”,””)).Split(‘/’)[0]
$start = 0
$end = 0
$start = $content.IndexOf(“<a “, $end)
while($start -ge 0)
{
if($start -ge 0)
{
# Get the position of of the beginning of the link. The +6 is to go past the href=”
$start = $content.IndexOf(“href=”, $start) + 6
if($start -ge 6)
{
$end = $content.IndexOf(“”””, $start)
$end2 = $content.IndexOf(“‘”, $start)
if($end2 -lt $end -and $end2 -ne -1)
{
$end = $end2
}
if($end -ge $start)
{
$link = $content.Substring($start, $end – $start)
# Handle case where link is relative
if($link.StartsWith(“/”))
{
$link = $site.Split(‘/’)[0] + “//” + $domain + $link
}
if($Script:numberLinks -le $Script:maxLinks -and $level -le $Script:maxLevels)
{
if(($Script:linksVisited -notcontains $link) -and $link.StartsWith(“http:”))
{
$Script:numberLinks++
Write-Host $Script:numberLinks”[“$level”] – “$link -BackgroundColor Blue -ForegroundColor White
$Script:linksVisited += $link
CrawlLink $link ([int]($level+1))
}
}
}
}
}
$start = $content.IndexOf(“<a “, $end)
}
}
Catch [system.exception]
{
}
}
CrawlLink $url 0

Chat Module using PowerShell

Background Information:

Since PowerShell is built on top of the .NET framework, it is possible for us to reuse all of its classes and objects. Now, those of you who know me, know I’m a developer at heart. I’ve always been a developer, and probably always will be. When I first started learnicq-my-icon.pnging the .NET platform back in 2003, one of the first project I did on my own was to create a chat application using a C# console app. Not sure if you remember, but chats used to be the big thing before Facebook and text messages took over 🙂 Anyway, I decided to give myself a challenge and see if I could recreate such a chat module using strictly PowerShell scripts.​

How does it work?:

In every “server-client chat engine you need at least two main components: a server instance, that will act as a dispatcher for messages received, and a client instance that will connect to the chat server and will post messages. For the purpose of this excercise will will be using the TCPListener .NET object to represent the server instance, and the TCPClient .NET object for the client one.

Server Instance:

To instantiate the server instance, we need to declare a new TCPListener object on the server, and specify a port on which it will be listening for incoming connections. In our case, our TCPListener will be listening on port 777. To tell the TCPListener object to start listening and accepting incoming connection, we need to call its Start() method. This method will put our PowerShell script in an idle state until a connection is received. For the sake of keeping things simple, our demo will only accept a single connection, meaning only one client will be allow to connect to our server at any given time. Once a connection has been established with a client, the server instance will obtain a reference to the communication channel (stream) with the client and will await for incoming messages. Because we want to server to be continuouosly listening for incoming messages, we will be using an infinite loop while($true). Everytime a message is received from the client, the message will be printed on screen using yellow text. The following PowerShell code will be used for generating the server instance:

function Listen()
{
$endpoint = new-object System.Net.IPEndPoint([system.net.ipaddress]::any, 777)
$listener = new-object System.Net.Sockets.TcpListener $endpoint
$listener.Start()
$client = $listener.AcceptTcpClient()

Write-Host “Client”$client.Client.RemoteEndPoint.Address”connected” -BackgroundColor Green

   [System.IO.StreamReader]$stream = new-object System.IO.StreamReader -argumentList $client.GetStream()

    while($true)
{
$line = $stream.ReadLine()
if($line -ne $null)
{
Write-Host $line -ForegroundColor Yellow
}
}
$listener.Stop()
}
Listen 

Client Instance:

The  client instance will simply take care of connecting to the remote server (in our case we connect to the localhost because everything runs on the same box), and once the connection has been established, will send and “Hello There!” message to the remote server instance. To connect remotely, we will call the Connect() method on the TCPClient object, passing it the IP address of the server, and the port on which we wish to establish the connection (it needs to be the same port the server is listening on). The following PowerShell code will be used to generate the Client instance:

function Connect()
{
$client = New-Object System.Net.Sockets.TcpClient
$client.Connect(“localhost”,777)

     $stream = new-object System.IO.StreamWriter $client.GetStream()
$stream.WriteLine(“Hello there!”)
$stream.Flush();
$client.Close()
}
Connect

Putting it Together:

For this demo, we will be running both the client and server instance on the same local machine, however, to differentiate each instance, we will configure the server session to have a Teal background with white text, and the client instance to have a pink background with black text.

Server:

20140427-1.png

Client:

20140427-2.png

Then, we need to initiate the server instance, and have it wait for incoming connections:

20140427-3.png

Next, we initiate the Client instance, which will connect to the remote server and automatically send a message:

20140427-4.png

20140427-5.png

Enjoy!

Retrieving a List of Event Receivers using PowerShell

Background Information:20140425-1.png

We wish to get a list of all event receivers associated with a specific list in our SharePoint environment using a PowerShell Script. Event receivers in the context of SharePoint are similar to what triggers are to SQL Server. They are blocks of logic that execute automatically in response to a specific event. In our case, these events are generated at the list level (new item added, item modified, item deleted, etc.). We want our PowerShell script to prompt the user to input the name of the list we wish to analyze, as well as the URL of the Web containing that list. In return, the script will loop through all event receivers associated with the specified list and will print the full list on the PowerShell console.

Event Receivers in the SharePoint Object Model:

In the SharePoint Object Model, you can access the list of associated Event Receivers to an object by calling the .EventReceivers property of a SharePoint artefact. This property will return a SPEventReceiverDefinitionCollection object that contains all event receivers definitions associated with the artefact. To get more information about the various receivers, our script will iterate through that collection and will retrieve information about the name of each Event Receiver, as well as the event they are associated with (ItemAdding, ItemUpdated, etc). Each SPEventReceiverDefinition object exposes a property named “Type” that tells us what event the receiver is associated with, as well as a Name property that lists the name given to each receiver.

Script:

The following PowerShell script will prompt the user to input the URL of a SharePoint Web and the name of a SharePoint list or library, and will print a report listing all Event Receivers associated with it.

# Prompts the user for parameters;

$webURL = Read-Host “URL of the Web”

$listName = Read-Host “Name of the list/library”

 

# Get a reference to the SharePoint web;

$web = Get-SPWeb $webURL

 

# Get a reference to the SharePoint list or library;

$list = $web.Lists[$listName]

 

foreach($eventReceiverDef in $list.EventReceivers)

{

    if($eventReceiverDef.Name -ne “”)

    {

                    $eventInfo = $eventReceiverDef.Name + ” – ” + $eventReceiverDef.Type

                    Write-Host $eventInfo -BackgroundColor Green -ForegroundColor Black

    }

}

 

$web.Dispose()

20140426-2.png

If you wish to remove an instance of an EventReceiverDefinition, simply get a reference to it, and call the Delete() method on it.

Interacting with Deleted SharePoint Artefacts using PowerShell

Background Information:

Since the introduction of Service Pack 1 for SharePoint 2010, Microsoft has made it possible for users to retrieve a deleted SharePoint Web or a Site Collection from the recycle bin. If a user goes and deletes a Web or a Site Collection from the SharePoint Interface, the web will be sent to the recycle bin for a period of 30 days, after which it will be disposed of automatically.  With this first Service Pack, Microsoft introduced a new Object to the SharePoint model called SPDeletedWeb or SPWebDeletedSite. This new object represents a deleted Web, and has a limited set of methods and properties available for it. As part of this Service Pack were also a few new PowerShell cmdlets that allow us to interact with these “half-alive” artefacts, allowing us to restore them to their former glory, or to send them out into the abyss forever.

20140425-2.png

The following list of PowerShell cmdlets were introduced as part of Service Pack 1 for SharePoint 2010:

  • Remove-SPDeletedWeb
  • Remove-SPDeletedSite
  • Get-SPDeletedWeb
  • Get-SPDeletedSite
  • Restore-SPDeletedWeb
  • Restore-SPDeletedSite

Now, something very important to take a good note of: You can only ever restore a Web or a Site Collection that was deleted through the web interface. If you used PowerShell (Remove-SPWeb or Remove-SPSite) to delete them, they are G-O-N-E, and there is no way for you to restore them but to use your backups.

Getting a Reference to a Deleted Web or Site Collection:

Using the Get-SPDeletedWeb or the Get-SPDeletedSite Powershell cmdlets, you can get a reference to a deleted web or site collection in your environment. Remember, this only works if you have SharePoint 2010 Service Pack 1 or higher (any flavour of SharePoint 2013 works). The way you’d normally go about restoring a deleted artefact is by specifying its URL. For example, if in my environment I have all my “secondary” Site Collections created under the “/sites/[…]” managed path, then I could retrieve a list of all my deleted Site Collections by calling the following PowerShell command:

Get-SPDeletedSite “/sites/*”

This command will return a collection of SPDeletedSite objects.

20140425.png

Restoring a Deleted Web or Site Collection:

Assuming you have a web or a site collection that has been deleted through the web interface, meaning that is it now a SPDeletedWeb or a SPDeletedSite object. To restore it using PowerShell you need to use the Restore-SPDeletedSite or the Restore-SPDeletedWeb cmdlet and pass it the URL of the object to restore, or a reference to it obtained by the Get-SPDeletedSite or Get-SPDeletedWeb cmdlet. The following Powershell command will restore the HR Site Collection

Restore-SPDeletedSite /sites/HR

20140425-3.png

Removing a Deleted Web or Site Collection:

Removing a deleted Site Collection or Web from the Recycle bin will delete it permanently from the SharePoint environment. This can be achieved by using the Remove-SPDeletedSite or the Remove-SPDeletedWeb PowerShell cmdlets. Just like for the restore operation, you can either pass it the URL of the deleted artefact or a reference to it. The following example will permanently delete the HR site collecton, which had been deleted through the Central Administration web interface.

Remove-SPDeletedSite /sites/hr

20140425-4.png