Monday, September 20, 2021

TFS Build failure: folder cannot be deleted because it is not empty

When we run the build pipeline in Azure Devops, if we encounter below error then you can make the change recommended here.

Issue

D:\DevOps\Build\33\s\PT\<foldername>cannot be deleted because it is not empty. 

D:\DevOps\Build\33\s\PT\<foldername> cannot be deleted because it is not empty.

---- Summary: 0 conflicts, 1 warnings, 0 errors ---- 

Sleeping for 200 ms 

Retrying. Attempt $2/$3 

##[error]_proc should be null. (Parameter '_proc')


Cause

You can perform different kinds of cleaning of the working directory of your private agent before the build is run. If the Clean is set to false, it does not  get a fresh pull before the build is run.


Resolution


Change the clean dropdown to true and the error goes of in the next run.




Saturday, September 18, 2021

Update Azure SQL Database table using Service Principal Context

The script below checks whether a key exists in the DB and if yes it updates and if not it adds the key and value to the table. The context used here is the Service Principal Name (SPN) which is the client ID and secret key. Also the SQL authentication user ID and password is required. Make sure your machine ip is added in the firewall rules to run the query.

$dbuser = "username"

$password = "dbpswd"

$tenid = "tenantid"

$clientid = "client ID"

$secretkey = "Secret Key"

$Servername ="dbservername"

$database="dbname"


Write-Output "Starting"

#$clientid = Get-AzureRMAutomationVariable -Name $varclientid

#$secretkey = Get-AzureRMAutomationVariable -Name $varsecretkey

#$dbuser = Get-AzureRMAutomationVariable -Name $vardbuser

#$password = Get-AzureRMAutomationVariable -Name $vardbpass

#$sbpk = "test"


Add-SqlAzureAuthenticationContext -ClientID $clientid -Secret $secretkey -Tenant $tenid

$sqlConn = New-Object System.Data.SqlClient.SqlConnection

$sqlConn.ConnectionString = "Server=$Servername.database.windows.net; User ID = $dbuser ; Password = $password ; Database = $database; Column Encryption Setting=enabled;"

$sqlConn.Open()

Write-Output "sql conn opened"

function updateparamMaster($sqlconn,$paraID,$ParaGrp,$ParaValue)

{


#Check if the paramid and ParamGroup exists

$sqlcmd = New-Object System.Data.SqlClient.SqlCommand

$sqlcmd.Connection = $sqlConn

$query = "select * from parametermaster where paramid= $paraID and ParamGroup= '"+$ParaGrp+"'"

$sqlcmd.CommandText = $query

$adp = New-Object System.Data.SqlClient.SqlDataAdapter $sqlcmd

$data = New-Object System.Data.DataSet

$adp.Fill($data)

$paramcount = $data.Tables[0].Rows.count

Write-Host "Row count-" $paramcount


if($paramcount -eq 0)

{

Write-Output $ParaGrp "ParamGroup does not exist- creating new entry"

$sqlcmd = New-Object System.Data.SqlClient.SqlCommand

$sqlcmd.Connection = $sqlConn

$sqlcmd.CommandText = "INSERT into parametermaster(paramid,ParamGroup,Value) VALUES (@paramid, @ParamGroup, @Val)"

$sqlcmd.Parameters.Add((New-Object Data.SqlClient.SqlParameter("@paramid",[Data.SQLDBType]::Int)))

$sqlcmd.Parameters["@paramid"].Value = $paraID

$sqlcmd.Parameters.Add((New-Object Data.SqlClient.SqlParameter("@ParamGroup",[Data.SQLDBType]::VarChar, 50)))

$sqlcmd.Parameters["@ParamGroup"].Value = $ParaGrp

$sqlcmd.Parameters.Add((New-Object Data.SqlClient.SqlParameter("@val",[Data.SQLDBType]::NVarChar, 500)))

$sqlcmd.Parameters["@val"].Value =$ParaValue

$sqlcmd.ExecuteNonQuery();

}

else

{

Write-Output $ParaGrp "ParamGroup exist- updating entry"

$sqlcmd = New-Object System.Data.SqlClient.SqlCommand

$sqlcmd.Connection = $sqlConn

$sqlcmd.CommandText = "UPDATE parametermaster SET [Value] = @Val WHERE paramid = @paramid AND ParamGroup = @ParamGroup"

$sqlcmd.Parameters.Add((New-Object Data.SqlClient.SqlParameter("@paramid",[Data.SQLDBType]::Int)))

$sqlcmd.Parameters["@paramid"].Value = $paraID

$sqlcmd.Parameters.Add((New-Object Data.SqlClient.SqlParameter("@ParamGroup",[Data.SQLDBType]::VarChar, 50)))

$sqlcmd.Parameters["@ParamGroup"].Value = $ParaGrp

$sqlcmd.Parameters.Add((New-Object Data.SqlClient.SqlParameter("@val",[Data.SQLDBType]::NVarChar, 500)))

$sqlcmd.Parameters["@val"].Value =$ParaValue

$sqlcmd.ExecuteNonQuery();

}


}


updateparamMaster -sqlconn $sqlConn -paraID 118 -ParaGrp "SharedDb" -ParaValue

Tuesday, September 14, 2021

Add Virtual Machine Scale Set (VMSS) Managed Identity to Azure Key Vault Access Policy- Powershell

 The below Powershell script will help you to add VMSS managed identity to Azure Key vault access policy.

#First, Get the identity Object ID and application Id based on the managed identity name

$identity = Get-AzUserAssignedIdentity -ResourceGroupName "RGName" -Name "sample-vmssid"


# $identity.ClienId is the Application ID and $identity.PrincipalID is the Object ID. You can run the below command by passing parameters and permissions required to be set to the Key vault

Set-AzKeyVaultAccessPolicy -ResourceGroupName "RGName" -VaultName "VaultName-kvt" -ObjectId $identity.PrincipalId -ApplicationId $identity.ClientId -PermissionsToKeys get,list,unwrapKey,wrapKey -PermissionsToSecrets get -PermissionsToCertificates get,list,delete,create


#Thats it and you can see the vmss managed identity in the access policy for key vault.


#You can do the above using Azure CLI as well like below

spObjectID=$(az resource list -n vmss_name --query [*].identity.principalId --out tsv)

az keyvault set-policy -n vaultname-kvt --key-permissions get list wrapKey unwrapKey --secret-permissions backup restore --certificate-permissions get list delete create --object-id spObjectID


**Always share your knowledge**

Sunday, September 12, 2021

Set the compilation debug flag in IIS web.config

 One of the first things I check when troubleshooting ASP.NET applications is the debug flag in the web.config.

For this, I’ve written the following function that use the [xml] accelerator to cast the web.config file contents as an xmlDocument and use PowerShell’s dot notation to get the debug flag value, or use the .NET methods of the dom document to set the debug flag value:


function SetWebConfigDebugFlag {

    PARAM(

        [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)]

        [string]$IISsitename,


        [Parameter(Mandatory=$true)]

        [ValidateSet(‘True’, ‘False’)]

        $DebugFlag = $false

    )

$mersite= Get-Website -Name $IISsitename

$appPath = $mersite.physicalPath + "\web.config"

$config = [xml](Get-Content -Path $appPath)

 try {

if (($config.SelectSingleNode(‘configuration/system.web/compilation’)) -eq $null) {

$compilation = $config.CreateElement(‘compilation’)

$sw = $config.SelectSingleNode(‘configuration/system.web’)

[void] $sw.AppendChild($compilation)

} 

if ($config.SelectSingleNode(‘configuration/system.web/compilation/debug’) -eq $null) {

$compilation = $config.SelectSingleNode(‘configuration/system.web/compilation’)

$compilation.SetAttribute(‘debug’, ($DebugFlag.ToString()).ToLower())

} else {

$config.configuration.‘system.web’.compilation.debug = $DebugFlag

}

$config.Save($appPath)

if($?) {

$Result = ‘Success’

$ThisDebugFlag = $DebugFlag

} else {

$Result = ‘Error saving the config file’

$ThisDebugFlag = ""

}

}

catch {

$Result = $appPath.Exception.Message

if ($Result -eq ‘You cannot call a method on a null-valued expression.’) {

$Result = "Configuration does not contain a ‘system.web’ section"

$ThisDebugFlag = ""

}

}

New-Object -TypeName PSObject -Property @{‘Path’=$appPath; ‘DebugFlag’=$ThisDebugFlag; ‘Result’=$Result }

}

#Calling the above function by passing iissitename and Debugflag params.

SetWebConfigDebugFlag -IISsitename "iissitename" -DebugFlag 'True'

Wednesday, September 8, 2021

Azure Sentinel- Most common Use cases deployment

 Ready to go . Just import them, configure any additional permissions needed. Take advantage of Azure Sentinel right now.


Disable Users from OnPrem Active Directory:

https://github.com/Azure/Azure-Sentinel/tree/master/Playbooks/Block-OnPremADUser


Block Azure AD Users:

https://github.com/Azure/Azure-Sentinel/tree/master/Playbooks/Block-AADUser


Integrate Azure Sentinel alerts with Service Now:

https://github.com/Azure/Azure-Sentinel/tree/master/Playbooks/Close-SentinelIncident-fromSNOW


Add Comments (Guidelines) on Incidents:

https://github.com/Azure/Azure-Sentinel/tree/master/Playbooks/Comment-RemediationSteps


Confirm Risks for Azure Active Directory Users:

https://github.com/Azure/Azure-Sentinel/tree/master/Playbooks/Confirm-AADRiskyUser


Collect Threat Vulnerability Management report from compromised Machine:

https://github.com/Azure/Azure-Sentinel/tree/master/Playbooks/Enrich-SentinelIncident-MDATPTVM


Send all details (Machine Vulnerabilities, Missing KBs, Security Recommendations, Alerts, Software Inventory) from a compromised Machine and send it via Teams:

https://github.com/Azure/Azure-Sentinel/tree/master/Playbooks/Get-MachineData-EDR-SOAR-ActionsOnMachine


Send scheduled report focused on Cost Management:

https://github.com/Azure/Azure-Sentinel/tree/master/Playbooks/Send-IngestionCostAlert


Start Packet Capture from a compromised Machine:

https://github.com/Azure/Azure-Sentinel/tree/master/Playbooks/Run-AzureVMPacketCapture


Send scheduled report focused on Connector Heath:

https://github.com/Azure/Azure-Sentinel/tree/master/Playbooks/Send-ConnectorHealthStatus


Restrict App Execution in a compromised Machine:

https://github.com/Azure/Azure-Sentinel/tree/master/Playbooks/Restrict-MDATPAppExectution

Monday, September 6, 2021

Backup objects into another vault in another subscription

 How to: Backup objects into another vault in another subscription

In this section, I'm getting the secret values and saving them into another vault directly. We want to do this without touching any disk files.

With this approach, we're simply fetching all secrets from Vault1 in Subscription1, and saving them to Vault2 in Subscription2. However, remember that the secrets we fetch now are not encrypted to your subscription, hence it's not a good idea to persist them in memory, sessions or disk. Here I'm not saving it to any variables.

Make sure you have installed Azure CLI for windows in order to run the below script.


Param(

    [parameter(mandatory)] [string] $sourceVaultName,

    [parameter(mandatory)] [string] $sourceSubscriptionId,

    [parameter(mandatory)] [string] $destinationVaultName,

    [parameter(mandatory)] [string] $destinationSubscriptionId,

    [string] $destinationSecretsDisable = $true

)


# 1. Set the source subscription id. 

Write-Host "Setting origin subscription to: $($sourceSubscriptionId)..."

az account set -s $sourceSubscriptionId


# 1.1 Get all secrets

Write-Host "Listing all origin secrets from vault: $($sourceVaultName)"

$originSecretKeys = az keyvault secret list --vault-name $sourceVaultName  -o json --query "[].name"  | ConvertFrom-Json


# 1.3 Loop the secrets, and push the value to the destination vault without instantiating new variables.

$originSecretKeys | ForEach-Object {

    $secretName = $_

    Write-Host " - Getting '$($secretName)' from origin, and setting in destination..."

    az keyvault secret set --name $secretName --vault-name $destinationVaultName -o none --value(az keyvault secret show --name $secretName --vault-name $sourceVaultName -o json --query "value")

}


Write-Host "Secrets restored."


You can call the above script as mentioned below

.\CopySecretsToAnotherVault.ps1 -originVault "vault1-name" -originSubscriptionId "SUBSCRIPTION GUID" -destinationVault "vault2-name" -destinationSubscriptionId "SUBSCRIPTION GUID"

Passing Keyvault certificates to Virtual Machine deployment using ARM template

 

Referencing certificate from keyvault in an ARM template

You need to make sure all parameters are passed

"virtualMachineProfile": {
          "osProfile": {
            "computerNamePrefix""[variables('compnamepref')]",
            "adminUsername""[variables('adminUPN')]",
            "adminPassword""[variables('adminpswd')]",
            "windowsConfiguration": {
              "provisionVMAgent"true,
              "enableAutomaticUpdates"false
            },
            "secrets": [
              {
                "sourceVault": {
                  "id""[resourceId(parameters('RG'), 'Microsoft.KeyVault/vaults', parameters('vaultName'))]"
                },
                "vaultCertificates": [
                  {
                    "certificateUrl""[parameters('Cert1')]",
                    "certificateStore""My"
                  },
                  {
                    "certificateUrl""[parameters('Cert2')]",
                    "certificateStore""My"
                  }
                ]
              }
            ]

Tuesday, August 24, 2021

Purging a soft deleted Azure APIM - API Management

 First you need to run the below script to get all soft deleted apims so that the details can be passed to the delete method which we will run after this. The output printed on powershell window is trimmed and hence I'm writing the response to an output file.

#GET Request- To list all soft deleted apims in a specific subscription

$token = Get-AzAccessToken

$request = @{

    Method = 'GET'

    Uri    = "https://management.azure.com/subscriptions/{subscriptionId}/providers/Microsoft.ApiManagement/deletedservices?api-version=2020-06-01-preview"

    Headers = @{

        Authorization = "Bearer $($token.Token)"

    }

}

Invoke-RestMethod @request  -OutFile c:\apimoutput.txt


#DELETE Request- This will purge the soft deleted apim 


$token = Get-AzAccessToken

$request = @{

    Method = 'DELETE'

    Uri    = "https://management.azure.com/subscriptions/{subscriptionId}/providers/Microsoft.ApiManagement/locations/{Location}/deletedservices/{APIMName}?api-version=2020-06-01-preview"

    Headers = @{

        Authorization = "Bearer $($token.Token)"

    }

}

Invoke-RestMethod @request

Version an API in Azure API Management using Azure Resource Manager

When creating a new API in an Azure API Management Service using the portal, you can specify whether you would like the API to be versioned


To achieve this through ARM scripts you'll need to create an ApiVersionSet resource first:
{
    "name": "[concat(variables('ManagementServiceName'), '/', variables('VersionSetName'))]",
    "type": "Microsoft.ApiManagement/service/api-version-sets",
    "apiVersion": "2017-03-01",
    "properties": {
        "description": "Api Description",
        "displayName": "Api Name",
        "versioningScheme": "Segment"
    }
}

Then update the apiVersionSetId property on the Microsoft.ApiManagement/service/apis resource:


{
        "type": "Microsoft.ApiManagement/service/apis",
        "name": "[concat(variables('ManagementServiceName'), '/', variables('ApiName'))]",
        "apiVersion": "2017-03-01",
        "dependsOn": [
            "[resourceId('Microsoft.ApiManagement/service/api-version-sets', variables('ManagementServiceName'), variables('VersionSetName'))]"
        ],
        "properties": {
            "displayName": "string",
            "apiRevision": "1",
            "description": "",
            "serviceUrl": "string",
            "path": "string",
            "protocols": [
                "https"
            ],
            "isCurrent": true,
            "apiVersion": "v1",
            "apiVersionName": "v1",
            "apiVersionDescription": "string",
            "apiVersionSetId": "[concat('/api-version-sets', variables('VersionSetName'))]"
        }
    }

Cloud Maker- Allowing all azure services to access resources

 Cloud Maker- Allowing all azure services to access resources. While creating SQL Server droplet or other resources, if you would like to enable all azure services to access your resource then you can achieve that through firewall rules as shown in the below screenshot.






Thursday, July 15, 2021

Format view using json in SharePoint Online Modern Asset Library

 You can use view formatting to customize how items in SharePoint lists and libraries are displayed. To do this, you construct a JSON object that describes the elements that are displayed when an item is loaded in a view and any styles to be applied to those elements. View formatting does not change the data in list items; it only changes how they're displayed to users who browse the list. Anyone who can create and manage views in a list can use view formatting to configure how views are displayed

To open the view formatting pane, open the view dropdown and choose Format current view.


The pane will look like the following depending on the current layout:


Sample schema for asset library is below

{
"$schema": "https://developer.microsoft.com/json-schemas/sp/view-formatting.schema.json",
"tileProps": {
"hideSelection": true,
"height": "300",
"width": "300",
"formatter": {
"elmType": "div",
"style": {
"align-items": "stretch",
"margin": "2px 2px",
"background-color": "#fbfbfb",
"height": "380px",
"overflow": "inherit",
"border-radius": "2px",
"box-shadow": "0px 1.6px 3.6px 0 #00000024, 0px 0.3px 0.9px 0 #00000024"
},
"children": [
{
"elmType": "div",
"style": {
"display": "flex",
"flex-wrap": "wrap",
"position": "relative",
"padding-bottom": "5px",
"width": "100%"
},
"children": [
{
"elmType": "div",
"style": {
"margin-top": "0px",
"height": "200px",
"display": "block",
"align-items": "center",
"justify-content": "center",
"position": "relative",
"border-bottom": "1px solid #EEE",
"overflow": "hidden",
"border-radius": "2px 2px 0 0"
},
"children": [
{
"elmType": "button",
"style": {
"position": "absolute",
"height": "100%",
"width": "100%",
"opacity": "0",
"cursor": "pointer"
},
"customRowAction": {
"action": "defaultClick"
}
},
{
"elmType": "div",
"style": {
"width": "=if([$File_x0020_Type] == '', '100px', '100%')",
"height": "=if([$File_x0020_Type] == '', '100px', '100%')",
"oveflow": "=if([$File_x0020_Type] == '', 'auto', 'hidden')",
"text-align": "center",
"overflow": "hidden"
},
"children": [
{
"elmType": "img",
"style": {
"height": "=if([$File_x0020_Type] == '', '100%', '0'"
},
"attributes": {
"src": "=if([$File_x0020_Type] == '', 'https://spoprod-a.akamaihd.net/files/fabric/office-ui-fabric-react-assets/foldericons-fluent/folder-large_frontplate_nopreview.svg', '')"
}
},
{
"elmType": "img",
"style": {
"display": "=if([$File_x0020_Type] == '', 'none', '')"
},
"attributes": {
"src": "@thumbnail.383x383"
}
}
]
}
]
},
{
"elmType": "div",
"style": {
"margin": "25px 0 0 0",
"position": "absolute",
"top": "153px",
"width": "100%",
"color": "#333333"
},
"attributes": {
"class": "ms-fontSize-14 ms-fontWeight-semibold"
},
"children": [
{
"elmType": "img",
"attributes": {
"src": "=if([$File_x0020_Type] == 'docx', 'https://spoprod-a.akamaihd.net/files/fabric/assets/item-types-fluent/20/docx.svg?v6', if([$File_x0020_Type] == 'xlsx', 'https://spoprod-a.akamaihd.net/files/fabric/assets/item-types-fluent/20/xlsx.svg?v6', if([$File_x0020_Type] == 'pptx', 'https://spoprod-a.akamaihd.net/files/fabric/assets/item-types-fluent/20/pptx.svg?v6', if([$File_x0020_Type] == 'pdf', 'https://spoprod-a.akamaihd.net/files/fabric/assets/item-types-fluent/20/pdf.svg?v6', if([$File_x0020_Type] == 'jpg' || [$File_x0020_Type] == 'png' || [$File_x0020_Type] == 'gif','https://spoprod-a.akamaihd.net/files/fabric/assets/item-types-fluent/20/photo.svg?v6', if([$File_x0020_Type] == 'mp4' || [$File_x0020_Type] == 'avi' || [$File_x0020_Type] == 'mov', 'https://spoprod-a.akamaihd.net/files/fabric/assets/item-types-fluent/20/video.svg?v6', if([$File_x0020_Type] == 'zip', 'https://spoprod-a.akamaihd.net/files/fabric/assets/item-types-fluent/20/zip.svg?v6','Unknown')))))))"
},
"style": {
"flex": "none",
"line-height": "100%",
"font-weight": "normal",
"font-size": "2rem",
"margin": "5px 5px 5px 10px",
"height": "25px"
}
},
{
"elmType": "div",
"txtContent": "[$VideoTitle]",
"style": {
"padding": "0 0 0 16px",
"font-weight": "bold",
"font-size": "1rem"
}
},
{
"elmType": "div",
"txtContent": "[$VideoSummary]",
"style": {
"padding": "0 0 0 16px"
}
}
]
}
]
}
]
}
}
}

You can modify this based on your needs.







Tuesday, June 15, 2021

Create a VNet with a Site-to-Site (S2S) VPN connection using PowerShell

 A Site-to-Site VPN gateway connection is used to connect your on-premises network to an Azure virtual network over an IPsec/IKE (IKEv1 or IKEv2) VPN tunnel. This type of connection requires a VPN device located on-premises that has an externally facing public IP address assigned to it


1. Create a virtual network and a gateway subnet

If you don't already have a virtual network, create one. When creating a virtual network, make sure that the address spaces you specify don't overlap any of the address spaces that you have on your on-premises network.

Create a resource group:

New-AzResourceGroup -Name TestRG1 -Location 'East US'

Create your virtual network.

    Set the variables.

$subnet1 = New-AzVirtualNetworkSubnetConfig -Name 'GatewaySubnet' -AddressPrefix 10.1.255.0/27 $subnet2 = New-AzVirtualNetworkSubnetConfig -Name 'Frontend' -AddressPrefix 10.1.0.0/24

    Create the VNet.

New-AzVirtualNetwork -Name VNet1 -ResourceGroupName TestRG1 ` -Location 'East US' -AddressPrefix 10.1.0.0/16 -Subnet $subnet1, $subnet2


To add a gateway subnet to a virtual network you have already created

   Set the variables.
  $vnet = Get-AzVirtualNetwork -ResourceGroupName TestRG1 -Name VNet1

   Create the gateway subnet.
Add-AzVirtualNetworkSubnetConfig -Name 'GatewaySubnet' -AddressPrefix 10.1.255.0/27 -VirtualNetwork $vnet

    Set the configuration.
Set-AzVirtualNetwork -VirtualNetwork $vnet


2. Create the local network gateway

The local network gateway (LNG) typically refers to your on-premises location. It is not the same as a virtual network gateway. You give the site a name by which Azure can refer to it, then specify the IP address of the on-premises VPN device to which you will create a connection. You also specify the IP address prefixes that will be routed through the VPN gateway to the VPN device. The address prefixes you specify are the prefixes located on your on-premises network. If your on-premises network changes, you can easily update the prefixes.

Use the following values:

  • The GatewayIPAddress is the IP address of your on-premises VPN device.
  • The AddressPrefix is your on-premises address space.

To add a local network gateway with a single address prefix:


New-AzLocalNetworkGateway -Name Site1 -ResourceGroupName TestRG1 ` -Location 'East US' -GatewayIpAddress '23.99.221.164' -AddressPrefix '10.101.0.0/24'

To add a local network gateway with multiple address prefixes:

New-AzLocalNetworkGateway -Name Site1 -ResourceGroupName TestRG1 ` -Location 'East US' -GatewayIpAddress '23.99.221.164' -AddressPrefix @('10.101.0.0/24','10.101.1.0/24')

To mdify IP address prefixes for your local network gateway:

Sometimes your local network gateway prefixes change. The steps you take to modify your IP address prefixes depend on whether you have created a VPN gateway connection.

3. Request a Public IP address

A VPN gateway must have a Public IP address. You first request the IP address resource, and then refer to it when creating your virtual network gateway. The IP address is dynamically assigned to the resource when the VPN gateway is created.

VPN Gateway currently only supports Dynamic Public IP address allocation. You cannot request a Static Public IP address assignment. However, this does not mean that the IP address will change after it has been assigned to your VPN gateway. The only time the Public IP address changes is when the gateway is deleted and re-created. It doesn't change across resizing, resetting, or other internal maintenance/upgrades of your VPN gateway.

Request a Public IP address that will be assigned to your virtual network VPN gateway.

$gwpip= New-AzPublicIpAddress -Name VNet1GWPIP -ResourceGroupName TestRG1 -Location 'East US' -AllocationMethod Dynamic

4. Create the gateway IP addressing configuration

The gateway configuration defines the subnet (the 'GatewaySubnet') and the public IP address to use. Use the following example to create your gateway configuration:

$vnet = Get-AzVirtualNetwork -Name VNet1 -ResourceGroupName TestRG1 $subnet = Get-AzVirtualNetworkSubnetConfig -Name 'GatewaySubnet' -VirtualNetwork $vnet $gwipconfig = New-AzVirtualNetworkGatewayIpConfig -Name gwipconfig1 -SubnetId $subnet.Id -PublicIpAddressId $gwpip.Id

5. Create the VPN gateway

Create the virtual network VPN gateway.

Use the following values:

  • The -GatewayType for a Site-to-Site configuration is Vpn. The gateway type is always specific to the configuration that you are implementing. For example, other gateway configurations may require -GatewayType ExpressRoute.
  • The -VpnType can be RouteBased (referred to as a Dynamic Gateway in some documentation), or PolicyBased (referred to as a Static Gateway in some documentation). 
  • Select the Gateway SKU that you want to use. There are configuration limitations for certain SKUs. If you get an error when creating the VPN gateway regarding the -GatewaySku, verify that you have installed the latest version of the PowerShell cmdlets
New-AzVirtualNetworkGateway -Name VNet1GW -ResourceGroupName TestRG1 ` -Location 'East US' -IpConfigurations $gwipconfig -GatewayType Vpn ` -VpnType RouteBased -GatewaySku VpnGw1

6. Configure your VPN device

Site-to-Site connections to an on-premises network require a VPN device. In this step, you configure your VPN device. When configuring your VPN device, you need the following items:

  • A shared key. This is the same shared key that you specify when creating your Site-to-Site VPN connection. In our examples, we use a basic shared key. We recommend that you generate a more complex key to use.

  • The Public IP address of your virtual network gateway. You can view the public IP address by using the Azure portal, PowerShell, or CLI. To find the Public IP address of your virtual network gateway using PowerShell, use the following example. In this example, VNet1GWPIP is the name of the public IP address resource that you created in an earlier step.

Get-AzPublicIpAddress -Name VNet1GWPIP -ResourceGroupName TestRG1

7. Create the VPN connection

Next, create the Site-to-Site VPN connection between your virtual network gateway and your VPN device. Be sure to replace the values with your own. The shared key must match the value you used for your VPN device configuration. Notice that the '-ConnectionType' for Site-to-Site is IPsec.

Set the variables.
$gateway1 = Get-AzVirtualNetworkGateway -Name VNet1GW -ResourceGroupName TestRG1 $local = Get-AzLocalNetworkGateway -Name Site1 -ResourceGroupName TestRG1

Create the connection.
New-AzVirtualNetworkGatewayConnection -Name VNet1toSite1 -ResourceGroupName TestRG1 ` -Location 'East US' -VirtualNetworkGateway1 $gateway1 -LocalNetworkGateway2 $local ` -ConnectionType IPsec -RoutingWeight 10 -SharedKey 'abc123'

8. Verify the VPN connection

There are a few different ways to verify your VPN connection.

You can verify that your connection succeeded by using the 'Get-AzVirtualNetworkGatewayConnection' cmdlet, with or without '-Debug'.

  1. Use the following cmdlet example, configuring the values to match your own. If prompted, select 'A' in order to run 'All'. In the example, '-Name' refers to the name of the connection that you want to test. :-  Get-AzVirtualNetworkGatewayConnection -Name VNet1toSite1 -ResourceGroupName TestRG1

  2. After the cmdlet has finished, view the values. In the example below, the connection status shows as 'Connected' and you can see ingress and egress bytes. "connectionStatus": "Connected", "ingressBytesTransferred": 33509044, "egressBytesTransferred": 4142431

To connect to a virtual machine

You can connect to a VM that is deployed to your VNet by creating a Remote Desktop Connection to your VM. The best way to initially verify that you can connect to your VM is to connect by using its private IP address, rather than computer name. That way, you are testing to see if you can connect, not whether name resolution is configured properly.

  1. Locate the private IP address. You can find the private IP address of a VM by either looking at the properties for the VM in the Azure portal, or by using PowerShell.

    • Azure portal - Locate your virtual machine in the Azure portal. View the properties for the VM. The private IP address is listed.

    • PowerShell - Use the example to view a list of VMs and private IP addresses from your resource groups. You don't need to modify this example before using it.

    • $VMs = Get-AzVM $Nics = Get-AzNetworkInterface | Where VirtualMachine -ne $null foreach($Nic in $Nics) { $VM = $VMs | Where-Object -Property Id -eq $Nic.VirtualMachine.Id $Prv = $Nic.IpConfigurations | Select-Object -ExpandProperty PrivateIpAddress $Alloc = $Nic.IpConfigurations | Select-Object -ExpandProperty PrivateIpAllocationMethod Write-Output "$($VM.Name): $Prv,$Alloc" }

  2. Verify that you are connected to your VNet using the Point-to-Site VPN connection.

  3. Open Remote Desktop Connection by typing "RDP" or "Remote Desktop Connection" in the search box on the taskbar, then select Remote Desktop Connection. You can also open Remote Desktop Connection using the 'mstsc' command in PowerShell.

  4. In Remote Desktop Connection, enter the private IP address of the VM. You can click "Show Options" to adjust additional settings, then connect.

  5. Troubleshoot a connection

    If you are having trouble connecting to a virtual machine over your VPN connection, check the following:

    • Verify that your VPN connection is successful.

    • Verify that you are connecting to the private IP address for the VM.

    • If you can connect to the VM using the private IP address, but not the computer name, verify that you have configured DNS properly

To modify IP address prefixes for a local network gateway

If the IP address prefixes that you want routed to your on-premises location change, you can modify the local network gateway. When using these examples, modify the values to match your environment.

To add additional address prefixes:

  1. Set the variable for the LocalNetworkGateway. $local = Get-AzLocalNetworkGateway -Name Site1 -ResourceGroupName TestRG1

  2. Set the gateway with the updated prefixes.  Set-AzLocalNetworkGateway -LocalNetworkGateway $local `

    -AddressPrefix @('10.101.0.0/24','10.101.1.0/24')

To modify the gateway IP address for a local network gateway

If the VPN device that you want to connect to has changed its public IP address, you need to modify the local network gateway to reflect that change. When modifying this value, you can also modify the address prefixes at the same time. Be sure to use the existing name of your local network gateway in order to overwrite the current settings. If you use a different name, you create a new local network gateway, instead of overwriting the existing one.

New-AzLocalNetworkGateway -Name Site1 ` -Location "East US" -AddressPrefix @('10.101.0.0/24','10.101.1.0/24') ` -GatewayIpAddress "5.4.3.2" -ResourceGroupName TestRG1


To delete a gateway connection

If you don't know the name of your connection, you can find it by using the 'Get-AzVirtualNetworkGatewayConnection' cmdlet.

Remove-AzVirtualNetworkGatewayConnection -Name VNet1toSite1 ` -ResourceGroupName TestRG1