Introduction
In recent months I’ve been involved in a project with Gary Blake to implement one of, if not the, first vCloud Director Disaster Recovery (DR) solution. The design is based upon the solution described in the VMware vCloud Blogs written by Chris Colotti and Duncan Epping. In order to provide a slick automated solution, I was keen to leverage the power of Windows PowerShell (PowerShell) and VMware vSphere PowerCLI (PowerCLI). Unsatisfied with the thought of manually running some basic scripts, I wanted VMware Site Recovery Manager (SRM) to drive the majority, if not all, of the recovery process. Throughout this project a number of challenges arose in executing PowerCLI functions in order to achieve the desired result, so I thought I would share some details of the final approach used.
The Challenge
In order to use SRM to drive the automated recovery of vCloud Director Resource Clusters, it was decided to implement a series of additional Recovery Plan Steps. These would execute PowerCLI functions that accept a series of parameters, including some of those available from the SRM Environment Variables (the Site Recovery Manager Administration Guide contains further details). If you were to search the internet on this subject you would undoubtedly find a large number of resources that suggest the solution is to; a) Call a PowerShell script using of a batch or ‘helper’ script, or b) Call a PowerShell script directly. Whilst both approaches can fulfil the requirement, I wanted more! I’ll explain why…
Using a batch script to call a PowerShell script works perfectly well but my issue with this approach was that SRM receives the exit code from the batch script and not the PowerShell script. I.e. if the batch script successfully runs but the PowerShell script experiences an error, SRM will still interpret the exit code of 0 from the batch script and hence interpret the Recovery Plan Step as successfully completed – not the slick solution I had in mind.
Calling a PowerShell script directly addresses the issue of SRM receiving the relevant exit code, since if an error is triggered by the PowerShell script it will be picked up by SRM and the Recovery Plan Step will be marked as failed. Problem Solved? Nearly, but I still wanted something more! Whilst this ultimately works, what I really wanted was the ability to call specific custom functions and in the process supply SRM Environment Variable as parameters.
The Solution
The end solution implemented was to provide the capability for SRM, through the use of additional Recovery Plan Steps, to call bespoke PowerShell Advanced Functions directly. In order to achieve this some specific configuration steps are required. We’ll cover these configurations steps in two stages; a) Calling PowerCLI Cmdlets from SRM, and b) Calling Advanced Functions from SRM.
Calling PowerCLI Cmdlets from SRM
The process for calling a PowerShell Cmdlet directly from SRM is relatively straight forward and effectively the same as that for calling a PowerShell script. The specifics arise when there is a requirement to call a PowerCLI Cmdlet. More specifically we need to ensure that the PowerCLI Cmdlets, that are distributed as a PowerShell Snapin, are loaded. Assuming PowerShell and PowerCLI are already installed, the following steps provide an explanation of how this can be achieved:
- Create a dedicated user as a service account for SRM. Configure the SRM service to run as this user.
- Log on to the SRM Server, using the previously created service account
- Open the 32bit PowerShell: Start > Accessories > Windows PowerShell > Windows PowerShell (x86)
- Set the Execution Policy by typing: Set-ExecutionPolicy RemoteSigned
- Find the path to the PowerShell Profile by typing: $profile. Validate it exists by typing: Test-Path $profile
- If the result was ‘False’, create a new profile by typing: New-Item -path $profile -type file –force
- Open the profile file by typing: notepad $profile
- Configure the profile to load vSphere Cmdlets by adding: Add-PSSnapin VMware.VimAutomation.Core
- Repeat step 8 for additional Cmdlets (e.g. vCloud Director) by adding: Add-PSSnapin <Snapin Name>
Upon completion of these configuration steps it will be possible to use an SRM Recovery Plan Step to execute any PowerCLI Cmdlets by selecting ‘Command on SRM Server’ and using the format C:\Windows\SysWOW64\WindowsPowerShell\v1.0\Powershell.exe <Cmdlet> <Params>. This is shown in the example below:
Calling Advanced Functions from SRM
Having worked through the guidance provided in the previous ‘Calling PowerCLI Cmdlets from SRM’ section, you should have the capability to call PowerShell or PowerCLI Cmdlets (and Cmdlets for any other Snapins added) directly from an SRM Recovery Plan Step. What you won’t yet be able to do is call any custom Advanced Functions you have created. The following steps provide an explanation regarding how this can be achieved:
- Take the <filename>.ps1 file containing the functions and create a module by renaming it <filename>.psm1
- Navigate to the directory C:\Windows\SysWOW64\WindowsPowerShell\v1.0\Modules
- Create a directory called <filename>, then copy the PowerShell module fileto the directory
- Open the 32bit PowerShell: Start > Accessories > Windows PowerShell > Windows PowerShell (x86)
- Type Get-Module –ListAvailableand verify that your new module is present
- Open the profile file by typing: notepad $profile
- Configure the profile file to load the new module by adding: Import-Module <filename>
Upon completion of these configuration steps it will be possible to use an SRM Recovery Plan Step to execute PowerCLI functions. Furthermore, assuming you’ve written them correctly (a subject for another post I think…), then you will also receive the relevant exit codes to indicate if the SRM Recovery Plan Step should be marked as successful or failed. In order to execute a custom Advanced Function simply select ‘Command on SRM Server’ and use the format C:\Windows\SysWOW64\WindowsPowerShell\v1.0\Powershell.exe <Function> <Params>. This is shown in the example below:
Implementation Tips
In addition to the implementation steps covered so far there are a few additional pointers worth mentioning that will save you some frustration. In particular I’m referring to the use of single vs double quotes and how to use the SRM Environment Variables as parameters.
Firstly, if you are having issues with calling any function the best course of action (apologies if I’m ‘teaching you to suck eggs’) is to first run your function on the command line and then transpose it in to the SRM Recovery Plan Step and add the Environment Variables etc… If you are still having issue then alter your problematic function such that it writes any supplied parameters to a log file, such that you confirm if they are being interpreted correctly. You’ll notice in the above example that various parameters, such as path names, are passed in double quotes and in the most part this works fine, however on some occasions you may find that the value is not passed correctly and some ‘tweaking’ is required. As a general rule I would recommend the following approach:
- In the first instance do not use any quotes – You’ll soon recognise if this is an issue as the PowerShell function will throw an error with respect to the parameters. I.e. The value of the supplied argument to a given parameter is actually being interpreted as a parameter, which is undefined.
- In cases where a given argument is causing an error (path names being a good example) then surround the argument in double quotes.
- Finally if you function is still generating an error or the value of the given argument is being interpreted incorrectly try using single quotes. This generally seemed to rectify issues where a given argument contained a space or special character.
Lastly, in the event you are attempting to pass SRM Environment Variables, you may find that the environment variable is interpreted literally. In these cases the solution, as can been seen in the above screen shot for the value %VMware_VC_Host%, is to use the Get-Content Cmdlet. For example replace the normal SRM Environment Variable with (Get-Content env:VMware_VC_Host). Credit due to Gary Blake for figuring this one out.
Conclusion
With the application of some simple configuration steps and some well considered scripting it is possible to use SRM to execute PowerShell advanced functions, that could be used to perform all manner of custom tasks for those more complex disaster recovery solutions. For instance, in the second example above an advanced function is being called to check the status of a defined service within a Microsoft Windows guest operating system and report back a success or fail (exit 0 or 1). Now what would be really nice would be the ability for SRM to perform a defined action based on the exit code…