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.

Scenario

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.

Solution

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.

Advertisement

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)

Issue

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

Solution

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.

Scenario

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.

Instructions

  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.

Scenario

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?

Solution

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.

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

function Prompt
{
 	switch($inpType)
	{
		"DEV"
		{
			$color = "Yellow"
		}
		"PROD"
		{
			$color = "Green"
		}
		Default
		{
			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>"
	Set-Location "<ENTER YOUR DEV SCRIPT DIRECTORY>"
	prompt
}
Else
{
	$env:PSModulePath = $env:PSModulePath + ";<ENTER YOUR PROD MODULE PATH>"
	Set-Location "<ENTER YOUR PROD SCRIPT DIRECTORY>"
	prompt
}
clear

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

Instructions

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

$env:PSModulePath

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

Get-Location

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

Prompt

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

PROD = PROD>

DEV = DEV>

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.

Gimme All Your Cache!


Those of us who have the wonderful job of managing a SharePoint farm know, installing patches can be a bit like playing roulette. This is especially true when installing Cumulative Updates, but not limited to.

Those of us who manage a SharePoint farm with multiple servers have definitely seen our fair share of messages like the one below.

Obviously, the first thing you need to verify, is that the noted patch is actually on all the servers. If it is, often we are then directed by sites, even mine, to manually run some combination of the PSCONFIG.exe command manually via powershell. This typically works because we’re forcing SharePoint to skip important version checks etc.

I highly recommend before you jump to any powershell that you follow the instructions on the site below.

SharePoint 2010 – Clearing the Configuration Cache

What this site is doing is clearing your configuration cache on each server before you attempt to run the SharePoint Configuration Wizard on any of your servers. The instructions specifically indicate they are for SharePoint 2010, but they work for SharePoint 2013 as well.

I’ve found I’ve even had issues running the PSCONFIG.exe manually and I still cannot get the config to finish. Clearing the cache is what works. You may need to reboot your servers, and you may even need to clear the cache twice, but soon, it will likely resolve the issue. So if you’re sitting stuck at 10% for forever, kill that PSCONFIG.exe task in the Task Manager and clear your cache. But don’t thank me, thank , the author of the above article.

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

clear
#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"
#endRegion

#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)

Find_AccessRequest_Input

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)

Find_AccessRequest-ResultsConsole

  • Now navigate to the Export location you entered. You should see a file with the following name:

yymmdd.hh.mm.ss_AccessRequest_<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.

Thanks.

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.

STEP 1

  • 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)

Add-SPUser_Group_Log

STEP 2

  • Enter A at the menu (see below)

Add-SPUser_Group_Menu

STEP 3

  • 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

Add-SPUser_Group_Input

STEP 4

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

Add-SPUser_Group_UserListing

STEP 5

  • 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)

STEP 6

  • 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")
	{
		AnswerCreate
	}
	if ($result -eq "B")
	{

	}
	if ($result -eq "?")
	{
		clear
		#Opens Default Internet browser and navigates to the below site that holds the instructions for this program
		Start-Process -FilePath "https://techchucker.wordpress.com/2013/09/17/addbulkspusergroups/"
	}
}
#endRegion

#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
}
#endRegion

#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
}
#endRegion

#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
}
#endRegion

#Region AnswerCeate Function

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

	#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
	PressKey

	#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
		}
		else
		{
			#Adds user/s to the SharePoint group
			Set-SPUser -Identity $LANID -Web $web -Group $group	
			Write-Host $LANID "has been added to "$group	
		}
	}	
}
#endRegion

#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"
}
#endRegion

#Region Program Actions
$ErrorActionPreference="SilentlyContinue"
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

do
{
	clear
	Menu
	$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
	}
	else
	{
		$confirm = $false
	}
}
while($confirm -eq $True)

Stop-Transcript
#endRegion

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]
#endRegion

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;
#endRegion

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
$newItem.Update()
}
#Dispose
$Site.Dispose();
$web.Dispose();
#endRegion

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.

Configure Kerberos for SharePoint 2010


Cerberus or Kerberos, in Greek and Roman mythology, is a multi-headed hound (usually three-headed)which guards the gates of the Underworld, to prevent those who have crossed the river Styx from ever escaping. more

Configuring Kerberos Authentication in SharePoint 2010 has gotten a bad reputation for being too hard to do so many, if not most, stick with the standard NTLM authentication. Even Microsoft recommends this. For many instances, this may be fine, but if you require Kerberos, I recommend using the below document from Microsoft to guide you through the configuration of Kerberos.

Configuring Kerberos Authentication for Microsoft SharePoint 2010 Products (Download)

How do I know if I should use Kerberos or NTLM?
This is a good article that lays out why you would use Kerberos. Click Here

Some keys to remember when setting up Kerberos is the people or technologies you will need to work with.

In a typical enterprise, you will need to speak with the following folks.

  • Active Directory Administrators (Create SPN’s & KDC configuration)
  • Load Balancing Administrators
  • SSL Encryption (external or internal)

If you are the administrator of all of this, then your job gets easier and harder, because now you have to know how to do all of this. The above document, however, walks you through the process step by step and then shows you how to effectively test to ensure the configuration is working.

Basically there are 5 steps to configuring Kerberos (not including SharePoint Installation)

  1. Create SPN’s – Info
  2. Configure account delegation
  3. Configure SSL
  4. Configure Load Balancing
  5. Configure Web Application

The process is more complex than just 5 steps, but those are the basic aspects of the configuration. Ensure you follow the above document and don’t get bored by all of the content within. They get a little too much into their scenario for configuration which is can be confusing. The naming scheme for service accounts and Service Applications are so similar it’s easy to get lost in the document.

I recommend you read through the document once or twice before starting, create an action plan that shows your step-by-step process before you begin then execute. More importantly, research and truly analyze whether your implementation really requires Kerberos or you can get by with just NTLM.

Once you’ve made it through, you’ll find it’s much easier than even the document makes it out to be. Sometimes these documents are much too wordy.

Leave your comments about your experiences with configuring Kerberos authentication for SharePoint 2010.