Home Lab

Well it has been a long time since I have posted anything here! We have been pretty busy with life and work! The reason I am writing is because I wanted to share a little about my home lab setup. Although I use this lab for work(Solution Architect at Unidesk), this is my equipment and my baby 100%. For work I use this lab to demonstrate to customers and prospects how Unidesk is able to deliver layered images to the provisioning mechanism like VMware View Composer, Citrix MCS, Citrix PVS. I also use it for personal geeky things! For example I have a Ubuntu VM that is my syslog server for the Fortigate 50E. It is not super pretty, but it does the job and I love palying around in my lab.

My Home Lab:

Switch: ZyXel GS1900-16
Firewal/Router: FortiGate 50E

1. Dell PowerEdge R710, Xeon X5660 @ 2.8GHz, 128GB Memory, 5TB local storage(1TB is SSD)
2. Dell PowerEdge R710, Xeon X5670 @ 2.93GHz, 144GB Memory, 12TB local storage

Shared Storage: Synology DS416 2.5TB(1TB is SSD) of storage

Hypervisor: ESXi 6
Nested Hypervisors: Hyper-V, Xenserver, AHV Community Edition

Technologies Deployed in Lab:
VMware vCenter
Horizon View & Composer
Citrix XenApp, XenDesktop, MCS, PVS
Unidesk 2x, 3x, 4x


Here is a quote from Jeff Weiner I came across in an article by Adam Lashinsky which you can find HERE

Focus has been — I’m oftentimes asked what keeps you up at night, and from day one it’s been focus and scale. And with regard to focus, you know, there’s the word focus and we’ve also created an acronym around it, FCS. So, the F is fewer things done better, the C is communicating the right information to the right person at the right time, and the S is the speed and quality of our decision-making.

I would like to focus on the F(Fewer things done better) here as it really struck me as extremely important.

Now I have never worked for a company that has experienced Hyper-Growth, however I can see where this strategy’s importance is more apparent to a company that is. I also think that the strategy is important for a company that is not growing. All too often employees are spread thin and as a result, the employee and the company will suffer. Why does this happen when the end result isn’t favorable? Two reasons, the employee has passion and wants to provide more value, and the company wants more value out of each employee and is more than willing to assign responsibilities. What is wrong with that? Nothing really, but it isn’t the correct approach to solve the issue of the employee and the company. In the Marine Corps we called this “Good initiative, bad judgement”.

A person who I respect and have worked with for many years told me that everyone has a worry basket and each persons worry basket isn’t always the same size. For example, some people may be able to hold five(5), while others may hold six(6) or eight(8). Although, the worry basket is always full; so if they take on another worry one of the previous has to be removed. In my opinion this same theory works for responsibilities. If you think of multitasking, you can only do/think of one thing at a time. So if you think of yourself as a great multitasker then maybe you have a larger basket with compatible worries/tasks/thoughts. For example, if an employee is well suited for customer service, then adding a task that is independent and segregated from the customer will impact their ability to switch worries/tasks/thoughts. This is because the employee is able to add and remove items from the basket more efficiently if they are leveraging the their strengths. I would suggest you check out this artcle about multitasking HERE and I’m sure you can find more.

Fewer things done better absolutely says it all. Identify your employees strengths, foster them and let them flourish to theirs and the company’s advantage. You will not only impact your bottom line, you will soon forget it because you are improving your top line. Which is a byproduct of the company and employee winning!

Modify Multiple Active Directory Accounts – PowerShell

The other day I wrote a script that populated my test server with 290 accounts. You can check it out HERE. Today I decided I would modify the logon hours for those accounts… It turned out to be more difficult than I thought because of the way you have to present the logon hours:

[byte[]]$hours = @(0,0,0,0,224,255,3,224,255,3,224,255,3,224,255,3,224,255,3,0,0)

There were a couple of sites that tried to explain it, but it easier to set the logon hours through the Active Directory Users and Computers MMC Snapin on a test user. Then go into ADSI Edit and take a look at the properties on the object and change the “Value Format” to Decimal:


After running the script, the end result is 290 accounts in the Employees OU changed from the default 24/7 logon to the following:


#Check if we are running in elevated powershell
If (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(`
    [Security.Principal.WindowsBuiltInRole] "Administrator"))
    Write-Warning "You do not have Administrator rights to run this script!`nPlease re-run this script as an Administrator!"

#Check if the Active Directory Module is loaded
if(-not (Get-Module ActiveDirectory)){
	Import-Module ActiveDirectory

#Grab the specific accounts we want(Everything in the Employees OU)
$employees = Get-ADUser -Filter * -SearchBase "OU=Employees,DC=lmnop,DC=local"

#Logon Hours Monday - Friday from 5AM - 6PM
#(I don't know how this works so I set it in MMC and check the value in ADSIEdit in Decimal)

[byte[]]$hours = @(0,0,0,0,224,255,3,224,255,3,224,255,3,224,255,3,224,255,3,0,0)

# create a hashtable to update the logon hours and a description
$replaceHashTable = New-Object HashTable
$replaceHashTable.Add("logonHours", $hours)
$replaceHashTable.Add("description", "Employees can only logon from Monday through Friday from 5:00 AM to 6:00 PM")

$count = 0

foreach($employee in $employees){
Write-Host "Changing logon hours for" $employee.SamAccountName
Set-ADUser $employee.SamAccountName -Replace $replaceHashTable

Write-Host $count " Accounts have been modified"

Populating Active Directory with Users and Groups with PowerShell

I whipped up this script in order to populate my Lab VM running Windows Server 2008 R2 with users and groups. Plus I was bored and wanted to work on my PowerShell 🙂

I did have to load an update so that I could run a few of the cmdlets(New-ADUser, New-ADGroup, & Add-ADGroupMember) you can find the update and info on it here http://support.microsoft.com/kb/2806748

#### Create Users and Groups in Fresh AD ####
#### I use this script to populate users and groups on a test server ####
#### Load Active Directory Module ####
Import-Module ActiveDirectory

#### CSV Format Below ####
## FirstName,LastName,UserName,Password,EmailAddress,Group1,Group2,Group3,Group4,Group5,Group6,Group7,Group8,Group9,Group10,Group11,Group12
## A. Scott,Wright,ascott0,WrA.57co,ascott0@adventure-works.com,DesktopAdmins,,Production Control,,,,,,,,,

### Import our CSV File ###

$UserList = Import-Csv "C:\ADShare\Powershell\AddUsers.csv"

$EmployeeOU = "OU=Employees,DC=lmnop,DC=local"

foreach ($User in $UserList){
	$FullName = $User.FirstName + " " + $User.LastName
	$Password = $User.Password
	$SAM = $User.UserName
	##Build Group List##
	$GroupList = @( 
	##Create User##
	New-ADUser -Name "$FullName" -SamAccountName $SAM -UserPrincipalName $SAM -DisplayName "$FullName" -GivenName $User.FirstName -Surname $User.LastName -EmailAddress $User.EmailAddress -AccountPassword ( ConvertTo-SecureString $Password -AsPlainText -Force) -Enabled $true -Path "$EmployeeOU" -PasswordNeverExpires $true
	##Check if group exists and Create if needed##
	Foreach($ADGroup in $GroupList){
		#Skip blanks
		if($ADGroup -ne ""){
				if(Get-ADGroup -Filter{SamAccountName -eq $ADGroup}){
				#Write-Host $ADGroup ": Exists"
				#Add User to Group
				Add-ADGroupMember $ADGroup $SAM
				Write-Host "Added $SAM to $ADGroup"
					#Write-Host $ADGroup ":Does Not Exist"
					#Create Group, Then add user to Group
					New-ADGroup -Name "$ADGroup" -Path "$EmployeeOU" -GroupScope Global
					Add-ADGroupMember $ADGroup $SAM
					Write-Host "Created Group $ADGroup"


Here is the complete CSV file I used (basically from the AdventureWorks Sample DB) AddUsers.csv

PowerShell is always fun.

NV Energy – Life Rescue

I recently left Tapani Inc. on 06Dec2013 and shortly after I took a short contract job working for Life Rescue, Inc. The job was to identify all confined space entry points at three(3) NV Energy power plants; Chuck Lenzie, Harry Allen, and Silverhawk. We created a base “Confined Space Data Sheet & Rescue Plan” for each entry point. I now know more about Natural Gas power plants than I would have ever imagined. (Living in Vegas kinda stunk over the holidays).

I will jump into something and normally do very well. I am a very dedicated hard working person, eager to learn new things.

I am now back home and looking to IT work.

Chuck Lenzie Map

Learning PowerShell

Learning Powershell? You should take a look at PowerGUI!
This free gem will help you get at what you want.

Define a variable and run it(debug or F5) and keep an eye on your variables pane and you will instantly see the time savings 🙂 You will now be able to browse through all those option and find what you are looking for!

Give it a try 🙂

Easy Powershell Oneliner

As I post things on this blog about PowerShell I will attempt to note how to do it with and without aliases. Just remember when going through the interwebs you can always look up and alias by typing Get-Alias or just type Get-Alias to see the entire list.

PS C:\>Get-Alias ft

Here is a little nugget you can try:

Without aliases:

PS C:\>Get-WmiObject -Class win32_bios |Select-Object *

With aliases

PS C:\>gwmi -Class win32_bios |Select *


PowerShell & PowerCLI

I have put off learning Windows PowerShell for too long. Which is really surprising, as I have done a lot of Perl and PHP in the past.

While I was a Student Linux Admin at Clark Community College (2001) I had written a Perl script for user account management on Computer Science Department RedHat box. The script took a CSV file with student ID’s and qualifying/disqualifying classes and created, disabled, and in some cases removed the account. If the account was going to be removed I would check the MySQL backend and if the user had an account that was disabled for 2 quarters then the account and user directory was removed at the start of the 3rd quarter.

I have done several Perl and PHP scripts, but one PHP script stands out.  We had put in a new ProxCard system to control our doors and gate and the software wasn’t usable for our non-technical staff.  I had to figure out where the ProxCard system was inserting records into the SQL database and once I figured that out I whipped up a couple of Perl scripts to test. Eventually this grew into a regular LAMP server with users accounts and auditing.

Yeah I really just wrote my second PowerShell/PowerCLI script a few days ago!

So my first script I wrote checked my vSphere cluster for VMs with multiple vCPUs (and no I didn’t do a “Hello World!”)

#Find all virtual destkops running on a cluster that have more than one vcpu

# Launch text
write-host "                                                                                  "
write-host "         Rob's First Script to check a cluster for VMs running more than one vcpu!" 
write-host "                                                                                  "

$cluster = Read-Host 'On Which cluster to you want to check for multiple vcpus?'

get-cluster $cluster | get-vm | select name,powerstate,numcpu,memorygb,host |where {$_.numcpu -gt 1 -and $_.powerstate -eq "PoweredOn"} |format-table -autosize

get-cluster $cluster | get-vm | select name,powerstate,numcpu,memorygb,host |where {$_.numcpu -gt 1 -and $_.powerstate -eq "PoweredOn"} |group-object -Property Host | Select Count, Name | format-table -autosize

I wrote my second script recently to find folders on a specific datastore. This datastore is used for a backup/archive snapshot for VDI using Unidesk. Currently when I remove a machine in Unidesk or restore to a different cachepoint we can end up getting orphaned files on the archive datastore.

#get-cluster cluster02
$cluster = "cluster02"

function CheckVM {
$VM = get-cluster $cluster | Get-VM -name $vmname -ErrorAction SilentlyContinue
        $status = "No VM"
   else { 
        $status = "VM Found" 

return $status

#grab folders on archive tier datastore VDIBU

$cp1ap=  "vmstores:\vc01@443\DataCenter\VDIBU\Unidesk Backups\VDI01\User"
$cp2ap=  "vmstores:\vc01@443\DataCenter\VDIBU\Unidesk Backups\VDI02\User"

#exclude any . files if any and make sure it's a folder and not a file
$cp1Folders =
get-childitem -exclude .* $cp1ap | select name,PSIsContainer | where {$_.PSIsContainer -eq "True"} |foreach {$_.name}

#exclude any . files if any and make sure it's a folder and not a file
$cp2Folders =
get-childitem -exclude .* $cp2ap | select name,PSIsContainer | where {$_.PSIsContainer -eq "True"} |foreach {$_.name}

#combine arrays and print out hash to see if a MM has been restored to another CP at some point in time
$AFolders = $cp1Folders + $cp2Folders

$AFolders | group | % {$hash = @{} } { $hash[$_.Name] = $_.Count }

foreach ($key in $hash.GetEnumerator()){
    $vmExists = CheckVM $($key.Name)
    Write-Host "$($key.Name)    has $($key.Value) archive folders and: $vmExists" 

I know it is ugly but it works 🙂