Category Archives: Troubleshooting

Trouble deleting an Azure AD App Registration?

Azure App Registrations can only be deleted if they aren’t shared.

Some app registrations have a settings screen that lets you change the shared flag, while some do not.

For those that don’t the fix is fairly easy:

Go to Azure AD in portal.azure.com, find the App registration you’re having trouble deleting.

  1. Click the manifest button
  2. Change “availableToOtherTenants” to false
  3. Click Save

Now you’ll see the ‘delete’ icon will ‘light up’ (turns from gray to black, indicating that you can use it now.

 

 

 

 

 

Hope this helps!

About Visual Studio Team Services Online

TFS online, otherwise known as VSTS, isn’t something I’ve had a lot of exposure to.

I thought I would jot down a few notes about it here..

VSTS sites all have a .visualstudio.com url – much like sharepoint online sites end in .sharepoint.com

Whereas SharePoint online is provisioned and managed via Office 365 and it’s control panel, VSTS is a bit different.

It’s provisioned in Azure, and as of this writing it’s a bit of a toss up if you’re better off using the old portal or the new – for me, the new one threw errors during provisioning, but the old ‘classic’ portal worked just fine.

Once it’s provisioned it shows up in both.

You can think of Visual Studio Team Services almost like a turnkey application you’d get from some of those web hosts that allow a single button wordpress install – you create it in Azure, but you manage it from itself, that is to say that once you’ve provisioned Visual Studio Team Services, and get a url like myVSTS.visualstudio.com, you’ll do all further configuration from that new URL – permissions, adding users, etc.

One area of confusion for me as an Azure administrator, was that I couldn’t see other Visual studio Team services in the new portal (they do show up in the old one), I also couldn’t set any meaningful permissions from either portal, making VSTS one of those services that the only way to manage it is for someone to give you rights to it after it is created.

Because of all this VSTS can be a bit of a “black box” at first – it doesn’t show up in azure like most azure services, yet it’s not managed from the office 365 portal like most of office 365.

What really helped me was to just create my own VSTS so I could see the UI, play around with it and see what it’s about.

If you do that and want to delete it later, this is also a bit perplexing. You might think you can delete it from azure since that’s where you created it, but you instead unlink an account from azure, then go to the url you were given (ie myVSTS.visualstudio.com) and go into settings and Delete the account from there.

Here’s the official article on how to delete an unneeded VSTS: https://www.visualstudio.com/en-us/docs/setup-admin/team-services/delete-or-recover-your-account-vs

  • Jack

Beware! Changes to AzureRM powershell commandlets may break your online scripts!

This week I ran into an interesting problem:

A powershell commandlet failed when run on Azure Automation Services, but it worked for me on my local machine.

It was a simple command

get-azurermsubscription

if you’re not familiar with it, it brings back a list of all the subscriptions you have access to in Azure.

The problem is, it used to return properties named “SubscriptionName” and “SubscriptionID”

These were recently changed to “Name” and “ID” causing code that used the old properties to fail.

This brings to light the importance of keeping your azureRM modules up to date on your local workstation, so you’re testing the same thing. In my case, I was using version 3.8, but 4.1 was current.

My last post listed a few commands of interest for keeping up with installed modules, as a recap, here are a few of interest:

Update-module AzureRM -force #this will fetch the latest versions of all your azureRM.* modules
get-installedmodule #lists installed modules (with a twist - it only shows the highest version you have installed if you have more than one)

One problem I ran into today: After updating all my Modules, powershell was slow as can be.  I had installed updated versions, but hadn’t removed the old ones.

Maybe there is a better way, and if so, please comment below, but I ended up creating a small script to remove prior versions. For findability, that’ll be in my next post.

 

An o365 Support case that was handled so quickly, I had to write about it!

I was so impressed with how fast this was turned around, I had to write about it…

A special shout out to Microsoft Sr. Escalation Engineer Sridhar Narra and the support team including Linda PorcelliLoren Jacobson and Tiffany Evenson who worked to resolve this issue so quickly!

Apparently in email addresses, the single quote is a legal character.

So names like: Bill.O’Brian@yourcompany.com are legal in the email sense.

Addresses like this can cause havoc on programmers.

Well it turns out that we had a few people like this in our company and this did not play well with Office 365 at all.

The first, and easiest thing we noticed was that if you found a person like Bill O’Brian in search and tried to click on them, the profile page for the user threw an error.

We opened a case with Microsoft and I was expecting something short like “Don’t use quotes in your email” but instead, they looked into and fixed it. FAST.

I’m used to changes in o365 taking 3 months to make it from ticket to production, this one took a few weeks, from the time we opened the ticket, to the time the issue was resolved in production.

This is a pace of improvement and change I’ve not seen until now and it’s really exiting to see things get fixed this quickly!

A special shout out to Microsoft Sr. Escalation Engineer Sridhar Narra and the support team including Linda Porcelli, Loren Jacobson and Tiffany Evenson who worked to resolve this issue so quickly!

As a side note, a  quotation mark in an email address has issues in other places of SharePoint. Our case was split into several cases. Sridhar’s team worked on the profile page, There’s another team looking at another case which I’ll update in the future when I have more information.  If your organization has issues similar to this, please open a premier ticket.

– Jack

 

Start off 2015 by fixing a messed up edit page in SP2007…

It’s the start of 2015…

Who needs the cloud, SP2013 or even SP2010! It’s time to get sucked into a support issue on a legacy SP2007 site 🙁

One of our legacy SP2007 sites had a custom list with an edit page that got corrupted.

Seems a user might have edited the edit page, and removed the web part that makes the edit page an edit page.

The solution wasn’t exactly quick or easy – I hadn’t worked with SP2007 in a long while and neither did our support engineer at Microsoft.

We ended up solving the issue ourselves.  We have 3rd tier support with Microsoft, which has been great on the 2010 and 2013 side, but in this case the product in question is 2007 and I can’t say I blame Microsoft if all the people who were good at 2007 have moved on to other things by now.

Here’s a rough outline of what we did:

1) The EditForm.aspx page was broken

2) A known good DB backup of the site was recovered in a test environment  – this had a good copy of the form.

3) The good working list in the test environment was saved as a template with and without data in the test environment. The STP file was then copied to production

5) In production, in the same sitecollection/subweb, a new empty user list was created, using the template file that was imported from the test environment. One test record was created (ID=1) so that we could validate that the restored, empty,  list worked.

6) SharePoint designer had to be enabled on production – it was found to be disabled via the onet.xml file for the STS template http://support.microsoft.com/kb/940958

7) Using some of the ideas from this article: http://hightechdave.com/recover-newform-aspx-from-the-dead-in-sharepoint-2007/

8) Editing the HTML of the broken EditForm.aspx in SharePoint Designer 2007,  We copied the webpart section from the restored ‘good’ list over to the ‘bad’ list. Note: this MUST be done in SharePoint Designer – editing the files from explorer will not work because part of this file is stored in the content database.

9) Saved the broken EditForm.aspx list and looked at it – it worked but referenced data from the new ‘good’ list (I had to construct the edit URL by hand, based on the edit url of the restored list, since the edit links on our allitems page were also broken…)

10) Edited the broken EditForm.aspx and also opened the newform.aspx page from the same list (the original list with the problem) in SharePoint Designer’s ‘code/html’ view.

11) Copied the guid from the NewForm.aspx to the EditForm.aspx

12) Saved it and looked at it.

13) Edited the broken EditForm.aspx in SPD and changed the title in the webpart to the name of the list –

14) Saved it and it was fixed.

Note some things that did not work:

The article mentioned using a new GUID – that failed for me.

Also, when I pasted the webpart code in AND changed the list guid AT THE SAME TIME – it did not work. It seemed I needed to save it after pasting in the list, then go back and edit it.

And last but not least, I remember having to change the title on the webpart (via SPD’s html editor) before the webpart displayed correctly. And I think there might be a chance that doing it at the same time as another change didn’t work – for all I know it would have/should have and I just made a mistake when I tried to do it all at once, but it definitely worked when done as described above.

Ok time to get back to 2015 and start working on some SharePoint Online initiatives!

– Jack

Sync an Active Directory Group with a SharePoint Group

Have you ever wanted to keep the members of a SharePoint group in sync with those of an Active Directory Group?

If so, you’re in luck, I happen to have just such as script.

Just a quick note, this was written for and tested on a 2010 site – in 2013, the default authentication is Claims – those funny looking strings like this: “i:0#.w|domain\user” (more info here) and you’ll need to work this script over a few times to make that work.

That said, this script will keep a SharePoint group in sync with an AD group.

The AD group is considered the “master”

That is to say, if the AD group has extra users that aren’t in SharePoint, they will be added to SharePoint.

If a user is removed from the AD group, they will also be removed from the SharePoint Group.

If a user is added to the SP Group, but isn’t in the AD group? They will be removed from the SP group.

This is one of those scripts that makes sense to run as a scheduled task once you get it working.  If you need help with that, see my post: Schedule your PowerShell scripts using the Windows task scheduler.

#AD to SharePoint Sync Script
#Jack Fruh 2014 Sharepointjack.com
write-host "NOTE: This has only been tested on NTLM authentication - it will likely need work to work with claims based authentication in 2013" -foregroundcolor red

function main()
{   
    #setup the environment so this can run as a schedule task:
    #note that the AD PowerShell Commands must be installed on the SharePoint Server for this to work.
    Write-host "note that the AD PowerShell Commands must be installed on the SharePoint Server for this to work." -foregroundcolor blue
    Write-host "Adding SharePoint Snapin"
    $Host.Runspace.ThreadOptions = "ReuseThread"
    Add-PSSnapin microsoft.sharepoint.powershell -ErrorAction SilentlyContinue
    Write-host "Importing AD module"
    import-module activedirectory

    write-host "Starting work..."
    #Hard coded variables for testing, 
    # we need the name of the AD Group, the name of the corresponding group in Sharepoint to sync with, and the URL of the SPWeb where the SP group resides.
    $ADgroupname = "TheGroup"
    $SPGroupName = "SyncMeWithAD"
    $spweburl = "http://sharepoint2010"
    #note that it's reasonably easy to turn this hardcoded list into a CSV import and then loop through multiple groups

    #get a list of the AD Users in the AD Group
    #$ADGroupMembers = get-adgroupmember -Identity $ADgroupname | select @{name="LoginName";expression={$_.samaccountname}}
    $ADGroupMembers = get-adgroupmember -Identity $ADgroupname | select @{name="LoginName";expression={$(getDomain($_.distinguishedName)) + "\" +  $_.samaccountname.toupper()}}
    if ($ADGroupMembers -eq $null)
    {
        write-host "The AD Group we're syncing with is empty - this is usually a problem or typo - the SP group will be left alone" -foregroundcolor red
        exit
    }


    #get the list of users in the SharePoint Group
    $web = get-spweb $spweburl
    $group = $web.groups[$SPGroupName]
    if ($group -eq $null) {write-host "SPGroup Not found" ; exit }
    $spusers = $group.users | select @{name="LoginName";expression={$_.LoginName.toupper()}}
  
    write-host "Debug: at this point we should have a list of user ID's from SharePoint in domain\user format, uppercase" 
    foreach($x in $spusers)
    {
        write-host $x.LoginName -foregroundcolor green
    }
  
    if($spusers -eq $null)
    {
      write-host "The SPgroup is empty" -foregroundcolor cyan
      write-host "Adding all AD group members to the SP group"
      foreach ($ADGroupMember in $ADGroupMembers)
      {
            #add the AD group member to the SP group
            write-host "Adding $($ADGroupMember.LoginName)" 
            write-host "new-spuser -useralias $($ADGroupMember.LoginName) -web $($web.url) -group $SPGroupName" -foregroundcolor green
            new-spuser -useralias $ADGroupMember.LoginName -web $web.url -group $SPGroupName
           # $web.site.rooteweb.ensureUser($ADGroupMember.loginname)
            set-SPuser -identity $ADGroupMember.LoginName -web $web.url -group $spgroupname
            
      }
      write-host "Done adding users - script will now exit" -foregroundcolor magenta
      exit
    }

    #use compare-object to get a listing of what's different between AD and SP
    write-host "Comparing AD Group Users to SP group Users"
    $result = compare-object -referenceobject $adgroupmembers -differenceobject $spusers  -includeequal -property LoginName

    Write-host "Result of comparison is:"
    $result
    write-host "-------------------------"
    
  
    

    #filter the results of the comparison to show only the users that need to be added
    Write-host "Looking for users in AD that we need to add to SharePoint"
    $missingSPusers = $result |  Where {$_.SideIndicator -eq '<='} | select LoginName #users in AD that are missing from SharePoint
    if ($missingSPusers -ne $Null)
    {
        foreach ($missingSPuser in $missingSPusers)
        {
            write-host "Adding $($missingSPUser.LoginName) to sharepoint"
            write-host "new-spuser -useralias $($missingSPuser.LoginName) -web $($web.url) -group $SPGroupName" -foregroundcolor green
            new-spuser -useralias $missingSPuser.LoginName -web $web.url -group $SPGroupName
            set-SPuser -identity $missingSPuser.LoginName -web $web.url -group $spgroupname
        }
    }
    
    #now do the reverse
    #Filter the results of the comparison to show 'extra' users that need to be removed
    write-host "Looking for Extra users in SharePoint that are not in AD"
    $extraSPusers = $result |  Where {$_.SideIndicator -eq '=>'} | select LoginName #users in AD that are missing from SharePoint
    if ($extraSPusers -ne $null)
    {
        foreach ($extraSPuser in $extraSPusers)
        {
            write-host "Removing $($extraSPuser.LoginName) to sharepoint"
            Remove-SPUser -useralias $($extraSPuser.LoginName) -Web $web -group $SPGroupName -confirm:$false
        }
    }
} # end main function

function getDomain($distinguishedname)
{
  $dn = $distinguishedname
  #extract Domain name from Distinguished name
  #Domain name should be the first DN= Entry from left to right.
  #Examples:  CN=BOB,OU=Users,DN=DomainShortName,DN=Com
  #Examples:  CN=BOB,OU=Users,DN=DomainShortName,DN=Forrest,DN=Com
  $start = $dn.indexof(",DC=")+4 #find the first occurance of DC in the Distinguishedname  
  $end = $dn.indexof(",",$start)  #find the first comma, this is the end of the domain name
  $domain = $dn.substring($start, $end-$start).toupper()
  return $domain
}

main

Now for a friendly reminder and some advice…
#1) Always test code you find online before using it in production…
#2) when you test this code, follow this advice:

Testing this code

When you test the code, you might make a mistake I made during development – I’ll share that mistake with you to save you an hour of time and some frustration.

Here’s what I did…

While testing, I wanted to try adding users to an AD group and wanted to make sure they added in correctly.

For one test I wanted to remove ALL the users from the SharePoint Group, and confirm that they came back ok.

To do this I used the UI to remove all the users – I checked each user, then clicked “actions->remove users from group” like this:
removeusersscreenSP2010

I then ran my Super Awesome AD Sync PowerShell Script which Added the groups back in.

Now here’s where it got ugly.

When I checked the UI, they weren’t there.

In fact, if I ran the powershell script again it indicated that they were being added back a second time (the script should have told me there was nothing to change!)

What was the cause?

It was my use of the refresh button…refresh in IE

Recall that the very last thing I did was remove users using that screen.

Now interestingly, you know how we all click “OK” on a screen without paying attention?

After I hit refresh, I got this, and ignored it:
dialogIshouldhaveread

See what I did there?

I was refreshing the delete in the UI!

Don’t make that mistake!

Instead of clicking the refresh button, it’s easier (and safer) to click the group name on the left:
dontclickrefreshwhenyoudelete

Lessons learned:

  • Pay attention to dialog boxes, they may save you an hour.
  • Don’t ever click ‘refresh’ after performing a delete!

 

SharePoint ULS logs Tips, Tricks, and Thoughts

ULS logs are where SharePoint logs what’s happening, they are plain text files.

Here are a few thoughts on optimizing your workflow when dealing with the ULS logs.

#1 – Know where your logs are.

In Central administration, under Monitoring->Diagnostic Logging, you can set the path for the ULS logs – this sets the path for EVERY server in your farm, so you’ll need to ensure the drive letter exists and has space on EACH server. In general, you don’t want these on the C: Drive, which unfortunately, is the default. I put them in a folder called d:\Sharepoint_Logs

#2 – Don’t log more than you need to!

ULS log files can be HUGE – on the Diagnostic Logging screen (Central admin->Monitoring->Diagnostic Logging) consider doing the following:

  • Under “Event throttling” select “All Categories” then pull the drop downs in that section to “Reset to Default”
  • Under the “Trace Log” area, set the number of days to something reasonable – Ie decide how far back you’d be willing to go to look at a problem, in many cases, 7 days should be sufficient.
  • Under the “Trace Log” area, Restrict Trace Log Disk Space – My Log drive is 80GB, but it’s also shared with a few other logs like the usage logs, and some CSV’s I generate with PowerShell – so I limit ULS logs to 40GB

#3 – Use the ULS Log Viewer.

There have been several of these types of viewers made, but there is “the one” that everyone always uses and that’s available here: http://www.toddklindt.com/ulsviewer

This used to be on Codeplex, but sadly, it wasn’t updated and Codeplex auto-deleted it. Todd was gracious enough to put a copy on his site so others can continue to use this great tool.

Personally, I keep a copy of the ULS Log Viewer right in the folder with the ULS logs- that way it’s nice and handy.

What the ULS logviewer does, is parse the log file and display it in a very user friendly way – I used to use Notepad++ to look at the logs and this is much much better for logviewing.  It has the option of opening a log file, or of opening the ULS logs in real time. One nice thing about it, is it seems to “Know” where your ULS logs are, so you can open the current one without having to go through a bunch of mouse clicks. It’s also great at letting you filter the logs, for example, seeing only the critical events.

#4 – PowerShell related ULS commands

There are a few PowerShell commands for the ULS logs that can be handy to know about. This MSDN page talks about all of them, below you’ll find a few that I’ve personally used with a longer explanation than whats on MSDN.

Merge-SPLogFile

What this one does, is combines all the ULS log file entries from all the servers in your farm, and merges them down to a single file on the box where the command was run – very helpful for tracing issues between boxes on your farm.

There are a lot of ways to use the command so try get-help Merge-SPLogfile -detailed to get the finer details (In particular, note the -starttime and -endtime parameters so you are only merging managable amounts of data!)

Also a quick search found this great article by Cecildt with screenshots and lots more detail than I have here: http://cecildt.blogspot.com/2012/10/sharepoint-2010using-merge-splogfile-to.html

New-SPLogFile

This command Closes the current ULS log file and starts a new one. To my knowledge it only does this on the server where you’ve run the command (ie if you have 3 servers, you’ll need to run on each one)  I’ve used this before when looking at a system in real time with a support person from MS- We ran this command to reset the log file, then recreated a problem, then ran the command again – and what we were left with was a very nice small ULS log that was reasonably timeboxed around the event we were investigating. We could have done the same with Merge-SPlogfile by setting times, but that command is slower, and we would have needed to jot down the start and end times.  In other words, New-SPlogfiles doesn’t do anything you couldn’t do with other tools, it just makes it easier under the right circumstances.

– 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