Certificate Services operations fail with error 0×80070057

While implementing a two-tier PKI I ran into the issue that certutil.exe -crl, and PowerShell cmdlets such as Get-CACrlDistributionPoint would fail on the Subordinate Domain CA with a generic error which made finding a solution very difficult:

PS C:\Windows\system32> Get-CACrlDistributionPoint
Get-CACrlDistributionPoint : CCertAdmin::GetConfigEntry: The parameter is incorrect. 0x80070057 (WIN32:
ERROR_INVALID_PARAMETER)
At line:1 char:1
+ Get-CACrlDistributionPoint
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-CACrlDistributionPoint], ArgumentException
+ FullyQualifiedErrorId : System.ArgumentException,Microsoft.CertificateServices.Administration.Comm
DistributionPointCommand

PS C:\Windows\system32> certutil -crl
CertUtil: -CRL command FAILED: 0x80070057 (WIN32: 87 ERROR_INVALID_PARAMETER)
CertUtil: The parameter is incorrect.
PS C:\Windows\system32>

I had started off by following this guide on Technet Blogs:

http://blogs.technet.com/b/yungchou/archive/2013/10/21/enterprise-pki-with-windows-server-2012-r2-active-directory-certificate-services-part-1-of-2.aspx

Not long after proceeding I realised that I needed to alter certain aspects of the way it was configured. I started again and continued to use the same CA server hostnames but with new CA names, this time preferring to follow this guide by Derek Seaman:

http://www.derekseaman.com/2014/01/windows-server-2012-r2-two-tier-pki-ca-pt-1.html

However I encountered the errors with the subordinate CA refusing to run the PowerShell cmdlets relating to the Certificate Authority. The errors were also encountered by commenter “Per” on Derek’s blog post, and similarly reported in the comments on the Windows Server 2012 R2 Active Directory Certificate Services Microsoft Test Lab page:

http://technet.microsoft.com/en-us/library/hh831348.aspx

There is a Microsoft KB referencing the same error at the time of creating the subordinate CA. The article implicates permissions, however this is a red herring.

It took a lot of trial and error, but eventually I did resolve this issue thanks to some pointers in a Microsoft Directory Services Team Blog post on troubleshooting Certificate Enrollment. I determined the root cause – several superfluous entries in Active Directory for an aborted CA installation. I needed to delete these with ADSIEdit, though I have subsequently discovered that you can also use the AD Sites and Services MMC snap-in to do this (at parent, View > Show Services Node). When I first attempted to set up the CAs I had been using the standard auto-generated names because I had thought that not doing so might invite trouble later on – so my subordinate domain CA had published itself to Active Directory at CN=Enrollment Services,CN=Public Key Services,CN=Services using the name domain-HOSTNAME-CA.

I had thought this entry was sane when I was looking back over the ADSIEdit output while investigating the problem – because I know it formats the cert request using this notation. Then I remembered that I had not used this CA name in my subsequent CA installation attempt. I removed this old name entry from Active Directory and it immediately fixed the issue. I guess because although it was for a different CA installation attempt, crucially it shared the same server hostname, hence the problem when PowerShell was invoking Certificate Services to query the Directory Service.

Following this, I then pruned similar superfluous records for the same abortive CA installation attempt which were located at:
CN=KRA,CN=Public Key Services,CN=Services
CN=AIA,CN=Public Key Services,CN=Services
CN=MY_CA_HOSTNAME,CN=CDP,CN=Public Key Services,CN=Services

Cross-compiling nano with UTF-8 support for Synology

export CROSS_PREFIX=i686-pc-linux-gnu
export TARGET=i686-pc-linux-gnu
export TOOLCHAIN=/usr/local/evansport-pc-linux-gnu
export AR=${TOOLCHAIN}/bin/${CROSS_PREFIX}-ar
export AS=${TOOLCHAIN}/bin/${CROSS_PREFIX}-as
export CC=${TOOLCHAIN}/bin/${CROSS_PREFIX}-gcc
export CXX=${TOOLCHAIN}/bin/${CROSS_PREFIX}-g++
export LD=${TOOLCHAIN}/bin/${CROSS_PREFIX}-ld
export LDSHARED="${TOOLCHAIN}/bin/${CROSS_PREFIX}-gcc -shared "
export RANLIB=${TOOLCHAIN}/bin/${CROSS_PREFIX}-ranlib
export CFLAGS="-I${TOOLCHAIN}/include -O3 ${MARCH}"
export LDFLAGS="-L${TOOLCHAIN}/lib"
export PKG_CONFIG_PATH="${TOOLCHAIN}/lib/pkgconfig"

#DSM 5.0 already includes libncursesw so we can link the nano binary to this
#fetch the source which was extracted from the Synology DSM 5.0 source tarball
wget https://dl.dropboxusercontent.com/u/1188556/ncurses-5.x.zip
unzip ncurses-5.x.zip
cd ncurses-5.x
./configure --prefix=${TOOLCHAIN} --host=${TARGET} --build=x86_64-linux-gnu --with-shared --without-normal --without-progs --without-debug --enable-widec
make
make install
cd ..
wget http://www.nano-editor.org/dist/v2.2/nano-2.2.6.tar.gz
tar xvzf nano-2.2.6.tar.gz
cd nano-2.2.6
#src/nano.h:92:20: fatal error: curses.h: No such file or directory
#http://blog.csdn.net/alienspy/article/details/24135761
wget http://dl.dropboxusercontent.com/u/1188556/nano.h.patch
patch nano.h < nano.h.patch
CFLAGS="${CFLAGS} -I${TOOLCHAIN}/include/ncurses" ./configure --prefix=${TOOLCHAIN} --host=${TARGET} --build=x86_64-linux-gnu --enable-utf8 --disable-nls --enable-color --enable-extra --enable-multibuffer --enable-nanorc
#sudo apt-get install texinfo
sed -i -e "s%^CPPFLAGS = -I/usr/include/ncursesw%CPPFLAGS = -I${TOOLCHAIN}/include/ncurses%" Makefile
sed -i -e "s%^CPPFLAGS = -I/usr/include/ncursesw%CPPFLAGS = -I${TOOLCHAIN}/include/ncurses%" src/Makefile
make
make install
#now install it to /usr/local/bin
 

nano.h.patch

--- src/nano.h.old      2014-09-17 12:16:15.006206100 +0100
+++ src/nano.h  2014-09-17 12:19:01.226206100 +0100
@@ -86,10 +86,10 @@
 #define KEY_IC SL_KEY_IC
 /* Ncurses support. */
 #elif defined(HAVE_NCURSES_H)
-#include <ncurses.h>
+#include <ncursesw/ncurses.h>
 #else
 /* Curses support. */
-#include <curses.h>
+#include <ncursesw/curses.h>
 #endif /* CURSES_H */

 #ifdef ENABLE_NLS
 

~/.nanorc

##############################################################################
#
# Syntax highlighting for XML files
#
# Author:  Josef 'Jupp' Schugt, jupp(a)rubyforge.org
# License: GPL 2  or later
#
# Version: 2004-02-25
#
##############################################################################
syntax "ml" ".*\.([jrs]?html?|xml|sgml?)$"
color white "^.+$"
color green  start="<" end=">"
color cyan   "<[^> ]+"
color cyan   ">"
color yellow start="<!DOCTYPE" end="[/]?>"
color yellow start="<!--" end="-->"
color red    "&[^;]*;"

##############################################################################
#
# Syntax highlighting for HTTP codes
#
# Author:  Josef 'Jupp' Schugt, jupp(a)rubyforge.org
# License: GPL 2  or later
#
# Version: 2004-02-25
#
##############################################################################
syntax "urls"
color brightmagenta   "^.*$"
color cyan      "^(1[0-9][0-9]|20[256]|30[45]).*$"
color green      "^20[03].*$"
color brightyellow   "^(201|30[0-37]).*$"
color brightred      "^(204|[45][0-9][0-9]|666).*$"

##############################################################################
#
# Syntax highlighting for CSS files
#
# Author:  Simon Rupf, simon.rupf(a)int-ag.ch
# License: GPL 2  or later
#
# Version: 2005-02-14
#
##############################################################################
syntax "css" "\.css$"
color brightred     "."
color brightyellow  start="\{" end="\}"
color brightwhite           start=":" end="[;^\{]"
color brightblue    ":active|:focus|:hover|:link|:visited|:link|:after|:before|$"
color brightblue    start="\/\*" end="\\*/"
color green         ";|:|\{|\}"

syntax "sh" "\.sh$"
#icolor brightgreen "^[0-9A-Z_]+\(\)"
#color green "\b(case|do|done|elif|else|esac|exit|fi|for|function|if|in|local|read|return|select|shift|then|time|until|while)\b"
#color green "(\{|\}|\(|\)|\;|\]|\[|`|\\|\$|<|>|!|=|&|\|)"
#color green "-[Ldefgruwx]\b"
#color green "-(eq|ne|gt|lt|ge|le|s|n|z)\b"
#color brightblue "\b(cat|cd|chmod|chown|cp|echo|env|export|grep|install|let|ln|make|mkdir|mv|rm|sed|set|tar|touch|umask|unset)\b"
icolor brightwhite "\$\{?[0-9A-Z_!@#$*?-]+\}?"
color brightcyan "(^|[[:space:]])#.*$"
#color brightyellow ""(\\.|[^"])*"" "'(\\.|[^'])*'"
#color cyan ""(\\.|[^"])*"" "'(\\.|[^'])*'"
#color ,green "[[:space:]]+$"

Securing access to Microsoft Exchange 2013 EAC

The coexistence of the Exchange 2013 Administration Console (EAC) with the other Exchange website virtual directories represents a considerable security vulnerability for any organization that installs it using the out-of-box defaults. Since most organizations need Outlook Anywhere and EWS to be Web-facing, and usually OWA too, the EAC will also end up being publicly accessible – inadvisable security practice in itself, even more so for another important reason that I will explain. The EAC uses the IIS Virtual Directory /ecp which has other non-admin functions for normal email users, so it is not really desirable to try to limit access to it. Besides, an Exchange Service Pack or Cumulative Update is quite likely to reset the Virtual Directory settings and permissions later anyway. Now that the Exchange Management Console application has been retired, it is not practical to completely disable EAC unless you especially enjoy PowerShell, so we need to find a way to harden the server.

The problem is that the Domain’s built-in Administrator account does not have the Active Directory account lockout policy applied to it, so the EAC can simply be brute-force attacked if this account has access to the EAC or indeed OWA. One mitigation against this vulnerability is to make sure that the domain’s built-in Administrator account has all Exchange remote access disabled, and that a separate user account is used for day-to-day management. It is probably best to also disable the mailbox entirely to reduce the chance of someone accidentally re-enabling any of this in the EAC later.

Set-CASMailbox Administrator -OWAEnabled $false -ECPEnabled $false -ActiveSyncEnabled $false -OWAforDevicesEnabled $false -EwsEnabled $false -ImapEnabled $false -PopEnabled $false

Disable-Mailbox Administrator

Note that merely disabling the Administrator mailbox (without the first step of amending the access) offers no protection – the ECP can still be accessed and you won’t be able to use the Set-CASMailbox cmdlet, since no mailbox object exists.

There is still a big security problem though. Since the authentication is being handled by IIS the usernames are not being screened, and so a user encounters an HTTP 403 error when they are barred from using ECP but have been authenticated successfully (even if you remove the Administrator account from the ‘Organization Management’ Exchange Security Group), so the brute-force attacker can saturate the server with logon requests and precisely determine when they have cracked the Domain Admin credentials. Although these credentials cannot be used remotely if the above mitigation steps have been taken, the attacker can still use them later to fully penetrate the organization via other means: social engineering, physically entering the building etc.

Microsoft’s recommended solution is to use Powershell to designate a whole CAS server’s ECP Virtual Directory for Internal use only (keeping ECP disabled on the public facing CAS servers). This is totally unworkable for most small-to-medium enterprises though.

The only valid mitigation therefore is to restrict access to the ECP virtual directory to local subnets – something that we had wanted to avoid, and which on first sight looks impossible (since it’s a Virtual Directory, not a Website that we can re-bind to a new IP address and firewall more restrictively). In order to do this you will need to install the IIS Security Feature ‘IP and Domain Restrictions’:

Install-Feature-IIS-IP-Domain-Security

For the Default Web Site’s /ecp Virtual Directory (which is the public one), configure IP Address and Domain Restrictions:

IIS-IP-Domain-Security-Settings

In there, click Edit Feature Settings… (in the right-hand pane) and set ‘Access for unspecified clients’ to Deny. Then use Add Allow Entry to define your permitted IP ranges.

As I mentioned in the opening paragraph though this will need to be checked after Service Packs and Cumulative Updates are applied to the Exchange Server, in case this configuration is lost.

In fact the same precautions against brute force attack of the Administrator account would also apply to earlier versions of Exchange, and for VPN connectivity – i.e. when AD accounts are being used for any public facing authentication, the built-in Administrator should never be granted remote access.

PowerShell for EAP-PEAP secured VPN on Windows 8.1

Simple VPN configurations can be deployed by Group Policy but EAP authentication settings cannot be configured like this, even using Windows 8.1 and Windows Server 2012 R2. Microsoft added some new PowerShell cmdlets to Windows 8.1 for configuring VPNs, but the worked examples do not appear to function for all the settings for PEAP connections, and they do not show a worked example of how you go about exporting and re-importing a connection’s XMLStream.

Defining the XML as a block within the script itself, even assigning it as data type XML does not seem to work. Not being particularly accustomed to PowerShell, the following script took a while to get right. I assigned it as a laptop startup script by GPO. If I need to modify the connection in future I can increment the version number since the script checks the local machine Registry for that, and will not install if the desired version marker is already present.

 
# VPN Connection EAP-PEAP VPN provisioning 
# patters 2013

# This script is loosely based on the EAP-TTLS one published by Microsoft at http://technet.microsoft.com/en-us/library/jj613766.aspx
# The worked examples on that page and at http://technet.microsoft.com/en-us/library/jj554822.aspx
# are rudimentary, and in some details for PEAP, incorrect. To set advanced options like the TrustedRootCAs and the
# the server identity checking warning, you *must* export a GUI-authored config as XML. Configuring XML attributes alone
# will not work because some of them are missing when creating a new connection, and adding them results in errors.


# Check for marker in the Registry, and quit if found
# Desired version is 1
$version = 1
$test = Get-ItemProperty "HKLM:\Software\MyCompany" "MyCompany VPN" -ErrorAction SilentlyContinue
If ($test -eq $null) {
       $test = 0
} else {
       $test = $test."MyCompany VPN"
}
If ($test -ge $version) {exit} 

# VPN Connection look-up to remove any previous installations
$isTestVpn = $false
$vpnConnections = Get-VpnConnection -AllUserConnection
If($vpnConnections.Name -eq "MyCompany VPN") {Remove-VpnConnection -Name "MyCompany VPN" -AllUserConnection -Confirm:$false -Force}
$vpnConnections = Get-VpnConnection
If($vpnConnections.Name -eq "MyCompany VPN") {Remove-VpnConnection -Name "MyCompany VPN" -Confirm:$false -Force}

Try
{
       #-------------------------------------------------
       #The following section documents the attempts to get this working manually before I got importing/exporting of XML working

       # http://technet.microsoft.com/en-us/library/jj554822.aspx says to use "New-EapConfiguration -Peap" here, but is wrong      
       #$a = New-EapConfiguration

       # Generate configuration XML for PEAP authentication method with EAP-MSCHAPv2 as its inner method
       #$b = New-EapConfiguration -Peap -VerifyServerIdentity -FastReconnect $true -TunnledEapAuthMethod $a.EapConfigXmlStream

       # Edit properties within the generated configuration XML
       #$c = $b.EapConfigXmlStream
       #$c.EapHostConfig.Config.Eap.EapType.ServerValidation.ServerNames = "vpn.mycompany.com"

       # Specify AddTrust Root CA for Comodo - This attribute is missing unless you create the connection using the GUI
       # The following appears to generate the XML correctly, but it won't be accepted by the Add-VpnConnection cmdlet
       #$c.EapHostConfig.Config.Eap.EapType.ServerValidation.SetAttribute("TrustedRootCA","02 fa f3 e2 91 43 54 68 60 78 57 69 4d f5 e4 5b 68 85 18 68")   

       # PeapExtensions settings are nested XML objects so setting them as string datatype will fail
       # see http://www.vistax64.com/powershell/173859-xml-property-text.html
       #$c.EapHostConfig.Config.Eap.EapType.PeapExtensions.PerformServerValidation."#text" = "true"
       #$c.EapHostConfig.Config.Eap.EapType.PeapExtensions.AcceptServerName."#text" = "true"
       # Once again this attribute is missing unless the connection is created using the GUI. Adding it does not work
       #$c.EapHostConfig.Config.Eap.EapType.PeapExtensions.PeapExtensionsV2.AllowPromptingWhenServerCANotFound."#text" = "true"      

       # Create the VPN connection ‘MyCompany VPN’ with the EAP configuration XML generated above
       #Add-VpnConnection -Name "MyCompany VPN" -ServerAddress "vpn.mycompany.com" -TunnelType Sstp -EncryptionLevel Maximum -AuthenticationMethod Eap -EapConfigXmlStream $c -AllUserConnection
       #-------------------------------------------------



       # FORTUNATELY THERE IS AN EASIER WAY (once you figure out PowerShell XML – why couldn’t MS have shown a worked example in the docs)...



       # Create your VPN configuration entry manually then export its XML like so:
       #$exportXML = (Get-VpnConnection -Name "My_VPN_Final" -AllUserConnection).EapConfigXmlStream
       #$exportXML.Save("${env:temp}\My_VPN_config.xml")

       $importXML = New-Object XML
       $importXML.Load("\\mycompany.com\data\Software\MyCompany VPN\MyCompany VPN.xml")
       Add-VpnConnection -Name "MyCompany VPN" -ServerAddress "vpn.mycompany.com" -TunnelType Sstp -EncryptionLevel Maximum -AuthenticationMethod Eap -EapConfigXmlStream $importXML -AllUserConnection
       
       # Leave a marker in the Registry
       If (-Not (Test-Path "HKLM:\Software\MyCompany")) {New-Item -Path "HKLM:\Software\MyCompany"}
       if (Get-ItemProperty "HKLM:\Software\MyCompany" "MyCompany VPN" -ErrorAction SilentlyContinue) {
              Set-ItemProperty -Path "HKLM:\Software\MyCompany" -Name "MyCompany VPN" -Value $version
       } else {
              New-ItemProperty -Path "HKLM:\Software\MyCompany" -Name "MyCompany VPN" -Value $version
       }

}
Catch
{
       Write-Host "Error in connection setup!"
       Write-Host $_.Exception.Message
       Throw
}

Deploying vCenter Server Appliance 5.1 with AD auth

In theory using the vCenter Server Appliance (hereafter vCSA) offers a number of big advantages over using vCenter. Firstly you don’t need to commit a Windows Server OS licence, secondly to manage your VMs you can use a Flash-enabled browser on any operating system (including on Surface RT!), and thirdly it should be a lot quicker to deploy.

On that last point, a number of configuration steps in the setup of the vCSA are counter-intuitive and can waste a substantial amount of time. This is because the vCSA defaults to a hostname of localhost.yourdomain.com. The various web services that the appliance runs (SSO, Lookup Service, Inventory Service, vSphere Web Client) interact with each other using SSL sessions and, although there’s a built-in method to make vCSA regenerate its self-signed certificates at boot time, at the time of writing this does not work once these web services have been configured.

If you do not edit the hostname, you will not be able to enable AD authentication, and will likely encounter “Failed to connect to VMware Lookup Service https://yourhostname:7444/lookupservice/sdk – SSL certificate verification failed” when attempting to use the vSphere Web Client. However if after completing the initial setup wizard you configure the hostname to something meaningful and try to regenerate the SSL certificates, the vCSA will hang at boot time, displaying:

Waiting for network to come up (attempt 1 of 10)...
Appliance Name - VMware_vCenter_Server_Appliance
Configuration for eth0 found
The network for interface eth0 is managed internally, network properties ignored
DNS : x.x.x.x
Hostname or IP has changed. Regenerating the self-signed certificates.
Starting VMware vPostgres: ok
Waiting for the embedded database to start up: .[OK]

Furthermore, most of the potentially useful VMware KB articles assume a dedicated vCenter, rather than a vCSA. There seems to be no way out of this boot hang, and you will have to start deploying the vCSA all over again. The trick is to cancel out of the Setup wizard and change the hostname at the very start, before the various web services have been initialized at all.

I have outlined the successful setup process here as a reminder for future deployments:

  • When downloading the vCSA, download the .ova file. Ignore the other .vmdk and .ovf downloads, the .ova one will allow you to set up the IP address details at the time of deployment rather than having to change them later.
  • It is recommended to use Thick Provisioning for the disk, despite 120GB being overkill for typical small deployments.
  • Enter the chosen static IP address, network and DNS settings. Sadly they left out a hostname field here which would have saved a lot of grief.
  • Do not start the VM on completion of the wizard, then reduce the vCSA virtual machine RAM from 8GB down to 4GB – the supported minimum configuration for small deployments of less than 10 hosts.
  • As per the instructions displayed on the vCSA VM console, connect a web browser to port 5480 (the default credentials are root and vmware), and accept the EULA.
  • At this point quit the Setup wizard. Failure to do this will cause SSL certificate issues later.
  • In the Network tab change the hostname, in the Admin tab change the root password and enable SSL certificate regeneration, and finally in the System tab set the correct time zone then reboot.
  • Create a DNS A record for your vCSA.
  • After the reboot when you connect back to the admin console, the hostname in the certificate will remain as localhost.yourdomain.com – this is apparently normal.
  • Disable SSL certificate regeneration.
  • Start the Setup wizard again from the main vCenter Server tab Summary screen.
  • Select “Configure with default settings”.
  • Enable AD authentication (an Active Directory Computer account object will be created for your vCSA).
  • Despite having enabled Active Directory authentication, this will not work until the AD domain SSO Identity Source has been configured – you’ll see the error “A general system error occurred: Authorize Exception”. The VMware documentation mentions using the SSO Admin account to do this (admin@System-Domain) but this password is not defined by the user when deploying a vCSA. By default the root account is also an SSO admin, so log in to vSphere Web Client on port 9443 as root. Navigate to Administration > Sign-On and Discovery > Configuration > Add Identity Source:
    vCSA - Add SSO Identity Source
  • Enter the server URLs in the format ldap://dc1.mydomain.com
  • The DNs will probably both be cn=Users,dc=yourdomain,dc=com since you are only likely to need the Domain Admin user or Domain Admins group.
  • You need to set the Domain Alias to the NETBIOS domain name or else the vSphere Web Client plugin’s “use windows credentials” option will not work.
  • Set Authentication Type to Password and use a basic AD user account that you might use for photocopier scan-to-email directory lookups. Test the settings and save once working ok.
  • vCSA does not implicitly trust Domain Admins like a standard vCenter installation would, and the permissions are somewhat difficult to find in the vSphere Web Client. Navigate Home > vCenter > vCenter Servers > your vCSA > Manage tab > Permissions:
    vCSA edit vCenter permissions
  • Add your required AD groups to the role Administrator.
  • I had a further issue after all this, where connecting using vSphere Client with the “use windows credentials” option would result in the error “A General System error occured: Cannot get user info”. This is due to an omission in the vCSA which has been fixed in the latest download version (currently 5.1.0.10100-1123965). You can get around this by editing a config file on the vCSA.
  • One final reboot of the appliance is necessary to avoid permissions errors from the Inventory Service when logging into the vSphere Web Client with Windows session authentication. Be aware that the port 9443 web service can take several minutes to start, even after the console of the appliance has apparently finished booting.
  • In environments where you can’t afford the 120GB of disk space for the vCSA, you could use VMware Converter to V2V the appliance, resizing to say 40GB in the process.
 
 

Tunlr enable/disable script for Microsoft Surface

I recently bought a Microsoft Surface and I have been wanting to watch a few programmes on BBC iPlayer whilst out of the country for Christmas. I discovered Tunlr – a free media proxy service which allows access to Hulu and iPlayer regardless of geolocation. However, editing DNS server settings by hand is time consuming and awkward without using the trackpad, so I wanted a script to automate the task. This will also work for other proxy services such as unblock-us.com – just replace the DNS IPs in the script. I had previously written a quick script for changing IP configuration which used netsh commands but these don’t work on Windows RT. Some other PowerShell methods I found weren’t supported either but I did find new network settings cmdlets for the purpose that were added in Windows 8/RT.

The next problem was elevation to get sufficient rights to change the network settings. It transpires that the PowerShell and VBScript environments are heavily restricted in Windows RT, which prevents auto-prompting for elevation. Fortunately Windows RT does allow Run as Administrator from the right-click menu for .cmd scripts. If you’re using touch control, you just touch and hold then release for the right-click. The script will remind you if you forget to do this. Hover your mouse over the top right corner of the script below, and use the View Source button to save the following to your desktop as Tunlr.cmd:

@echo off

::Use Tunlr to watch streaming TV services regardless of geolocation
::Tunlr DNS servers redirect requests for well-known services via Tunlr's proxy servers
::Tunlr should only be used while watching streams to reduce server load
::More details at http://tunlr.net/

::Elevation cannot be automated on Windows RT since object creation is disabled for PowerShell and VBScript
::http://stackoverflow.com/questions/13504499/windows-rt-powershell-permissiondenied-on-new-object

ipconfig /all | find "142.54.177.158" > nul && (
  echo Disabling Tunlr...
  PowerShell -Command Set-DnsClientServerAddress -InterfaceAlias "WiFi" -ResetServerAddresses || (
    echo Right-click and re-run this script as Administrator
    pause
  )
) || (
  echo Enabling Tunlr...
  PowerShell -Command Set-DnsClientServerAddress -InterfaceAlias "WiFi" -ServerAddresses 142.54.177.158,209.141.56.79 || (
    echo Right-click and re-run this script as Administrator
    pause
  )
)

UAC elevation for Windows batch script

I recently needed to make an interactive batch script elevate for admin privileges. I found an example script by jagaroth, and then refined it to make it even more compact. It only writes out one temporary script file, and passes the rest of the required variables on the command line. It can cope with paths containing spaces. It was something of a shell escaping nightmare as you can see from line 14!

@echo off

::Windows XP doesn't have UAC so skip
for /f "tokens=3*" %%i in ('reg query "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion" /v ProductName ^| Find "ProductName"') do set WINVER=%%i %%j 
echo %WINVER% | find "XP" > nul && goto commands

::prompt for elevation
if "%1" == "UAC" goto elevation
(
  echo Set objShell = CreateObject^("Shell.Application"^)
  echo Set objFSO = CreateObject^("Scripting.FileSystemObject"^)
  echo strPath = objFSO.GetParentFolderName^(WScript.ScriptFullName^)
  echo If objFSO.FileExists^("%~0"^) Then
  echo   objShell.ShellExecute "cmd.exe", "/c """"%~0"" UAC ""%~dp0""""", "", "runas", 1
  echo Else
  echo   MsgBox "Script file not found"
  echo End If
) > "%TEMP%\UAC.vbs"
cscript //nologo "%TEMP%\UAC.vbs"
goto :eof
:elevation
del /q "%TEMP%\UAC.vbs"

:commands
::navigate back to this script's home folder
%~d2
cd "%~p2"

::put your main script here
echo 1st arg: %1
echo 2nd arg: %2
pause