Author Archives: Lorenzo Soncini

About Lorenzo Soncini

Hello world!

MCT SUMMIT 2017 – Windows Containers

I’m start working on my presentation for the summit in Thessaloniki.

Container are a completely new feature in Windows.Was introduced in Windows Server 2016 and with Windows 10 anniversary update. The advantage use is application isolation, lightweight, resource effective.

My session is about 45 minute and the agenda is:

  • Virtual Machine and Container
  • Docker introduction
  • Build Ship and Run
  • Microsoft ASP.NET 4.x apps in container

Using new C# 7 tuple

I have read the blog from Microsoft who explain the new feature of C#

https://blogs.msdn.microsoft.com/dotnet/2017/03/09/new-features-in-c-7-0/

For my experiment I would like use the new c# tuple on a MVC project build on .Net Framework 4.6.2

For this after some google time I have discovered the need of:

Add NUGET package System.ValueTuple

Add NUGET pakage Microsoft.CodeDom.Providers.DotNetCompilerPlatform

All works when use the designer all works fine but when I try to build my MVC project I receive the error :

CS0012: The type ‘System.Object’ is defined in an assembly that is not referenced. You must add a reference to assembly ‘System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a’.

So I’m looking and the solution is:

Update the NUGET package Microsoft.Net.Compilers to version 2.0.1

After that you need to tell Visual Studio 2017 use c# 7. To do that right click on the project, select properties.

VS2017ProjectProperties

Go to the menu on the right of the properties windows and chose Build. Scroll down and on the bottom right of the windows click on the button “Advanced…”

Now you can choose the language version:

VS2017ProjectPropertiesBuildAdvanced

 

Brief history….and future 2017

Hello Everybody,

I have start working during the studies at University of Bologna in the city of Cesena in 1995 as “system manager” with the beginning of internet (the first internet access was a shared modem 56k on a network when NetBeui was a network protocol and Novell as the best server system…).

In 1998 I become a certified MCSE (Microsoft Certified System Engineer on Windows NT 4.0 and Exchange 5.5).

In 2008 I have start work on Dynamics CRM 4 and the first data analysis system and begin my hybrid view.

In 2015 he returned student at the University of Bologna attending MBA Professional XVII edition.

In 2016 I decided to take Dynamics NAV and reorganize all the processes and strategies of my company (www.zzsoft.it)

In 2017…
30 % is system (Windows 2016, SharePoint, Exchange and cloud)
30 % is business analytics (Data science…)
30 % is Dynamics CRM, NAV…..AX ??
10 % is a mix of activities

 

Microsoft Certified Trainer – Regional Lead 2016

Per questo 2016 sono stato selezionato per essere MCT Regional Lead in Italia assieme al collega Ruggiero Lauria (Congratulazioni! … ad entrambi).

Passato l’entusiasmo ed un po’ di orgoglio per l’opportunità ricevuta e l’entusiasmo per la sfida che ne consegue, nella mente si materializza la domanda fondamentale: ed ora che si fa?

Leggendo dal sito:

“The MCT Regional Leads play a key part in helping Microsoft serve the global MCT Community through community leadership, mentoring support, and engagement with Microsoft. Additionally, the MCT Program relies on the MCT Regional Leads for input on program changes, organizing events, forum engagement, and helping to disseminate key communication to the broader community.”

In sostanza siamo stati creati per fare da aggancio tra Microsoft e la comunità MCT.  Quindi devo sapere dai vari MCT cosa pensano Microsoft possa fare per migliorare  il nostro lavoro.

Parto con il condividere il mio pensiero.

Il mondo cambia intorno a noi, oggi la formazione on line fatta di materiale multimediale è una realtà e sta diffondendosi nel mondo. La qualità sta aumentando,  sempre più completa e facile da usufruire.

Ed in Italia?

Per ora siamo difesi dalla scarsa conoscenza (o meglio voglia di affaticarsi) dell’inglese (lingua nella quale si trovano la maggior parte dei materiali) ma sicuramente anche da noi le cose cambiano e cambieranno…
La mia esperienza mi insegna che avremo sempre meno formazione d’aula “generica”  e corsi a calendario.
Unite  le due considerazione e credo che si giunga alla conclusione che assisteremo alla scomparsa del classico corso d’aula sul prodotto. (Quei MOC, Microsoft Official Curriculum, che hanno fatto crescere migliaia di professionisti…)

E per gli MCT cosa succede? Il nostro è uno dei lavori che le nuove tecnologie andranno a cancellare?
Parafrasando Gaber: oggi no, domani forse, ma dopodomani sicuramente!
Quindi la risposta è si, se non sapremo adattarci all’evoluzione del nostro “ecosistema”.

Personalmente sto portando avanti una decisa riorganizzazione del mio lavoro di formatore e della divisione che si occupa di formazione all’interno di ZZ Soft.
Nel nostro futuro vedo tre aree trainanti:

  1. Formazione a distanza
  2. Formazione a personale IT a seguito di specifici interventi progettuali
  3. Produzione di contenuti multimediali per la formazione utente finale facilmente usufruibile e distribuibile

Condiviso il mio pensiero mi vengono in mente le cose più pratiche e meno filosofiche:
Rapporto MCT e mondo Dynamics ? Ha senso oggi per un MCT puntare sul mondo Dynamics ….

Beh spero che altri si uniranno nella condivisione di idee in proposito. Buon lavoro a tutti!

Lorenzo

Dynamics CRM 2015 : some simple javascript function

// JavaScript CRM 2015 code
if (typeof (ZZSOFT) == “undefined”)
{ ZZSOFT = { __namespace: true }; }
if (typeof (ZZSOFT.CRM) == “undefined”)
{ ZZSOFT.CRM = { __namespace: true }; }
ZZSOFT.CRM.Common = {
//
// Disable all control inside the form
//
disableAllControls: function () {
  Xrm.Page.data.entity.attributes.forEach(function (attribute, index) {
    ZZSOFT.CRM.Common.disableCtrl(attribute.getName());
  });
},
//
// Enable all control inside the form
//
enableAllControlss: function () {
  Xrm.Page.data.entity.attributes.forEach(function (attribute, index) {
    ZZSOFT.CRM.Common.enableCtrl(attribute.getName());
  });
},
//
// Disable e single control on form and business process bar if it is present
// ctrlName = Control name
disableCtrl: function (ctrlName) {
  var c = Xrm.Page.getControl(ctrlName);
  if (c != null) {
    c.setDisabled(true);
  }
  var hpc = Xrm.Page.getControl(“header_process_” + ctrlName);
  if (hpc != null) {
    hpc.setDisabled(true);
  }
},
//
// Enable single control on form and business process bar if it is present
// ctrlName = Control name
enableCtrl: function (ctrlName) {
  var c = Xrm.Page.getControl(ctrlName);
  if (c != null) {
    c.setDisabled(false);
  }
  var hpc = Xrm.Page.getControl(“header_process_” + ctrlName);
  if (hpc != null) {
    hpc.setDisabled(false);
  }
},
//
// Hide single control on form and business process bar if it is present
// ctrlName = Control name
hideCtrl: function (ctrlName) {
  var c = Xrm.Page.getControl(ctrlName);
  if (c != null) {
    c.setVisible(false);
  }
  var hpc = Xrm.Page.getControl(“header_process_” + ctrlName);
  if (hpc != null) {
    hpc.setVisible(false);
  }
},
//
// Show single control on form and business process bar if it is present
// ctrlName = Control name
showCtrl: function (ctrlName) {
  var c = Xrm.Page.getControl(ctrlName);
  if (c != null) {
    c.setVisible(true);
  }
  var hpc = Xrm.Page.getControl(“header_process_” + ctrlName);
  if (hpc != null) {
    hpc.setVisible(true);
  }
},
//
// Hide section
// sectionName = Name of the section
hideSection: function (sectionName) {
  var tabs = Xrm.Page.ui.tabs.get();
  for (var i in tabs) {
    var tab = tabs[i];
    tab.sections.forEach(function (section, index) {
      if (section.getName() == sectionName) {
        section.setVisible(false);
      }
    });
  }
},
//
// Show section
// sectionName = Name of the section
showSection: function (sectionName) {
  var tabs = Xrm.Page.ui.tabs.get();
  for (var i in tabs) {
    var tab = tabs[i];
    tab.sections.forEach(function (section, index) {
      if (section.getName() == sectionName) {
        section.setVisible(true);
      }
    });
  }
},
//
// Hide tab
// tabName= Name of the tab
hideTab: function (tabName) {
  var tabs = Xrm.Page.ui.tabs.get();
  for (var i in tabs) {
    var tab = tabs[i];
    if (tab.getName() == tabName) {
      tab.setVisible(false);
    }
  }
},
//
// Show tab
// tabName= Name of the tab
showTab: function (tabName) {
  var tabs = Xrm.Page.ui.tabs.get();
  for (var i in tabs) {
    var tab = tabs[i];
    if (tab.getName() == tabName) {
      tab.setVisible(true);
    }
  }
},
__namespace: true
}

Microsoft Dynamics CRM 2015 and javascript

During my last Dynamics CRM 2015 project I have made many customizations using JavaScript. I have found some difficult retrieve and discover information regarding the different “SOAP” messages used by the Organization Services. I have attached to this post a modified file of the Microsoft SDK with more message and function. Inside the namespace “SDK.SOAPSamples” I have added three synchronous call to the organization  service of Dynamics CRM 2015.

  • SDK.SOAPSamples.assignEntitySync: function (recordId, recordType, newOwnerId)Assign the record identify by recordId (the guid of the record) and recordType (logicalname of the entity) at the user with the newOwnerId (the guid of the user)
  • SDK.SOAPSamples.changeEntityStateSync: function (recordId, recordType, stateCode, statusCode)Change the Statecode (int value) and Statuscode (int value) of the record identify by recordId (the guid of the record) and recordType (logicalname of the entity)
  • SDK.SOAPSamples.loseOpportunityRequest: function (recordId, comment) Close the opportunity identified by recordId (the guid of the opportunity) and add the comment (a string)
  • SDK.SOAPSamples.closeQuoteSync: function (quoteId, statusCode, closeNote)Close the quote identified by quoteId (the guid of the quote) with the statusCode (int value) and add the comment (closeNote is string)

ATTENTION: The function need to be correct for a production environment. For example if someone use a comment like “Hello ‘ word “” probably the system return an error.
PS. I’m unable attach the script. Send me a message and I send you the script. In the future I post it in OneDrive or DropBox
SDK.SOAPSamples = {
_getClientUrl: function () {
///<summary>
/// Returns the URL for the SOAP endpoint using the context information available in the form
/// or HTML Web resource.
///</summary
var OrgServicePath = "/XRMServices/2011/Organization.svc/web";
var clientUrl = "";
if (typeof GetGlobalContext == "function") {
var context = GetGlobalContext();
clientUrl = context.getClientUrl();
}
else {
if (typeof Xrm.Page.context == "object") {
clientUrl = Xrm.Page.context.getClientUrl();
}
else { throw new Error("Unable to access the server URL"); }
}

return clientUrl + OrgServicePath;
},
assignRequest: function (Assignee, Target, Type, successCallback, errorCallback) {
///<summary>
/// Sends the Assign Request
///</summary>
this._parameterCheck(Assignee, "GUID", "The SDK.SOAPSamples.assignRequest method Assignee parameter must be a string Representing a GUID value.");
///<param name="Assignee" Type="String">
/// The GUID representing the System user that the record will be assigned to.
///</param>
this._parameterCheck(Target, "GUID", "The SDK.SOAPSamples.assignRequest method Target parameter must be a string Representing a GUID value.");
///<param name="Target" Type="String">
/// The GUID representing the user-owned entity record that will be assigne to the Assignee.
///</param>
this._parameterCheck(Type, "String", "The SDK.SOAPSamples.assignRequest method Type parameter must be a string value.");
Type = Type.toLowerCase();
///<param name="Type" Type="String">
/// The Logical name of the user-owned entity. For example, 'account'.
///</param>
if (successCallback != null)
this._parameterCheck(successCallback, "Function", "The SDK.SOAPSamples.assignRequest method successCallback parameter must be a function.");
///<param name="successCallback" Type="Function">
/// The function to perform when an successfult response is returned.
///</param>
this._parameterCheck(errorCallback, "Function", "The SDK.SOAPSamples.assignRequest method errorCallback parameter must be a function.");
///<param name="errorCallback" Type="Function">
/// The function to perform when an error is returned.
///</param>
//The request is simply the soap envelope captured by the SOAPLogger with variables added for the
// values passed. All quotations must be escaped to create valid JScript strings.
var request = [];

request.push("<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">");
request.push("<s:Body>");
request.push("<Execute xmlns=\"http://schemas.microsoft.com/xrm/2011/Contracts/Services\"");
request.push(" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">");
request.push("<request i:type=\"b:AssignRequest\"");
request.push(" xmlns:a=\"http://schemas.microsoft.com/xrm/2011/Contracts\"");
request.push(" xmlns:b=\"http://schemas.microsoft.com/crm/2011/Contracts\">");
request.push("<a:Parameters xmlns:c=\"http://schemas.datacontract.org/2004/07/System.Collections.Generic\">");
request.push("<a:KeyValuePairOfstringanyType>");
request.push("<c:key>Target</c:key>");
request.push("<c:value i:type=\"a:EntityReference\">");
request.push("<a:Id>" + this._xmlEncode(Target) + "</a:Id>");
request.push("<a:LogicalName>" + this._xmlEncode(Type) + "</a:LogicalName>");
request.push("<a:Name i:nil=\"true\" />");
request.push("</c:value>");
request.push("</a:KeyValuePairOfstringanyType>");
request.push("<a:KeyValuePairOfstringanyType>");
request.push("<c:key>Assignee</c:key>");
request.push("<c:value i:type=\"a:EntityReference\">");
request.push("<a:Id>" + this._xmlEncode(Assignee) + "</a:Id>");
request.push("<a:LogicalName>systemuser</a:LogicalName>");
request.push("<a:Name i:nil=\"true\" />");
request.push("</c:value>");
request.push("</a:KeyValuePairOfstringanyType>");
request.push("</a:Parameters>");
request.push("<a:RequestId i:nil=\"true\" />");
request.push("<a:RequestName>Assign</a:RequestName>");
request.push("</request>");
request.push("</Execute>");
request.push("</s:Body>");
request.push("</s:Envelope>");

var req = new XMLHttpRequest();
req.open("POST", SDK.SOAPSamples._getClientUrl(), true)
// Responses will return XML. It isn't possible to return JSON.
req.setRequestHeader("Accept", "application/xml, text/xml, */*");
req.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
req.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/Execute");
req.onreadystatechange = function () { SDK.SOAPSamples.assignResponse(req, successCallback, errorCallback); };
req.send(request.join(""));

},
assignResponse: function (req, successCallback, errorCallback) {
///<summary>
/// Recieves the assign response
///</summary>
///<param name="req" Type="XMLHttpRequest">
/// The XMLHttpRequest response
///</param>
///<param name="successCallback" Type="Function">
/// The function to perform when an successfult response is returned.
/// For this message no data is returned so a success callback is not really necessary.
///</param>
///<param name="errorCallback" Type="Function">
/// The function to perform when an error is returned.
/// This function accepts a JScript error returned by the _getError function
///</param>
if (req.readyState == 4) {
req.onreadystatechange = null; //avoids memory leaks
if (req.status == 200) {
if (successCallback != null)
{ successCallback(); }
}
else {
errorCallback(SDK.SOAPSamples._getError(req.responseXML));
}
}
},
_getError: function (faultXml) {
///<summary>
/// Parses the WCF fault returned in the event of an error.
///</summary>
///<param name="faultXml" Type="XML">
/// The responseXML property of the XMLHttpRequest response.
///</param>
var errorMessage = "Unknown Error (Unable to parse the fault)";
if (typeof faultXml == "object") {
try {
var bodyNode = faultXml.firstChild.firstChild;
//Retrieve the fault node
for (var i = 0; i < bodyNode.childNodes.length; i++) {
var node = bodyNode.childNodes[i];

//NOTE: This comparison does not handle the case where the XML namespace changes
if ("s:Fault" == node.nodeName) {
for (var j = 0; j < node.childNodes.length; j++) {
var faultStringNode = node.childNodes[j];
if ("faultstring" == faultStringNode.nodeName) {
errorMessage = faultStringNode.textContent;
break;
}
}
break;
}
}
}
catch (e) { };
}
return new Error(errorMessage);
},
_xmlEncode: function (strInput) {
var c;
var XmlEncode = '';

if (strInput == null) {
return null;
}
if (strInput == '') {
return '';
}

for (var cnt = 0; cnt < strInput.length; cnt++) {
c = strInput.charCodeAt(cnt);

if (((c > 96) && (c < 123)) ||
((c > 64) && (c < 91)) ||
(c == 32) ||
((c > 47) && (c < 58)) ||
(c == 46) ||
(c == 44) ||
(c == 45) ||
(c == 95)) {
XmlEncode = XmlEncode + String.fromCharCode(c);
}
else {
XmlEncode = XmlEncode + '&#' + c + ';';
}
}

return XmlEncode;
},
_parameterCheck: function (parameter, type, errorMessage) {
switch (type) {
case "String":
if (typeof parameter != "string") {
throw new Error(errorMessage);
}
break;
case "Function":
if (typeof parameter != "function") {
throw new Error(errorMessage);
}
break;
case "EntityFilters":
var found = false;
for (x in this.EntityFilters) {
if (this.EntityFilters[x] == parameter) {
found = true;
break;
}
}
if (!found) {
throw new Error(errorMessage);
}
break;
case "Boolean":
if (typeof parameter != "boolean") {
throw new Error(errorMessage);
}
break;
case "GUID":
var re = new RegExp("[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}");
if (!(typeof parameter == "string" && re.test(parameter))) {
throw new Error(errorMessage);
}

break;
default:
throw new Error("An invalid type parameter value was passed to the SDK.MetaData._parameterCheck function.");
break;
}
},
assignEntitySync: function (recordId, recordType, newOwnerId)
{
///<summary>
/// Sends the Assign Request
///</summary>
this._parameterCheck(recordId, "GUID", "The SDK.SOAPSamples.assignRequest method Assignee parameter must be a string Representing a GUID value.");
///<param name="recordId" Type="String">
/// The GUID representing the System user that the record will be assigned to.
///</param>
this._parameterCheck(newOwnerId, "GUID", "The SDK.SOAPSamples.assignRequest method Target parameter must be a string Representing a GUID value.");
///<param name="newOwnerId" Type="String">
/// The GUID representing the user-owned entity record that will be assigne to the Assignee.
///</param>
this._parameterCheck(recordType, "String", "The SDK.SOAPSamples.assignRequest method Type parameter must be a string value.");
recordType = recordType.toLowerCase();
///<param name="recordType" Type="String">
/// The Logical name of the user-owned entity. For example, 'account'.
///</param>
var request = [];

request.push("<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">");
request.push("<s:Body>");
request.push("<Execute xmlns=\"http://schemas.microsoft.com/xrm/2011/Contracts/Services\"");
request.push(" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">");
request.push("<request i:type=\"b:AssignRequest\"");
request.push(" xmlns:a=\"http://schemas.microsoft.com/xrm/2011/Contracts\"");
request.push(" xmlns:b=\"http://schemas.microsoft.com/crm/2011/Contracts\">");
request.push("<a:Parameters xmlns:c=\"http://schemas.datacontract.org/2004/07/System.Collections.Generic\">");
request.push("<a:KeyValuePairOfstringanyType>");
request.push("<c:key>Target</c:key>");
request.push("<c:value i:type=\"a:EntityReference\">");
request.push("<a:Id>" + this._xmlEncode(recordId) + "</a:Id>");
request.push("<a:LogicalName>" + this._xmlEncode(recordType) + "</a:LogicalName>");
request.push("<a:Name i:nil=\"true\" />");
request.push("</c:value>");
request.push("</a:KeyValuePairOfstringanyType>");
request.push("<a:KeyValuePairOfstringanyType>");
request.push("<c:key>Assignee</c:key>");
request.push("<c:value i:type=\"a:EntityReference\">");
request.push("<a:Id>" + this._xmlEncode(newOwnerId) + "</a:Id>");
request.push("<a:LogicalName>systemuser</a:LogicalName>");
request.push("<a:Name i:nil=\"true\" />");
request.push("</c:value>");
request.push("</a:KeyValuePairOfstringanyType>");
request.push("</a:Parameters>");
request.push("<a:RequestId i:nil=\"true\" />");
request.push("<a:RequestName>Assign</a:RequestName>");
request.push("</request>");
request.push("</Execute>");
request.push("</s:Body>");
request.push("</s:Envelope>");
var req = new XMLHttpRequest();
req.open("POST", SDK.SOAPSamples._getClientUrl(), false);
// Responses will return XML. It isn't possible to return JSON.
req.setRequestHeader("Accept", "application/xml, text/xml, */*");
req.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
req.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/Execute");
//req.onreadystatechange = function () { SDK.SOAPSamples.assignResponse(req, successCallback, errorCallback); };
req.send(request.join(""));
if (req.status != 200) {
SDK.SOAPSamples._getError(req.responseXML);
}
},
changeEntityStateSync: function (recordId, recordType, stateCode, statusCode)
{

// create the SetState request
var request = "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">";
request += "<s:Body>";
request += "<Execute xmlns=\"http://schemas.microsoft.com/xrm/2011/Contracts/Services\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">";
request += "<request i:type=\"b:SetStateRequest\" xmlns:a=\"http://schemas.microsoft.com/xrm/2011/Contracts\" xmlns:b=\"http://schemas.microsoft.com/crm/2011/Contracts\">";
request += "<a:Parameters xmlns:c=\"http://schemas.datacontract.org/2004/07/System.Collections.Generic\">";
request += "<a:KeyValuePairOfstringanyType>";
request += "<c:key>EntityMoniker</c:key>";
request += "<c:value i:type=\"a:EntityReference\">";
request += "<a:Id>" + recordId + "</a:Id>";
request += "<a:LogicalName>" + recordType + "</a:LogicalName>";
request += "<a:Name i:nil=\"true\" />";
request += "</c:value>";
request += "</a:KeyValuePairOfstringanyType>";
request += "<a:KeyValuePairOfstringanyType>";
request += "<c:key>State</c:key>";
request += "<c:value i:type=\"a:OptionSetValue\">";
request += "<a:Value>" + stateCode + "</a:Value>";
request += "</c:value>";
request += "</a:KeyValuePairOfstringanyType>";
request += "<a:KeyValuePairOfstringanyType>";
request += "<c:key>Status</c:key>";
request += "<c:value i:type=\"a:OptionSetValue\">";
request += "<a:Value>" + statusCode + "</a:Value>";
request += "</c:value>";
request += "</a:KeyValuePairOfstringanyType>";
request += "</a:Parameters>";
request += "<a:RequestId i:nil=\"true\" />";
request += "<a:RequestName>SetState</a:RequestName>";
request += "</request>";
request += "</Execute>";
request += "</s:Body>";
request += "</s:Envelope>";
var req = new XMLHttpRequest();
req.open("POST", SDK.SOAPSamples._getClientUrl(), false);
// Responses will return XML. It isn't possible to return JSON.
req.setRequestHeader("Accept", "application/xml, text/xml, */*");
req.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
req.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/Execute");
//req.onreadystatechange = function () { SDK.SOAPSamples.assignResponse(req, successCallback, errorCallback); };
req.send(request);
if (req.status != 200) {

SDK.SOAPSamples._getError(req.responseXML);
}

},
loseOpportunityRequest: function (recordId, comment) {
var requestMain = ""
requestMain += "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">";
requestMain += " <s:Body>";
requestMain += " <Execute xmlns=\"http://schemas.microsoft.com/xrm/2011/Contracts/Services\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">";
requestMain += " <request i:type=\"b:LoseOpportunityRequest\" xmlns:a=\"http://schemas.microsoft.com/xrm/2011/Contracts\" xmlns:b=\"http://schemas.microsoft.com/crm/2011/Contracts\">";
requestMain += " <a:Parameters xmlns:c=\"http://schemas.datacontract.org/2004/07/System.Collections.Generic\">";
requestMain += " <a:KeyValuePairOfstringanyType>";
requestMain += " <c:key>OpportunityClose</c:key>";
requestMain += " <c:value i:type=\"a:Entity\">";
requestMain += " <a:Attributes>";
requestMain += " <a:KeyValuePairOfstringanyType>";
requestMain += " <c:key>opportunityid</c:key>";
requestMain += " <c:value i:type=\"a:EntityReference\">";
requestMain += " <a:Id>" +recordId + "</a:Id>";
requestMain += " <a:LogicalName>opportunity</a:LogicalName>";
requestMain += " <a:Name i:nil=\"true\" />";
requestMain += " </c:value>";
requestMain += " </a:KeyValuePairOfstringanyType>";
requestMain += " <a:KeyValuePairOfstringanyType>";
requestMain += " <c:key>subject</c:key>";
requestMain += " <c:value i:type=\"d:string\" xmlns:d=\"http://www.w3.org/2001/XMLSchema\">" + comment + "</c:value>";
requestMain += " </a:KeyValuePairOfstringanyType>";
requestMain += " </a:Attributes>";
requestMain += " <a:EntityState i:nil=\"true\" />";
requestMain += " <a:FormattedValues />";
requestMain += " <a:Id>00000000-0000-0000-0000-000000000000</a:Id>";
requestMain += " <a:LogicalName>opportunityclose</a:LogicalName>";
requestMain += " <a:RelatedEntities />";
requestMain += " </c:value>";
requestMain += " </a:KeyValuePairOfstringanyType>";
requestMain += " <a:KeyValuePairOfstringanyType>";
requestMain += " <c:key>Status</c:key>";
requestMain += " <c:value i:type=\"a:OptionSetValue\">";
requestMain += " <a:Value>4</a:Value>";
requestMain += " </c:value>";
requestMain += " </a:KeyValuePairOfstringanyType>";
requestMain += " </a:Parameters>";
requestMain += " <a:RequestId i:nil=\"true\" />";
requestMain += " <a:RequestName>LoseOpportunity</a:RequestName>";
requestMain += " </request>";
requestMain += " </Execute>";
requestMain += " </s:Body>";
requestMain += "</s:Envelope>";
var req = new XMLHttpRequest();
req.open("POST", SDK.SOAPSamples._getClientUrl(), false);
// Responses will return XML. It isn't possible to return JSON.
req.setRequestHeader("Accept", "application/xml, text/xml, */*");
req.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
req.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/Execute");
req.send(requestMain);
if (req.status != 200) {
SDK.SOAPSamples._getError(req.responseXML);
} else {
return req.responseXML;
}
},
closeQuoteSync: function (quoteId, statusCode, closeNote) {
var reqMessage = ""
reqMessage += "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">";
reqMessage += " <s:Body>";
reqMessage += " <Execute xmlns=\"http://schemas.microsoft.com/xrm/2011/Contracts/Services\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">";
reqMessage += " <request i:type=\"b:CloseQuoteRequest\" xmlns:a=\"http://schemas.microsoft.com/xrm/2011/Contracts\" xmlns:b=\"http://schemas.microsoft.com/crm/2011/Contracts\">";
reqMessage += " <a:Parameters xmlns:c=\"http://schemas.datacontract.org/2004/07/System.Collections.Generic\">";
reqMessage += " <a:KeyValuePairOfstringanyType>";
reqMessage += " <c:key>QuoteClose</c:key>";
reqMessage += " <c:value i:type=\"a:Entity\">";
reqMessage += " <a:Attributes>";
reqMessage += " <a:KeyValuePairOfstringanyType>";
reqMessage += " <c:key>quoteid</c:key>";
reqMessage += " <c:value i:type=\"a:EntityReference\">";
reqMessage += " <a:Id>" + quoteId + "</a:Id>";
reqMessage += " <a:LogicalName>quote</a:LogicalName>";
reqMessage += " <a:Name i:nil=\"true\" />";
reqMessage += " </c:value>";
reqMessage += " </a:KeyValuePairOfstringanyType>";
reqMessage += " <a:KeyValuePairOfstringanyType>";
reqMessage += " <c:key>subject</c:key>";
reqMessage += " <c:value i:type=\"d:string\" xmlns:d=\"http://www.w3.org/2001/XMLSchema\">" + closeNote+ "</c:value>";
reqMessage += " </a:KeyValuePairOfstringanyType>";
reqMessage += " </a:Attributes>";
reqMessage += " <a:EntityState i:nil=\"true\" />";
reqMessage += " <a:FormattedValues />";
reqMessage += " <a:Id>00000000-0000-0000-0000-000000000000</a:Id>";
reqMessage += " <a:LogicalName>quoteclose</a:LogicalName>";
reqMessage += " <a:RelatedEntities />";
reqMessage += " </c:value>";
reqMessage += " </a:KeyValuePairOfstringanyType>";
reqMessage += " <a:KeyValuePairOfstringanyType>";
reqMessage += " <c:key>Status</c:key>";
reqMessage += " <c:value i:type=\"a:OptionSetValue\">";
reqMessage += " <a:Value>" + statusCode + "</a:Value>";
reqMessage += " </c:value>";
reqMessage += " </a:KeyValuePairOfstringanyType>";
reqMessage += " </a:Parameters>";
reqMessage += " <a:RequestId i:nil=\"true\" />";
reqMessage += " <a:RequestName>CloseQuote</a:RequestName>";
reqMessage += " </request>";
reqMessage += " </Execute>";
reqMessage += " </s:Body>";
reqMessage += "</s:Envelope>";
var req = new XMLHttpRequest();
req.open("POST", SDK.SOAPSamples._getClientUrl(), false);
// Responses will return XML. It isn't possible to return JSON.
req.setRequestHeader("Accept", "application/xml, text/xml, */*");
req.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
req.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/Execute");
req.send(reqMessage);
if (req.status != 200) {
SDK.SOAPSamples._getError(req.responseXML);
}
},
__namespace: true
};

Configure ADFS 3.0 with Sharepoint 2013 for Claim authentication

Update Sptember, 23 2014

1. Install AD FS server
2. Install and configure SharePoint 2013 server
3. Configure ADFS
3.1 Create the claim rule
3.2 Export the Token-Signing certificate
4 Configure SharePoint 2013
4.1 Configure web application
4.2 Modify the SharePoint web application web.config
4.3 Remove authentication type request
9. Usefull link
The used lab environment are:
DC01 – Domain Controller and Federation Server
SQL01 – SQL Server 2012 Standard with Reporting Services
SHP01 – SharePoint 2013 SP 1 Enterprise
On all server is installed Windows Server 2012 R2 Standard.
Install Federation Server on the Domain Controller is not a good think!

1. Install and configure an AD FS server
Install the ADFS Service on Windows 2012 R2 (see link at point 9). In our case the fully qualify domain name of the machine is DC01.intra.zzlab.com and we use the external name sts.zzlab.com. So we need to add all the two name to the registry key as reported in this Microsoft KB article

2. Install and configure the SharePoint 2013 server
You need to use SharePoint 2013 with SP1 for installing on Windows Server 2012 R2. The setup of SharePoint is standard setup. SharePoint need to be SSL enabled. Add in the Intranet zone of internet explorer in the SharePoint server the address of the ADFS Server and the SharePoint web application.

3. Configure relay party on ADFS
On the ADFS Server open the AD FS Management tools and under the Trust Relationships folder on the left pane right click on Relying Party Trusts and select Add Relying Party Trust…
A. Welcome page
B. Select Data Source
Select the option “Enter data about the relying party manually”
C. Specify Display Name
Insert the Display name. I have used the FQDN of the SharePoint Server (shp01.intra.zzlab.com)
D. Choose profile
Use AD FS Profile
E. Configure certificate
This certificate are used for token encryption and need to be stored on the “Computer account” certificate store. I have used the SSL certificate of the SharePoint Server (shp01.intra.zzlab.com).
F. Configure URL
Select the option “Enable support for WS-Federation Passive Protocol” and insert the URL of the SharePoint Trust Service (https://<sharepoint server FQDN>/_trust/)
G. Configure identifiers
Add the uniform resource name (URN) (is the historical name for a uniform resource identifier (URI)) of your SharePoint in the standard form urn:sharepoint:<Any string>.
In my case I have used urn:sharepoint:zzlab
F. Configure Multi-Factor Authentication Now?
I have selected “I do not want to configure …”
G. Choose Issuance Authorization Rule
This is the standard authentication rule. I have select “Permit all users to access this relying party”
H. Ready to add trust
Is the review of the configuration
I. Finish

3.1 Create the claim rule
After the configuration wizard the system automatically open the rule control windows and we need add some rule (Issuance Transform Rules) to complete the Claims token. SharePoint use EmailAddress for authentication so we add a rule to send User Principal Name as Email Address
I have created this rules:

R1 Rule template: Pass Through or Filter an Incoming Claim
Claim rule name: Pass Through UPN (or something descriptive)
Incoming claim type: UPN
Pass through all claim values
R2 Rule template: Pass Through or Filter an Incoming Claim
Calim rule name: Pass Through Primary SID (or something descriptive)
Incoming claim type: Primary SID
Pass through all claim values
R3 Rule template: Transform an incoming Claim
Claim rule name: Transform Windows Account Name to Name (or something descriptive)
Incoming claim type: Windows account name
Outgoing claim type: Name (or *Name)
Pass through all claim values
R4 Rule template: Send LDAP Attributes as Claims
Calim rule name: Send UPN as Email Address (or something descriptive)
Attribute store: Select “Active Directory”
“Mapping of LDAP attributes to outgoing claim types” select: LDAP Attribute: User-Principal-Name
Under Outgoing Claim Type: E-Mail Address

3.2 Distribute the certificate
Export the certificate used by AD FS for token sign and save it on the SharePoint server (we don’t need the certificate private key)  inside the Computer certificate store.
SharePoint also need access to the private key of the certificate used for token encryption selected in the relay party configuration (3. Configure relay party on ADFS,  point E). So if you have used a different certificate need to export with private key and import inside SharePoint server (SHP01) computer certificate store.

4 Configure SharePoint 2013
First step is import the token-signing certificate on the SharePoint server. For do this we need to use the “SharePoint management shell”. First copy the exported certificate on the SharePoint server. In my case I have saved the certificate in C:\Temp so my <PathToTokenSignCert> is C:\Temp\TokenSignCert.cer.
After that use the command:
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2("<FullPathOfTheTokenSignCertFile>")
New-SPTrustedRootAuthority -Name "Token Signing Cert" -Certificate $cert

Is important to import all the certificate chain with the same command
After that register the claim provider in SharePoint:

$emailClaimMap = New-SPClaimTypeMapping -IncomingClaimType "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" -IncomingClaimTypeDisplayName "EmailAddress" -SameAsIncoming
$upnClaimMap = New-SPClaimTypeMapping -IncomingClaimType “http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn" -IncomingClaimTypeDisplayName “UPN” -SameAsIncoming
$roleClaimMap = New-SPClaimTypeMapping -IncomingClaimType “http://schemas.microsoft.com/ws/2008/06/identity/claims/role" -IncomingClaimTypeDisplayName “Role” -SameAsIncoming
$sidClaimMap = New-SPClaimTypeMapping -IncomingClaimType “http://schemas.microsoft.com/ws/2008/06/identity/claims/primarysid" -IncomingClaimTypeDisplayName “SID” -SameAsIncoming
$realm = “urn:sharepoint:zzlab”
$signInURL = “https://sts.zzlab.com/adfs/ls"
$ap = New-SPTrustedIdentityTokenIssuer -Name "ZZLAB AD Federation" -Description “ZZLAB AD Federation Server” -realm $realm -ImportTrustCertificate $cert -ClaimsMappings $emailClaimMap,$upnClaimMap,$roleClaimMap,$sidClaimMap -SignInUrl $signInURL -IdentifierClaim $emailClaimmap.InputClaimType

4.1 Configure web application to use ADFS
Using the SharePoint Central Administration web site enable the use of the newly created SPTrustedIdentityTokenIssuer. Go to Manage web applications and select the desired web application from the list. Select the Authentication Providers button and the desired SharePoint zone. Select the Trusted Identity Provider and the newly registered.

4.2 Modify the SharePoint web application web.config
We have used an encrypted token in ADFS and we have used an encryption certificate so we need to explain how decrypt the token. For decrypt the token we need access to the private key of the encryption certificate. SharePoint web application access the key using the same user of the Application Pool for the IIS web site. Using the Certificates snap-in look for the Computer account and find the certificate. Right click on it and using the All tasks > Manage private key … add the application pool user and give it the Read permission. For this reason we need to modify the web.config of the web application. Open the web.config with notepad and find the <microsoft.identityModel> section (in my case is the last section of the file who end just before the </configuration> tag. Inside the <securityTokenHandlers> add the path name for manage encrypted token <add type=”Microsoft.IdentityModel.Tokens.EncryptedSecurityTokenHandler, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35″ /> After that we need to explain at SharePoint what is the certificate used for encrypt the token, to do this we need add just before the tag </service>:

<serviceCertificate>
<certificateReference x509FindType="FindByThumbprint" findValue="<ThumbprintOfTheCertificate>" storeLocation="LocalMachine" storeName="My"/>
</serviceCertificate>

4.3 Remove authentication type request
At this point SharePoint ask with kind of authentication use: Federation Server or Windows You will likely want to remove this step and have all login efforts go directly to ADFS instead. Change the web application login page. Select “Custom Sign In Page” and use the url /_trust/default.aspx Save and wait.

9. Usefull link
AD FS Deployment documentation
Deploying ADFS 3.0 for SharePoint 2013 in a perimeter network

Install Dynamics CRM 2013 on premise

The lab environment:

DC01 – Windows 2012 R2 Core Edition as Domain Controller
SQL01 – Windows 2012 R2 Standard with SQL 2012 Server Enterprise with all features
CRM01 – Windows 2012 R2 Standard (where we install the Microsoft Dynamics CRM 2013)

Prepare the environment
Create in Active Directory a specific Organizational Unit used by the system for permission management
Set the SQL Server Agent Service who start in Automatic mode and start it
Create service user and add specific user permission
Install the Dynamics CRM Server Email Router service (We don’t need this service so I don’t have installed)
Install the Dynamics CRM Server
Install the Dynamics CRM Reporting Extensions on Microsoft Reporting Server Service
Update to service pack 1 the Dynamics CRM Server and Dynamics CRM Reporting Extensions

Create service user
You need 6 service user who are just members of Domain Users:

  • Application service (crmapp.service)
  • Deployment web service (crmdepweb.service)
  • Sandbox processing service (crmsandbox.service)
  • VSS Writer Service (crmvsswriter.service)
  • Asynchronous Processing Service (crmasync.service)
  • Monitoring Service (crmmonitor.service)

Add the Application service (crmapp.service) user and Asynchronous Processing Service (crmasync.service) user to the Performance Log User local group of the Dynamics CRM Server

I have used this PowerShell command:

Import-Module ActiveDirectory
$ADPathContainer = "OU=ServiceUser,OU=ZZLAB,DC=intra,DC=zzlab,DC=com"
New-ADUser -SamAccountName "crmapp.service" -UserPrincipalName "crmapp.service@intra.zzlab.com" -Name "CRM Application Service User" -DisplayName "CRM Application Service User" -GivenName "CRM Application" -SurName "Service User" -Path $ADPathContainer -AccountPassword (ConvertTo-SecureString 'Pa$$w0rd' -AsPlainText -Force) -Enabled $True -PasswordNeverExpires $True -ChangePasswordAtLogon $False
New-ADUser -SamAccountName "crmdepweb.service" -UserPrincipalName "crmdepweb.service@intra.zzlab.com" -Name "CRM Deployment Web Service User" -DisplayName "CRM Deployment Web Service User" -GivenName "CRM Deployment Web" -SurName "Service User" -Path $ADPathContainer -AccountPassword (ConvertTo-SecureString 'Pa$$w0rd' -AsPlainText -Force) -Enabled $True -PasswordNeverExpires $True -ChangePasswordAtLogon $False
New-ADUser -SamAccountName "crmsandbox.service" -UserPrincipalName "crmsandbox.service@intra.zzlab.com" -Name "CRM Sandbox Processing Service User" -DisplayName "CRM Sandbox Processing Service User" -GivenName "CRM Sandbox Processing" -SurName "Service User" -Path $ADPathContainer -AccountPassword (ConvertTo-SecureString 'Pa$$w0rd' -AsPlainText -Force) -Enabled $True -PasswordNeverExpires $True -ChangePasswordAtLogon $False
New-ADUser -SamAccountName "crmvsswriter.service" -UserPrincipalName "crmvsswriter.service@intra.zzlab.com" -Name "CRM VSS Writer Service User" -DisplayName "CRM VSS Writer Service User" -GivenName "CRM VSS Writer" -SurName "Service User" -Path $ADPathContainer -AccountPassword (ConvertTo-SecureString 'Pa$$w0rd' -AsPlainText -Force) -Enabled $True -PasswordNeverExpires $True -ChangePasswordAtLogon $False
New-ADUser -SamAccountName "crmasync.service" -UserPrincipalName "crmasynchronous.service@intra.zzlab.com" -Name "CRM Asynchronous Service User" -DisplayName "CRM Asynchronous Service User" -GivenName "CRM Asynchronous" -SurName "Service User" -Path $ADPathContainer -AccountPassword (ConvertTo-SecureString 'Pa$$w0rd' -AsPlainText -Force) -Enabled $True -PasswordNeverExpires $True -ChangePasswordAtLogon $False
New-ADUser -SamAccountName "crmmonitor.service" -UserPrincipalName "crmmonitor.service@intra.zzlab.com" -Name "CRM Monitoring Service User" -DisplayName "CRM Monitoring Service User" -GivenName "CRM Monitoring" -SurName "Service User" -Path $ADPathContainer -AccountPassword (ConvertTo-SecureString 'Pa$$w0rd' -AsPlainText -Force) -Enabled $True -PasswordNeverExpires $True -ChangePasswordAtLogon $False

Dynamics CRM Server Setup
Install the Dynamics CRM 2013 from the “autoplay menu” the application crash on my Windows 2012 R2 server. So I run the SetupServer.exe from the folder \Server\amd64.
The procedure ask me the following information:
1. Internet connection to check the upgrade
2. Insert the CRM 2013 product key
3. Accept the license agreement
4. Install required components
5. Select the installation location (I have accepted the default folder path)
6. Specify server role (I have installed every thinks on one server)
7. Specify deployment option (I have accepted the default “Create a new deployment” and I have specified the SQL01.intra.zzlab.com as SQL server)
8. Select the Organizational Unit (select the Organizational Unit created in the preparation environment section)
9. Specify the service user (Created in the preparation environment section)
10. Select the web site (I have choose for the default web site on my server)
11. Email Router Name (I have left blank because I don’t install the email router now)
12. Specify Organization Settings
13. Specify the report server url
14. Help us to improve customer experience
15. Select Microsoft Update preferences
16. System checks
17. Service disruption warnings
18. Ready to install

Install Dynamics CRM Reporting Extensions on Microsoft Reporting Service server
Also in this case the auto run setup lunch crash immediately on Windows 2012 R2 Server.
I run the SetupSrsDataConnector.exe from <DVD drive letter>:\Server\amd64\SrsDataConnector.
The setup wizard ask only for the Reporting Server name and automatically do everything.

Install the Service Pack 1 for Dynamics CRM Server and Dynamics CRM Reporting Extensions
The setup of service pack run automatically without any question

Create a self signed certificate with alternatives names

For many courses or test lab environment we need a certificate (SSL,…) so after some experience with OpenSSL I have found in internet and “rearrange” a work of other people for create a PowerShell Script for self signed certificate creation with Subject Alternatives Names.
The script need to be executed with administrative permission (start PowerShell as administrator) and store the new certificate in the Computer store machine. You can export the certificate and the private key using the MMC Certificates snap-in on windows installation with GUI. If you are using a Core windows installation you need the CERTUTIL command.

#####################################################################
#
# Creates self-signed signing certificate and install it to certificate store
# with alternative names
#
# Note: Requires at least Windows Vista. Windows XP/Windows Server 2003
# are not supported.
#
# LSO (Lorenzo Soncini) - August 12, 2014
#
# Update with information found
# http://forums.iis.net/t/1180823.aspx
#
# Pavel Khodak, 2012
# http://blogs.msdn.com/b/pavelkhodak/
#
# Based on the work of
# Vadims Podans - http://www.sysadmins.lv/
# Adam Conkle - http://social.technet.microsoft.com/wiki/contents/articles/4714.how-to-generate-a-self-signed-certificate-using-powershell-en-us.aspx
#####################################################################

# INPUT PARAMETER
# Change here the value to the Certificates Parameter
# Certificate subject in X500 format…
[string] $Subject = ‘CN = CRM01’
# CertificateFriendlyName…
[string] $FriendlyName = “CRM01 ZZLab Certificate”
# Subject Alternatives Names…
[string[]] $AltDnsNames = @(“crm.zzlab.com”, “crm.intra.zzlab.com”, “crm01.intra.zzlab.com”)
[Net.IPAddress[]] $IPAltNames
# Key length, use 2048 or more…
[int] $KeyLength = 2048
# Valid period …
[datetime] $NotBefore = [DateTime]::Now
[datetime] $NotAfter = $NotBefore.AddYears(5)
# END INPUT PARAMETER
#
try {
$OS = @(Get-WmiObject -Class Win32_OperatingSystem)
if ($OS[0].Version -lt 6) {
Write-Error “This version of Windows is not supported. Windows Server 2008 or Windows Vista or later is required.”
return
}
Write-Host “`n WARNING: This script sample is provided AS-IS with no warranties and confers no rights.” -ForegroundColor Yellow
Write-Host “`n This script sample will generate self-signed certificates with private key”
Write-Host ” in the Local Computer Personal certificate store.”
#region Enums
# http://msdn.microsoft.com/en-us/library/aa379394%28VS.85%29.aspx
$X500NameFlags = @{
STR_NONE = 0 # Display characteristics are not identified.
OID_NAME = 2 # OIDs are separated from their associated attribute value by using an equal sign (=).
X500_NAME = 3 # OIDs are converted to their X.500 key names.
}

# http://msdn.microsoft.com/en-us/library/aa379409%28VS.85%29.aspx
$X509KeySpec = @{
NONE = 0 # The intended use is not identified.
KEYEXCHANGE = 1 # The key can be used to encrypt (including key exchange) or sign depending on the algorithm.
SIGNATURE = 2 # The key can be used for signing.
}

# http://msdn.microsoft.com/en-us/library/aa379024.aspx
$MachineContext = @{
User = 0x0;
Computer = 0x1
}

# http://msdn.microsoft.com/en-us/library/aa374830.aspx
$AltNameType = @{
DNS_NAME = 3 # A Domain Name System (DNS) name such as MyDomain.Microsoft.com.
IP_ADDRESS = 8 # An Internet Protocol (IP) address in dotted decimal format 123.456.789.123.
}

# http://msdn.microsoft.com/en-us/library/aa374936%28v=VS.85%29.aspx
$EncodingType = @{
BASE64 = 0x1 # The string is base64 encoded without beginning and ending certificate headers.
}

# http://msdn.microsoft.com/en-us/library/aa376782%28VS.85%29.aspx
$InstallResponseRestrictionFlags = @{
AllowUntrustedCertificate = 0x2 # Installs untrusted end entity and certification authority certificates.
AllowUntrustedRoot = 0x4 # Same as AllowUntrustedCertificate but also installs the certificate even if the certificate chain cannot be built because the root is not trusted.
}

# http://msdn.microsoft.com/en-us/library/aa379399%28v=VS.85%29.aspx
$X509CertificateEnrollmentContext = @{
User = 0x1 # The certificate is intended for an end user.
Computer = 0x2 # The certificate is intended for a computer.
AdminForceMachine = 0x3 # The certificate is being requested by an administrator acting on the behalf of a computer.
}

# http://msdn.microsoft.com/en-us/library/aa379412.aspx
$X509PrivateKeyExportFlags = @{
ALLOW_EXPORT_NONE = 0x0 # Export is not allowed. This is the default value.
ALLOW_EXPORT = 0x1 # The private key can be exported.
PLAINTEXT_EXPORT_FLAG = 0x2 # The private key can be exported in plaintext form
ALLOW_ARCHIVING_FLAG = 0x4 # The private key can be exported once for archiving.
ALLOW_PLAINTEXT_ARCHIVING_FLAG = 0x8 # The private key can be exported once in plaintext form for archiving.
}

# http://msdn.microsoft.com/en-us/library/aa379417%28v=VS.85%29.aspx
$X509PrivateKeyUsageFlags = @{
NONE = 0 # The permitted uses are not defined.
DECRYPT = 0x1 # The key can be used to decrypt content.
SIGNING = 0x2 # The key can be used for signing.
ALL_USAGES = 0xffffff # All of the uses defined for this enumeration are permitted.
}

# http://msdn.microsoft.com/en-us/library/aa379410(v=VS.85).aspx
$X509KeyUsageFlags = @{
DIGITAL_SIGNATURE = 0x80 # Used with a Digital Signature Algorithm (DSA) to support services other than nonrepudiation, certificate signing, or revocation list signing.
KEY_ENCIPHERMENT = 0x20 # Used for key transport.
DATA_ENCIPHERMENT = 0x10 # Used to encrypt user data other than cryptographic keys.
}
#endregion

#region Create private key. http://msdn.microsoft.com/en-us/library/aa378921(VS.85).aspx

$PrivateKey = New-Object -ComObject X509Enrollment.CX509PrivateKey
$PrivateKey.ProviderName = “Microsoft RSA SChannel Cryptographic Provider”
$PrivateKey.KeySpec = $X509KeySpec.KEYEXCHANGE
$PrivateKey.KeyUsage = $X509PrivateKeyUsageFlags.ALL_USAGES
$PrivateKey.Length = $KeyLength
$PrivateKey.MachineContext = $MachineContext.Computer
# Set security descriptor. http://msdn.microsoft.com/en-us/library/windows/desktop/aa379034(v=vs.85).aspx
$PrivateKey.SecurityDescriptor = “D:PAI(A;;0xd01f01ff;;;SY)(A;;0xd01f01ff;;;BA)(A;;0x80120089;;;NS)”
$PrivateKey.ExportPolicy = $X509PrivateKeyExportFlags.ALLOW_EXPORT
$PrivateKey.Create()
#endregion

#region Create certificate request template. http://msdn.microsoft.com/en-us/library/aa377124(VS.85).aspx

$Cert = New-Object -ComObject X509Enrollment.CX509CertificateRequestCertificate
$Cert.InitializeFromPrivateKey($X509CertificateEnrollmentContext.Computer, $PrivateKey, “”)
#region Add alternative names. http://msdn.microsoft.com/en-us/library/aa378081(v=VS.85).aspx
$altNamesCollection = New-Object -ComObject X509Enrollment.CAlternativeNames
$extNames = New-Object -ComObject X509Enrollment.CX509ExtensionAlternativeNames
foreach ($dnsName in $AltDnsNames) {
$altDnsName = New-Object -ComObject X509Enrollment.CAlternativeName
$altDnsName.InitializeFromString($AltNameType.DNS_NAME, $dnsName)
$altNamesCollection.Add($altDnsName)
}

foreach ($ip in $IPAltNames) {
$base64EncodedIp = [Convert]::ToBase64String($ip.GetAddressBytes())
$altNameIp = New-Object -ComObject X509Enrollment.CAlternativeName
$altNameIp.InitializeFromRawData($AltNameType.IP_ADDRESS, $EncodingType.BASE64, $base64EncodedIp)
$altNamesCollection.Add($altNameIp)
}

$extNames.InitializeEncode($altNamesCollection)
$Cert.X509Extensions.Add($extNames)
#endregion

#region Certificate Extensions.
# Extension code are http://msdn.microsoft.com/en-us/library/windows/desktop/aa374855(v=vs.85).aspx
# Add certificate key usage statements.
$OIDs = New-Object -ComObject X509Enrollment.CObjectIDs

# define Server authentication enhanced key usage (actual OID = 1.3.6.1.5.5.7.3.1)
$OID = New-Object -ComObject X509Enrollment.CObjectID
$OID.InitializeFromValue(“1.3.6.1.5.5.7.3.1”)
$OIDs.Add($OID)
# define Client authentication enhanced key usage (actual OID = 1.3.6.1.5.5.7.3.2)
$OID = New-Object -ComObject X509Enrollment.CObjectID
$OID.InitializeFromValue(“1.3.6.1.5.5.7.3.2”)
$OIDs.Add($OID)
# define SmartCard authentication enhanced key usage (actual OID = 1.3.6.1.4.1.311.20.2.2)
$OID = New-Object -ComObject X509Enrollment.CObjectID
$OID.InitializeFromValue(“1.3.6.1.4.1.311.20.2.2”)
$OIDs.Add($OID)
# define CodeSigning enhanced key usage (actual OID = 1.3.6.1.5.5.7.3.3) from OID
$OID = New-Object -ComObject X509Enrollment.CObjectID
$OID.InitializeFromValue(“1.3.6.1.5.5.7.3.3”)
$OIDs.Add($OID)

# now we create Enhanced Key Usage extension, add our OIDs and encode extension value
# http://msdn.microsoft.com/en-us/library/aa378132(VS.85).aspx
$EKU = New-Object -ComObject X509Enrollment.CX509ExtensionEnhancedKeyUsage
$EKU.InitializeEncode($OIDs)

$Cert.X509Extensions.Add($EKU)

# Add Key Encipherment, Data Encipherment extensions.
$keyUsageExt = New-Object -ComObject X509Enrollment.CX509ExtensionKeyUsage
$keyUsageExt.InitializeEncode(
$X509KeyUsageFlags.KEY_ENCIPHERMENT -bor `
$X509KeyUsageFlags.DATA_ENCIPHERMENT
)

$Cert.X509Extensions.Add($keyUsageExt)
#endregion

# Create Subject field in X.500 format. http://msdn.microsoft.com/en-us/library/aa377051(VS.85).aspx
$name = New-Object -ComObject X509Enrollment.CX500DistinguishedName
$name.Encode($Subject, $X500NameFlags.X500_NAME)
$Cert.Subject = $name

$Cert.Issuer = $Cert.Subject
$Cert.NotBefore = $NotBefore
$Cert.NotAfter = $NotAfter
$Cert.Encode()
#endregion

#region Process request and build end certificate.
# interface: http://msdn.microsoft.com/en-us/library/aa377809(VS.85).aspx
$enrollment = New-Object -ComObject X509Enrollment.CX509enrollment
$enrollment.InitializeFromRequest($Cert)
$endCert = $enrollment.CreateRequest($EncodingType.BASE64)

$enrollment.CertificateFriendlyName = $FriendlyName

# Install certificate.
$enrollment.InstallResponse(
$InstallResponseRestrictionFlags.AllowUntrustedRoot,
$endCert,
$EncodingType.BASE64,
“”
)
#endregion

} catch {
Write-Error (‘Failed to create web server certificate. The error was: “{0}”.’ -f $_)
}

Use the certutil utility for export the certificate
In the same PowerShell administrative session use the command:

certutil -store

for list all certificate. Look for the Serial Number of the desired certificate.
With the command:

certutil -exportPFX <Certificate Serial Number> <Certificate destination file>.pfx

the system ask for a PFX password and export the selected certificate in file <Certificate destination file>.pfx