2020 The Year of Sustainability

2020 The Year of Sustainability

This article is contributed. See the original author and article here.

It is fair to say that 2020 has been disruptive, and nowhere is that more evident than in the acceleration of the climate crisis. 2020 was another year for the record books: the Artic is now 12 degrees F warmer on average than it was in 1990, an area the size of Connecticut was lost to historic wildfires in California alone, and global biodiversity is in freefall as the next mass extinction quickens. The list goes on and on but for all the bad news, there was some good too: 2020 saw Microsoft step forward with several bold new commitments, promising to leverage its vast resources to create solutions and drive sustainable change across the entire economy and we felt this acutely in the Worldwide Sustainability Community (WWSC) as new members and new questions flooded in.Wildfires raging in CaliforniaWildfires raging in California


 


 


As I look back at 2020, I see it as the year sustainability was finally elevated to its rightful place as an essential part of Microsoft’s corporate strategy and slowly but surely, its very culture.


 


On January 9, 2020, I walked up to the microphone at the company’s first all-team meeting of the year and asked our CEO Satya Nadella, “How will you make sustainability a core cultural value at Microsoft? How will you make sustainability the next accessibility?” He essentially replied, “Stay tuned – we’re gonna have a lot more to say about this soon.”


 


Satya was foreshadowing January 15th, a mere 6 days later, when Microsoft unveiled its game-changing carbon negative announcement. I was sitting in the front row in Building 99 that day, wondering what was about to happen. I watched as Satya, Amy, Brad, and Lucas took the stage to tell the world, “Those of us who can afford to move faster and go further should do so,” and that Microsoft would lead the way by leveraging its resources to make sustainable change happen faster, in line with the best available science. 


 


Watching President and Chief Legal Officer Brad Smith give a master class in carbon scope calculations was a sure sign things were different. As Vox, put it, “Climate change has moved out of the public relations department, into the C-suite, and down to the shop floor.” It was a turning point not only for Microsoft but for the overall debate on what role the private sector could play in addressing the climate crisis, where so many governments had failed to act.


 


At Microsoft, this moment represented something even more important: the awakening of our company’s ecological consciousness. This was a moment many of us in the WWSC had been working towards for years. 


 


WWSC Earth DayWWSC Earth DayThe carbon announcement was just the beginning and was quickly followed by three more sustainability commitments throughout the year: ecosystems in April (just in time for the 50th anniversary of Earth Day, the birth of the modern environmental movement!), waste in August, and water in October. The sum of these announcements was that Microsoft would become a carbon negative, zero waste, water positive company that protected more land than it used for all of its operations by 2030. Sustainability would now be an indispensable part of Microsoft’s future; the company was proudly taking a leadership role and would create scalable tech solutions others could use too.


 


The sleeping giant had finally woken. The number of customer requests asking how Microsoft could help them be more sustainable went from a slow trickle to a raging torrent in the blink of an eye. 


 


In many ways, this represents a new beginning: the hardest work lies ahead, and the window of time to do it is rapidly closing. At the current rate, our global civilization will spend its remaining carbon budget in 7 short years, by 2027, representing how many more greenhouse gases we can emit into the atmosphere before we pass a tipping point likely to be a civilization ender. To put this in perspective: while Microsoft promises to be carbon negative by 2030 (pulling more carbon out of the atmosphere than it emits annually), the target date is three years after we’ve exhausted the planetary budget. 


 


Global carbon emissions are still rising despite commitments made by most countries at the Paris Agreement in 2015Global carbon emissions are still rising despite commitments made by most countries at the Paris Agreement in 2015


 



Microsoft’s total carbon emissions (16 million metric tons in 2019) represent .04% of the global annual total (40 billion metric tons). Even with the best of intentions, Microsoft is too small in the scheme of things to move the needle on our own. This is why such a big part of Microsoft’s strategy here is to empower customers, partners, and even competitors (we’re all Earthlings, after all) with new solutions themselves to create a wave of sustainable change across the entire economy.


 


Despite the grim reality that most things are moving in the wrong direction and we are running out of time, there are encouraging signs of progress. I can see interest sparking in other companies, companies that are looking to us for answers and for help. I see this progress happening every day from the conversations happening in our Worldwide Sustainability Community, watching as employees educate each other and point each other to answers to questions that weren’t even being asked six months ago. ​​​​​​​


 


2020 was, without a doubt, the year of sustainability at Microsoft. It’s fair to say that 2021 will be an important year for translating our corporate commitments into actionable change, something all employees have an important role to play in and precisely why we founded the WWSC. 


 


We are now 10% of the way into our 2030 journey – the next 90% will need to be about education, innovation, and most importantly, action in rapid succession. It will need to happen at hyper-scale: any solutions we develop need to be highly scalable to address truly planetary sized challenges within the timeframe. I believe the fastest way to make this happen is culture change at Microsoft, the first wave of which has begun, initiated both from the bottom-up grassroots and now, the top-down leadership. Where we meet in the middle is where we get the most inertia. 


 


In 2021, we will need to take action to translate Microsoft’s commitments into real change – and we need your help. The Worldwide Sustainability Community was founded on the belief that everyone has something meaningful to contribute and you don’t need sustainability in your job title to drive change in this space. This reinforces that it is incumbent on all of us to apply our growth mindset and be constant learners when it comes to sustainability. We must grow our knowledge in this area so that we can take full advantage of the opportunity that lies before us. Only then will we understand how to leverage the vast resources of a trillion-dollar technology company to help solve the world’s most pressing environmental challenges.

Microsoft 365 PnP Weekly – Episode 110

Microsoft 365 PnP Weekly – Episode 110

This article is contributed. See the original author and article here.

pnp-weekly-110-promo.png


 


In this installment of the weekly discussion revolving around the latest news and topics on Microsoft 365, hosts – Vesa Juvonen (Microsoft) | @vesajuvonen, Waldek Mastykarz (Microsoft) | @waldekm, are joined by Erwin van Hunen (Valo Intranet) | @erwinvanhunen – MVP, Father of PnP PowerShell, and Lead Architect at Valo Intranet in Sweden.


 


How do you end up owning a PnP open source project?  Start by making and sharing something that makes your own life easier.  In Erwin’s case, create a little PowerShell module in 2014.   Now, 60 Million PowerShell Cmdlets are executed each day.  Subsequent discussion focuses on who, why, where, how to use PnP PowerShell.  PnP PowerShell can be used for Microsoft Teams and Planner in addition to SharePoint.  Covered off on connectivity, authentication, supportability, roadmap, and on how PnP PowerShell and Microsoft Graph PowerShell are complementary.  Future and present – a multi-Platform PnP PowerShell for Windows, Mac, Linux, Raspberry Pi, Azure Functions, Azure Automation.  PnP.PowerShell v1.00 is releasing this week thanks to contributions from many PnP community members.


 


This episode was recorded on Monday, January 18, 2020.


 



 


Did we miss your article? Please use #PnPWeekly hashtag in the Twitter for letting us know the content which you have created. 


 


As always, if you need help on an issue, want to share a discovery, or just want to say: “Job well done”, please reach out to Vesa, to Waldek or to your Microsoft 365 PnP Community.


 


Sharing is caring!

Automate the Deployment of Azure Firewall as a Network Virtual Appliance (NVA)

This article is contributed. See the original author and article here.

Purpose:


 


The purpose of this post is to demonstrate how to automate the deployment of Azure Firewall to be used as an Network Virtual Appliance (NVA) in a Hub & Spoke architecture.  Our previous post on this subject (Using Azure Firewall as a Network Virtual Appliance (NVA) (microsoft.com) walked through this process as it would be done in the Azure Portal.  In this post we will show how to deploy this entire solution with one Powershell script.


 


Assumptions: Knowledge of creating Azure virtual machines and Azure virtual networks, as well as user-defined routes and peering is assumed.  The firewall rules described in this writing will allow all outbound traffic from resources in Spoke1 and Spoke2.  This configuration is for demonstration purposes only.  Depending on the security posture needed for a production environment, this configuration would likely be more tightly controlled from the firewall.  For our demonstration purposes, this configuration is being used for functionality and convenience.


 


Here are the items that are deployed with this automated solution:


 


Resource Group:



  • Just one named AzureFW


 


Virtual Networks:






















Vnet



Address Space



Hub



10.200.0.0/16



Spoke1



10.201.0.0/16



Spoke2



10.020.0.0/16



 


Subnets:


























Subnet



CIDR



Hub-Subnet



10.200.0.0/24



AzureFirewallSubnet



10.200.1.0/24



Spoke1-Subnet



10.201.0.0/24



Spoke2-Subnet



20.202.0.0/24



 


Virtual Network Peering:



  • Hub peers with Spoke1 (bi-directional)


    • Forwarding must be enabled


  • Hub peers with Spoke2 (bi-directional)


    • Forwarding must be enabled



 


Route Tables: 



  • RT-Spoke1


    • Attached to default subnet in Spoke1-Vnet.

    • Routes:


      • 0.0.0.0/0: Next Hop: <<Azure Firewall Private IP>>


    • RT-Spoke2


      • Attached to default subnet in Spoke2-Vnet.

      • Routes:


        • 0.0.0.0/0: Next Hop: <<Azure Firewall Private IP>>





Azure Firewall:



  • NAT Rule Collection:


    • Rule 1, priority 1000 allow:


      • Spoke1-RDP, allow traffic from any source to destination firewall public IP address on port 3389 which is translated to Spoke1 VM private IP address on port 3389


    • Network Rule Collections:


      • Rule 1, priority 2000, allow:


        • Spoke1-Outbound, allow all traffic from source 10.201.0.0/24 to any destination, all ports

        • Spoke2-Outbound, allow all traffic from source 10.202.0.0/24 to any destination, all ports





Virtual Machines:



  • (3) Windows VM’s


    • (1) VM in Hub VNet, hub-subnet

    • (1) VM in Spoke1 VNet, spoke1-subnet

    • (1) VM in Spoke2 Vnet, spoke2-subnet



 


 


Powershell Code Parameters/Notes:


 


The Powershell code used to deploy this solution can be easily modified to suit your needs.  This sample code was written to deploy the solution as a lab environment meant for testing.  Here are a few of the parameters that can be input or modified.


 


















































































































































































































Param



Default



Options



Note



SubscriptionName



My-Subscription



 



 



RGBase



AzureFw



 



Base of Resource Group Name



AzureEnvironment



MAC



MAC, MAG, *Any*



Feeds a function to translate Azure Env



RG



$RGBase-RG



 



Adds “-RG” to RGBase for Resource Group Name



Location



EastUS



 



Azure Location



Script



c:tempDisable-WindowsFW.ps1



 



Temp location of script created to disable Windows Firewall on all VM’s after creation



VMUser



AzureAdmin



 



Admin user for VM’s if not using VMPWPrompt flag



VMPw



My@zurePW010203



 



Admin user password for VM’s if not using VMPWPrompt



VMPwPrompt



$false



$true,$false



Flag if you want to use VM admin name/password from variables or if you want to be prompted to enter for each VM



HubNvetName



Hub-Vnet



 



Name of Hub Vnet



Spoke1VnetName



Spoke1-Vnet



 



Name Spoke1 Vnet



Spoke2VnetName



Spoke2-Vnet



 



Name of Spoke2 Vnet



HubSubnetName



HubSubnet



 



Name of Hub Subnet



Spoke1SubnetName



Spoke1Subnet



 



Name of Spoke1 Subnet



Spoke2SubnetName



Spoke2Subnet



 



Name of Spoke2 Subnet



HubVnetAddSpace



10.200.0.0/16



 



Hub Vnet Address Space



Spoke1VnetAddSpace



10.201.0.0/16



 



Spoke1 Vnet Address Space



Spoke2VnetAddSpace



10.202.0.0/16



 



Spoke2 Vnet Address Space



HubSubnetCIDR



10.200.0.0/24



 



Hub Subnet CIDR



HubAzFwSubnetCIDR



10.200.1.0/24



 



Azure Firewall Subnet CIDR



Spoke1SubnetCIDR



10.201.0.0/24



 



Spoke1 Subnet CIDR



Spoke2SubnetCIDR



10.202.0.0/24



 



Spoke2 Subnet CIDR



HubVMName



Hub-VM-01



 



Hub VM Name



Spoke1VMName



Spoke1-VM-01



 



Spoke1 VM Name



Spoke2VMName



Spoke2-VM-01



 



Spoke2 VM Name



HubVMIP



10.200.0.10



 



Hub VM IP



Spoke1VMIP



10.201.0.10



 



Spoke1 VM IP



Spoke2VMIP



10.202.0.10



 



Spoke2 VM IP



VMSize



Standard_B2ms



 



VM Sku Family (VM Size)



ConvertStorage



$true



$true, $false



Flag to run convert storage function.  Function that converts from Premium SSD disks to Standard SSD disks on all created VM’s



VMPIP



$false



$true, $false



Flag for assigning Public IP to each VM created



OutFile



c:tempCreate-AzureFW-As-NVA-FINAL_LOG.log



 



Path to output log file



VMStorageType



StandardSSD_LRS



 



Disk storage type used if $ConvertStorage is set to $true



 


 


Powershell Code:


 


 


 


 


 


 


 

param (
    [string]$SubscriptionName = "My-Subscription",
    [string]$RGBase = "AzureFW",
    [string]$AzureEnvironment = "MAC",
    [string]$RG = "$RGBase-RG",
    [string]$Location="EastUS",
    [string]$Script = "C:tempDisable-WindowsFW.ps1",
    [string]$VMUser = "AzureAdmin",
    [string]$VMPW = 'Azure@dmin010203',
    [switch]$VMPWPrompt = $false,
    [string]$HubVnetName = "Hub-vnet",
    [string]$Spoke1VnetName = "Spoke1-vnet",
    [string]$Spoke2VnetName = "Spoke2-vnet",
    [string]$HubSubnetName = "HubSubnet",
    [string]$Spoke1SubnetName = "Spoke1Subnet",
    [string]$Spoke2SubnetName = "Spoke2Subnet",
    [string]$HubVnetAddSpace = "10.200.0.0/16",
    [string]$Spoke1VnetAddSpace = "10.201.0.0/16",
    [string]$Spoke2VnetAddSpace = "10.202.0.0/16",
    [string]$HubSubnetCIDR = "10.200.0.0/24",
    [string]$HubAzFWSubnetCIDR = "10.200.1.0/24",
    [string]$Spoke1SubnetCIDR = "10.201.0.0/24",
    [string]$Spoke2SubnetCIDR = "10.202.0.0/24",
    [string]$HubVMName = "Hub-VM-01",
    [string]$Spoke1VMName = "Spoke1-VM-01",
    [string]$Spoke2VMName = "Spoke2-VM-01",
    [string]$HubVMIP = "10.200.0.10",
    [string]$Spoke1VMIP = "10.201.0.10",
    [string]$Spoke2VMIP = "10.202.0.10",
    [string]$VMSize = "Standard_B2ms",
    [switch]$ConvertStorage = $false,
    [switch]$VMPIP = $false,
    [string]$Outputfile = "c:tempCreate-Azure-Firewall-As-NVA_Final_LOG.log",
    [string]$VMStorageType = "StandardSSD_LRS"
)

#Logging/Output Function

Function Log($out) {
    $t = [System.DateTime]::Now.ToString("yyyy.MM.dd hh:mm:ss")
    set-variable -Name Now -Value $t -scope Script
    $Out = $Now +" ---- "+$out
    $Out | add-content $Outputfile
    Write-Host $Out -ForegroundColor "Green"
}

#Begin Processing
$Start = Get-Date
Log "Starting Process:  $Start"

#Convert necessary parts for MAG
Switch ($AzureEnvironment)
{
    "MAG" {$AzureEnvironment = "AzureUSGovernment"}
    "MAC" {$AzureEnvironment = "AzureCloud"}
    "AzureUSGovernment" {$AzureEnvironment = "AzureUSGovernment"}
    "AzureCloud" {$AzureEnvironment = "AzureCloud"}
    Default {$AzureEnvironment = "AzureCloud"}
}

#Connect to Azure
Connect-AzAccount -Environment $AzureEnvironment
Select-AzSubscription -SubscriptionName $SubscriptionName

#Validate Locations
$AzLocations = ((Get-AzLocation).Location)
If ($AzLocations -inotcontains $Location)
{
    Log "Creating error because Location: $Location is not found in Connected Environment: $AzureEnvironment Locations: $AzLocations"
    Log "Stopping Script"
    Log "ERROR: Selected Azure Environment and Selected Azure Region Do Not Match.  Change Region or Azure Environment.  (eg MAG vs MAC in the -AzureEnvironment Parameter)"
    Write-Error "Selected Azure Environment and Selected Azure Region Do Not Match.  Change Region or Azure Environment.  (eg MAG vs MAC in the -AzureEnvironment Parameter)" -ErrorAction Stop
}

#Create new RG
Log "Creating Resource Group"
New-AzResourceGroup -Name $RG -Location $Location

#Create Virtual Network and Subnets
Log "Creating VNets"
$s1 = New-AzVirtualNetworkSubnetConfig -Name $HubSubnetName -AddressPrefix $HubSubnetCIDR
$s2 = New-AzVirtualNetworkSubnetConfig -Name "AzureFirewallSubnet" -AddressPrefix $HubAzFWSubnetCIDR
$s3 = New-AzVirtualNetworkSubnetConfig -Name $Spoke1SubnetName -AddressPrefix "$Spoke1SubnetCIDR"
$s4 = New-AzVirtualNetworkSubnetConfig -Name $Spoke2SubnetName -AddressPrefix "$Spoke2SubnetCIDR"
$Hubvnet = New-AzVirtualNetwork -Name $HubVnetName -Location $Location -ResourceGroupName $RG -AddressPrefix "$HubVnetAddSpace" -Subnet $s1,$s2
$Spoke1vnet = New-AzVirtualNetwork -Name $Spoke1VnetName -Location $Location -ResourceGroupName $RG -AddressPrefix "$Spoke1VnetAddSpace" -Subnet $s3
$Spoke2vnet = New-AzVirtualNetwork -Name $Spoke2VnetName -Location $Location -ResourceGroupName $RG -AddressPrefix "$Spoke2VnetAddSpace" -Subnet $s4

#Setup Peering Between Hub and Each Spoke
Log "Setting Up Peering"
Add-AzVirtualNetworkPeering -Name Hub-Spoke1 -VirtualNetwork $Hubvnet -RemoteVirtualNetworkId $Spoke1vnet.Id -AllowForwardedTraffic
Add-AzVirtualNetworkPeering -Name Spoke1-Hub -VirtualNetwork $Spoke1vnet -RemoteVirtualNetworkId $Hubvnet.Id -AllowForwardedTraffic
Add-AzVirtualNetworkPeering -Name Hub-Spoke2 -VirtualNetwork $Hubvnet -RemoteVirtualNetworkId $Spoke2vnet.Id -AllowForwardedTraffic
Add-AzVirtualNetworkPeering -Name Spoke2-Hub -VirtualNetwork $Spoke2vnet -RemoteVirtualNetworkId $Hubvnet.Id -AllowForwardedTraffic

#create Public IP for Firewall
Log "Setting up PIP for FW"
$FWPipName = $RGBase + "-FW-PIP"
$FWPip = New-AzPublicIpAddress -Name $FWPipName -ResourceGroupName $RG -Location $Location -AllocationMethod Static -Sku Standard

#Create AZFW
Log "Creating Firewall"
$FWName = $RGBase + "-AzFW"
$Azfw = New-AzFirewall -Name $FWName -ResourceGroupName $RG -Location $Location -VirtualNetwork $Hubvnet -PublicIpAddress $FWPip

#Add a rule to allow internal traffic
Log "Creating Rules to Firewall"
$Azfw = Get-AzFirewall -ResourceGroupName $RG
$FWPrivIP = $Azfw.IpConfigurations[0].PrivateIPAddress
$FWAssignedPIP = $FWPip.IPAddress
$NetRule3 = New-AzFirewallNetworkRule -Name "Spoke1-All" -Protocol "Any" -SourceAddress $Spoke1SubnetCIDR -DestinationAddress "*" -DestinationPort "*"
$NetRule4 = New-AzFirewallNetworkRule -Name "Spoke2-All" -Protocol "Any" -SourceAddress $Spoke2SubnetCIDR -DestinationAddress "*" -DestinationPort "*"
$NatRule1 = New-AzFirewallNatRule -Name "RDP-In" -Protocol "TCP" -SourceAddress "*" -DestinationAddress $FWAssignedPIP -DestinationPort "3389" -TranslatedAddress $Spoke1VMIP -TranslatedPort "3389"
Log "Creating Rule Collections for FW"
$NetRuleCollection2 = New-AzFirewallNetworkRuleCollection -Name "Allow-Outbound" -Priority 2000 -Rule $NetRule3,$NetRule4 -ActionType "Allow"
$NatRuleCollection1 = New-AzFirewallNatRuleCollection -Name "Inbound-RDP-Nat" -Priority 1000 -Rule $NatRule1
Log "Assigning Rule Collections to FW and Saving"
$Azfw.NetworkRuleCollections.Add($NetRuleCollection2)
$Azfw.NatRuleCollections.Add($NatRuleCollection1)
Set-AzFirewall -AzureFirewall $Azfw

#Create Route Tables and Routes
Log "Creating Route Tables"

#Spoke1 to Spoke2
$Spoke1RouteName = $RGBase + "Spoke1-AllTraffic"
$Spoke1RouteTableName = $RGBase + "Spoke1-RT"
$Spoke1Route = New-AzRouteConfig -Name $Spoke1RouteName -AddressPrefix "0.0.0.0/0" -NextHopType VirtualAppliance -NextHopIpAddress $FWPrivIP
$Spoke1RouteTable = New-AzRouteTable -Name $Spoke1RouteTableName -ResourceGroupName $RG -location $Location -Route $Spoke1Route -DisableBgpRoutePropagation

#Spoke2 to Spoke1
$Spoke2RouteName = $RGBase + "Spoke2-AllTraffic"
$Spoke2RouteTableName = $RGBase + "Spoke2-RT"
$Spoke2Route = New-AzRouteConfig -Name $Spoke2RouteName -AddressPrefix "0.0.0.0/0" -NextHopType VirtualAppliance -NextHopIpAddress $FWPrivIP
$Spoke2RouteTable = New-AzRouteTable -Name $Spoke2RouteTableName -ResourceGroupName $RG -location $Location -Route $Spoke2Route -DisableBgpRoutePropagation

#Associate route tables to Subnets
Log "Associating Route Tables to Subnets"
Set-AzVirtualNetworkSubnetConfig -VirtualNetwork $Spoke1Vnet -Name $Spoke1SubnetName -AddressPrefix $Spoke1SubnetCIDR -RouteTable $Spoke1RouteTable | Set-AzVirtualNetwork
Set-AzVirtualNetworkSubnetConfig -VirtualNetwork $Spoke2Vnet -Name $Spoke2SubnetName -AddressPrefix $Spoke2SubnetCIDR -RouteTable $Spoke2RouteTable | Set-AzVirtualNetwork

#Create an IP configuration with a static private IP address
Log "Creating IP Configs with Private IP for VMs"
$HubIpConfigName = "Hub-IPConfig"
$HubSubnet = Get-AzVirtualNetworkSubnetConfig -VirtualNetwork $Hubvnet -Name $HubSubnetName
$Spoke1IpConfigName = "Spoke1-IPConfig"
$Spoke1Subnet = Get-AzVirtualNetworkSubnetConfig -VirtualNetwork $Spoke1vnet -Name $Spoke1SubnetName
$Spoke2IpConfigName = "Spoke2-IPConfig"
$Spoke2Subnet = Get-AzVirtualNetworkSubnetConfig -VirtualNetwork $Spoke2vnet -Name $Spoke2SubnetName

#Check if PIP is required, get PIP, and set Ip Configurations accordingly
If ($VMPIP){
    #PIP Required.  Create new and set Ip Configs
    Log "VMPIP Flag Found.  Creating PIP and Adding to Each VM"
    $HubPIP1 = New-AzPublicIpAddress -Name "$HubVMName-NIC-PIP" -ResourceGroupName $RG -Location $Location -AllocationMethod Static -Sku Standard
    $Spoke1PIP1 = New-AzPublicIpAddress -Name "$Spoke1VMName-NIC-PIP" -ResourceGroupName $RG -Location $Location -AllocationMethod Static -Sku Standard
    $Spoke2PIP1 = New-AzPublicIpAddress -Name "$SPoke2VMName-NIC-PIP" -ResourceGroupName $RG -Location $Location -AllocationMethod Static -Sku Standard
    $HubIpConfig = New-AzNetworkInterfaceIpConfig -Name $HubIpConfigName -Subnet $HubSubnet -PrivateIpAddress $HubVMIP -PublicIpAddress $HubPIP1 -Primary
    $Spoke1IpConfig = New-AzNetworkInterfaceIpConfig -Name $Spoke1IpConfigName -Subnet $Spoke1Subnet -PrivateIpAddress $Spoke1VMIP -PublicIpAddress $Spoke1PIP1 -Primary
    $Spoke2IpConfig = New-AzNetworkInterfaceIpConfig -Name $Spoke2IpConfigName -Subnet $Spoke2Subnet -PrivateIpAddress $SPoke2VMIP -PublicIpAddress $Spoke2PIP1 -Primary
}
Else 
{
    #PIP NOT Required.  Set IP Config without PIP
    Log "VMPIP is NOT Found.  Creating IPConfig with NO PIP"
    $HubIpConfig = New-AzNetworkInterfaceIpConfig -Name $HubIpConfigName -Subnet $HubSubnet -PrivateIpAddress $HubVMIP -Primary
    $Spoke1IpConfig = New-AzNetworkInterfaceIpConfig -Name $Spoke1IpConfigName -Subnet $Spoke1Subnet -PrivateIpAddress $Spoke1VMIP -Primary
    $Spoke2IpConfig = New-AzNetworkInterfaceIpConfig -Name $Spoke2IpConfigName -Subnet $Spoke2Subnet -PrivateIpAddress $SPoke2VMIP -Primary
}

#Create & Configure NSG's for the NIC's
Log "Create NSG Rules"
$NSGRule = New-AzNetworkSecurityRuleConfig -Name "Allow-RDP" -Protocol Tcp -Direction Inbound -Priority 1000 -SourceAddressPrefix * -SourcePortRange * -DestinationAddressPrefix * -DestinationPortRange 3389 -Access Allow

# Create a network security group
Log "Create NSGs for VMs"
$HubNSG = New-AzNetworkSecurityGroup -ResourceGroupName $RG -Location $Location -Name "HubNetworkSecurityGroup" -SecurityRules $NSGRule
$Spoke1NSG = New-AzNetworkSecurityGroup -ResourceGroupName $RG -Location $Location -Name "Spoke1NetworkSecurityGroup" -SecurityRules $NSGRule
$Spoke2NSG = New-AzNetworkSecurityGroup -ResourceGroupName $RG -Location $Location -Name "Spoke2NetworkSecurityGroup" -SecurityRules $NSGRule

#Create the NICs
Log "Create NICs for VMs"
$HubNIC = New-AzNetworkInterface -Name "$HubVMName-NIC" -ResourceGroupName $RG -Location $Location -IpConfiguration $HubIpConfig -NetworkSecurityGroupId $HubNSG.Id
$Spoke1NIC = New-AzNetworkInterface -Name "$Spoke1VMName-NIC" -ResourceGroupName $RG -Location $Location -IpConfiguration $Spoke1IpConfig -NetworkSecurityGroupId $Spoke1NSG.Id
$Spoke2NIC = New-AzNetworkInterface -Name "$Spoke2VMName-NIC" -ResourceGroupName $RG -Location $Location -IpConfiguration $Spoke2IpConfig -NetworkSecurityGroupId $Spoke2NSG.Id

#Setup Credentials for VM's
If ($VMPWPrompt)
{
    Log "VMPWPrompt Found.  Prompting for VM Name/PW"
    $Cred = Get-Credential -UserName $VMUser -Message "Specify Credentials for VM OS"
} Else 
{
    Log "NO VMPWPrompt Found.  Using Specified Creds for VMs"
    $SecurePassword = ConvertTo-SecureString $VMPW -AsPlainText -Force
    $Cred = New-Object System.Management.Automation.PSCredential ($VMUser, $securePassword)
}

#Define the virtual machines
Log "Building Config for VMs"
$HubVirtualMachine = New-AzVMConfig -VMName $HubVMName -VMSize $VMSize
$HubVirtualMachine = Set-AzVMOperatingSystem -VM $HubVirtualMachine -Windows -ComputerName $HubVMName -ProvisionVMAgent -EnableAutoUpdate -Credential $Cred
$HubVirtualMachine = Add-AzVMNetworkInterface -VM $HubVirtualMachine -Id $HUbNIC.Id
$HubVirtualMachine = Set-AzVMSourceImage -VM $HubVirtualMachine -PublisherName 'MicrosoftWindowsServer' -Offer 'WindowsServer' -Skus '2016-Datacenter' -Version latest
$Spoke1VirtualMachine = New-AzVMConfig -VMName $Spoke1VMName -VMSize $VMSize
$Spoke1VirtualMachine = Set-AzVMOperatingSystem -VM $Spoke1VirtualMachine -Windows -ComputerName $Spoke1VMName -ProvisionVMAgent -EnableAutoUpdate -Credential $Cred
$Spoke1VirtualMachine = Add-AzVMNetworkInterface -VM $Spoke1VirtualMachine -Id $Spoke1NIC.Id
$Spoke1VirtualMachine = Set-AzVMSourceImage -VM $Spoke1VirtualMachine -PublisherName 'MicrosoftWindowsServer' -Offer 'WindowsServer' -Skus '2016-Datacenter' -Version latest
$Spoke2VirtualMachine = New-AzVMConfig -VMName $Spoke2VMName -VMSize $VMSize
$Spoke2VirtualMachine = Set-AzVMOperatingSystem -VM $Spoke2VirtualMachine -Windows -ComputerName $Spoke2VMName -ProvisionVMAgent -EnableAutoUpdate -Credential $Cred
$Spoke2VirtualMachine = Add-AzVMNetworkInterface -VM $Spoke2VirtualMachine -Id $Spoke2NIC.Id
$Spoke2VirtualMachine = Set-AzVMSourceImage -VM $Spoke2VirtualMachine -PublisherName 'MicrosoftWindowsServer' -Offer 'WindowsServer' -Skus '2016-Datacenter' -Version latest

#Create the virtual machine
Log "Creating VMs"
New-AzVM -ResourceGroupName $RG -Location $Location -VM $HubVirtualMachine -Verbose
New-AzVM -ResourceGroupName $RG -Location $Location -VM $Spoke1VirtualMachine -Verbose
New-AzVM -ResourceGroupName $RG -Location $Location -VM $Spoke2VirtualMachine -Verbose
Start-Sleep -Seconds 15

#Create Script to Disable Windows Firewall
Log "Creating Script to Disable Windows FW in VM OS"
'Get-netfirewallprofile | Set-netfirewallprofile -enabled "false"' | out-file -FilePath $Script -Force

#Run Script Inside VM's to Disable Windows Firewall
Log "Execute Script to Disable Windows FW Inside VMs"

Invoke-AzVMRunCommand -ResourceGroupName $RG -Name $HubVMName -CommandId "RunPowerShellScript" -ScriptPath $Script

Invoke-AzVMRunCommand -ResourceGroupName $RG -Name $Spoke1VMName -CommandId "RunPowerShellScript" -ScriptPath $Script

Invoke-AzVMRunCommand -ResourceGroupName $RG -Name $Spoke2VMName -CommandId "RunPowerShellScript" -ScriptPath $Script

#Remove Script to Disable Windows Firewall
Log "Remove Generated Script"
Remove-Item -Path $Script -Force

#If ConvertSTorage is $True, convert storage of all VM's in RG.  Includes Shutdown and Startup.
If ($ConvertStorage)
{

    #Get the VM's in the RG, Stop the VM's, Get the Disks for the VM's, Set the Disk to SSD Standard, Start the VM's
    Log "ConvertStorage Flag Found.  Changing Storage to $StorageType"
    $VMs = Get-AzVM -ResourceGroupName $RG
    Foreach ($VM in $VMs)
    {
        #Wait for VM's to Finish Provisioning
        $Count = 0
        Do
        {
            $Count++
            Log "Sleeping for VM Provisioning...Trying to Convert Storage for $($VM.Name)"
            Log "Loop Iteration Count: $Count"
            Start-Sleep -Seconds 10
            $V = $null
            $V = Get-AzVM -ResourceGroupName $RG -Name $VM.Name
            Log "VM: $($V.Name) is in Provisioning State: $($V.ProvisioningState)"
        } Until ($V.ProvisioningState -eq "Succeeded")
        Log "Stopping VM $($VM.Name) for Storage Conversion"
        Stop-AzVM -ResourceGroupName $RG -Name $VM.name -Force
        Start-Sleep -Seconds 15
        $VMID = $null
        $VMID = $VM.Id
        $vmDisks = $null
        $vmDisks = Get-azDisk -ResourceGroupName $RG | Where-Object {$_.managedby -eq $VMID}
    
        Foreach ($Disk in $vmDisks)
        {
            Log "Converting Storage for Disk"
            $disk.Sku = [Microsoft.Azure.Management.Compute.Models.DiskSku]::new($VMStorageType)
           $disk | Update-AzDisk
        }
    }
 
#Start VMs
    Foreach ($VM in $VMs)
    {
        Log "Starting VM $($VM.Name) After Disk Conversion"
        Start-AzVM -ResourceGroupName $RG -Name $VM.name -NoWait
    }
}

$Stop = Get-Date
Log "Output Log File Stored to: $Outputfile"
Log "Total Duration: $(($Stop-$Start).Minutes) Minutes"

 


 


 


 


 


 


 


 

Find the Hostname of a Hyper-V VM

Find the Hostname of a Hyper-V VM

This article is contributed. See the original author and article here.

If you are running a virtual machine (VM) on Hyper-V, sometimes you want to know on which Hyper-V host this VM is running. If you don’t have access to the Hyper-V host, you need to find that information from within the virtual machines operating system. Luckily, the hostname of the physical Hyper-V server the virtual machine is running on can be found in the virtual machines registry.

 

You can find that information under the following registry key:

 

ComputerHKEY_LOCAL_MACHINESOFTWAREMicrosoftVirtual MachineGuestParameters

 

You will get some additional information about the Hyper-V host as well as the physical Hyper-V Hostname of the VM.

 

Find the Hostname of a Hyper-V VM in RegistryFind the Hostname of a Hyper-V VM in Registry

You could also run the following PowerShell command to get the Hyper-V hostname inside the VM:

 

Get-ItemProperty -Path “HKLM:SOFTWAREMicrosoftVirtual MachineGuestParameters”  | Select-Object HostName

 

Since we run a version of Hyper-V in our Microsoft Azure datacenters, this also works with Azure VMs.

 

Get physical hostname of a Hyper-V VM using PowerShell (Azure VM)Get physical hostname of a Hyper-V VM using PowerShell (Azure VM)

I hope this post was helpful and shows you how you can find the hostname the physical Hyper-V host of a VM. if you have any questions feel free to leave a comment below.

And yes, the first screenshot was taken on a Surface Pro X running Hyper-V on Windows 10 on ARM.

Service Bus –Complete Message Asynchronously or Synchronously?

Service Bus –Complete Message Asynchronously or Synchronously?

This article is contributed. See the original author and article here.

Test Entities: 


I use a same Queue to do this test. The Max delivery count is 1 If you are interested about the usage of “Max delivery count” please check from here Service Bus exceeding MaxDeliveryCount 


Message lock duration time is 30s.  


Scarlett_liu_0-1611052688610.jpeg


My Program: 


Here I use different function in .Net for receive messages. All the functions have Async” like ReceiveBatchAsync means the functions are working Asynchronously. 


 


To simulate the situation by sending a large number of messages, I received 5000 messages at one operation. 


 



  • Here is the program that complete messages in Asynchronous patterns.  


using Microsoft.ServiceBus.Messaging; 


using System; 


using System.Collections.Generic; 


using System.Linq; 


using System.Text; 


using System.Threading.Tasks; 


 


namespace SendReceiveQueue 


{ 


    class Program 


    { 


        static string connectionString = <your connection string>; 


        static string queueName = <queue name>; 


        static void Main(string[args) 


        { 


            MainAsync().GetAwaiter().GetResult(); 


        } 


        public static async Task MainAsync() 


        { 


            QueueClient receiveClient = QueueClient.CreateFromConnectionString(connectionStringqueueName); 


            //create a sender on the queue 


            var Timestamp2 = new DateTimeOffset(DateTime.UtcNow).ToUnixTimeMilliseconds(); 


            Console.WriteLine(“Receiving message -, timestamp:{0}”, Timestamp2); 


 


 


             IEnumerable<BrokeredMessagemessageList = await receiveClient.ReceiveBatchAsync(5000); 


            foreach (BrokeredMessage message in messageList) 


            { 


                try 


                { 


                    var Timestamp0 = new DateTimeOffset(DateTime.UtcNow).ToUnixTimeMilliseconds(); 


                    Console.WriteLine(“Message”+message.GetBody<string>() +“time”+Timestamp0); 


 


                    message.CompleteAsync(); 


                } 


                catch (Exception ex) 


                { 


                    var Timestamp3 = new DateTimeOffset(DateTime.UtcNow).ToUnixTimeMilliseconds(); 


                    Console.WriteLine(“abandon message – timestamp:{0},errorr message {1}”, Timestamp3,ex.Message); 


                    await message.AbandonAsync(); 


                } 


            } 


 


            await receiveClient.CloseAsync(); 


        } 


    } 


} 


 


This is the result. The average time of receiving message is in 200ms to 300ms. 


Scarlett_liu_1-1611052688631.jpeg



  • And this is the Code for receiving messages with Synchronous messaging patterns.  


using Microsoft.ServiceBus.Messaging; 


using System; 


using System.Collections.Generic; 


using System.Linq; 


using System.Text; 


 


 


namespace SendReceiveQueue 


{ 


    class Program 


    { 


        static string connectionString = <your connection string>; 


        static string queueName = <queue name>; 


        static void Main(string[args) 


        { 


            MainTest(); 


        } 


        static void MainTest() 


        { 


            QueueClient receiveClient = QueueClient.CreateFromConnectionString(connectionStringqueueName); 


            //create a sender on the queue 


            var Timestamp2 = new DateTimeOffset(DateTime.UtcNow).ToUnixTimeMilliseconds(); 


            Console.WriteLine(“Receiving message -, timestamp:{0}”, Timestamp2); 


 


            IEnumerable<BrokeredMessagemessageList = receiveClient.ReceiveBatch(5000); 


            foreach (BrokeredMessage message in messageList) 


            { 


                try 


                { 


                    var Timestamp0 = new DateTimeOffset(DateTime.UtcNow).ToUnixTimeMilliseconds(); 


                    Console.WriteLine(“Message” + message.GetBody<string>() + “time” + Timestamp0); 


 


                    message.Complete(); 


                } 


                catch (Exception ex) 


                { 


                    var Timestamp3 = new DateTimeOffset(DateTime.UtcNow).ToUnixTimeMilliseconds(); 


                    Console.WriteLine(“abandon message – timestamp:{0},errorr message {1}”, Timestamp3, ex.Message); 


                    message.Abandon(); 


                } 


            } 


 


            receiveClient.Close(); 


            Console.Read(); 


        } 


    } 


} 


 


This is the result. At first time the messages can also finish in 200ms to 300ms. But after a while It shows error for “lock expired”.  


Scarlett_liu_2-1611052688638.jpeg


Why didn’t we get any errors while using the Async pattern in this program? Why we got “Lock expired” exception while using Sync pattern 


This exception is highly possible in receiving messages in one operation. Using Peeklock receive mode, Service Bus locked all the 5000 messages at the same time. And then complete messages in Asynchronous pattern, Messages can be completed without blocking 


But using Synchronous pattern, all the Messages was completed one by one, the waiting time exceeds 30s. So, it shows “lock expired” error.  


You can get detailed information on how the asynchronous C# backend works from this document. Asynchronous programming in C# | Microsoft Docs 


 


Test Result Summary 



  • From the test result, it indicates that Asynchronous Messaging pattern is more efficient since it will return immediatelyWe recommend using Asynchronous over than Synchronous. 

  • As mentioned before this “Lock expired” exception may be due to many reasons. That also the reason Service Bus have Dead Lettering Queue to prevent Service Bus message being lost. If you are interested in this topic, you are welcome to provide your comments.