I have some PowerShell scripts that run PreRequisiteInstaller.exe, Setup.exe, and then configure a farm based on an XML configuration file. I noticed that if Setup.exe did not prompt for a reboot, that my script would fail with the following error directly after Setup.exe completed. The line that is failing is the Add-PSSnapIn Microsoft.SharePoint.PowerShell line :
The local farm is not accessible. Cmdlets with FeatureDependencyId are not registered.
No xml configuration files loaded.
The type initializer for 'Microsoft.SharePoint.Utilities.SPUtility' threw an exception.
Add-PSSnapin : The type initializer for 'Microsoft.SharePoint.Utilities.SPUtility' threw an exception.
If I leave the PowerShell instance running, I can reproduce the error over, and over, and over… The workaround is pretty easy, you open a new instance of PowerShell, and the Add-PSSnapIn command works. The trouble with that approach is that I’m trying to automate work, and avoiding errors is what it’s all about. I was also going for a single PowerShell window experience, and that’s not going to work with any workaround to launch multiple processes. Before resigning to a workaround, I decided to dig into this a bit. I was hoping that an environment variable or registry key was missing that I could fix-up with my script, as a lot of that info typically is read when the process starts.
Since the error mentioned that xml files were not being loaded, I started trying to figure out which XML files are being referred to. I came across this blog that points out the SharePoint PowerShell DLL loads XML files from the 14\CONFIG\POWERSHELL\Registration directory [as well as some other nifty info about SharePoint working with PowerShell]. With that info, I ran Process Monitor while reproducing the error. Sure enough, the PowerShell process never even tries to read the XML files when it throws that error. I can see the process load Microsoft.SharePoint.PowerShell.dll from the GAC, but the process stops doing work after that. It’s starting to look like the “No xml configuration files loaded” error was right… 🙂
I then break out WinDbg.exe to try and see what is really happening in the process. I attach to the process, load PSSCor2.dll, and run SXE CLR to break on .Net exceptions. I reproduce the error, and find an exception is being thrown. Dumping out the exception, the process is actually having issues loading System.Core.dll [wasn’t expecting that at all]
0:017> !pe 00000000032bb160
Exception object: 00000000032bb160
Exception type: System.IO.FileNotFoundException
Message: Could not load file or assembly 'System.Core, Version=126.96.36.199, Culture=neutral, PublicKeyToken=b77a5c561934e089' or one of its dependencies. The system cannot find the file specified.
SP IP Function
000000001D61B0E0 0000000000000001 Microsoft_SharePoint!Microsoft.SharePoint.Utilities.SPReaderWriterLock..ctor(System.String)+0x2
000000001D61B1B0 000007FF002E73A2 Microsoft_SharePoint!Microsoft.SharePoint.Utilities.SPProcessContext..cctor()+0x32
I look at the top of the managed stack, the snap in has loaded, it’s trying to load the farm, and blowing up cause it can’t find the System.Core assembly.
OS Thread Id: 0x5bc (17)
Child-SP RetAddr Call Site
000000002163dc60 000007ff002e0a7c Microsoft.SharePoint.Administration.SPFarm.FindLocal
000000002163dcf0 000007ff002e02ad Microsoft.SharePoint.Administration.SPWebService.get_ContentService
000000002163dd90 000007feec7f02e4 Microsoft.SharePoint.PowerShell.SPCmdletSnapIn.get_Cmdlets
Process Monitor is not showing the PowerShell process even probing for the DLL, and the module is not loaded into PowerShell already. The System.Core.DLL is in the GAC using the strong name information in the exception. I confirm my account has no issues loading the assembly as opening a new instance of PowerShell, with Windbg.exe attached, and running Add-PSSnapIn confirms the modules load without error.
At this point, I decided to just work around the problem, as I was actually trying to get some work done. Maybe if I can’t sleep in the future, I’ll dig into why the process is not trying to load the DLL, but that will have to wait for another day.
My workaround was to have a launcher script. This script’s purpose was to launch new PowerShell processes, passing in a PS1 file to run. I already had my scripts split up by functionality, so it wasn’t a lot of work to call the installation PS1 file, then when that script completed, open another PowerShell instance for the configuration scripts. Here’s an example of what that script looks like.