I’m presenting and Hosting SharePoint Saturday Chicago Suburbs on May 17th

If you live in the Chicago Area, Sign up for SPSChicagoSuburbs (http://www.spschicagosuburbs.com)

I’m on the planning team and we’ve got a great event planned, with tons of great sessions and speakers, all made possible by our fantastic Sponsors!

I’ll be presenting “Intro to PowerShell” at 10:30am

We also have a mobile website for handy use on your phone during the conference, the url is easy to type too! http://spscsm.com
(If you’re an iphone user, once you have the site up, click the ‘share’ button, then ‘Add to Home Screen’ to create an ‘app’ icon for easy access)

I hope to see you there!

– Jack

Active Directory Migration Woes (Part 2)

In Part 1, I talked about a SP2013 farm that wasn’t behaving as a result of a lengthy in-progress AD migration, and linked to an article that talked about a hack, and then ultimately a solution via a SharePoint setting if your farm was patched to a patch level sometime around October 2012 or later. On the 2013 farm that resolved the issue and all were happy.

In Part 2, We visit the same issue on a SharePoint 2007 farm, and use the articles “hack” to resolve the issue in the 2007 environment.
For reference, the article who’s approach was used is here:
http://blogs.technet.com/b/craigf/archive/2012/10/15/sharepoint-and-sid-history-not-playing-well-together.aspx

The 2007 farm, unlike the 2013 farm doesn’t have the option of using the SharePoint setting – it doesn’t exist in the version of SP2007 in use, and a shotgun upgrade of the SP2007 farm is not an option.

Time to re-visit the “Hack” portion of the above article…

The Problem:
Two domains, Users in Domain A, SharePoint in Domain B
The users are going to be migrated one day, from A to B.
The AD team has replicated all the users so that they now exist in BOTH domain A and B.
Along with this replication, an attribute called “SID History” was set in domain B for each user.

Because of this, here’s how things work in Domain B…
If a program (any program, not just SharePoint) asks Domain B to fetch a user ID from a SID, Domain B will look in it’s list of users/Sids.
In Ordinary times, when users existed in only one place, the domain B controller would try itself first, and not finding the ID, would then send off the request to Domain A.

In our case however, the ID’s exist in both places.

So an app requests the User ID from a given SID from the DC in Domain B. This time, Domain B finds that SID in SID history. “AH HA” the domain says to itself. “I don’t have this ID, but I can see right here, that ID was migrated to an ID I DO have. I’ll just give you the DomainB\Account” (Remember we want DomainA\Account)

While that would be very helpful if we were done with our migration, and really really helpful if the Domain A account was deleted and gone, in our case we had a little problem.

The users were still using accounts from Domain A, so we needed those to resolve.

In the article, Craig Forster figured out that by using the right tool to query AD, you could pre-populate the LSA cache with the “desired” user accounts from the right domain controller, eliminating the whole name lookup and SID history piece of the puzzle.

Craig’s article mentioned the approach he used, but not the scripts.

That’s where this blog post comes in…
I crafted a solution to do what Craig’s article described.

First things first, the prerequisites:

  • PSGetSid.exe you can get this from Sysinternals
  • You’ll need PowerShell on the WFE’s for your 2007 Farm (regular PowerShell, we’re not touching SharePoint so there’s no need to panic that SP2007 doesn’t support SharePoint)
  • You’ll need the AD PowerShell module – this is a windows server
    “feature”, found under “remote server tools” when you add a feature.

Ok now for an overview of the solution:
From Craig’s article, we know we need to query not just the domain, but we need to look for every specific user.
To make this practical, we want to query AD for the list of users, then use the PSGetSid.exe program to query for that user.

start-transcript D:\adhack\RunLog.txt
import-module ActiveDirectory

$PSGETSID = "D:\ADHACK\PSgetSid.exe"
$batchFileName = "D:\ADHACK\FixMyAD.bat"

# this is to start the file clean so it's not appending between executions.
"Rem Start of file" | out-file -filepath $BatchFilename -Encoding "ASCII"

#Note, there is a good chance the next two registry commands will fail, for example, if they already exist - these are easy enough to set manually so thats what you should do, but leave theme here for reference

#set the timeout - this should be a number greater than the time it takes to run this script, for example, if the script takes 15 min to run and you schedule it to run every 20 min, then you'd want this to be something like 40 minutes so if it fails once, you'd still have the values in cache.
new-itemproperty -path HKLM:\SYSTEM\CurrentControlSet\Control\LSA\ -name LsaLookupCacheRefreshTime -PropertyType dword -value 40 #time in Minutes

#set the LSA cache (Default of 128 is too small)
new-itemproperty -path HKLM:\SYSTEM\CurrentControlSet\Control\LSA\ -name LsaLookupCacheMaxSize -PropertyType dword -value 131072 #this is the decimal value

#remember, you're running this from a WFE that's joined to the DESTINATION Domain

#first OU Example - query an OU in DESTDOMAIN (This would imply you have read rights to that OU from the WFE) 
$users = Get-ADUser -filter * -searchbase "OU=UserList,DC=DESTDOMAIN,DC=MYCOMPANY,DC=COM" | Select SamAccountName | Sort SamAccountName
foreach ($user in $users)
{
   #Here, note we're getting the user ID in TARGETDOMAIN, but issuing the command to SOURCEDOMAIN
   $act = "SOURCEDOMAIN\$($user.Samaccountname)"
  write-host "Attempting to cache $act" -foregroundcolor yellow
   & .\PSGetSid.exe $act   
   $line = "$PSGETSID $act"
   $line | out-file -filepath $BatchFileName -Encoding "ASCII" -Append 
   write-host "Done with $act" -foregroundcolor blue  
}


#Second OU EXAMPLE - querying the SOURCEDOMAIN when you've restricted access to the OU on the TARGETDOMAIN

#Need to specify the -server value name to query the SOURCEDOMAIN domain at server.

#Here what we're doing is going back to the original domain where the active user accounts exist - by active, I mean these are the ones they are logging in with each day.
#Doing this is similar, but note we need to specify the -Server parameter, and oddly, you don't actually specify a server name there, you specify the name of the Source Domain
#Also, as I wrote this, it occurred to me that it's quite possible that this query alone is doing the same thing as PSgetSid.exe, so maybe thats not needed in this case (Where the SOURCEDOMAIN is being queried) I'll have to test it one day...

$users = Get-ADUser -filter * -searchbase "OU=UserList,DC=SOURCEDOMAIN,DC=OLDCOMPANY,DC=COM" -Server SOURCEDOMAIN.OLDCOMPANY.COM | Select SamAccountName | Sort SamAccountName
foreach ($user in $users)
{
   $act = "SOURCEDOMAIN\$($user.Samaccountname)"
   write-host "Attempting to cache $act" -foregroundcolor yellow
   & .\PSGetSid.exe $act   
   $line = "$PSGETSID $act"
   $line | out-file -filepath $BatchFileName -Encoding "ASCII" -Append 
   write-host "Done with $act" -foregroundcolor blue  
}

write-host "Done $($users.count) users attempted to cache" -foregroundcolor green
stop-transcript

Ok so that’s the script – put it in the same folder as the PSGetSid.exe file

Now you might be wondering, what’s that FixMyAD.bat file it’s creating?
Well, it’s not really needed, but here’s the thought behind it – if you look at what it’s doing, FixMyAd.bat is just the PSGetSid.exe command repeated a bunch of times for each user in your environment. For a while, I was having trouble getting PSgetSid.exe to run when shelled out from Powershell, so I added that code with the thought that PS could generate the command and then a different job could run the batch file – it turned out to not be necessary, but I left it in there – it might be handy for some edge cases.

Normally, I’d schedule the PowerShell to run per the video Here: http://youtu.be/oJ4nktysxnE however, in this domain, it wasn’t having any of that – the security policy would not run unsigned scripts – I tried to change it, but that registry key was locked down. Darn!

Luckily I had another trick at my disposal: A small batch file launcher to launch PowerShell with the security disabled:

This is a non-powershell batch file that launches Powershell with an executionpolicy of bypass, then calls the PS1 file with the script and runs it.

pslauncher.bat:

powershell -Command "& {Set-ExecutionPolicy -scope currentuser -executionpolicy bypass}" -NoExit
powershell -Command "& {d:\ADHack\PreCache.ps1}" -NoExit

Note that I also had to set the scheduled task to “Run with highest privileges”

So thats the solution I ended up using to rig the LSA cache so it would display the correct user ID’s
Oh one more note- if you want to test if this is working, you might want to reset the LSA cache – as best I could tell, there is no way to do this, but I think you can set the two registry keys to zero, do a test to see what an uncached response is, then set the registry back and test again. No reboot was needed (the keys are documented at the top of the PowerShell script.)

Also, please accept my apologies if this whole thing doesn’t make sense etc… Craig did a great job explaining in his original article, so I didn’t want to rehash all that here, but did want to capture the solution I used since his didn’t show that.

Active Directory Migration Woes (Part 1)

The company I work for is undergoing a very long Active Directory migration project.
The result of which has included duplicate users in multiple domains, issues with Sid History, users not showing up in SharePoint, etc…

We’ve tried lots of things to work around the state of AD and one article was pretty critical for us:

http://blogs.technet.com/b/craigf/archive/2012/10/15/sharepoint-and-sid-history-not-playing-well-together.aspx

The true gem of the article isn’t the article itself, it’s in the comments from Brandon on the 17th of May 2013:

This is covered in the August 2012 CU (Note, this is also part of 2010SP2) … when you run this command: STSADM -o setproperty -pn HideInactiveProfiles -pv true it will bypass disabled accounts and query the active domain.

(Interestingly, that propertyname doesn’t show up when you invoke help on STSADM -o getproperty)

For some more background on what we did,

Our AD team made copies of all user accounts from “OLDDOMAIN” to “NEWDOMAIN” these copies also included “SidHistory” When this happened what we observed was it became impossible on SP2013 to pick an “OLDDOMAIN\user” – they would only show under “NEWDOMAIN\user” – since our accounts were migrated, but the users themselves were not yet using the migrated accounts (they were still logging on as “OLDDOMAIN\user”) this created a huge problem for the SharePoint team, and thousands of SharePoint users.

Part of the solution was that article, and the other part, was that the AD Team moved the duplicated accounts In “NEWDOMAIN” to a “Holding” Organizational Unit (OU) within AD (that OU was still in NEWDOMAIN), they then asked us for the service accounts we use for SharePoint and Denied access to that OU for those accounts.

The net effect of all of this work is that SharePoint 2013 now behaves as it would if there were not duplicated accounts on our domain. When we search a user, they only show up once, and from the “correct” users domain.

Now eventually, the AD team is going to ask users to start using the accounts in the “NEWDOMAIN” -when this happens, they will pull the account OUT of the “Holding” OU, making them visible to SharePoint, and they will also deactivate the old account in “OLDDOMAIN” which would prevent duplicates from showing up.

All the credit for this solution goes to the AD team I work with for the “Holding” OU and related permissions work, and also to Craig Forester for the Blog post with the original workaround and to Brandon Ryan for posting the property name. I’ve documented it here because it’s been so impactful for us, and wanted to be sure I had a permanent reference in case the original article is ever moved.

-Jack

I’m Presenting at SP24 on April 16th

I’m excited to be part of the 24 hour SharePoint Online Conference:

https://www.sp24conf.com

This is a 24 hour virtual online conference, that’s absolutely FREE!

The conference has 2 concurrent sessions, one business track and one technical track.

It starts at 10pm GMT on April 16th and runs through 11pm GMT on April 17th

For those from the Midwest US, that’s 5PM CDST on April 16th through 6PM CDST on April 17th.

I’m slotted for the first timeslot after the Keynote 6pm CST
More information available at https://www.sp24conf.com

PowerPoint:  SP24_JackFruh_PowerShellTimeMachine

Scripts: Scripts_SP24S006 SharePointPowerShellTimeMachine_JackFruh

PowerShell / SharePoint PS cheat Sheet: Combined PowerShell and SharePoint Cheat Sheet

Video on scheduling a PowerShell script to run weekly with the Windows Task Scheduler http://youtu.be/oJ4nktysxnE

How I figured it out video: http://youtu.be/0DDQszLSJ5w
This video is a 40 minute walkthrough of the process of creating a PowerShell Script from scratch.  It’s a great guide to see the techniques that are used to drill down through the object model, and explore parameters, variables and objects you might not be familiar with – all from within powershell.  A great skill to have for those times when searching the internet doesn’t turn up a script that meets your needs, and for furthering your understanding of SharePoint’s internals.

 

 

– Jack

 

I’m Speaking at SharePoint Saturday Twin Cities on April 5th

If you live in the Twin Cities MN area and want to learn more about SharePoint, Mark your calendar for April 5th 2014!

I’ll be at SPSTC giving an “Intro to PowerShell” session.

It’s always an honor to be selected to speak amongst so many excellent speakers and SharePoint experts!

If you haven’t already signed up, do so now, space is limited!

http://www.spstc.com/ 

Update: the Slide Deck from SPSTC is available here, and should be on the SPSTC website soon!

Download the PPT here->  Intro To PowerShell by Jack Fruh

– Jack

Cool scripts for documenting your farm.

Update:
When we ran this script on a new environment, it was pretty cool, but in production, it generated some unreasonably large files.

Reader Amy also posted her experiences in the comments below and had a 3GB file!

So this will take some more work – looks like we’ll need to identify what is important, what kind of changed we’d want to track and trim down the script as a result.

Original article:


My awesome co-worker Stevan found this link today and it is such a great find that I wanted to put it here to share with all, plus it helps me find it later!

Basically it’s a PowerShell script that catalogs everything in your SharePoint farm and exports to XML Files

This link is to the 2013 version, but there is a link to the 2010 version on the same page:

http://technet.microsoft.com/en-us/library/ff645391(v=office.15).aspx

My intention is to modify the script so that the output gets placed into folders named Year-Month-Date that way I can create a scheduled task in windows, and run this on a regular basis. Then it’ll be a simple matter of using a tool like Windiff to compare files from one folder to another and I should know quickly what changed.

When I get to that point, I’ll paste the updated code below.

– Jack

 

Fun configuring Office web apps 2013 (OWA)

Note: This is not a “how to” article on what steps you need to take to configure OWA in 2013, it is a listing of the problems I ran into while configuring mine, and what solutions I found.  If you’re installing OWA, you’ll definitely want to read this, as it will probably help you, but it’s not a step by step how to guide on how to do it…

I ran into a few problems while configuring OWA for use in a new SharePoint 2013 farm today.

The DNS name you pick matters

I wasn’t sure of the architecture of this whole thing and one question was bugging me…

Does the user need direct access to the OWA server? Or do the SharePoint Web Front ends act as a proxy for it?

I setup a config and ran Fiddler on the client with the browser to see what server(s) it connected to – sure enough it connects to the OWA server(s) directly.

This has some implications for us if we’re making this available on the internet…
Think of this for a moment, in 2010, OWA was a “Service Application” – if your user had access to the WFE, SharePoint took care of the rest, even if OWA was on a different box (or boxes) It was Magic.

With OWA2013, you’ll need an external IP address, an SSL certificate your browsers will see as valid, and NLB or an external load balancer if you’re using more than one OWA box.
It also means you’ll want to build your OWA farm with a legit DNS name and not the machine name.

Uninstalling an old config:

First, I had messed around with using HTTP before my certificates were ready.
No Problem, I thought, I’ll just remove that Initial Farm config I had built with New-OfficeWebAppsFarm command, surely there is a Remove-OfficeWebAppsFarm command right?

Wrong.

get-command *office*

The above shows me 3 commands for creating, but only 2 for removing!

Yep, I can use New-OfficeWebAppsFarm, but there is no Remove-OfficeWebAppsFarm!

It turned out to be easy enough, on my one box farm in Dev, I just needed to use

Remove-OfficeWebAppsMachine

Note that if you have more than one machine in the OWA farm, you’d need to run the above command on each box, saving the first one (master) until last.

With that cleared up and was ready to install with my cert.

The next thing I ran into – the new-OfficeWebAppsFarm command wants the “friendly name” of the cert, not the domain name – it was easy enough to figure that out, but it threw me for a loop.

Time for my first OWA farm install!

Here I ran the command below on the first node of OWA:

New-OfficeWebAppsFarm -internalURl https://myurl.com -editingenabled -certificate "Mycertsfriendlyname"

Everything seemed pretty great…

Confirming it works

Except when you’re done, you’re supposed to check that it works by visiting this URL:

https://myurl.com/hosting/discovery

This is supposed to display a nice little snippit of XML – one that looks familiar if you’ve ever pulled up a web service in a browser.

Instead I got an error.

HTTP Error 500.21 – Internal Server Error
Handler “DiscoveryService” has a bad module “ManagedPipeLineHandler” in its module list

It looked like asp.net wasn’t registered.

I searched the error, and found this article: http://consulting.risualblogs.com/blog/2013/04/03/office-webapps-deployment-error/

bottom line, I ran this command:

c:\windows\Microsoft.net\framework\v4.0.xxxx\aspnet_regiis.exe -ir

and that re-bound ASP.net to IIS.

So far so good, the page was coming up now on the first node.

Adding a second OWA server

Now time for the second node.

To add a 2nd-99th OWA node, the command is a little different:

New-OfficeWebAppsMachine -MachineToJoin myowaurl.com

Here, I ran into one more issue – kinda simple but an “of course!” kinda moment.

When I ran the command the first time, it couldn’t find the OWA server to connect to.

Care to guess why?

Because these are all behind a load balancer, I had host entries on both OWA servers that pointed back to themselves. This is common so that you can log on to one server and confirm THAT server is working.  Well, I got ahead of myself here, and the new-officewebappsmachine command was being redirected back to itself.

Not-going-to-work

Easy fix, I pointed the host entry to the other server long enough to do the command, then set it back so I could test it locally.  I’m glad I did that, because the second node had the same problem as the first, something I might not have found without the host entry.
I ran that aspnet_regiis.exe -ir command a second time, and did an IIS reset and things were looking good on my second OWA node.

Oh and one more goofy thing I noticed…

Configuring SP to talk to OWA

No OWA build is complete until it’s registered with SharePoint 2013 so SP knows where to send the traffic.

To do this, on the SharePoint server we run this command:

New-SPWOPIBinding -Servername urltoyourserver.com

Now what’s odd here, is it rejected my server name multiple times.

It did not like:

  • “Https://myurl.com/”
  • https://myurl.com
  • “Myurl.com” (I don’t know if I actually tried this one)

What worked was just using myurl.com – no quotes, no https://

As soon as I finished the stuff above, I thought I was ‘done’ after all, the commands worked so OWA must work now right?

Kinda.

Don’t test OWA with the System account

I ran into a few more issues when I tried to test this. Remember that bit above, where I said on each OWA server, I had put in a host entry so that I could log on to the server, and test just that server? Well, I was logging on to the server as the SharePoint “System Account” – and guess what? That doesn’t work.  Now you might expect a nice error that says something like “You can’t use this as the system account” – Nope. Just a nice correlation ID to go hunt down.  And in the ULS logs what do we see? Well, nothing that indicates that I can’t use the admin – I dug it up the solution by searching the web.
So I tested with a different account which solved one problem, but it still wasn’t working…

Make sure the individual WOPI bindings match the overall zone

You configure the connection between SharePoint and OWA on the SP box by using commands like this:

New-SPWOPIBinding –ServerName dnsnameof.yourserver.com
write-host "Setting Zone"
Set-SPWOPIZone -zone "External-HTTPS"

Now, you might ask, how did I choose the zone?  There are 4 choices, and somewhere I read that if this site is going to be available internally and externally, use “External-HTTPS”

Not so fast..

As it turns out there’s another command that’s relevant here:

Get-SPWOPIBinding

This will list out a bunch of individual bindings for each file type.
Guess what those bindings said? Internal-HTTPS.

Another search on the internet and yeah, these should have been the same as the overall zone set by the Set-SPWOPIZONE command I used above.

Wanting a “quick win” it seemed faster to change the overall zone by reissuing the set-SPWOPIZone command than to figure out how to update 185 bindings. I ran this:

Set-SPWOPIZONE -zone "internal-https"

And guess what??

OWA works now.

Ok, so that sums up my first few installs of Office Web Apps 2013 and tying them to SharePoint 2013 in a multi-server OWA farm.

That’s a lot of material, lets see if i can sum this up with a nice bulleted list:

  • Use a real DNS name for your OWA box, not the machine name.
  • It’s possible to remove an OWA farm config, even though there is not a “remove-OfficeWebAppsFarm.
  • Don’t put host entries on your OWA boxes until after you’re done with the install.
  • When configuring the WOPI bindings on the SharePoint farm, don’t use https:// in the DNS name.
  • make sure the zone listed for each binding matches the zone set for the the overall connection.
  • When you test OWA, don’t use the Farm account.

– Jack

User leaves the company and users mysite is no longer accesible

This has happened to me a few times….

A user leaves and his or her AD account is deleted.

Sharepoint catches wind and marks the mysite as abandoned and emails the manager it had in User profile service, then deletes the User profile.

Then a day later someone emails the SharePoint Admin (me) and says they aren’t actually that person’s manager.

The link in the email to the mysite doesn’t work and it’s easy to think that it just auto deleted.

Checking the site with powershell (get-spsite http://mysiteurl/person/userid) shows the site collection still exists.

I found the answer at Demand Prasad’s blog.

To see the contents of the mysite, you need to be one of the two site collection admins as assigned in Central admin, but you can’t use central admin, you have to use

stsadm -o siteowner -url http://mystite/person/userid -secondarylogin domain\userid

The orignal blog post does a great job of explaining it so head over and have a read.

http://demantprasad.wordpress.com/2013/05/03/my-site-cleanup-job-and-user-not-found-error-message-in-sharepoint-2010/

Customize the SP2013 blue bar

I don’t often do a ton of link spam, but this was a great article that came up on the SPYam discussion board the other day and it was worth jotting down so I wouldn’t loose track of it.

Ryan Dennis over at Sharepointblog.co.uk figured out that the html snippet used to display the word “SharePoint” is actually an editable property of the web application, named SuiteBarBrandingElementHTML

So this would let you see it and or update it:

$app = get-spwebapplication $url
$app.SuiteBarBrandingElementHTML

Ryan wrote a nice little wrapper function around this so please give his blog a visit!.

http://www.sharepointblog.co.uk/customizing-the-sharepoint-2013-suite-bar-branding-using-powershell

 – Jack

Troublshooting a 404 error related to moving a content database

I’ve had an odd issue come up a few times now….

For one reason or another, a content database needed to be detached and then re-attached to the SharePoint farm.

The most recent need for this was so a specific content DB could me moved to a different disk on the SQL server.

In theory, the operation is pretty easy:
  • Umount the Content DB –  I did this from Central administration, Manage content databases
  • have the DBA move the DB to a new disk.
  • Mount the content DB – this is where trouble started….
Here’s what happened:

The Site collections in that DB were available on one WFE, but not the other one.

Hmm, now for the troubleshooting….

Using PowerShell, I used the command below on each WFE:

get-spcontentdatabase -webapplication http://myurl.com

Oddly, on the working WFE, my “moved” content database showed  up in the list.

On the non-working WFE it was missing.

The fix:

I tried unmounting and remounting from Central admin – no luck. (though one time the “working” WFE flipped to the other WFE!)

Next I thought I would get clever and use powershell on the broken WFE to mount it there – this didn’t work- I got an error that said the Content DB was already attached.

I also tried things like restarting IIS, Restarting the SharePoint Timer Service and Restarting the SharePoint Admin Service – no luck.

I also tried clearing the SharePoint Timer Cache – no luck either!

So Finally I unmounted it from the farm (again from CA)

Then I ran the command below on ALL nodes (WFE and APP) to confirm that it wasn’t in the farm anywhere:

get-spcontentdatabase -webapplication http://myurl.com

Finally I ran the mount-spcontentdatabase command from the Central admin box:

Mount-SPContentDatabase -name mydbname -WebApplication http://myurl.com

Note that I only had to run this once – I confirmed the Content DB was visible on all 5 boxes by re-running the get-spcontentdatabase command on each of them and all was good!

As a side note, I was lucky – Because we moved the content database, I knew what site collection to validate. Also as a habit, I log into each WFE to validate – had I used the public URL and gone through the load balancer,  would have had a 50/50 chance of seeing the problem.

To make matters worse, we have 18 content Databases in this web application. The Content database we moved was NOT the root site collection! Meaning uncaught issues would have gone unnoticed for a long time. And when the issues were discovered, they’d only apply to a single site collection and only then on a specific WFE would there be a problem. These kinds of situations are nearly impossible to figure out down the road.

So if you find yourself detaching & re-attaching content databases, be sure to test the site collections in those databases on each WFE, it could save you hours down the road.

(SharePoint 2010 SP1)