Saturday 31 August 2013

ADFS issues - ID3242: The security token could not be authenticated or authorized.

What a load of fun I had yesterday with ADFS. For some unknown reason, working web services stopped working today and after a lot of pleading we managed to get the logs from the ADFS server, which was showing this error:

 ID3242: The security token could not be authenticated or authorized.

After a lot of soul searching and hair pulling, we realized that the issue might be with the encryption certificate as the ADFS server cannot get to the CRL distribution point of the encryption certificate, due to the firewall.

This can be sorted out with these commands:
Add-PSSnapin Microsoft.ADFS.PowerShell (Import-Module ADFS - if using Win2k12 R2)  
Set-ADFSRelyingPartyTrust -TargetName <name> -EncryptionCertificateRevocationCheck None 
Set-ADFSRelyingPartyTrust -TargetName <name> -SigningCertificateRevocationCheck None 
We also set the signing certificate revocation check to none, although I think this is not needed, but there seems to be some reluctance to remove it.

Edit:

I write most of my posts well in advance and I'm not 100% that this is entirely correct. I'd like to say that I will check to make sure, but it's extremely unlikely.

Edit 2:

In our case it seems that this is indeed the solution as the ADFS server cannot get to the CRL Distribution Point, which causes issues :), which is why disabling the Revocation Checks on the certificates works.

Monday 26 August 2013

Issues with solutions in Ms Dynamics CRM 2011 - Be careful when renaming custom workflow activities

We have a couple of custom workflow activity libraries, and one of them is a bit like a helper library with about 10 custom activities and yesterday I decided to screw it all up had a brilliant idea. One of the custom activities was confusingly named as it had been extended from its original purpose of retrieving an entityreference to a custom entity, to actually create that custom entity if it could not be found, so far so good.

I then thought that a bit of control would be nice, so I added a new argument so that we could choose whether the custom entity would be created if it wasn't found.

I updated the assembly on the server using the pluginregistration tool and nothing happened, the new attribute would not appear, cue bouncing of the CRM services, still nothing. IIS went down and up and still nothing. Server does the same thing and nothing.

So bullet biting time then; I removed the custom workflow activity from the three dialogs where it was being used, thankfully at the very end of the dialogs and then deleted it using the pluginregistration tool, updated the assembly again, bounce the crm services and iis and it starts working.

Incidentally, in theory this should not be needed, i.e. adding a new argument to a workflow should just show in CRM, but this might be only if it's not in use anywhere, I don't really know, every time I have made a change like this, i.e. add or remove attributes I have had to go through the rigmarole, which is really annoying.

I fixed the dialogs back to what they were and think nothing of it, until late this afternoon, when the import of the solution to the test server fails.

We then tried doing a new import but this time we use the overwrite all customizations and still it fails, so same procedure as in the development environment, namely remove the custom workflow activity from the dialogs, remove the custom workflow activity from the server using the pluginregistration tool, then finally we were able to import the solution successfully.

The moral of the story is:

Be Careful When  Renaming Custom Workflow Activities

Wednesday 21 August 2013

Editing Active Directory user accounts from PoweShell

For reasons too long to explain I had to make changes to a few accounts (5+) today so rather than do them one by one I thought I would try using PowerShell.
Import-Module ActiveDirectory 
Get-ADUser -Filter 'name -like "*service"' | %{Set-ADUser -PasswordNeverExpires $true -Identity $_.Name}
No prices for guessing what the change needed was.

Friday 16 August 2013

Using Selenium with Microsoft Dynamics CRM 2011

Earlier this week I was asked to look at the possiblity of using Selenium with Microsoft Dynamics CRM 2011 since it now supports Firefox (nothing like a clued up Test manager). At any rate, I thought I would give it a try.

The problem was that recording tests with the Selenium IDE wasn't not working as I was hitting constant javascript errors, so I decided to use the IDE as some sort of guidance and then modify the code generated to get it to work.

The test test [sic.] was to generate an entity (change) off another (callback) and then check that depending on the change type (field pre_type) various workflows and/or plugins would trigger.

Why this needed doing with Selenium it's beyond me, but there you go.

I won't go into details about the entities, but suffice to say that callback is the main entity in the system, there is a 1:N relationship between callback and change and changes can be created from the callback form.

So, I installed Selenium, downloaded the IE driver and got coding:

using System.Text;

using OpenQA.Selenium;
using OpenQA.Selenium.Firefox;
using OpenQA.Selenium.IE;
using OpenQA.Selenium.Support.UI;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Threading.Tasks;
using System.Threading;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            IWebDriver driver = new InternetExplorerDriver(@"C:\Users\john\Downloads\selenium-dotnet-2.32.1\IEDriverServer_Win32_2.32.3\");
            driver.Url = "https://devcrm.dev.local//main.aspx?skipNotification=1";
            driver.FindElement(By.CssSelector("#pre_callback > nobr.ms-crm-NavBar-Subarea-Title")).Click();

            driver.SwitchTo().Frame("contentIFrame");

            driver.FindElement(By.Id("crmGrid_findCriteria")).Clear();
            driver.FindElement(By.Id("crmGrid_findCriteria")).SendKeys("*William*");
            driver.FindElement(By.Id("crmGrid_findCriteriaButton")).Click();

            driver.FindElement(By.Id("gridBodyTable_primaryField_{B2C895DC-DEAD-BEEF-9B08-F05056B2009F}_0")).Click();

            WaitForNewWindow(driver, 2);
            driver.SwitchTo().Window(driver.WindowHandles[1]);
            driver.SwitchTo().Frame("contentIFrame");

            driver.FindElement(By.Id("nav_pre_pre_callback_pre_change")).Click();
            driver.SwitchTo().DefaultContent();

            driver.FindElement(By.Id("pre_change|OneToMany|SubGridAssociated|Mscrm.SubGrid.pre_change.AddNewStandard-Large")).Click();

   WaitForNewWindow(driver, 3);

            driver.SwitchTo().Window(driver.WindowHandles[2]);
            driver.SwitchTo().Frame("contentIFrame");
            driver.FindElement(By.Id("DateInput")).SendKeys(DateTime.Now.ToString("dd/MM/yyyy"));
            driver.FindElement(By.Id("pre_changedetails")).SendKeys("Selenium Attack");
            
   for(int i=1; i < 6; i++
   {
                 SelectDropDown(driver, "pre_type", i);
                 driver.SwitchTo().DefaultContent();
                 driver.FindElement(By.Id("pre_change|NoRelationship|Form|Mscrm.Form.pre_change.SaveAndClose-Large")).Click();
   }
            driver.Quit();

        }

        private static void WaitForNewWindow(IWebDriver driver, int windowNumber)
        {
            while (driver.WindowHandles.Count != windowNumber)
            {
                Thread.Sleep(133);
            }
        }

        private static void SelectDropDown(IWebDriver driver, string fieldName, int selection)
        {
            IWebElement sourceWeb = driver.FindElement(By.Id(fieldName));
            SelectElement source = new SelectElement(sourceWeb);
            source.SelectByIndex(selection);
        }
    }
}

There is no reason why this could not be done as a unit test, but I thought it would be easier to distribute to the testers as a console app (It does need a lot of work, I know)

I have to say that I found it extremely flaky, in fact it seemed to need two runs, one to warm up and then it would almost always work.

Since, I haven't used Selenium much, I can't say how reliable or otherwise it is, but using the IE driver was not found suitable for testers.

I think it can be used for early morning checks and things like that but not for automated testing, all in all it was a big disappointment.

Sunday 11 August 2013

Sed equivalent in Powershell

A few days back I was trying to fix some issues with our Visual Studio solution, where the hintpaths were all wrong, so I thought it would try to use PowerShell:
ls -recurse -Include *.csproj | % {sp $_ isreadonly $false; (Get-Content $_) -replace "here","there" | Set-Content -Path $_}
A few comments to make:

% is an alias for foreach-object
sp is an alias fro Set-ItemProperty
-replace allows using regular expressions

The only downside was that I still had to check in the projects back into TFS manually, for some reason the TFS powertools would not allow me to checkout more than 2 projects at the same time, but on the plus side this is a good equivalent to Sed in PowerShell.

Tuesday 6 August 2013

Powershell one liner to check that a server is listening on a particular port

A lot of times I find myself trying to RDP to a box following a reboot only to be denied because although the box is pinging, not all services are up, so I can't connect to the box. This handy one liner helps by displaying errors until the connection on the port can be made.
$s = New-Object system.net.sockets.tcpclient; while (-not ($s.Connected)){$s.Connect("10.10.10.125",3389)}
Needless to say that if you change the port you can test any other service.

Thursday 1 August 2013

Adding comments to fetchxml queries in MS Dynamics CRM 2011

Today I learnt that it is possible to embed comments in fetchxml queries, which when you think about it is obvious, but I didn't know.

I think this can be really useful for optionsets. Mind you if you are lazy/pressed for time enough that you don't create a enum for your optionsets then it's unlikely that you are going to bother with comments, but then again you might, as adding a comment is certainly quicker than creating an enum.

Exempli Gratia:

<fetch mapping="logical" count="50" version="1.0">
 <entity name="h2h_claim">
  <filter>
   <!--2 equals customers with a medium risk rating, i.e. at least 1 claim in the last 6 months-->
   <condition attribute="h2h_risk" operator="eq" value="2" />
  </filter>
 </entity>
</fetch>