TeamViewer on Raspberry Pi 3

During the summer we moved from an apartment to a house. Among many other things, this meant changes to the Internet connectivity. Our old place had VDSL, but now I got to choose what I want. Fiber optics would’ve been an option (fast and reliable), but it’s rather expensive compared to the other alternatives. In the end, I ended up with a 50/50 Mbit/s 4G mobile broadband connection which is shared through a 4G router (which I already owned). This was by far the most bang for the buck. We also happen to live quite near a 4G base station, so regular speeds reach about 40Mbit/s+. Not bad. Not bad at all. I’m not a gamer either, so no need for low ping times. On the negative side, all Finnish 4G mobile broadband connections are NAT:ed on the ISP side (exception is enterprise/business subscribers). This dilemma is also the subject of this post, in other words how to “bypass” dual NAT using TeamViewer. (I had to ditch my fancy old VPN stuff 😦 )

Well, moving along to the subject, TeamViewer. TeamViewer is by no means a new technology, but the possibility to use it on the RPi is limited. When googling you’ll most certainly find a solution named ExaGear Desktop. ExaGear Desktop enables x86 programs to be run (or “emulated”) on the RPi. While this is a good idea, it’ll most certainly be slow. A RPi running Raspbian is already quite slow, so doing x86 emulation on top of that is even slower. You’ll also find people telling you it’s impossible to run TeamViewer on the RPi altogether (which is untrue).

Why would you need TeamViewer on the RPi you ask? Isn’t there already SSH and port forwarding and such? Yes, BUT port forwarding won’t work with (double) NAT:ed 3G/4G connections. (NAT at the ISP level and NAT behind the router). As stated before, my main Internet connection at home is a 4G mobile broadband connection (without a public IP) connected to a 4G router. This combination doesn’t allow me to remote connect to my LAN using the “normal methods” (VPN, port forwarding and so on). The reason for this is that you can’t configure the ISP NAT rules (obviously). Some similar information about this dilemma can be found here for example: (in Finnish)


Luckily there’s a solution to this dilemma (and luckily I’m here to minimize your googling):

The TeamViewer IoT contest: 🙂

Just download and install it in Raspbian (with a simple double click). After that have a look at the Frequently Asked Questions and the General Questions & Answers + Troubleshooting Questions and Answers on the same download page. The only settings I changed were:

  • Sat an unattended fixed password and disabled random password (via the GUI).
  • Edited /boot/config.txt and commented out framebuffer_width and framebuffer_height lines. I left them at 1280×720 which worked OK for me. (I did this because I’m running the RPi headless and the resolution would therefore be screwed up (too tiny) if connecting without a monitor attached to the RPi).
  • Added the RPi to the “My Computers”-list in the TeamViewer client (from Windows)
  • Voilà!


…and some screenshots:


Fig 1. Connected, yey 🙂



Fig 2. Having a look at the doggycam remotely



Alternative solutions

  • Pay a slightly more expensive monthly fee for your mobile broadband connection, and in return get a public IP address. This is true for almost all ISP’s here in Finland at least.
  • Some ISP’s provide public IP’s on 4G mobile broadband connections using IPv6. This only works with a couple of mobile broadband sticks/routers however (they have to fully support IPv6). I wouldn’t buy a new stick (or router) only for this feature. (They’re rather expensive after all).
  • Use TeamViewer on a x86 computer instead of a RPi. Yes, why not. Then again it consumes much more energy than a RPi when in use 24/7. It’s also noisy. And hey, everything is always much more cool and hip with a RPi🙂


That’s it! This was just a short little post that hopefully will make your life a whole lot easier when dealing with the evil NAT:ed 4G connections🙂

ownCloud 9 on Raspberry Pi 2 with mounted Buffalo NAS

The Linux nerd inside me was screaming for a new RPi project. What to build? What to do? You can’t read any modern IT literature nowadays without stumbling upon the word “cloud”. Well, cloud it is. Owncloud in my case. I guess almost everyone is familiar with this open source cloud software, but for those of you that aren’t you can find information at:

The idea was to access my trusty old Buffalo NAS remotely, without having the need to map network drives etc. Buffalo is actually offering some sort of cloud solution also, but hey, it’s much more fun configuring your own stuff🙂 The idea is quite simple – The RPi is a front-end for the NAS. Clients are connecting to the RPi, which in turn mount network storage from the NAS. Here’s the setup:


Fig 1. RPi + Buffalo NAS


Initial questions and ideas

  • Should Raspberry Pi / ownCloud be visible on the Internet? If so, how to secure it properly?
      • Port forwarding with restrictions / reverse proxy?
  • If not visible on the Internet, how should one connect from the outside world?
      • VPN?

I actually decided to go with option 2, not visible on the Internet. My decision is based on the fact that I’m already running a VPN server. It’s one more extra step before getting/synchronizing the files, but I think it’s worth it in the end. Besides, all my other services are behind VPN also.

That said, I STILL configured ownCloud to be “future-proof” even if the server won’t be Internet-facing (with port forwarding etc.) right now. (See the securing ownCloud chapter). Better safe than sorry🙂



As with almost every project, I usually follow an existing guide. ownCloud is quite a mainstream product, so there are tons and tons of documentation available. The guide that I used as my baseline this time was: . Thanks to the author🙂 Steps:

  • Followed the guide down to “Now make your ownCloud directory adjust your path as necessary to your mounted hard drive folder..”. As I’ll be using a NAS, it was time for another guide:
    • created a share on the NAS (named owncloud). Gave the share read/write access for a user also named “owncloud”.
    • mounted the share on the RPi. The guide uses backslash, but it should be forward slash:
      • e.g. mount -t cifs // /mnt -o username=owncloud,password=owncloud
    • Did not follow step 3 completely because there was no data-directory created during the installation (yet). The installer GUI will look for a data directory though, so this is the time to create and mount it properly.
    • Got the uid of www-data or apache user by using id command:
      • root@owncloud:~# id www-data
        uid=33(www-data) gid=33(www-data) groups=33(www-data),1000(pi)
      • OK. ID is 33
    • Created a local data-directory which will mount the owncloud share (from the NAS).
    • mkdir -p /var/www/owncloud/data
      • changed ownership and permission on the data directory;
        • chmod -R 770 /var/www/owncloud/data ; chown -R www-data:www-data /var/www/owncloud/data
      • Added the following line to /etc/fstab (bottom of file) to make the data directory available in owncloud (setup):
        • // /var/www/owncloud/data cifs user,uid=33,rw,suid,username=owncloud,password=owncloud,file_mode=0770,dir_mode=0770,noperm 0 0
    • Ran mount –a and checked if the NAS got properly mounted. For me it did. In other words the “local” /var/www/owncloud/data was now actually living on the NAS.
    • Finished the configuration via ownClouds own GUI setup. Everything went fine…
    • …however, after a reboot the share was NOT auto mounted😦
    • I got an error when trying to access owncloud over the web interface: Please check that the data directory contains a file “.ocdata” in its root
      • Scratched my head and wondered what the hell went wrong. I was quite sure it had to do with permissions. Turned out I was right. Short version:
        • created an empty .ocdata –file (after I had manually mounted /var/www/owncloud/data directory from the NAS).
        • chmodded that file and the data-directoy with “new rights” ;
          • chmod 777 .ocdata ; chmod 777  /var/www/owncloud/data
          • success, the NAS now got automounted after a RPi-reboot🙂
    • Everything worked, so moving over to the (optional) security part.


Securing ownCloud

Owncloud’s own Security & setup warnings will warn you about things to fix. Here’s a screenshot with almost no security measurements taken. (Actual screenshot is not mine, it’s “borrowed” from the Internet):


Fig 2. Before fixing Security & Setup warnings. I’ll write about memory cache in the next chapter (Optimizing ownCloud).


… and here’s a screenshot with fixed security (also memcached fixed):


Fig 3. No security & setup warnings🙂


Basic security

The initial setup guide I followed had already done some basic security measurements (luckily):

  • Redirected all unencrypted traffic to HTTPS (in /etc/nginx/sites-available/owncloud):
      server {
        listen 80;
        return 301 https://$server_name$request_uri;  # enforce https
  • Used SSL certificates for https (self-signed):
      ssl_certificate /etc/nginx/ssl/owncloud.crt;
      ssl_certificate_key /etc/nginx/ssl/owncloud.key;
  • Created a virtual host for owncloud, not using “default”.
  • Protected the data directory and files from the internet (outside world):
       # Protecting sensitive files from the evil outside world
        location ~ ^/owncloud/(data|config|\.ht|db_structure.xml|README) {
                 deny all;
  • After this, there were still some things to take care of. Although not visible in Fig 2 above, I also got a warning saying that HTTP Strict Transport Security wasn’t used. Well, a quick googling fixed this. All that was needed was a parameter in the same configuration file as above (/etc/nginx/sites-available/owncloud):

More information about security can be found in ownClouds own Hardening and Security Guidance:


Advanced security

If you are going to deploy a server that’s facing the Internet you have to think about security. The basic security measurements are a must, but what if you want to secure it even more? You certainly want your site protected against DDOS and brute-force attacks, don’t you? Well, here’s where one of my favorites come into play – fail2ban. If you have no idea what I’m talking about I suggest that you read at least the following: (<- Specifically THIS link)

If you’re lazy, just follow the above guides and setup accordingly. However, use common sense and double check that everything seems to be in order before going production. I myself created the following jail-files and configuration files, and restarted fail2ban. Everything was working as expected🙂 My configuration files:

root@owncloud:/etc/fail2ban/filter.d#  ls -la ngin*.*
-rw-r–r– 1 root root 345 May 23 09:28 nginx-auth.conf
-rw-r–r– 1 root root 422 Mar 15  2014 nginx-http-auth.conf
-rw-r–r– 1 root root 280 May 23 09:29 nginx-login.conf
-rw-r–r– 1 root root 300 May 23 09:28 nginx-noscript.conf
-rw-r–r– 1 root root 230 May 23 09:28 nginx-proxy.conf
-rw-r–r– 1 root root 282 May 24 09:53 nginx-req-limit.conf


root@owncloud:/etc/fail2ban/filter.d# ls -la own*
-rw-r–r– 1 root root 146 May 23 09:08 owncloud.conf

(Contents of these files can be found in the links above)

…and jail-files:

root@owncloud:/etc/fail2ban# cat jail.local

enabled = true
filter  = owncloud
port    = https
bantime  = 3000
findtime = 600
maxretry = 3
logpath = /var/www/owncloud/data/owncloud.log

enabled = true
filter = nginx-auth
action = iptables-multiport[name=NoAuthFailures, port=”http,https”]
logpath = /var/log/nginx*/*error*.log
bantime = 600 # 10 minutes
maxretry = 6

enabled = true
filter = nginx-login
action = iptables-multiport[name=NoLoginFailures, port=”http,https”]
logpath = /var/log/nginx*/*access*.log
bantime = 600 # 10 minutes
maxretry = 6

enabled  = true
filter = apache-badbots
action = iptables-multiport[name=BadBots, port=”http,https”]
logpath = /var/log/nginx*/*access*.log
bantime = 86400 # 1 day
maxretry = 1

enabled = false
action = iptables-multiport[name=NoScript, port=”http,https”]
filter = nginx-noscript
logpath = /var/log/nginx*/*access*.log
maxretry = 6
bantime  = 86400 # 1 day

enabled = true
action = iptables-multiport[name=NoProxy, port=”http,https”]
filter = nginx-proxy
logpath = /var/log/nginx*/*access*.log
maxretry = 0
bantime  = 86400 # 1 day

enabled = true
filter = nginx-req-limit
action = iptables-multiport[name=ReqLimit, port=”http,https”, protocol=tcp]
logpath = /var/log/nginx/*error*.log
findtime = 600
bantime = 7200
maxretry = 10


After you’ve created the jails and the configuration files you should restart the fail2ban service, “sudo service fail2ban restart”. You can then have a look in the log file, /var/log/fail2ban.log to see if everything looks ok. For me it did:

2016-05-24 09:55:53,094 fail2ban.jail   [4778]: INFO    Jail ‘ssh’ started
2016-05-24 09:55:53,136 fail2ban.jail   [4778]: INFO    Jail ‘owncloud’ started
2016-05-24 09:55:53,162 fail2ban.jail   [4778]: INFO    Jail ‘nginx-auth’ started
2016-05-24 09:55:53,190 fail2ban.jail   [4778]: INFO    Jail ‘nginx-login’ started
2016-05-24 09:55:53,223 fail2ban.jail   [4778]: INFO    Jail ‘nginx-badbots’ started
2016-05-23 10:28:13,243 fail2ban.jail   [1350]: INFO    Jail ‘nginx-noscript’ started
2016-05-24 09:55:53,249 fail2ban.jail   [4778]: INFO    Jail ‘nginx-proxy’ started
2016-05-24 09:55:53,281 fail2ban.jail   [4778]: INFO    Jail ‘nginx-req-limit’ started

All this configuration is a bit overkill for me as I’m not going to expose the ownCloud server on the Internet. Instead I’m using VPN + ownCloud. This is however a great opportunity to learn about ownCloud and it’s security so it would be a shame NOT to configure it as secure as possible🙂 (The ssh-jail is a very nice bonus if you’re also forwarding that port towards the Internet).


Optimizing ownCloud

After all the security hardening stuff it was time to look at optimization. The initial guide includes some optimization and it installs all the PHP modules needed for memory caching. I’m quite sure I could optimize ownCloud much more, but there’s no need to overdo it in such a small home environment. In other words, memory caching is enough in my case. More info about memory caching can be found in ownClouds own documentation:

Even though this topic is already covered at the bottom in the initial guide (, I’ll write a summary here:

  • Edit /var/www/owncloud/config/config.php
  • At the bottom of the file, add:
    'memcache.local' => '\OC\Memcache\Memcached',
    'memcache.distributed' => '\OC\Memcache\Memcached',
    'memcached_servers' => 
    array (     0 => 
    array (     0 => '',     1 => 11211,     ),     ),
  • Check that memcached is running:

      root@owncloud:# netstat -nap | grep memcached
      tcp        0      0*               LISTEN      457/memcached
      udp        0      0*                           457/memcached
      unix  3      [ ]         STREAM     CONNECTED     7961     457/memcached
      unix  3      [ ]         STREAM     CONNECTED     7955     457/memcached
      unix  3      [ ]         STREAM     CONNECTED     7753     457/memcached
      unix  3      [ ]         STREAM     CONNECTED     7967     457/memcached
      unix  3      [ ]         STREAM     CONNECTED     7960     457/memcached
      unix  3      [ ]         STREAM     CONNECTED     7954     457/memcached
      unix  3      [ ]         STREAM     CONNECTED     7966     457/memcached
      unix  3      [ ]         STREAM     CONNECTED     7964     457/memcached
      unix  3      [ ]         STREAM     CONNECTED     7958     457/memcached
      unix  3      [ ]         STREAM     CONNECTED     7963     457/memcached
      unix  3      [ ]         STREAM     CONNECTED     7957     457/memcached


  • Done. You should now have a pretty safe (and optimized) environment to play with🙂


ownCloud works pretty much the same way as Dropbox and others. Here’s a screenshot from a Mac client and one test-file synchronized:


Fig 4. ownCloud + Mac.


Useful configuration paths

I’ll finish this blog post with a short summary of useful configuration paths. Here you go:

/var/www/owncloud/config/config.php (


Adding Edge and Reverse Proxy Servers to an Existing Lync 2013 Environment

My recent task was to expand our existing Lync environment (Lync Server 2013 Standard) with an Edge and a Reverse proxy server. (This guide probably works for Skype for Business as well). Our old Lync environment had been in test usage for a while (with a rather small test-user group), but with more and more Lync users adding up it was time to expand. As a matter of fact, a Lync environment without Edge and reverse proxy servers is rather useless – you are unable to organize external meetings.

First, let me start off by saying that there are A LOT of “moving parts” involved in configuring a reverse proxy and an Edge server. You must plan for IP addresses, DMZ settings, DNS settings, certificates, firewall settings and so forth. To get a grasp of the whole picture I’m suggesting that you read/watch the following: – A very good protocol poster (Skype for Business Server 2015 Protocol Workloads) that helps with the overall picture. It’s also very good for checking firewall requirements/port configurations. Yes, it’s a bit overwhelming but very good in the end🙂 – Explains (firewall) ports.

A good place to continue after this would be It’s a very nice all-around document about Edge and Reverse proxy. Pay close attention to the chapter about Best Practices. Our goal in the end was to get something that resembles this picture:


Fig 1. Lync Front-end in combination with Edge and Reverse proxy – Simple Topology. (Pic source:


Even after a lot of reading, It’s hard to know where to start (in this blog post). There are soooooo many different things going on and a lot of stuff to remember. A good place to start could be certificate planning, which also means that you have to decide which IPs/hostnames you’ll be using in your own environment. Then again, I think the best place to start is planning network infrastructure/topology. First, consider whether you are going with a simple topology (Front-end, Edge server, Reverse proxy – we’re using this) OR a complex topology (multiple Front-ends, Edge servers, Reverse proxies). Second, It’s very important to have a working DMZ, and you should also know if you’ll be using (only) Public IP addresses or public IPs in combination with NATed ones. After you’ve got an answer to these questions it will be much easier planning for the other requirements. With this in mind, I’ll start off with the networking part. I’ll then move over to areas like DNS, certificates, actual Edge server installation, IIS ARR installation and finally some words about mobility and federation.

But first off, here’s a short explanation of what the Edge and Reverse proxy servers bring to the table:


Includes 4 modules:

  • Access Edge service. The Access Edge service provides a single, trusted connection point for both outbound and inbound Session Initiation Protocol (SIP) traffic.
  • Web Conferencing Edge service. The Web Conferencing Edge service enables external users to join meetings that are hosted on your internal Lync Server 2013 deployment.
  • A/V Edge service. The A/V Edge service makes audio, video, application sharing, and file transfer available to external users. Your users can add audio and video to meetings that include external participants, and they can communicate using audio and/or video directly with an external user in point-to-point sessions. The A/V Edge service also provides support for desktop sharing and file transfer.
  • XMPP Proxy service. The XMPP Proxy service accepts and sends extensible messaging and presence protocol (XMPP) messages to and from configured XMPP Federated partners.


Reverse proxy

The reverse proxy is required for the following:

  • To allow users to connect to meetings or dial-in conferences using simple URLs
  • To enable external users to download meeting content
  • To enable external users to expand distribution groups
  • To allow the user to obtain a user-based certificate for client certificate based authentication
  • To enable remote users to download files from the Address Book Server or to submit queries to the Address Book Web Query service
  • To enable remote users to obtain updates to client and device software
  • To enable mobile devices to automatically discover Front End Servers offering mobility services
  • To enable push notifications to mobile devices from the Office 365 or Apple push notification services




Networking / Network interfaces

I’m now assuming that you have:

  • A working Lync Server Standard/Enterprise 2013 (or Skype for Business) Front-end
  • A soon-to-become (Lync) Reverse Proxy server (Windows Server 2012 R2)
  • A soon-to-become Lync Edge server (Windows Server 2012 R2)
  • Talked to your network guys about the network infrastructure (IPs/DMZ). Hardware (F5) load balancers can be a whole different story for example.
  • Talked to your firewall guys about opening ports. I myself sat down with the Skype for Business Server 2015 Protocol Workloads printout and had a long discussion with a firewall guy. We/he got the job done without any hiccups. (It’s still working fine today🙂 )


On the Reverse Proxy:

Assign one IP for the internal network adapter and one for the external network adapter. Internal and External should be in different subnets. One interface is communicating with the internet and the other one is communicating with your internal network/AD. Have a look at or for examples. (I’m not going into much DNS details (yet), but you could name these new IPs and for example).

  • Set the default gateway on the external network adapter only
  • Assign static routes. From my experience, the information regarding this can be a bit difficult to understand. Let me copy/paste the information from the above link:

Important: Similar to the Edge Servers, you set the default gateway on the external network adapter only. The default gateway will be the IP address of the router or external facing firewall that directs traffic to the Internet. For traffic that is destined from the reverse proxy to the internal facing network adaptor, you must use persistent static routes (such as the route command in Windows Server) for all subnets containing servers referenced by the web publishing rules. Setting a persistent route does not cause the computer to become a router. If IP forwarding is not enabled, the computer is acting only to direct specific traffic destined for another network to the appropriate interface. This is essentially setting two gateways – one as the default pointing to the external networks, and one for traffic destined to the internal interface and on to a router or other network.
However, creating persistent routes for all subnets may not be necessary if your network’s routers are configured to summarize routes. Create a persistent route to the network where the router is defined and use the router as the default gateway. If you are not sure how your network is configured and need guidance on what persistent routes need to be created, consult with your company’s Network Engineers.
The reverse proxy must be able to resolve the DNS host (A) records for the internal Director or Front End Server and next hop pool FQDNs used in the web publishing rules. As with the Edge Servers, for security reasons, we recommend that you do not configure a reverse proxy to use a DNS server located in the internal network. This means you either need DNS servers in the perimeter, or you need HOSTS file entries on the reverse proxy that resolves each of these FQDNs to the internal IP address of the servers”.

In plain English this means that you configure the external interface “normally”, as you would with any other external network interface in your infrastructure. You should define the gateway as the “IP address of the router or external facing firewall that directs traffic to the Internet”. Your network guys can help you with this if unsure (also see the next chapter). The internal side on the other hand should not have a default gateway – instead you configure static routes. I’ll try to explain this:

Example network subnets (defined by your network administrators):

External DMZ (16 addresses, all are not needed but room for expansion)


Internal DMZ (16 addresses, all are not needed but room for expansion)



Server configuration:

Example external network adapter configuration on the server:


Example Internal network adapter configuration on the server:

GW:      no gw

We’re using split-brain DNS so the internal and external DNS names are the same. All IP’s are from a Class B chunk, and they’re all public IP’s that are defined as internal or external in the firewall/DNS. With the above configuration in place, you should now add a route to the internal interface on the reverse proxy server. This is done with the route add command (The –p switch make the changes persistent). Here’s an example using the above IP schema:

C:\>route add -p mask
C:\>route add -p mask
C:\>route add -p mask
C:\>route add -p mask
C:\>route add -p mask

The above command example would make all of the above IP ranges take the route against the internal interface. All other IPs would take the external route. The above ranges are also defined as internal in DNS/firewall. Do the same for all of your internal IP ranges. This method is different when using NAT and/or non-split-brain configurations. (In case of NAT, your internal IPs are in the 192.168.x.x, 10.x.x.x, or 172.16.x.x. range). Perhaps a picture will tell more than words:


Fig 2. Internal and external overview. (Picture source:

This should be it for the networking part on the Reverse proxy server. Now we do the same on the Edge server.


On the Edge server:

The network configuration on the Edge server follow the same pattern as the Reverse proxy. I’m using three external IPs and one internal IP. This is by best practice design ( If you are in a limited-budget-external-IP-dilemma, you can also make it work with one external IP (not including that option in this text however).

  • Assign three external IPs
    • one for SIP traffic
    • one for AV traffic
    • one for Web Conferencing
  • Assign one internal IP

I’m not going much into DNS details now either, but you could name these new IPs,, and for example. There’s nothing much to add here. Follow the same procedure as for the reverse proxy when configuring your internal and external network interfaces:

Server configuration:

Example Internal network adapter configuration on the server:

GW:      no gw

Example external network adapter configuration on the server:





Now add the same routes as you did on the reverse proxy. There you have it, we can now move over to the DNS part.




I assume that you by now have figured out your topology and configured networking on the involved servers. Good, that’s one step in the right direction. You might have noticed that I haven’t talked much about host names, only IP addresses. This is mostly because you can configure the networking part this far without knowing (almost) any host names. (Of course you most certainly will ask for a hostname at the same time you get an IP address, but anyways).

I have to say that DNS was one of the most confusing/difficult/challenging/painful parts in this whole configuration/deployment. There were tons and tons of misleading/wrong information, and it required countless hours of testing. Anyways, I’ll spare you the DNS-pain and tell you about our configuration in a while. But before I do, I make you read some homework. Here are a couple of interesting links (with or without errors):

Let me start off by saying that I like the jackstromberg article. All my testing was actually based on the DNS table from that article. However those records were also a bit confusing, and some even unnecessary. Here are our DNS records with comments:


Internal DNS:


Fig 3. Internal DNS

No other records are required for our specific configuration/environment (at the moment). SRV records are a thing of the past and only needed when working with Lync 2010 clients. See for more information. If you are going to use federation however (which we probably are in the future), you SHOULD set up SRV records (though not needed if manually entering servers). See: As you can see, Allowed Partner Server (Direct Federation) works without SRV records but specifying the records when you federate will probably still make your life easier.

I will now also make a statement about the record in the Internal DNS. You can read on many, MANY places on the Internet that you should have this record present in the internal DNS so that mobility works. I can confirm that our users mobile phones (WP, iOS, Android) work just FINE without this record. The key is to have the external Web Services record present in the internal DNS ( and point it to the reverse proxy. If you DO use lyncdiscover in the internal DNS, ALL traffic will go through the proxy. This is probably not a desirable configuration. Yes, I’ve seen this “live” in our environment so I know what I’m talking about. The “problem” went away after we removed the record from the internal DNS. Good info about this:

Read the above links CAREFULLY and you’ll have a MUCH better understanding, believe me🙂 Again, this setup works FOR US. I’m not saying that the record should be removed from every internal DNS configuration out there.


External DNS:


Fig 4. External DNS.

External DNS was much more straight forward. Comments are included in the picture.

The DNS records are (as you can see) a bit different for the external network/outside world compared to the internal network. All external traffic goes through the reverse proxy, which in turn use URL rewrites to connect to the corresponding URLs on the inside network. (I’ll leave the URL rewrite / ISS/ARR discussion for a later chapter).


Hosts file:

You have probably noticed that the record is present in BOTH the internal and external DNS. The reason for this is mobile devices. Mobile devices need to access the mobility service, and they do that ONLY from the outside. I’m yet again referring to the Mobility service flow using AutoDiscover (picture) at Lyncs own autodiscover feature will know if the client is on the internal or external network based on the lyncdiscover/lyncdiscoverinternal record. However, it’s a whole different story with If this URL is accessed from either the inside or outside network, the client is unable to know it’s final destination. This is because you’re pointing the client (in both cases) to the reverse proxy, which in turn point to the same URL internally and externally. This means that you’ll end up in an endless loop. To solve this you’ll edit the hosts-file.

You also have to add a local DNS record for lyncdiscover, otherwise this record will remain unresolvable as it’s not present in the internal DNS. This was all a big mystery for me, as the documentation seldom mentioned this dilemma. I got an idea after hours of googling though – the holy hosts-file. Thanks to for the idea. This was by no means a big surprise, but you’ll get lost (in DNS) after hours and hours of testing. Believe me.

This means that you’ll have to add local DNS records on the reverse proxy. Fire up notepad and edit the C:\Windows\System32\drivers\etc\hosts –file on the reverse proxy. Add the following:, where is the IP of your Front-end server., where is the IP of your Front-end server.

(Meet and dialin are already resolvable by internal DNS and correctly points to the Front-end).

Now when a client resolves webext (internally or externally), it always gets sent to the reverse proxy. The reverse proxy in turn resolves webext to the front-end via the hosts-file. Lyncdiscover in turn won’t be resolvable internally after it reaches the reverse proxy if no hosts file-record is added. There you have it – all your DNS problems solved🙂




Certificates and DNS go somewhat hand-in-hand as you need to know which hostnames you’ll be using in the certificates. I’d probably start off by reading again. Some information to get you started:

Take your time to read and plan – this way you’ll be rewarded in the end. The above links discuss both internal and external certificates. They also discuss the differences between the reverse proxy and the Lync Edge certificates.

We’re not completely going by best practice regarding the certificates. We’re using external certificates on the internal front-end server. This is due to the fact that we already had an external certificate installed on the Front-end. It doesn’t do much harm either, and at least for us it’s not an extra expense.

Without further stories I’ll present our “certificate solution”. We’re using one certificate per interface on the edge server, but you could also use just one certificate will all hosts included. This would be more expensive due to the fact that you’ll have to pay extra for additional SAN-names. (You DON’T need a certificate for the AV-interface on the Edge server).


Fig 5. Edge and Reverse proxy certificate chart.

To add to this list, our Front-end needed to get its public certificate renewed with the added host Before the renewal, it included public certs for lyncdiscover, lyncdiscoverinternal, meet, dialin and sip. Now it includes all those + webext. Webext is needed for the external Web Services (externally accessing the front-end). More about that later on.

The following chapters has information about how to install the certificates on the servers.



Configuring the Lync Front-end Server for Edge / Installing the Edge Server / Edge Server Certificate Installation

Congratulations If you’ve had the energy to read this far. It’s now finally time to install the Edge server🙂 Much of the Edge installation/configuration is actually tied to the Front-end server however. You’ll start by making changes to your current topology and then export/publish the topology on the Edge server. Like you’ve probably noticed before, it’s the prep work that takes most of the time. (Internet is full of articles on how to install an Edge server). That said, I happen to like the post at and our installation is based on this article. However, there are some differences. In Step 6, the article tells you to request internal and external certificates from the setup itself. We didn’t do it this way because our internal CA isn’t an “online certification authority” (it doesn’t respond to online web requests due to security reasons). Instead we made an offline request and signed it manually on the CA. A little bit more hassle, but worked just fine in the end.

We didn’t use the certificate request wizard for the external certificate either, as those gets created by our “certificate guy”. He uses his own methods and just delivers a fully working certificate. I won’t go into the details, but it works. So in the end, whatever floats your boat and can get you the correct certificates is fine🙂

If using this “manual method” (alternative to Step 6 in the guide), you must manually install the certificate(s) in the certificate store(s) before continuing. This is by no means difficult. For the internal/external certificates do the following:

  • Fire up “mmc.exe” on the Edge server
  • Add the certificates Snap-in. Select computer account –> local computer and click OK.
  • Right click on the Personal –> Certificates folder.
    • Select All Tasks… Import
    • Imported certificate will show up in this location.
  • Move the different certificates to their corresponding places (Personal, Trusted Root Certification Authorities, Intermediate Certification Authorities). See screenshots/figures below.


Fig 6. Personal certificate (computer)


Fig 7. Trusted Root CA certificate


Fig 8. Intermediate CA certificate

  • Done. External certificates are also showing in this list as I have imported them in the same manner.

Now, back to the installation post at

Some of my own notes:

  • Followed the guide.
    • Network specifications were OK.
    • Software specifications were OK. Didn’t (need to) install Windows Identity Foundation on the Front-end. (It should be installed as a pre-requirement on the Edge server however).
    • Fired up Topology Builder on the front-end and followed the guide.
      • FQDN of the new edge pool should match the FQDN (CN) on the internal certificate: from certificate chart
      • Access Edge service should match the FQDN (CN) on the external certificate:
      • Web Conferencing Edge service should match the FQDN (CN) on the external certificate:
      • A/V Edge service should match the FQDN (CN) on the external certificate:
        • NOTE: This is a “DNS/certificate-thing”. Whatever certificate CN-record you created for the above services should be used. You can swap CN and SAN records for a more “clean” name, i.e. vs. (See above DNS/certificate chart and the note about switching places between CN and SAN).
      • Enabled federation (not xmpp yet though)
      • Defined internal and external IP addresses
      • Defined Next hop pool: our front-end
    • Changed the External web services in the Topology builder to match the one we have defined in DNS and in the certificate (would be in the example).


Fig 9. External web services

    • Published the topology
    • Exported the configuration (step 4 in guide).
  • Moved over to the Edge server itself
    • Installed Lync server and imported the configuration (step 5 in guide)
    • The certificates were already installed in the certificate store so no need to request certificates (step 6)
      • Defined the existing certificates
    • Started services
    • Done! (no need for step 8 and 9, yet)



Installing and configuring the Reverse Proxy server / Reverse Proxy server Certificate Installation

I’m now assuming that you have a working Edge server. You can install the reverse proxy server without a working Edge server also, but installing the Edge server first makes it easier to test the reverse proxy functionality right after the installation. First some homework/reading:

I decided to go with a combination of the Microsoft guide and the jackstromberg one this time. In the end, it worked perfectly. I had lots of problems and headaches down the line, but this time it had nothing to do with the guides (rather it had to do with typos and a non-working ARR that had to be reinstalled).

Before following the (Microsoft) guide however, we have to install the certificates the same way we did on the Edge server. The reverse proxy certificates are of course different, but I’m assuming that you have requested them at the same time as the Edge certificates. Just follow the Edge steps (fire up mmc.exe and so on) and you’re good to go. One different step is that you have to bind the certificates in IIS, otherwise they won’t be used when clients connect via the reverse proxy. It’s rather easy, let me show you some screenshots:


Fig 10. Adding https bindings in IIS.


Fig 11. Adding https bindings in IIS. Remember to add both the internal and the external interface, with their own certificate.

Now continue following the guides, or use another guide of your choice.

I used the following simple URLs:


All good, tested and working!🙂

A note from my own experiences: ARR is VERY STRICT regarding the URL rewrite rules. If something isn’t working, be sure to double check the rules!




I wasn’t quite sure if there was a need for a separate mobility chapter as I’ve covered this area quite well in the DNS and certificate chapters. I guess a couple of lines won’t do no harm however. I’ll once again start by giving you a nice list of homework/reading: (deleting cache)

Much of the mobility stuff has to do with the fact that the mobility service isn’t working properly via lyncdiscoverinternal. Instead you configure the mobile devices to go the external way, via the reverse proxy. See the following picture:


Fig 12. Lync mobility (source:

The mobility bit was a big headache, but in the end we got it working in a desirable way. The secret was to remove from the internal DNS (against many recommendations). See the DNS chapter for more information.




We’re definitely interested in federation, but we haven’t federated with any partners yet. It’s no harm reading about federation though, and in the end it will be much easier setting it up once you’ve done your homework. I’ve done my homework, so why wouldn’t you🙂 Here you go:

The Edge server is already enabled for federation, but the front-end is not. This is easily fixed in the Topology builder once we/you decide to federate:


Fig 13. Enable federation on the Front-end.

In addition to this, it’s also recommended that you add a DNS SRV record (



And finally here’s a screenshot I took sometime in the middle of the whole deployment. As I’ve stated before, there were lots and lots of googling and homework to be done🙂


Fig 14. Google is your friend. Don’t believe everything you read though…

That’s Firefox with Tab Mix Plus and Multirow Bookmarks Toolbar Plus Extensions, btw.


This quite much summarizes the Lync Edge and Reverse Proxy server deployment. Hope you’ve enjoyed reading🙂

Get Programs and Features script

I was trying to find a good method/script to (remotely) get all the installed programs from a Windows 7 client. I didn’t want to use Remote Desktop or similar however, so it had to be a method that was unnoticeable for the user. I know that SCCM has its own software inventory, but I wanted a fast(er) way to check if version XXX of Office is installed on a client. The reason for this was mainly because there are (unfortunately) soooo many different Office installations throughout the whole University. (Also, it’s nice to have some clues about the client before SCCM starts using its magic). The script lists more than (Office) installations however, including other useful information as well. It is based on

and It basically queries the registry of a remote client and returns the installed software. Cheers to the author Anthony Howell!

This modified version also lists:

  • Colored headings🙂
  • OS Name
  • OS Version
  • System Model
  • Total Physical Memory
  • Original Install Date
  • Uptime/System Boot Time
  • Current logged on user

Usage: .\get_programs_and_features.ps1 computername.

Here’s a screenshot with example output:


Fig 1. get_programs_and_features.ps1


The text in the screenshot is in Swedish, but it should be quite self explanatory🙂

If you want to have a go yourself, the script looks like this (download link at the bottom):

        [string[]]$Name = $env:COMPUTERNAME
        $LMkeys = “Software\Microsoft\Windows\CurrentVersion\Uninstall”,”SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall”
        $LMtype = [Microsoft.Win32.RegistryHive]::LocalMachine
        $CUkeys = “Software\Microsoft\Windows\CurrentVersion\Uninstall”
        $CUtype = [Microsoft.Win32.RegistryHive]::CurrentUser
        ForEach($Computer in $Name)
            write-host “Information om datorn: ” $Computer -foreground “magenta”
            $datastring= systeminfo /s $Computer
            $datastring | find “OS Name”
            $datastring | find “OS Version”
            $datastring | find “System Model”           
            $datastring | find “Total Physical Memory”
            $datastring | find “Original Install Date”           
            $datastring | find “System Boot Time”
            write-host “Inloggad person för tillfället (console): ” -foreground “magenta”
            qwinsta /server:$Computer
            $MasterKeys = @()
            If(!(Test-Connection -ComputerName $Computer -count 1 -quiet))
                Write-Error -Message “Unable to contact $Computer. Please verify its network connectivity and try again.” -Category ObjectNotFound -TargetObject $Computer
            $CURegKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($CUtype,$computer)
            $LMRegKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($LMtype,$computer)
            ForEach($Key in $LMkeys)
                $RegKey = $LMRegKey.OpenSubkey($key)
                If($RegKey -ne $null)
                    ForEach($subName in $RegKey.getsubkeynames())
                        foreach($sub in $RegKey.opensubkey($subName))
                            $MasterKeys += (New-Object PSObject -Property @{
                            “ComputerName” = $Computer
                            “Name” = $sub.getvalue(“displayname”)
                            “SystemComponent” = $sub.getvalue(“systemcomponent”)
                            “ParentKeyName” = $sub.getvalue(“parentkeyname”)
                            “Version” = $sub.getvalue(“DisplayVersion”)
                            “UninstallCommand” = $sub.getvalue(“UninstallString”)
            ForEach($Key in $CUKeys)
                $RegKey = $CURegKey.OpenSubkey($Key)
                If($RegKey -ne $null)
                    ForEach($subName in $RegKey.getsubkeynames())
                        foreach($sub in $RegKey.opensubkey($subName))
                            $MasterKeys += (New-Object PSObject -Property @{
                            “ComputerName” = $Computer
                            “Name” = $sub.getvalue(“displayname”)
                            “SystemComponent” = $sub.getvalue(“systemcomponent”)
                            “ParentKeyName” = $sub.getvalue(“parentkeyname”)
                            “Version” = $sub.getvalue(“DisplayVersion”)
                            “UninstallCommand” = $sub.getvalue(“UninstallString”)
            $MasterKeys = ($MasterKeys | Where {$_.Name -ne $Null -AND $_.SystemComponent -ne “1” -AND $_.ParentKeyName -eq $Null} | select Name,Version | sort Name)
            write-host “Har följande program installerade:” -foreground “magenta”


Downloadable version (translated to English):

Installing SharePoint 2013 in a two-tier topology

I got the task of installing SharePoint 2013 for a small business. The SharePoint site won’t be used by that many people simultaneously, so the server load will remain quite small. With that in mind I had to figure out a suitable topology. There are many, many sources on the web describing this, so getting information wasn’t a problem. In the end, I decided to go with a two-tier topology. A single-tier would have been sufficient, but It’s nice to have a separate SQL-server which can be used by other applications/servers as well.

“In a two-tier deployment, SharePoint 2013 components and the database are installed on separate servers. This kind of deployment maps to what is called a small farm. The front-end Web servers are on the first tier and the database server is located on the second tier. In the computer industry, the first tier is known as the Web tier. The database server is known as the database tier or database back-end”.


Another useful link: (you’ll find a nice document/pdf describing Streamlined Topologies for SharePoint 2013). The document states that a two-tier farm is sufficient for up to 10.000 users. More than enough in my case.

My installation is actually based on, even though I would call this a two-tier topology and not three. The SQL-guide from this post is not used, as it suggest installing every component (which is unnecessary). Shortly said there are only two servers included in my setup, namely:

  • SharePoint 2013 (more about features and roles later in the document)
  • SQL Server 2014 Standard

I won’t go into the hardware details of the servers themselves because it varies so much from deployment to deployment. It’s easy to scale out with more memory or better/faster SAN-disks if you have the need for it in the near future. It’s also a good idea to read the following information before installing:


AD Accounts for SharePoint and SQL

My first task was to create the needed service accounts in Active Directory. There’s a very good site describing the needed accounts at I only used

  • sp_install (SharePoint installation)
  • sp_farm (SharePoint Farm Account)
  • ​sql_install (SQL server installation account)
  • ​sql_user (SQL user account)

from the list. Later I created an account named sp_srv for running miscellaneous services. This is more than plenty for such a small deployment. You can read more about service accounts here:

SharePoint 2013 Service Accounts Best Practices Explained: (I’m using medium security option)

Initial deployment administrative and service accounts in SharePoint 2013:

SharePoint 2013: Service Accounts:


SQL Server 2014

Next on the checklist was the installation of SQL Server 2014. SQL is a requirement for SharePoint so it should be installed before you install SharePoint itself. I decided to go with as a base for my installation. Before installing, I also suggest reading the following (you can never be too prepared):

A simple install of SQL Server 2012 for SharePoint Server 2013 or 2010:

Instruction Guide for Installing SQL Server 2012 SP1 for SharePoint 2013:

Install SharePoint 2013 – Part 4 SQL Server:

Service Account Suggestions for SharePoint 2013:

“The SQL Guy” Post #15: Best Practices For Using SQL Server Service Accounts:



After doing some homework (reading articles) I came up with the idea of using SQL with a Named Instance (with SQL-aliases for SharePoint) instead of the Default Instance. I also thought of blocking the default SQL port and using a new static one (configured by SQL aliases). All of this to get better security. I buried this idea however, and instead running with the Default Instance following this guide: (The server itself is already quite well firewalled by a hardware firewall). Some more information regarding the same matter:

Best practices for SQL Server in a SharePoint Server farm:

Blocking the standard SQL Server ports:

Configure SQL Server security for SharePoint 2013 environments:

If one ever decide to use SQL aliases, it’s advisable to read the following document:

I secured the SQL server using “server isolation” instead.

“Server Isolation can be done several different ways, but the end result is the same: configuring the server to only respond to authorized machines.”


In my environment, I’m only allowing traffic from the soon-to-be installed SharePoint server (using the above method).



With the security taken care of, it’s finally time for installation! Following the guide I mentioned earlier (, I went through the steps. I got a firewall warning in the setup (Fig 1), but it was easily fixed by poking a hole in the windows firewall (Fig 2).


Fig 1. SQL Server 2014 Setup warning



Fig 2. Poking a hole in the firewall (Added the SharePoint server IP).

Next step:

  • Enabled Server Feature: .NET Framework 3.5 (needed for SQL server installation)

Continued the setup:

  • SQL Server Feature selection:
    • Database Engine Services
    • Management Tools – Complete
  • That’s it, no extra crap;

“After selecting SQL Server Feature Installation and clicking Next, a list of SQL Server features is displayed, as shown in Figure X. We really need only one SQL Server feature for SharePoint: Database Engine Services. However, I will also install the Management Tools (Complete) feature, which gives you handy tools such as SQL Server Management Studio. As you browse through the list of features, you might be tempted to check more features than you really need. But unless you’re going to use a particular feature immediately, I don’t recommend installing it. If you want to add a feature later, such as SQL Server Reporting Services, you can just run Setup again and add the feature to your existing instance.”

Source (again):

Server Configuration/Service Accounts:

  • SQL Server Agent and SQL Server Database Engine: sql_user (the AD account created earlier).

Database Engine Configuration/Specify SQL Server Administrators:

  • myadminaccount and sql_install (the AD account created earlier).

I’m using the default installation paths for SQL as this is a small scale installation.

Installation complete!



All tweaks are based on the following articles:

  • Max degree of parallelism = 1
  • Maximum server memory 3.5GB (out of 4GB)
  • Model Database’s Recovery Model: simple
  • Compressed backups
  • Also adding the sp_install user to SQL, see below:

“To give the sp_install account the permissions it needs, in SSMS navigate to Security, Logins in Object Explorer. Right-click and select New Login. Under General, type the username and make sure you include the domain. Then on the Server Roles page, shown in Figure 3, select the dbcreator and securityadmin check boxes and verify that the public check box is still selected. Then click OK.”


Fig 3. Assigning Permissions to the sp_install Account

“Let me offer a few words of advice about setting the sp_install permissions. SharePoint assumes that those three roles, dbcreator, public, and securityadmin, have the default set of permissions in SQL Server. Don’t alter those permissions. I’ve seen DBAs in very secure environments try to lock down these three roles. Doing so will most certainly break SharePoint in crazy and unusual ways. That might not happen right away, and it might not happen to you when you’re using the interface. It could be a monthly timer job that fails, for instance. Also, don’t change any SQL Server permissions that SharePoint sets. SharePoint is very fussy, and if it sets permissions, it really needs them. Because of SharePoint’s rigidity on its SQL Server permissions, I recommend that you put SharePoint in its own SQL Server instance. SharePoint will thank you, and so will your DBAs.”


That’s it for SQL, moving on to the SharePoint installation.



SharePoint Server 2013 installation

I’m being a bit lazy now and just copy/pasting information… why rewrite something that someone has already written (well)?

SharePoint Server 2013 checklist:

Before you begin to install and configure SharePoint 2013, do the following:


Everything in order, let’s continue! (Again, the installation is quite much based on

Well, I didn’t get so far. The prerequisite checker failed with the message: Application Server Role, Web Server (IIS) Role: configuration error.

A suggested solution was to install a hotfix from Microsoft; This didn’t work however, as the fix was only for Windows Server 2012, NOT the R2 version. Next test was to follow a guide from

Steps to fix (Installing .Net Framework 3.5):

  1. Insert the Windows Server 2012 installation image or DVD
  2. Open a command prompt window (run as Administrator) and run the following:
  3. Dism /online /enable-feature /featurename:NetFX3 /All /Source:D:\sources\SxS /LimitAccess


Fig 4. Success!🙂


Continuing with the setup…


Fig 5. Complete installation (production). Using default file locations (because small scale installation).

Done. The SharePoint Configuration Wizard will then run:


Fig 6. Create a new farm



Fig 7. Database settings. Database server and account settings were discussed in the SQL chapter.



Fig 8. SharePoint Central Administration Web Application

Port 18811 (or whatever SharePoint chooses for you) must be blocked (outside the domain), otherwise the Central Administration URL will be open for anyone on the Internet.



Fig 9. Completing the configuration wizard



Fig 10. Configuration successful!



There are A LOT of different services running on a SharePoint server. However, in a small scale environment, you’ll probably only need/use a few of these. I took a look at the old server and compared the services running there. Here’s a screenshot of SharePoint 2010 and its active services:


Fig 11. SharePoint 2010 services

From the screenshot we can see that the following services are running:

  • Central Administration
  • SharePoint Foundation incoming E-Mail
  • SharePoint Foundation Web Application
  • SharePoint Foundation Workflow Timer Service

With this in mind, I tried to keep the services at a minimum on the SharePoint 2013 server as well.

I couldn’t find the exact same ones in 2013, but I decided to go with the following:


Fig 12. SharePoint 2013 services

  • Search Service Application
  • State Service
  • Usage and Health data collection


After SharePoint had configured itself I was greeted with a message that some services are running with the “wrong” accounts (Fig 13).


Fig 13. SharePoint Failing Services

The failing services are:

  • SharePoint Central Administration v4 (Application Pool)
  • SPTimerV4(Windows Service) = Farm
  • AppFabricCachingService (Windows Service)


My idea was to run the default SharePoint services with the “sp_farm” account. Other services can be run with the “sp_srv” account if/when needed.

Update: It’s not recommended running the Wizard, instead you should manually configure the settings.


You change the account settings in SharePoint –> Central Administration –> Configure service accounts. I changed the farm account to “sp_farm”. Everything more or less broke after that😦 I had to do some googling to get it up running again.

Solution (before changing farm account to sp_farm):

  • Register the account (sp_farm) as a managed account. To change a managed account password go to Central Admin > Security > Configure Managed Accounts (/_admin/MangedAccounts.aspx). Click the Edit icon next to the account whose password you want to change.


           Fig 14. Register Managed Account.

  • Go to the Configure Service Accounts page and Select the Farm Account and set the new managed account
  • Reboot the server.



Done. SharePoint is now installed🙂



You shouldn’t use http with SharePoint outside your domain. Instead you should use https (http over SSL). Request a certificate for your SharePoint site from a 3rd party certificate issuer (or similar), and then apply the certificate. You could/should also use http redirection (http –> https) and/or Alternate Access Mappings. You can follow these guides for example:

Deploying Office 2016 and Office Proofing Tools Kit 2016 / Office 2016 language packs with SCCM 2012 R2

I recently deployed Office 2013 SP1 (and wrote a blog post about it). Now I got the honours to do the same for Office 2016. The procedure is theoretically quite the same, but with many different bugs and gotchas. The following procedure describes how to remove any previous versions of Office and corresponding Proofing tools & language packs and replace them with Office 2016 versions. I’ll dive right into the steps:

Customizing Office 2016

  • Got a copy of Office 2016 and extracted the iso. Our version is “Professional Plus” with Volume Licensing.
  • Fired up a command prompt and navigated to the extracted Office directory.
  • From here I ran “setup.exe /admin”  to launch the Office Customization Tool (OCT).
  • Customized the OCT settings according to our needs:
    • Setup/Organization Name
    • Setup/Licensing and user interface/Use KMS client key
    • Setup/Licensing and user interface/I accept the terms in the License Agreement, Display level: None, No tick in Competition notice, Tick for Suppress modal and No cancel.
    • Setup/Remove previous installations/Remove the following earlier versions of Microsoft Office Programs/Remove all (here’s a BUG btw, more on that later on).
    • Setup/Modify Setup Properties:
      • SETUP_REBOOT, value Never
    • Features/Modify user settings:
    • Features/Set feature installation states:
      • Everything gets installed.
    • Additional content/Configure shortcuts
      • For some weird reason, Office 2016 by default decides to put all of the shortcuts on the start menu WITHOUT a subdirectory – splattered all over the start menu. This is fixable by editing the shortcut entries. In Fig 2. below, I’ve added the path/directory \Microsoft Office 2016. You also have to add a “[“ in Start in, otherwise you can’t close the dialog box. It’s a “feature” (bug), see: While editing, you can also decide which shortcuts you want to put on the Desktop. In Fig 2, I’ve chosen to put the Excel shortcut on both the Desktop ([DesktopFolder]) and in the Start menu ([ProgramMenuFolder]\Microsoft Office 2016).
    • Update: More bugs, sigh. Skype for Business shortcut launches “Skype for Business Recording Manager” instead of “Skype for Business”. I’m getting very frustrated with all the bugs. See: Anyways, I corrected the mistake MS has made. In Fig 3 target should definitely not be Skype for Business Recording Manger, instead it should be “Skype for Business 2016”. At least so I thought. After this “fix” (and a test-deployment), my reward was the following message:


                   Fig 1. Problem with shortcut

      • Only solution (as I can see it), is to force-copy a “functional shortcut icon” during deployment. With functional I mean a shortcut that has been manually created from C:\Program Files (x86)\Microsoft Office\Office16\lync.exe. (You should also remove all the Skype for Business shortcut entries in OCT).
        • This shortcut will then be deployed as a dependency. See later chapter about dependencies.


                    Fig 2. Office 2016 OCT.


                   Fig 3. Skype for Business – example shortcut entry.



Deploying Office 2016/Removing Office 2013/2010

The deployment part was quite straight forward after the customization part was done. Well, so I thought. Instead I got to fiddle with SCCM’s supersedence and dependencies. More on that later on. As with Office 2013, I basically followed a (very good) guide from with some changes for our environment. In this case the changes were about uninstalling Office 2013 SP1, as a fully patched Office 2013 SP1 WON’T get uninstalled even though I’ve chosen to remove previous versions in the OCT (see my (unanswered) post at The remove previous version-feature works with Office 2010 however, which means I don’t have to create a supersedence relation for that version (luckily).


Checking parameters for Office 2013 uninstallation:

In order for Office 2013 SP1 to be silently removed via SCCM before you install Office 2016, you have to be sure that the uninstall string is correct and a custom xml-file is in place. I’m already using “custom.xml” (together with OCT) for the installation part, so I’ve created a custom2.xml for the uninstallation part. (The reason for this is also a bug, see my Office 2013 deployment post). This file contains only the following information:

<Configuration Product=”ProPlus”>
<Display Level=”none” CompletionNotice=”no” SuppressModal=”yes” AcceptEula=”yes” />

You’ll then use this xml file when you specify the uninstall string for Office 2013 SP1 in SCCM. See for details. If you don’t specify a xml file, the uninstallation won’t be silent. This in turn means it won’t be successful.



With all the parameters done, you can now deploy Office 2016 using Office 2013 as Supersedence (see screenshot below):


Fig 4. Supersedence.


All of the fields aren’t visible in the screenshot, but the fields are:

This application supersedes the following applications:

Application: Microsoft Office 2013 SP1
Old Deployment Type: Microsoft Office Professional Plus 2013 SP1 installer
Replacement Deployment Type: Microsoft Office Professional Plus 2016 installer
Active: Yes
Uninstall: Yes (Tick in the box)

That’s it! All the other options are the same as with a regular deployment, you just add the Supersedence-information (so Office 2013 SP1 can be successfully removed while installing Office 2016). This would not be successful without having specified the correct uninstallation information/parameters for Office 2013 SP1.

A general rule of thumb when using supersedence is that you must have the correct uninstall information specified for the application that will be superseded!


Update! I had problems deploying Office as “available”. (“Required” was working ok though). I always got the message “Past due – will be updated”  in Software Center (see Fig 5). This on the other hand made Office upgrade itself without user interaction, which was not acceptable for a deployment that was made available (NOT required).


Fig 5. Past due – will be updated.

After some googling I found out it was related to the supersedence settings. Don’t know if you can call this a bug, but at least it was working better if I followed this advice:

“Regarding the issue where you have set the application to AVAILABLE in the deployment, however the application uninstalls and upgrades without user interaction, I have found a work around.

The cause of the problem seems to be when you are deploying an application to a collection the option “automatically upgrade any superseded versions of this application” is CHECKED and GREYED out. If you deploy the application BEFORE you have added the supersedence, this will NOT be greyed out and you will be able to leave it unchecked. Then add the supersedence rules.

Hope this helps



I mentioned the word better because even now it wasn’t working 100% correct. I had to click “Install” in Software Center about 3-4 times (for all the dependent applications). This wasn’t acceptable, as the software (and all its dependencies) should install with just ONE click. Well, I found the solution to this dilemma myself – just leave one checkbox unticked. (See Fig 6).


Fig 6. Supersedence checkbox.

With all this done, the deployment was running smoothly with just one click (“Install”) in Software Center.



Customizing Office Proofing Tools Kit 2016

This is actually the exact same procedure as for Proofing Tools 2013. I’ll copy/paste the information from my previous blog post:

We are using a Proofing Tools “CD” which include all of the proofing tool languages. Proofing Tools doesn’t/can’t change the UI language btw, only check the spelling. With this CD, there’s no need to separately download each proofing tool language. After some googling I stumbled upon which seemed useful. Once again I’ll share my configuration so you don’t have to scratch your own head. First off, there’s NO “setup.exe /admin” on this cd/iso. You have to manually specify the languages (proofing) you need. The file you need to edit is located on the extracted iso, in my case \Office_2016_Proofing_Tools\proofkit.ww\config.xml. My file looks like this:

<Configuration Product=”Proofkit”>

   <Display Level=”none” CompletionNotice=”no” SuppressModal=”yes” AcceptEula=”yes” />
   <COMPANYNAME Value=”Abo Akademi” />
   <OptionState Id=”ProofingTools_1053″ State=”local” Children=”force” />
   <OptionState Id=”ProofingTools_1030″ State=”local” Children=”force” />
   <OptionState Id=”ProofingTools_1035″ State=”local” Children=”force” />
   <OptionState Id=”ProofingTools_1036″ State=”local” Children=”force” />
   <OptionState Id=”ProofingTools_1031″ State=”local” Children=”force” />
   <OptionState Id=”ProofingTools_1032″ State=”local” Children=”force” />
   <OptionState Id=”ProofingTools_1040″ State=”local” Children=”force” />
   <OptionState Id=”ProofingTools_1044″ State=”local” Children=”force” />
   <OptionState Id=”ProofingTools_2068″ State=”local” Children=”force” />
   <OptionState Id=”ProofingTools_1045″ State=”local” Children=”force” />
   <OptionState Id=”ProofingTools_1049″ State=”local” Children=”force” />
   <OptionState Id=”ProofingTools_1048″ State=”local” Children=”force” />
   <Setting Id=”SETUP_REBOOT” Value=”Never” />

This bypasses all prompts in the setup process and installs 12 proofing languages. I’m not going to list the languages here (OptionState Id values), as there’s a table is available at: . That’s it for the configuration – now ready for deployment.

Source: plus all the forgotten ones…



Deploying Office Proofing Tools Kit 2016/Removing Proofing Tools Kit 2013/2010

Again, this information is already available in my previous blog post about deploying Office Proofing Tools 2013 SP1, so please have a look there before you continue. The difference in the 2016 version is that I will use different dependencies so that Office and the language packs will be installed before proofing tools is installed. I’ll also use Supersedence the same way I did with Office 2016 above.


Checking parameters for Proofing Tools Kit 2013 SP1 uninstallation:

First off, I’ll copy/paste information about the installation:

Edit “programs” tab. The installation command should now include our custom.xml instead of the MSI-command. The command I used was: setup.exe /config \\sccm2012r2\Software\Office_2013_Proofing_Tools_with_Service_Pack_1\proofkit.ww\config.xml.  ( /config .\proofkit.ww\config.xml is an easier/better syntax, btw)

Ok – now you just have to add the uninstall information with a custom UNintallation xml-file. This is also the same procedure as with the Office 2016 deployment. Anyway, I created a custom2.xml file in the same location as mentioned above. It includes basically the same information as the Office 2013 SP1 uninstallation xml-file:

<Configuration Product=”Proofkit“>
   <Display Level=”none” CompletionNotice=”no” SuppressModal=”yes” AcceptEula=”yes” />

…and for the uninstall program string I’m using: setup.exe /uninstall Proofkit /config .\proofkit.ww\config2.xml

There you have it. Both the install and the uninstall information are now specified. You can now go ahead and make the same Supersedence rules as with the Office 2016 deployment:


Fig 7. Office 2016 Proofing Tools Kit – Supersedence.

Only thing that isn’t fully visible in the screenshot above is Application: Microsoft Office Proofing Tools 2013 SP1 – multilanguage.


You can now do the same thing with Office 2010 (proofing tools) if you want to uninstall/remove that version prior to installing proofing tools 2016. You’ll then add another supersedence rule so that BOTH Office 2010 proofing tools AND Office 2013 proofing tools will be superseded (both should then be in the list in Fig 7).

(I also specified the uninstallation information for Office 2016 (proofing tools) already, so I can (hopefully) use the same procedure with future versions of Microsoft Office).



Deploying Office 2016 language packs/Removing Office 2013/2010 language packs

Some people are also using language packs with Office so I had to figure out a way of uninstalling/replacing these with the 2016 versions. Luckily, Microsoft is using quite the same syntax as with proofing tools, so the task was actually quite simple. You start with the same procedure – checking for a valid config.xml file for installation and uninstallation. The difference here is that you don’t need any specific codes for the language(s), as one language pack only installs one specific language. Another nice thing is that you can use the SAME xml file for both the installation and the uninstallation. The custom.xml for the Swedish language looks like this for example:

<Configuration Product=”“>
<Display Level=”none” CompletionNotice=”no” SuppressModal=”yes” AcceptEula=”yes” />

That’s the only thing you need to add/edit to make it silent. The paths for the files are a bit different than with Proofing tools though. The xml file is in .\ (or omui.xx.xx for your own language). The MSI-file used for deployment (or actually only for getting the product code) is in the same directory. The installation and uninstallation strings are also a bit different. Let me show you some screenshots and whatnot from SCCM;

First off you create a new application and make it think it’s going to use a MSI file for installation. You do it like this only to get the detection method/MSI product code.


Fig 8. Create Application Wizard.

Use the path:

\\yoursccmserver\yoursoftwarestash\Microsoft Office 2016 Multilang Pack Swedish\ (or similar for another language) and select the file OMUI.msi

Then just next, next, next through the wizard.


After this, you edit the Deployment Type. First off, go to the Content location. This path will be wrong (as the msi file is located in the -directory). Please REMOVE “” from the content location path. That’s it for content.


Fig 9. Office 2016 Swedish language pack content location.


Then you move over to the “Programs” tab. Here’s where the magic happens. Remove all the text/strings from installation program and uninstallation program. Replace the text with the one from Fig 10 below.


Fig 10. Programs tab. Same xml is used for both installation and uninstallation (even though it got cut off in the screenshot).

In case you want to copy/paste, the strings are:

Installation program: setup.exe /config .\\config.xml
Uninstall program: setup.exe /uninstall /config .\\config.xml




You can now do the same thing with Office 2010 language packs if you want to uninstall/remove that version prior to installing the 2016 language packs. You’ll then add another supersedence rule so that BOTH Office 2010 language pack AND Office 2013 language pack will be superseded.




There you have it. You’ve created separate SCCM applications for Office 2016, Office 2016 Proofing tools and Office 2016 language packs. That’s very nice and all, but you probably don’t like deploying all three applications separately, now do you? Well, this is where dependencies comes into play.

In my final deployment I ONLY deploy Office 2016 Proofing Tools. Office 2016 (main office application) is a dependency of Proofing tools, and so are the language packs. See Fig 11 for details.

NOTE! Create THREE SEPARATE dependency groups, otherwise there will be an “OR” statement instead of “AND”. I learned this the hard way when the language packs wouldn’t install. See the right and the wrong way to create the dependencies below:   


Fig 11. Office 2016 Proofing Tools dependencies, the CORRECT way.



Fig 12. Office 2016 Proofing Tools dependencies, the WRONG way.


Update! As there is a bug with the Skype for Business shortcut icon, the shortcut will also be deployed as a dependency.

  • First, create a new directory for your application (script) on your sccm server. Call it “Office2016-Skype for Business-shortcut” for example.
  • Copy the Skype for Business 2016-custom shortcut (created in the Customizing Office 2016 part) to this directory.
  • Create two new PowerShell script files in this directory;
    • Name the scripts Office2016-Skype for business-shortcut.ps1 and Office2016-Skype for business-shortcut-uninstall.ps1 for example.
      • Contents of Office2016-Skype for business-shortcut.ps1:

copy “Skype for Business 2016.lnk” “C:\Users\Public\Desktop\Skype for Business 2016.lnk”
copy “Skype for Business 2016.lnk” “C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Microsoft Office 2016\Skype for Business 2016.lnk”

      • Contents of Office2016-Skype for business-shortcut-uninstall.ps1:

del “C:\Users\Public\Desktop\Skype for Business 2016.lnk”
del “C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Microsoft Office 2016\Skype for Business 2016.lnk”


Create a new application using the following information:

  • Create Application
  • Manually specify the application information
  • Name: whatever you like
  • Deployment Types:
    • Type: Script Installer
    • Manually specify the deployment type information
    • Name: whatever you like
    • Content location: wherever you store your applications, in a subdirectory called “Office2016-Skype for Business-shortcut” for example
    • Installation program: powershell.exe -executionpolicy Bypass -file “Office2016-Skype for business-shortcut.ps1”
    • Uninstallation program: powershell.exe -executionpolicy Bypass –file “Office2016-Skype for business-shortcut-uninstall.ps1”
    • Detection method: Setting type: File System: C:\Users\Public\Desktop\Skype for Business 2016.lnk AND C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Microsoft Office 2016\Skype for Business 2016.lnk exist.
    • Install for system, whether or not a user is logged on, hidden.

With all this done, create yet another dependency group. Add this newly created application to this dependency group. You then have a total of FOUR dependencies.





Let’s sum it up:

  • Actual deployment “object” is Office 2016 proofing tools, which in turn use dependencies (main office application + language packs).
  • Office 2016 supersedes Office 2013.
  • Office 2016/2013 removes/uninstalls Office 2010 via OCT (no supersedence).
  • Proofing tools packages use supersedence to update themselves to the newest versions (2010 –> 2016,  2013->2016).
  • Language pack packages use supersedence to update themselves to the newest versions (2010 –> 2016,  2013->2016).
  • Office 2016 is a dependency of Proofing tools 2016, and so are the language packs (and the Skype for Business shortcut).
  • A shortcut for Skype for Business is created in the Start menu and on the desktop. (It is NOT created via OCT as it creates a faulty one).


And some screenshots:


Fig 13. Downloading all of the needed packages/applications.

The number of downloaded components depend on which Office-components SCCM detects on the client. (Is Office already installed and are only the language packs needed, for example). I’ve now changed the application catalogue name of the “main” application to something more convenient than “Microsoft Office Proofing Tools 2016 – multilanguage”. Currently I’m using “Office 2016 with proofing tools + swe & fi language packs”.



Fig 14. Updating components. One done, seven to go.



Fig 15. Before Office 2016 deployment. Office 2013 SP1 (with Proofing tools and two language packs). Same components are installed if using Office 2010.



Fig 16. After successful Office 2016 deployment. Same thing, new versions🙂


Success!🙂 (Finally… after many, many, many hours of testing)


BTW, feel free to comment if you find this post useful.

Exchange Server Connector (for SCCM)

I was “given” the task of finding an easy way for the IT supporters to check whether or not a user has configured his/her mobile phone (Nokia Lumia) against our Exchange server. We’re checking this mostly because the user agreement states that every user should have an Exchange account configured. With an Exchange account configured, it’s possible (for the Exchange/SCCM Admins) to remotely wipe the phone (among other things).

The Exchange Server Connector is by no means a full blown MDM solution (for SCCM), but it can handle the basic tasks. If you want a solution with all the bells and whistles, have a look at Microsoft Intune instead. On the positive side, Exchange Server Connector is free and Intune is not. Some differences between the MDM solutions can be found here for example:

The above links include tables which will help you decide what mobile device management methods support the mobile device platforms you have in your environment. They can also help you decide between in Depth vs. Light Management and so on. All in all the links gives you an idea of what you can and cannot do with the Exchange Connector.

The short version is that SCCM 2012 (R2) is out-dated in terms of MDM management. You only have support for limited devices by default, check: (Mobile Devices Enrolled by Configuration Manager and Mobile Device Legacy Client). By adding the Exchange Server Connector you’ll get support for more devices (all Exchange Active Sync devices), but the configuration on these devices is limited to the same things that can be configured on the Exchange Server (“light management”). The settings are listed in the table “Choose a mobile device management solution based on management functionality” from the page . As you can see, you can’t install software or make a software inventory but things like Remote wipe and settings management are possible. I’ll attach a screenshot of the things you can configure:


Fig 1. Mobile device access (EAS settings)


Fig 2. Mobile device mailbox policies

These same settings apply to SCCM once you have the connector set up correctly. That said, let’s set it up!



First some reading for you all:

I used tips from the guides but overall it was an easy task. Here are my steps:


Fig 3. Accounts in SCCM

  • Started SCCM, then navigated to Administration –> Overview –> Hierarchy Configuration –> Exchange Server Connectors


Fig 4. Exchange Server Connector.

  • Added a new connector with the default values. Properties from the newly created connector below:


Fig 5. Properties, General

Note: There are problems with the URL if using load balancers. I had to change the URL to one of our CAS servers (and not pointing to the single namespace/autodiscover URL in DNS). Check the problems and gotchas-chapter below for more details.



Fig 6. Properties, Account



Fig 7. Properties, Discovery



Fig 8. Properties, Settings

If you change a setting here, that setting will be changed from Configured by Exchange Server to Configured by Configuration Manager from now on. In other words, you are giving the SCCM server authority to handle these settings instead of Exchange. Also note the “Allow external mobile device management”: xxxxx” –option, and read the text above it. I changed mine to Allowed.



Fig 9. Properties, Access Rules



Theoretically everything should now be set up and working. Unfortunately, that wasn’t the case for me. I immediately noticed that no devices showed up under “Devices/All Mobile Devices” in SCCM. I had configured all steps correctly, and SCCM didn’t complain. Luckily there are logs (EasDisc.log on the SCCM server) so you can have a better understanding what’s going on behind the scenes. That said, I noticed some problems in the log straight away:


Fig 10. EasDisc.log: the problems

Some googling led me to Someone had a similar setup and suggested using the FQDN of one of the CAS servers instead of the NLB URL. Tried that – success!🙂 (almost…)


Fig 11. EasDisc.log: problem solved, everything looks good. Log also reported INFO: Total number of devices discovered 357       SMS_EXCHANGE_CONNECTOR        x.x.2015 11:57:48 which is not visible in the screenshot.


View from SCCM

Let’s have a look at the whole thing in action from SCCM:


Fig 12. All Mobile Devices.



Fig 13. Another view



Everything APPEARED to be working fine now. After a while I noticed it wasn’t. I configured a test-device with my own account, but it DIDN’T show up in Assets and Compliance –> Overview –> Devices –> All Mobile Devices in SCCM (Fig 11). However the list with All Mobile Devices (Fig 10) got updated (correct number of devices). Very strange.

Some head scratching and googling later I ended up at

Well, well, well. Problem with load balancers. Duh. My solution: Added another connector for our second CAS. Well, that didn’t work. It was still showing the same amount of devices😦 My test-device wouldn’t show up either. It was now unfortunately time to state that the Exchange Connector won’t work if you have more than one CAS in your environment. Too bad😦

Update: Currently I’m using an EAS device report script on the Exchange server for collecting miscellaneous information about mobile devices. More on that in a blog post later on…


Search queries in SCCM

(Even though the connector didn’t work as expected, I had already made a couple of queries before noticing the problem…)

It’s always nice to get a list of devices, but in most cases you’ll want to have the list sorted in some way. I was requested to sort our list by the Windows Phone OS. I used a slightly modified query from:


select SMS_R_SYSTEM.ResourceID,SMS_R_SYSTEM.ResourceType,SMS_R_SYSTEM.Name,SMS_R_SYSTEM.SMSUniqueIdentifier,SMS_R_SYSTEM.ResourceDomainORWorkgroup,SMS_R_SYSTEM.Client from SMS_R_System where SMS_R_System.OperatingSystemNameandVersion like “%Windows Phone%

Using this query, I got all Windows Phones listed:


Fig 14. Query for Windows Phones

Instead of using Reporting, I find it much easier to just mark the whole list and copy/paste it into Excel (or another document). Some sort of “export to .csv” right-click plugin for SCCM would be awesome though.