<?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>Nick Eales’ blog</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/neales/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/neales/feed.xml</link>
    <description>Hoping to save someone some time (including myself)</description>
    <lastBuildDate>Wed, 14 Feb 2018 03:44:18 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>Install highly available SCVMM 2016 using SQL Always On</title>
      <link>https://docs.microsoft.com/archive/blogs/neales/install-highly-available-scvmm-2016-using-sql-always-on</link>
      <pubDate>Wed, 14 Feb 2018 13:14:24 GMT</pubDate>
      <dc:creator><![CDATA[NickEales-MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/neales/?p=265</guid>
      <description><![CDATA[One of my customers recently had a frustrating time installing a VMM 2016 in a highly available...]]></description>
      <content:encoded><![CDATA[One of my customers recently had a frustrating time installing a VMM 2016 in a highly available configuration when using SQL Always on for the database. A standalone install into a highly available virtual machine does not meet their requirements. Due to the frustrations with getting this to work, I am sharing the steps we used.
&nbsp;
<p style="margin: 0in;font-family: Calibri;font-size: 11.0pt">Assumptions:</p>

<ul>
 	<li>Operating systems are already installed on at least four machines (SqlNode1, SqlNode2, VmmNode1, VmmNode2)</li>
 	<li>Failover Clustering is configured so that SqlNode1 and SqlNode2 are in one cluster and VmmNode1 and VmmNode2 are in a different cluster.</li>
 	<li>SQL Enterprise is installed and configured with always on capability enabled and a listener configured (SqlFMList). In our case, the listener was configured to listen on port 1771. SQL must be using port 1433 for a non-always on instance / database for this to work</li>
</ul>
&nbsp;

<p style="margin: 0in;font-family: Calibri;font-size: 11.0pt">The installation steps we used</p>
<ol>
 	<li>Create the VMMService account (eg svc_vmmservice), and grant it permissions to
<ul>
 	<li>SQL on SqlNode1</li>
 	<li>Local administrator group on  VmmNode1 and VmmNode2</li>
</ul>
</li>
 	<li>Install VMM on VmmNode1. When you get to the SQL configuration section, give the computer name SqlNode1, port 1433, and allow it to create the database (VirtualManagerDB). Note down the location of the DKM.</li>
 	<li>Uninstall VMM, choosing the option to retain the database.</li>
 	<li>Ensure the svc_vmmservice account has a db_owner permissions of the VMM database.</li>
 	<li>Ensure the SQL Listener / AG is active on the node that has the Database, but do not add the database to the Always On group yet.</li>
 	<li>Use the below ini file to install VMM on one VMM node at a time -  (we couldn't get this to work using the graphical installer due to the SQL port required and issues with the user interface). This will install VMM so that when launching the console, connect to the address "vmm:8100"</li>
</ol>
<pre style="margin: 0in;margin-left: .375in;font-family: Calibri;font-size: 11.0pt">[OPTIONS]
ProductKey=XXXXXXXXXXXX
UserName=Name
CompanyName=Name
ProgramFiles=C:\Program Files\Microsoft System Center 2016\Virtual Machine Manager
CreateNewSqlDatabase=0
SqlDatabaseName=VirtualManagerDB
SqlServerPort=1771
RemoteDatabaseImpersonation=0
SqlMachineName=SqlFMList
IndigoTcpPort=8100
IndigoHTTPSPort=8101
IndigoNETTCPPort=8102
IndigoHTTPPort=8103
WSManTcpPort=5985
BitsTcpPort=443
#CreateNewLibraryShare=1
#LibraryShareName=MSSCVMMLibrary
#LibrarySharePath=D:\VMMLIB\
#LibraryShareDescription=Virtual Machine Manager Library Files
SQMOptIn = 0
MUOptIn = 0
VmmServiceLocalAccount = 0
TopContainerName="CN=DKM,DC=LAB,DC=INTRANET" #replace this with the DKM location
HighlyAvailable = 1
VmmServerName=VMM
VMMStaticIPAddress=10.51.83.236
Upgrade=0</pre>
&nbsp;
<p style="margin: 0in;font-family: Calibri;font-size: 11.0pt">The command line used to use this INI file is:</p>

<pre style="margin: 0in;font-family: Calibri;font-size: 11.0pt;color: #262626">setup.exe /server /i /f &lt;IniFilePath&gt; /VmmServiceDomain &lt;Domain&gt; /VmmServiceUserName &lt;Service Account&gt; /VmmServiceUserPassword &lt;Service account PW&gt; /IACCEPTSCEULA</pre>
&nbsp;
<ol start="7">
 	<li>After installation of VMM on both nodes, check the VMM console can connect to the server</li>
 	<li>Using cluster manager take the VMM service offline</li>
 	<li>Add the SQL database to the AG with the listener used in the above file (SqlFMList).</li>
 	<li>Restart VMM. Check that VMM works with different combinations of which node VMM &amp; SQL are on.</li>
</ol>
&nbsp;
The "Upgrade" setting in the ini file - is set to zero because in the initial installation to create the database, my customer also applied UR4. By default the installation appears to try to "upgrade" the database version if the versions don't match the expected version (2016 RTM) - since we were using a newer version, we had to tell it not to upgrade it.]]></content:encoded>
    </item>
    <item>
      <title>Create VMM template for Ubuntu 16.04</title>
      <link>https://docs.microsoft.com/archive/blogs/neales/create-vmm-template-for-ubuntu-16-04</link>
      <pubDate>Tue, 23 Jan 2018 14:11:02 GMT</pubDate>
      <dc:creator><![CDATA[NickEales-MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/neales/?p=245</guid>
      <description><![CDATA[There seems to be a lot of guidance - but none of it was clear enough for me.. these are my quick...]]></description>
      <content:encoded><![CDATA[There seems to be a lot of guidance - but none of it was clear enough for me.. these are my quick notes - sorry for any typo's / mistakes
<ul>
 	<li>Download Ubuntu 16.04 ISO</li>
 	<li>Create &amp; boot a Gen 2 VM using this ISO &amp; a blank disk</li>
 	<li>Follow wizard (force UEFI disks if using  Gen2 VM, and I didn't encrypt the disks, and be sure to install the "OpenSSH Server") - I suggest a generic username &amp; password - as the one used here appears to still be there after VMM template is deployed.</li>
 	<li>After deployment, wait for VM to boot &amp; get it's IP address by logging into the VM &amp; running 'ifconfig'.</li>
</ul>
<ul>
 	<li>From VMM server:</li>
</ul>
<pre>Cd "C:\Program Files\Microsoft System Center 2016\Virtual Machine Manager\agents\Linux"
c:\program files\putty\PSCP.exe *.* username@VmIp:</pre>
<ul>
 	<li>the ':' after the IP is important - specifies the location to copy the files to. without anything after the ':' it will copy it to the users' home folder</li>
 	<li>Then from VM:</li>
</ul>
<pre># Update with latest security &amp; other updates
sudo apt-get update &amp;&amp; sudo apt upgrade
# enable automatic upgrades
sudo apt install unattended-upgrades
cat &gt; 20auto-upgrades &lt;&lt; EOF
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Download-Upgradeable-Packages "1";
APT::Periodic::AutocleanInterval "7";
APT::Periodic::Unattended-Upgrade "1";
EOF
sudo mv ./20auto-upgrades /etc/apt/apt.conf.d/
# install VMM agent
chmod +x install
sudo ./install ./scvmmguestagent.1.0.2.1075.x64.tar
# UEFI fix (needed for Gen 2 VMs)
sudo grub-install --target=x86_64-efi --efi-directory=/boot/efi --no-nvram --removable
# install &amp; enabled Hyper-V Integration components
sudo apt-get update &amp;&amp; sudo apt-get install linux-tools-$(uname -r) linux-cloud-tools-$(uname -r) -y
hv_fcopy_daemon
hv_kvp_daemon
hv_set_ifconfig
hv_vss_daemon
hv_get_dns_info
# shutdown VM for VHD image. (this is also needed for IC's to start working)
sudo shutdown -h now</pre>
<div class="sitewrap">
<div class="hfeed site wrap" id="page">
<div id="main">
<div class="innerwrap">
<div class="site-content" id="primary">
<div id="content" role="main"><article class=" posttitle-show introfeature post-1725 post type-post status-publish format-standard hentry category-blog category-carlos-vargas category-hyper-v category-linux tag-devops tag-hyper-v tag-ubuntu" id="post-1725"></article></div>
</div>
</div>
</div>
</div>
</div>
<ul>
 	<li>Next copy VHD to VMM library</li>
 	<li>Set VHD OS type to Ubuntu 16.04 (64 bit)</li>
 	<li>Create VM template
<ul>
 	<li>Make sure secure boot is disabled &amp; VM Generation matches that used above.</li>
</ul>
</li>
</ul>
&nbsp;

The above steps didn't work for me when using Ubuntu 17.04]]></content:encoded>
    </item>
    <item>
      <title>Getting a private certificate from Key Vault</title>
      <link>https://docs.microsoft.com/archive/blogs/neales/getting-a-private-certificate-from-key-vault</link>
      <pubDate>Mon, 26 Jun 2017 22:22:26 GMT</pubDate>
      <dc:creator><![CDATA[NickEales-MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/neales/?p=236</guid>
      <description><![CDATA[Getting a certificate from key vault using PowerShell – while it isn’t obvious also isn’t hard. I’m...]]></description>
      <content:encoded><![CDATA[Getting a certificate from key vault using PowerShell – while it isn’t obvious also isn’t hard. I’m putting this sample code here for me to use as a reference – but feel free to use &amp; adjust it as you want.

A few key points first about certificates in Key Vault.
<ul>
 	<li>BYO certificates when loaded into key vault are added using the *AzureKeyVaultCertificate* powershell cmdlets.</li>
 	<li>Key Vault can generate self-signed certificates using the New-AzureKeyVaultCertificatePolicy cmdlet with ‘-IssuerName Self’ and the Add-AzureKeyVaultCertificate cmdlet</li>
 	<li>Private Certificates can then be accessed using the Get-AzureKeyVaultSecret cmdlet</li>
 	<li>Public Certificates  can then be accessed using the Get-AzureKeyVaultKey cmdlet.</li>
 	<li>Access to run each cmdlet is governed through a range of access policies. E.g. ‘Get’ rights on ‘secret’ objects lets you get a secret (e.g. by running Get-AzureKeyVaultSecret with ’-name’), and ‘List’ rights on ‘key’ objects lets you list the keys (e.g. by running Get-AzureKeyVaultKey without ’-name’).</li>
 	<li>the below script assumes that you have authenticated to Key Vault and have permissions for the get operation.</li>
</ul>
anyway.. some code to get private certificates and make them available for a few difference purposes (the main point of this post):

&nbsp;
<pre><span style="font-family: Consolas;font-size: small">#get Secret object (Containing private key) from Key Vault</span>
<span style="font-family: Consolas;font-size: small">$AzureKeyVaultSecret=Get-AzureKeyVaultSecret -VaultName $VaultName -Name $CertificateName -ErrorAction SilentlyContinue</span>

<span style="font-family: Consolas;font-size: small">#Convert private cert to bytes
$PrivateCertKVBytes = [System.Convert]::FromBase64String($AzureKeyVaultSecret.SecretValueText)</span>

#Convert Bytes to Certificate (flagged as exportable &amp; retaining private key)
#possible flags: <a href="https://msdn.microsoft.com/en-us/library/system.security.cryptography.x509certificates.x509keystorageflags(v=vs.110).aspx"><span style="font-family: Consolas;font-size: small">https://msdn.microsoft.com/en-us/library/system.security.cryptography.x509certificates.x509keystorageflags(v=vs.110).aspx
</span></a><span style="font-family: Consolas;font-size: small">$certObject = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 -argumentlist $PrivateCertKVBytes,$null, "Exportable, PersistKeySet"
</span>

<span style="font-family: Consolas;font-size: small">#Optional: import certificate to current user Certificate store
$Certificatestore = New-Object System.Security.Cryptography.X509Certificates.X509Store -argumentlist "My","Currentuser"
$Certificatestore.open("readWrite")
$Certificatestore.Add($certObject)
$Certificatestore.Close()</span>

<span style="font-family: Consolas;font-size: small">#if private certificate needs to be exported, then it needs a password - create Temporary Random Password for certificate
$PasswordLength=20
$ascii = 33..126 | %{[char][byte]$_}
$CertificatePfxPassword = $(0..$passwordLength | %{$ascii | get-random}) -join ""</span>

<span style="font-family: Consolas;font-size: small">#Encrypt private Certificate using password (required if exporting to file or memory for use in ARM template)
$protectedCertificateBytes = $certObject.Export([System.Security.Cryptography.X509Certificates.X509ContentType]::Pkcs12,
$CertificatePfxPassword)
Write-output "Private Certificate Password: '$CertificatePfxPassword'"</span>

<span style="font-family: Consolas;font-size: small">#Optional: Export encrypted certificate to Base 64 String in memory (for use in ARM templates / other):
$InternetPfxCertdata = [System.Convert]::ToBase64String($protectedCertificateBytes)</span>

<span style="font-family: Consolas;font-size: small">#Optional: Export encrypted certificate to file on desktop:
$pfxPath = '{0}\{1}.pfx' -f [Environment]::GetFolderPath("Desktop") ,$CertificateName
[System.IO.File]::WriteAllBytes($pfxPath, $protectedCertificateBytes)</span></pre>
&nbsp;

While the above example is for getting a private certificate, getting a public certificate is similar &amp; simpler. (use Get-AzureKeyVaultKey instead / a slight change to the flags if importing it locally / no need to encrypt if exporting to a .CER file).

As always – please let me know if you have any questions or comments – that’s how I learn.]]></content:encoded>
    </item>
    <item>
      <title>OAuth using PowerShell and certificate Service Principal to Azure Function App</title>
      <link>https://docs.microsoft.com/archive/blogs/neales/oauth-using-powershell-and-certificate-service-principal-to-azure-function-app</link>
      <pubDate>Mon, 19 Jun 2017 22:48:36 GMT</pubDate>
      <dc:creator><![CDATA[NickEales-MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/neales/?p=225</guid>
      <description><![CDATA[Hi,

Recently I needed a way to write PowerShell code to use a certificate backed service...]]></description>
      <content:encoded><![CDATA[Hi,

Recently I needed a way to write PowerShell code to use a certificate backed service principal to use OAuth authentication when calling a web hook. This took longer than it should to figure out (my colleague Arian helped a lot), so I figured I may be able to save someone else some time by sharing this online.

For the application you are sending the authenticated web hook to, modify the Authorization settings under “Platform features”:

&nbsp;

<a href="https://msdnshared.blob.core.windows.net/media/2017/06/image443.png"><img title="image" alt="image" src="https://msdnshared.blob.core.windows.net/media/2017/06/image_thumb420.png" class="" width="727" border="0" height="380" /></a>

&nbsp;

Enable App Service Authentication, choose AD Auth, and configure the AD Auth setting

<a href="https://msdnshared.blob.core.windows.net/media/2017/06/clip_image00110.png"><img title="clip_image001" alt="clip_image001" src="https://msdnshared.blob.core.windows.net/media/2017/06/clip_image001_thumb9.png" class="" width="706" border="0" height="489" /></a>

&nbsp;

Set the following values (sources provided later):

&nbsp;

<a href="https://msdnshared.blob.core.windows.net/media/2017/06/clip_image00161.png"><img title="clip_image001[6]" alt="clip_image001[6]" src="https://msdnshared.blob.core.windows.net/media/2017/06/clip_image0016_thumb.png" class="" width="699" border="0" height="629" /></a>

Value 3 is the tenant ID:

<a href="https://msdnshared.blob.core.windows.net/media/2017/06/clip_image0022.png"><img title="clip_image002" alt="clip_image002" src="https://msdnshared.blob.core.windows.net/media/2017/06/clip_image002_thumb2.png" class="" width="662" border="0" height="96" /></a>

Values 2 &amp; 4 come from the App Registrations in Azure AD for the Service Principal (these can also be queried via PowerShell if needed (Get-AzureADServicePrincipal)

<a href="https://msdnshared.blob.core.windows.net/media/2017/06/clip_image0031.png"><img title="clip_image003" alt="clip_image003" src="https://msdnshared.blob.core.windows.net/media/2017/06/clip_image003_thumb1.png" class="" width="768" border="0" height="434" /></a>

&nbsp;

This is some sample code used to call the webhook &amp; pass some parameters to it, and show the output:
<pre>function Get-AuthHeaderUsingCert {
    param(
        $TenantID,
        $CertificateThumbprint,
        $ApplicationIdURL,
        $ApplicationId
    )
    $AuthUri = "https://login.windows.net/$TenantID/oauth2/authorize"
    $clientCertificate = Get-Item -Path Cert:\CurrentUser\My\$CertificateThumbprint
    $authenticationContext = New-Object -TypeName Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext -ArgumentList $AuthUri
    $certificateCredential = New-Object -TypeName Microsoft.IdentityModel.Clients.ActiveDirectory.ClientAssertionCertificate -ArgumentList ($ApplicationId, $clientCertificate)
    $authToken = $authenticationContext.AcquireTokenAsync($ApplicationIdURL, $certificateCredential)
    $authHeader = @{
        'Content-Type'='application/json'
        'Authorization'=$authToken.result.CreateAuthorizationHeader()
    }
    $authHeader
}

add-type -path C:\Temp\Microsoft.IdentityModel.Clients.ActiveDirectory.dll
#I'm using Version 2.28.31117.1411 of this DLL - Apparently newer ones don't work for this.

$AuthHeader = Get-AuthHeaderUsingCert -TenantID $tenantID -CertificateThumbprint $CertificateThumbprint -ApplicationId $ApplicationId -ApplicationIdURL $ApplicationIdURL 
if([string]::IsNullOrWhiteSpace($authheader)){throw "no auth"}
$JSONArguments = $(@{'ArgName'='ArgValue'} | convertto-json -Depth 5)
$Result = Invoke-Webrequest -Uri $WebhookURL -Headers $AuthHeader -Body $JSONArguments -Method Post
$result

</pre>]]></content:encoded>
    </item>
    <item>
      <title>Use a Custom Script Extension to Sysprep an Azure VM</title>
      <link>https://docs.microsoft.com/archive/blogs/neales/use-a-custom-script-extension-to-sysprep-an-azure-vm</link>
      <pubDate>Mon, 13 Mar 2017 10:33:33 GMT</pubDate>
      <dc:creator><![CDATA[NickEales-MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/neales/?p=115</guid>
      <description><![CDATA[Hi All,

I’ve been in a situation where I want to run sysprep on a Azure VM to create an...]]></description>
      <content:encoded><![CDATA[<div class="post">
<div class="body">
<div class="postBody" id="e55ae3a2-7a29-43fd-a073-2e472750f254" style="margin: 4px 0px 0px;border-width: 0px;padding: 0px">

Hi All,

I’ve been in a situation where I want to run sysprep on a Azure VM to create an image, hopefully without needing to login / connect directly to the VM. I thought that this was an opportunity to learn about custom script extensions. (for use in other situations as well)

&nbsp;

in summary, I created a powershell script file, and saved it to a new file 'sysprep.ps1':
<pre>param([switch]$runSysprep=$false)
write-output "Sysprep Script Run, parameter 'runSysprep': $runSysprep"

if($runSysprep){
  write-output "starting Sysprep"
  Start-Process -FilePath C:\Windows\System32\Sysprep\Sysprep.exe -ArgumentList '/generalize /oobe /shutdown /quiet'
  write-output "started Sysprep"
}else{
  write-output "skipping Sysprep"
}
</pre>
&nbsp;

I then uploaded this to a storage account, set the security on the container to ‘blob’ (there's nothing sensitive in that script), then ran the following:
<pre>$VMName =  'vmName'
$VMRG = 'vmResourceGroup'
$VMLocation = 'AustraliaEast'
$ExtensionName = 'runsysprep'
$Scripturi = 'https://&lt;storageAccountName&gt;.blob.core.windows.net/templates/scripts/sysprep.ps1'
Set-AzureRmVMCustomScriptExtension -FileUri $ScriptURI -ResourceGroupName  $VMRG -VMName $VMName -Name $ExtensionName -Location $VMLocation -run './sysprep.ps1' -Argument '-runSysprep'</pre>
&nbsp;

This gave the output:
<pre>RequestId IsSuccessStatusCode StatusCode ReasonPhrase
--------- ------------------- ---------- ------------
                         True         OK OK</pre>
To see the output messages from the script that was run:
<pre>$status = Get-AzureRmVMDiagnosticsExtension -ResourceGroupName $VMRG -VMName $VMName -Name $ExtensionName -Status
$status.SubStatuses.message</pre>
This displayed the output that was expected:
<pre>Sysprep Script Run, parameter 'runSysprep': True\nstarting Sysprep\nstarted Sysprep</pre>
&nbsp;

A short time later, the VM is shutdown (but is still allocated &amp; incurring charges), so i then shutdown the VM:

</div>
</div>
</div>
<pre>Stop-AzureRmVM -Name $VMName -ResourceGroupName $VMRG  -force</pre>
<div class="post">
<div class="body">
<div class="postBody" id="e55ae3a2-7a29-43fd-a073-2e472750f254" style="margin: 4px 0px 0px;border-width: 0px;padding: 0px">

&nbsp;

As with everything I post about, please give comments / questions on my approach /methods

Nick

</div>
</div>
</div>]]></content:encoded>
    </item>
    <item>
      <title>Azure Automation Webhook parameter passing</title>
      <link>https://docs.microsoft.com/archive/blogs/neales/azure-automation-webhook-parameter-passing</link>
      <pubDate>Tue, 14 Feb 2017 02:00:00 GMT</pubDate>
      <dc:creator><![CDATA[NickEales-MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/neales/?p=85</guid>
      <description><![CDATA[Hi All,

Recently I was exploring the use of webhooks &amp; needed to troubleshoot the parameters...]]></description>
      <content:encoded><![CDATA[Hi All,

Recently I was exploring the use of webhooks &amp; needed to troubleshoot the parameters being passed to a webhook.

With the theme of my blog - hoping to save someone some time, this is a quick post to save someone creating this from scratch.

This is the Azure Automation PowerShell runbook that I used to display what was being passed to the webhook:
<pre>param (
        [object]$WebhookData
    )
 
    # If runbook was called from Webhook, WebhookData will not be null.
    if ($WebhookData -ne $null) {
         $webhookbody = convertfrom-json $webhookdata.RequestBody
         $webhookbody.context.timestamp | write-output
         $webhookbody.context.event.OperationName | write-output
         $webhookbody.context.resourceId | write-output
         $webhookbody.context | write-output
         $webhookbody | write-output
    }

</pre>
As usual for any of my blog posts – if you have any feedback about any of the above, please provide it – that’s how I learn.]]></content:encoded>
    </item>
    <item>
      <title>Hyper-V Performance - Networking</title>
      <link>https://docs.microsoft.com/archive/blogs/neales/hyper-v-performance-networking</link>
      <pubDate>Tue, 24 Jan 2017 14:15:49 GMT</pubDate>
      <dc:creator><![CDATA[NickEales-MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/neales/?p=55</guid>
      <description><![CDATA[This is a continuation of a series on Hyper-V performance monitoring. The previous posts covered...]]></description>
      <content:encoded><![CDATA[This is a continuation of a series on Hyper-V performance monitoring. The previous posts covered CPU, Storage and Memory performance, This post is on network performance.

Network monitoring in a Hyper-V environment depends very heavily on the configuration in use, the available hardware (speed of NIC) and the configuration in use.

&nbsp;
<h1>Physical network adapter throughput</h1>
Counter: <strong>Network Interface\Bytes Total/sec</strong>

Why: This show how busy each physical NIC is.

Threshold: 90% of Network hardware speed (both NIC and connected switch)

What to do if threshold is met or exceeded:
<ul>
 	<li>Ensure that you are applying weights to the network traffic to prioritize traffic types in this order (there are several methods to apply these weights - depending on the network config, and this all changes for Win2016):
<ol>
 	<li>Host Management,</li>
 	<li>CSV storage (Win2012 R2 and earlier)</li>
 	<li>VM storage</li>
 	<li>Live Migration (if using dynamic optimization or some other automatic load balancing method - otherwise put this last)</li>
 	<li>VM traffic</li>
</ol>
</li>
 	<li>If the prioritization has already occurred, and any suboptimal performance is occurring, then either:
<ul>
 	<li>increase capacity (more / faster NICs &amp; switches)</li>
 	<li>Reduce load by shifting workloads to other hosts</li>
</ul>
</li>
</ul>
&nbsp;
<h1>Virtual Machine Network throughput</h1>
Counter: <strong>Hyper-V Virtual Network Adapter\Bytes/sec</strong>

Why: This shows the network throughput for each VM Network adapter. This can be used for capacity planning and for load tracking purposes.

Threshold: This depends on the type of environment (most environments won't use a threshold, but will keep it for capacity planning)

&nbsp;

I'm sure there are more counters that are relevant - if you have suggestions, please let me know (if they are storage related, please check that post first).

&nbsp;

As usual for any of my blog posts – if you have any feedback about any of the above, please provide it – that’s how I learn]]></content:encoded>
    </item>
    <item>
      <title>Hyper-V Performance – Memory</title>
      <link>https://docs.microsoft.com/archive/blogs/neales/hyper-v-performance-memory</link>
      <pubDate>Tue, 22 Nov 2016 21:17:44 GMT</pubDate>
      <dc:creator><![CDATA[NickEales-MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/neales/?p=46</guid>
      <description><![CDATA[&nbsp; This is a continuation of a series on Hyper-V performance monitoring. The previous posts...]]></description>
      <content:encoded><![CDATA[<p>&nbsp;</p> <p>This is a continuation of a series on Hyper-V performance monitoring. The previous posts covered CPU and storage performance, This post is on Memory performance, and the remaining post will cover network performance.</p> <p>Memory performance in Hyper-V environments is a mix of availability, ensuring Virtual Machines have the memory they need, and NUMA memory usage. </p> <p>&nbsp;</p> <h1>Host Available Memory</h1> <ul> <li>Counter: <strong>Hyper-V Dynamic Memory Balancer\Available Memory</strong></li> <li>Why: This is the memory available for virtual machine usage on a Hyper-V host, while ensuring that there is sufficient memory available for Hardware and Hyper-V management.</li> <li>Threshold: &lt; 2GB</li> <li>What to do if threshold is breached:</li> <ul> <li>Check for many VMs with memory pressure &lt; 60%, if so, reduce min memory</li> <li>Check for static memory assignment VMs that have been assigned more than needed (DM candidates?)</li> <li>Check Dynamic Memory is responding on virtual machines enabled for Dynamic Memory (a value for the “Average Pressure” value provides that).</li> <li>Reduce memory usage on hosts (load balance VMs between hosts?)</li></ul></ul> <p>&nbsp;</p> <h1>Virtual Machine Memory Pressure</h1> <ul> <li>Counter: <strong>Hyper-V Dynamic Memory VM(*)\Average Pressure</strong></li> <li>Threshold: Any Instance &gt; 85% sustained &gt; 1 min. (Note this thresholds assumes the default buffer setting of 20% - adjust this threshold on a per virtual machine basis if the buffer value is modified)</li> <li>Why: This displays the ratio of committed memory within the VM to the memory allocated to the virtual machine. This indicates whether the virtual machine has enough memory for its current needs, and values close to and over 100 indicate performance impacting page file use within the virtual machine. This value will be 0 if dynamic memory is disabled on Hyper-V 2012 R2 and earlier. <br>For virtual machines using dynamic memory, Hyper-V should maintain this at "100 / (100 + (100 * Memory Buffer))" (for default buffer for 20%, target pressure is 83.3%)</li> <li>What to do if threshold is breached:</li> <ul> <li>Check each virtual machine's max memory settings (vs how much has been allocated to the virtual machine)</li> <li>Check overall host available memory </li></ul></ul> <p>&nbsp;</p> <h1>Virtual Machine Allocated Memory</h1> <ul> <li>Counter: <strong>Hyper-V Dynamic Memory VM(*)\Physical Memory</strong></li> <li>Threshold: </li> <ul> <li>no threshold (informational counter, used for capacity planning), or </li> <li>(optional) if dynamic memory is enabled, then &gt; 90% of maximum memory. This is optional due the difficulty in implementing this with VMs of different maximum values.</li></ul> <li>Why: This displays the current amount of allocated memory for each virtual machine (this value will reduce if dynamic memory reduces the memory allocated to virtual machines). The amount of memory shown within the virtual machine (either task manager or performance monitor counters) does not reduce when the memory is reduced (through dynamic memory), and so should not be used. </li> <li>What to do if threshold is breached (if one is used):</li> <ul> <li>identify if the dynamic memory maximum value for the virtual machine needs to be increased</li> <li>check the memory usage by the virtual machine is expected.</li></ul></ul> <p>&nbsp;</p> <h1>Remote NUMA Memory Node Access</h1> <ul> <li>Counter: <strong>Hyper-V Vm Vid Partition(*)\Remote Physical Pages.</strong></li> <li>Threshold: &gt; 100 (and increasing by at least 100/hour). Note that this value will reset if the VM is restarted or migrated to a different host.</li> <li>Why: A Non-Uniform Memory Access (NUMA) node is a physical grouping of processors and memory (on a motherboard) for performance. Accessing memory on a remote NUMA node (on the same motherboard) is slower than accessing memory in the closest NUMA node for any type of CPU processing.&nbsp; A remote physical page access occurs when a virtual machine CPU core running on one physical processor accesses virtual machine memory on a remote NUMA node. Hyper-V does everything it can do to avoid this occurring by choosing which processors and sections of physical memory to allocate to virtual machines, however some configurations or levels of load can cause this to occur.</li> <li>What to do if threshold is breached:</li> <ul> <li>Use NUMA aware applications in virtual machines with large amounts of memory. </li> <li>Reduce the memory load on the host machine (if live migrating VMs away, prefer any VMs with this issue). </li> <li>If one virtual machine is primarily impacted (and performance is less than expected / desired), perform an action that results in that machines physical memory being reallocated to somewhere where there is sufficient memory available for the virtual machine's memory and NUMA configuration. These actions may be live migrate that VM to a different host or power off &amp; power on that VM.</li> <li>Avoid using dynamic memory for large memory virtual machines (&gt; 16 GB). Virtual machines with dynamic memory enabled present a single NUMA node to virtual machines (Hyper-V servers running 2012 R2 or earlier). This may or may not impact the performance of the virtual machine.</li></ul></ul> <p>&nbsp;&nbsp;&nbsp; <br>As usual for any of my blog posts - if you have any feedback about any of the above, please provide it - that's how I learn.</p>]]></content:encoded>
    </item>
    <item>
      <title>Hyper-V Performance - Storage</title>
      <link>https://docs.microsoft.com/archive/blogs/neales/hyper-v-performance-storage</link>
      <pubDate>Mon, 07 Nov 2016 13:00:12 GMT</pubDate>
      <dc:creator><![CDATA[NickEales-MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/neales/?p=45</guid>
      <description><![CDATA[This is a continuation of a series on Hyper-V performance monitoring. The previous post covered CPU...]]></description>
      <content:encoded><![CDATA[This is a continuation of a series on Hyper-V performance monitoring. The previous post covered CPU performance, This post is on storage performance, and the remaining posts will cover memory and network.

Storage performance is often the most impactful on the performance and responsiveness of Hyper-V virtual machines.
<h3>Disk Latency of the virtual machine storage from the host.</h3>
<ul>
 	<li>Why: Latency to the Virtual Machine data from Hyper-V is the most common cause of non-optimal virtual machine performance. It significantly helps to know what the normal range is in an specific environment before troubleshooting. This is the first (and for performance – the most important) storage counter to look at.</li>
 	<li>Counters:
<ul>
 	<li>For CSV Disks containing virtual machine data:
<ul>
 	<li>Cluster CSV File System(*)\Read Latency</li>
 	<li>Cluster CSV File System(*)\Write Latency</li>
</ul>
</li>
 	<li>For both CSV or SMB Storage:
<ul>
 	<li>SMB Client Shares(*)\Avg. sec/Data Request (only shares containing virtual machine data)</li>
</ul>
</li>
 	<li>When local storage used for VMs (typically non-highly available virtual machines)
<ul>
 	<li>Logical Disk(*)\Avg. Disk sec/Transfer (only instances containing virtual machine data)</li>
</ul>
</li>
</ul>
</li>
</ul>
<ul>
 	<li>Threshold (for all of the disk latency thresholds): 0.015 (15ms) is a general threshold, but this will vary - Client virtualization may have higher thresholds (25ms), and server virtualization may have lower thresholds (often 8ms or lower).</li>
</ul>
<ul>
 	<li>What to do if threshold is exceeded:
<ul>
 	<li>For non-local storage:
<ul>
 	<li>Check connection to storage - everything from storage adapters (NIC or FC) to the physical disks, inclusive.</li>
 	<li>Check storage unit load &amp; latency issues</li>
 	<li>Check storage adapter driver &amp; settings (including any load balancing or multipath configuration)</li>
 	<li>Check storage unit and storage path load (both MB/Sec and IOPS) vs baseline numbers.</li>
</ul>
</li>
 	<li>For local storage
<ul>
 	<li>Check local machine CPU (look for any single cores running 100%), and disk idle time</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3>Disk Idle Time</h3>
<ul>
 	<li>Why: This counter provides a clear measurement of what percentage of time the disk remained in idle state, meaning all the requests from the operating system to the disk have been completed and there is zero pending requests. Disk performance (and virtual machine responsiveness) will usually degrade significantly soon after this threshold is reached.</li>
 	<li>Counter: Logical Disk(*)\% Idle Time (any instance)</li>
 	<li>Threshold: &lt; 50% , sustained &gt; 5 min</li>
 	<li>What to do if threshold is exceeded:
<ul>
 	<li>Check storage unit load &amp; latency issues</li>
 	<li>Check storage adapter driver &amp; settings (including any load balancing or multipath configuration</li>
 	<li>Check storage load (MB/Sec and IOPS) vs baseline numbers.</li>
 	<li>Identify busy virtual machine virtual disks (see "Hyper-V Virtual Storage Device\Normalized Throughput" in this post), and consider redistributing the busy virtual machine virtual disks.</li>
</ul>
</li>
</ul>
<h3>Disk Space</h3>
<ul>
 	<li>Why: It is very important to track disks running low on space. When the available space drive containing virtual machine storage falls too low, any operation that involves using more disk space will cause the virtual machine to have an outage and will show a status of "Paused-Critical" (visible in Hyper-V manager). The threshold chosen here should give ample warning before this outage occurs.</li>
 	<li>Counter: LogicalDisk(*)\Free Megabytes (any instance other than "_Total" or "C:")</li>
 	<li>Threshold: &lt; 200GB (or whatever threshold is appropriate)
<ul>
 	<li>the value should depend on disk capacity, expected growth, file system type, backup technology and size of regular fluctuations. Suggested values range from 5% (&gt;10TB disks) to 15 % (&lt;1TB disks).</li>
 	<li>If the underlying storage is thinly provisioned, this threshold should generally be 15%.</li>
 	<li>This counter won't show data for remotely accessed SMB storage.</li>
</ul>
</li>
 	<li>What to do if threshold is exceeded:
<ul>
 	<li>Check for snapshots, differencing disks, Hyper-V Replica's (especially initial sync on targets), dynamic disks</li>
</ul>
</li>
</ul>
<h3>Storage MB/sec</h3>
<ul>
 	<li>Why: The host counters can be useful information when troubleshooting disk latency and idle time issues. For any shared storage where performance issues are being seen by any device accessing the storage, it is important to identify which host (or combination of hosts) is generating the load. Once the host has been identified, use the virtual machine counters to identify which virtual machine is generating the traffic. If it is an application or service on the host OS, stop it then contact the vendor for a fix or uninstall it - our purpose here is running virtual machines securely, fast and reliably - anything that interferes needs to be carefully evaluated.</li>
</ul>
<ul>
 	<li>Threshold: no threshold - use this for getting a baseline and for capacity planning.</li>
 	<li>Counters (Host):
<ul>
 	<li>For CSV Disks containing VM data:
<ul>
 	<li>Cluster CSV File System(*)\IO Read Bytes/sec</li>
 	<li>Cluster CSV File System(*)\IO Write Bytes/sec</li>
</ul>
</li>
 	<li>For both CSV or SMB Storage:
<ul>
 	<li>SMB Client Shares(*)\Data Bytes/sec (Read Bytes/sec or Write Bytes/sec)</li>
</ul>
</li>
 	<li>When local storage used for virtual machines (typically non-highly available virtual machines)
<ul>
 	<li>LogicalDisk(*)\Disk Bytes/sec</li>
</ul>
</li>
</ul>
</li>
 	<li>Counters (VM):
<ul>
 	<li>Which virtual machines are generating most storage traffic
<ul>
 	<li>Hyper-V Virtual Storage Device(*)\Read Bytes/sec</li>
 	<li>Hyper-V Virtual Storage Device(*)\Write Bytes/sec</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3>IOPS(or equivalent):</h3>
<ul>
 	<li>Why: This can be useful information when troubleshooting disk latency and idle time issues. For any shared storage where performance issues are being seen by any device accessing the storage, it is important to identify which host (or combination of hosts) is generating the load. Storage teams also like to use these numbers for comparison purposes.</li>
</ul>
<ul>
 	<li>Threshold: no threshold - use this for getting a baseline and for capacity planning.</li>
 	<li>Counter (Host):
<ul>
 	<li>For CSV Disks containing VM data:
<ul>
 	<li>Cluster CSV File System(*)\IO Reads/sec</li>
 	<li>Cluster CSV File System(*)\IO Writes/sec</li>
</ul>
</li>
 	<li>For both CSV or SMB Storage:
<ul>
 	<li>SMB Client Shares(*)\Data Requests/sec (Read Requests/sec / Write Requests/sec)</li>
</ul>
</li>
 	<li>When local storage used for virtual machines (typically non-highly available virtual machines)
<ul>
 	<li>LogicalDisk(*)\Disk Transfers/sec</li>
</ul>
</li>
</ul>
</li>
 	<li>Counters (VM):
<ul>
 	<li>Which virtual machines are generating most storage traffic
<ul>
 	<li>Hyper-V Virtual Storage Device(*)\Read Operations/sec</li>
 	<li>Hyper-V Virtual Storage Device(*)\Write Operations/sec</li>
</ul>
</li>
</ul>
</li>
</ul>
&nbsp;

As usual for any of my blog posts – if you have any feedback about any of the above, please provide it – that’s how I learn.]]></content:encoded>
    </item>
    <item>
      <title>Hyper-V Performance - CPU</title>
      <link>https://docs.microsoft.com/archive/blogs/neales/hyper-v-performance-cpu</link>
      <pubDate>Mon, 24 Oct 2016 20:58:58 GMT</pubDate>
      <dc:creator><![CDATA[NickEales-MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/neales/?p=35</guid>
      <description><![CDATA[Hi - I'm Nick Eales from the Microsoft Premier Field Engineering team, based in Sydney...]]></description>
      <content:encoded><![CDATA[Hi - I'm Nick Eales from the Microsoft Premier Field Engineering team, based in Sydney Australia.

I frequently get asked by both Microsoft people as well as customers how to monitor Hyper-V. This generally really means that people want specific performance counters and thresholds - and these are not easily found in any form of consolidated list - which is what I hope to provide (across a few blog entries). I also aim to provide what each counter means (in real world terms), and what to do / look at to figure out why it exceeds the thresholds.

A word of caution - I have provided values that are what I initially use when reviewing a customer environment. The thresholds often need to be varied based on hardware and requirements. These starting values are based on experience at large numbers of customer environments worldwide (by my colleagues &amp; I), while reviewing and troubleshooting Hyper-V.

My focus when choosing these counters and values is what will change the "feel" and "responsiveness" of the virtual machines running on these servers. If these are met, then throughput will usually look after itself.

There are four typical areas that you monitor in any server environment - CPU, Disk, Memory and Network. Hyper-V is no different - although the counters used to measure these a Hyper-V environment are often totally different to a standard server.

This post is going to focus on the CPU Performance counters - since they generate the most confusion. Later posts will address the other areas.
<h3>Physical CPU utilization</h3>
<ul>
 	<li>Counter: Hyper-V Hypervisor Logical Processor(*)\%Total Run Time.</li>
 	<li>Threshold: (any instance) &gt; 50% sustained for &gt; 5 min)</li>
 	<li>What to do if threshold is exceeded:
<ul>
 	<li>
<div style="margin-right: 0px">If _Total meets this, identify sources of CPU load (sounds obvious but.. )</div></li>
 	<li>
<div style="margin-right: 0px">If single / small % of CPUs consistently affected, especially (but not necessarily) CPU 0 look for VMQ / RSS config issues, or other hardware issue.</div></li>
 	<li>
<div style="margin-right: 0px">If a small number of CPUs are impacted, but the busy CPU does vary, then check the two "% Guest Run Time" processor counters below.</div></li>
</ul>
</li>
</ul>
<h3>Management operating system CPU usage.</h3>
<ul>
 	<li>Counter: Hyper-V Hypervisor Root Virtual Processor(_Total)\% Guest Run Time.</li>
 	<li>Threshold (_Total instance) &gt; 5% sustained for &gt; 5 min</li>
 	<li>What: This measures the amount of physical CPU time spent running Hyper-V host OS virtual CPUs.</li>
 	<li>Why: The host OS doesn't compete for CPU time in Hyper-V. It always immediately gets any CPU time it needs, which is necessary to provide great performance for virtual machines. This means any unnecessary CPU usage in the host OS can have a significant negative performance impact on all virtual machines - which is why the guidance is to install as little as possible on the host OS (absolute minimum of agents, services &amp; applications).</li>
 	<li>What to do if threshold is exceeded:
<ul>
 	<li>Check for any non-default OS running services / agents / processes in this OS, and review if they are really necessary.</li>
 	<li>Check VMQ/RSS configuration (if 10GB NICs are in use) and for bad drivers - especially if this the CPU usage is focused on a small percentage of the hosts OS's VPs.</li>
 	<li>Standard CPU performance troubleshooting - as if it was a physical machine.</li>
 	<li>For general administration, use remote management tools instead of locally or via RDP on the host.</li>
</ul>
</li>
</ul>
&nbsp;
<h3>Virtual Machine Processor Usage</h3>
<ul>
 	<li>Counter: Hyper-V Hypervisor Virtual Processor(*)\% Guest Run Time.</li>
 	<li>Threshold (any instance) &gt; 75%, sustained for &gt; 10min</li>
 	<li>What: This measures the amount of physical CPU time each VM virtual CPU instance uses. Each virtual processor can only run on one physical CPU thread at a time.</li>
 	<li>Why: Unlike the Processor performance object and task manager inside a virtual machine, this accurately shows how much physical CPU time is being consumed by each VP.</li>
 	<li>What to do if threshold is exceeded:
<ul>
 	<li>Check VMs have sufficient VP (consider adding one of more processors to the VM)</li>
 	<li>Perform standard high CPU usage troubleshooting inside the VM as you would if it was a physical machine to reduce the CPU usage within the VM.</li>
</ul>
</li>
</ul>
&nbsp;
<h3>Physical CPU Context Switching</h3>
<ul>
 	<li>What: This measures the rate (number of times per second) each logical CPU changes what virtual processor it is running.</li>
 	<li>Counter: Hyper-V Hypervisor Logical Processor(*)\Context Switches/sec.</li>
 	<li>Threshold: (any instance except for "_Total") &gt; 20000, (sustained for &gt; 5min).</li>
 	<li>Why: We use this as a general health &amp; performance indicator for the host &amp; virtual machines. This counter must be used in context with all other activity based counters (CPU, Disk &amp; Network, latency &amp; throughput).</li>
 	<li>What to do if threshold is exceeded:
<ul>
 	<li>Check VM config (particularly remove / disable any active &amp; busy emulated devices)</li>
 	<li>Check that the VM is using the correct version of the integration components.</li>
 	<li>Check host operating system utilization Root VP CPU usage (host OS utilization) - see the "Hyper-V Hypervisor Root Virtual Processor" counter section for the specifics.</li>
 	<li>Check drivers - particularly network and storage drivers, but other too.</li>
 	<li>Check for significant inconsistency across your hosts - it can indicate significant configuration or load differences.</li>
</ul>
</li>
</ul>
&nbsp;

In a Hyper-V environment, please try to avoid using "Processor\% Processor Time" - for Hyper-V this does not measure physical CPU usage. This counter measures the amount of time the CPU is not idle within a specific operating system's view - and the timer that it uses for this calculation is dependent on exclusive use of the CPU - which is not the case in a Hyper-V environment. For similar reasons, please do not use "Processor\Processor Queue Length".

As usual for any of my blog posts - if you have any feedback about any of the above, please provide it - that's how I learn.]]></content:encoded>
    </item>
  </channel>
</rss>