Decreasing Indentation of Visual Studio Lines

There are a few articles already out on the Internet, but every time I need them, it takes me forever to find them (have you heard of bookmarks?). I decided to write my own post so I know I’ll always be able to find it.


I’ve just copied and pasted about 100 lines of PowerShell code to a script I’m writing, but the indentation is way too far in for this. I’d love to just select all of it and use a key combo like indenting.


The solution is easy, just use this key combo

Shift + Tab

That’s it! Why can I never remember this? Now I don’t have to. I just need to remember I wrote this article.


Error: The Search Display Templates Are Not Present on this Site Collection

I’m in the process of testing the new SharePoint Online Hybrid Search capabilities that have been released with the August 2015 Cumulative Update (KB3055009). I ran into an issue that I was able to resolve pretty quickly, but I wanted to share the solution I found.

Hybrid Search Information (This is in preview, do not deploy to production environments)


After running the Onboarding Script after all the errors had been dealt with, I attempted to create a new Result Source in my newly created Hybrid Search Service Application.

Here’s what I am doing

I am creating a result source to show only Remote (cloud) search results

  1. In Central Administrator of my on-premise farm I navigate to the newly created Hybrid Search Service Application
  2. Click Result Sources link in the left navigation
  3. Click New Result Source
  4. I enter the following settings
    • Result Source Form
  5. Click the Launch Query Builder button (see above)
  6. If it doesn’t appear automatically, click the Test Query button and you’ll see the following error below
    • Query Builder Error
    • Full Error Text: Build Your QueryThe Search display templates are not present on this site collection. To add them, you need to activate the “Search Server Web Parts and Templates” feature on the Site Collection Features page.Correlation ID: 13783c9d-e6d3-1051-1690-22b8fb473c46


Essentially, SharePoint is telling us that it doesn’t have all the Search features enabled in Central Administration. I have no idea why, since search and the query builder were working prior. The resolution for me was to run the below command.

  1. Open the SharePoint Management Console as Administrator
  2. Enter the following command
    1. Enable-SPFeature SearchWebParts -URL http://centraladministration:PortNumber
  3. Now try the Query Builder again and it should work

If you have questions or this doesn’t solve the issue for you please post a comment.

Creating Desktop Shortcuts to PowerShell that Pass a Parameter

Previously I wrote about how to create a Dynamic PowerShell Profile which allows you to choose upon execution of PowerShell whether you are running your scripts in a DEV state or PROD state.

In this article, I’ll go one step further and show you how to create a custom Desktop Shortcut that will automatically pass the parameters you’ve identified in your Dynamic PowerShell Profile so you don’t need to enter them when you double click the shortcut.


In this scenario, I want to have 2 desktop shortcuts. One that will open PowerShell using my DEV profile and one that will open my PROD profile. Technically, the shortcuts are opening the same PowerShell executable, and are running the same profile. The difference is in the parameter/s it is passing when it executes.


  1. Click Start and Enter “PowerShell” into the search bar (this is assuming you’re running Windows 7 or higher)
  2. Right Click the “Windows Powershell” result
  3. Choose Send To > Deskop (create shortcut)
  4. Right Click the new shortcut on your desktop
  5. Click Properties
  6. Click the Shortcut tab
  7. Place or cursor at the end of the text in the Target: field
  8. Enter the following text:  -noprofile -noexit -command . $profile -inpType DEV
  9. The entire string will now look similar to: %SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe -noprofile -noexit -command . $profile -inpType DEV
  10. Click OK

What Did We Just Do?

Let’s take a look at the additional text we added and break it down.

-noprofile = This tells powershell not to load the $profile we have created and associated with PowerShell. We’re not loading this initially because we want to easily pass a parameter without needing user interaction

-noexit = This tells PowerShell to stay open after executing. If you don’t include this, you’ll see the PowerShell application open and then it will disappear just like that. Allowing PowerShell to close right away is useful when you’re doing silent installs or other tasks that you don’t want/need the user to interact with the application once the process is complete.

-command . $profile = This tells PowerShell to run a command which is the . $profile command which is actually telling PowerShell to run the $profile script.

-inpType DEV = This tells PowerShell that you’re going to pass the $profile script a parameter with is named “inpType” which is created in the $profile script we created previously (you can name your parameters whatever you want). DEV is the parameter itself. You could pass PROD if you wanted instead.

Now, you can change the name of the shortcut to something like “DEV – Windows PowerShell” then copy and paste, rename the new one as “PROD – Windows PowerShell” then change the Target path entry to reflect a PROD parameter entry and now you have 2 shortcuts that will allow you to quickly run in DEV or PROD mode.

I hope this is useful to you. If you have questions or need assistance, feel free to post a question. If you need help adding to your profile, by all means post the question and hopefully I’ll be able to help you out.

Dynamic PowerShell Profile

If you’re writing PowerShell scripts the right way, you’re testing your scripts against a Test, or DEV environment prior to deploying those scripts to your Production environment (You ARE testing your scripts right?). If you’re using source control for your scripts (You ARE using source control for your scripts right?) then you’re likely using a DEV branch for your in progress script and then when all is ready you can Merge that into MAIN or whatever you call your production branch.

NOTE: If you aren’t using source control, branching & merging, and testing, you’ve probably got bigger problems than your PowerShell profile.


If you are able to remotely run your code against your servers or if you’re like me and you’re managing Office 365, you’re running your test scripts and your production scripts on the same workstation.

Some of the common repeatable steps I have to take to differentiate my DEV and PROD instance are to change my directory I’m running my scripts from and since I write a lot of Modules, I need to ensure I’m using the correct Modules.

Out of the box, you’re going to have to manually change your directory and go in and add a temporary module directory depending on where your DEV and PROD modules are stored. I can write a script to do this and that’s what I’ve done, but instead of calling that script manually, why not incorporate it into your profile?


Below is a simple profile I’ve created for my workstation that allows me to determine what environment I’m working in when I run PowerShell. Now, I do nothing different when I open my Windows PowerShell. When it executes it runs the $profile and my script executes prompting me to enter “DEV” or “PROD” based on what I’m working on at the time.

Here’s the script you will copy and paste into your $profile file on your workstation. See below for the instructions.

	[Parameter(Mandatory=$True,HelpMessage="Enter the environment you will be working on (DEV or PROD)")]

function Prompt
			$color = "Yellow"
			$color = "Green"
			Write-Host "ERR -- Environment Type entry not valid." `n -foregroundcolor Red
	Write-Host ($inpType + ">") -noNewLine -foregroundColor $color
	Return " "
if($inpType -eq "DEV")
	$env:PSModulePath = $env:PSModulePath + ";<ENTER YOUR DEV MODULE PATH>"
	$env:PSModulePath = $env:PSModulePath + ";<ENTER YOUR PROD MODULE PATH>"

What is this script doing?

There are three specific tasks this script is doing.

  • Add Temporary Module Path (based on Parameter entry)
  • Sets Current Directory (based on Parameter entry)
  • Changes Prompt text and color (based on Parameter entry


Follow these steps to include the script above into your Windows PowerShell Profile. Note there are pieces you need to modify in the script above that are wrapped in <>’s. You’ll need to change the paths to represent your own locations.

  1. Open Windows PowerShell
  2. Verify you have a $profile created. Click for instructions and information about PowerShell Profiles
  3. Edit your profile by entering the following command: notepad $profile
  4. Copy the code above (make sure you’ve changed paths to represent your paths) and paste the code into the $profile notepad file
  5. Save
  6. Close PowerShell and Re-Open
  7. You should see a prompt similar to the image below

Profile Prompt

Once you’ve entered the environment, your PowerShell prompt should look like the below image

Profile DEV Prompt

Verify Your Profile Environment

It’s wise to verify you got the profile paths correct. Test that the $profile applied the variables as expected by running the following commands

Module Path


The information returned will be a semi-colon separated result including all current module paths. Your newly added path should be included in this

Current Directory


This should return the current directory your PowerShell session is set to right now. This should reflect your environment path you entered.


You should be able to see the prompt is different depending on the input you chose.



If I Entered “DEV” Do I Have to Close PowerShell to get into “PROD”

No, you do not have to close out, though it might not be a bad idea depending on all the stuff you add to the profile. You can switch easily by entering the following command

. $profile PROD

There is a little bit of error handling, but not much in this script so be aware that you will want to augment this script if you want more error handling.

What can I do with this?

The sky is the limit. If you want to have specific modules loaded or snap-ins you know you’ll use, go ahead and add them. Just be warned, if you add too much stuff, it could slow the overall load time down as well.

Check back to my blog, I’ll show you how you can create a desktop shortcut to automatically enter the parameter so you can quickly get into your DEV or PROD PowerShell profile without entering anything.

You Know You’re A Nerd When…

You know you’re a huge nerd when… You send jokes to your co-workers complaining about leadership via Lync using fake PowerShell commands.

Wow! It’s getting really nerdy up in here today. 🙂

Joke of the day today.

Set-SPExpert -Identity “Leadership” -Force -ErrorAction SilentlyContinue

Wow! That’s so bad.

Microsoft Ignite Activity Overload

I am so excited. On Sunday I get to hop on a plane headed for Chicago for the Microsoft Ignite conference May 4th-8th. Of all the nerd inspired things one could do, going to a Microsoft technology conference has got to be at the top of the list.

I’m learning pretty quickly, though that nerds apparently know how to party, or at least to appear to know how to party. I’ve not been to a conference of this size, so having to pick and choose my after-hours entertainment from the slew of options available to me is a bit daunting, but a nice problem to have.

I, and my employer are hoping I’ll come away from this 5 day experience with some valuable knowledge, skills, and contacts regarding SharePoint, Office 365, OneDrive for Business, Skype for Business, Windows PowerShell and so many other technologies.

I’m not sure if I have any readers that are also going to Ignite, but if you are, what sessions are you looking forward too and what after-hours stuff are you hoping to do? I’m really hoping I’ll bump elbows with someone important who has extra tickets to one of the Wild vs. Blackhawks playoff games as I’d love to see my team when I’m in Chicago.

For those of you not a member of the nerd world of enterprise technologies, what are your recommendations for things to do in the great Windy City of Chicago USA next week? Any great restaurants you can recommend? We’re going to be downtown in the Michigan ave area so I’m looking for great ideas there?

If any of you are going, I’d say we should meet up and have a drink, but let’s be honest, are we really going to do that? Do you really want to meet me? Of all the people out there, I’ll be honest, it’s not going to be that awesome meeting me… ha ha or is it? If you’re willing to go to a midnight viewing of the new Avengers: Age of Ultron (2015) movie with me, then I’ll meet up with pretty much anybody, or you have tickets to the Hawks game, just don’t plan on murdering me please, that would be a pretty big downer.

Who’s Managing Permissions?

Find_AccessRequestIt has been a while since I’ve posted anything, but that doesn’t mean I’ve been sitting around twiddling my thumbs all day. Here’s a quick SharePoint post. Stay tuned for more as we ramp up our new environment and we migrate to it. There should be some interesting stuff. (I hope)

Recently we’ve been getting requests from our messaging team (MS Exchange 2010) to remove/change e-mail addresses assigned in the Access Request field of our SharePoint sites as the domain has changed. This wouldn’t be an issue but we have 600+ Site Collections with 6,000+ individual sites. This of course means manually searching for the particular sites that have the offending e-mail address would be impossible. Thus, I have created a simple to use PowerShell script to iterate through every single SPWeb in the desired Web Application and return all Webs that have the user submitted e-mail address. Below is the full code.

**Note: I did not handle errors in this script. The most common error you will get is if you have Site Collections set to Read Only, or No Access. You will need to either reset their lock state or write logic to identify this and handle.

Step 1

  • Copy below code and save to file named Find_AccessRequest.ps1

#End user is required to input Web Applciation, E-mail Address, and Export File Path
#Region User variable input
$inpWebApp = Read-Host "Enter the Web App Friendly Name"
$webapp = Get-SPWebApplication $inpWebApp
$inpEmail = Read-Host "Enter the e-mail address to search for"
$inpExportPath = Read-Host "Enter the path for the export"

#Gets the current date and time for the FilePath
$date = Get-Date -UFormat %y%m%d.%H.%M.%S
$path = $inpExportPath + "/" + $date + "_AccessRequest_" + $inpEmail + ".csv"

#Iterates through each site collection within the specified Web Application
foreach($spsite in $webapp.Sites)
	#Writes the current Site Collection to the console for troubleshooting purposes
	Write-Host "SC: " $spsite.URL

	#Iterates through each web within the site collection
	foreach($web in $spsite.AllWebs)
		#Web must have permissions broken, request access enabled, and the e-mail must match the user input
		if( $web.HasUniqueRoleAssignments -and $web.RequestAccessEnabled -and $web.RequestAccessEmail -eq $inpEmail) 
			#Writes the results to the console and exports to a CSV file
			Write-Host "	" -NoNewline; Write-Host $web.URL -BackgroundColor White -ForegroundColor Black
			Write-Output $web.URL | Out-File -Append -FilePath $path

Step 2

  • Run the file created in Step 1
  • Enter the following information (see screenshot below)
    • Web Application Name
    • E-mail Address to find
    • Path for export (do not include filename, the script will create the name)


Step 3

  • As the script runs it will provide the following information on the console screen in real time (see below)
    • Site Collection URL
    • SP Web URL that has a matching e-mail address in the Access Request field (highlighted in White)


  • Now navigate to the Export location you entered. You should see a file with the following name:<email address>.csv

  • Open the file. There will be a single column of data. The data will be each SPWeb that has the supplied e-mail address configured as the Access Request e-mail. It will only include Webs that have their permissions broken, which enables the web manager to configure the Access Request field independent of the parent site/web.

I hope this helps someone out there who needs to find an e-mail address in the Access Request field. I may at some point add to the script to allow for changing the address in bulk, but so far our need has only resulted in a few webs at a time.

As always, please a comment letting me know if this helped or if you have ideas to improve upon the script or for ideas for future scripts.


Add Users in Bulk to SharePoint Groups

The other day I had a user ask to add 600+ users to a SharePoint group. Immediately I knew PowerShell was going to save the day, again. So, here is the script I wrote. You can download the full script along with a sample answer file. All I ask is that you let me know if you run into issues, and know that this script is provided as-is with no warranty or guarantees. I haven’t taken into account all possible errors so my error handling is very limited here.

**Typically it is recommended you use an Active Directory security group, but sometimes we have to make exceptions**

Don’t freak out because of the amount of code. Most of the code is building the menu to make it easy for even the least experienced PowerShell user to use. I write a lot of PowerShell scripts, so I don’t like having to open a script and review it to determine what/how to run it. Yes, I could build a help menu for the script, but I prefer a menu that will simply give me and others on my team the options to choose from. The screenshots below should help you understand what the code is doing. The help menu will bring you to this article.


  • Run the file named Add-SPUser_Group.ps1 from the SharePoint CLI
  • Enter a path to a directory to store the activity log (see below)



  • Enter A at the menu (see below)



  • Enter the path and filename of the .csv answer file (example answer file included in script download)
  • Enter the URL of the site to add the users to
  • Enter the Group ID

You can find the Group ID of a SharePoint Group by navigating to the Group in the browser. The ID is in the URL of the group



  • The list of Usernames will be displayed to you (Usernames must be in DOMAIN\Username format in your answer file) (see below)



  • You will see one of the following messages for each user in your answer file
    • “DOMAIN\Username” created and added to “Group ID” (displayed if a user account did not exist in the site. The account is added to the site, then added to the group)
    • “DOMAIN\Username” has been added to “Group ID” (displayed if a user already exists in the site and is added to the group)


  • You will now be brought back to the main menu shown in STEP 2

Download Code

#Region Action Function
#Action taken via user input based on menu option chosen
Function Action ($result)
	if ($result -eq "A")
	if ($result -eq "B")

	if ($result -eq "?")
		#Opens Default Internet browser and navigates to the below site that holds the instructions for this program
		Start-Process -FilePath ""

#Region PressKey Function

#User must enter any key to continue
Function PressKey
	Write-Host "Press any key to continue..." -ForegroundColor Black -BackgroundColor White

	$x = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyUp,AllowCtrlC")

	return clear

#Region WebInput Function
#Function to request web input from user
Function WebInput
	$inpWeb = Read-Host "Enter the URL of the site to add users to a group"

	return $inpWeb

#Region GroupInput Function
#Function to request SharePoint Group input from user
Function GroupInput
	$inpGroup = Read-Host "Enter the SharePoint Group ID to add users to"

	return $inpGroup

#Region AnswerCeate Function

#Function to take answer file and add multiple users to SharePoint Group
Function AnswerCreate

	#Imports user inputted answer file
	$userList = Import-Csv ($answerFile = Read-Host "Enter path to Answer File (e.g. c:\filename.csv)")
	$web = WebInput
	$group = GroupInput

	Write-Output $userList

	#Iterates through each record storing variables and executing user add
	ForEach ($user in $userList)
		$validateUser = $null
		$LANID = $user."LANID"

		$validateUser = Get-SPUser -Identity $LANID -Web $web -ErrorAction SilentlyContinue #This will throw an error if the user does not exist

		if($validateUser -eq $null)
			Write-Host $LANID "does not exist"
			New-SPUser -UserAlias $LANID -Web $web -group $group
			Write-Host $LANID "created and added to " $group
			#Adds user/s to the SharePoint group
			Set-SPUser -Identity $LANID -Web $web -Group $group	
			Write-Host $LANID "has been added to "$group	

#Region Menu Function

#Function to display the menu for the program
Function Menu
	Write-Host "Add Users to SP Groups in Bulk`n`n" -ForegroundColor Black -BackgroundColor White
	Write-Host "Choose the action you would like to perform shown below.`n`n"

	Write-Host "	A	-	Add users in bulk using Answer File`n"
	Write-Host "	?	-	Program Help`n"
	Write-Host "	Exit	Exits this program`n`n"

#Region Program Actions
Stop-Transcript | out-null
$ErrorActionPreference = "Continue"

$logPath = Read-Host "Enter log path (c:\Logs)"
$date = Get-Date -UFormat %y%m%d.%H.%M.%S
$logFile = "\" + $date + "_AddUserGroup.txt"

Start-Transcript -path $logPath$logFile -append

	$result = Read-Host "Enter your selection"
	if($result -ne "exit")
		Action $result
		#Write-Host "Would you like to return to the main menu?`n`n"
		#$confirm = Confirm ($inp = Read-Host "Enter Y or N")
		$confirm = $True
		$confirm = $false
while($confirm -eq $True)


Output to SharePoint List Using PowerShell

Those of us who manage SharePoint Farms have inevitably been tasked with running PowerShell scripts that need data written outside of the PowerShell console. The most common output method is to a .txt or .csv file. That’s all well and good, but wouldn’t it be cool to send that output straight to a SharePoint list? It turns out, it’s really quite easy to do. Below, I hope to provide an example of how to do this.

STEP 1 – Establish SharePoint List Variable

**NOTE** You will need to already have a list created with the columns you plan to use in your output prior to running the script

#Region SP Output File Variables
$webURL = "http://yourdomain"
$listName = "List Name"

#Get the SPWeb object and save to variable
$listWeb = Get-SPWeb $webURL

#Get the SPList object to retrieve the list
$list = $listWeb.Lists[$listName]

STEP 2 – Establish Web Application Variable

In this script snippet you as a user are asked to enter the URL of the Web Application to run the scrip against. You can certainly hard code this to automate the script, but I prefer when offering scripts, to never hard code variables but rather leave it open for others to decide. This is why step 1 above has the two variables hard coded and in this step it is shown as a user input option. You can choose either or and modify the code as needed.

#Region Web Application Variable
$Siteurl = Read-Host "Enter Web Application URL"
$Rootweb = New-Object Microsoft.Sharepoint.Spsite($Siteurl);
$Webapp = $Rootweb.Webapplication;

STEP 3 – Write to SharePoint List

Now that you’ve instantiated the list above, you can now begin writing to that list. I will use the following example for this example code.

Example: Export the following information for each site collection in a web application

  • Site Name – (Single line of text)
  • Site URL – (Hyperlink or Picture)
  • Primary Site Collection Administrator – (Single line of text)
  • Secondary Site Collection Administrator – (Single line of text)
#Region Write to SP List

#Loops through each collection within the web application
Foreach ($Site in $Webapp.Sites)
#Create new item
$newItem = $list.Items.Add()

#Web variable used to get Site Collection Title
$web = Get-SPWeb $Site.URL

#Add properties to this list item
$newItem["Title"] = $web.Title
$newItem["Site URL"] = $Site.Url
$newItem["Primary Site Collection Administrator"] = $Site.Owner.Name
$newItem["Secondary Site Collection Administrator"] = $Site.SecondaryContact.Name

#Update the object to publish to list

Here is what your results can look like below

List Image

If you would like to download this script in its entirety you can get the Example Output to SP.ps1 here. If you have questions please leave a comment here. Also, if you have a way of writing the Administrator info into the Person fields let me know. I didn’t have time to figure that out. I can just use a workflow to do it, but if I could just write directly to a Person field that would be ideal.

PDF Compatibility in SharePoint 2010

Out of the box SharePoint 2010 does not make it easy to store and work with PDF files. When you save a PDF to a SharePoint 2010 library there are four things you will notice right away.

  1. There is no PDF icon
  2. Opening a PDF results in a Save dialog box (see below) instead of opening in the browser or client
  3. PDF files cannot be edited without saving locally first
  4. PDF files are not supported in Search (Future Post)

This is going to get on your users nerves and it really detracts from all the cool things SharePoint 2010 can do. There are many posts out there giving advice as to what to do to resolve these issues. Most don’t address it properly, however. If you see any recommendations telling you to set your Web Application from Strict to Permissive then you need to disregard that advice. In a nutshell, setting the Web Application to Permissive allows any file type to be opened in SharePoint 2010 which can leave your network at risk.  So DON”T DO THAT!

We’ll first go over the process for getting the PDF icon to appear.

Add PDF Icon

Note: These instructions apply to any program file you want to add, not just for PDF’s

These steps are to be performed on all of your Web Front End Servers (WFE).

  • Download the Adobe PDF icon (Click Here)
  • Save the downloaded file as: ICPDF.gif
  • Copy the ICPDF.gif file to the following location

C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\IMAGES

  • Navigate to the following location
C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\XML
  • Edit the DOCICON.XML file
  • Add the following line of code in the <ByExtension> section. (Preferrably you will put this in alphabetical order by the extension)
<Mapping Key=”pdf” value=”icpdf.gif” EditText=”Adobe Acrobat” OpenControl=”AdobeAcrobat.OpenDocuments”/>
  • Save the DOCICON.XML file
  • Perform an IISRESET on all WFE’s (note this will result in a short outage)

You should now see the PDF Icon Adobe PDF icon appear next to all PDF files stored in your SharePoint 2010 libraries and if you have Adobe Reader X you will be prompted if you would like to check out the file and open and then will open in your Adobe client software.

NOTE: This will address the ability to open and edit a PDF in your Adobe software as long as you have Adobe Reader X installed. Otherwise this will not work as expected.

Add PDF to Allowed Mime Types

Now we need to address the ability to open a PDF from the browser. This is predominantly important for environments that do not have Adobe Reader X installed.

Continue reading