Apr 122019

System.Security.Claims.ClaimsIdentity is the .Net class that helps management of a claims based user identity using which you can add claims to a .Net application for more granular user control based on the user claims provided by the issuer in your application.

MSDN Link to class documentation:

For example…
1. switch the UI to a different view if role of user logged in is the company CEO.
2. switch site theme based on users favorite color.
3. switch site locale based on user country or show a customized greeting.
4. restrict access to site based on user age.
5. etc…

Here is a short script to assign claims to the current thread principal and verify user claims using PowerShell.

# Add assembly for displaying message box
Add-Type –AssemblyName System.Windows.Forms

# Claims
$claims = New-Object System.Collections.Generic.List[System.Security.Claims.Claim]

# Add claims to claims list
$claims.Add(((New-Object System.Security.Claims.Claim([System.Security.Claims.ClaimTypes]::Email, "nibu.bt@gmail.com"))))
$claims.Add(((New-Object System.Security.Claims.Claim("WebSite", "http://ntcoder.com"))))
$claims.Add(((New-Object System.Security.Claims.Claim("Primary Skill", "C++"))))
$claims.Add(((New-Object System.Security.Claims.Claim([System.Security.Claims.ClaimTypes]::Country, "India"))))
$claims.Add(((New-Object System.Security.Claims.Claim([System.Security.Claims.ClaimTypes]::Role, "CEO"))))

# Instantiate claims identity object
$cid = New-Object System.Security.Claims.ClaimsIdentity($claims, "Password")

# Assign principal
[System.Threading.Thread]::CurrentPrincipal =  New-Object System.Security.Claims.ClaimsPrincipal($cid)

Write-Host "Current Thread Principal: " -NoNewline
[System.Threading.Thread]::CurrentPrincipal | Select-Object -ExpandProperty Claims | Select-Object Issuer, Type, value | Format-Table -AutoSize

# Write authentication status
Write-Host "Authenticated: $($cid.IsAuthenticated)"

$tp = [System.Threading.Thread]::CurrentPrincipal

# Check if user is CEO, if yes then display a messagebox, check above role that we added 
    $null = [System.Windows.Forms.MessageBox]::Show("Welcome CEO, opening CEO view...", "User", [System.Windows.Forms.MessageBoxButtons]::OK,[System.Windows.Forms.MessageBoxIcon]::Information)

# Check country of user, if India then display an Indian greeting message.
if($tp.HasClaim([System.Security.Claims.ClaimTypes]::Country, "India"))
    $null = [System.Windows.Forms.MessageBox]::Show("Namaskar!", "Greetings!", [System.Windows.Forms.MessageBoxButtons]::OK,[System.Windows.Forms.MessageBoxIcon]::Information)

Script output follows...

PS C:\> c:\NibuRoot\Powershell\powershellsnips\Claims.ps1
Current Thread Principal:
Issuer Type Value
------ ---- -----
LOCAL AUTHORITY http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress email@gmail.com
LOCAL AUTHORITY WebSite http://ntcoder.com
LOCAL AUTHORITY http://schemas.xmlsoap.org/ws/2005/05/identity/claims/country India
LOCAL AUTHORITY http://schemas.microsoft.com/ws/2008/06/identity/claims/role CEO

Authenticated: True

Jan 182018

PowerShell provides multiple ways to access Excel. My favorite so far is via COMObject Excel.Application. This object provides direct access to Excel workbooks, worksheets. In this short article we’ll see how to accomplish this using PowerShell and Excel’s COMObject.

Instantiating Excel COM Object using New-Object PowerShell CmdLet

Using following line of code to instantiate Excel COM object.

$excelObj = New-Object -ComObject Excel.Application
Creating an Excel workbook
$excelWB = $excelObj.WorkBooks.Add()
Get reference to a worksheet
$excelWS = $excelWB.WorkSheets.Item(1)
Get reference to an excel worksheet cell

Change attributes of a Cell using following code…

$excelWS.Cells.Item(1, 1) = "Test"
$excelWS.Cells.Item(1, 1).Font.Bold = $true
Sample code to fill out an Excel worksheet

I’m here using Get-Process cmdlet to generate some data in tabular format. But basically, below script uses above logic to fill out the sheet…

$excelObj = New-Object -ComObject Excel.Application
$excelWB = $excelObj.workbooks.Add()
$excelWS = $excelWB.WorkSheets.Item(1)
#Get processes running on my machine
$procs = Get-Process
#Get all column names, process class' property name
$ColumnNames = $procs[0].GetType().GetMembers() | Where-Object{$_.MemberType -eq "Property" -and $_.MemberType -ne "Module"} | %{$_.Name}
#Make main excel window visible
$excelObj.Visible = $true
#Add excel column title
$cIndex = 0; #Column index
$ColumnNames | %{$cIndex++;$excelWS.Cells.Item(1, $cIndex).Font.Bold=$true;$excelWS.Cells.Item(1, $cIndex)=$_}
#Add process information into excel rows
$rIndex = 1;$procs | %{$cIndex = 0;$rIndex++;$proc=$_;$ColumnNames | %{$cIndex++;$excelWS.Cells.Item($rIndex, $cIndex) = "$($proc.$($_))"}}

Another option

PowerShell now does come with built in Excel support if you’re ok to install following module…

Install-Module ImportExcel

With this module in place you can run commands like…

Get-Process | Where Company | Export-Excel C:\Temp\ps.xlsx -Show -IncludePivotTable -PivotRows Company -PivotData @{Handles=”sum”} -IncludePivotChart -ChartType PieExploded3D

This will create an excel workbook with data in a pivot table. For this case we’ve set PivotData to sum of handles based on product company.



Jan 082018


While debugging a crash on a customer SharePoint farm, we had to do constant checks on all SharePoint servers for latest entries in the ‘System’ eventlog. So wrote this PowerShell one-liner, using Get-EventLog, to help him out…


Get-SPServer | Where-Object{$_.Role -ne "Invalid" } | %{ Write-Host "++++++++++++++++++ComputerName: $($_.Name.Split('.')[0])+++++++++++++++++++++++";
Get-EventLog -ComputerName $_.Name -LogName System -Newest 10} | ft -AutoSize

Command explained

  1. Get-SPServer: return all servers in the farm.
  2. Checking role of each server to make sure we’re accessing just the SharePoint servers.
  3. Drawing a header right before dumping out event log entries. If name is FQDN then we just take the first part, not necessary though.
  4. Call Get-EventLog by passing in computer name and log category as ‘System’, we’re retrieving newest 10 entries. Feel free to change this.

If you run into any issues or if you have any better way of doing this please let me know.

Sample output

PS C:\Windows\system32> Get-SPServer | Where-Object{$_.Role -ne "Invalid" } | %{ Write-Host "++++++++++++++++++ComputerName: $($_.Name.Split('.')[0])+++++++++++++++++++++++";
Get-EventLog -ComputerName $_.Name -LogName System -Newest 10} | ft -AutoSize
++++++++++++++++++ComputerName: SP+++++++++++++++++++++++

Index Time         EntryType   Source                  InstanceID Message                                                                 
----- ----         ---------   ------                  ---------- -------                                                                 
19665 Jan 08 12:00 Information Service Control Manager 1073748860 The Software Protection service entered the stopped state.              
19664 Jan 08 12:00 Information Service Control Manager 1073748860 The Software Protection service entered the running state.              
19663 Jan 08 12:00 Information EventLog                2147489661 The system uptime is 1026236 seconds.                                   
19662 Jan 08 10:21 Information Service Control Manager 1073748860 The Windows Modules Installer service entered the stopped state.        
19661 Jan 08 10:19 Information Service Control Manager 1073748860 The Windows Update service entered the stopped state.                   
19660 Jan 08 10:19 Information Service Control Manager 1073748860 The Windows Modules Installer service entered the running state.        
19659 Jan 08 10:14 Information Service Control Manager 1073748860 The Windows Store Service (WSService) service entered the stopped state.
19658 Jan 08 10:09 Information Service Control Manager 1073748860 The Windows Store Service (WSService) service entered the running state.
19657 Jan 08 10:07 Information Service Control Manager 1073748860 The Windows Update service entered the running state.                   
19656 Jan 08 07:18 Information Service Control Manager 1073748860 The Windows Modules Installer service entered the stopped state.
Dec 232017

Use following PowerShell commands to list all printers installed on any machine…

First command uses WMI (Windows Management Instrumentation)…

Get-WmiObject -Class "Win32_Printer" -ComputerName "localhost" | ft -Property Name, DriverName, SystemName, ShareName -AutoSize
Command Output
Name                           DriverName                                  SystemName        ShareName   
----                           ----------                                  ----------        ---------   
Send To OneNote 2016           Send to Microsoft OneNote 16 Driver         MYMACHINE                    
Microsoft XPS Document Writer  Microsoft XPS Document Writer v4            MYMACHINE                    
Microsoft Print to PDF         Microsoft Print To PDF                      MYMACHINE                    
Fax                            Microsoft Shared Fax Driver                 MYMACHINE                     

The next command uses built-in PowerShell command Get-Printer

Get-Printer -ComputerName mymachine
Command Output
Name                           ComputerName    Type         DriverName                PortName        Shared   Published  DeviceType     
----                           ------------    ----         ----------                --------        ------   ---------  ----------     
Send To OneNote 2016           mymachine       Local        Send to Microsoft OneN... xxx:            False    False      Print          
Microsoft XPS Document Writer  mymachine       Local        Microsoft XPS Document... xxxxxxxxxx:     False    False      Print          
Microsoft Print to PDF         mymachine       Local        Microsoft Print To PDF    xxxxxxxxxx:     False    False      Print          
Fax                            mymachine       Local        Microsoft Shared Fax D... xxxxxx:         False    False      Print
Please note that I’ve removed some printers from this list due to security issues.
Aug 142015

In this post we’ll be discussing on how to manipulate strings using PowerShell. PowerShell comes with the following string manipulation operators…

  • split – case sensitive split
  • isplit – case insensitive split
  • csplit – case sensitive split
  • join – joins an array into one string
  • replace – case sensitive split
  • ireplace – case insensitive split
  • creplace – case sensitive split
Split Demo Using Split Function Call
#store comma delimited wild animals list into a string
$wildanimals = "Tiger,Lion,Elephant,Bear,Fox,Jackal,Hyena"
#split the string using Split function based on ","
Split Demo Using -Split Operator
#split array using -split operator
$wildanimals -split ","
#split into three strings, this will leave the third string unsplit
$wildanimals -split ",", 3
#replace all "," with " "
$wildanimals = ($wildanimals -replace ",", " ")
#alternate syntax, with no split criteria the default is to use " " as split criteria
-split $wildanimals
#restore "," back instead of " "
$wildanimals = ($wildanimals -replace " ", ",")
Join Demo
#store into an array
$wildanimalsarray = $wildanimals -split ","
#join operator takes an array and makes it a string, each element separated by ","
$wildanimalsarray -join ","
Replace Demo
#replace all instances of Elephant with Zebra
$wildanimals -replace "Elephant","Zebra"

The case sensitive and insensitive operators are similar in usage except they are sensitive/insensitive to case. Hope this helps you.

Jul 232015
Very important:

Please make sure necessary backups are in place before you perform this operation. First test in your dev/test environment and only then use in your production environment.

Ideally a feature will be scoped to a Farm, WebApplication, Site, or Web, but orphaned features won’t be having a scope. The command to list all orphaned features in a SharePoint farm is as follows…

PowerShell command to list all orphaned features…
Get-SPFeature | ? { $_.Scope -eq $null }
Sample output…
PS C:\windows\system32> Get-SPFeature | ? { $_.Scope -eq $null }

DisplayName                    Id                                       CompatibilityLevel   Scope                         
-----------                    --                                       ------------------   -----                         
ReportServerCentralAdmin       5f2e3537-91b5-4341-86ff-90c6a2f99aae     14                                                 
ReportServerStapling           6bcbccc3-ff47-47d3-9468-572bf2ab9657     14                                                 
PowerView                      bf8b58f5-ebae-4a70-9848-622beaaf2043     14                                                 
ReportServerCentralAdmin       5f2e3537-91b5-4341-86ff-90c6a2f99aae     15                                                 
ReportServerStapling           6bcbccc3-ff47-47d3-9468-572bf2ab9657     15                                                 
PowerView                      bf8b58f5-ebae-4a70-9848-622beaaf2043     15
PowerShell command to delete an orphaned feature…
foreach($f in @(Get-SPFeature | ? { $_.DisplayName -eq "ReportServerCentralAdmin" }))

Why did we need a foreach? Because a feature could be listed twice with different “CompatibilityLevel” values. So in this case “ReportServerCentralAdmin” is listed twice with “CompatibilityLevel” set to 14 and 15. So we delete both via $f.Delete().

Jul 222015


Get-SPFeature is a command used to list out all the features in a SharePoint farm (scope can be set). You can scope this command to different levels, the levels are…

  • Farm – Only SharePoint farm level features are displayed
  • Web Application – Only web application level features are displayed
  • Site – Only site level features are displayed
  • Web – For sub sites


#Display all SharePoint farm features
Get-SPFeature –Limit All
Scoping features…
#Display all SharePoint features scoped to farm
Get-SPFeature -Limit ALL | Where-Object {$_.Scope -eq "FARM"}

#Display all SharePoint features scoped to web application
Get-SPFeature -Limit ALL | Where-Object {$_.Scope -eq "webapplication"}

#Display all SharePoint features scoped to site
Get-SPFeature -Limit ALL | Where-Object {$_.Scope -eq "site"}

#Display all SharePoint features scoped to web
Get-SPFeature -Limit ALL | Where-Object {$_.Scope -eq "web"}
List all features in a Site Collection…

#Displays all SharePoint features for a site collection using Grid view

Get-SPSite http://mysiteurl | Get-SPWeb -Limit ALL |%{ Get-SPFeature -Web $_ } | Out-GridView –Title “All features for this site”

Sample Grid Output…
All Features in a Sharepoint Site Collection


#For detailed help type in… Get-Help Get-SPFeature –Full

May 012015

Here are some sample PowerShell commands to manipulate XML contents in memory and then later dump them to an XML file. I’ve added comments inline to explain a line of PowerShell command.

#Clear output

#Sample XML content
$xml = @'
<?xml version="1.0" encoding="UTF-8"?>
<book genre="novel" style="hardcover">
<title>The Handmaid's Tale</title>
<book genre="novel" style="other">
<title>The Poisonwood Bible</title>
<book genre="novel" style="paperback">
<title>The Bean Trees</title>

# Dump XML to output window

#Get all attributes named "genre" from above XML
$nodes = $xml.SelectNodes("//@genre")
#Output: 3

#Get first book in the XML
$firstbook = $xml.SelectSingleNode("/bookstore/book[1]")
#Output: <title>The Handmaid's Tale</title><author><first-name>Margaret</first-name><last-name>Atwood</last-name></author><price>19.95</price>

# Using Select-Xml: Get last book in the XML
$selxml = Select-Xml -Xml $xml -XPath "/bookstore/book[last()]"
#Output: <title>The Bean Trees</title><author><first-name>Barbara</first-name><last-name>Kingsolver</last-name></author><price>5.99</price>

# Filter out nodes based on conditions, dump titles of books whose price is greater than 11
$xml.SelectNodes("/bookstore/book[price>11]/title") | Format-Table
#Output: #text 
 # ----- 
 #The Handmaid's Tale 
 #The Poisonwood Bible
# Modify XML value of a node, change price
$xml.SelectSingleNode("/bookstore/book[price<11]/price") #Old price
$xml.SelectSingleNode("/bookstore/book[price<11]/price").InnerText = 10 #New Price
$xml.SelectSingleNode("/bookstore/book[price<11]/price") #Print new price
#Output: #text 

#Save XML