Visual Studio Crashing because Temp Folder issue

Today I was getting an error when running Visual Studio.

<entry>
<record>180</record>
<time>2018/02/06 14:46:47.096</time>
<type>Error</type>
<source>Editor or Editor Extension</source>
<description>System.IO.IOException: The file exists. at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath) at System.IO.__Error.WinIOError() at System.IO.Path.InternalGetTempFileName(Boolean checkHost) at System.Windows.Input.Cursor.LoadFromStream(Stream cursorStream) at Microsoft.VisualStudio.Text.Editor.Implementation.LeftSelectionMargin.get_RightArrowCursor() at Microsoft.VisualStudio.Text.Editor.Implementation.LeftSelectionMarginProvider.CreateMargin(IWpfTextViewHost textViewHost, IWpfTextViewMargin containerMargin) at Microsoft.VisualStudio.Text.Utilities.ContainerMargin.&lt;AddMargins&gt;b__2(IWpfTextViewMarginProvider mp) at Microsoft.VisualStudio.Text.Utilities.GuardedOperations.InstantiateExtension[TExtension,TMetadata,TExtensionInstance](Object errorSource, Lazy`2 provider, Func`2 getter)</description>
</entry>

So I internet searched and found several articles that suggested my “Temp” folder(s) were full.

No problem, right click C:, properties and do some clean up and delete Temp items.

I still was getting the error.

The issue was that while cleaning up “Temp” gets rid of files, it does not seem to get rid of subfolders.  And subfolders (with no files) still take up space.

So I found this StackOverFlow article:

 

https://stackoverflow.com/questions/1965787/how-to-delete-files-subfolders-in-a-specific-directory-at-command-prompt-in-wind

I put this code in a .bat file

 

del /q “C:\Users\MYUSERNAME\AppData\Local\Temp\*”
FOR /D %%p IN (“C:\Users\MYUSERNAME\AppData\Local\Temp\*.*”) DO rmdir “%%p” /s /q

 

Now my Visual Studio starts normally.  Apparently, I had a BUNCH of (empty) subfolders in my temp path.

😦

 

Posted in Uncategorized | Leave a comment

The SDK ‘Microsoft.NET.Sdk.Publish’ specified could not be found.

I got a weird error today…trying to build my azure function.

 

\.nuget\packages\microsoft.net.sdk.functions\1.0.2\build\netstandard1.0\Microsoft.NET.Sdk.Functions.Publish.props(13,11): error MSB4236: The SDK ‘Microsoft.NET.Sdk.Publish’ specified could not be found.

Internet searching did not find much.

My VS 2017 timeline was this.

I installed Visual Studio 2017 Enterprise.

I installed Visual Studio 2017 Enterprise Preview 2.

My enterprise edition expired, and my company is working on getting an upgraded license (still in the red tape stage).

So I installed I installed Visual Studio 2017 Professional.  I installed then Visual Studio 2017 Professional Preview 2. (I did not uninstall Enterprise versions, as I expect to get a upgraded msdn subscription shortly).

Then I tried to build and got the above error.

It turns out there are multiple versions of msbuild.exe

 

C:\Program Files (x86)\Microsoft Visual Studio\Preview\Enterprise\MSBuild\15.0\Bin\msbuild.exe
C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\Bin\msbuild.exe
C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\MSBuild\15.0\Bin\msbuild.exe
C:\Program Files (x86)\Microsoft Visual Studio\Preview\Professional\MSBuild\15.0\Bin\msbuild.exe

 

I got the error above by using the

C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\Bin\msbuild.exe

But I switched to using

C:\Program Files (x86)\Microsoft Visual Studio\Preview\Professional\MSBuild\15.0\Bin\msbuild.exe

and the error went away

No idea if its because of an expired license or overlaying Pro on top of Enterprise edition or what.

Hope that helps sombody.

Posted in Uncategorized | 1 Comment

Scrum Team Names / Agile Team Names Ideas

I did some searches for “best scrum team names” and was a little disappointed.  Here is a (growing?) list.

About 1/3 are internet-copied. 2/3 of them are “originals” ***.

*** But as U2/Bono/Paul Hewson once sang :
“Every artist is a cannibal, every poet is a thief………
All kill their inspiration and sing about their grief”

 

Scrummy Bears

Scrumbledores

Scrumbledore’s Army

 

BoolMeOvers

Air Conditionals

cOver Lords

 

Your time is gonna Scrum

Here comes the Scrum Little Darling

Don’t Scrum Around Here No More

Scrumglasses at Night

Don’t let the Scrum Go Down On Me

The House of the Rising Scrum

Easy like ScrumDay Morning

Walking on Scrumshine

Scrum Like It Hot

ScrumDay, ScrumHow

Scrum As You Are

Scrumshine of your Love

Coverage Drop and Rolls

Scrum At Me Bro

Sweet Scrumshine

Scrum On Hear the Noise

Johnny Scrum Lately

Scrum On Eileen

The Apple Scrumpling Gang

Don’t let the Scrum Go Down on Me

Scrum Kind of Wonderful

Scrumbody That I Used To Know

Scrumdog Millionaires

Easy Scrum Easy Go

Pour Scrum Sugar On Me

Black Holed Scrum

Posted in Uncategorized | Leave a comment

ActionConditionFailed. “The execution of template action ‘Condition’ is skipped” “Expected status values ‘Succeeded’ and actual value ‘Failed’.” Azure Logic Apps

I’ve been jumping into the Azure Logic Apps world.

On an Http Request Trigger (the Logic App one, not the Function app one), I wanted to reject the request if I received bad json.

Not only did I want to reject the request, I wanted the end user to get some “hints” as to why the json schema validation failed.

So I coded up a basic azure function (that I would later pull into my Logic App.

using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Text;
using System.Threading.Tasks;

using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Host;

using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Schema;

namespace GranadaCoder.AzurePoc.AzureFunctionsOne
{
public static class SimpleJsonSchemaValidator
{
[FunctionName(“SimpleJsonSchemaValidatorFunctionName”)]
public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Function, “post”, Route = null)]HttpRequestMessage req, TraceWriter log)
{
log.Info(string.Format(“C# HTTP trigger function SimpleJsonSchemaValidatorFunctionName about to process a request. (‘{0}’)”, DateTime.Now.ToLongTimeString()));

try
{
log.Info(string.Format(“SimpleJsonSchemaValidatorFunctionName HostingEnvironment.ApplicationPhysicalPath='{0}'”, System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath));

/* json schema straight from https://www.newtonsoft.com/json/help/html/JsonSchema.htm
you can get valid and invalid json from there as well) */

string jsonSchemaText = @”{
‘description’: ‘A person’,
‘type’: ‘object’,
‘properties’:
{
‘name’: {‘type’:’string’},
‘hobbies’: {
‘type’: ‘array’,
‘items’: {‘type’:’string’}
}
}
}”;

log.Info(string.Format(“SimpleJsonSchemaValidatorFunctionName jsonSchemaText='{0}'”, jsonSchemaText));

JSchema schema = JSchema.Parse(jsonSchemaText);

var content = req.Content;
string jsonContent = content.ReadAsStringAsync().Result;

log.Info(string.Format(“SimpleJsonSchemaValidatorFunctionName jsonContent='{0}'”, jsonContent));

JObject jobj = JObject.Parse(jsonContent);

IList<string> messages;
bool valid = jobj.IsValid(schema, out messages);
if (!valid)
{
string errorMsg = string.Join(“,”, messages);
throw new ArgumentOutOfRangeException(string.Format(“Not Cool Alert. ({0})”, errorMsg));
}

log.Info(“C# HTTP trigger function SimpleJsonSchemaValidatorFunctionName processed a request.”);
return req.CreateResponse(HttpStatusCode.OK, jsonContent, new JsonMediaTypeFormatter());
}
catch (Exception ex)
{
string errorMsg = GenerateFullFlatMessage(ex);
log.Error(errorMsg);
return req.CreateResponse(HttpStatusCode.BadRequest, errorMsg);
}
}

private static string GenerateFullFlatMessage(Exception ex)
{
return GenerateFullFlatMessage(ex, false);
}

private static string GenerateFullFlatMessage(Exception ex, bool showStackTrace)
{
string returnValue;

StringBuilder sb = new StringBuilder();
Exception nestedEx = ex;

while (nestedEx != null)
{
if (!string.IsNullOrEmpty(nestedEx.Message))
{
sb.Append(nestedEx.Message + System.Environment.NewLine);
}

if (showStackTrace && !string.IsNullOrEmpty(nestedEx.StackTrace))
{
sb.Append(nestedEx.StackTrace + System.Environment.NewLine);
}

nestedEx = nestedEx.InnerException;
}

returnValue = sb.ToString();

return returnValue;
}
}
}

Please note that I am getting my json and json schema from the example from newtonsoft.

https://www.newtonsoft.com/json/help/html/JsonSchema.htm

Ok, then I created a new Logic App.

FailedRequestResponse

My initial “Request” trigger was added.  No brainer on that.  Something has to be the trigger for the Logic App.

Then I added an action … an Azure Function, and wired up my “SimpleJsonSchemaValidatorFunctionName”.

Then I added a “Condition”.  The condition would check the StatusCode of the output of SimpleJsonSchemaValidatorFunctionName.

If the StatusCode was 200, then it would simple send a request back with the body equal to “Hooray Everything AOK  Hooray”.

The “Else” branch of the condition would send a request back with the body equal to the body from SimpleJsonSchemaValidatorFunctionName (which could contain all the json validations)

Everything via the Logic App Designer went as planned.

If I submitted good Json, I got back “Hooray Everything AOK  Hooray”.  Sweet!
The good json (from the newtonsoft website) was:

{
  'name': 'James',
  'hobbies': ['.NET', 'Blogging', 'Reading', 'Xbox', 'LOLCATS']
}

If I submitted bad Json……..I did NOT get what I expected. 😦  Boo!
The bad json (from the newtonsoft website) was:

{
   'name': null,
   'hobbies': ['Invalid content', 0.123456789]
 }

My client got a response back with below message

{
“error”: {
“code”: “NoResponse”,
“message”: “The server did not received a response from an upstream server. Request tracking id ‘00000000000000000000000000000’.”
}
}

In the Azure portal, I got the below error message.

ActionConditionFailed. The execution of template action ‘Condition’ is skipped: the ‘runAfter’ condition for action ‘SimpleJsonSchemaValidatorFunctionNameInstanceOne’ is not satisfied. Expected status values ‘Succeeded’ and actual value ‘Failed’.

The fix was simple.  Simply add “Failed” to a list of possible outcomes of that Logic App workflow step.
But you have to do it view the code view…….(aka, not in the Designer)

“runAfter”: {
“SimpleJsonSchemaValidatorFunctionNameInstanceOne”: [
“Failed”,     
“Succeeded”        ]

Now when I run my client, I got the proper response with the body text as seen below:

Specified argument was out of the range of valid values.
Parameter name: Not Cool Alert. (Invalid type. Expected String but got Null. Path ‘name’, line 2, position 15.,Invalid type. Expected String but got Number. Path ‘hobbies[1]’, line 3, position 45.)

(Again, my “bad” json is from the example from newtonsoft.  https://www.newtonsoft.com/json/help/html/JsonSchema.htm

Voila!  Now my Logic App Http Request Trigger will not only reject bad json, it will provide “hints” (aka, json schema error messages) back to the caller.  Now they can fix the json themselves without having to call me!

Below is my full LogicApp.json with my simple addition bolded

 

{
“$schema”: “https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#&#8221;,
“actions”: {
“SimpleJsonSchemaValidatorFunctionNameInstanceOne”: {
“type”: “Function”,
“inputs”: {
“body”: “@triggerBody()”,
“function”: {
“id”: “/subscriptions/yada/yada/yada/not/for/you/to/see/functions/SimpleJsonSchemaValidatorFunctionName”
}
},
“runAfter”: {}
},
“Condition”: {
“type”: “If”,
“expression”: “@equals(outputs(‘SimpleJsonSchemaValidatorFunctionNameInstanceOne’)[‘statusCode’], 200)”,
“actions”: {
“HoorayResponse”: {
“type”: “Response”,
“inputs”: {
“statusCode”: “@outputs(‘SimpleJsonSchemaValidatorFunctionNameInstanceOne’)[‘statusCode’]”,
“body”: “Hooray Everything AOK Hooray”
},
“runAfter”: {}
}
},
“runAfter”: {
“SimpleJsonSchemaValidatorFunctionNameInstanceOne”: [
“Failed”,
“Succeeded”
]
},
“else”: {
“actions”: {
“BooNoGoodResponse”: {
“type”: “Response”,
“inputs”: {
“statusCode”: “@outputs(‘SimpleJsonSchemaValidatorFunctionNameInstanceOne’)[‘statusCode’]”,
“body”: “@body(‘SimpleJsonSchemaValidatorFunctionNameInstanceOne’)”
},
“runAfter”: {}
}
}
}
}
},
“parameters”: {},
“triggers”: {
“manual”: {
“type”: “Request”,
“kind”: “Http”,
“inputs”: {
“schema”: {}
}
}
},
“contentVersion”: “1.0.0.0”,
“outputs”: {}
}

Posted in Software Development | Tagged | Leave a comment

Service Bus and Custom Self Signed Certificates with a High Availability/Multiple Computing Nodes in the Farm

Wow.  I had an adventure with certificates with an On Premise Service Bus installation.  At first, I was using the “Auto Generate” option.  However, I ran into an issue where I uninstalled Service Bus (but I left the certificates in the store), and tried to reinstall Service Bus (this time using the certificates that were already in the store.  (I was basically pseudo testing disaster recovery).

(Side note : Disaster recovery is kinda talked about here : http://sharepoint-community.net/profiles/blogs/workflow-manager-disaster-recovery )

I have posted something about the error (reinstalling by reusing the same certificates) here: https://social.msdn.microsoft.com/Forums/azure/en-US/6ae07eb9-121a-4187-8181-e198490a530d/using-the-auto-generated-certificates-causes-bad-key-issue-if-the-certificates-are-used-again-on?forum=servbus

Basically, I was getting a “Bad Key” error.

So let’s review a little bit.  The “Auto-Generate” option created certificates like this:

Certificate : IssuedTo: *Machine1.fullyqualified.domainname.com* Issued By: AppServerGeneratedSBCA Intended Purposes : Server Authentication

——–
Certificate : IssuedTo: AppServerGeneratedSBCA Issued By: AppServerGeneratedSBCA Intended Purposes : <All>

The most interesting part of the Auto-Generate option is the name of the “Service Authentication” certificate. *Machine1.fullyqualified.domainname.com* which reflects the first machine on which Service Bus was installed.

Then I documented where Microsoft (via the Service Bus installer) put these certficates:

Auto Created Certificates

Certificate : IssuedTo: *Machine1.fullyqualified.domainname.com* Issued By: AppServerGeneratedSBCA Intended Purposes : Server Authentication
On the “Server” aka “Machine1” (where you first installed Service Bus)
Cert Stores : (Personal) (This has the private key)

On “MachineN” (The ServiceBus “Add Farm” will auto-voodoo put the certs on MachineN)
Cert Stores : (Personal) (This has the private key)

On a “ClientMachine” (You must manually put the certs on this machine)
Cert Stores : (Personal) (No private key, aka public key)
——–
Certificate : IssuedTo: AppServerGeneratedSBCA Issued By: AppServerGeneratedSBCA Intended Purposes : <All>
On the “Server” aka “Machine1” (where you first installed Service Bus)
Cert Stores : (Personal, Trusted Root Certificate Authorities, Intermediate Certificate Authorities)….they are the same thumbprint) (This has the private key)

On “MachineN” (The ServiceBus “Add Farm” will auto-voodoo put the certs on MachineN)
Cert Stores : (Trusted Root Certificate Authorities) (This has the private key)

On a “ClientMachine” (You must manually put the certs on this machine)
Cert Stores : (Trusted Root Certificate Authorities) (No private key, aka public key)

So I started down the road of generating the certificates myself.

Using help I got from this article ( http://www.22bugs.co/post/sb-farm-errors-and-their-solutions/ ), I came up with this “.bat” file code to create the necessary certificates.  (If you are quick-reading this blog entry, then the code below will NOT work for multiple-computing-nodes in the farm.  Aka, don’t use this below code)

REM https://blogs.technet.microsoft.com/jhoward/2005/02/02/how-to-use-makecert-for-trusted-root-certification-authority-and-ssl-certificate-issuance/#comment-34025

set __rootDirectory=C:\LetsMakeSomeCerts\MakeCert\SelfSignedWithTrustedRootAuth\Output\
set __makecertExe=C:\LetsMakeSomeCerts\MakeCert\makecert.exe
set __pvk2pfxExe=C:\LetsMakeSomeCerts\MakeCert\PVK2PFX.exe

set __trustRootAuthorityName=MeAndMyselfTrustedRootAuthority

MD “%__rootDirectory%”

@ECHO OFF

ECHO Need to run As-Administrator to install certs in cert-store

FOR /f “tokens=2,* delims= ” %%a in (‘IPCONFIG ^/ALL ^| FINDSTR “Primary Dns”‘) do set tempsuffix=%%b
FOR /f “tokens=1,2 delims=:” %%a in (‘echo %tempsuffix%’) do set dnssuffix=%%b
SET __FQDN=%COMPUTERNAME%.%DNSSUFFIX:~1%

ECHO Server FQDN: %__FQDN%
%__makecertExe% -pe -r -n “CN=%__trustRootAuthorityName%” -ss my -sr LocalMachine -a sha1 -sky signature -b 10/01/2016 -e 12/31/9998 -sv “%__rootDirectory%%__trustRootAuthorityName%PrivateKeyfile.pvk” “%__rootDirectory%%__trustRootAuthorityName%.cer”

%__makecertExe% -pe -n “CN=%__FQDN%” -ss my -sr LocalMachine -a sha1 -sky exchange -eku 1.3.6.1.5.5.7.3.1 -in “%__trustRootAuthorityName%” -is MY -ir LocalMachine -sp “Microsoft RSA SChannel Cryptographic Provider” -sy 12 -b 10/01/2016 -e 12/31/9998 -sv “%__rootDirectory%%__FQDN%.pvk” “%__rootDirectory%%__FQDN%.cer
set __rootDirectory=
set __makecertExe=
set __pvk2pfxExe=
SET __FQDN=
set __trustRootAuthorityName=

pause

And that was working well, until I tried to add more computing-nodes to the farm.  One reason you add more computing-nodes to the farm is so that if one node fails, the others will pick it up.  Aka, High Availability.

So the setup looked like this:

First Machine with Service Bus : Machine1.fullyqualified.domainname.com
Second Machine with Service Bus : Machine2.fullyqualified.domainname.com

Well, then I “took down” the first machine, the “client” should be able to continue by communicating with Machine2.fullyqualified.domainname.com.  Mine was failing. 😦

So after looking at the certificates that Auto-Generate created, I discovered that the “Subject Alternate Name” was set to
DNS Name=*.fullyqualified.domainname.com
and that was the secret that allowed the client to talk to the second (or the third, or the fourth or the fifth) machine in the farm.

But “makecert.exe” doesn’t support setting the “Subject Alternate Name”.

Side note, you can read about the “Subject Alternate Name” here :
https://www.digicert.com/subject-alternative-name.htm

Gaaaaaaaaaaaaaaaaaaaaaaaa!  (That’s my version of a Homer Simpson “D’oh”)

So I couldn’t use Auto-Generate and “makecert.exe” couldn’t set (all of) the properties correctly.

So I tried to find some ways to create the certificates that supported “Subject Alternate Name”.

At first, I tried Mono.Security.  And that looked promising.  But I hit an issue that I logged here: ( https://stackoverflow.com/questions/40287336/mono-security-wont-set-multiple-keyusages )

So then I went to Bouncy Castle.  And I was able to create some “rough code” to get the certificates that I needed.

So I am posting that code here, in the hopes it may help someone.

The code will mimic the certificates : “Machine1.fullyqualified.domainname.com” and “AppServerGeneratedSBCA”.  Here the “AppServerGeneratedSBCA” is replaced by “BouncyCastleTrustedRootCertAuthority”.  (You can call it whatever name you choose).

The Machine1.fullyqualified.domainname.com certficate will be of the “1.3.6.1.5.5.7.3.1” variety.  I’ve also tried to mimic all of the key-usages that were in the original Microsoft “auto generated” certificates.

Which were:
(for “Machine1.fullyqualified.domainname.com”) : X509Extension.X509KeyUsageExtension.KeyUsages=’KeyEncipherment, DigitalSignature

and

(for “AppServerGeneratedSBCA”) (which will be “BouncyCastleTrustedRootCertAuthority”) :
X509Extension.X509KeyUsageExtension.KeyUsages=’CrlSign, KeyCertSign

And finally, here is the C# code.

using System;
using System.Collections.Generic;
using System.IO;

using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.Pkcs;
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Prng;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Pkcs;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities;
using Org.BouncyCastle.X509;

namespace ServiceBusCertificateMaker.BAL
{
/*
<?xml version=”1.0″ encoding=”utf-8″?>
<packages>
<package id=”BouncyCastle” version=”1.8.1″ targetFramework=”net45″ />
</packages>
*/

/* Notes, because this code actually places certificates IN YOUR CERTIFICATE STORE, it needs to be run “As Administrator” */

public class BouncyCastleMaker
{
public const string DefaultIssuer = “BouncyCastleTrustedRootCertAuthority”;

public void MakeItSo(string certificateName, List<string> subjectAlternateNames, string certificateFileName, string privateKeyFilePassword, string rootsigningCertFileName)
{
string issuerCnName = string.Format(“CN={0}”, DefaultIssuer);
AsymmetricKeyParameter caPrivKey = GenerateCACertificate(issuerCnName, privateKeyFilePassword, rootsigningCertFileName);
System.Security.Cryptography.X509Certificates.X509Certificate2 cert = GenerateSelfSignedCertificate(certificateName, subjectAlternateNames, certificateFileName, privateKeyFilePassword, issuerCnName, caPrivKey);
AddCertToStore(cert, System.Security.Cryptography.X509Certificates.StoreName.My, System.Security.Cryptography.X509Certificates.StoreLocation.LocalMachine);
ServiceBusSample.Shared.Showers.SecurityShower.ShowCertAndChain(cert);
}

public System.Security.Cryptography.X509Certificates.X509Certificate2 GenerateSelfSignedCertificate(string certificateName, List<string> subjectAlternateNames, string certificateFileName, string privateKeyFilePassword, string issuerName, AsymmetricKeyParameter issuerPrivKey)
{
return GenerateSelfSignedCertificate(certificateName, subjectAlternateNames, certificateFileName, privateKeyFilePassword, issuerName, issuerPrivKey, 2048);
}

public System.Security.Cryptography.X509Certificates.X509Certificate2 GenerateSelfSignedCertificate(string certificateName, List<string> subjectAlternateNames, string certificateFileName, string privateKeyFilePassword, string issuerName, AsymmetricKeyParameter issuerPrivKey, int keyStrength)
{
string subjectName = string.Format(“CN={0}”, certificateName);

// Generating Random Numbers
var randomGenerator = new CryptoApiRandomGenerator();
var random = new SecureRandom(randomGenerator);

// The Certificate Generator
X509V3CertificateGenerator certificateGenerator = new X509V3CertificateGenerator();

// Serial Number
var serialNumber = BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(long.MaxValue), random);
certificateGenerator.SetSerialNumber(serialNumber);

// Signature Algorithm
const string SignatureAlgorithm = “SHA256WithRSA”;
certificateGenerator.SetSignatureAlgorithm(SignatureAlgorithm);

// Issuer and Subject Name
var subjectDN = new X509Name(subjectName);

// original code var issuerDN = issuerName;
var issuerDN = new X509Name(issuerName);
certificateGenerator.SetIssuerDN(issuerDN);
certificateGenerator.SetSubjectDN(subjectDN);

// Valid For
var notBefore = DateTime.UtcNow.Date;
var notAfter = notBefore.AddYears(2);

certificateGenerator.SetNotBefore(notBefore);
certificateGenerator.SetNotAfter(notAfter);

KeyUsage keyUsage = new KeyUsage(KeyUsage.DigitalSignature | KeyUsage.KeyEncipherment);
certificateGenerator.AddExtension(X509Extensions.KeyUsage, true, keyUsage);

// Add the “Extended Key Usage” attribute, specifying “server authentication”.
var usages = new[] { KeyPurposeID.IdKPServerAuth };
certificateGenerator.AddExtension(
X509Extensions.ExtendedKeyUsage.Id,
false,
new ExtendedKeyUsage(usages));

/* DNS Name=*.fullyqualified.domainname.com */
if (subjectAlternateNames.Count <= 1)
{
/* the <=1 is for the simple reason of showing an alternate syntax .. */
foreach (string subjectAlternateName in subjectAlternateNames)
{
GeneralName altName = new GeneralName(GeneralName.DnsName, subjectAlternateName);
GeneralNames subjectAltName = new GeneralNames(altName);
certificateGenerator.AddExtension(X509Extensions.SubjectAlternativeName, false, subjectAltName);
}
}
else
{
//Asn1Encodable[] ansiEncodeSubjectAlternativeNames = new Asn1Encodable[]
// {
// //new GeneralName(GeneralName.DnsName, “*.fullyqualified.domainname.com”),
// new GeneralName(GeneralName.DnsName, “*.fullyqualified.domainname.com”)
// };

List<Asn1Encodable> asn1EncodableList = new List<Asn1Encodable>();
foreach (string subjectAlternateName in subjectAlternateNames)
{
asn1EncodableList.Add(new GeneralName(GeneralName.DnsName, subjectAlternateName));
}

DerSequence subjectAlternativeNamesExtension = new DerSequence(asn1EncodableList.ToArray());
certificateGenerator.AddExtension(X509Extensions.SubjectAlternativeName.Id, false, subjectAlternativeNamesExtension);
}

// Subject Public Key
AsymmetricCipherKeyPair subjectKeyPair;
var keyGenerationParameters = new KeyGenerationParameters(random, keyStrength);
var keyPairGenerator = new RsaKeyPairGenerator();
keyPairGenerator.Init(keyGenerationParameters);
subjectKeyPair = keyPairGenerator.GenerateKeyPair();

certificateGenerator.SetPublicKey(subjectKeyPair.Public);

// Generating the Certificate
var issuerKeyPair = subjectKeyPair;

// selfsign certificate
var certificate = certificateGenerator.Generate(issuerPrivKey, random);

// correcponding private key
PrivateKeyInfo pinfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(subjectKeyPair.Private);

// merge into X509Certificate2
var x509 = new System.Security.Cryptography.X509Certificates.X509Certificate2(certificate.GetEncoded());

var seq = (Asn1Sequence)Asn1Object.FromByteArray(pinfo.PrivateKey.GetDerEncoded());
if (seq.Count != 9)
{
throw new PemException(“malformed sequence in RSA private key”);
}

var rsa = new RsaPrivateKeyStructure(seq);
RsaPrivateCrtKeyParameters rsaparams = new RsaPrivateCrtKeyParameters(
rsa.Modulus, rsa.PublicExponent, rsa.PrivateExponent, rsa.Prime1, rsa.Prime2, rsa.Exponent1, rsa.Exponent2, rsa.Coefficient);

x509.PrivateKey = DotNetUtilities.ToRSA(rsaparams);

File.WriteAllBytes(certificateFileName.Replace(“.pfx”, “.cer”), x509.Export(System.Security.Cryptography.X509Certificates.X509ContentType.Cert));

// Export Certificate with private key
File.WriteAllBytes(certificateFileName, x509.Export(System.Security.Cryptography.X509Certificates.X509ContentType.Pkcs12, privateKeyFilePassword));

return x509;
}

public AsymmetricKeyParameter GenerateCACertificate(string subjectName, string privateKeyFilePassword, string rootsigningCertFileName, int keyStrength = 2048)
{
// Generating Random Numbers
var randomGenerator = new CryptoApiRandomGenerator();
var random = new SecureRandom(randomGenerator);

// The Certificate Generator
var certificateGenerator = new X509V3CertificateGenerator();

// Serial Number
var serialNumber = BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(long.MaxValue), random);
certificateGenerator.SetSerialNumber(serialNumber);

// Signature Algorithm
const string SignatureAlgorithm = “SHA256WithRSA”;
certificateGenerator.SetSignatureAlgorithm(SignatureAlgorithm);

// Issuer and Subject Name
var subjectDN = new X509Name(subjectName);
var issuerDN = subjectDN;
certificateGenerator.SetIssuerDN(issuerDN);
certificateGenerator.SetSubjectDN(subjectDN);

// Valid For
var notBefore = DateTime.UtcNow.Date;
var notAfter = notBefore.AddYears(2);

certificateGenerator.SetNotBefore(notBefore);
certificateGenerator.SetNotAfter(notAfter);

KeyUsage keyUsage = new KeyUsage(KeyUsage.KeyCertSign | KeyUsage.CrlSign);
certificateGenerator.AddExtension(X509Extensions.KeyUsage, true, keyUsage);

// Subject Public Key
AsymmetricCipherKeyPair subjectKeyPair;
var keyGenerationParameters = new KeyGenerationParameters(random, keyStrength);
var keyPairGenerator = new RsaKeyPairGenerator();
keyPairGenerator.Init(keyGenerationParameters);
subjectKeyPair = keyPairGenerator.GenerateKeyPair();

certificateGenerator.SetPublicKey(subjectKeyPair.Public);

// Generating the Certificate
var issuerKeyPair = subjectKeyPair;

// selfsign certificate
Org.BouncyCastle.X509.X509Certificate certificate = certificateGenerator.Generate(issuerKeyPair.Private, random);
System.Security.Cryptography.X509Certificates.X509Certificate2 x509 = new System.Security.Cryptography.X509Certificates.X509Certificate2(certificate.GetEncoded());

#region Private Key

// correcponding private key
PrivateKeyInfo pinfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(subjectKeyPair.Private);

var seq = (Asn1Sequence)Asn1Object.FromByteArray(pinfo.PrivateKey.GetDerEncoded());
if (seq.Count != 9)
{
throw new PemException(“malformed sequence in RSA private key”);
}

var rsa = new RsaPrivateKeyStructure(seq);
RsaPrivateCrtKeyParameters rsaparams = new RsaPrivateCrtKeyParameters(
rsa.Modulus, rsa.PublicExponent, rsa.PrivateExponent, rsa.Prime1, rsa.Prime2, rsa.Exponent1, rsa.Exponent2, rsa.Coefficient);

x509.PrivateKey = DotNetUtilities.ToRSA(rsaparams);
#endregion

// Add CA certificate to Root store
AddCertToStore(x509, System.Security.Cryptography.X509Certificates.StoreName.Root, System.Security.Cryptography.X509Certificates.StoreLocation.LocalMachine);

File.WriteAllBytes(rootsigningCertFileName.Replace(“.pfx”, “.cer”), x509.Export(System.Security.Cryptography.X509Certificates.X509ContentType.Cert));

// Export Certificate with private key
File.WriteAllBytes(rootsigningCertFileName, x509.Export(System.Security.Cryptography.X509Certificates.X509ContentType.Pkcs12, privateKeyFilePassword));

return issuerKeyPair.Private;
}

public bool AddCertToStore(System.Security.Cryptography.X509Certificates.X509Certificate2 cert, System.Security.Cryptography.X509Certificates.StoreName st, System.Security.Cryptography.X509Certificates.StoreLocation sl)
{
bool bRet = false;

try
{
System.Security.Cryptography.X509Certificates.X509Store store = new System.Security.Cryptography.X509Certificates.X509Store(st, sl);
store.Open(System.Security.Cryptography.X509Certificates.OpenFlags.ReadWrite);
store.Add(cert);

store.Close();
}
catch
{
throw;
}

return bRet;
}
}
}

And then the code to call it, with specific parameter names.

private static void RunBouncyCastleMakerStuff()
{
string fullyQualifiedName = “StarDot.fullyqualified.domainname.com”;

List<string> subjectAlternateNames = new List<string>();
/* you can either add by wildcard */
//subjectAlternateNames.Add(“*.fullyqualified.domainname.com”); /* see https://www.digicert.com/subject-alternative-name.htm */

/* or you can add by machine names on the farm */
subjectAlternateNames.Add(“Machine1.fullyqualified.domainname.com”);
subjectAlternateNames.Add(“Machine2.fullyqualified.domainname.com”);
subjectAlternateNames.Add(“Machine3.fullyqualified.domainname.com”);

string privateKeyFilePassword = “MyPrivateKeyPa$$word”;

string rootFolder = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString(“N”));

string certFileName = Path.Combine(rootFolder, fullyQualifiedName + “.pfx”);
string rootsigningCertFileName = Path.Combine(rootFolder, BouncyCastleMaker.DefaultIssuer + “.pfx”);

if(!Directory.Exists(rootFolder))
{
Directory.CreateDirectory(rootFolder);
}

if (System.IO.File.Exists(certFileName))
{
System.IO.File.Delete(certFileName);
}

if (System.IO.File.Exists(rootsigningCertFileName))
{
System.IO.File.Delete(rootsigningCertFileName);
}

new BouncyCastleMaker().MakeItSo(fullyQualifiedName, subjectAlternateNames, certFileName, privateKeyFilePassword, rootsigningCertFileName);

Process.Start(“explorer.exe”, rootFolder);
}

This will create the certificates:

Certificate : IssuedTo: *StarDot.fullyqualified.domainname.com* Issued By: BouncyCastleTrustedRootCertAuthority Intended Purposes : Server Authentication


 

Then you need to put the certificates in the stores of Machine1, Machine2-N, and “The Client”.

NOT Auto Created Certificates (Aka Custom Certificates)

Same as above “Auto Created Certificates” except

First: Manually Add all certificates listed above in “Auto Generate”.

ADDITIONALLY :

——–
Certificate : IssuedTo: BouncyCastleTrustedRootCertAuthority  Issued By: BouncyCastleTrustedRootCertAuthority  Intended Purposes : <All>

On “MachineN”
Cert Stores : Manually add (private-key-version) to Personal.

And there ya go.

I have tested installations, re-installs (pseudo testing disaster recovery), and that my client will keep processing, even if Machine1.fullyqualified.domainname.com “goes down”.  (You can test this by stopping the Windows-Service “Service Bus Gateway” on Machine1.fullyqualified.domainname.com (or Machine2.fullyqualified.domainname.com or MachineN.fullyqualified.domainname.com, but stopping the service on “Machine1.fullyqualified.domainname.com” is the test that proves the certificate still work for the other computing-nodes)

While I haven’t shown the “client” code, the client-code is main-stream code using this package:

<?xml version=”1.0″ encoding=”utf-8″?>
<packages>
<package id=”Microsoft.WindowsAzure.ConfigurationManager” version=”2.0.1.0″ targetFramework=”net45″ />
<package id=”WindowsAzure.ServiceBus” version=”2.1.4.0″ targetFramework=”net45″ />
</packages>

with objects such as MessagingFactory, QueueClient.

Oh yeah, here is my “Certificate-Show-er” code.  (Not shower, like bathing… 8) )

using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;

namespace ServiceBusSample.Shared.Showers
{
public static class SecurityShower
{
public static void ShowHttpWebRequest(System.Net.HttpWebRequest hwr)
{
StringBuilder sb = new StringBuilder();
if (null != hwr)
{
sb.Append(“———————————————–HttpWebRequest” + System.Environment.NewLine);
sb.Append(string.Format(“HttpWebRequest.Address.AbsolutePath='{0}'”, hwr.Address.AbsolutePath) + System.Environment.NewLine);
sb.Append(string.Format(“HttpWebRequest.Address.AbsoluteUri='{0}'”, hwr.Address.AbsoluteUri) + System.Environment.NewLine);
sb.Append(string.Format(“HttpWebRequest.Address='{0}'”, hwr.Address) + System.Environment.NewLine);

sb.Append(string.Format(“HttpWebRequest.RequestUri.AbsolutePath='{0}'”, hwr.RequestUri.AbsolutePath) + System.Environment.NewLine);
sb.Append(string.Format(“HttpWebRequest.RequestUri.AbsoluteUri='{0}'”, hwr.RequestUri.AbsoluteUri) + System.Environment.NewLine);
sb.Append(string.Format(“HttpWebRequest.RequestUri='{0}'”, hwr.RequestUri) + System.Environment.NewLine);

foreach (X509Certificate cert in hwr.ClientCertificates)
{
ShowX509Certificate(sb, cert);
}
}

string result = sb.ToString();
Console.WriteLine(result);
}

public static void ShowCertAndChain(X509Certificate2 cert)
{
X509Chain chain = new X509Chain();
chain.ChainPolicy.RevocationFlag = X509RevocationFlag.EntireChain;
chain.ChainPolicy.RevocationMode = X509RevocationMode.Offline;
chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllFlags;

chain.Build(cert);

ShowCertAndChain(cert, chain);
}

public static void ShowCertAndChain(X509Certificate cert, X509Chain chain)
{
StringBuilder sb = new StringBuilder();
if (null != cert)
{
ShowX509Certificate(sb, cert);
}

if (null != chain)
{
sb.Append(“-X509Chain(Start)-” + System.Environment.NewLine);
////sb.Append(string.Format(“Cert.ChainStatus='{0}'”, string.Join(“,”, chain.ChainStatus.ToList())) + System.Environment.NewLine);

foreach (X509ChainStatus cstat in chain.ChainStatus)
{
sb.Append(string.Format(“X509ChainStatus::'{0}’-‘{1}'”, cstat.Status.ToString(), cstat.StatusInformation) + System.Environment.NewLine);
}

X509ChainElementCollection ces = chain.ChainElements;
ShowX509ChainElementCollection(sb, ces);
sb.Append(“-X509Chain(End)-” + System.Environment.NewLine);
}

string result = sb.ToString();
Console.WriteLine(result);
}

private static void ShowX509Extension(StringBuilder sb, int x509ExtensionCount, X509Extension ext)
{
sb.Append(string.Empty + System.Environment.NewLine);
sb.Append(string.Format(“——–X509ExtensionNumber(Start):{0}”, x509ExtensionCount) + System.Environment.NewLine);
sb.Append(string.Format(“X509Extension.Critical='{0}'”, ext.Critical) + System.Environment.NewLine);

AsnEncodedData asndata = new AsnEncodedData(ext.Oid, ext.RawData);
sb.Append(string.Format(“Extension type: {0}”, ext.Oid.FriendlyName) + System.Environment.NewLine);
sb.Append(string.Format(“Oid value: {0}”, asndata.Oid.Value) + System.Environment.NewLine);
sb.Append(string.Format(“Raw data length: {0} {1}”, asndata.RawData.Length, Environment.NewLine) + System.Environment.NewLine);
sb.Append(asndata.Format(true) + System.Environment.NewLine);

X509BasicConstraintsExtension basicEx = ext as X509BasicConstraintsExtension;
if (null != basicEx)
{
sb.Append(“-X509BasicConstraintsExtension-” + System.Environment.NewLine);
sb.Append(string.Format(“X509Extension.X509BasicConstraintsExtension.CertificateAuthority='{0}'”, basicEx.CertificateAuthority) + System.Environment.NewLine);
}

X509EnhancedKeyUsageExtension keyEx = ext as X509EnhancedKeyUsageExtension;
if (null != keyEx)
{
sb.Append(“-X509EnhancedKeyUsageExtension-” + System.Environment.NewLine);
sb.Append(string.Format(“X509Extension.X509EnhancedKeyUsageExtension.EnhancedKeyUsages='{0}'”, keyEx.EnhancedKeyUsages) + System.Environment.NewLine);
foreach (Oid oi in keyEx.EnhancedKeyUsages)
{
sb.Append(string.Format(“————EnhancedKeyUsages.Oid.FriendlyName='{0}'”, oi.FriendlyName) + System.Environment.NewLine);
sb.Append(string.Format(“————EnhancedKeyUsages.Oid.Value='{0}'”, oi.Value) + System.Environment.NewLine);
}
}

X509KeyUsageExtension usageEx = ext as X509KeyUsageExtension;
if (null != usageEx)
{
sb.Append(“-X509KeyUsageExtension-” + System.Environment.NewLine);
sb.Append(string.Format(“X509Extension.X509KeyUsageExtension.KeyUsages='{0}'”, usageEx.KeyUsages) + System.Environment.NewLine);
sb.Append(string.Format(“X509KeyUsageExtension.KeyUsages.X509KeyUsageFlags.CrlSign='{0}'”, (usageEx.KeyUsages & X509KeyUsageFlags.CrlSign) != 0) + System.Environment.NewLine);
sb.Append(string.Format(“X509KeyUsageExtension.KeyUsages.X509KeyUsageFlags.DataEncipherment='{0}'”, (usageEx.KeyUsages & X509KeyUsageFlags.DataEncipherment) != 0) + System.Environment.NewLine);
sb.Append(string.Format(“X509KeyUsageExtension.KeyUsages.X509KeyUsageFlags.DecipherOnly='{0}'”, (usageEx.KeyUsages & X509KeyUsageFlags.DecipherOnly) != 0) + System.Environment.NewLine);
sb.Append(string.Format(“X509KeyUsageExtension.KeyUsages.X509KeyUsageFlags.DigitalSignature='{0}'”, (usageEx.KeyUsages & X509KeyUsageFlags.DigitalSignature) != 0) + System.Environment.NewLine);
sb.Append(string.Format(“X509KeyUsageExtension.KeyUsages.X509KeyUsageFlags.EncipherOnly='{0}'”, (usageEx.KeyUsages & X509KeyUsageFlags.EncipherOnly) != 0) + System.Environment.NewLine);
sb.Append(string.Format(“X509KeyUsageExtension.KeyUsages.X509KeyUsageFlags.KeyAgreement='{0}'”, (usageEx.KeyUsages & X509KeyUsageFlags.KeyAgreement) != 0) + System.Environment.NewLine);
sb.Append(string.Format(“X509KeyUsageExtension.KeyUsages.X509KeyUsageFlags.KeyCertSign='{0}'”, (usageEx.KeyUsages & X509KeyUsageFlags.KeyCertSign) != 0) + System.Environment.NewLine);
sb.Append(string.Format(“X509KeyUsageExtension.KeyUsages.X509KeyUsageFlags.KeyEncipherment='{0}'”, (usageEx.KeyUsages & X509KeyUsageFlags.KeyEncipherment) != 0) + System.Environment.NewLine);
sb.Append(string.Format(“X509KeyUsageExtension.KeyUsages.X509KeyUsageFlags.None='{0}'”, (usageEx.KeyUsages & X509KeyUsageFlags.None) != 0) + System.Environment.NewLine);
sb.Append(string.Format(“X509KeyUsageExtension.KeyUsages.X509KeyUsageFlags.NonRepudiation='{0}'”, (usageEx.KeyUsages & X509KeyUsageFlags.NonRepudiation) != 0) + System.Environment.NewLine);
}

X509SubjectKeyIdentifierExtension skIdEx = ext as X509SubjectKeyIdentifierExtension;
if (null != skIdEx)
{
sb.Append(“-X509SubjectKeyIdentifierExtension-” + System.Environment.NewLine);
sb.Append(string.Format(“X509Extension.X509SubjectKeyIdentifierExtension.Oid='{0}'”, skIdEx.Oid) + System.Environment.NewLine);
sb.Append(string.Format(“X509Extension.X509SubjectKeyIdentifierExtension.SubjectKeyIdentifier='{0}'”, skIdEx.SubjectKeyIdentifier) + System.Environment.NewLine);
}

sb.Append(string.Format(“——–X509ExtensionNumber(End):{0}”, x509ExtensionCount) + System.Environment.NewLine);
}

private static void ShowX509Extensions(StringBuilder sb, string cert2SubjectName, X509ExtensionCollection extColl)
{
int x509ExtensionCount = 0;
sb.Append(string.Format(“——–ShowX509Extensions(Start):for:{0}”, cert2SubjectName) + System.Environment.NewLine);
foreach (X509Extension ext in extColl)
{
ShowX509Extension(sb, ++x509ExtensionCount, ext);
}

sb.Append(string.Format(“——–ShowX509Extensions(End):for:{0}”, cert2SubjectName) + System.Environment.NewLine);
}

private static void ShowX509Certificate2(StringBuilder sb, X509Certificate2 cert2)
{
if (null != cert2)
{
sb.Append(string.Format(“X509Certificate2.SubjectName.Name='{0}'”, cert2.SubjectName.Name) + System.Environment.NewLine);
sb.Append(string.Format(“X509Certificate2.Subject='{0}'”, cert2.Subject) + System.Environment.NewLine);
sb.Append(string.Format(“X509Certificate2.Thumbprint='{0}'”, cert2.Thumbprint) + System.Environment.NewLine);
sb.Append(string.Format(“X509Certificate2.HasPrivateKey='{0}'”, cert2.HasPrivateKey) + System.Environment.NewLine);
sb.Append(string.Format(“X509Certificate2.Version='{0}'”, cert2.Version) + System.Environment.NewLine);
sb.Append(string.Format(“X509Certificate2.NotBefore='{0}'”, cert2.NotBefore) + System.Environment.NewLine);
sb.Append(string.Format(“X509Certificate2.NotAfter='{0}'”, cert2.NotAfter) + System.Environment.NewLine);
sb.Append(string.Format(“X509Certificate2.PublicKey.Key.KeySize='{0}'”, cert2.PublicKey.Key.KeySize) + System.Environment.NewLine);

////List<X509KeyUsageExtension> keyUsageExtensions = cert2.Extensions.OfType<X509KeyUsageExtension>().ToList();
////List<X509Extension> extensions = cert2.Extensions.OfType<X509Extension>().ToList();

ShowX509Extensions(sb, cert2.Subject, cert2.Extensions);
}
}

private static void ShowX509ChainElementCollection(StringBuilder sb, X509ChainElementCollection ces)
{
int x509ChainElementCount = 0;
foreach (X509ChainElement ce in ces)
{
sb.Append(string.Empty + System.Environment.NewLine);
sb.Append(string.Format(“—-X509ChainElementNumber:{0}”, ++x509ChainElementCount) + System.Environment.NewLine);
sb.Append(string.Format(“X509ChainElement.Cert.SubjectName.Name='{0}'”, ce.Certificate.SubjectName.Name) + System.Environment.NewLine);
sb.Append(string.Format(“X509ChainElement.Cert.Issuer='{0}'”, ce.Certificate.Issuer) + System.Environment.NewLine);
sb.Append(string.Format(“X509ChainElement.Cert.Thumbprint='{0}'”, ce.Certificate.Thumbprint) + System.Environment.NewLine);
sb.Append(string.Format(“X509ChainElement.Cert.HasPrivateKey='{0}'”, ce.Certificate.HasPrivateKey) + System.Environment.NewLine);

X509Certificate2 cert2 = ce.Certificate as X509Certificate2;
ShowX509Certificate2(sb, cert2);

ShowX509Extensions(sb, cert2.Subject, ce.Certificate.Extensions);
}
}

private static void ShowX509Certificate(StringBuilder sb, X509Certificate cert)
{
sb.Append(“———————————————–” + System.Environment.NewLine);
sb.Append(string.Format(“Cert.Subject='{0}'”, cert.Subject) + System.Environment.NewLine);
sb.Append(string.Format(“Cert.Issuer='{0}'”, cert.Issuer) + System.Environment.NewLine);

sb.Append(string.Format(“Cert.GetPublicKey().Length='{0}'”, cert.GetPublicKey().Length) + System.Environment.NewLine);

X509Certificate2 cert2 = cert as X509Certificate2;
ShowX509Certificate2(sb, cert2);
}
}
}

Last note:  If you’re having certificate issues on “the client”, you can hook into this event below to see what is happening.  This is how I originally figured out all the settings on the Auto-Generated certificates.

/* Use the below to debug failed verification. Remember that the Certificate ALTERNATE subject name comes into play in a High Availability scenario */
ServicePointManager.ServerCertificateValidationCallback =
new System.Net.Security.RemoteCertificateValidationCallback((
sender,
cert,
chain,
ssl) =>
{
Console.WriteLine(“ServerCertificateValidationCallback for Cert.Subject : ‘{0}'”, cert.Subject);
System.Net.HttpWebRequest hwr = sender as System.Net.HttpWebRequest;
if (null != hwr)
{
SecurityShower.ShowHttpWebRequest(hwr);
}

SecurityShower.ShowCertAndChain(cert, chain);
return true; /* return true here is ONLY FOR DEBUGGING */
});

Posted in Uncategorized | Leave a comment

Custom MSBuild Task and capturing Command Line Output

I recently had a need to “capture the output” of a command line tool, but within a MSBuild Custom Task (context).

While I know there are “msbuild’ish” ways to accomplish the below example (getting a list of directories from a “dir” command), the below is an ~~example~~ of how to capture the output of a command line call.

What am I talking about?

Well, for example, if run the command (from a command line prompt):

dir “c:\”

You would see (in the command line window) something like the below:

C:\>dir “c:\”

Volume in drive C has no label.
Volume Serial Number is JER-33_3

Directory of c:\

10/15/2012 01:20 PM <DIR> Program Files
11/08/2012 02:29 PM <DIR> Program Files (x86)
08/16/2012 02:23 PM <DIR> Users
11/08/2012 02:08 PM <DIR> Windows

0 File(s) 0 bytes
4 Dir(s) 33,490,378,752 bytes free

C:\>

So how can I “capture” the output while inside of a custom MSBuild Task?

First.  I didn’t figure this out on my own.  I googled and bing searched by rumpus off.  And then I came across an example.

https://msbuildextensionpack.svn.codeplex.com/svn/Solutions/Main3.5/Framework/Framework/CommandLine.cs

namespace MSBuild.ExtensionPack.Framework
{
[HelpUrl(“http://www.msbuildextensionpack.com/help/3.5.12.0/html/324b0e31-5ff0-baac-40ae-bf26297e5821.htm&#8221;)]
public class CommandLine : Task
{
//not seen stuff here
}
}

And I totally ripped their code.

But what I did do is package this up in a smaller (more digestable?) example as seen below.
And I remember when I first started with writing my own custom MSBuild tasks that what is obvious to me now, was not obvious when I first started.

So, in a nutshell:
“CollectedOutput” will be the property that has all the contents for the ‘dir “c:\”‘.

The CSharp code will need to be put into a “Class Library” DotNet csproj of course.
If you want the example to run “out of the box”, then name the new csproj with the name “GranadaCoder.Framework.CrossDomain.MSBuild” (If you don’t do this, you’ll need to adjust the name of the .dll mentioned in the .msbuild file).
After compiling, place the .dll in the same folder as the .msbuild and .bat file.

//START CSharp Code//

namespace GranadaCoder.Framework.CrossDomain.MSBuild.Tasks.Temp
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.ComponentModel;
using System.Reflection;

using Microsoft.Build.Utilities;
using Microsoft.Build.Framework;
using System.Diagnostics;

public class CommandLineDirectoryTask : ToolTask
{

private static readonly string WINDIR_ENVIRONMENT_VARIABLE = “windir”;
private static readonly string CMD_RUNTIME_EXE = “cmd.exe”;
private static readonly string COMMAND_LINE_SWITCH_C_DIR = “/c dir”;

public CommandLineDirectoryTask()
{
base.ToolExe = CMD_RUNTIME_EXE; // see http://msdn.microsoft.com/en-us/library/microsoft.build.utilities.tooltask.toolexe.aspx
this.ToolPath = this.ReadSystem32EnvironmentVariable();
}

[Required]
public string DirectoryNameToList { get; set; }

/// <summary>
/// Gets or sets the collected output from the command-line.
/// </summary>
///
[Output]
public string CollectedOutput { get; set; }

/// <summary>
/// Gets or sets the StdErr stream encoding. Specifies the encoding of the captured task standard error stream.
/// The default is the current console output encoding.
/// </summary>
/// <remarks>Exec Equivalent: StdErrEncoding</remarks>
[Output]
public string StdErrEncoding { get; set; }

/// <summary>
/// Gets or sets the StdOut stream encoding. Specifies the encoding of the captured task standard output stream.
/// The default is the current console output encoding.
/// </summary>
/// <remarks>Exec Equivalent: StdOutEncoding</remarks>
[Output]
public string StdOutEncoding { get; set; }

/// <summary>
/// Gets the name of the tool.
/// </summary>
/// <value>The name of the tool.</value>
protected override string ToolName
{
get { return base.ToolExe; }
}

/// <summary>
/// Generates the full path to tool.
/// </summary>
/// <returns></returns>
protected override string GenerateFullPathToTool()
{
return Path.Combine(ToolPath, ToolName);
}

/// <summary>
/// Executes this instance.
/// </summary>
/// <returns></returns>
public override bool Execute()
{
//return base.Execute();
return InternalExecute();
}

private bool InternalExecute()
{

string command = this.GenerateFullPathToTool();
string commandLineArguments = GenerateSvnExportCommandLineArguments();

this.Log.LogMessage(“Execute: {0} {1}”, command, commandLineArguments);
ProcessStartInfo startInfo = this.GetCommandLine(command, commandLineArguments, this.DirectoryNameToList, this.StdErrEncoding, this.StdOutEncoding);
using (Process process = Process.Start(startInfo))
{
//this.Log.LogMessage(“Collect Standard Output Stream”);

while (!process.StandardOutput.EndOfStream || !process.HasExited)
{
this.CollectOutputLine(process.StandardOutput.ReadLine());
}

//this.Log.LogMessage(“Collect Standard Error Stream”);
while (!process.StandardError.EndOfStream)
{
this.CollectOutputLine(process.StandardError.ReadLine());
}

}

return true;

}

/// <summary>
/// Gets a command process object with the command specified.
/// </summary>
/// <param name=”command”>The command to execute</param>
/// <param name=”workingDirectory”>The command working directory</param>
/// <param name=”standardErrorEncoding”>The standard error stream encoding</param>
/// <param name=”standardOutputEncoding”>The standard output stream encoding</param>
/// <returns>Returns a command prompt start information that is ready to start</returns>
/// <remarks>StdErr and StdOut are always redirected.</remarks>
private ProcessStartInfo GetCommandLine(string command, string commandLineArguments, string workingDirectory, string standardErrorEncoding, string standardOutputEncoding)
{
var process = new ProcessStartInfo
{
FileName = command,
Arguments = commandLineArguments,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true,
ErrorDialog = false
};

if (!string.IsNullOrEmpty(standardErrorEncoding))
{
try
{
process.StandardErrorEncoding = Encoding.GetEncoding(standardErrorEncoding);
}
catch (ArgumentException ex)
{
this.Log.LogMessage(“Non-fatal exception caught: invalid encoding specified for standard error stream: {0}”, standardErrorEncoding);
this.Log.LogWarningFromException(ex);
}
}

if (!string.IsNullOrEmpty(standardOutputEncoding))
{
try
{
process.StandardOutputEncoding = Encoding.GetEncoding(standardOutputEncoding);
}
catch (ArgumentException ex)
{
this.Log.LogMessage(“Non-fatal exception caught: invalid encoding specified for standard output stream: {0}”, standardOutputEncoding);
this.Log.LogWarningFromException(ex);
}
}

if (!string.IsNullOrEmpty(workingDirectory))
{
if (Directory.Exists(workingDirectory))
{
process.WorkingDirectory = workingDirectory;
}
else
{
this.Log.LogWarning(“Non-fatal input error: provided working directory does not exist: {0}”, workingDirectory);
}
}

return process;
}

/// <summary>
/// Generates the command line commands.
/// </summary>
/// <returns></returns>
protected string GenerateSvnExportCommandLineArguments()
{
StringBuilder builder = new StringBuilder();
AppendIfPresent(builder, CommandLineDirectoryTask.COMMAND_LINE_SWITCH_C_DIR, QuoteItUp(this.DirectoryNameToList));
Log.LogCommandLine(builder.ToString());
return builder.ToString();
}

/// <summary>
/// Collects a line of output.
/// </summary>
/// <param name=”text”>The text line</param>
private string CollectOutputLine(string text)
{
text = string.IsNullOrEmpty(text) ? null : text.Trim();
if (!string.IsNullOrEmpty(text))
{
this.CollectedOutput += Environment.NewLine + text;
this.Log.LogMessage(text);
}

return text;
}

/// <summary>
/// Append the command and argument only if the argument exists. Repped from the internet at http://www.zorched.net/2009/01/08/msbuild-task-for-partcover/
/// </summary>
/// <param name=”builder”>The containing string builder.</param>
/// <param name=”cmdArg”>The command argument switch.</param>
/// <param name=”value”>The value of the command argument.</param>
protected static void AppendIfPresent(StringBuilder builder, string cmdArg, string value)
{
if (!String.IsNullOrEmpty(value))
{
builder.AppendFormat(“{0} {1} “, cmdArg, value);
}
}

/// <summary>
/// Wrap quotes around a string and escape charcters if needed.
/// </summary>
/// <param name=”builder”>The containing string builder.</param>
protected static string QuoteItUp(string args)
{
if (String.IsNullOrEmpty(args))
{
return args;
}

bool alreadyHasQuoteBookEnds = false;

if (args.StartsWith(“\””) && args.EndsWith(“\””))
{
alreadyHasQuoteBookEnds = true;
}

// Escape internal quotes if any
if (args.Contains(“\””))
{
args = args.Replace(“\””, “\\\””);
}

if (!alreadyHasQuoteBookEnds)
{
// quote string
args = String.Format(“\”{0}\””, args);
}
return args;
}

private string ReadSystem32EnvironmentVariable()
{
string returnValue = string.Empty;

if (!String.IsNullOrEmpty(System.Environment.GetEnvironmentVariable(WINDIR_ENVIRONMENT_VARIABLE)))
{
returnValue = System.Environment.GetEnvironmentVariable(WINDIR_ENVIRONMENT_VARIABLE);
returnValue = Path.Combine(returnValue, “System32”);
}
else
{
base.Log.LogWarning(string.Format(“The ‘{0}’ Environment Variable was not available. You will need to manually set the ToolPath value”, WINDIR_ENVIRONMENT_VARIABLE));
}

return returnValue;
}
}
}

//END CSHARP Code

—————————————

//Start file “CommandLineDirectoryTaskTest.msbuild”

<?xml version=”1.0″ encoding=”utf-8″?>
<Project DefaultTargets=”AllTargetsWrapper” xmlns=”http://schemas.microsoft.com/developer/msbuild/2003″&gt;
<!– –>
<PropertyGroup>
<WorkingDirectory>.</WorkingDirectory>
</PropertyGroup>
<!– –>
<PropertyGroup>
<GranadaCoderMSBuildFileName Condition=”Exists(‘$(WorkingDirectory)\MSBuildHelpers\GranadaCoder.Framework.CrossDomain.MSBuild.dll’)”>$(WorkingDirectory)\MSBuildHelpers\GranadaCoder.Framework.CrossDomain.MSBuild.dll</GranadaCoderMSBuildFileName>
<GranadaCoderMSBuildFileName Condition=”Exists(‘$(WorkingDirectory)\GranadaCoder.Framework.CrossDomain.MSBuild.dll’)”>$(WorkingDirectory)\GranadaCoder.Framework.CrossDomain.MSBuild.dll</GranadaCoderMSBuildFileName>
<GranadaCoderMSBuildFileName Condition=”$(GranadaCoderMSBuildFileName)==””>CannotFind_GranadaCoder.Framework.CrossDomain.MSBuild.dll</GranadaCoderMSBuildFileName>
</PropertyGroup>
<!– –>
<!– –>
<UsingTask AssemblyFile=”$(GranadaCoderMSBuildFileName)” TaskName=”CommandLineDirectoryTask”/>
<!– –>
<!– –>
<Target Name=”AllTargetsWrapper”>
<CallTarget Targets=”CommandLineDirectoryTask1″ />
</Target>
<!– –>
<!– –>
<Target Name=”CommandLineDirectoryTask1″>

<CommandLineDirectoryTask DirectoryNameToList=”C:\wutemp\”>
<Output TaskParameter=”CollectedOutput” PropertyName=”MyCollectedOutput1″/>
</CommandLineDirectoryTask>

<Message Text=”The CollectedOutput1 is $(MyCollectedOutput1)”/>
<Message Text=” “/>
<Message Text=” “/>
<Message Text=” “/>
<Message Text=” “/>

<CommandLineDirectoryTask ContinueOnError=”true” DirectoryNameToList=”C:\work3\” >
<Output TaskParameter=”ExitCode” PropertyName=”MyErrorCode”/>
<Output TaskParameter=”CollectedOutput” PropertyName=”MyCollectedOutput2″/>
</CommandLineDirectoryTask>

<Message Text=”The CollectedOutput2 is $(MyCollectedOutput1)”/>
<Message Text=” “/>
<Message Text=” “/>
<Message Text=”The exit code (MyErrorCode) is $(MyErrorCode)”/>

</Target>

</Project>

//End file “CommandLineDirectoryTaskTest.msbuild”

—————————————

//Start CommandLineDirectoryTaskTest.bat file
set msBuildDir=%WINDIR%\Microsoft.NET\Framework\v3.5
set msBuildDir=%WINDIR%\Microsoft.NET\Framework\v2.0.50727
set msBuildDir=%WINDIR%\Microsoft.NET\Framework\v3.5

call %msBuildDir%\msbuild /target:AllTargetsWrapper “CommandLineDirectoryTaskTest.msbuild” /p:Configuration=Release;FavoriteFood=Popeyes /l:FileLogger,Microsoft.Build.Engine;logfile=CommandLineDirectoryTaskTest_AllTargetsWrapped.log

set msBuildDir=

//End CommandLineDirectoryTaskTest.bat file

Posted in Software Development | Leave a comment

How to find References in a C# Project File (.csproj) using LINQ (Xml)

I was asked to “Generate a report of all our c# projects and their dependencies.

:<

So instead of going through 333+ csprojs manually, it was time to write a helper routine to look through the .csproj xml.

And instead of old-school XPath and SelectNodes() (boooo), it was time to write some Linqy-Dinq.

The below code will query a csproj file and report back all all project references. 

It will report back:

(1) If the reference is an already compiled dll.  Not in the GAC.
(2) If the reference is an already compiled dll.  In the GAC.
(3) If the reference is a reference “by project”.

Feel free to post any suggestions and/or improvements.

The biggest trick was adding the namespace to the conditional clauses. ( ns + “SomeElementName” ).
The other trick was figuring out how to ignore Xml-Element(s) if there was no value.
Oh, it is so simple when it is done.  But took a while to figure out the nuances.

//using System.Xml.Linq;

string fileName = @”C:\MyFolder\MyProjectFile.csproj”;

XDocument xDoc = XDocument.Load(fileName);

XNamespace ns = XNamespace.Get(http://schemas.microsoft.com/developer/msbuild/2003&#8221;);


//References “By DLL (file)”

var list1 = from list in xDoc.Descendants(ns + “ItemGroup”)
from item in list.Elements(ns + “Reference”)

/* where item.Element(ns + “HintPath”) != null */ /* optional */

select new
{
CsProjFileName = fileName,
ReferenceInclude = item.Attribute(“Include”).Value,
RefType = (item.Element(ns + “HintPath”) == null) ? “CompiledDLLInGac” : “CompiledDLL”,
 HintPath = (item.Element(ns + “HintPath”) == null) ? string.Empty : item.Element(ns + “HintPath”).Value};

foreach  (var v in list1)
{
    Console.WriteLine(v.ToString());
}

//References “By Project”
var list2 = from list in xDoc.Descendants(ns + “ItemGroup”)
from item in list.Elements(ns + “ProjectReference”)

where
item.Element(ns + “Project”) != null

select new
{
CsProjFileName = fileName,
ReferenceInclude = item.Attribute(“Include”).Value,
RefType = “ProjectReference”,
ProjectGuid = item.Element(ns + “Project”).Value
};

foreach (var v in list2)
{
    Console.WriteLine(v.ToString());
}

Posts that helped me:

http://stackoverflow.com/questions/2338512/understanding-linq-to-xml-descendants-return-no-results

http://stackoverflow.com/questions/2630192/c-sharp-check-an-element-exists-while-using-linq-to-xml

Bonus Code:

string startFolder = @”C:\DotNetCodeBase\”;

System.IO.DirectoryInfo dir = new System.IO.DirectoryInfo(startFolder);

IEnumerable<System.IO.FileInfo> fileList = dir.GetFiles(“*.csproj”, System.IO.SearchOption.AllDirectories);

IEnumerable<System.IO.FileInfo> fileQuery = from file in fileList
    where file.Extension == “.csproj”
    orderby file.Name
select file;

 

Posted in Software Development | 3 Comments

Create a COM+ Application with Powershell

$comAdmin = New-Object -comobject COMAdmin.COMAdminCatalog
$apps = $comAdmin.GetCollection(“Applications”)
$apps.Populate();

$newComPackageName = “MyFirstCOMPackage”

$appExistCheckApp = $apps | Where-Object {$_.Name -eq $newComPackageName}

if($appExistCheckApp)
{
$appExistCheckAppName = $appExistCheckApp.Value(“Name”)
“This COM+ Application already exists : $appExistCheckAppName”
}
Else
{
$newApp1 = $apps.Add()
$newApp1.Value(“Name”) = $newComPackageName
$newApp1.Value(“ApplicationAccessChecksEnabled”) = 0 <# Security Tab, Authorization Panel, “Enforce access checks for this application #>

<# See http://msdn.microsoft.com/en-us/library/ms686107(v=VS.85).aspx#identity for full documentation. #>

<# Optional (to set to a specific Identify) #>
$newApp1.Value(“Identity”) = “MyDomain\myUserName”
$newApp1.Value(“Password”) = “myPassword”

$saveChangesResult = $apps.SaveChanges()
“Results of the SaveChanges operation : $saveChangesResult”
}

Full documentation of the properties here.

http://msdn.microsoft.com/en-us/library/ms686107(v=VS.85).aspx#applicationaccesschecksenabled

I’m a C# developer.  But Powershell rocks the suburbs for alot of tasks!

Posted in Software Development | Leave a comment

Hello world!

Welcome to WordPress.com. This is your first post. Edit or delete it and start blogging!

Posted in Uncategorized | 1 Comment

Bug in Documentation : Microsoft Access Database Engine 2010 Redistributable

Microsoft Access
Database Engine 2010 Redistributable

http://www.microsoft.com/downloads/en/details.aspx?familyid=C06B8369-60DD-4B64-A44B-84B371EDE16D&displaylang=en

There is a bug in the documentation at the download page.

The documentation says:
1.If you are the user of an application, consult your application
documentation for details on how to use the appropriate driver.

2.If
you are an application developer using OLEDB, set the Provider argument
of the ConnectionString property to “Microsoft.ACE.OLEDB.12.0”
    If
you are connecting to Microsoft Office Excel data, add “Excel 14.0” to
the Extended Properties of the OLEDB connection string.

The "Excel 14.0" is the issue.

It should be "Excel 12.0".

Her are a few connection strings to provide full context.

// Old School Jet, been around for a while
"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=’C:\MyOldSchoolFile.xls’;Extended Properties=’Excel 8.0;HDR=NO;IMEX=1;’;"

//Newer version with xslx
"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=’C:\MyXlsXFile.xlsx’;Extended Properties=’Excel 12.0 Xml;HDR=NO;IMEX=1;’;"

//Newer version, any xls file
"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=’C:\AlmostAnyExcelVersionFileRunningUnder64BitOS.xls’;Extended Properties=’Excel 12.0;HDR=NO;IMEX=1;’;"

Don’t take the above as absolute truth.  But it should draw attention to the issue (if you’re experiencing it), and help with some more google (errr. bing) searches.

Here are some other phrases which might lead you here.

The OLE DB provider "Microsoft.Jet.OLEDB.4.0" has not been registered
    ( Trying to read an excel file on a 64 bit O/S?  The purple string above should work for you under a 64 bit O/S. )

"Could not find installable ISAM"     
    ( This might show up because of the "14.0" vs "12.0" bug mentioned above )

See also:
http://stackoverflow.com/questions/2075054/upload-an-excel-file-in-classic-asp-on-windows-2003-x64-using-office-2010-drivers/

http://social.msdn.microsoft.com/Forums/en/adodotnetdataproviders/thread/686d8ebb-0da3-4f0c-bf16-9c650f8dcb32

http://www.connectionstrings.com/excel-2007

Posted in Software Development | 6 Comments