Derek Souter - the grumpy IT Admin
Derek Souter - the grumpy IT Admin


Just a little blog for IT pro's

Monday, 9th July 2018


So, I needed a script to backup the farm configuration for SharePoint.   After fighting with some people that disagreed with the permissions required, we finally got agreement to setup the necessary permissions and the scheduled task.


I used a few bits of code that I found online, and created a script that works in every environment.


It is designed to run on a server that is running Central Administration, and backs up the configuration to a file share that it expects to find on another server also running Central Administration, or to a file share hosted locally.


it will also create both a debug log and a backup log (in a sub-folder) - and cleans up any backups or logs that are older than the specified number of days.


I have also created a very basic work instruction on how to setup the scheduled task.


SharePoint Configuration Backup
PowerShell script that can be run manually or as a scheduled task to backup the Farm Configuration
Text document [12.2 KB]
Instructions to run Scheduled task
follow these very basic instructions to run the backup script as a scheduled task
Backup Work Instructions.docx
Microsoft Word document [18.0 KB]

Thursday, 21st December 2017


Merry Christmas


This week I found myself in need of a populated domain - with several hundred thousand user accounts.


A little bit of digging online led me to a script by Helge Klein (, and a modified version by Rob Bridgeman on GitHub (   


Neither worked exactly for me, so I had to adjust them.


I now have a script that works perfectly in my environment, and I used to create 250000 users spread over 11 OU's.   My next project will be to extend the list of addresses, create some random groups, add the users into the groups at random during the creation process, and maybe create some random OUs as well.


This is my version of a PowerShell script to populate Active Directory with some test user accounts
Demo Users creation.txt
Text document [8.1 KB]
This is one of the backing files required for the PowerShell script
Save it in the same folder as the script
This is the list of Addresses, feel free to extend it - please note, that any postcodes listed in this file must have a matching code in the PostalAreaCode file
Text document [335 Bytes]
This is one of the backing files required for the PowerShell script
Save it in the same folder as the script
This is the list of first names, taken from 1990 US Census data
Text document [40.3 KB]
This is one of the backing files required for the PowerShell script
Save it in the same folder as the script
This is the list of surnames, taken from 1990 US Census data
Text document [634.8 KB]
This is one of the backing files required for the PowerShell script
Save it in the same folder as the script
This is the list of Postcodes, and maps to the telephone number area code, feel free to extend it
Text document [1.4 MB]

#Credit for original script to Helge Klein
#Adapted to allow higher numbers of users with the same information set.

# Summary of changes.
# Reduced Male and Female names into one list for ease of expansion
# Changed Displayname code to create each combination of names possible
# Changed sAMAccountname generation to add unique account ID with orgShortName as suffix.

# Derek Souter - 20/12/2017
# Updated to ensure that both firstnames and lastnames are created randomly
# Added list of OUs, and ensured that users are created randomly within those OUs
# this version was tested to create 250000 users in 11 different OUs

# Known issues
# Usercount (For me anyway) seems to be inaccurate when import completes. May be related to errorcheck compensation when usercount is reduced. Consistently seem to get many more users that intended.

Set-StrictMode -Version 2

Import-Module ActiveDirectory

write-host "import AD"

# Set the working directory to the script's directory
Push-Location (Split-Path ($MyInvocation.MyCommand.Path))

# Global variables
# User properties
$ou = "OU=User Accounts,OU=Accounts,DC=domain,DC=uk"         # Which OU to use as the root to create the users in.   
$initialPassword = "Password1"               # Initial password set for the user
$orgShortName = "TEST"                         # This is used to build a user's sAMAccountName
$dnsDomain = "TEST.DOMAIN"                      # Domain is used for e-mail address and UPN
$company = "Sandbox environment"                           # Used for the user object's company attribute
$departments = (                             # Departments and associated job titles to assign to the users
                  @{"Name" = "Finance & Accounting"; Positions = ("Manager", "Accountant", "Data Entry")},
                  @{"Name" = "Human Resources"; Positions = ("Manager", "Administrator", "Officer", "Coordinator")},
                  @{"Name" = "Sales"; Positions = ("Manager", "Representative", "Consultant")},
                  @{"Name" = "Marketing"; Positions = ("Manager", "Coordinator", "Assistant", "Specialist")},
                  @{"Name" = "Engineering"; Positions = ("Manager", "Engineer", "Scientist")},
                  @{"Name" = "Consulting"; Positions = ("Manager", "Consultant")},
                  @{"Name" = "IT"; Positions = ("Manager", "Engineer", "Technician")},
                  @{"Name" = "Planning"; Positions = ("Manager", "Engineer")},
                  @{"Name" = "Contracts"; Positions = ("Manager", "Coordinator", "Clerk")},
                  @{"Name" = "Purchasing"; Positions = ("Manager", "Coordinator", "Clerk", "Purchaser")}
$OUs = ("AAA","BBB","CCC","DDD","EEE","FFF","GGG","HHH","III","JJJ","KKK")   # OUs to add to the $ou variable to create users in.  this is concatenated with the ou variable later in the script
$phoneCountryCodes = @{"GB" = "+44";"JP" = "+81";"US" = "+01"}         # Country codes for the countries used in the address file

# Other parameters
$userCount = 250000                           # How many users to create
$locationCount = 4                          # How many different offices locations to use

write-host "Creating "$usercount " users in "$locationcount " locations"

# Files used
$firstNameFile = "Firstnames.txt"            # Format: FirstName
$lastNameFile = "Lastnames.txt"              # Format: LastName
$addressFile = "Addresses.txt"               # Format: City,Street,State,PostalCode,Country
$postalAreaFile = "PostalAreaCode.txt"       # Format: PostalCode,PhoneAreaCode

# Read input files
write-host "Importing first names"
$firstNames = Import-CSV $firstNameFile
$firstnamecount = $firstNames.count-1
write-host "Imported "$firstnamecount" first names"

write-host "Importing last names"
$lastNames = Import-CSV $lastNameFile
$lastnamecount = $lastNames.count-1
write-host "Imported "$lastnamecount" last names"

write-host "Importing addresses"
$addresses = Import-CSV $addressFile

write-host "Importing postcodes"
$postalAreaCodesTemp = Import-CSV $postalAreaFile

# Convert the postal & phone area code object list into a hash
$postalAreaCodes = @{}
foreach ($row in $postalAreaCodesTemp)
   $postalAreaCodes[$row.PostalCode] = $row.PhoneAreaCode
$postalAreaCodesTemp = $null

# Preparation
$securePassword = ConvertTo-SecureString -AsPlainText $initialPassword -Force

# Select the configured number of locations from the address list
$locations = @()
$addressIndexesUsed = @()
for ($i = 0; $i -le $locationCount; $i++)
   write-host "setting a random address"
   # Determine a random address
   $addressIndex = -1
      $addressIndex = Get-Random -Minimum 0 -Maximum $addresses.Count
   } while ($addressIndexesUsed -contains $addressIndex)
   # Store the address in a location variable
   $street = $addresses[$addressIndex].Street
   $city = $addresses[$addressIndex].City
   $state = $addresses[$addressIndex].State
   $postalCode = $addresses[$addressIndex].PostalCode
   $country = $addresses[$addressIndex].Country
   $locations += @{"Street" = $street; "City" = $city; "State" = $state; "PostalCode" = $postalCode; "Country" = $country}
   # Do not use this address again
   $addressIndexesUsed += $addressIndex

# Create the users

# Randomly determine this user's properties
# Sex & name
$i = 0
write-host "set user"
while ($i -lt $userCount) 
    $FirstnameIndex = Get-Random -Minimum 0 -Maximum $firstNames.count
    $LastNameIndex = Get-Random -Minimum 0 -Maximum $lastnames.count
    $Fname = $firstnames[$FirstnameIndex].Firstname
    $Lname = $lastNames[$LastNameIndex].Lastname

    $displayName = $Fname + " " + $Lname

   # Address
   $locationIndex = Get-Random -Minimum 0 -Maximum $locations.Count
   $street = $locations[$locationIndex].Street
   $city = $locations[$locationIndex].City
   $state = $locations[$locationIndex].State
   $postalCode = $locations[$locationIndex].PostalCode
   $country = $locations[$locationIndex].Country
   # Department & title
   $departmentIndex = Get-Random -Minimum 0 -Maximum $departments.Count
   $department = $departments[$departmentIndex].Name
   $title = $departments[$departmentIndex].Positions[$(Get-Random -Minimum 0 -Maximum $departments[$departmentIndex].Positions.Count)]

   # OU to place
   $UserOUIndex = Get-Random -Minimum 0 -Maximum $ous.count
   $UserOU = $OUs[$UserOUIndex]
   $fullUserOU = -join("OU=",$UserOU,",",$OU)

   # Phone number
   if (-not $phoneCountryCodes.ContainsKey($country))
      "ERROR: No country code found for $country"
   if (-not $postalAreaCodes.ContainsKey($postalCode))
      "ERROR: No country code found for $country"
   $officePhone = $phoneCountryCodes[$country] + "-" + $postalAreaCodes[$postalCode].Substring(1) + "-" + (Get-Random -Minimum 100000 -Maximum 1000000)
   # Build the sAMAccountName: $orgShortName + employee number
   $employeeNumber = Get-Random -Minimum 100000 -Maximum 1000000
   $sAMAccountName = $orgShortName + $employeeNumber
   $userExists = $false
   Try   { $userExists = Get-ADUser -LDAPFilter "(sAMAccountName=$sAMAccountName)" }
   Catch { }
   if ($userExists)
      if ($i -lt 0)

   # Create the user account
      New-ADUser -SamAccountName $sAMAccountName -Name $displayName -Path $fulluserou -AccountPassword $securePassword -Enabled $true -GivenName $Fname -Surname $Lname -DisplayName $displayName -EmailAddress "$Fname.$Lname@$dnsDomain" -StreetAddress $street -City $city -PostalCode $postalCode -State $state -Country $country -UserPrincipalName "$sAMAccountName@$dnsDomain" -Company $company -Department $department -EmployeeNumber $employeeNumber -Title $title -OfficePhone $officePhone

   "Created user #" + ($i+1) + ", $displayName, $sAMAccountName, $title, $department, $street, $city"
   $i = $i+1
   #$employeeNumber = $employeeNumber+1

      if ($i -ge $userCount) 
       "Script Complete. Exiting"

Friday, 24th November 2017



SharePoint 2013 - change license key


A large part of my job is working on SharePoint 2013 environments, many of which were installed with the incorrect (Standard) License key.


After some major issues changing from a Standard to an Enterprise license key, I came up with a very simple method that works for me - YMMV


1.  Logon to the SharePoint Central Admin server

2.  Select "Upgrade and Migration"

3.  Select "Enable Enterprise Features"

4.  Select the radio button for Enterprise

5.  Enter the Enterprise key

6.  Click OK

7.  wait until the error message is displayed

8.  Open a SharePoint PowerShell as an administrator

9.  Enter the command "set-spfarmconfig -InstalledProductRefresh"

10.  Go back to the SharePoint Central Admin server

11.  Select "Upgrade and Migration"

12.  Select "Enable Features on Existing Sites"

13.  Wait for it to complete


you should now have changed to an enterprise license key

Wednesday, 24th May 2017


Wannacry Virus


I really wish the media would stop calling the Wannacry virus a "hack" or saying it was an attack on the NHS.  

It was a nasty virus that was sent to hundreds of millions of email addresses across the globe. 

People opened the attachment (these are generally either a macro enabled word document or a PDF), allowed the embedded script to run, which then went off to the internet to download the really bad payload which then infects the local machine, which then went off to the local network to infect any vulnerable unpatched systems it could find.  

The NHS  IT staff  were in compliance of UK government regulations regarding patching (all critical and security patches  must be installed within 3 months of release by vendor). 

The patch had been released the month before by Microsoft, and was probably still being rolled out to the test systems, before being deployed to all live systems.


If you want to stop this sort of thing from affecting your network, you can do various things - but none of them individually will work


1.            Have decent perimeter email scanning in place, to limit the number of spam and infected emails that get in to your organisation.

2.            Have security policies in place to stop word documents running macros (same for PDF files).

3.            Have a proxy server that can scan for malicious payloads in the downloads – and maybe even redirect any unusual web requests to a confirmation page before allowing access.

4.            Use the security tools provided to limit the access users have to only what is required to do their job – do they need to be able to delete files from a specific network share?

5.            Use Windows File Filters on the server to prevent the creation of the encrypted file types (it is hard to keep up, but there is currently no easy way to limit the creation of files to an allowed list of file types - file screens are good, but not perfect) – currently the ransomware will not delete the files if it cannot encrypt them (that is likely to change soon).

6.            Ensure you have a decent backup strategy for your data – make sure you know where it is, and that it can be recovered quickly and easily.  Assume that you WILL get hit with something at some point, plan for it.

7.            Train the staff in identifying spam and possibly infected emails, and what not to do with the attachments – they are your first line of defence, and “oh, I don’t really know about computers” is not a decent response in this day and age – sorry people, but if you use a computer every day, you should know at least some basics in how to protect yourself.

8.            Listen to your IT department – they are not simply a cost to your business, often they are the ones keeping everything running so that everyone else can do their job.    And if you constantly ignore their suggestions, then they will stop making them, and the good ones will leave.

Wednesday, 11th January 2017


Happy New Year.


Always fun when someone from a place you used to work contacts you to find out who deals with something, and to let you know that there is a major issue there.   Exactly the sort of thing that would have had me laughing all day, but it's widely known that i have a sick sense of humour.


1&1 currently also have a "glitch" with the domain renewals - I transferred two domains to them, which both were renewed for 2 years.  At the same time I noticed that another domain was due to renew this year, so I renewed it for 2 years at the same time - got an email that said "I am pleased to inform you that your domain ************* has successfully renewed for the next 2 year(s). The next renewal date is set for 20.05.2018."   when I contacted them, initially the person didn't understand the issue with that email.................they then said that they would get someone to contact me.  this morning I contacted them again - and was informed that it was a "glitch" in the renewal process, and that they were working on fixing it.   I also pointed out that it would have been nice if someone had even dropped me an email to let me know.


Oh well, guess I just need to wait and see how long it takes them to sort it, and if they bother to contact me once it is resolved.

Monday, 19th December 2016


Merry Christmas,  what a fun few weeks it's been.   So, we have an issue attempting to add a new node to an existing 2 node SQL cluster.   The team tried (and failed) to add the freshly built node to the cluster.   It failed validation because the MPIO driver on the new node is newer than the existing nodes.  Solution suggested by the team - downgrade the MPIO driver on the new node to the same as the existing nodes.   Guess what, it didn't work.   Solution suggested by myself - look at upgrading the MPIO driver on the existing nodes.    Now, we need to spend even more time discussing this, and trying to work out another solution.    Looks like we will be well in to January before get this sorted.     Well, at least it's a problem for another team.  Happy holidays.

Tuesday, 4th October 2016.


Well, it's been an interesting few months.  I changed jobs a little over a month ago.  I am now working for HPE, spending most of my time in meetings (after spending over a month doing nothing).

Friday, 20th May 2016
TGIF! (Thank God It's Friday)

Another week finished, time to think about photo's I can take this weekend


Print Print | Sitemap
© Derek Souter