Tag Archives: Powershell

Some updates to the PowerCLI Shutdown VMs Script – Now w/ a virtualized vCenter option

shutdown-button-mdOver that past few months I've been getting quite a few emails and comments as it pertains to the scripts I have shared to shutdown and power on VMs in the event of power loss.  I assume since the storm weather is kicking in people are realizing that they need to have some kind of protection in regards to gracefully getting the VMs down.  Now I've had the (privilege?) of watching my script run multiple times in a production environment and it has gotten to the point where it is working flawlessly.  One caveat to the script though – whichever Windows box is executing the PowerShell must stay powered on longer than your vCenter Server.

That being said the script would be pretty useless if you had a virtualized vCenter Server running on the same cluster as your production VMs that your are shutting down – this is what all of the emails and comments that I've been getting have been based around.  So, without further ado I've added a few updates to the script to better support those with a virtualized vCenter.  A few explanations below…

So first off (Line 50) I've added a variable called $vCenterVMName and assigned this a default value of NA.  This variable should hold the VM Name of your vCenter Server.  I've tried to keep just one version of the script supporting both virtualized and non-virtualized vCenter's thus is why the default to "NA".  So if you don't have a virtualized vCenter just leave the variable set to NA and the script will run as it always had, otherwise if you do, put its' VM name in here.

Secondly down on Lines 107 to 1118 I do a few things.  First, check to see if you have changed that default value and if you have we need to figure out which ESXi host vCenter is running on in order to shut it down last.  This is what's done here.

Then, in each of the shutdown loops (Line 125 and Line 162) I've added an if statement.  Basically it just checks to see if the VM it is processing is the vCenter Server.  If so, it doesn't process the shutdown.

Lastly I've done a couple more things.  On Line 186 I've added a check while shutting down the hosts.  If the host that is being processed is the host that vCenter is running on I want to leave it till the end, so it is skipped during this loop.  Then, the finally the block of code starting on Line 196, if needed, will send the shutdown command to the host that is running vCenter Server.

As you may of noticed I've added a some logging as well, nothing bit, just a record of what happened in a txt file rather than relying on Write-Host.  The script in its' entirety is below or you can download it here.  Watch for updates to the power on script to support the vritualized vCenter as well.  Just not sure how I'm going to tackle that one yet ūüôā

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
#################################################################################
# Power off VMs (poweroffvms.ps1)
#
# This is a complete update to my previous shutdown script.  No longer do we
# loop through the esx hosts and shut down VMs per host.  We now just shut them
# all down up front.  Also, no more $vmstoleaveon variable.  I'm assuming here 
# that your vCenter is not virtual.  If it is you can most likely grab version
# 1 of this script and take the code to leave the vCenter host till last.  Maybe
# someday I'll get around to updating it to merge the two...but for now, this is
# it!
#
# This script does have a 'partner' script that powers the VMs back on, you can
# grab that script at http://blog.mwpreston.net/shares/
#
# Created By: Mike Preston, 2012 - With a whole lot of help from Eric Wright 
#                                  (@discoposse)
#
# Variables:  $mysecret - a secret word to actually make the script run, stops 
#                         the script from running when double click DISASTER
#             $vcenter - The IP/DNS of your vCenter Server
#             $username/password - credentials for your vCenter Server
#             $filename - path to csv file to store powered on vms
			  used for the poweronvms.ps1 script.
#             $cluster - Name of specific cluster to target within vCenter
#             $datacenter - Name of specific datacenter to target within vCenter
#
#
# Usage: ./poweroffvms.ps1 "keyword"
#        Intended to be ran in the command section of the APC Powerchute Network
#        Shutdown program before the shutdown sequence has started.
#
#################################################################################
 
param($keyword)
 
Add-PSSnapin VMware.VimAutomation.Core
#some variables
$vcenter = "vcenterServer"
$username = "user"
$password = "password"
$cluster = "clusterName"
$datacenter = "datacenterName"
$filename = "c:\path\to\poweredonvms.csv"
$mysecret = "kerfuffle"
$date = ( get-date ).ToString('yyyyMMdd')
$logfile = New-Item -type file "C:\ShutdownLog-$date.txt"
 
#for use with a virtualized vCenter - bring it down last :) - if you don't need this functionality
#simply leave the variable set to NA and the script will work as it always had
$vCenterVMName = "NA"
 
Write-Host "A Powerchute network shutdown command has been sent to the vCenter Server." -Foregroundcolor yellow
Write-Host "This script will shutdown all of the VMs and hosts located in $datacenter" -Foregroundcolor yellow
Write-Host "Upon completion, this server ($vcenter) will also be shutdown gracefully" -Foregroundcolor yellow
Write-Host ""
Write-Host "This script has also has a counterpart (powervmsbackon.ps1) which should" -Foregroundcolor yellow
Write-Host "be setup to run during the startup of this machine ($vcenter). " -Foregroundcolor yellow
Write-Host "This will ensure that your VMs are powered back on once power is restored!" -Foregroundcolor yellow
Sleep 5
 
Add-Content $logfile "mwpreston.net PowerOff Script Engaged"
Add-Content $logfile ""
 
if ($keyword -ne $mysecret) 
{ 
    Write-Host "You haven't passed the proper detonation sequence...ABORTING THE SCRIPT" -ForegroundColor red
    Add-Content $logfile "You haven't passed the proper detonation sequence...ABORTING THE SCRIPT"
    exit
}
 
#connect to vcenter
Write-Host "Connecting to vCenter - $vcenter ...." -nonewline
Add-Content $logfile "Connecting to vCenter - $vcenter"
$success = Connect-VIServer $vcenter -username $username -Password $password
if ($success) { Write-Host "Connected!" -Foregroundcolor Green }
else
{
    Write-Host "Something is wrong, Aborting script" -Foregroundcolor Red
    Add-Content $logfile "Something is wrong, Aborting script"
    exit
}
Write-Host ""
Add-Content $logfile  ""
 
#Get a list of all powered on VMs - used for powering back on....
Get-VM -Location $cluster | where-object {$_.PowerState -eq "PoweredOn" } | Select Name | Export-CSV $filename
 
#change DRS Automation level to partially automated...
Write-Host "Changing cluster DRS Automation Level to Partially Automated" -Foregroundcolor green
Get-Cluster $cluster | Set-Cluster -DrsAutomation PartiallyAutomated -confirm:$false 
#change the HA Level
Write-Host ""
Write-Host "Disabling HA on the cluster..." -Foregroundcolor green
Write-Host ""
Add-Content $logfile "Disabling HA on the cluster..."
Add-Content $logfile ""
Get-Cluster $cluster | Set-Cluster -HAEnabled:$false -confirm:$false 
 
#get VMs again (we will do this again instead of parsing the file in case a VM was powered in the nanosecond that it took to get here.... :)
Write-Host ""
Write-Host "Retrieving a list of powered on guests...." -Foregroundcolor Green
Write-Host ""
Add-Content $logfile "Retrieving a list of powered on guests...."
Add-Content $logfile ""
$poweredonguests = Get-VM -Location $cluster | where-object {$_.PowerState -eq "PoweredOn" }
 
Add-Content $logfile "Checking to see if vCenter is virtualized"
#retrieve host info for vCenter
if ($vcenterVMName -ne "NA") 
{ 
    Add-Content $logfile "vCenter is indeed virtualized, getting ESXi host hosting vCenter Server"
    $vCenterHost = (Get-VM $vCenterVMName).Host.Name 
    Add-Content $logfile "$vCenterVMName currently running on $vCenterHost - will process this last"
}
else
{
    Add-Content $logfile "vCenter is not virtualized"
}
 
Add-Content $logfile "Proceeding with VM PowerOff"
Add-Content $logfile ""
#and now, let's start powering off some guests....
ForEach ( $guest in $poweredonguests ) 
{
    if ($guest.Name -ne $vCenterVMName)
    { 
        Write-Host "Processing $guest ...." -ForegroundColor Green
        Write-Host "Checking for VMware tools install" -Foregroundcolor Green
        $guestinfo = get-view -Id $guest.ID
        if ($guestinfo.config.Tools.ToolsVersion -eq 0)
        {
            Write-Host "No VMware tools detected in $guest , hard power this one" -ForegroundColor Yellow
            Add-Content $logfile "$guest.Name - no VMware tools, hard power off"
            Stop-VM $guest -confirm:$false
        }
        else
        {
           write-host "VMware tools detected.  I will attempt to gracefully shutdown $guest"
           Add-Content $logfile "$guest.Name - VMware tools installed, gracefull shutdown"
           $vmshutdown = $guest | shutdown-VMGuest -Confirm:$false
        }
    }   
}
 
#Lets wait a minute or so for shutdowns to complete
Write-Host ""
Write-Host "Giving VMs 2 minutes before resulting in hard poweroff"
Write-Host ""
Add-Content $logfile ""
Add-Content $logfile "Waiting a couple minutes then hard powering off all remaining VMs"
Add-Content $logfile ""
Sleep 120
 
 
#Now, let's go back through again to see if anything is still powered on and shut it down if it is
Write-Host "Beginning Phase 2 - anything left on....night night..." -ForegroundColor red
Write-Host ""
#get our list of guests still powered on...
$poweredonguests = Get-VM -Location $cluster | where-object {$_.PowerState -eq "PoweredOn" }
ForEach ( $guest in $poweredonguests ) 
{
    if ($guest.Name -ne $vCenterVMName)
    { 
        Write-Host "Processing $guest ...." -ForegroundColor Green
        #no checking for toosl, we just need to blast it down...
        write-host "Shutting down $guest - I don't care, it just needs to be off..." -ForegroundColor Yellow
        Add-Content $logfile "$guest.Name - Hard Power Off"
        Stop-VM $guest -confirm:$false
    }
}
 
#wait 30 seconds
Write-Host "Waiting 30 seconds and then proceding with host power off"
Write-Host ""
Add-Content $logfile ""
Add-Content $logfile "Processing power off of all hosts now"
Sleep 30
 
#and now its time to slam down the hosts - I've chosen to go by datacenter here but you could put the cluster
#  There are some standalone hosts in the datacenter that I would also like to shutdown, those vms are set to
# start and stop with the host, so i can just shut those hosts down and they will take care of the vm shutdown ;)
 
$esxhosts = Get-VMHost -Location $cluster
foreach ($esxhost in $esxhosts)
{
    if ($esxhost.Name -ne $vCenterHost)
    {
        #Shutem all down
        Write-Host "Shutting down $esxhost" -ForegroundColor Green
        Add-Content $logfile "Shutting down $esxhost"
        $esxhost | Foreach {Get-View $_.ID} | Foreach {$_.ShutdownHost_Task($TRUE)}
    }
}
 
#finally shut down the host which vCenter resides on if using that functionality
if ($vcenterVMName -ne "NA") 
{
    Add-Content $logfile ""
    Add-Content $logfile "Processing $vcenterHost - shutting down " 
    Get-VMhost $vCenterHost | Foreach {Get-View $_.ID} | Foreach {$_.ShutdownHost_Task($TRUE)} 
}
 
Add-Content $logfile ""
Add-Content $logfile "All done!"
#that's a wrap

So there you have it!  Hopefully this will help some of you out with your shutdown endeavors.  Feel free to make any changes you need in order to make it work for your environment and let me know how it goes – keep those comments, concerns, thoughts and emails coming in!

Move your templates to a new cluster – The PowerCLI Way

powerclilogoAlright, here's a script I quickly pieced together to accomplish the task of moving some of our templates over to a new cluster.  At the time I was currently in the process of deploying a new cluster on a new distributed virtual switch, thus this script only tackles your templates on a single host basis.  Meaning I was walking each host over to the new switch one by one and then migrating virtual machine networking and all vmkernel interfaces on the host, then performing a vmotion on the VMs and templates and finally destroying the original host…

Oh well, enough history (blabbing).  The script is very simple as you can see below.  Aside from your vCenter information it takes a couple of variables; source and destination host (Lines 7/8).  The only quirkiness I found was with the Set-Template cmdlet – I could not find a way to specify the location of the VM when converting it, thus you can see on line 18 I have to move it back to my source host after the conversion to ensure i will have the connectivity on my migrated vMotion network.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$vcenter ='IP of vCenter'
$vcuser = 'vCenter User'
$vcpass = 'vCenter Pass'
 
Connect-VIServer $vcenter -user $vcuser -pass $vcpass
 
$sourcehost = get-vmhost 'Source Hostname/IP'
$destinationhost = get-vmhost 'Target Hostname/IP'
 
#get all templates on source host
$templates = get-template -Location $sourcehost
 
foreach ($template in $templates)
{
    # convert template to VM
    Set-Template $template -ToVM -confirm:$False
    # ensure it is running on my source host
    Get-VM -Name $template | Move-VM -Destination $sourcehost
    # migrate vm to new cluster
    Get-VM -Name $template | Move-VM -Destination $destinationhost
    # convert back to a template
    Get-VM -Name $template | Set-VM -ToTemplate -Confirm:$false
}

So that's it!  I told you it was a quickie!  Again, I don't have a secret alias of PowerCLI Man so if you have any suggestions on how to improve up on any of this let me know…

Friday Shorts – vClouds, Veeammy Secret Features, DMZ stylin, Sysprep

So join now, ’cause at the Derek Zoolander Center For Kids Who Can’t Read Good And Wanna Learn To Do Other Stuff Good Too, we teach you that there’s more to life than just being really, really, really good looking. Right kids?!. – Derek Zoolander from Zoolander

Veeam keeps packing on features

veeam_logoOn Monday of last week, Veeam announced a couple of pretty cool new features that will be bundled in with the others that they have been slowly releasing over the last few months. One question that i have seen come up many times in the Veeam forums, sometimes even authored by myself is what the best way to get your backups offsite may be. Well Veeam has answered that with their very own wan acceleration and data movement options. Yup, your backup vendor is not only providing you with the option to move those backups offsite, but are now providing you with the most efficient way to do so. Veeam is slotted to be GA sometime in Q3 of this year! Cant wait! In the mean time have a look at what Veeam has put together for their monthly draw, a pretty sweet mobile lab that I wouldn’t mind getting my hands on.

DMZ and VMware vCloud Networking and Security

VMware LogoYou know vShield right? Ever wonder what VMwares’ recommendations are about how to properly design, configure, secure and deploy a fully virtualized DMZ are? If yes then you are in luck! A new technical whitepaper was put out this week titled Securing the DMZ with VMware vCloud¬ģ Networking and Security. This is no marketing stuff either. When they call it a technical paper they mean it. You will see how to setup the firewalls, the access rules, logging, VLANS, etc. Be sure to check it out!

The VMware clouds are rolling in

vCloudAs Im sure all of you have heard by now VMware has launched their own hybrid cloud model and added yet another acronym to their portfolio. The vCHS, or VMware vCloud Hybrid Service is supposed to hit a sky near you sometime in June. IMO I see this as a valid offering from VMware. One can only hope that the familiarity and comfort of the vSphere and vCloud will help to drive adoption. Certainly worth a look if you are a current vSphere customer

And in a tribute to the gloomy last 30 days or so before the Google Reader exit I thought I would try and include some of the many blog posts that I read on a daily basis and star inside of it. So without further ado i give you….

Sh!t I’ve Starred

My First vCenter Orchestrator Workflow ‚Äď Part 5 – A little bit of SQL

orchestratepart5Thus far in this¬†series¬†of posts we have installed and configured vCenter Orchestrator as well as setup and utilized a couple of plugins; the vCenter plug-in and the PowerShell plug-in. ¬†Before the series ends I wanted to go through one more plug-in. ¬†The SQL plug-in. ¬†The SQL plug-in is used for, well, you guessed it; running SQL queries against a database. ¬†If you remember in Part 4 we setup a workflow that took two input parameters; a host and a location code. ¬†The script then went on to create a new port group on a vSwitch named locationcode-VM_Network. ¬†The logic in itself works fine and the workflow validates, the only problem I see with it is that the user needs to enter the ‘location code’ manually as an input. ¬†Now I know you are all very careful and take your time when doing things, but I’m not, and more than likely after doing this 40 or 50 times you can count on me keying in that location code wrong ūüôā – Enter the SQL plugin.

So the setup is as follows; I have a database containing a table with the following columns; locationcode and deployed (boolean). ¬†What I would like to do is have an input parameter that would allow me to select the location code from a list of non-deployed locations in a¬†drop-down¬†box (rather than manually enter this information in), and in turn pass the location code to my PowerShell script. ¬†Once the script has ran I’d like to update the deployed column for that specific location, ensuring it isn’t displayed in the list again in turn ensuring I can’t deploy the same location twice. ¬†Make sense? ¬†I know it’s a lot to follow but the concepts of setting it up are pretty much the same no matter what you are looking to do.

Alright – enough background – Let’s get into it. ¬†I’m not going to go through the installation of the SQL Plug-in – it’s exactly the same installation process as the Powershell plug-in which we covered in Part 4. ¬†Similar to how we setup our Powershell host we need to setup our SQL server database connection inside of vCO. ¬†To do this fire up your vCO client and navigate through the workflow tree to Library->SQL->Configuration and select the ‘Add a database’ workflow, right click and Start Workflow. ¬†There are a few parameters as you can see that we need to pass to the workflow in order for it to¬†successfully¬†run. ¬†First, give this connection a name and select your desired Database Type – in my case MS SQL. ¬†Also here we need to pass a Connection URL. ¬†Now if you don’t know anything about jdbc connection urls no fear, it’s not that difficult. ¬†Simply enter it in the the following format…

jdbc:jtds:sqlserver://[SERVERNAME]:[SERVERPORT]/[DATABASENAME]

So, for a SQL Server with named DC.lab.local running on the default port 1433 and ¬†database named ServerDeploy you would use the following…

jdbc:jtds:sqlserver://dc.lab.local:1433/ServerDeploy

SetupSQLPic1

After clicking Next we are once again presented with our Shared/Per User session mode – again, I chose shared to use one simple set of credentials rather than a per user authentication. ¬†When you are ready click ‘Submit’ to add your new database to vCO’s inventory. ¬†One thing to note here is that this step is not¬†necessary¬† ¬†If we wanted we could perform all of this at run time inside code, however for tutorial purposes and learning purposes it’s sometimes easier to do it this way.

Alright, nuff config! ¬†It’s time now to get started on our task at hand; Querying the database for non-deployed servers and pushing the result as a¬†drop-down¬†box as an input parameter to our workflow that we created in Part 4. ¬†First off there is a simple change we need to make to our existing workflow. ¬†Here’s a tip – don’t feel like buffalo-ing your original workflow, simply right click on it and ¬†select ‘Duplicate Workflow’ to copy it. ¬†OK, first off we need a new attribute. ¬†We originally have locationcode setup an input parameter of type string – and we still need this, however the result we get back from our database will be an array of strings. ¬†So, on the General tab of your workflow create a new attribute called ¬†databaseParameter of type SQL:Database and assign it the value of the Database we created earlier (this should allow you to browse the inventory to do so). ¬†Once you are done that simply Save & Close and continue on with any validation errors.

Workflow-pic1-NewAttr

So here comes the real magic! ¬† We need to take that database attribute and pass it to a newly created action which will in turn spit out an array of string attributes (our locations in our database). ¬† Again, you could do the following all in script embedded within your workflow, but you never know when you are going to need to reuse something so I’ve decided to create a new action to do so. ¬† ¬†To create an new action be sure you are on ‘Design’ view from within your client and click on the actions tab in the left hand side menu. ¬†Where you place your action doesn’t really matter, I chose to right click com.vmware.library.sql and create my action inside that module. ¬†Just remember where you put it and what you named it:).

Workflow-pic2-NewAction

OK, you should now be in the Action editor. ¬†This is where we are going to place the code that does all the querying of the database. ¬†As I said earlier we need to pass this Action a database parameter and it will return an array of string. ¬† The setup of input parameters and return types, along with all the other work we are going to do is all done on the scripting tab. ¬†First off define your return type of an Array/string. ¬†Secondly add an input parameter of type SQL:Database. ¬†You can see all of this outlined in the capture below…

Workflow-pic2b-ActionEditor

Hey! ¬†That was easy! ¬†Now it’s time for a little scripting. ¬†vCO script is nothing but Javascript which calls the rich set of API’s that vSphere provides, along with the functions and properties of all the plug-ins provided in vCO. ¬†The script I used is displayed below…

1
2
3
4
5
6
7
8
9
10
var resultingArray = new Array();
 
var query = "SELECT locationcode FROM Locations WHERE deployed = 0";
var resultingActiveRecords = databaseParameter.readCustomQuery(query);
for each (var resultRecord in resultingActiveRecords) {
var locationcode = resultRecord.getProperty("locationcode");
resultingArray.push(locationcode);
}
 
return resultingArray;

Simply paste this into the script pane of your action. ¬†As you can see it’s a pretty simple script. ¬†Creates and array, queries our database, pushes the locationcode column value of each record returned into that array and finally returns the array. ¬†So – time to Save and Close and head back to our workflow.

So at this point we are left with 2 tasks.  The first being the creation of the drop-down box as an input.  To do this we will need to change the way our original input parameter, locationcode, is displayed.  This is done on the Presentation tab of our script editor.  Be sure you have selected locationcode in the Presentation tree that the top of the screen and select the icon to add a new property to it.  There are many several different properties listed but the one we are after is called Predefined list of elements.  Under the value field of our new property select the icon to assign an action.  In the popup find/filter for our action we created earlier, assign the actions parameter to our database parameter and click Apply.

WorkFlow-pic3-RunAction

There done right…well, kinda, you could run the workflow now and it would populate our input and it would go ahead and run the PowerCLI script and the VM Network would be created, however if you remember it was my intent to go back at the end of the workflow and update our database to ensure that the same locationcode could not be selected twice. ¬†To do this we will need to drag a new Scriptable task element to run after we invoke our PowerCLI script. ¬†Inside this scriptable task we will need to import a couple of local attributes in order to accomplish the sql we need to do, the locationcode, and the databaseParameter.

Workflow-pic4-NewScriptableTask

As for the script it’s going to look very similar to the syntax that we placed inside of our action with the exception of and executeCustomQuery function¬†in place¬†of the readCustomQuery and the actual query itself is different. ¬†The following is what I used…

1
2
var query = "UPDATE locations SET deployed= 1 WHERE locationcode= '" + locationcode+ "'";
databaseParameter.executeCustomQuery(query);

And now at last we are done!! ¬†Go ahead and run your workflow, either from within the vCO client or the Web Client and you should now see a¬†drop-down¬†selection for the locationcode. ¬†Once it’s selected once the script will run, create the VM Network, then update our database to ensure that the selected locationcode is not shown again in the¬†drop-down.

Workflow-pic5-alldone

So that my friends is the end of the line for me on creating my first vCenter Orchestrator Workflow but it is most¬†definitely¬†not the end of the line with vCO. ¬†With access to a huge set of vSphere API’s along with all of the¬†functionality¬†and properties provided by its’ plugins, throw in some sweet integration with the vSphere Web Client I’m beginning to see my usage of vCO ramp up within my current role. ¬†This series has hardly even grazed the surface in terms of vCO’s functionality so I urge you all to go out there and learn as much as you can about this product. ¬†I’ll do one more post in the series and outline some of the resources that I’ve found along the creation of this workflow so expect to see that soon.

My first vCenter Orchestrator Workflow

Using PowerCLI to set multipath policy based on array model

powerclilogoGoing through all of your hosts and setting your multipathing policy manually through either the C# or the vSphere Web Client can certainly be a trying task. ¬†Sure, if you have 2 or 3 hosts it might be alright, but anything above that and things start to get pretty¬†monotonous¬†really fast! ¬†Also we have all known that if you need to perform the same task more than once it’s always better to script it – Firstly it creates consistency¬†across¬†your environment, secondly it saves you time, and thirdly it helps the economy as you are out buying coffee when normally you would be at your desk clicking….

So all that leads me to the following script… ¬†For the most part the script does two things – first it gets a list of all of your LUNS associated with a host or group of hosts, second, it sets up your desired multipathing policy on those luns based on the model of array presenting them as well as marks paths as preferred if applicable… ¬†That being said, I’ve only included a few different models inside the script below, to see a full list of models you can run “esxcli storage nmp satp rule list”¬† from the esxcli to list all of the models and integrate them into the script as you see fit.

So first off you can see that the script accepts a parameter – if you pass the string fixall with the call of the script it will just continue without prompts, otherwise, it asks you for a y/n answer. ¬† Also, when setting a path policy to fixed you might want to specify a preferred path – you can see that I’ve set this up as vmhba1, just be sure to customize the script to your liking for your environment…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#fixall - if equals autoyes then don't prompt for y/n
param ($fixall)
 
$vcenter = "vcenterserver"
$username = "username"
$password = "password"
 
$hostcontainer = "cluster or datacenter containing hosts to check"
 
Write-Host "Connecting to vCenter Server..."
$success = connect-viserver $vcenter -username $username -Password $password
 
$vmhosts = get-vmhost -Location $hostcontainer
 
foreach ($vmhost in $vmhosts)
{
  Write-Host "Processing " $vmhost.Name"......" -ForegroundColor white -BackgroundColor Red
 
  #get all luns of type 'disk' from host
  $luns = get-ScsiLun -VMhost $vmhost -LunType disk
 
  foreach ($lun in $luns)
  {
    $multipath = $lun.MultipathPolicy
    $canname = $lun.CanonicalName
    $model = $lun.Model
    # if lun belongs to EVA
    if ($model -eq "HSV400")
    {
      $defaultpolicy = "roundrobin"
      if ($multipath -ne $defaultpolicy)
      {
        #get matching datastore name of lun
        $ds = Get-Datastore | Where-Object {$_.Extensiondata.Info.vmfs.Extent.DiskName -eq "$canname"}
        $dsname = $ds.Name
        Write-Host "$dsname" -foregroundcolor red -backgroundcolor yellow -nonewline; Write-Host " is on the EVA and is currently set to " -nonewline; Write-Host "$multipath" -ForegroundColor yellow -nonewline; Write-Host " where it should be " -nonewline; Write-Host "Round Robin" -ForegroundColor green -NoNewline; Write-Host " - Fix? " -NoNewline;
        if ($fixall -eq "autoyes")
        {
          $fix = "y"
        }
        else
        {
          $fix = Read-Host " y/[N]:"
        }
        if ($fix -eq "y")
        {
          $lun | set-ScsiLun -MultipathPolicy $defaultpolicy
          Write-Host "***Complete***" -Foregroundcolor green
        }
      }
    }
    #if lun belongs to an MSA
    elseif ($model -eq "MSA1000 VOLUME")
    {
      $defaultpolicy = "fixed"
      $prefPathHBA = "vmhba1"
      if ($multipath -ne $defaultpolicy)
      {
        #get corresponding datastore name of lun
        $ds = Get-Datastore | Where-Object {$_.Extensiondata.Info.vmfs.Extent.DiskName -eq "$canname"}
        $dsname = $ds.Name
        Write-Host "$dsname" -foregroundcolor red -backgroundcolor yellow -nonewline; Write-Host " is on the MSA and is currently set to " -nonewline; Write-Host "$multipath" -ForegroundColor yellow -nonewline; Write-Host " where it should be " -nonewline; Write-Host "Fixed" -ForegroundColor green -NoNewline; Write-Host " - Fix? " -NoNewline;
        if ($fixall -eq "autoyes")
        {
          $fix = "y"
        }
        else
        {
          $fix = Read-Host " y/[N]:"
        } 
        if ($fix -eq "y")
        {
          $lunpath = Get-ScsiLunPath -scsilun $lun | where-object {$_.ExtensionData.Adapter -like "*$prefPathHBA"}
          $lun | set-ScsiLun -MultipathPolicy $defaultpolicy -PreferredPath $lunpath -confirm:$false
        }
      }
    }
  }
}

Again I don’t claim to be a Powershell/PowerCLI scriptmaster, so if you see any performance enhancements, problems, suggestions, concerns please use the comments section below to let me know… – Anyone can write a script, but it takes a community to make it a great script.

My First vCenter Orchestrator Workflow ‚Äď Part 4 ‚Äď A look at the Powershell Plug-in

Orchestrate-FacilitateAlright! ¬†So far throughout this series of posts we have installed, configured and setup vCenter Orchestrator; as well as created and tested the integration between both vCO and the vSphere Web Client. ¬†So what’s next in my venture? ¬†Well if you can remember back to Part 1 of the series I set out on a quest to develop a workflow that would take an un-configured host and go through a series of tasks to create datastores, rename networks, setup hostname, etc… ¬†Basically configure it the way I wanted. ¬†Now there are built-in workflows in vCO to do this, however I had already done this work inside of a PowerShell script – so my main goal was to get vCO to execute that script. ¬†And this leads us to part 4!

So first off as I said above there are a ton of great built in workflows inside of vCO that can do pretty much anything. ¬†Some things however, such as the ability to run a Powershell script, are missing! ¬†Thankfully there is a thriving developers community built around vCO and it’s SDKs allowing third party vendors to release their own sets of workflows in the form of a plug-in. ¬†So as you probably guessed by now we will need to install a plugin to handle our Powershell script execution.

This plugin is called the vCenter Orchestrator Plug-in for Microsoft Windows Powershell and can be found over on VMware’s site. ¬†You will need to download this file. ¬†Once you have your hands on the vmoapp file we need to go into the vCenter Orchestrator Configuration page (https://IP_OF_vCO:8283/) to install it. ¬†Select Plug-ins from the left hand menu, then browse down to the Install new plug-in section. ¬†Upload your file and click ‘Upload and install’, accept the EULA and away you go… If you browse back to the main Plug-ins page you will notice that it states the plugin will be installed at the next server startup; so if you wish you can do this task manually by going to Startup Options -> Restart Service.

vCO-InstallPlugin

At this point we can fire up our vCO client. ¬†Having a look in the Library of¬†workflows¬†we can now see a PowerShell folder. ¬†Expanding this out further let’s us see some of the workflows that come packaged with the plug-in. ¬†So we now have a few configuration steps we need to go through before executing scripts with this plug-in.

First off we need setup a PowerShell host. ¬†A PowerShell host is simply a Windows machine with Powershell installed located somewhere in your environment that will handle the storing and executing of the scripts. ¬†There is a great article on all of the steps here but I will go through explaining them all as well. ¬† Keep in mind this might not be the most secure of ways to go about everything – but this is simply a lab so I’m not too worried – for those concerned w/ security implications check out the full lengthy thrilling winrm read on the msdn ūüôā ¬†¬†

So, once you have chosen which machine you would like to be your Powershell host go ahead and drop to a command prompt on that machine and run the following list of commands.

  • To create a winrm listener and open any required firewall ports
  • winrm quickconfig
  • To enable kerberos authentication
  • winrm set winrm/config/service/auth @{Kerberos=”true”}
  • Allow transfer of unencrypted data – told you wasn’t the most secure ūüôā
  • winrm set winrm/config/service @{AllowUnencrypted=”true”}
  • Up the max memory per shell – I needed to do this to get things working
  • winrm set winrm/config/winrs @{MaxMemoryPerShellMB=”2048″}

And there we are! ¬†Things should be setup fine now on our host end to allow the connections from our vCO server. ¬†Now we need to configure kerberos on the vCO end of things. ¬†To do this you will need to console into your vCO server and get on the command line there – hope your comfortable with vi ūüôā

Basically we need to create a file under /opt/vmo/jre/lib/security called krb5.conf Рto do so simply

cd /opt/vmo/jre/lib/security
vi krb5.conf

This file will need to look as follows – obviously change to fit your environment – if you happen to be using an default configuration of the autolab then you are good just to copy the following…

[libdefaults]
default_realm = LAB.LOCAL
udp_preferences_limit = 1
 
[realms]
LAB.LOCAL = {
kdc = dc.lab.local
default_domain = LAB.LOCAL
}
 
[domain_realms]
.LAB.LOCAL=LAB.LOCAL
LAB.LOCAL=LAB.LOCAL

Once you are done simply hit :wq to save and exit.  In order to grant vCO permission to access our newly created krb5 file you will also need to change ownership of the file using the following command

chown vco.vco krb5.conf

And, in order for changes to take affect, restart the vCO service – you can do this from the configuration page->Startup Options or simply

service vcod restart

Whew! ¬†Ok! ¬†Getting somewhere….Now we need to add the host into our configuration of the Powershell plug-in. ¬† I find the easiest way to do this is to simply run the ‘Add a Powershell Host’ workflow however you can develop the script/code on the fly to add the host during your own workflow if you want. ¬† The way I have documented however is as follows…

Browse to the PowerShell plug-in configuration by expanding Library->PowerShell->Configuration in the workflows view of your vCO Client. ¬†Right click ‘Add a PowerShell host’ and select Start Workflow.

vCO-AddHost1

Here we need to add a few key pieces of information.  Enter a name for your PowerShell host Рthis can be whatever you wish, then enter the HOSTNAME of the host you setup (kerberos will not work with IP)   and click Next.

vCO-AddHost2

The only item that needs to be changed on the Host Type screen is Authentication; be sure Kerberos is selected and click ‘Next’.

vCO-AddHost3

In the User Credentials screen you have a couple of options in regards to Session mode. ¬†Again since this is a lab environment I selected Shared Session, however if you were looking at a more production type deployment you might want to explore the Per User settings which will execute commands under the credentials of the current user connected to vCO. ¬†Enter in some credentials with access to vCO and click ‘Submit’. ¬†The workflow should kick off and you can watch it flow through the different elements. ¬†When done, hopefully you have a nice green¬†check mark¬†beside it!

Now that we have¬†successfully¬†installed the Powershell plug-in and added a Powershell host lets go ahead and create a script on our Powershell host to run in order to make sure everything works. ¬†Although my end goal is to completely configure a host – ¬†for simplicity¬†sake¬†I’ll use a small snippet of the complete script. ¬†So I have placed the following script on my PowerShell host to simply add a new VM Network to vSwith0. ¬†As you can see the script is pretty simple, takes two parameters, a host and a location code. ¬†The location code is used to represent uniquness in my environment and is actually used multiple times in the complete script for the hostname, datastores, etc….

1
2
3
4
5
6
param ($hosttoconfigure, $locationcode)
add-pssnapin VMware.VimAutomation.Core
$username = "Host Username"
$password = "Host Password"
$success = Connect-VIServer $hosttoconfigure -username $username -Password $password
Get-VirtualSwitch -Name vSwitch0 | New-VirtualPortGroup -Name "$locationcode-VM_Network" -confirm:$false

So let’s get started on our workflow to call this script. ¬†Again, create a new workflow and call it what you will. ¬† Once you are in the workflow editor move to the Inputs tab. ¬†Here we will get the information from the user that we require in the script. ¬†So go head and add a couple of inputs to the workflow, one being hosttoconfigure (Type VC.HostSystem) and locationcode (Type String).

vCO-SetupParameters

By selecting our host parameter and clicking the eye icon we can set the ‘Show in Inventory’ presentation property on the host input. ¬†This will basically allow the user to browse through their vCenter to select the host when running the workflows, so might as well go ahead and do that as well.

vCO-PresentationProperty

The Powershell workflow that we will be using is called ‘Invoke and external script’ and requires 3 parameters; One, a Powershell Host which we have setup previously, the second is the script to execute, and the third is the arguments to pass to the script.

vCO-PS-SetupParameters

Once on the Schema tab go head and drag the ‘Invoke an external script’ workflow into yours. ¬† When you see the parameter setup black bar pop up click ‘Setup’ and we can have a look at the parameters.

vCO-PS-PromoteParameters

Through this screen we can basically promote or link the parameters from the Script workflow to our main workflow. ¬†You can see that I’ve done a few things. ¬†One, I’ve set the host parameter to a value (same as creating an attribute) and browsed through my inventory to select my Powershell host that we created previously. ¬†Secondly I manually inputted the path to my Powershell script in the externalScript parameter. ¬†Thirdly I selected to skip the arguments parameter at this time. ¬†I’ve done this because I need to pass the hostname as well as the locationcode parameter from my main workflow to this parameter which we will do with a separate element called a Scriptable task. ¬†Go ahead and click ‘Promote’.

vCO-PS-ScriptableTask

So now we have our main input parameters setup (locationcode and hosttoconfigure) as well as our script setup and ready to go.  We just need to tackle that arguments parameter.  As I said we will do this with a separate Scriptable Task workflow so go ahead and drag that into your schema, just before your Invoke External Script.   A scriptable task is just that, kind of a blank canvas to do any sort of scripting (javascript) that you desire.

vCO-PS-ScriptableTask-SetupInVars

So let’s go ahead and click the pencil icon to edit our scriptable task. ¬†There are few IN parameters that we are going to need inside of our script; The first is hosttoconfigure and the second is locationcode.

vCO-PS-ScriptableTask-SetupOutVars

Now move on to the OUT parameters.  We will need to create a new out parameter to store our arguments, so click the link for a new parameter and create a new workflow attribute called scriptArgs of type string.

Now we need to move to the Scripting tab. ¬†This is where we can concatenate a property of the hosttoconfigure parameter and the locationcode to populate our newly created scriptArgs variable. ¬†Honestly it’s a one-liner. ¬†I’m sure there is a way to create this workflow without even requiring this whole Scriptable task but this is the way I got to to work (again, my FIRST vCO workflow). ¬†Copy/Paste the following into your scripting tab.

scriptArgs = hosttoconfigure.Name + " " + locationcode;

Ok, you can close out of your Scriptable task workflow now.  We are almost there.  All that we have left to do is map the External Script workflow paramater arguments to our Scriptable task elements parameter scriptArgs.  Thankfully this is an easy thing to do.

vCO-PS-MapVars

Once again go into your External Script element and click on the Visual Binding tab.  Here, as shown above, we simply need to drag the scriptArgs in attribute over to the arguments in parameter.

vCO-PS-AllDONE

Guess what! ¬†Your done! ¬†If everything has been setup properly and I’ve done a good job at explaining what to do then you should be able to Save and Close your workflow and actually run it on a host (a test host of course). ¬†The result – you should get a VM Network setup on vSwitch0 – oh and a pretty green checkmark beside your workflow ūüôā

At this point I’m going to cut off this post since it’s getting pretty long. ¬†That being said I’m not going to end the series! ¬†I’m always looking at ways to better automate things and you know, having users type in that location code just isn’t good enough for me, a lot of room for error there; they could type it in wrong, do the same location twice, on and on and on… ¬†And hey, I have a database already setup with my location codes in it and whether or not they have already been deployed. ¬†So, stay tuned for Part 5 of my series where we will go through configuring the SQL plug-in and setting up our location input parameter to be populated by an SQL table – as well as update that same table on completion of our script.

My first vCenter Orchestrator Workflow

Creating Roles and adding Active Directory Users & Groups to the role through PowerCLI

As of late I’ve been working on a PowerCLI script to assist me with the deployment of around 50 or so ESXi hosts. ¬†For the most part the PowerCLI cmdlets have been pretty self explanatory and pretty simple to use. ¬†Really I just need to setup some DNS, Hostnames, Networks, Datastores, NTP settings, and permissions…you know, everything you would normally do when setting up a host. ¬†The problem I’ve ran into is when I hit that permissions section.

Essentially what I wanted to do was create a new role containing only those permissions that I wanted then simply assign an active directory group to that role. ¬†So the role part, not too bad, pretty simple really…I used the following…

New-VIRole -Name "Elevated VM User" -Privilege (Get-VIPrivilege -ID "VirtualMachine.Interact")
Get-VIRole "Elevated VM User" | Set-VIRole -AddPrivilege (Get-VIPrivilege -ID "ScheduledTask.Run")
Get-VIRole "Elevated VM User" | Set-VIRole -AddPrivilege (Get-VIPrivilege -ID "ScheduledTask.Create")
Get-VIRole "Elevated VM User" | Set-VIRole -AddPrivilege (Get-VIPrivilege -Name "Power")
Get-VIRole "Elevated VM User" | Set-VIRole -AddPrivilege (Get-VIPrivilege -Name "Maintenance")

Basically this just creates my new role (Elevated VM User) and adds a handful of permissions to it. ¬†In order to find out the name for all the priveleges I simply just ran Get-VIPrivelege -Role ‘Admin’.

So now that I had my role created I just need to add an AD Account to that role. ¬†A lot of the documentation led me to the New-VIPermission cmdlet – sounds easy, but running the following New-VIPermission -Role ‘Elevated VM User’ -Principal ‘DOMAIN\Username’ produced nothing but the following errors for me….

New-VIPermission : 9/12/2012 2:47:40 PM New-VIPermission Could not find VIAccount with name ‘Domain\Username’.
At line:1 char:17
+ New-VIPermission <<<< -Role ‘Admin’ -Principal ‘Domain\Username’
+ CategoryInfo : ObjectNotFound: (Domain\Username:String) [New-VIPermission], VimException
+ FullyQualifiedErrorId : Core_ObnSelector_SelectObjectByNameCore_ObjectNotFound,VMware.VimAutomation.ViCore.Cmdlets.Commands.PermissionManagement.NewVIPermission

New-VIPermission : 9/12/2012 2:47:40 PM New-VIPermission Value cannot be found for the mandatory parameter Entity
At line:1 char:17
+ New-VIPermission <<<< -Role ‘Admin’ -Principal ‘Domain\Username’
+ CategoryInfo : NotSpecified: (:) [New-VIPermission], VimException
+ FullyQualifiedErrorId : Core_BaseCmdlet_UnknownError,VMware.VimAutomation.ViCore.Cmdlets.Commands.PermissionManagement.NewVIPermission

Now it seams as if me passing the string of ‘Domain\Username’ is not satisfying whatever object it is that -Principal is looking for. ¬†So after a many googling and twittering the following code is how I ended up assigning Domain\Username to the role I created.

$groupName = "Domain\Username"
$currhost = get-vmhost HOSTNAME | % {Get-View $_.Id}
$authmgr = Get-View AuthorizationManager-ha-authmgr
$perm = New-Object VMware.VIM.Permission
$perm.Principal = $groupName
$perm.group = $true
$perm.propagate = $true
$perm.RoleId = ($authmgr.RoleList | where {$_.Name -eq "Elevated VM User"}).RoleId
$authmgr.SetEntityPermissions($currhost.parent,$perm)

And this worked perfect! ¬†As I’ve always said I’m sure there are a million ways to do something and if you think your way is more efficient or better than mine, please share! ¬†This is my first crack at it so all suggestions and comments are always welcome ūüôā

Getting rid of those VM Memory Limits (you know, the ones you didn’t know existed)

OK so here’s a quick one. ¬†I know there are many other posts out there about this, i’ve come across multiple ones but again for my own documentation and for the mere fact that usually writing about something helps me to remember it I’m going to throw one more out into the mix.

I’ve¬†occasionally¬†come across a bunch of my VMs which seem for some reason to have a memory limit set on them. ¬†BTW, vCheck is a great tool for reporting on these. ¬† We all know the dangers of memory limits (swapping,¬†ballooning, etc) and to tell you the truth I’m not sure why or how they got set. ¬†I’m assuming I have a template somewhere within my environment which has a limit imposed on it. ¬†Either way, there is a quick and easy way to get rid of those limits using PowerCLI.

First off I wanted to see which VMs had lmits imposed on them from within a certain cluster in my environment.  The following command does just that.

Get-VM -Location CLUSTERNAME | Get-VMResourceConfiguration 
| where {$_.MemLimitMB -ne '-1'} | Select VM,MemLimitMB

Furthermore, If you do have some VMs that you want to have a memory limit set on and not returned here and you have some soft of consistency within their name (ie. Veeam Replica’s) you can do the following to exclude them…

Get-VM -Location CLUSTERNAME | where {$_.Name -notlike '*Replica'} 
| Get-VMResourceConfiguration | where {$_.MemLimitMB -ne '-1'} 
| Select VM,MemLimitMB

You should be left with a listing of your VMs which have a memory limit set on them…

To set these VMs limit to unlimited, just pipe in the Set-VMResourceConfiguration cmdlet as follows

Get-VM -Location CLUSTERNAME | Get-VMResourceConfiguration 
| where {$_.MemLimitMB -ne '-1'} 
| Set-VMResourceConfiguration -MemLimitMB $null

Voila! ¬†No more memory limits…as you can imagine you can do the same with CPULimitMhz. ¬†FYI, if you want to learn more about PowerShell or PowerCLI or scripting you are in the wroooooonnnnggg place, I know what I know, but most examples I get from the following people and you should really follow Alan Renouf (blog/twitter), Luc Dekens (blog/twitter), Jake Robinson (blog/twitter), William Lam (blog/twitter) Eric Wright (blog/twitter), Josh Atwell (blog/twitter) or Hal Rottenberg (blog/twitter). ¬†I’m sure I’m missing a few, these are just the ones I can remember off the top of my head, feel free to recommend some more CMDLET¬†rock stars¬†to me in the comments below…. ūüôā

Practise makes perfect! More PowerCLI APC Powerchute Network Shutdown Goodness (Now with Power On!)

Picture this, a quaint little city in Eastern Ontario. It’s been at least a couple of months since we have really had any rain. My tomato plants are dying, my lawn is completely brown, but the datacentre, it’s chugging along nicely‚ĶThen it hits us, the first rainfall (of any real value) of the summer. Finally maybe things will start to grow again. Chatter around the office turns to the weather yet again, people are smiling, happy, can’t wait to get home see if maybe there was a chance that their grass might have turned a slight shade of green‚Ķand then, nothing but darkness and the faint sound of our¬†neighbouring¬†businesses generator kicking on‚Ķ!

Are you kidding me? It rains once this summer and it knocks the power out? Wow! No big deal though right? We have our Powerchute Network Shutdown all configured to peel through and shut-down all of our physical hardware, and a while back I wrote this nifty little script to shutdown the virtual infrastructure, no problem!

And thus the title for this blog post ‚Äď Practise makes Perfect! Turns out that I could have been a little more efficient in my script. Initially I was looping through hosts one by one shutting off VMs, then waiting, then checking, then going through for another pass, and then moving on to the next host‚Ķ Well, with 10 minutes left on battery I don’t have the time to complete this process on our 8 production hosts, let alone an environment of any type of size. Needless to say the VMs and hosts that didn’t get the time of the day with the script fell hard. Thankfully, there was no corruption or issues resulting from it, but still, I don’t like things not going as planned . When I’m standing in the datacenter I like to see all of the blinky lights shut off before those air conditioners stop pumping out coolness.. So out of my failures I give you the new and improved shutdown script (now with Power ON). You can head straight here to pull down both the power off and power on scripts, but they are explained in a bit more detail below as there is a little bit of configuration to get the power on functionality to work‚Ķ. ¬†As well a big thanks goes out to a fellow Toronto VMUGer (VMUGite ??) Eric Wright (blog / twitter ) and his ‘The Art of Shutdown‘ post a couple of months back. ¬†Eric wrote a great script to shut things down and even has a great little ‘test’ mode in his version. ¬†I got a few lines of code and ideas from Eric’s script so go check it out as well

Power Off the VMs

So first off is the shutdown script ‚Äď you can get the complete version here.

Just a few notes regarding my updates to the script.

if ($keyword -ne $mysecret) 
{ 
    Write-Host "You haven't passed the proper detonation sequence...ABORTING THE SCRIPT" -ForegroundColor red
    exit
}

So first off you see here that if you call the script without a parameter or with a parameter that doesn’t match our secret keyword inside the script the whole thing aborts. ¬†This is to stop us from simply double clicking this or accidenttally unleashing a disaster amongst ourselves.

Get-VM -Location $cluster | where-object {$_.PowerState -eq "PoweredOn" } | Select Name | Export-CSV c:\Scripts\Shutdown\PowereredOnVMGuests.csv

Another important addition to the script.  Basically this dumps a list of the powered on VMs to a csv file.  This will be used in the partner power on script once power has been restored.

The rest of the script is pretty straight forward.  Basically sets DRS to manual mode, disables HA, gracefully shuts down the VMs (any without VMware Tools installed get a hard shutdown), waits a couple of minutes and does another pass, then procedes to shutdown the hosts.  Again, the complete poweroff script can be downloaded here.

Power On the VMs

So all is good, VMs got powered off, but what happens when power comes back up. ¬†Even if you do get your hosts powered back on they aren’t going to turn on your VMs automatically. ¬†Now I know there is a start and stop with host setting but when you are in a DRS cluster this doesn’t do you much good as it is a host setting and VMs move between hosts. ¬†Thus the power on script! ¬†So this script will sit on the same box as your shutdown script. ¬†It needs to be outside of your virtual infrastructure. ¬†My vCenter Server is a physical box so I have placed both the shutdown and the power on scripts there. ¬†Also, you will need to have this script be triggered on start-up for this machine. ¬†This is simply do to the fact that I don’t want to be running any scripts in the middle of the night if power is restored…I’d rather walk in to a fully functional datacenter the next morning ūüôā

The full script can be downloaded here but below are a few explanations of what happens….

if (Test-Path $filename)

The complete script is wrapped in this if statement. ¬†Meaning if the power off dump file doesn’t exist then the script will not execute.

    while ((Get-Service vpxd).Status -ne "Running")
    {
        Write-Host "." -nonewline
        Sleep 2
        Write-Host "." -nonewline
        Sleep 2
        Write-Host "." -nonewline
        Sleep 2 
    }

This repeating loop basically waits for the vCenter Service to be started before the script can continue. ¬†Since this script should be executed during startup we may have to spend some time here waiting for vCenter to get all its ducks in a row ūüôā

    foreach ($iVM in $myImportantVMs)
    {
        Write-Host "Powering on $iVM ..." -nonewline
        Start-VM $iVM
        Sleep 5
        Write-Host "DONE" -Foregroundcolor Green   
    }

Before reading the dump file and getting into the thick of everything we have the option to power on some of the more important VMs first.  So if you have any mail servers, dhcp servers, dns servers, it would be a good idea to put them into $myImportantVMs to have them started first. Once these VMs are on a similar type function will power on the rest of the VMs in the csv file, one by one, every 5 seconds.  You can set the sleep command to whatever you want but 5 seems good for me.

    rename-item "$fileName" "$nameOnly-$DateStamp$extOnly"

This is nearing the end of the script and basically appends the date to the csv file.  This prevents the script from running on next startup Рunless you have another power outage of course.

So there you have it – a complete power off script and a complete power on script. ¬†I know I’ve rambled a little bit in the post but I’m just in that sort of mood. ¬†If you need a hand setting things up or have any questions, concerns, improvements,¬†criticism¬†don’t hesitate to leave them in the comments. ¬†I’ll get back to you…. ¬†And yes, my tomato plants are all dead!

vSphere Syslog Collector – Install and Configure

I've always used vi-logger from within the vSphere Management Assistant to deal with my syslogging of our ESXi servers, that is until our last upgrade to vSphere 5.  The vi-logger command is no more within the 5.0 version of the VMA so I began looking from some alternate solutions.  Now I could of went out and used a Kiwi product or Splunk or configured a Linux box to do our syslogging, however I thought i would give the vSphere Syslog Collector that is bundled with the vCenter installation media a shot.  Honestly I don't find syslog to be a real science.  You centralize the log files, not a big deal, but having a solution all from one vendor is kind of nice.  The vSphere Syslog Collector does exactly what it says; it collects the log files from the ESXi hosts, but it also gives you some status information from within a vCenter plugin as well.  As well, it's a pretty easy install and config as you will see below.

First off mount the ISO of the vCenter installer on the server you would like to act as your collector and select 'VMware Syslog Collector' and click 'Install'.  During the install (and in VMware's documentation) it is called the vSphere Syslog Collector, however on the menu it's called the VMware Syslog Collector.  Let's just say VSC for short to cover off both names…

After accepting the EULA and licensing you should be presented with the Destinations screen.  Here we need to do a couple of things; First, select where you want the collector application to be installed and secondly, where the logs that are collected are going to be stored (Repository directory).  Also, we have the option here to chose how large we want the log files to grow as well as the number of rotations to keep.  I left all of these values at their defaults, except for the repository directory as I wanted to place this on some lower level, cheaper storage.

Next we need to chose a setup type.  I chose to go with VMware vCenter Server installation as I wanted to integrate this with my vCenter instance. Otherwise, you can chose the 'Standalone Installation' option.  

After selecting your setup type, if choosing to integrate with vCenter you will need to provide login credentials to your vCenter Server.  For the most part this should be pretty straightforward.

Next up is ports and protocols.  Again, I left all of these at default, however you may wish to change the ports that the syslog collector operate on.

Then it's just matter of specifying how it should be defined on the network and letting it install…

So that's it, the collector is now installed.  One more step, we need to tell the desired hosts where we want to ship their logs to.  This can be done in a few different ways, all accomplishing the same thing, but, to each his own, here are the methods that I'm aware of.

1. The GUI – for the non command line type people.

Select your desired host which you want to syslog.  Go to Configuration->Advanced Settings (under Software)->Syslog->Global.  From here it is as simple as setting the hostname or IP address of your syslog server in the syslog.Global.LogHost option.

***Updated April 2012***

Also, be sure to open up the syslog ports within the firewall built into ESXi itself.  Go to Configuration->Security Profile and click 'Properties' in the Firewall section.  It can be as simple as just checking the box next to syslog, however if you would like to further secure your environment you can click the 'Firewall' button at the bottom and specify which IP address/networks are allowed to connect through these ports.

 

2. The ESXi Command Line space

Using the following two commands you can do the exact same thing as explained in #1.

esxcli system syslog config set –loghost=vCenter01
esxcli system syslog reload
 
Updated – And the firewall commands to open up the correct ports and restrict access to your syslog server.
 
esxcli network firewall ruleset set –ruleset-id=syslog –enabled=true –allowed-all=false
esxcli network firewall ruleset allowedip add –ruleset-id syslog –ip-address 192.168.42.150
 

3. Host Profiles 

For those with larger installations, you can certainly set the syslog information in a host profile and remediate that against your hosts.  Those setting are located within the profile under the 'Advanced Configuration Option and the same 'Syslog.Global.logHost' option.  *** NOTE*** Until you actually create a host profile from a host that has already had this advanced option setup you will not see this option'.

Updated 

As well, don't forget to set the firewall options for your syslog server in the host profile under the Firewall Configuration -> Ruleset Configuration ->syslog – Ruleset section.

4. PowerCLI

Things begin to get a little fuzzy here.  If you try to run the get and set VMHostSyslogServer cmdlets on ESXi 5 you will receive an error stating that the host isn't supported for those cmdlets, however, they still work, they still setup the syslog server.  The proper way to do this through powershell is using the get and set VMHostAdvancedConfiguration cmdlets examples below.  And once again, I found even this to be a bit quirky in the sense that I couldn't get the set-VMHostAdvancedConfiguration to just accept a -Name and -Value for the setup, but had to use the -NameValue pairing instead.  Also I'm sure someone that knows powershell (not me ūüôā ) can rock this out on one line, but for now, this is what I got.

$sysloginfo = get-VMHostAdvancedConfiguration -Name "syslog.Global.logHost" -VMhost "IP of host that is already setup"
Set-VMHostAdvancedConfiguration -VMHost "IP of host you want to setup" -NameValue $sysloginfo

Updated

As for enabling the syslog in the firewall that can be achieved with the following command

Get-VMHostFirewallException -VMhost hostname -name syslog | Set-VMHostFirewallException -Enabled $true

But when it comes to setting the allowed IP I cannot for the life of me find a way to do this…I'll update later if I do, or if you do, please let me know in the comments. ūüôā

So there you have it!  A fully functional instance of the vSphere Syslog Collector.  As always comments, questions, concerns, rants – put'em in the comments ūüôā

The Resource Pool Priority Pie Paradox – Part 3 – The Powershell Code

Part 2 – The 4:1 Formula
Part 3 – Powershell Scripts

So in parts 1 and 2 of this series I explained (hopefully) what the resource pool priority pie paradox is and how to punch some key numbers into a formula and figure out what exactly you could set for custom shares on a production and test resource pool in order to come out with that 4:1 ratio.  In this part I'll show you how you can get those numbers from your own environment using the VMware PowerCli without having to do the math yourself.

Just a note, for the script to work you must only have two resource pools, which you assign to variables at the beginning of the script.  Along with the resource pools you need to assign your vCenter server name as well as the cluster name.  You may also need to pump in your credentials if you aren't running this from a trusted client.

Anyways, the script is below, feel free to modify as you please.  If you see a spot where I could be more efficient or if I'm doing anything completely crazy let me know…  You can also download it here if you don't feel much like copying and pasting..:)

#################################################################################
# ResourcePoolPie

#
# This script will poll look at VMs residing in a production and a test resource
# pool and determine how to best set the custom share value in order to maintian
# a 4:1 Production:Test ratio.  Note, you must be setup in a Production and Test
# Environment inside of one cluster.  Its kind of unique to my environment and
# may not apply to everyone elses, but feel free to change and modify what you
# need in order to make it work for you.
#
# The following variables will need to be assigned
#
#   $vcenterserver = ip address of vcenter
#   $clustername = name of cluster containing resource pools
#   $prodname = name of production resource pool
#   $testname = name of test resource pool
#
# Created By: Mike Preston, 2011
#
#
#################################################################################

Add-PSSnapin VMware.VimAutomation.Core
# Assign appropriate values to following variables.
$vcenterserver = ""
$clustername = ""
$prodname = ""
$testname = ""
# establish connection to vcenter server
$connection = Connect-VIServer $vcenterserver
# get cluster information
$clus = get-Cluster -Name $clustername | get-view
# get resource pool information
$prodpool = Get-ResourcePool -Location $clustername -Name $prodname
$testpool = Get-ResourcePool -Location $clustername -Name $testname
# get a list of vms in production and test
$prodvms = get-vm -Location $prodpool | where { $_.PowerState -eq "PoweredOn" }
$testvms = get-vm -Location $testpool | where { $_.PowerState -eq "PoweredOn" }
# initialize counters to zero
$totalprodcpu = 0
$totaltestcpu = 0
$totalprodmem = 0
$totaltestmem = 0
# loop through production pool and total cpu/memory
foreach ($vm in $prodvms)
{
    $totalprodcpu = $totalprodcpu + $vm.NumCPU
    $totalprodmem = $totalprodmem + $vm.MemoryMB
}
# loop through test pool and total cpu/memory
foreach ($vm in $testvms)
{
    $totaltestcpu = $totaltestcpu + $vm.NumCPU
    $totaltestmem = $totaltestmem + $vm.MemoryMB
}
# Begin CPU calculations
Write-Host "CPU Configuration"
Write-Host "=========================================================="
write-host "Production Pool contains" $prodvms.count "Powered On VMs containing" $totalprodcpu "cpus"
write-host "Test Pool contains" $testvms.count "Powered On VMs containing" $totaltestcpu "cpus"
write-host "Cluster has" $clus.summary.effectivecpu "MHZ to hand out"
#populate variables for formula a(4w-3x) = nx

 

$a = $totalprodcpu
$w = $clus.summary.effectivecpu
$n = $totalprodcpu + $totaltestcpu
Write-Host ""
# lets solve x ūüôā
Write-Host "Lets plug these numbers into our formula and solve x (Production Share)"
Write-Host "a = total number in production, w = total resources, n = total number in prod and test"
Write-Host "——————————–"
Write-Host "a(4w-3x) = nx) "
Write-Host "$a(4($w) – 3(x)) = $n(x)) "
# lets get some tmp vars initialized
$tmp1 = 4 * $w
Write-Host "$a($tmp1 – 3x) = $n(x)"
$tmp2 = $a * $tmp1
$tmp3 = 3 * $a
Write-Host "$tmp2 – $tmp3(x) = $n(x)"
$tmp4 = $n + $tmp3
Write-Host "$tmp4(x) = $tmp2"
$prodpoolresources = $tmp2 / $tmp4
Write-Host "x = $prodpoolresources"
Write-Host "——————————–"
$prodpoolresources = [Math]::Round($prodpoolresources,0)
$testpoolresources = $w – $prodpoolresources
$prodsharepercpu = $prodpoolresources / $totalprodcpu
$prodsharepercpu = [Math]::Round($prodsharepercpu,0)
$testsharepercpu = $testpoolresources / $totaltestcpu
$testsharepercpu = [Math]::Round($testsharepercpu,0)
# Display recommendations
Write-Host "Recommended Share setting for production $prodpoolresources Mhz split between" $prodvms.count "Vms with" $totalprodcpu "cpus resulting in" $prodsharepercpu "Mhz per cpu"
Write-Host "Recommended Share setting for test $testpoolresources Mhz split between" $testvms.count "Vms with" $totaltestcpu "cpus resulting in" $testsharepercpu "mhz per cpu"
# Begin calculating Memory
Write-Host "=========================================================="
Write-Host "Memory Configuration"
Write-Host "=========================================================="
write-host "Production Pool contains" $prodvms.count "Powered On VMs containing" $totalprodmem "MB of Memory"
write-host "Test Pool contains" $testvms.count "Powered On VMs containing" $totaltestmem "MB of Memory"
write-host "Cluster has" $clus.summary.effectivememory "MB of memory to hand out"
#populate variables for formula a(4w-3x) = nx
$a = $totalprodmem
$w = $clus.summary.effectivememory
$n = $totalprodmem + $totaltestmem
Write-Host ""
# lets solve x ūüôā
Write-Host "Lets plug these numbers into our formula and solve x (Production Share)"
Write-Host "——————————–"
Write-Host "a(4w-3x) = nx) "
Write-Host "$a(4($w) – 3(x)) = $n(x)) "
# lets get some tmp vars initialized
$tmp1 = 4 * $w
Write-Host "$a($tmp1 – 3x) = $n(x)"
$tmp2 = $a * $tmp1
$tmp3 = 3 * $a
Write-Host "$tmp2 – $tmp3(x) = $n(x)"
$tmp4 = $n + $tmp3
Write-Host "$tmp4(x) = $tmp2"
$prodpoolresources = $tmp2 / $tmp4
Write-Host "x = $prodpoolresources"
Write-Host "——————————–"
$prodpoolresources = [Math]::Round($prodpoolresources,0)
$testpoolresources = $w – $prodpoolresources
$prodsharepermb = $prodpoolresources / $totalprodmem
$testsharepermb = $testpoolresources / $totaltestmem
# Output results
Write-Host "Recommended Share setting for production $prodpoolresources MB split between" $prodvms.count "Vms with" $totalprodmem " MB of RAM resulting in $prodsharepermb shares per MB"
Write-Host "Recommended Share setting for test $testpoolresources MB split between" $testvms.count "Vms with" $totaltestmem " MB of RAM resulting $testsharepermb shares per MB"
Write-Host "=========================================================="

 

 

Part 2 – The 4:1 Formula
Part 3 – Powershell Scripts