Showing posts with label Powershell. Show all posts
Showing posts with label Powershell. Show all posts

Friday, December 22, 2023

Add resource locks to individual records in a private DNS zone

 It is possible to add resource locks to individual records in private DNS zones. A scenario for this could be a critical or central A record that you don't want to be changed by mistake while still allowing for ongoing updates to the private DNS zone as part of daily operations.

If you have a centralized private DNS zone setup with Azure policy handling the DNS record creation and you also use private endpoints (PE), then there is a (perhaps small) risk that A records can be overwritten. This is the case if someone creates a new PE and associates with the same resource. The DeployIfNotExist policy will run on PE creation and replace the existing record and so that the PaaS service will resolve to a new local IP (note that if you delete the new PE again, the A record will also be deleted and the original PE will no longer have an A record and so will have to be recreated or the A record re-added).

Adding locks to individual records is described in further detail here. Note that this can currently only be done using PowerShell and can't be done via the Azure portal.

The example from MSFT looks like below:


An actual example is shown below:

# Lock a DNS record set

$lvl = "ReadOnly"

$lnm = "dontChangeMe"

$rsc = "privatelink.blob.core.windows.net/testaccountdelete001"

$rty = "Microsoft.Network/privateDNSZones/A"

$rsg = "rg-dns-conn-001"

 

New-AzResourceLock -LockLevel $lvl -LockName $lnm -ResourceName $rsc -ResourceType $rty -ResourceGroupName $rsg

Note that the MSFT example uses a regular DNS zone whereas my example uses private DNS zones (marked in bold above).

See example below for when lock is applied:


Once applied, you can see (and edit and delete) the lock in the portal under the private DNS zone -> "you're private DNS zone, e.g. for blob" -> Locks, see below:



The reason that the lock type is set to ReadOnly and not CannotDelete is that the latter option will  allow the records to be overwritten which we don't want.


Friday, June 16, 2023

Installing VS Code, PowerShell, Azure PowerShell, and AZ CLI on macOS

 It's relatively simple to get these tools installed on a Mac so you can start working with Azure and ARM templates via code.

This article just collects the relevant information and puts it in order:

Visual Studio Code

This can be installed as a regular app in macOS, follow the link:

https://code.visualstudio.com/docs/setup/mac 


Homebrew


Homebrew is a package manager for macOS and Microsoft's recommended way af installing PowerShell and other tools.


https://learn.microsoft.com/en-us/powershell/scripting/install/installing-powershell-on-macos?view=powershell-7.3


The commands to run for Homebrew are:


/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"


When Homebrew has been installed, it will ask you to run two additional commands (to add Homebrew to you PATH), these are:


(echo; echo 'eval "$(/opt/homebrew/bin/brew shellenv)"') >> /Users/<REPLACE WITH USER>/.zprofile


eval "$(/opt/homebrew/bin/brew shellenv)"


PowerShell


To install PowerShell follow the same link as above:


Or run the following commands:

brew install --cask powershell

And to run PowerShell from the terminal:

pwsh

Azure PowerShell

To install Azure PowerShell, follow this link:


Or run this command:

Install-Module -Name Az -Repository PSGallery -Force

This will give you the Azure related commands such as:

Connect-AzAccount, Get-AzContext, Set-AzContext, etc 


AZ CLI


To install, follow this link:


https://learn.microsoft.com/en-us/cli/azure/install-azure-cli-macos


Or run:

brew update && brew install azure-cli

This gives you all the AZ commands. A separate Az login is required to use the Az commands in Azure.

Terraform

To install, see link or run below two commands:


brew tap hashicorp/tap

brew install hashicorp/tap/terraform



Friday, February 3, 2023

PowerShell and Az CLI commands to deploy ARM templates

 This is just a quick note on the PowerShell command to deploy ARM templates.

Command should be run from the location where the ARM templates are located (or update the file path).

New-AzResourceGroupDeployment -Name deploy_some_storage_account -ResourceGroupName rg-some_resource_group-001 `

  -TemplateFile .\deploy_storage_account.json `

  -TemplateParameterFile .\deploy_storage_account.parameters.json

There is another example here for deploying a key vault.

And here's link to the Microsoft documentation.

For Az CLI the command format is:

az deployment group create --resource-group <resource-group-name> --template-file <path-to-bicep>

Friday, October 9, 2020

Join a VM to an active directory domain in Azure with PowerShell

 At current client we have a hybrid setup with an on-prem datacenter and VPN connections to Azure. The on-prem active directory has been extended to Azure with an additional two domain controllers (classic active directory).

We have a generic virtual machine deployment template in PowerShell and want to be able to have VMs automatically join the domain as part of the deployment process.

A first learning is to make sure that the IP addresses of the DC's are specified as custom DNS servers on the VNets where they reside (assuming they also function as DNS servers). Otherwise, the VMs won't be able to resolve the domain (VNet -> DNS servers -> Custom).

Up front we have verified that a VM can be manually joined to the domain from the VM itself.

The PowerShell command for setting the domain is: Set-AzVMADDomainExtension

The MS documentation is not very thoroughly described for this command, unfortunately.

We got pretty far using this guide instead.

When using that example and trying jo join, the PowerShell script kept hanging and timing out. From the VM itself in the event log, it just stated NetJoin action failed. But no helpful error description.

We had to adjust two things to make it work:

1. For the JoinOption parameter, instead of using 0x00000001, we used 0x00000003 (which is similar to setting 0x00000001 and 0x00000002). This specifies joining a domain instead only a workgroup (option 1) and option 2 creates an account on the domain.

2. By using the Invoke-AzVMRunCommand command we set the DNS suffix from inside the VM using PowerShell before running the domain join command.

This works in our setup. The code examples can be seen below (first script calls the second script). It can be added to an existing VM deployment script or be run as a standalone script post VM install.

Join domain

# Update variables
$VMName = "XXVMname"
$ResourceGroupName = "XX-RGname"

# Do not update these variables
$DomainName = "XXdomainname.local"
$ServiceAcct = "XXdomainname\XXserviceaccountname"
$secretnameDomain = "XXnameofsecretinKeyVault"
$JoinOpt = "0x00000003" # specifies the options to join a domain, 0x00000001 + 0x00000002
$OU = "OU=XX,OU=XX,DC=XX,DC=Local" # Update string with corrrect OU path (not a requirement)
$kvname = "XXnameofKeyVault"
$LocationName = "westeurope"
$ScriptPathDNSsuffix = ".\SetDnsSuffixInVM.ps1"

Write-Host "Set DNS suffix in VM. $(Get-Date)"
# Set DNS suffix in VM (for domain join to work)
Invoke-AzVMRunCommand -ResourceGroupName $ResourceGroupName `
 -VMName $VMName `
 -CommandId 'RunPowerShellScript' `
 -ScriptPath $ScriptPathDNSsuffix

# Get service account password from key vault
$ServiceAcctPassword = (Get-AzKeyVaultSecret -vaultName $kvname -name $secretnameDomain).SecretValueText | ConvertTo-SecureString -AsPlainText -Force
$Credential = New-Object System.Management.Automation.PSCredential ($ServiceAcct, $ServiceAcctPassword);

Write-Host "Joining domain $DomainName. $(Get-Date)"
Set-AzVMADDomainExtension -DomainName $DomainName `
 -VMName $VMName `
 -ResourceGroupName $ResourceGroupName `
 -Location $LocationName `
 -Credential $Credential `
 -OUPath $OU `
 -JoinOption $JoinOpt `
 -Restart `
 -Verbose
Write-Host "Script done at $(Get-Date)"

Set DNS Suffix in VM (SetDnsSuffixInVM.ps1)

$DnsSuffix = "XXDomainname.local"

$interfacealias = get-dnsclient | Where-Object {$_.InterfaceAlias -eq "Ethernet"}
set-dnsclient -Interfaceindex $interfacealias.Interfaceindex `
-ConnectionSpecificSuffix $DnsSuffix `
-RegisterThisConnectionsAddress $True


Thursday, October 1, 2020

Azure: Allowing Windows Server to activate via KMS through Azure Firewall

 At current client we have an Azure Firewall installed. And only outbound traffic on ports 80 and 443 is allowed. Today we found that Windows Servers do not activate (we're buying the licenses per Windows Server). 

The reason for this is that the VMs can't reach the KMS server for Azure Global cloud:

Azure Global KMS: kms.core.windows.net  - IP: 23.102.135.246 on port 1688. See here for more info. 

(I found a general activation troubleshooting guide here where they recommend testing with PsPing. I didn't get around to trying that, but it might be useful.)

I tried adding a network rule in the Azure Firewall using the FQDN, kms.core.windows.net. That failed.

But adding a rule using the IP address in stead worked fine (and that looks to be 'allowed' as well by MS).

The following rule was added in Azure Firewall via PowerShell:

 # Allow VMs to reach kms.core.windows.net for Windows Server activation
 $NetRule2 = New-AzFirewallNetworkRule -Name "allow-kms" -Protocol TCP,UDP -SourceAddress `
  "10.1.1.0/24", `
  "10.1.2.0/24" `
 -DestinationAddress "23.102.135.246" -DestinationPort "1688"

And remember to add the rule variable as well to the New-AzFirewallNetworkRuleCollection cmdlet:

$NetRuleCollection = New-AzFirewallNetworkRuleCollection -Name 'fw-rule-collection' -Priority 200 `
   -Rule $NetRule1,$NetRule2 -ActionType "Allow"

When done, I RDP'ed to a VM and went to activation. It wasn't activated. I clicked on troubleshoot and the VM activated. Likely after a while all VMs will activate automatically.




Azure: Create an availability set with two VMs with PowerShell

If you have two or more virtual machines in Azure running in a pair or a cluster (for example domain controllers), you want to make sure that the proper redundancy is in place.

There are two ways to go about this. One is to place the VMs in different availability zones (different datacenters in the region) and the other is availability sets which separate VMs on different hardware and in different maintenance groups - within the same physical datacenter.

An availability set is the combination of a fault domain (which is separate physical hardware within a given datacenter) and an update domain (specifies logical groups of hardware to avoid downtime during planned or unplanned MS maintenance, se here).

Availability set

The order in which you create the availability set is the following:
  • First you create the availability set
  • Then you create the individual VMs - and the important part is that the availability set has to be specified/set during VM creation using a parameter (AvailabilitySetName). If the VM has already been created without this parameter, then it cannot be added to the availability set later
If you are creating the VMs in PowerShell from scratch an not using the "New-AzVMConfig" cmdlet to specify VM settings in your script, then you can follow this MS guide. However, if you're using "New-AzVMConfig" then it has to be done slightly differently.

Create availability set

# Variables

$ResourceGroupName = "myRG"
$LocationName = "westeurope"
$AvailSetName = "AvailabilitySetAD01"

New-AzAvailabilitySet `
   -Location $LocationName `
   -Name $AvailSetName `
   -ResourceGroupName $ResourceGroupName `
   -Sku aligned `
   -PlatformFaultDomainCount 2 `
   -PlatformUpdateDomainCount 2

This creates the availability set with two fault domains and two update domains. In West Europe you can have up to three fault domains.

To create the VMs, make sure that the following lines are set in the script (copy/paste the snippet to get all the code):

$AvailSetName = "AvailabilitySetAD01"
# Get the availability set for domain controllers
$AvailSet = Get-AzAvailabilitySet -ResourceGroupName $ResourceGroupName -AvailabilitySetName $AvailSetName
# Create new VM config object and add it to the availability set
$VirtualMachine = New-AzVMConfig -VMName $VMName -VMSize $VMSize -AvailabilitySetID $AvailSet.Id

An example of a full VM script including the above three lines can be seen below. If using this in its entirety, make sure that the resource groups, key vault, and storage group are created in advance (or not use the specific parts about key vault and boot diagnostics).


# Update these variables:
# Update to correct RG name
$ResourceGroupName = "ad-RG"
$Vnetrgname = "vnet-RG"
$rgLogmon = "logmon-RG"
$secrgname  = "sec-RG"

$ComputerName = "myServer01" # Change this!
$VMName = "myServer01" # Change this!
$VMSize = "Standard_B2s"
$Vnetname = "MYvnet"
$SubnetName = "MyZone01"
$Disksize = "128"
$OSDiskName = $($VMName) + '-disk01'
$Publisher = "MicrosoftWindowsServer"
$Offer = "WindowsServer"
$Sku = "2019-Datacenter"
$DiskType = "StandardSSD_LRS"
$PrivateIP = "192.168.1.10" # Change this!
$stgaccountname = "myStorageAccount"
$kvname = "MyKV"
$secretname = "localadmpwd"
$AvailSetName = "AvailabilitySetAD01"

# Do not update these variables
$VMLocalAdminUser = "localadmin"
# Will prompt for password during deploy
#$VMLocalAdminSecurePassword = ConvertTo-SecureString  -AsPlainText -Force
# Will get password from text file
#$VMLocalAdminSecurePassword = Get-Content ./vmos-sec-key.txt | ConvertTo-SecureString -AsPlainText -Force
# Will retrieve passwd from key vault
$VMLocalAdminSecurePassword = (Get-AzKeyVaultSecret -vaultName $kvname -name $secretname).SecretValueText | ConvertTo-SecureString -AsPlainText -Force
$LocationName = "westeurope"
$NICName = $($VMName) + '-nic01'
$OSDiskName = $($VMName) + '-OsDisk01'

Write-Host "Creating variables at $(Get-Date)"
# Get existing Vnet
$Vnet = Get-AzVirtualNetwork -Name $Vnetname -ResourceGroupName $Vnetrgname
# Get existing subnet
$Subnet = Get-AzVirtualNetworkSubnetConfig -Name $SubnetName -VirtualNetwork $Vnet
# Set static private IP address
$IPconfig = New-AzNetworkInterfaceIpConfig -Name "IPConfig1" -PrivateIpAddressVersion IPv4 -PrivateIpAddress $PrivateIP -SubnetId $Subnet.Id
# Create a new NIC for the VM and associate the private IP
$NIC = New-AzNetworkInterface -Name $NICName -ResourceGroupName $ResourceGroupName -Location $LocationName -IpConfiguration $IPconfig -Force

# Create credentials object
$Credential = New-Object System.Management.Automation.PSCredential ($VMLocalAdminUser$VMLocalAdminSecurePassword);
# Get the availability set for domain controllers
$AvailSet = Get-AzAvailabilitySet -ResourceGroupName $ResourceGroupName -AvailabilitySetName $AvailSetName
# Create new VM config object and add it to the availability set
$VirtualMachine = New-AzVMConfig -VMName $VMName -VMSize $VMSize -AvailabilitySetID $AvailSet.Id
# Set OS type and OS name and add to VM config object
$VirtualMachine = Set-AzVMOperatingSystem -VM $VirtualMachine -Windows -ComputerName $ComputerName -Credential $Credential -ProvisionVMAgent -EnableAutoUpdate
# Associate the NIC with the VM config object
$VirtualMachine = Add-AzVMNetworkInterface -VM $VirtualMachine -Id $NIC.Id
# Specify OS type for the VM config object
$VirtualMachine = Set-AzVMSourceImage -VM $VirtualMachine -PublisherName $Publisher -Offer $Offer -Skus $Sku -Version latest
# Set disk size in GB
$VirtualMachine = Set-AzVMOSDisk -VM $VirtualMachine -DiskSizeInGB $Disksize -Name $OSDiskName -StorageAccountType $DiskType -CreateOption FromImage
# Set storage account for boot diagnostics (udpate line below)
$VirtualMachine = Set-AzVMBootDiagnostic -VM $VirtualMachine -Enable -ResourceGroupName $rgLogmon -StorageAccountName $stgaccountname

Write-Host "Creating new VM...(this can take 10+ minutes). Starting at $(Get-Date)"
# Create the VM using VM config object 
New-AzVM -ResourceGroupName $ResourceGroupName -Location $LocationName -VM $VirtualMachine -Verbose
Write-Host "VM created"
  
Write-Host
Write-Host "Script done at $(Get-Date)"
Write-Host

When done, it will look like below in the portal:



Availability zones

In regions that support availability zones (e.g. West Europe), there can be up to three logical zones - named 1, 2, and 3 that each represent one physical datacenter (Microsoft states that a zone may be more than one DC but does not promise this, so we assume a zone is one DC).


Zone numbering is only consistent within a subscription, so you cannot rely on e.g. Zone 1 being the same physical location if deploying in different subscriptions.

According to MS documentation, there are two types of availability zones services:

  • Zonal services – where a resource is pinned to a specific zone (for example, virtual machines, managed disks, Standard IP addresses), or
  • Zone-redundant services – when the Azure platform replicates automatically across zones (for example, zone-redundant storage, SQL Database).

So for VMs one can pin or specify a zone for a VM using zonal services. This has to be done during deployment and cannot be change or updated after deploy. If nothing is specified, the Zone value will be empty you will not be in control of or be able to view zone placement.

If deploying with PowerShell, the '-Zone' parameter has to be used with a value of 1, 2, or 3. See example below:

# Create a virtual machine configuration

$vmConfig = New-AzVMConfig -VMName myVM -VMSize Standard_DS1_v2 -Zone 2 | `

    Set-AzVMOperatingSystem -Windows -ComputerName myVM -Credential $cred | `

    Set-AzVMSourceImage -PublisherName MicrosoftWindowsServer -Offer WindowsServer `

    -Skus 2016-Datacenter -Version latest | Add-AzVMNetworkInterface -Id $nic.Id


To add a managed disk to a specific zone, the same same -Zone parameter should be used, se here.

If deploying via the portal there is a redundancy option where you choose availability zone and zone number, see below:




It should be noted that there is a cost associated with datatransfer in and out of zones. But placing a VM in a zone does not have a cost on its own.

Tuesday, September 29, 2020

Azure: Encrypting VM disks with Powershell using Azure key vault

 Encrypting disks in Azure for virtual machines can be a good idea if you have sensitive data on them. At current client the decision is to encrypt disks for domain controllers but not for general purpose VMs (as it adds a bit of administrative overhead and might impact performance - I don't have specific numbers on this).

If you have a key vault in place with the -EnabledForDiskEncryption parameter set it is relatively easy to configure on the VM. The VM has to be already running so it is a post step after install.

From the VM deploy script you can add the below code snippet to your script:

# Encrypt VM disks (should only be done for AD VMs and VMs with highly sensitive data)
Write-host "Checking if disks are encrypted on VM"

# Get key vault
$KeyVault = Get-AzKeyVault -VaultName $kvname -ResourceGroupName $secrgname

# Check if disk already encrypted, if not then encrypt it
if (Get-AzVmDiskEncryptionStatus -VMName $VMName -ResourceGroupName $ResourceGroupName | Where-Object {$_.OsVolumeEncrypted -eq "Encrypted"}){
    Write-host "Disk already encrypted"
}
else {
    Write-host "Encrypting disks"
    Set-AzVMDiskEncryptionExtension -ResourceGroupName $ResourceGroupName `
     -VMName $VMName `
     -DiskEncryptionKeyVaultUrl $KeyVault.VaultUri `
     -DiskEncryptionKeyVaultId $KeyVault.ResourceId `
     -Force

Variables:

  • $kvname: Name of the key vault
  • $secrgname: Name of the resource group where key vault resides
  • $VMName: Name of the VM
  • ResourceGroupName: Name of resource group where VM resides
Assuming you have the correct permissions set on the key vault, then the secret will be created automatically in the key vault. During the encrypt process the VM will reboot and it takes about 10 minutes depending on the size of the disks.





Wednesday, September 23, 2020

Azure: Delete tags on resource groups and resources with Powershell

 At current client we've been pushing out standard tags via Azure Policy to both resource groups and resources. One policy adds tags to the resource groups and another poicy inherits the tags from the resource groups to the resources (to only have to update tags in one place).

After some evaluation we found that we'd pushed too many tags and needed to delete some of them from some of the subscriptions.

There is no easy way to do this in bulk from the portal but it can be done with Powershell.

The logical command to use would be Remove-AzTag but apparently that is only for unused tags and so it won't work if you've added values to your tags.

To delete tags with values added to them, you need two different scripts. One for resource groups and one for the resources.

If you have an 'inherit tags' policy enabled that force changes on updates, then make sure to delete first the tags on the resource groups and then on the resources. Otherwise the tags will be re-written to the resources immediately on update.

Both scripts below will traverse all or selected subscriptions and delete tags.

DeleteTagsOnRGs.ps1

# This script will delete the specified tag including values only on resources groups.

# Update this variable with tag name to be deleted. No tag value required.
$DeleteTag = "ContactEmail"

# Get all subscriptions in tenant
# $subscriptions = Get-AzSubscription
# To get all subscriptions except subscription named: SUBS NAME
# Replace -notlike with -eq to get a specific subscription
$subscriptions = Get-AzSubscription | Where-Object {$_.Name -notlike "SUBS NAME"}

# Traverse through all subscriptions
Foreach ($subscription in $subscriptions ) {

# Select a subscription    
Select-AzSubscription -subscriptionid $subscription

# Get list of resource groups in subscription
$rg = Get-AzResourceGroup
# For each resource group, get the associated tags and put into a variable
Foreach ($i in $rg.ResourceGroupName)
{
 $Tags = (Get-AzResourceGroup -Name $i).Tags
 # Remove the tag with the Name specified
 $Tags.Remove($DeleteTag)
 # Set the tags on the resource group
 Set-AzResourceGroup -Name $i -Tag $Tags
}

}

DeleteTagsOnResources.ps1

# This script will delete tags on all resources in all subscriptions, 
# however not on the resource groups, see DeleteTagsOnRGs.ps1 for that.
# Must run as .ps1 script, pasting into Cloud Shell will not work.
# Note, there can be a delay of 20-30 mins from running script until Tags appear 
# as deleted in the Portal
# Before running this script, ensure that tags are deleted at RG level first 
# otherwise they'll be re-added via the Inherit policy (if applied)

# To get all subscriptions
# $subs = Get-AzSubscription
# Get only a specific subscription
# $subs = Get-AzSubscription | Where-Object {$_.Name -eq "SUBS NAME"}
# To get all subscriptions except SUBS NAME
$subs = Get-AzSubscription | Where-Object {$_.Name -notlike "SUBS NAME"}

# Specify tag name
$tagname = "ContactEmail"
# Specify tag value
$tagvalue = "person@companyemail.com"

# Through all subscriptions, get resources with specified tag and value, 
# remove the tag from the array and update the resource
$subs | ForEach-Object {
    Set-AzContext $_
    $rs = Get-AzResource -TagName $tagname -TagValue $tagvalue
    $rs | ForEach-Object {
        $_.Tags.Remove($tagname)
        $_ | Set-AzResource -Force
    }  
}

That's it.

Saturday, April 11, 2009

Draw a nice Visio digram from your VC using Powershell

If you have been drawing infrastructure diagrams in Visio of your company setup, you know how cumbersome it can be - especially as the infrastructure changes often. In stead of manually changing your Visio drawings, here's a new tool, that can depict an exact copy of your Virtual Center (now vCenter) or a given cluster - or from a given host - in Visio.

You need to have Powershell and VI Toolkit installed to run script. See here for installation instructions.

1. Go to Virtu-al for further instructions. Download the vDiagram.zip file.
2. Once extracted copy the 'My-VI-Shapes.vss' file to your 'My Documents\My Shapes' folder. If the folder does not exist create it and copy the file in.
3. Run the powershell script (Start-> VMware VI Toolkit -> VMware VI Toolkit ) with the following options:
To diagram the entire Infrastructure:
vDiagram.ps1 -VIServer MYVISERVER or HOST
To diagram a specific cluster use the following:
vDiagram.ps1 -VIServer MYVISERVER -Cluster "Production Cluster"

Friday, April 10, 2009

Quick guide to installing Powershell, VI Toolkit, and Powergui

If you want to try to administer VMware infrastructure with Powershell, there are a number of applications that you need to install. Furthermore, if you want to have a GUI based interface, then Powergui is a strong tool in combination with their VMware plugin.

If it's you first time trying it out it can be a little tiring to figure out the order in which the apps are to be installed, so here's a quick getting started guide:

1. Install Microsoft Powershell. Link can be found at MS site. If you're running WinXP, look for "Windows Management Framework Core (WinRM 2.0 and Windows PowerShell 2.0)"

2. Install the VI Toolkit 1.5 (for Windows), use the same link as above. If you receive a warning related to Powershell execution policy, then openPowershell from Start -> Programs and run the following command:

Set-ExecutionPolicy remotesigned

3. Go to Powergui.org and install Powergui. During installation, choose to install the VI Client plugin.

4. Install the Powergui VMware Powerpack, click here. Look for the XML file, VMware.VIToolkit.powerpack. Download file. Open Powergui. Right click root note and choose import. Import the .xml you just downloaded. Done.

5. To add a host or a VC server, open Powergui, expand the VMware folder, choose 'Managed host', and choose 'Add connection' in the menu to the right. This will give you a nice recognisable view like the one from the VI client.