My Talk at the Montréal .NET User Group

Yesterday I was in Montréal, which is about a 2 hours and a half drive from my place. I was down in “La belle province” to give a talk to the Montréal .NET User group (in French) on how PowerShell is an invaluable tool for every developer to have in their back pocket. The talk lasted for over an hour and a half, and there was a lot of very interesting questions and discussions surrounding the topic I was presenting on.  In my session I was explaining to the audience how you can build custom reusable modules for PowerShell, leveraging their coding skills. I gave demos of how to create new PowerShell cmdlets using Visual Studio, as well as demos on how to create your own reusable Function that acts just like a normal cmdlet would do.

One of the demo I gave was a custom function I had built and that was simulating a sports event between the Montreal Canadians (hockey team), and another random team in the national hockey league. The function was generating a random score and printing the result back on the screen. Here is an excerpt from my code:

Function Get-SimulatedGameScore
{
 [CmdletBinding()]
   param
   (
      [Parameter(Mandatory=$True,
  ValueFromPipeline=$True,
      ValueFromPipelineByPropertyName=$True,
        HelpMessage=’Name of the home team’)]
      [ValidateLength(3,30)]
      [string]$homeTeam,

  [Parameter(Mandatory=$True,  
  ValueFromPipeline=$True,
      ValueFromPipelineByPropertyName=$True,
        HelpMessage=’Name of the visitor team’)]
  [Alias(‘Visitor’)]
      [ValidateLength(3,30)]  
      [string]$visitorTeam
   )
 begin{ Write-Host “Sending off Maggie the Monkey” }
 process{
  Do
  {
   $homeScore = Get-Random -min 0 -max 9
   $visitorScore = Get-Random -min 0 -max 9
  }While($homeScore -eq $visitorScore)

  if($homeScore -gt $visitorScore)
  {
   Write-Host “$homeTeam – $homeScore” -BackgroundColor Green -ForegroundColor Black
   Write-Host “$visitorTeam – $visitorScore” -BackgroundColor Red -ForegroundColor Black
  }
  else
  {
   Write-Host “$homeTeam – $homeScore” -BackgroundColor Red -ForegroundColor Black
   Write-Host “$visitorTeam – $visitorScore” -BackgroundColor Green -ForegroundColor Black
  }
 }
}

Get-Random “Lightning”, “Red Wings”, “Capitals”, “Sharks”, “Bruins”, “Canucks”, “Flames” | Get-SimulatedGameScore -Visitor “Canadiens”

 
 

My Presentation:

http://www.slideshare.net/nikcharlebois/powershell-mtldev-2015

All About PowerShell Versions

​As you guys know, SharePoint 2010 requires PowerShell 2.0 in order to leverage the Microsoft.SharePoint.PowerShell snap in. For most of us, working with recent versions of Windows Server such as Windows Server 2012 R2 with Update 1, PowerShell version 4.0 is the default version installed which causes conflicts with SharePoint 2010. Now if you wish to determine what version of PowerShell you have installed, you can use the following little trick. PowerShell includes a built-in variable named $PSVersionTable which contains information about the current version of the product that’s loaded in the shell. The following example was executed on my development server which has Windows Server 2012 R2 with Update 1 and the Windows Management Framework (WMF 5.0) February 2015 installed.


We can clearly see from that listing that my environment supports PowerShell Common Language Runtime (CLR) 1.0, 2.0,3.0, as well as 4.0 (based on the PSCompatibleVersions Property. This means that we should be able to tell our Powershell session to change the current CLR down to any of these versions. This can be achieved by calling the following line of PowerShell code:

PowerShell -Version xx


After executing the line above in your PowerShell session, the CLR will now be set to whatever version you asked for. It is important to note however that the CLR’s are based on the version .NET versions, and that they require the associated .NET version to be installed on your machine. For example, on my dev machine, I only have .NET 4.5 installed. If I try to set the PowerShell CLR to version 2.0, PowerShell will give me an error, letting me know I need to download and install the .NET 2.0 Framework. The error is shown below (Version v2.0.50727 of the .NET Framework is not installed and it is required to run version 2.0 of PowerShell).


In the case, simply go to the Microsoft Download Centre, download and install the bits to make this error go away and you’ll be able to downgrade the CLR to version 2.0 no problem.

Master PowerShell Script to Check Changes in SharePoint

As I explained in multiple blog posts in the past, every second tuesday of the month, whenever Microsoft releases their SharePoint 2013 Cumulative Updates, I go ahead and install them on my dev environments. The first thing I do afterward is run a custom PowerShell script I have developped myself, get information about the various PowerShell cmdlets, and Object Model properties exposed by my environment, and compare that list with the list from the previous month. Then, using a comparison tool such as WinMerge, I check for the difference between what was available in the previous month compared to what is now available after applying the new Cumulative Update. Today I decided to share my script with you guys in order for you to better understand how I go about determining if Microsoft introduced any new goodies with their update packages. The following script is what I run on my local server every month after installing the latest SharePoint 2013 Cumulative Update:

Add-PSSnapin Microsoft.SharePoint.PowerShell

$fileContent = “—- PowerShell Cmdlets —-`r`n”

$powerShellCmdlets = Get-Command | Where{$_.ModuleName -eq “Microsoft.SharePoint.PowerShell”}

foreach($cmdlet in $powerShellCmdlets)
{
$fileContent += $cmdlet.Name + “`r`n”

}

$fileContent += “`r`n—- SPFarm —-`r`n”

$farm = Get-SPFarm

$members = $farm | Get-Member 

foreach($member in $members){
$fileContent += $member.Name + “`r`n” 

}

$fileContent += “`r`n—- SPWebApplication —-`r`n”

$webApp = Get-SPWebApplication

$members = $webApp | Get-Member

foreach($member in $members)

$fileContent += $member.Name + “`r`n” 

}

$fileContent += “`r`n—- SPSite —-`r`n”

$site = Get-SPSite http://localhost

$members = $site | Get-Member

foreach($member in $members){

$fileContent += $member.Name + “`r`n”
}
$fileContent += “`r`n—- SPWeb —-`r`n”
$web = Get-SPWeb http://localhost
$members = $web | Get-Member

foreach($member in $members)
{
$fileContent+= $member.Name + “`r`n”
}

$fileContent += “`r`n—- SPList —-`r`n”

$lists = $web.Lists

$list = $lists[2]

$members = $list | Get-Member

foreach($member in $members)
{
$fileContent += $member.Name + “`r`n”
}

$fileContent += “`r`n—- SPView —-`r`n”

$views = $list.Views

$view = $views[0]

$members = $view | Get-Member

foreach($member in $members){
$fileContent += $member.Name + “`r`n”

}

$fileContent += “`r`n—- SPListItem —-`r`n”

$items = $list.Items

$item = $items[0]

$members = $item | Get-Member

foreach($member in $members)

{
$fileContent += $member.Name +“`r`n”
}

$fileContent += “`r`n—- SPContentDatabase —-`r`n”

$contentDB = Get-SPContentDatabase

$members = $contentDB | Get-Member

foreach($member in $members){
$fileContent += $member.Name + “`r`n” 

}

$fileContent += “`r`n—- SPServiceApplication —-`r`n”

$service = Get-SPServiceApplication

$members = $service[0] | Get-Member

foreach($member in $members){
$fileContent += $member.Name + “`r`n”
}

$fileContent | Out-File “C:\CU\Current.txt”

What my script does is the following:

  •  Get a full list of all PowerShell cmdlets contained in the Microsoft.SharePoint.PowerShell module;
  • Get all properties and methods on the following objects based on the SharePoint Object Model:
    • SPFarm
    • SPWebApplication
    • SPSite
    • SPWeb
    • SPList
    • SPListItem
    • SPView
    • SPServiceApplication
    • SPContentDatabase

Then it writes the resulting list in a text file on disk, in my case under c:\CU\Current.txt.

All Lights on SharePoint ULS Logs with PowerShell

This morning I decided to play a bit with the various PowerShell cmdlets that are available in SharePoint 2013 and that allow users to interact with the ULS logs. This blog post aims at providing an explaination of each of the cmdlets, and give concrete examples as to when you could potential use them in real world scenarios. The first thing I did in order to obtain the full list of PowerShell cmdlets that were available to me and that were related to the ULS files was to execute the following line of PowerShell:

Get-Command | Where{$_.ModuleName -eq “Microsoft.SharePoint.PowerShell” -and $_.Name -like ‘*LogFile*’}

20150418-01.png

So 3 cmdlets in total: Merge-SPLogFile, New-SPLogFile, and New-SPUsageLogFile. Their names are pretty self explanatory, but still, let us examine the two first cmdlets.

Merge-SPLogFile:

If you ever played with PowerShell for SharePoint, then this cmdlet ought to be one of the very first one you’ve ever used. This cmdlet let you merge log files from all SharePoint servers contained within your farm into a single file. This is extremely useful, preventing the users from having to go on every single server in the farm and try to determine which one contains the error matching a specific Correlation Id. Let us assume that we have a SharePoint farm with 3 Web-Front ends, and 2 application servers. Upon navigating to a site within the SharePoint environment, the user gets an error page exhibiting the following Correlation ID: b681d542-bde8-45e6-8c6a-3953d8a4aa82. In order to scan all 5 SharePoint servers at once to determine what server has a log file containing the error with that Correlation ID, one could simply execute the following line of PowerShell:

Merge-SPLogFile -Path C:\temp\nik.txt -Correlation b681d542-bde8-45e6-8c6a-3953d8a4aa82

20150418-02.png

It may take a few seconds for the operation to complete. Once completed, a file will have been created at c:\temp\nik.txt and will contain information about the error we are investigating.

20150418-03.png

Now, to prevent you from having to go back and manually retrieve the file that has just been created, we could modify the script a little:

$path = “C:\temp\nik.txt”

Merge-SPLogFile -Path $path -Correlation b681d542-bde8-45e6-8c6a-3953d8a4aa82

Get-Content $path

20150418-04.png

Another very interesting operation we can do with the Merge-SPLogFile cmdlet is to merge information out of all log files based on Severity Level. For example, we can merge all entries that have a severity level of Unexpected by using the following line of PowerShell:

Merge-SPLogFile -Path c:\Temp\nik.txt -Level Unexpected

20150418-05.png

New-SPLogFile:

This cmdlet is very straight forward. Calling it simply creates a new log file. Normally, within SharePoint, ULS log files are created after a predefined time span (default is 30 minutes). Log files are normally split into several small ULS log files. By default, these files are kept for 14 days.

20150418-06.png

This cmdlet is normally called without any parameters. Calling it will automatically create an new log file and the tracing process will use that new file to flush future log entries.

New-SPLogFile

20150418-07.png

Monitoring IIS with PowerShell

While this article doesn’t apply directly for SharePoint admins, it is targeting any users who are in charge of maintaining an IIS server and who wish to use PowerShell to monitor their servers. The processed associated with the various application pools defined in IIS ​are called “w3wp”. For the scope of this example, we will show you how you can use PowerShell to monitor the CPU usage for these w3wp processes on a given server.

Let us start off by looking at what is available to us in terms of PowerShell cmdlets to obtain information about a specific process. The Get-Process cmdlet returns a full list of all processes currently running on a server. The figure below shows the execution of this cmdlet on my local server:

20150417-01.png

We can see from the screen above that I have 3 w3wp processes listed. Let us now use a select statement on that list of processes to obtain a reference only to these 3 processes. The line of PowerShell code required to achieve this will look like the following:

Get-Process | Where{$_.ProcessName -eq “w3wp”}

Executing this line of PowerShell will return a result similar to the following:

20150417-02.png

Now what we need to do is to declare a custom expression in order to allow us to obtain the CPU % used by each of our processes. By default, the Process object returned by the Get-Process cmdlet doesn’t expose a CPU percentage property. Therefore we have to declare it manually. This can be done with the following lines of PowerShell:

$CPU = @{
Name = ‘CPU ‘
Expression = {
$TotalSec = (New-TimeSpan -Start $_.StartTime).TotalSeconds
[Math]::Round( ($_.CPU * 100 / $TotalSec), 2)
}
}

With the above declaration, we are defining a new variable named $CPU, that represents total % of CPU consume by a specific process. This percentage value is obtained by calculating the time spent since the process was first initiated, and dividing it by the CPU load. I know you guys are probably already lost by now, so let’s dig into a step by step explanation. The first line of the Expression is the following:

$TotalSec = (New-TimeSpan -Start $_.StartTime).TotalSeconds

Let us start by dissecting this command into two major parts. The first one being the $_.StartTime portion. In our context the operator $_ represents the current process. So let’s execute the following lines of Powershell and see their expected outcome, where $processes[0] represents the first w3wp process out of the three:

$processes  = Get-Process | Where{$_.ProcessName -eq “w3wp”}

$processes[0].StartTime

20150417-03.png

* es my server is in french “Avril” is French for “April”

This gives us the time at which the process was first started. then the second part of the script simply returns the number of seconds that went by since the process was first started (in our case 11:28:56) up until now. Executing the entire line returns the following:

(New-TimeSpan -Start $processes[0].StartTime).TotalSeconds

20150417-04.png

Let us now move on to the second line of the Expression declaration. In summary, what this line does is round up (using 2 decimal digits) the result of the total time in second our process used CPU and divides it by the overall time spent running the process in seconds. The result should give us an average of how much CPU load our process has been using on the server.

 

Now that we understand a bit more how to obtain the current CPU % of a process, let us look at what the complete script will look like:

$CPU = @{
Name = ‘CPU ‘
Expression = {
$TotalSec = (New-TimeSpan -Start $_.StartTime).TotalSeconds
[Math]::Round( ($_.CPU * 100 / $TotalSec), 2)
}
}

$processes  = Get-Process | Where{$_.ProcessName -eq “w3wp”}

foreach($process in $processes)

{

$process | SELECT Name, $CPU

}

20150417-05.png