<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="https://www.w3.org/2005/Atom" xmlns:sy="https://purl.org/rss/1.0/modules/syndication/" xmlns:dc="https://purl.org/dc/elements/1.1/" xmlns:content="https://purl.org/rss/1.0/modules/content/" xmlns:wfw="https://wellformedweb.org/CommentAPI/" xmlns:slash="https://purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>Tim's blog</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/timomta/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/timomta/feed.xml</link>
    <description>A Microsoft Field Consultant&amp;#039;s Notes</description>
    <lastBuildDate>Mon, 09 Apr 2018 19:03:12 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>How to Add the OMS Client to a VM Scale Set</title>
      <link>https://docs.microsoft.com/archive/blogs/timomta/how-to-add-the-oms-client-to-a-vm-scale-set</link>
      <pubDate>Mon, 09 Apr 2018 12:03:12 GMT</pubDate>
      <dc:creator><![CDATA[Tim Omta]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/timomta/?p=545</guid>
      <description><![CDATA[I was asked by a customer to add the OMS client to an Azure VM ScaleSet (VMSS). This is not...]]></description>
      <content:encoded><![CDATA[I was asked by a customer to add the OMS client to an Azure VM ScaleSet (VMSS). This is not documented directly for a VMSS, though it is for Azure VMs. After some asking around and some experimentation, I was able to successfully deploy the OMS agent to the VMSS using the following PowerShell:

<code>select-azurermsubscription -subscriptionid ‘your subscription id’
$PublicSettings = @{"workspaceId" = "your oms workspace id"}
$ProtectedSettings = @{"workspaceKey" = "your big base64 oms key"}

# Get information about the scale set
$vmss = Get-AzureRmVmss -ResourceGroupName 'VMSSRESOURCEGROUP' `
                        -VMScaleSetName 'VMSSNAME'

Add-AzureRmVmssExtension `
   -VirtualMachineScaleSet $vmss `
   -Name "Microsoft.EnterpriseCloud.Monitoring" `
   -Publisher "Microsoft.EnterpriseCloud.Monitoring" `
   -Type "MicrosoftMonitoringAgent" `
   -TypeHandlerVersion 1.0 `
   -AutoUpgradeMinorVersion $true `
   -Setting $PublicSettings `
   -ProtectedSetting $ProtectedSettings 

# Update the scale set and apply the Custom Script Extension to the VM instances
Update-AzureRmVmss `
              -ResourceGroupName $vmss.ResourceGroupName `
              -Name $vmss.Name `
              -VirtualMachineScaleSet $vmss

# Only needed for manual update VMSS – warning tells them all to update, so modify to suit
$jobs=@()
Get-AzureRmVmssVM -ResourceGroupName $vmss.ResourceGroupName -VMScaleSetName $vmss.Name | foreach {
    $jobs+=Update-AzureRmVmssInstance -ResourceGroupName $vmss.ResourceGroupName -Name $vmss.Name -InstanceId $_.InstanceId -AsJob
}

$jobs | Wait-Job
$jobs | Receive-Job</code>

<strong>References</strong>
<a href="https://docs.microsoft.com/en-us/azure/virtual-machine-scale-sets/">Azure VMSS </a>
<a href="https://docs.microsoft.com/en-us/azure/operations-management-suite/operations-management-suite-overview">Azure Operations Management Suite (OMS)</a> 
<a href="https://docs.microsoft.com/en-us/azure/virtual-machines/windows/extensions-oms">Azure VM OMS Agent</a>]]></content:encoded>
    </item>
    <item>
      <title>Stand Alone Service Fabric Error=EndpointProviderPortRangeExhausted</title>
      <link>https://docs.microsoft.com/archive/blogs/timomta/stand-alone-service-fabric-errorendpointproviderportrangeexhausted</link>
      <pubDate>Thu, 14 Dec 2017 15:23:06 GMT</pubDate>
      <dc:creator><![CDATA[Tim Omta]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/timomta/?p=535</guid>
      <description><![CDATA[I ran into an issue with a customer wherein they had set up an on-premise, or stand-alone, Service...]]></description>
      <content:encoded><![CDATA[<p>I ran into an issue with a customer wherein they had set up an on-premise, or stand-alone, Service Fabric cluster. They had deployed several services to the cluster and some of the services would seem to randomly fail to start. The only way to see some information about the errors was to take a look in the Application Event logs on the nodes.
</p><p>We observed errors that looked like this:
</p><p>End(ActivateServicePackageInstance): AppId=mtsDeviceServiceType_App0, AppVersion=1.0 ServicePackageName=ContainerActorPkg, ServicePackageActivationContext=, ServicePackageVersionInstance=1.0:1.0:131575929604768573, <strong>Error=EndpointProviderPortRangeExhausted</strong>
	</p><p>It was odd to me because I had never seen this before in clusters hosted in Azure. After speaking with support, it turns out that stand-alone clusters have a much lower ephemeral port range of 30 ports by default. An Azure cluster is set much higher, which is why I had never seen the error there.
</p><p>In this case the ephemeral port range was being used up on a first-come-first-served basis by whichever service started and got a port first, so the erroring applications looked random.
</p><p>To correct the error, increase the # of application ports by modifying the standalone cluster templates (like ClusterConfig.X509.MultiMachine.json) to allocate a larger range:<br /><br /><span style="font-family:Courier New">"nodeTypes": [<br />{<br />"name": "NodeType0",<br />...<br />"applicationPorts": {<br />"startPort": "20001",<br />"endPort": "20031" </span><span style="font-family:Wingdings">ß</span><span style="font-family:Courier New"> use a higher number giving you a larger range<br />},<br />}
</span></p><p>References
</p><p><a href="https://docs.microsoft.com/en-us/azure/service-fabric/service-fabric-cluster-creation-for-windows-server">https://docs.microsoft.com/en-us/azure/service-fabric/service-fabric-cluster-creation-for-windows-server</a>
	</p>]]></content:encoded>
    </item>
    <item>
      <title>Where Did Application Insights Put my Performance Counter Data?</title>
      <link>https://docs.microsoft.com/archive/blogs/timomta/where-did-application-insights-put-my-performance-counter-data</link>
      <pubDate>Thu, 30 Nov 2017 12:21:31 GMT</pubDate>
      <dc:creator><![CDATA[Tim Omta]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/timomta/?p=505</guid>
      <description><![CDATA[I ran into an issue finding performance counter values I had pushed to Application Insights and...]]></description>
      <content:encoded><![CDATA[<p>I ran into an issue finding performance counter values I had pushed to Application Insights and wanted to note it to save others some time.
</p><p>You can configure Azure Diagnostics (WAD) to push diagnostic and performance data to Application Insights:
</p><p><a href="https://docs.microsoft.com/en-us/azure/monitoring-and-diagnostics/azure-diagnostics-configure-application-insights">https://docs.microsoft.com/en-us/azure/monitoring-and-diagnostics/azure-diagnostics-configure-application-insights</a>
	</p><p>Once you configure WAD to sink data to Application Insights, you can go into your Azure Subscription Portal, click on the instance of Application Insights that you have set up, then click on the Analytics button to get a very powerful ability to query all the incoming diagnostic data:
</p><a href="https://msdnshared.blob.core.windows.net/media/2017/11/AIAnalytics.png"><img src="https://msdnshared.blob.core.windows.net/media/2017/11/AIAnalytics-300x81.png" alt="" width="300" height="81" class="alignnone size-medium wp-image-525" /></a><p>
</p><p>As the data comes in from WAD, it is routed by Application Insights to different 'tables', which are listed in tree form as child nodes under the parent node 'APPLICATION INSIGHTS'. You can then query these tables to see the data:
</p><a href="https://msdnshared.blob.core.windows.net/media/2017/11/AITableTree.png"><img src="https://msdnshared.blob.core.windows.net/media/2017/11/AITableTree-136x300.png" alt="" width="136" height="300" class="alignnone size-medium wp-image-515" /></a><p>
	</p><p>I had designated several performance counters to be captured by WAD and sent to Application Insights. Naturally, I assumed that I would find them in the table named performanceCounters (see above picture). However, I only found some of them showing up there, one of which was % Processor Time. I didn't know what happened to others and thought I had misconfigured WAD.
</p><p>After some investigation, I found out that for legacy reasons, some performance counters are forced by Application Insights to the performanceCounters table. All other counters go to the customMetrics table.
</p><p>As best as I could determine after speaking with various people, here is a list of counters that are routed by Application Insights to the performanceCounters table:
</p><p style="margin-left: 36pt">@"\Process(??APP_WIN32_PROC??)\% Processor Time",
</p><p style="margin-left: 36pt">@"\Memory\Available Bytes",
</p><p style="margin-left: 36pt">@"\ASP.NET Applications(??APP_W3SVC_PROC??)\Requests/Sec",
</p><p style="margin-left: 36pt">@"\.NET CLR Exceptions(??APP_CLR_PROC??)\# of Exceps Thrown / sec",
</p><p style="margin-left: 36pt">@"\ASP.NET Applications(??APP_W3SVC_PROC??)\Request Execution Time",
</p><p style="margin-left: 36pt">@"\Process(??APP_WIN32_PROC??)\Private Bytes",
</p><p style="margin-left: 36pt">@"\Process(??APP_WIN32_PROC??)\IO Data Bytes/sec",
</p><p style="margin-left: 36pt">@"\ASP.NET Applications(??APP_W3SVC_PROC??)\Requests In Application Queue",
</p><p style="margin-left: 36pt">@"\Processor(_Total)\% Processor Time"
</p><p>
 </p><p>All other counters are routed to the customMetrics table. There does not appear to be any configuration option to change where Application Insights routes the data, so I wanted to let those interested know that they'll need to query both the performanceCounters and customMetrics tables to retrieve performance counter values.
</p>]]></content:encoded>
    </item>
    <item>
      <title>Controlling the Number of Outgoing Connections From HttpClient (.Net Core or Full Framework)</title>
      <link>https://docs.microsoft.com/archive/blogs/timomta/controlling-the-number-of-outgoing-connections-from-httpclient-net-core-or-full-framework</link>
      <pubDate>Mon, 23 Oct 2017 13:18:05 GMT</pubDate>
      <dc:creator><![CDATA[Tim Omta]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/timomta/?p=466</guid>
      <description><![CDATA[Although there are references to this all over the web for full framework, I had trouble finding it...]]></description>
      <content:encoded><![CDATA[Although there are references to this all over the web for full framework, I had trouble finding it for .Net Core, so I thought I'd note it for others that may be searching.

On <strong>.Net Full framework</strong>, you can control the number of outgoing client connections by setting <a href="https://docs.microsoft.com/en-us/dotnet/api/system.net.servicepointmanager.defaultconnectionlimit?view=netframework-4.7#System_Net_ServicePointManager_DefaultConnectionLimit">ServicePointManager.DefaultConnectionLimit</a> to the desired number. It is 2 by default.

On <strong>.Net Core</strong>, you can set it by changing <a href="https://docs.microsoft.com/en-us/dotnet/api/system.net.http.httpclienthandler.maxconnectionsperserver?view=netcore-2.0#System_Net_Http_HttpClientHandler_MaxConnectionsPerServer">HttpClientHandler.MaxConnectionsPerServer</a> to your desired limit. The default is int.MaxValue -- much higher than the default for the full framework.
]]></content:encoded>
    </item>
    <item>
      <title>Add Azure Antimalware Extension to a VM Scale Set</title>
      <link>https://docs.microsoft.com/archive/blogs/timomta/add-azure-antimalware-extension-to-a-vm-scale-set</link>
      <pubDate>Wed, 08 Mar 2017 12:34:16 GMT</pubDate>
      <dc:creator><![CDATA[Tim Omta]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/timomta/?p=445</guid>
      <description><![CDATA[If you're running a Windows Server 2016 base image, ignore this post because we've built Windows...]]></description>
      <content:encoded><![CDATA[If you're running a Windows Server 2016 base image, ignore this post <a href="https://technet.microsoft.com/en-us/windows-server-docs/security/windows-defender/windows-defender-overview-windows-server">because we've built Windows Defender in</a>. However, if you're running Server 2012R2, for example, and wish to apply the Microsoft Antimalware Extension to an existing VM Scale Set, here is a PowerShell script to do it:
<code>
# Add the Microsoft Antimalware Extension to an Azure VMSS
# Assumes you have already authenticated your PowerShell session
# with Login-AzureRMAccount and selected the correct subscription
# with Select-AzureRMSubscription

$rgname = 'myResourceGroupName'
$vmssname = 'myVMSSName'
$location = 'westcentralus' # change to the Azure Region of your VMSS
 
# retrieve the most recent major version number of the extension
$allVersions= (Get-AzureRmVMExtensionImage -Location $location -PublisherName "Microsoft.Azure.Security" -Type "IaaSAntimalware").Version
$latestVersion=$allVersions[-1]
$majorVersion=$latestVersion.Substring(0,$latestVersion.IndexOf('.', 2))

$VMSS = Get-AzureRmVmss -ResourceGroupName $rgname -VMScaleSetName $vmssname
Add-AzureRmVmssExtension -VirtualMachineScaleSet $VMSS -Name "IaaSAntimalware" -Publisher "Microsoft.Azure.Security" -Type "IaaSAntimalware" -TypeHandlerVersion $majorVersion
Update-AzureRmVmss -ResourceGroupName $rgname -Name $vmssname -VirtualMachineScaleSet $VMSS 
</code>

A customer asked me how to do this. I didn't know, so I asked around, put it together, tested it, and thought I'd share.

Special thanks to <a href="https://azure.microsoft.com/en-us/blog/author/guybo/">Guy Bowerman</a> for help with the script and a quick review.

<b>References</b>
<a href="https://docs.microsoft.com/en-us/azure/virtual-machine-scale-sets/virtual-machine-scale-sets-overview">Azure VM Scale Sets</a>
<a href="https://technet.microsoft.com/en-us/windows-server-docs/security/windows-defender/windows-defender-overview-windows-server">Windows Defender Built into Server 2016</a>]]></content:encoded>
    </item>
    <item>
      <title>How to Trap Uncaught Exceptions and Avoid 5xx Errors in ASP.Net WebAPI</title>
      <link>https://docs.microsoft.com/archive/blogs/timomta/how-to-trap-uncaught-exceptions-and-avoid-5xx-errors-in-asp-net-webapi</link>
      <pubDate>Sat, 04 Mar 2017 10:42:59 GMT</pubDate>
      <dc:creator><![CDATA[Tim Omta]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/timomta/?p=435</guid>
      <description><![CDATA[I was recently writing a WebAPI 2.x project for a customer that involved file IO, decompression, and...]]></description>
      <content:encoded><![CDATA[I was recently writing a WebAPI 2.x project for a customer that involved file IO, decompression, and database IO. Though the things the API does are not complex, there are many things that can go wrong in any of those types of operations that can cause exceptions to be thrown (SQL parsing errors, IO errors, connection errors, etc). I took steps to catch and deal with the exceptions that I could anticipate, but there is always the potential for some to go unhandled, which results in a 500 class error from the WebAPI. 5xx errors are very generic “Internal Server” errors and difficult to debug in addition to being just plain ugly going back to the customer.

WebAPI 1.x has <a href="https://docs.microsoft.com/en-us/aspnet/web-api/overview/error-handling/exception-handling#exception-filters">Exception Filters</a>, which cover many cases. You’ll also notice, as you go through the documentation, that it tells you how to write and <a href="https://docs.microsoft.com/en-us/aspnet/web-api/overview/error-handling/exception-handling#registering-exception-filters">register</a> them.

WebAPI 2.x has even more, <a href="https://docs.microsoft.com/en-us/aspnet/web-api/overview/error-handling/web-api-global-error-handling">global</a> options that allow you to cover more cases, like exceptions thrown from controller constructors or during a response stream. The new options are 2 base classes, <a href="https://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Http/ExceptionHandling/ExceptionLogger.cs">ExceptionLogger</a> and <a href="https://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Http/ExceptionHandling/ExceptionHandler.cs">ExceptionHandler</a>, that you can inherit from and override methods on to gain control of how uncaught exceptions are handled. The goal of the first class is to allow you to insert a call to your logging framework to log the exception. The goal of the second class is to allow you to send the client an error message of your choosing rather than “500 Internal Server Error”. This looked great and was what
I wanted to do, but though the doc explained the goals of global error handling, it didn’t explain how to properly write or register these options.

Of course, like most projects, it had to be done yesterday and professionally because, well, that’s my job. In order to leverage these new exception handling options, I had to spend a good deal of time asking questions, doing web queries, downloading, and spelunking through sample code.

I would like to save you that time by showing you how to implement register ExceptionLogger and ExceptionHandler.

<b>ExceptionLogger</b>
To implement ExceptionLogger, simply write your own class that inherits from it, as the docs show. At the time of this blog post, the docs do not show the proper override to write though. At a minimum, override the Log(ExceptionContext context) method. If you look at the <a href="https://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Http/ExceptionHandling/ExceptionLogger.cs">source code for ExceptionLogger</a>, you’ll see that the base implementation of LogAsync will wrap a call to your overridden Log method in a Task, so no need to override it unless you really need to do something special in the async case.

To register ExceptionLogger, add this call to the Register(HttpConfiguration config) method of your WebApiConfig class:
<code>config.Services.Add(typeof(IExceptionLogger), new TraceExceptionLogger());</code>

<b>ExceptionHandler</b>
To implement ExceptionHandler, you again write your own class that inherits from it, as the docs show, but instead you must override
the Handle(ExceptionHandlerContext context) method at a minimum.
To register ExceptionHandler, add this call to the Register(HttpConfiguration config) method of your WebApiConfig class:
<code>config.Services.Replace(typeof(IExceptionHandler), new UncaughtExceptionHandler());</code>

<a href="https://aspnet.codeplex.com/SourceControl/latest#Samples/WebApi/Elmah/ReadMe.txt">Here is a sample</a> that I finally found that shows registration and implementation. It uses an additional package called ELMAH, but you don’t need that to implement what I’ve told you about here. The sample shows 2 very basic controllers that throw exceptions and how these are handled with an implementation of ExceptionLogger (ElmahExceptionLogger) and ExceptionHandler (GenericTextExceptionHandler). Registration of these classes is shown in WebApiConfig for the project.

<b>References</b>
<a href="https://docs.microsoft.com/en-us/aspnet/web-api/overview/error-handling/exception-handling">https://docs.microsoft.com/en-us/aspnet/web-api/overview/error-handling/exception-handling</a>
<a href="https://docs.microsoft.com/en-us/aspnet/web-api/overview/error-handling/web-api-global-error-handling">https://docs.microsoft.com/en-us/aspnet/web-api/overview/error-handling/web-api-global-error-handling</a>
<a href="https://docs.microsoft.com/en-us/aspnet/web-api/overview/releases/whats-new-in-aspnet-web-api-21#global-error">https://docs.microsoft.com/en-us/aspnet/web-api/overview/releases/whats-new-in-aspnet-web-api-21#global-error</a>
<a href="https://aspnet.codeplex.com/SourceControl/latest#Samples/WebApi/Elmah/ReadMe.txt">https://aspnet.codeplex.com/SourceControl/latest#Samples/WebApi/Elmah/ReadMe.txt</a>]]></content:encoded>
    </item>
    <item>
      <title>How to Remove the Server Header from WebListener</title>
      <link>https://docs.microsoft.com/archive/blogs/timomta/how-to-remove-the-server-header-from-weblistener</link>
      <pubDate>Sat, 03 Dec 2016 16:04:45 GMT</pubDate>
      <dc:creator><![CDATA[Tim Omta]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/timomta/?p=395</guid>
      <description><![CDATA[Sometimes enterprises or those hosting web sites wish to remove the Server HTTP response header so...]]></description>
      <content:encoded><![CDATA[Sometimes enterprises or those hosting web sites wish to remove the Server HTTP response header so they can make it more difficult for an attacker to determine what type of web server they are using (IIS, Apache, etc). Though it is doubtful as to how much protection this actually provides, it is still a common practice.

ASP.Net Core includes a new web server called <a href="https://docs.microsoft.com/en-us/aspnet/core/fundamentals/servers/weblistener">WebListener</a> to offer you a light weight alternative to IIS.

I was asked how to remove the Server header from WebListener by a customer. After some asking around and experimenting, the following solution turned out to be the best one at present:

<code>public void Configure(IApplicationBuilder app)
{
&nbsp;&nbsp;&nbsp;&nbsp;// Add code to the beginning of Configure to blank out
&nbsp;&nbsp;&nbsp;&nbsp;// the header, which removes it
&nbsp;&nbsp;&nbsp;&nbsp;app.Use((context, next) =&gt;
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;context.Response.Headers.Add("Server", string.Empty);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return next();
&nbsp;&nbsp;&nbsp;&nbsp;});

&nbsp;&nbsp;&nbsp;&nbsp;// continue with other pipeline configuration code...
}</code>

Here is the response from a WebListener server before the above addition:
<img alt="Before" src="https://msdnshared.blob.core.windows.net/media/2016/12/2016-12-03_15-10-07before-e1480805293316.png" />

Here is the response after the code was added:
<img alt="After" src="https://msdnshared.blob.core.windows.net/media/2016/12/2016-12-03_15-10-07after-e1480805328354.png" />

In the latter figure, you can see that the server responded without the Server header in the HTTP response.]]></content:encoded>
    </item>
    <item>
      <title>How Do I Set Up A .Net Core WebListener With SSL?</title>
      <link>https://docs.microsoft.com/archive/blogs/timomta/how-do-i-set-up-a-net-core-weblistener-with-ssl</link>
      <pubDate>Fri, 04 Nov 2016 17:09:09 GMT</pubDate>
      <dc:creator><![CDATA[Tim Omta]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/timomta/?p=375</guid>
      <description><![CDATA[I've been doing a lot of research on Service Fabric and Windows Docker Containers lately. These are...]]></description>
      <content:encoded><![CDATA[I've been doing a lot of research on <a href="https://azure.microsoft.com/en-us/documentation/services/service-fabric/">Service Fabric</a> and <a href="https://msdn.microsoft.com/en-us/virtualization/windowscontainers/about/about_overview">Windows Docker Containers</a> lately. These are natural platforms for .Net Core, which added another learning item to my list: <a href="https://docs.asp.net/en/latest/">.Net Core</a>. 
As a result, I set out to get a .Net Core <a href="https://docs.asp.net/en/latest/fundamentals/servers.html">WebListener</a> web server up and running on <a href="https://msdn.microsoft.com/en-us/library/dd184075.aspx">Windows Server Core 2016</a>. I chose Server Core because it emulates the kind of environment you'll be faced with when running on Docker or Service Fabric, which is essentially a bare bones, no UI environment.

I'm not attempting to teach you Hyper-V, Docker, or how to get around in Server Core as they are big subjects by themselves. If you are afraid of the command line, you should not be here until you do some prerequisite learning.

<h3>Objective: Set up a .Net Core WebListener Server with SSL on Windows Server Core 2016
</h3>

<h4>Create Your Server Core Host</h4>
Start by installing Server Core 2016 in a VM. You could use a Docker container too if you're so inclined. 

<h4>Create Your SSL Certificate</h4>
Log onto the new Server Core machine. At the administrative command prompt, type
<code>start powershell
</code>

Issue a PowerShell command to to create a self-signed cert (use your server's DNS name)
<code>New-SelfSignedCertificate -CertStoreLocation Cert:\LocalMachine\My -DnsName server0.contoso.com</code>
You'll need the cert thumbprint a little later. Mine was: C74235968895ECA9C9D50703D30CE17A7D3AEEFF

<h4>Register Your App With HTTP.SYS</h4>
Issue a PowerShell command to create a GUID
<code>New-guid</code>
You'll need this Guid to use as an AppId later. Mine was: 921328e8-5cdf-4b7f-a3cc-4e50147d1521

Switch back to your original administrative command prompt and issue these commands to create the Url ACLs (80 and 443)
<code>netsh http add urlacl url=https://+:443/ user=Users
netsh http add urlacl url=https://+:80/ user=Users</code>

While still in the same command prompt, issue a command to associate the cert thumb print and App Id (created above) with port 443
<code>netsh http add sslcert ipport=0.0.0.0:443 certhash=C74235968895ECA9C9D50703D30CE17A7D3AEEFF appid={921328e8-5cdf-4b7f-a3cc-4e50147d1521}</code>
Note: If you run the above from PowerShell rather than cmd, you may need to escape some characters to get it to work

<h4>Open the Firewall Web Ports</h4>
Switch to your PowerShell prompt
Issue a PowerShell command to open 80 and 443 in the Windows Firewall. This will allow HTTP(S) traffic to WebListener.
<code>New-NetFirewallRule -DisplayName 'HTTP(S) Inbound' -Profile @('Domain', 'Private') -Direction Inbound -Action Allow -Protocol TCP -LocalPort @('80', '443')</code>
I opened both ports because I wanted to test both clear HTTP and HTTPS. I also chose to restrict the ports from being open on the Public firewall profile by specifying Domain and Private.

<h4>Install .Net Core</h4>
Issue a PowerShell command to download .Net Core to the machine
<code>Invoke-WebRequest "https://go.microsoft.com/fwlink/?LinkID=827524" -OutFile .\DotNetCoreSetup.exe -UseBasicParsing</code>

In the same PowerShell prompt, install .Net Core using the following
<code>.\DotNetCoreSetup.exe /install /quiet /log .\log.txt</code>

.Net Core will silently (and very quickly) install. I chose silent because this is not a full GUI machine. When the install finishes, you should see several text log files in the directory you issued the above command from. Even though you're on Server Core, Notepad still works and you can use it to inspect the logs and satisfy yourself that you had a successful install.
Once satisfied, I really recommend you restart the machine with this PowerShell command
<code>Restart-Computer</code>
You don't need to restart, but it is a pain if you don't let the machine pick up the environment changes.

<h4>Create a Web Application to Serve</h4>
Now we need an app. The easiest thing to do is to adapt the template web app.
Step 1 - From your Server Core console, enter the following to create the template web app:
<code>
mkdir aspnetcoreapp
cd aspnetcoreapp
dotnet new web
</code>

Step 2 - Modify aspnetcoreapp.csproj file to include the WebListener package reference right under the Microsoft.AspNetCore package reference. Notepad is available on Server Core by typing 'notepad' at your command prompt. Your csproj should look like this:
<code>
&lt;Project Sdk="Microsoft.NET.Sdk.Web"&gt;
  &lt;PropertyGroup&gt;
    &lt;TargetFramework&gt;netcoreapp1.0&lt;/TargetFramework&gt;
  &lt;/PropertyGroup&gt;
  &lt;ItemGroup&gt;
    &lt;Folder Include="wwwroot\" /&gt;
  &lt;/ItemGroup&gt;
  &lt;ItemGroup&gt;
    &lt;PackageReference Include="Microsoft.AspNetCore" Version="1.0.3" /&gt;
    <mark>&lt;PackageReference Include="Microsoft.AspNetCore.Server.WebListener" Version="*" /&gt;</mark>
  &lt;/ItemGroup&gt;
&lt;/Project&gt;</code>

Step 3 - Modify Program.cs by replacing the WebHostBuilder initialization statement with this:
<code>
            var host = new WebHostBuilder()
                .UseWebListener()
		.UseUrls("https://+:80", "https://+:443")
                .UseStartup&lt;Startup&gt;()
                .Build();
</code>
NOTE: Make sure the above URL strings <mark>"https://+:80"</mark> and <mark>"https://+:443"</mark> match the URL strings used in the ACLs you created with netsh earlier in 'Register Your App with HTTP.SYS'.
If you don't, you may receive a 503 Service Unavailable from the web server.

Step 4 - From your Server Core console, enter the following to restore the packages and run the server:
<code>
dotnet restore
dotnet run
</code>

Step 5 - Browse to your Server Core machine name from another machine on the network, using either HTTP or HTTPS. In my case, the URLs to browse to were the same as the DnsName for my cert and machine:
<code>
https://server0.contoso.com/
https://server0.contoso.com/
</code>

You should have a working SSL enabled WebListener server running on Windows Server Core 2016.
Now go and brag about your .Net Core, bare metal, headless, command line skills.
 
<strong>References</strong>
<a href="https://docs.asp.net/en/latest/">ASP.Net Core Docs</a>
<a href="https://technet.microsoft.com/windows-server-docs/get-started/Windows-Server-2016">Windows Server 2016</a>
<a href="https://github.com/aspnet/WebListener">WebListener repository</a>
<a href="https://docs.asp.net/en/latest/fundamentals/servers.html">WebListener ASP.Net Core Docs</a>
<a href="https://msdn.microsoft.com/en-us/library/windows/desktop/aa364698(v=vs.85).aspx">URL routing/registration/pattern matching behavior</a>
<a href="https://azure.microsoft.com/en-us/documentation/services/service-fabric/">Service Fabric Documentation</a>
<a href="https://msdn.microsoft.com/en-us/virtualization/windowscontainers/about/about_overview">Containers for Windows</a>

]]></content:encoded>
    </item>
    <item>
      <title>How Do I Open Ports with PowerShell?</title>
      <link>https://docs.microsoft.com/archive/blogs/timomta/how-do-i-open-ports-with-powershell</link>
      <pubDate>Fri, 04 Nov 2016 13:32:08 GMT</pubDate>
      <dc:creator><![CDATA[Tim Omta]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/timomta/?p=365</guid>
      <description><![CDATA[If you have a history with Windows, you're probably used to using netsh to open ports on the Windows...]]></description>
      <content:encoded><![CDATA[If you have a history with Windows, you're probably used to using netsh to open ports on the Windows Firewall. We have a whole slew of PowerShell cmdlets to administer the Windows Firewall now and I wondered how to use PowerShell to open ports. It took me longer than it should have to do it, so I thought I'd share. In the end it is simple, but there are a lot of cmdlets to wade through, which is where I got hung up.

Here is what you'd do with netsh to open ports 80 and 443:
<code>
netsh advfirewall firewall add rule name="Open Port 80" dir=in action=allow protocol=TCP localport=80
netsh advfirewall firewall add rule name="Open Port 443" dir=in action=allow protocol=TCP localport=443
</code>
Here is how you'd open the same ports for only the Domain and Private profiles (not Public) with PowerShell:
<code>
New-NetFirewallRule -DisplayName 'HTTP(S) Inbound' -Profile @('Domain', 'Private') -Direction Inbound -Action Allow -Protocol TCP -LocalPort @('80', '443')
</code>

<strong>References</strong>
<a href="https://technet.microsoft.com/en-us/library/jj554906(v=wps.630).aspx">PowerShell cmdlets to manage the Windows firewall</a>
<a href="https://support.microsoft.com/en-us/kb/947709">Netsh Examples</a>]]></content:encoded>
    </item>
    <item>
      <title>How to Use PowerShell DSC to Prepare a Data Drive on an Azure VM</title>
      <link>https://docs.microsoft.com/archive/blogs/timomta/how-to-use-powershell-dsc-to-prepare-a-data-drive-on-an-azure-vm</link>
      <pubDate>Sat, 23 Apr 2016 22:39:05 GMT</pubDate>
      <dc:creator><![CDATA[Tim Omta]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/timomta/?p=285</guid>
      <description><![CDATA[Introduction
I was asked how to automate formatting a data drive on an Azure VM. The drive had been...]]></description>
      <content:encoded><![CDATA[<h1>Introduction
</h1><p>I was asked how to automate formatting a data drive on an Azure VM. The drive had been provisioned already when the infrastructure was created via ARM script, however the disk was raw. I developed this solution with <a href="https://blogs.msdn.microsoft.com/powershell/2014/08/07/introducing-the-azure-powershell-dsc-desired-state-configuration-extension/">Azure PowerShell Desired State Configuration (DSC)</a>, Azure PowerShell 1.0 (newest release as of April 2016), and my Windows 10 client machine, meaning I have PowerShell 5 and can leverage the <a href="https://www.powershellgallery.com/">PowerShell Gallery</a>. DSC was originally developed for Windows Server and has been extended into Azure.
</p><h1>Setup From Administrative PowerShell
</h1><p>The first step is to install the xStorage module from the PowerShell Gallery. PowerShell needs the NuGet provider to download module packages from the gallery. I issued the below commands from an administrative PowerShell session. Once you have completed this on your development client machine, you don't need to do it again.
</p><p>
 </p><p><span style="font-family:Courier New;font-size:10pt">PS C:\WINDOWS\system32&gt; <strong>Install-Module xStorage</strong>
		</span></p><p>
 </p><p><span style="font-family:Courier New;font-size:10pt">NuGet provider is required to continue
</span></p><p><span style="font-family:Courier New;font-size:10pt">PowerShellGet requires NuGet provider version '2.8.5.201' or newer to interact with NuGet-based repositories. The NuGet provider must be available in 'C:\Program Files\PackageManagement\ProviderAssemblies' or
</span></p><p><span style="font-family:Courier New;font-size:10pt">'C:\Users\tomta\AppData\Local\PackageManagement\ProviderAssemblies'. You can also install the NuGet provider by running 'Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force'. Do you want PowerShellGet to install andimport the NuGet provider now?
</span></p><p><span style="font-family:Courier New;font-size:10pt">[Y] Yes  [N] No  [S] Suspend  [?] Help (default is "Y"): y
</span></p><p>
 </p><p><span style="font-family:Courier New;font-size:10pt">Untrusted repository
</span></p><p><span style="font-family:Courier New;font-size:10pt">You are installing the modules from an untrusted repository. If you trust this repository, change its InstallationPolicy value by running the Set-PSRepository cmdlet. Are you sure you want to install the modules from
</span></p><p><span style="font-family:Courier New;font-size:10pt">'PSGallery'?
</span></p><p><span style="font-family:Courier New;font-size:10pt">[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "N"): y
</span></p><p>
 </p><h1>Module Code
</h1><p>This part does not need to be done from an Administrative PowerShell. I just started ISE from a PowerShell prompt and used it to write my Desired State Configuration (DSC) script.
</p><p><span style="font-family:Courier New;font-size:10pt">PS C:\temp&gt; <strong>ise</strong>
		</span></p><p>
 </p><p>In ISE, I wrote and saved the below to c:\temp\prepardisk.ps1
</p><p>
 </p><p><span style="font-family:Courier New;font-size:10pt">Configuration DataDisk
</span></p><p><span style="font-family:Courier New;font-size:10pt">{
</span></p><p style="margin-left: 36pt"><span style="font-family:Courier New;font-size:10pt">Import-DSCResource -ModuleName xStorage
</span></p><p>
 </p><p style="margin-left: 36pt"><span style="font-family:Courier New;font-size:10pt">Node localhost
</span></p><p style="margin-left: 36pt"><span style="font-family:Courier New;font-size:10pt">{
</span></p><p style="margin-left: 72pt"><span style="font-family:Courier New;font-size:10pt">xWaitforDisk Disk2
</span></p><p style="margin-left: 72pt"><span style="font-family:Courier New;font-size:10pt">{
</span></p><p style="margin-left: 108pt"><span style="font-family:Courier New;font-size:10pt">DiskNumber = 2
</span></p><p style="margin-left: 108pt"><span style="font-family:Courier New;font-size:10pt">RetryIntervalSec = 60
</span></p><p style="margin-left: 108pt"><span style="font-family:Courier New;font-size:10pt">Count = 60
</span></p><p style="margin-left: 72pt"><span style="font-family:Courier New;font-size:10pt">}
</span></p><p style="margin-left: 72pt"><span style="font-family:Courier New;font-size:10pt">xDisk FVolume
</span></p><p style="margin-left: 72pt"><span style="font-family:Courier New;font-size:10pt">{
</span></p><p style="margin-left: 108pt"><span style="font-family:Courier New;font-size:10pt">DiskNumber = 2
</span></p><p style="margin-left: 108pt"><span style="font-family:Courier New;font-size:10pt">DriveLetter = 'F'
</span></p><p style="margin-left: 108pt"><span style="font-family:Courier New;font-size:10pt">FSLabel = 'Data'
</span></p><p style="margin-left: 72pt"><span style="font-family:Courier New;font-size:10pt">}
</span></p><p style="margin-left: 36pt"><span style="font-family:Courier New;font-size:10pt">}
</span></p><p><span style="font-family:Courier New;font-size:10pt">}
</span></p><p>
 </p><p>
 </p><p><span style="font-family:Courier New;font-size:10pt">DataDisk -outputpath C:\DataDisk
</span></p><p><span style="font-family:Courier New;font-size:10pt">Start-DscConfiguration -Path C:\DataDisk -Wait -Force -Verbose
</span></p><p>
 </p><p>The above will wait for disk volume 2 to show up connected to the Azure VM, which it should already be. It will then initialize, partition, format, and bring the volume up as F:. 
</p><h1>Deployment
</h1><p>Next, we deploy the DSC configuration we want the VM to enact up to Azure, then tell he VM to update. You need an Azure storage account. The account is used to store the configuration so the VM can get it.
</p><p>I performed these actions on a classic VM. If you're using ARM, the following steps are different and I need to write another post for it <span style="font-family:Wingdings">J</span>. I'm also assuming that you have authenticated your PowerShell session by executing Add-AzureAccount, and using Select-Subscription to activate the correct subscription for your VM and storage account.
</p><p>PS C:\temp&gt; $key=<strong>Get-AzureStoragekey</strong> -StorageAccountName timsstorageaccount
</p><p>PS C:\temp&gt; $context=<strong>New-AzureStorageContext</strong> -StorageAccountName $key.StorageAccountName -StorageAccountKey $key.Primary
</p><p>PS C:\temp&gt; <strong>Publish-AzureVMDscConfiguration</strong> -ConfigurationPath C:\temp\preparedisk.ps1 -StorageContext $context
</p><p>PS C:\temp&gt; $vm = <strong>get-azurevm</strong> -ServiceName TimsCloudService -name dev1vm1
</p><p>PS C:\temp&gt; <strong>Set-AzureVMDscExtension</strong> -vm $vm -ConfigurationArchive "preparedisk.ps1.zip" -ConfigurationName "DataDisk"  -StorageContext $context | Update-AzureVM
</p><p>
 </p><p><span style="font-family:Courier New;font-size:10pt">OperationDescription OperationId                          OperationStatus
</span></p><p><span style="font-family:Courier New;font-size:10pt">-------------------- -----------                          ---------------
</span></p><p><span style="font-family:Courier New;font-size:10pt">Update-AzureVM       3f88ae8d-5cf0-a7c8-8e0f-f4c30324e96d Succeeded
</span></p><p>
 </p><h1>Visually Check the Deployment
</h1><p>After a few minutes, I RDP'd into the Azure VM to be satisfied that all worked well. I opened Windows File Explorer and the disk showed up partitioned, formatted, and with the correct drive letter.
</p><p><img src="https://msdnshared.blob.core.windows.net/media/2016/04/042416_0552_HowtoUsePow11.png" alt="" />
	</p><h1>Further Reading
</h1><p><a href="https://msdn.microsoft.com/en-us/powershell/dsc/overview">Windows PowerShell Desired State Configuration Overview</a>
	</p><p><a href="https://blogs.msdn.microsoft.com/powershell/2014/08/07/introducing-the-azure-powershell-dsc-desired-state-configuration-extension/">Introducing Azure PowerShell DSC</a>
	</p><p><a href="https://blogs.msdn.microsoft.com/powershell/2014/04/03/configuring-an-azure-vm-using-powershell-dsc/">Configuring an Azure VM Using PowerShell DSC</a>
	</p><p><a href="https://www.powershellgallery.com/GettingStarted">Getting Started with the PowerShell Gallery</a>
	</p>]]></content:encoded>
    </item>
  </channel>
</rss>